В этой статье мы поговорим о Usermode’ных способах обхода EDR. Методы обхода в ядре затрагивать не будем, потому что для их реализации злоумышленнику придется самостоятельно загрузить в систему уязвимый драйвер (или же найти такой драйвер в системе). Это непросто, поэтому такие кейсы встречаются редко.
Для начала поговорим о компонентах, из которых состоит классическая EDR-система.
Что такое EDR?
EDR-системы (Endpoint Detection and Response) состоят из нескольких компонентов (см. рис. 1).
Endpoint — конечное устройство: компьютер пользователя, виртуальная машина, сервер организации и т. д. Словом, любое устройство, которое необходимо защитить.
Агент EDR — приложение, которое анализирует события операционной системы и может вынести вердикт, является ли тот или иной объект вредоносным. Плюс осуществляет действия по реагированию, отправляет телеметрию на сервер и получает от него команды.
Сервер EDR — управляющий сервер, который отвечает за администрирование и настройку агентов, отображение событий с Endpoint’ов, генерацию отчетов по инцидентам, управление расследованиями и реагированием.
Драйвер — компонент, работающий в ядре ОС. В системе может быть один или несколько драйверов EDR. Они регистрируют callback-функции для получения нотификаций о старте процессов, загрузке библиотек и других событиях. Для этого используются функции PsSetCreateProcessNotifyRoutine, PsSetCreateThreadNotifyRoutine и PsSetLoadImageNotifyRoutine. Для получения событий файловой системы используется драйвер — мини-фильтр. Также драйверы выполняют функцию самозащиты агента.
Системные журналы — Windows Event Log состоит из множества системных журналов и журналов приложений. Для удобного просмотра в Windows есть утилита Event Viewer.
ETW — Event Tracing for Windows, механизм ОС для трассировки событий приложений и драйверов.
Edr.dll — библиотека, внедряемая в каждый процесс при его запуске (для упрощения повествования назовем ее edr.dll, хотя в реальности она может называться по-разному). Осуществляет перехват (хукинг) вызовов функций Windows API для получения сведений об активности процессов.
Нарушение работы EDR
Первый способ незаметно выполнить вредоносные действия на Endpoint‘е — нарушить работоспособность одного или нескольких компонентов EDR.
Угрозы:
- Остановка сервиса.
- Удаление/повреждение файлов или ключей реестра.
- Выгрузка драйвера.
- Нарушение сетевого соединения между агентом и сервером.
За противодействие этим угрозам в агенте EDR отвечает драйвер самозащиты. Он защищает файлы, процессы, ключи реестра и прочие компоненты системы на уровне ядра. Помимо самого драйвера, в состав компонента самозащиты также может входить служба, работающая в пользовательском режиме и взаимодействующая с драйвером. Она выполняет периодические проверки целостности/работоспособности компонентов и структур EDR (например, целостности хуков, работоспособности ETW-сессий и др.).
Однако всегда есть риск обхода самозащиты — например, из-за Zero-day-уязвимостей в ОС, ошибок в коде продукта, уязвимых драйверов или драйверов из состава инструментов для управления процессами (Process Hacker и др.). Соответственно, помимо предотвращения несанкционированных воздействий на компоненты EDR, другой важной задачей компонента самозащиты является создание нотификаций. Например, при попытке отключения самозащиты или нарушения работы компонентов EDR. Благодаря этому специалисты по мониторингу смогут заметить активность злоумышленников и вовремя отреагировать, даже если атакующий уже успел навредить отдельным составляющим системы.
Периодические проверки работоспособности компонентов EDR и сетевого соединения называются Health Check. Для проверки наличия сетевого соединения агент периодически отправляет на сервер Heartbeat: небольшое сообщение, смысл которого — сказать «я жив». Если сообщение не поступит, на сервере изменится статус соответствующего Endpoint’а.
Один из интересных инструментов для нарушения сетевого соединения между агентом и сервером — утилита EDR Silencer. Она использует механизм Windows Filtering Platform (WFP) для блокирования отправки сетевого трафика от EDR-агента на сервер. EDR Silencer ищет среди запущенных в системе процессов те, которые относятся к EDR, и добавляет для них блокирующий WFP фильтр. После этого система не может отправить на сервер нотификацию об атаке.
Тем не менее одно из ключевых свойств EDR-агента — возможность реагировать автономно, без подключения к серверу. Благодаря этому система может самостоятельно выявить факт добавления фильтра и восстановить соединение. Есть несколько способов задетектить блокировку:
- по событию 5441 журнала Security;
- по детекту запуска процесса с параметром «blockedr»;
- статический YARA-детект на EDR Silencer.
Также для обнаружения активности EDR Silencer можно использовать утилиту EDRNoiseMaker. Отметим, что заложенную в ней логику можно повторить и непосредственно в EDR-агенте.
Нарушение поставки событий
Поставщиками событий для EDR могут быть:
• собственный драйвер;
• Windows Event Log (WEL);
• Event Tracing for Windows (ETW);
• edr.dll.
Рассмотрим способы нарушения их работы.
Windows Event Log
В Windows каждое приложение может вести журнал в формате evtx, в который будут записываться важные отладочные сообщения. Система по умолчанию пишет логи в журналы System, Security, Application и др. Но злоумышленник может попробовать стереть компрометирующие его записи.
Угрозы:
- Изменение настроек / очистка журналов.
- Использование утилиты Windows Event Log Killer и ей подобных.
1. Очистить логи можно разными способами. Например, с помощью PowerShell-команд Remove-EventLog или Clear-EventLog -LogName <имя журнала>. Для их обнаружения следует проверять запускаемые PowerShell-скрипты. Также злоумышленник может вручную удалить файлы логов. Однако это действие отразится в журналах: Event ID 1102 — «The audit log was cleared» для Security; и 104 — «The System log file was cleared» для других.
Помимо этого, очистить журнал можно с помощью утилиты wevtutil от Microsoft. Чтобы обнаружить ее применение, необходимо мониторить запуски процесса «wevtutil» с параметром «cl» (например, Event ID 1 Sysmon’а или 4688 Security). Либо использовать собственную реализацию мониторинга — через драйвер или edr.dll.
Другой способ нарушить поставку событий из WEL в EDR — использовать PowerShell-команду Limit-EventLog -LogName <имя журнала> -OverflowAction DoNotOverwrite. Последний параметр означает, что, как только лог достигнет максимального размера (по умолчанию ~20 МБ), новые события будут автоматически удаляться. Для журнала Security переполнение сопровождается событием 1104: «The security log is now full». Также следует мониторить события 4103 и 4104 журнала Microsoft-Windows-PowerShell/Operational на предмет наличия команды «Limit-EventLog» с параметром «-OverflowAction DoNotOverwrite».
2. Наконец, переходим к утилите Windows EventLog Killer и ей подобным. Они интересны тем, что действуют довольно скрытно и завершают все потоки службы eventlog, не останавливая при этом процесс службы. То есть служба продолжает работать, но события перестают записываться в журналы. Подобные вредоносные утилиты успешно детектируются с помощью статических правил.
Общие рекомендации:
- Контролируйте поступление событий из соответствующих журналов WEL на сервер.
- Проверьте настройку разрешений на редактирование/очистку журналов WEL в групповых политиках.
- Используйте драйвер самозащиты для блокирования попыток очистить журналы и завершить потоки EventLog’а.
- Применяйте статические правила для детекта известных вредоносных утилит, используемых для нарушения работы службы Windows Event Log.
Event Tracing for Windows
Механизм Event Tracing for Windows выглядит следующим образом (см. рис. 2).
Сессии (сеансы) — предоставляют потребителям события от одного или нескольких провайдеров либо записывают события в лог.
Контроллеры — приложения, которые управляют сессиями. Определяют путь к логу и выявляют, какие провайдеры поставляют события в ту или иную сессию, запускают и останавливают сеансы трассировки.
Провайдеры — приложения, которые занимаются поставкой событий в сессии.
Потребители — приложения, использующие события.
ОС не предоставляет достаточно средств для получения событий мониторинга, поэтому производители EDR часто используют ETW в качестве поставщика событий. Однако изначально эта служба разрабатывалась как средство отладки, а не мониторинга, поэтому на уровне ОС механизмов защиты ETW не существует.
Угрозы:
- Нарушение поставки событий с помощью системных утилит или WinAPI
- Модификация реестра.
- Патчинг EtwEventWrite в ntdll.dll.
1. Самый простой способ нарушить поставку ETW-событий — использовать штатные системные утилиты (logman, xperf) или PowerShell-команды Stop-Etw-Trace-Session/Remove-EtwTraceProvider. Для предотвращения их запуска для остановки логирования рекомендуется мониторить старты процессов с соответствующими параметрами с помощью драйвера или edr.dll.
Для остановки сессии также можно использовать WinAPI-функцию StopTrace. Это более скрытный способ, и для его блокирования необходимо перехватить вызов данной функции (подробнее о перехватах — в следующем разделе).
2. Кроме того, в ETW есть сессия Autologger, которая логирует события во время загрузки ОС. Чтобы ее отключить, достаточно обнулить ключ HKLM\System\CurrentControlSet\Control\WMI\Autologger\<имя сессии>\Start. Для защиты от злоумышленников можно с помощью драйвера проверять попытки записи в этот ключ и блокировать их, если модифицирующий процесс не относится к EDR-агенту.
3. Еще один способ нарушить поставку событий ETW — пропатчить WinAPI-функцию EtwEventWrite в ntdll.dll так, чтобы она сразу возвращала статус об успешном завершении. В качестве противодействия следует выполнять периодические проверки пролога функции EtwEventWrite в ntdll.
Общие рекомендации:
- Проверяйте, что агент продолжает получать события от используемых провайдеров.
- Убедитесь в том, что EDR использует несколько источников событий, а не полагайтесь только на один.
Перехваты Usermode’ных WinAPI-функций
При запуске каждого процесса в системе драйвер EDR-агента внедряет библиотеку edr.dll в его адресное пространство. edr.dll загружается и переписывает прологи определенных функций WinAPI так, чтобы после вызова функции управление передавалось на код, который логирует вызов, обрабатывает параметры и возвращаемое значение функции, а также может запретить ее дальнейшее выполнение. Как правило, EDR-системы ставят хуки на функции в ntdll.dll, поскольку именно оттуда выполняются системные вызовы в ядро.
На основании информации о перехваченных вызовах EDR-агент решает, является ли процесс вредоносным, и при необходимости может отправить нотификацию на сервер или отреагировать (удалить файл, завершить процесс и т. д.). Перехват функций — не самая надежная технология (бывают проблемы со стабильностью и перфомансом), однако иногда у нас может не быть других источников получения информации о событии, кроме Usermode’ных хуков.
Угрозы:
- Выгрузка библиотеки EDR.
- Запрет загрузки библиотеки EDR в процесс.
- Перезапись EDR’ного хука (восстановление пролога).
- Прямой вызов Syscall’ов.
1. Существует ВПО, которое проверяет наличие перехвата перед вызовом конкретной WinAPI-функции. Если перехват установлен, функция не вызывается. Однако тогда не будет выполнена и вредоносная активность.
2. Один из способов скрыть этот процесс от EDR — выгрузить библиотеку edr.dll с помощью FreeLibrary. Это действие можно расценивать как вредоносное и сразу завершать процесс, который его выполнил. Обнаружить выгрузку библиотеки можно с помощью того же хука на FreeLibrary либо ETW-события eventid: 6 провайдера Kernel-Process.
3. Следующий способ скрыться от EDR — запретить загрузку edr.dll при старте вредоносного процесса. В структуре STARTUP_INFO, которая передается в функцию CreateProcess, есть поле — указатель на список атрибутов. Если атрибут PROC_THREAD_ATTRIBUTE_MITIGATION_POLICY имеет значение PROCESS_CREATION_MITIGATION_POLICY_BLOCK_NON_MICROSOFT_BINARIES_ALWAYS_ON, ОС запретит загрузку в создаваемый процесс всех библиотек, кроме тех, которые имеют валидную подпись Microsoft. Таким образом, если edr.dll не подписана Microsoft, она не будет загружена в создаваемый процесс.
В качестве противодействия можно перехватывать запуски процессов и проверять параметры запуска на предмет наличия флага PROCESS_CREATION_MITIGATION_POLICY_BLOCK_NON_MICROSOFT_BINARIES_ALWAYS_ON. Это редкое действие, и оповещение на сервер (как минимум) здесь точно не будет лишним.
Подробнее об атрибутах можно прочитать на msdn в документации к функции UpdateProcThreadAttribute.
Еще один способ скрыться от EDR — восстановить исходные прологи функций в ntdll.dll. Это можно сделать двумя способами:
- Еще раз загрузить в память процесса ntdll.dll и перезаписать прологи функций.
- Запустить дочерний процесс в Suspended-режиме и перезаписать прологи функций (при запуске дочернего процесса в Suspended-режиме ntdll еще не будет переписана EDR’ом, поскольку драйвер не получит нотификации о старте процесса, пока не будет вызвана функция ResumeThread).
Отметим, что оба подхода содержат аномальное поведение. В первом случае это повторная загрузка ntdll, во втором — запуск процесса в Suspended-режиме (наличие флага CREATE_SUSPENDED можно проверить с помощью перехвата функции CreateProcess).
4. Идем дальше: чтобы обойти EDR’ные хуки, можно вызвать Syscall напрямую. Системный вызов или Syscall — это вызов кода ядра, в ассемблере он выглядит так (см. рис. 3).
В регистр EAX помещается номер системного вызова, после этого вызывается инструкция Syscall, которая передает управление на ядерный код. В разных версиях ОС номера системных вызовов могут отличаться, поэтому легитимный софт не использует Syscall напрямую, а вызывает экспорты, предоставляемые системными библиотеками.
В свою очередь, ВПО может выполнять системные вызовы напрямую, чтобы не обращаться к системным библиотекам, функции которых могут быть перехвачены EDR. Но подобное поведение является аномалией, и его можно выявить путем анализа стека вызовов на стороне драйвера EDR. Если системный вызов выполняется не из ntdll.dll, вызывающий процесс нужно завершить.
Общие рекомендации:
- Периодически проверяйте работоспособность хуков (healthcheck).
- Анализируйте стек вызовов в драйвере: детект чтения системных библиотек с диска (вне LoadLibrary), вызовы Syscall не из ntdll.
- Обеспечьте отправку нотификаций на сервер при попытке копирования системных библиотек в произвольные директории.
- Выполняйте отправку нотификаций на сервер при запуске Suspended-процессов.
- Убедитесь в том, что EDR использует несколько источников событий.
Скрытие/мимикрия
Скрытие — это мимикрия вредоносного процесса под легитимный, которая не нарушает работу EDR. Рассмотрим два способа ее реализации.
Спуфинг родительского процесса
В этом случае злоумышленники подменяют родительский процесс, чтобы придать вредоносному более легитимный вид. Если вредоносный процесс запущен доверенным (подписанным Microsoft) приложением, аналитик может не обратить на него внимания.
Мы уже упоминали структуру STARTUP_INFO, которая передается в функцию CreateProcess. В этой структуре есть поле PROC_THREAD_ATTRIBUTE_PARENT_PROCESS — в него можно записать pid существующего легитимного процесса. При этом и драйвер, и Task Manager будут отображать внедренный pid как родительский.
Обнаружить это довольно легко: смотрим на событие eventid: 1 провайдера Kernel-Process — это событие о запуске процесса. В нем есть поля ParentProcessId (содержит внедренный pid) и Execution ProcessID (содержит pid реального родительского процесса). Если они не совпадают, запущенный процесс и процесс с Execution ProcessID следует завершить.
Также обнаружить подмену родительского процесса можно на уровне драйвера EDR: путем сопоставления значения ParentProcessId с CreatingThreadId –> UniqueProcess из структуры PS_CREATE_NOTIFY_INFO (драйвер EDR выдаст нотификацию о запуске процесса). В обычной ситуации ParentProcessId и CreatingThreadId –> UniqueProcess будут указывать на один и тот же процесс, а в случае спуфинга родительского процесса — на разные (см. рис. 4).
Спуфинг командной строки
Часто логика детектирования вредоносного софта и хакерских утилит завязана на сканировании командной строки, из которой был запущен процесс. Как злоумышленники скрывают реальную командную строку:
- Создается Suspended-процесс с безобидными аргументами.
- Вызывается функция NtQueryInformationProcess для получения адреса PEB (Process Environment Block). В PEB содержится информация о процессе, в том числе командная строка.
- PEB -> ProcessParameters -> CommandLine перезаписывается на вредоносную. Именно она будет выполняться при возврате процесса из Suspended-режима.
- Исполнение передается на основной поток процесса с помощью функции ResumeThread.
С точки зрения защиты запуск Suspended-процесса — подозрительное действие, поэтому нотификация о нем должна отправляться на сервер EDR. Для обнаружения факта подмены командной строки нужно перехватывать функции CreateProcess и ResumeThread. Затем необходимо сравнить в обработчиках перехватов командную строку, полученную из CreateProcess, с той, что находится в PEB. Если они отличаются, следует запретить ResumeThread и завершить процесс.