Перейти к содержимому

Анализ подозрительного PowerShell в SIEM: обфускация Base64 и AMSI-bypass на реальном образце

Анализ подозрительного PowerShell в SIEM: обфускация Base64 и AMSI-bypass на реальном образце
Время чтения: 12 мин.

По данным CrowdStrike Global Threat Report 2025, 79% атак в 2024 году обошлись без доставки отдельного вредоносного файла. Атакующие используют то, что уже есть на машине, и PowerShell — их любимый инструмент. В SOC это выглядит знакомо: SIEM выдаёт событие с блоком текста на три экрана, каждый второй символ — часть Base64-строки, между ними — вызовы .NET-классов. Под кодировкой прячется отключение антивирусного сканирования и загрузчик полезной нагрузки. Итог для организации — криптомайнер на серверах, RAT (троян удалённого доступа) в корпоративной сети или выгрузка данных. И всё это без единого «настоящего» вредоносного файла на диске.

Разберём, как SOC-аналитику вручную декодировать такой образец, что искать в логах и какие правила обнаружения настроить в SIEM.

Зачем атакующие прячут команды в Base64 и ломают AMSI

Прежде чем лезть в логи — разберёмся, зачем атакующие вообще усложняют себе жизнь обфускацией. Это часть цепочки атаки (kill chain — модель, описывающая этапы от начального доступа до достижения цели), где каждый этап решает конкретную задачу.

Типичная цепочка:

  1. Initial Access — жертва открывает фишинговое вложение или переходит по ссылке.
  2. Execution — из документа или ярлыка (.lnk) запускается PowerShell-команда. В базе MITRE ATT&CK (открытая база тактик и техник атак; T-коды вроде T1059.001 — идентификаторы конкретных техник) это техника T1059.001. PowerShell — легитимный инструмент Windows, его запуск сам по себе не вызывает подозрений у антивируса.
  3. Defense Evasion — команда закодирована в Base64 (T1027.010 — Command Obfuscation), чтобы сигнатурный анализ антивируса не распознал вредоносные строки. Base64 — способ кодирования двоичных данных в текстовую строку из ASCII-символов. Саму кодировку часто используют для легитимных задач, поэтому антивирус не блокирует её автоматически. Дополнительно вредонос отключает AMSI (T1562.001 — Disable or Modify Tools), чтобы следующие скрипты не сканировались.
  4. Command & Control — после обхода защит скрипт скачивает основную нагрузку (майнер, RAT, бэкдор) с внешнего сервера.

AMSI (Antimalware Scan Interface) — интерфейс Windows, через который антивирус сканирует скрипты и команды прямо перед выполнением. Когда антивирус (Windows Defender, Kaspersky Endpoint Security или другой продукт с поддержкой AMSI) получает через этот интерфейс содержимое скрипта, он проверяет его по сигнатурам. Если атакующий сначала «ломает» AMSI, все последующие команды в этом процессе PowerShell выполняются без проверки — антивирус их просто не видит.

Подход Living off the Land («живём за счёт ресурсов жертвы») делает атаку труднообнаружимой: PowerShell есть на каждой Windows-машине, Base64-кодирование — стандартная функция, а AMSI-bypass выполняется в памяти и не оставляет файлов на диске. Вот почему эти техники так популярны.

Что видит SIEM: ScriptBlock Logging и Event ID 4104

Главный источник телеметрии для обнаружения вредоносного PowerShell — Event ID 4104 из журнала Microsoft-Windows-PowerShell/Operational. Это событие генерируется механизмом ScriptBlock Logging (запись содержимого выполняемых скриптов в журнал событий Windows).

Ключевой момент, который стоит запомнить: ScriptBlock Logging записывает уже декодированный код. Даже если атакующий запускает PowerShell с флагом -EncodedCommand и передаёт туда Base64-строку, в Event ID 4104 попадёт расшифрованное содержимое. Тут возникает парадокс: AMSI-bypass нужен, чтобы скрыть код от антивируса, но сам bypass-скрипт записывается в лог до того, как AMSI отключён. По данным Red Canary, этот парадокс — одна из главных причин, почему детект AMSI-bypass через ScriptBlock Logging работает так хорошо.

Два уровня логирования PowerShell:

  • Automatic ScriptBlock Logging — включён по умолчанию начиная с PowerShell 5.0. Записывает скрипты, содержащие «подозрительные» ключевые слова из списка Microsoft (туда входят Invoke-Expression, FromBase64String, AmsiUtils). Для большинства атак этого достаточно.
  • Global ScriptBlock Logging — записывает всё, что выполняется в PowerShell, без фильтрации. Нужно включить отдельно. Генерирует большой объём событий, зато не даёт атакующему шанс проскочить мимо фильтра.

Дополнительные источники событий:

  • Module Logging (Event ID 800 / 4103) — фиксирует загруженные модули и содержимое Add-Type. Полезно, когда атакующий компилирует C#-код прямо в PowerShell.
  • Sysmon Event ID 7 — записывает загрузку DLL. Если процесс (например, notepad.exe) загружает System.Management.Automation.dll, это означает, что внутри запущен PowerShell-движок без видимого окна powershell.exe. Подход описан в проекте Sysmon Modular Олафа Хартонга и рекомендуется Red Canary как дополнение к ScriptBlock Logging.

Как включить расширенное логирование PowerShell

Для настройки через групповую политику (GPO — Group Policy Object, механизм централизованного управления настройками Windows в домене Active Directory):

  1. Откройте gpedit.msc → Computer Configuration → Administrative Templates → Windows Components → Windows PowerShell.
  2. Turn on PowerShell Script Block Logging → Enabled. Поставьте галочку «Log script block invocation start / stop events» для полной трассировки.
  3. Turn on Module Logging → Enabled. В поле Module Names укажите * для записи всех модулей.
  4. Выполните gpupdate /force на целевых машинах.
  5. Убедитесь, что события из журнала Microsoft-Windows-PowerShell/Operational пересылаются в SIEM. Для Splunk это настраивается через inputs.conf, для Microsoft Sentinel — через Data Connector «Windows Security Events via AMA», для Elastic — через Winlogbeat.

После включения проверьте, что события типа 4104 поступают: выполните в PowerShell любую команду (например, Get-Process) и найдите соответствующее событие в вашем SIEM. Нет события — значит где-то по пути пересылка сломалась, и дальше двигаться бессмысленно.

Деобфускация Base64-пейлоада: пошаговый разбор

Требования к окружению

  • ОС: Windows 10/11 или Server 2016+ с PowerShell 5.1 для анализа; для безопасного исследования — изолированная VM (FLARE VM подходит, 4 ГБ RAM минимум, 8 ГБ рекомендуется, без доступа к продуктивной сети)
  • Инструменты: PowerShell ISE (входит в состав Windows), CyberChef (запускается в браузере, установка не нужна — gchq.github.io/CyberChef)
  • SIEM: Splunk Enterprise 8.x+ / Microsoft Sentinel / Elastic 8.x+ / MaxPatrol SIEM с подключённым источником PowerShell-событий
  • Права: доступ на чтение к индексу PowerShell-логов в SIEM (права администратора на конечных точках не нужны)

Находим подозрительное событие и декодируем

Шаг 1 — поиск в SIEM. Ищем события Event ID 4104, содержащие характерные маркеры обфускации. Для Splunk запрос: index=wineventlog EventCode=4104 ("FromBase64String" OR "EncodedCommand"). Для Microsoft Sentinel (KQL): SecurityEvent | where EventID == 4104 | where EventData contains "FromBase64String". Для Elastic: фильтр event.code: "4104" с поиском по powershell.scriptblock.text. Если результаты есть — переходим к анализу. Если нет — вернитесь к предыдущему разделу и убедитесь, что ScriptBlock Logging включён.

Шаг 2 — извлекаем ScriptBlock. Вот типичный подозрительный ScriptBlock из Event ID 4104 (пример адаптирован из реального образца, описанного Pentest Laboratories):

# Содержимое поля ScriptBlockText в Event ID 4104
[Ref].Assembly.GetType(
  'System.Management.Automation.' +
  $([Text.Encoding]::Unicode.GetString(
    [Convert]::FromBase64String('QQBtAHMAaQBVAHQAaQBsAHMA')))
).GetField(
  $([Text.Encoding]::Unicode.GetString(
    [Convert]::FromBase64String('YQBtAHMAaQBJAG4AaQB0AEYAYQBpAGwAZQBkAA=='))),
  'NonPublic,Static'
).SetValue($null,$true)

На первый взгляд — мешанина .NET-вызовов и Base64. Сейчас разберём по шагам.

Шаг 3 — декодируем Base64-строки. В примере две закодированные строки: QQBtAHMAaQBVAHQAaQBsAHMA и YQBtAHMAaQBJAG4AaQB0AEYAYQBpAGwAZQBkAA==. Декодировать можно тремя способами:

  • CyberChef (самый безопасный): откройте CyberChef в браузере, добавьте рецепт From Base64 → Decode text (UTF-16LE, потому что PowerShell использует Unicode/UTF-16). Вставьте первую строку — результат: AmsiUtils. Вставьте вторую — результат: amsiInitFailed.
  • PowerShell ISE на изолированной VM: выполните [Text.Encoding]::Unicode.GetString([Convert]::FromBase64String('QQBtAHMAaQBVAHQAaQBsAHMA')) — в консоли появится AmsiUtils. Для второй строки аналогично — amsiInitFailed.
  • Linux: echo 'QQBtAHMAaQBVAHQAaQBsAHMA' | base64 -d | iconv -f UTF-16LE -t UTF-8 вернёт AmsiUtils.

Шаг 4 — подставляем результат обратно. Теперь скрипт читается: [Ref].Assembly.GetType('System.Management.Automation.AmsiUtils').GetField('amsiInitFailed','NonPublic,Static').SetValue($null,$true).

Это классический AMSI-bypass, впервые опубликованный исследователем Мэттом Грэбером: через рефлексию .NET скрипт устанавливает внутренний флаг amsiInitFailed в значение $true. После этого AMSI «считает», что инициализация провалилась, и прекращает сканирование для текущего процесса PowerShell. Все последующие команды в этой сессии выполняются без проверки антивирусом. Одна строчка — и антивирус ослеп.

Как понять, что декодирование прошло верно: результат содержит читаемые строки с осмысленными именами .NET-классов. Если вместо текста «мусор» — попробуйте ASCII вместо UTF-16 или проверьте, не сжато ли содержимое дополнительно через GZip (паттерн IO.Compression.GzipStream + FromBase64String).

AMSI-bypass техники: что искать в логах PowerShell

Разобранный выше пример — одна из техник, причём самая простая. По данным Trend Micro, AMSI-bypass активно используется в реальных атаках: от криптомайнеров до RAT. В одном из задокументированных Trend Micro кейсов цепочка выглядела так: powershell "IEX(New-Object Net.WebClient).DownloadString(...)" → AMSI-bypass через WriteInt32 и строковое форматирование → загрузка XMRig-майнера. Pentest Laboratories описывает минимум семь методов обхода AMSI, каждый с характерными артефактами в Event ID 4104.

Основные AMSI-bypass техники и их маркеры в ScriptBlockText:

Техника Что искать в ScriptBlockText MITRE ATT&CK
Установка флага amsiInitFailed amsiInitFailed, AmsiUtils, SetValue($null,$true) T1562.001
Патчинг AmsiScanBuffer в памяти AmsiScanBuffer, VirtualProtect, Marshal::Copy, байты 0xB8, 0x57, 0x00, 0x07, 0x80, 0xC3 T1562.001
PowerShell Downgrade до v2 powershell -version 2 в Event ID 4688 / Sysmon EID 1 (в 4104 этих событий нет — PowerShell 2.0 не поддерживает ScriptBlock Logging) T1562.001
Строковая конкатенация '{0}m{1}{2}' -f, разбитые переменные $w = 'System.Management.Automation.A' T1027.010
Загрузка и распаковка GZip IO.Compression.GzipStream, IO.MemoryStream, FromBase64String в связке с IEX (алиас Invoke-Expression) T1140

Атакующие часто комбинируют техники: сначала кодируют AMSI-bypass в Base64 и сжимают GZip, затем, после отключения AMSI, загружают основную нагрузку — антивирус её уже не сканирует. По наблюдениям s3cur3th1ssh1t, почти все публичные PoC-снипеты AMSI-bypass добавляются в сигнатуры антивирусов в течение нескольких недель после публикации. Поэтому атакующие вынуждены постоянно модифицировать код — менять имена переменных, применять конкатенацию, использовать форматирование строк. Гонка вооружений в чистом виде.

Обнаружение AMSI-bypass: ограничения по вендорам

[Применимо: внутренний пентест, любая Windows-инфраструктура с настроенным ScriptBlock Logging. В средах с отключённым логированием или PowerShell 2.0 детект через Event ID 4104 неприменим.]

  • Windows Defender (Windows 10/11, Server 2016+): встроенный AMSI-провайдер. ScriptBlock Logging фиксирует bypass-попытку до её выполнения — но только при включённом логировании. Если Automatic ScriptBlock Logging не настроен, события 4104 не генерируются. Тут всё просто: нет логов — нет детекта.
  • Kaspersky Endpoint Security 12.x+ / EDR Expert: поддерживает AMSI как дополнительный источник телеметрии. При обнаружении патчинга amsi.dll в памяти генерирует отдельное событие, которое можно пересылать в SIEM через syslog.
  • CrowdStrike Falcon: детектирует AMSI-bypass через собственные сенсоры на уровне ядра, не полагаясь только на ScriptBlock Logging. Событие попадает в Falcon Console и может пересылаться в SIEM через Falcon Data Replicator или API.
  • Elastic Security 8.x+ с Elastic Defend: использует комбинацию ScriptBlock Logging и собственных behavior-правил. Из коробки содержит detection rules для AMSI-bypass в категории «Defense Evasion».

Слепая зона — PowerShell Downgrade. Если атакующий запускает powershell -version 2, ScriptBlock Logging не работает вообще. Детект возможен только через анализ командной строки процесса в Event ID 4688 или Sysmon EID 1: наличие флага -version 2 в аргументах. Рекомендация — полностью удалить компонент PowerShell 2.0: Disable-WindowsOptionalFeature -Online -FeatureName MicrosoftWindowsPowerShellV2Root. Серьёзно, если у вас ещё стоит PowerShell 2.0 — удалите его сегодня.

SIEM-правила обнаружения подозрительного PowerShell

Sigma-правило для AMSI-bypass и обфускации

Sigma — открытый формат описания правил обнаружения, который конвертируется в запросы для конкретного SIEM (Splunk SPL, Sentinel KQL, Elastic EQL) через утилиту Sigma CLI. Один раз написал правило — используешь везде.

title: AMSI Bypass Attempt in PowerShell ScriptBlock
logsource:
    product: windows
    service: powershell/scriptblock
detection:
    selection:
        EventID: 4104
        ScriptBlockText|contains|any:
            - 'AmsiUtils'
            - 'amsiInitFailed'
            - 'AmsiScanBuffer'
            - 'VirtualProtect'
    condition: selection
level: high

После конвертации в SPL для Splunk: index=wineventlog EventCode=4104 (ScriptBlockText="*AmsiUtils*" OR ScriptBlockText="*amsiInitFailed*" OR ScriptBlockText="*AmsiScanBuffer*"). Для KQL в Microsoft Sentinel: SecurityEvent | where EventID == 4104 | where EventData has_any ("AmsiUtils", "amsiInitFailed", "AmsiScanBuffer").

Для обнаружения Base64-обфускации добавьте отдельное правило с ключевыми словами FromBase64String, [Convert]::FromBase64String в связке с Invoke-Expression или его алиасом IEX. Комбинация Base64-декодирования и IEX в одном ScriptBlock — один из самых надёжных индикаторов вредоносной активности.

Ограничения сигнатурных правил

Сигнатурные правила (те, что ищут конкретные строки) — первый рубеж обороны, но не панацея:

  • Строковая конкатенация: атакующий разбивает AmsiUtils на $a = 'Amsi'; $b = 'Utils'; $a + $b — прямое совпадение не сработает. Решение: детект по поведению — комбинация вызовов GetType + GetField + SetValue в одном ScriptBlock.
  • Переименование переменных: замена $base64binary на $x не влияет на функциональность, но обойдёт простую сигнатуру. Решение: ищите .NET-методы (FromBase64String, Reflection.Assembly), а не имена переменных.
  • Кастомные обфускаторы: инструменты типа Invoke-Obfuscation генерируют множество вариантов одного скрипта. Но, как отмечает s3cur3th1ssh1t, скрипты после Invoke-Obfuscation часто детектируются в мониторируемых средах — сама обфускация становится индикатором. Ирония: чем сильнее запутан скрипт, тем подозрительнее он выглядит.

Поведенческие правила — второй рубеж. Они сложнее в написании и дают больше ложных срабатываний, но обходить их значительно труднее. Пример: правило SIEM-корреляции, срабатывающее при сочетании «запуск PowerShell от дочернего процесса Word/Excel» + «сетевое соединение на внешний IP» в рамках одного хоста за 5 минут. По данным PT Research, атакующему в корне изменить своё поведение при атаке — задача нерешаемая, в отличие от смены строковых сигнатур.

Чеклист: настройка обнаружения PowerShell-угроз

Готовый список действий для передачи сисадмину или включения в аудиторский отчёт:

  1. Включить ScriptBlock Logging через GPO: Computer Configuration → Administrative Templates → Windows PowerShell → Turn on PowerShell Script Block Logging → Enabled.
  2. Включить Module Logging через GPO: Turn on Module Logging → Enabled, Module Names = *.
  3. Удалить PowerShell 2.0: Disable-WindowsOptionalFeature -Online -FeatureName MicrosoftWindowsPowerShellV2Root.
  4. Настроить пересылку событий из Microsoft-Windows-PowerShell/Operational в SIEM (WEF, Winlogbeat или агент SIEM).
  5. Создать правило обнаружения AMSI-bypass: Event ID 4104 с ключевыми словами AmsiUtils, amsiInitFailed, AmsiScanBuffer, VirtualProtect.
  6. Создать правило обнаружения Base64-обфускации: Event ID 4104 с FromBase64String + IEX / Invoke-Expression в одном ScriptBlock.
  7. Настроить алерт на powershell -version 2 в Event ID 4688 или Sysmon EID 1.
  8. Развернуть Sysmon с конфигурацией Sysmon Modular — Event ID 7 для загрузки System.Management.Automation.dll нестандартными процессами.
  9. Рассмотреть Constrained Language Mode через WDAC или AppLocker — блокирует большинство AMSI-bypass на уровне политики.
  10. Проверить через 7 дней: события 4104 поступают, правила генерируют алерты на тестовых кейсах, ложные срабатывания не превышают допустимого порога.

Каждый пункт — конкретная задача. Первые четыре закрывают телеметрию (без неё обнаружение невозможно), пункты 5-7 — базовый детект, 8-10 — усиление позиции. OWASP A09:2021 (Security Logging and Monitoring Failures) прямо указывает: без настроенного логирования нарушения не обнаруживаются. NIST CSF 2.0 в подкатегории DE.AE-01 требует установить baseline и отслеживать отклонения — анализ логов PowerShell ложится точно сюда.

Большинство SOC-команд останавливаются на первом уровне: включают ScriptBlock Logging, пишут пару Sigma-правил на известные строки и считают задачу решённой. Формально — алерты приходят. На практике — атакующие давно знают эти строки и обходят их конкатенацией, форматированием, GZip-сжатием. Разница между «у нас есть правило на PowerShell» и «мы реально ловим обфусцированный PowerShell» — в поведенческих правилах и в рутине ручного разбора.

CyberChef плюс десять минут на декодирование Base64 → GZip → ещё раз Base64 — вещь, которую автоматика не заменяет, потому что каждый образец уникален. Пока SOC полагается только на сигнатуры, атакующий с Invoke-Obfuscation опережает на два шага. Когда аналитик умеет разбирать руками — сигнатуры становятся первым фильтром, а не последней линией обороны. Это и есть главный навык, который отличает L1-оператора, закрывающего алерт кнопкой, от L2-аналитика, способного вытащить из закодированного блока конкретный индикатор компрометации (хеш, URL, IP-адрес) и понять, что именно хотел сделать атакующий. Если ты переходишь в ИБ из IT и хочешь системно разобраться в таких задачах — на IB Basics эту цепочку разбирают с лабами за пару месяцев.

Эту тему и смежные навыки разбирают на практике в курсе «Аналитик SOC» Codeby Academy.