Detecting wmiexec-Pro

Detecting wmiexec-Pro

@cherepawwka

Всем привет!

Сегодня мы познакомимся с интересным инструментом wmiexec-Pro, расширяющим возможности wmiexec.py из набора Impacket, и научимся находить следы его использования в сетевом трафике и на хосте.

WMI

Немного о WMIexec

Wmiexec.py из набора Impacket — это скрипт для удаленного выполнения команд, использующий похожий на smbexec подход, но выполняющий команды через WMI. Основным его преимуществом является то, что он запускается под учетной записью пользователя (который должен иметь права администратора), а не под системой, плюс он не генерирует шумные сообщения в журнале событий, как это делает smbexec.py при создании службы.

Wmiexec-Pro разрабатывался как следующее поколение wmiexec.py, предлагая больше новых функций и требуя для работы только порт 135 (Microsoft RPC). Даже если порт 445 на конечных хостах фильтруется, для wmiexec-Pro это будет не проблема.

Также инструмент представляет возможности AV evasion (уклонение от средств антивирусной защиты) и успешно обходит такие антивирусы, как Windows Defender, HuoRong и 360. Забегая вперёд, я скажу, что с KES такой номер не проходит: при попытке использования wmiexec-Pro для создания псевдошелла KES детектит его следующим образом:

  • Trojan.Multi.GenAutorunWMI.a;
  • PDM:Exploit.Win32.Generic.

Заявленные разработчкиом фишки инструмента:

  • AV Evasion;
  • Не используется win32_process;
  • Требуется только порт 135;
  • Имеется модуль обхода AMSI;
  • Имеется модуль передачи файлов;
  • Имеется модуль удаленного включения RDP с помощью метода класса WMI;
  • Злоупотребляет брандмауэром Windows;
  • Имеется модуль зацикленной очистки журналов событий;
  • Имеется модуль удаленного включения WinRM без вызова CMD;
  • Имеется модуль, позволяющий осуществить атаку RID-Hijack для повышения привилегий и закрепления;
  • Полезная нагрузка исполняется через VBS-файлы.

Варианты использования взяты из описания на официальном репозитории инструмента (ссылка приведена выше).


Remote command execution via wmiexec-Pro

В этой статье мы подробно разберем один вариант использования инструмента, позволяющие удалённо выполнять код в системе.

Код исполняется благодаря модулю exec-command, принимающему на вход несколько переключателей:

  • -clear
  • -command "whoami"
  • -shell

Разница между ними минимальная с точки зрения детекта, так как скрипты, используемые для выполнения команд, похожи друг на друга, и их обнаружение практически не отличается.

Переключатель -command исполняет одну команду, а -shell инициирует полуинтерактивный шелл в удаленной системе.

Скриншот исполнения команды whoami представлен ниже:

whoami execution with wmiexec-Pro

Можно заметить довольно обширный вывод информации при исполнении скрипта, в том числе и имя создаваемых объектов в системе. Оно будет также отображено в логах, если логирование на эксплуатируемом узле настроено корректно.

Перед тем, как разибрать детект инструмента в логах, давайте поближе познакомимся с тем, что такое WMI, и узнаем, что такое WMI subscriptions.


Справка: WMI

Windows Management Instrumentation (WMI) — инструментарий управления Windows, одна из базовых технологий для централизованного управления и слежения за работой различных частей компьютерной инфраструктуры под управлением платформы Windows. Она предоставляет программный интерфейс для получения информации о системе, управления компонентами и принятия действий на основе событий.

Одним из простых примеров использования WMI может быть получение информации о процессоре компьютера. С помощью WMI можно получить различные данные о процессоре, такие как название, количество ядер и тактовая частота. Для этого можно использовать PowerShell скрипт:

$processors = Get-WmiObject -Class Win32_Processor
foreach ($processor in $processors) {
  Write-Host "Processor Name: $($processor.Name)"
  Write-Host "Number of Cores: $($processor.NumberOfCores)"
  Write-Host "Max Clock Speed: $($processor.MaxClockSpeed) MHz"
  Write-Host "-----------------------------"
}

Этот скрипт использует команду Get-WmiObject для получения объектов класса Win32_Processor, представляющих процессоры в системе. Затем он перебирает каждый объект и выводит информацию о названии процессора, количестве ядер и максимальной тактовой частоте.

Вывод скрипта в системе выглядит следующим образом:

Processor Name: Intel(R) Core(TM) i5-9400F CPU @ 2.90GHz
Number of Cores: 6
Max Clock Speed: 2904 MHz
-----------------------------

С точки зрения красной команды WMI может быть использован для выполнения определённых действий:

  • горизонтальное перемещение;
  • закрепление;
  • выполнение кода;
  • Command and Control (C2).

Факт того, что WMI является частью Windows и существует почти во всех операционных системах Windows, начиная с Windows 98, позволяет злоумышленникам оставаться вне поля зрения синей команды.

Ключевым аспектом, используемым злоумышленником, является механизм WMI event subscription.


Справка: WMI subscriptions

WMI subscriptions (подписки WMI) позволяют получать оповещения (events) об изменениях, происходящих в системе или в специфических компонентах, используя Windows Management Instrumentation.

Предположим, вы хотите получать оповещения о запуске нового процесса в операционной системе. Для этого вы можете создать WMI Subscription, чтобы отслеживать события в классе Win32_Process. Когда происходит событие создания нового процесса, ваше приложение или служба будет оповещена, и вы сможете принять соответствующие действия, например, записать информацию о процессе в журнал или выполнить анализ безопасности.

Пример кода VBS для создания WMI Subscription:

Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")
Set objEventSource = objWMIService.ExecNotificationQuery("SELECT * FROM __InstanceCreationEvent WITHIN 1 WHERE TargetInstance ISA 'Win32_Process'")

Do
  Set objEvent = objEventSource.NextEvent()
  Set objProcess = objEvent.TargetInstance
  WScript.Echo "New process created:"
  WScript.Echo "Process Name: " & objProcess.Name
  WScript.Echo "Process ID: " & objProcess.ProcessId
Loop

Обычно злоупотребление WMI subscriptions требует создания трех классов, которые используются для хранения полезной нагрузки (__EventConsumer) и события (__EventFilter), при наступлении которого будет запускаться нагрузка, а также информации о связи двух вышеуказанных классов:

  1. __EventFilter // Определяет триггер (новый процесс, неудачный вход в систему и т. д.);
  2. __EventConsumer // Содержит код полезной нагрузки;
  3. __FilterToConsumerBinding // Связывает классы фильтра и потребителя.

Реализация этого метода не требует какого-либо набора инструментов, поскольку в Windows есть утилита, которая может взаимодействовать с WMI (wmic), а также для этих целей можно использовать PowerShell. Однако для автоматизации злоупотребления возможностями WMI можно использовать различные постэксплуатационные фрэймворки, такие как Metasploit, Empire, PoshC2, PowerSploit. Следует отметить, что WMI events запускаются от имени NT AUTHORITY\SYSTEM и сохраняются после перезагрузки (что и обеспечивает закрепление), а для использования этого метода необходимы права администратора.

Эксплуатация

Проведём тестовую атаку и посмотрим, каким образом мы может точно распознать используемое средство

python wmiexec-pro.py contoso.com/administrator@10.10.10.10 -hashes 'aad3b435b51404eeaad3b435b51404ee:e19ccf75ee54e06b06a5907af13cef42' exec-command -command whoami

В данном случае мы используем технику Pass-The-Hash, не зная фактического пароля администратора. В случае, если администратор входит в группу Protected Users, такой вариант не пройдёт, так как мы не сможем использовать NTLM авторизацию.

Результат команды выглядит следующим образом:

Исполнение whoami

Мы видим, что получили ответ от удалённой системы, а вместе с этим подтверждение того, что команда исполнилась от имени NT AUTHORITY\SYSTEM.

Важно упомянуть, что в этом случае мы использовали единичную команду без установления шелла. Как я говорил ранее, создаваемая нагрузка будет незначительно отличаться.

Давайте теперь научимся выявлять вредоносную активность!


Detection

Обнаружение в сетевом трафике

Начнем с сетевого трафика.

Для начала найдём сессии, которые были порождены нашей активностью:

Обнаружение в PT NAD

Мы видим, что, как и заявлял автор, для атаки используется только 135 порт (445 тут нет). Также используется случайный порт DCERPC для взаимодействия со службой WMI, что есть норма.

На DCERPC сработало 3 алерта, которые выглядят следующим образом:

Атаки, распознанные PT NAD

Я не буду приводить весь набор правил, но скажу, что они срабатывают на следующее содержимое в TCP-пакетах:

  • EventConsumer
  • ActiveScriptEventConsumer
  • VBScript
  • ROOT|5c|subscription
  • Set objNet = CreateObject(|22|WScript.Network|22|)

Указанные строки также отчетливо видны в Wireshark при использовании опции Follow -> TCP Stream

Содержимое TCP-трафика в сессии

Наибольший интерес в данном случае представляет сам скрипт, передаваемый на удаленный хост. Это ни что иное, как один из характерных для wmiexec-Pro VBS-скриптов, который используется для удаленного исполнения единичной команды.

Вернёмся к репозиторию и проверим код функции, которую мы использовали для выполнения команды. Сам код модуля exec-command находится в директории modules, название скрипта аналогично названию модуля: exec_command.py.

В случае, если мы не передаём никаких дополнительных аргументов, по умолчанию отработает функция exec_command_WithOutput. Часть её кода приведена на скриншоте ниже:

Содержимое VBS-скрипта

Функция использует определённый VBS-скрипт, хранящийся в файле /lib/vbscripts/Exec-Command-WithOutput.vbs репозитория. Перейдём к нему:

Exec-Command-WithOutput.vbs

Нетрудно догадаться, что этот именно тот скрипт, который мы видели в трафике (достаточно сравнить 2 скриншота), что точно идентифицирует используемый инструмент и явно говорит об используемой тактике злоумышленника.

Наиболее интересная часть скрипта начинается со строки №30:

Полезная нагрузка скрипта

Этот VBS-скрипт создает задачу планировщика задач Windows (Task Scheduler) для выполнения команды cmd.exe с определенным аргументом и получения результатов вывода в указанный файл.

Можно выделить следующие шаги, выполняемые этим скриптом:

  1. Создание экземпляра объекта "Schedule.Service", который представляет сервис планировщика задач;
  2. Подключение к сервису планировщика задач с использованием метода Connect;
  3. Создание экземпляра корневой папки задач планировщика задач;
  4. Создание экземпляра задачи через метод NewTask объекта сервиса планировщика задач;
  5. Установка описания и автора для задачи через объект RegistrationInfo;
  6. Настройка параметров задачи с помощью объекта Settings: включение задачи (Enabled = True), запуск при доступности (StartWhenAvailable = True) и отображение окна задачи (Hidden = False).
  7. Создание триггера;
  8. Создание действия для задачи, которое выполняет команду cmd.exe. Указывается путь к cmd.exe через свойство Path объекта Action, аргументы команды указываются через свойство arguments;
  9. Проверка имени пользователя. Если имя пользователя — SYSTEM, то оно остается пустым (Empty). Это гарантирует, что задача будет выполняться с правами системного пользователя;
  10. Регистрация задачи в планировщике задач с помощью метода RegisterTaskDefinition у корневой папки. Задается имя задачи, объявление задачи (taskDefinition), версия XML (6), имя пользователя (LoginUser), указывается пустой пароль и флаг для перезаписи задачи, если она уже существует;
  11. Удаление задачи с указанным именем из планировщика задач через метод DeleteTask.

Таким образом, этот скрипт создает задачу в планировщике задач Windows, которая будет выполнять команду cmd.exe с указанными аргументами и сохранять результаты в файл. Именно этот скрипт и позволяет удалённо исполнять код в скомпрометированной системе, причем делать это от имени системы.

Исполняемая команда передаётся в base64:

command = Base64StringDecode("REPLACE_WITH_COMMAND")

Если мы посмотрим трафик, то видим такую строку:

command = Base64StringDecode("d2hvYW1p")

Нетрудно понять, что d2hvYW1p = base64_encode("whoami")

Обнаружение в логах хоста

Теперь перейдём к обнаружению активности на хосте.

Для примера повторим атаку, выполнив в этот раз команду tasklist:

python wmiexec-pro.py contoso.com/administrator@10.10.10.10 -hashes 'aad3b435b51404eeaad3b435b51404ee:e19ccf75ee54e06b06a5907af13cef42' exec-command -command tasklist

Результат можно увидеть на скриншоте ниже:

Результат выполнения tasklist

Основная идея поиска активности wmiexec-Pro сводится к анализу трёх событий: 19, 20 и 21 (Sysmon)

Фильтр для MP SIEM: msgid in [19, 20, 21]

Краткое описание указанных событий:

  1. Sysmon 19 — WmiEventFilter activity detected
  2. Sysmon 20 — WmiEventConsumer activity detected
  3. Sysmon 21 — WmiEventConsumerToFilter activity detected

Как мы знаем выше, эксплуатация WMI подразумевает создание экземпляров трёх классов. Каждое из приведённых выше событий демонстрирует один из этапов атаки, и нетрудно догадаться, что всего их 3.

При поиске соответствующей активности в логах скомпрометированной машины, применив приведённый выше фильтр, мы можем увидеть следующие события:

События, связанные с изменением WMI subscriptions

Наиболее интересное для нас событие имеет идентификатор 20, так как в поле Destination у него содержится полный текст VBS-скрипта, исполняемый при наступлении события, указанного в фильтре:

Содержимое скрипта в событии

Поле Name содержит имя создаваемого экземпляра класса, и в событии 21 мы видим, как это имя линкуется с соответствующим значением имени из события 19.

Если мы засунем скрипт в CyberChef, то увидим, что это буквально тот же скрипт, что мы видели в трафике и в репозитории на GitHub:

Преобразование скрипта с CyberChef

Давайте теперь исследуем всю последовательность событий. Для начала проанализируем запущенные в окрестности инцидента процессы на узле. Для этого найдем события с Event ID = 1 (Sysmon):

События запуска процессов на узле

Наиболее интересные строки выделены красным цветом. Первое, что обращает на себя внимание — это запуск процесса scrcons.exe. Scrcons.exe — Windows Management Instrumentation (WMI) standard event consumer — процесс, ответственный за выполнение сценариев VBScript или PowerShell. Активность процесса в контексте выполнения сценария может указывать на то, что злоумышленник злоупотребил локальным или удаленным выполнением кода, что в нашем случае действительно имеет место.

Далее мы видим запуск процесса cmd.exe, commandline которого совпадает с командной строкой, которую мы видели в скрипте в репозитории (и в трафике):

"c:\windows\system32\cmd.exe" /Q /c tasklist 1> C:\Windows\Temp\windows-object-d5733598-be84-44a5-b23c-f5ba16dc9b30.log 2>&1

Также указанная команда характерна для скриптов Impacket, отсюда в MP SIEM можно наблюдать срабатывание правила корреляции Impacket_Like_Execution.

О том, что это злоупотребление WMI, может подсказать процесс wmiprvse.exe (WMI Provider Host), запущенный одновременно с запуском утилиты tasklist. Важно подметить, что родительский процесс cmd.exesvchost.exe, что и свидетельствует о том, что переданная при эксплуатации команда будет исполняться от имени системы.

Теперь просмотрим события, которые, как мы предполагаем, должны появиться при осуществлении атаки. Раз мы знаем, что скрипт создаёт задачу планировщика в системе, найдем события, связанные с запланированными задачами.

Воспользуемся следующим фильтром:

msgid in [4698, 4699, 4700, 4701, 4702]

Краткое описание событий:

  • 4698 — A scheduled task was created
  • 4699 — A scheduled task was deleted
  • 4700 — A scheduled task was enabled
  • 4701 — A scheduled task was disabled
  • 4702 — A scheduled task was updated

После применения фильтра увидим следующую картину:

События создания и удаления запланированных задач на хосте

В поле TaskContent лога попал XML-документ, описывающий созданную задачу. Давайте изучим его подробнее:

{
 "Event": {
  "xmlns": "http://schemas.microsoft.com/win/2004/08/events/event",
  "System": {
   "Provider": {
    "Name": "Microsoft-Windows-Security-Auditing",
    "Guid": "{54849625-5478-4994-a5ba-3e3b0328c30d}"
   },
   "EventID": "4698",
   "Version": "0",
   "Level": "0",
   "Task": "12804",
   "Opcode": "0",
   "Keywords": "0x8020000000000000",
   "TimeCreated": {
    "SystemTime": "2023-10-27T02:45:15.318036500Z"
   },
   "EventRecordID": "36986912777",
   "Correlation": {
    "ActivityID": "{0bd42447-d4ca-000a-4824-d40bcad4d901}"
   },
   "Execution": {
    "ProcessID": "852",
    "ThreadID": "1688"
   },
   "Channel": "Security",
   "Computer": "XXX",
   "Security": null
  },
  "EventData": {
   "Data": [
    {
     "text": "S-1-5-18",
     "Name": "SubjectUserSid"
    },
    {
     "text": "XXX",
     "Name": "SubjectUserName"
    },
    {
     "text": "XXX",
     "Name": "SubjectDomainName"
    },
    {
     "text": "0x3e7",
     "Name": "SubjectLogonId"
    },
    {
     "text": "\\caf8cecf-7f65-41a8-bb97-0d0f664d0b2b",
     "Name": "TaskName"
    },
    {
     "text": "<?xml version=\"1.0\" encoding=\"UTF-16\"?>\r\n<Task version=\"1.2\" xmlns=\"http://schemas.microsoft.com/windows/2004/02/mit/task\">\r\n <RegistrationInfo>\r\n  <Author>Microsoft</Author>\r\n  <Description>Update</Description>\r\n  <URI>\\caf8cecf-7f65-41a8-bb97-0d0f664d0b2b</URI>\r\n </RegistrationInfo>\r\n <Triggers>\r\n  <RegistrationTrigger>\r\n   <Enabled>true</Enabled>\r\n  </RegistrationTrigger>\r\n </Triggers>\r\n <Settings>\r\n  <MultipleInstancesPolicy>IgnoreNew</MultipleInstancesPolicy>\r\n  <DisallowStartIfOnBatteries>false</DisallowStartIfOnBatteries>\r\n  <StopIfGoingOnBatteries>true</StopIfGoingOnBatteries>\r\n  <AllowHardTerminate>true</AllowHardTerminate>\r\n  <StartWhenAvailable>true</StartWhenAvailable>\r\n  <RunOnlyIfNetworkAvailable>false</RunOnlyIfNetworkAvailable>\r\n  <IdleSettings>\r\n   <Duration>PT10M</Duration>\r\n   <WaitTimeout>PT1H</WaitTimeout>\r\n   <StopOnIdleEnd>true</StopOnIdleEnd>\r\n   <RestartOnIdle>false</RestartOnIdle>\r\n  </IdleSettings>\r\n  <AllowStartOnDemand>true</AllowStartOnDemand>\r\n  <Enabled>true</Enabled>\r\n  <Hidden>false</Hidden>\r\n  <RunOnlyIfIdle>false</RunOnlyIfIdle>\r\n  <WakeToRun>false</WakeToRun>\r\n  <ExecutionTimeLimit>PT72H</ExecutionTimeLimit>\r\n  <Priority>7</Priority>\r\n </Settings>\r\n <Actions Context=\"Author\">\r\n  <Exec>\r\n   <Command>c:\\windows\\system32\\cmd.exe</Command>\r\n   <Arguments>/Q /c tasklist 1&gt; C:\\Windows\\Temp\\windows-object-d5733598-be84-44a5-b23c-f5ba16dc9b30.log 2&gt;&amp;1</Arguments>\r\n  </Exec>\r\n </Actions>\r\n <Principals>\r\n  <Principal id=\"Author\">\r\n   <UserId>SYSTEM</UserId>\r\n   <LogonType>InteractiveToken</LogonType>\r\n   <RunLevel>LeastPrivilege</RunLevel>\r\n  </Principal>\r\n </Principals>\r\n</Task>",
     "Name": "TaskContent"
    }
   ]
  }
 }

В таком виде задача не очень читаема, поэтому воспользуемся CyberChef для приведения её в удобный для анализа вид:

Созданная задача

Если мы посмотрим на некоторые поля (Author, Description, Enabled и т.п.), то обнаружим, что они имеют те же значения, которые мы ранее встречали при анализе скрипта (что, опять же, неудивительно):

Содержимое задачи

Также нас наиболее интересует раздел Exec, который содержит исполняемую команду и аргументы к ней:

<Exec> 
  <Command>c:\windows\system32\cmd.exe</Command>
  <Arguments>/Q /c tasklist 1&gt; C:\Windows\Temp\windows-object-d5733598-be84-44a5-b23c-f5ba16dc9b30.log 2&gt;&amp;1</Arguments> </Exec>

Ниже приведены строки скрипта, где эти значения устанавливаются:

Примечание: символы > и & заменены их XML-сущностями, чтобы не нарушить синтаксис разметки.

Так, мы нашли ещё одно подтверждение работы рассматриваемого инструмента и артефакты на хосте.


Помимо запуска процессов и создания запланированных задач, полезными событиями для поиска источника будут события сетевых соединений, которые логирует Sysmon. Здесь нас интересует событие с EventId = 3. Для начала ищем источник, делая следующий запрос:

msgid = 3 and dst.port = 135

В дальнейшем добавляем в запрос IP-адрес, чтобы увидеть все события сетевых соединений:

msgid = 3 and src.ip = 10.0.0.1

Результат можно увидеть ниже:

Результат поиска событий сетевых соединений

Мы находим 2 события, одно из которых — обращение на порт 135 (о чем говорил автор эксплойта), а второе — обращение на случайный DCOM-порт по протоколу DCE/RPC. Процессом, обслуживающим соединения, в обоих случаях является экземпляр svchost.exe, отвечающий за запуск служб.

Ну и напоследок, зная адрес источника атаки, найдём скомпрометированную УЗ, под которой осуществлялась эксплуатация. Сделать это можно простым поиском событий успешной авторизации на хосте (EventID 4624). Чтобы убедиться, что учетная запись, под которой осуществляется вход, имеет права администратора, учтём ещё событие 4672.

msgid in [4624, 4672]
События авторизации на хосте

В поле subject.privileges нормализованного события мы увидим все привилегии, назначенные учетной записи при входе. Я думаю, что Debug и Backup говорить не стоит, и из события понятно, что учетная запись обладает административными привилегиями.


Выводы

Подведём итоги!

В статье мы познакомились с WMI, узнали, что такое WMI subscriptions, и научились обнаруживать следы использования инструмента wmiexec-Pro в сетевом трафике и в логах атакуемой машины. Для выявления активности на хосте использовались следующие события:

  1. Sysmon: 1, 3, 19, 20, 21;
  2. Windows Security: 4624, 4672, 4698, 4699, 4700, 4701, 4702.

Все эти события помогли нам сложить комплексную картину происходящей на хосте активности, явно определить используемое для эксплуатации средство, а также позволили подробнее понять вектор повышения привилегий административной учетной записи до уровня системы путём удалённого исполнения команд ОС при помощи WMI.

Ниже приложу некоторые дополнительные ссылки с материалом о возможностях WMI с точки зрения злоумышленника, а также способами обнаружения вредоносной активности синими командами:

  1. https://pentestlab.blog/2020/01/21/persistence-wmi-event-subscription/
  2. https://attack.mitre.org/techniques/T1546/003/
  3. https://www.elastic.co/guide/en/security/current/persistence-via-wmi-event-subscription.html
  4. https://medium.com/threatpunter/detecting-removing-wmi-persistence-60ccbb7dff96

Надеюсь, этот материал был вам полезен. До новых встреч!

До новых встреч!

Report Page