Изображение: freerangestock
Изображение: freerangestock

Чтение файла, запись в реестр, создание нового процесса — вот примеры событий, обработка которых задействует ядро операционной системы. Практика показывает, что большинство интересных операций в ОС стабильно обнаруживается отслеживанием системных вызовов. Большинство, но не все.

Не так давно мы опубликовали статью, посвященную плагину exploitmon для системы динамического анализа вредоносных файлов DRAKVUF. Главным героем нашего сегодняшнего материала стал еще один плагин в этой системе — rpcmon.

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

Что такое RPC, или Немного теории

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

  • использование файловой системы или реестра — например, создать файл, где один процесс будет писать, другой — читать, и наоборот;

  • именованные каналы — это туннели, в которые можно как записывать данные, так и считывать их. По сути, каналы — объекты, похожие на файл, но без группы свойств, привычных файлам (размер, статичное содержимое и пр.);

  • разделяемая память — в адресном пространстве выделяется страница со свойствами, которые сделают ее доступной двум процессам. Другими словами, оба процесса будут «видеть», что там находится, и благодаря использованию регулирующих компонентов поочередно записывать и считывать. Ее принято использовать для передачи больших данных;

  • Component Object Model (COM) — технология была создана для того, чтобы приложения могли взаимодействовать между собой независимо от платформы (кодовой базы, на которой они написаны) за счет унифицированного подхода к интерфейсу взаимодействия. Благодаря протоколу взаимосвязи приложений не имеет значения, какая реализация «под капотом»;

  • Remote Procedure Call (RPC) — взаимодействие процессов, находящихся за рамками одной операционной системы. Давайте рассмотрим этот способ подробнее.

Технология RPC предполагает, что процессы могут находиться на разных машинах, а в качестве «транспорта» между ними используется сетевой протокол. На стороне клиента вызывается функция, которая подготавливает передаваемую информацию, например капсулирует и кодирует. Соответственно, получается пакет данных, который с помощью сетевого транспорта отправляется на серверную сторону. В свою очередь, на серверной стороне есть действующая в обратную сторону логика — она обрабатывает полученный пакет данных, разбирает его и получает данные, которые следует использовать далее. Затем управление передается на серверную процедуру, которая выполнит все необходимые действия.

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

Транспорт между процессами на одном устройстве инкапсулируется протоколом LPC (Local Inter-Process Communication). Данная технология создана как раз для того, чтобы процессы могли быстро и с высокой производительностью общаться между собой на одном компьютере. Для этого в ядре ОС используются специальные объекты — LPC-порты, или ядерные порты, через которые в виде сообщений передается вся информация в случае, если данных немного. Когда данных много, обмен происходит через общую страницу памяти (см. схему ниже).

В этой статье не будем рассматривать межпроцессное взаимодействие на уровне LPC, поскольку в своих вредоносных техниках хакеры еще не достигли того момента, когда они могут самостоятельно реализовать всю необходимую прослойку на нижестоящем уровне, усложняя анализ на более понятном верхнем слое. Следовательно, перехватывать такое взаимодействие на уровне LPC пока неактуально. Однако мы в PT Expert Security Center не исключаем, а даже прогнозируем в будущем более глубокий анализ межпроцессного взаимодействия в LPC-слое, где задействовано ядро. Там мы также сможем обеспечить более надежный анализ — уже на уровне ядерных сообщений, а не только пользовательской памяти.

Удаленный вызов процедур

Итак, поднявшись на уровень выше, начнем рассматривать взаимодействие на слое удаленного вызова процедур. Вот что там происходит:

  • используется MIDL-интерфейс (Microsoft Interface Definition Language) для клиент-серверного взаимодействия;

  • обмен информацией происходит с использованием специального протокола передачи данных — NDR (Network Data Representation), который также документирован.

На клиентской стороне есть набор API-функций, которые вызываются, когда клиент хочет инициировать передачу сообщений по технологии RPC. Ниже представлено несколько одноименных функций семейства NdrClientCall. Два их главных аргумента, представляющие наибольший интерес, выделены стрелочками на рисунке ниже.

ptStubDescriptor представляет собой указатель на структуру интерфейса MIDL от Microsoft. Хотя в этой структуре очень много полей, для базовой имплементации достаточно определить первое поле: это еще один указатель на другую структуру, а именно RPCInterfaceInformation; непосредственно сама структура называется RPC_CLIENT_INTERFACE. В ней второе поле — RPC_SYNTAX_IDENTIFIER InterfaceID — однозначный идентификатор конечного получателя. Эти интерфейсы неизменны у каждого сервиса, к которому мы захотим обратиться.

pFormat это форматная строка, тогда как proc_num, одно из ее первых полей, — это номер вызываемой процедуры.

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

О плагине rpcmon

В PT Sandbox используется система с открытым кодом DRAKVUF — безагентная песочница, позволяющая на уровне гипервизора перехватывать данные и анализировать память внутри виртуальной машины (о ней мы подробно рассказали в одной из статей нашего цикла). Главными составляющими системы динамического анализа вредоносных файлов DRAKVUF являются плагины, которые позволяют обрабатывать данные тем или иным образом.

Как перехватывать межпроцессное взаимодействие с помощью rpcmon

Разберем по шагам написанный код:

Шаг 1. Перехватываемые API

Объявляется функция NdrClientCall, которую необходимо перехватить. (На самом деле плагин перехватывает больше, некоторые функции мы пока перехватываем в экспериментальных целях.)

Шаг 2. Описание структуры данных

В плагине описаны уже рассмотренные в статье структуры (см. картинку ниже).

Шаг 3. Извлечение идентификатора интерфейса

Эти структуры накладываются на передаваемые перехваченные данные. Ниже показан фрагмент кода, который извлекает идентификатор целевого интерфейса, где происходит обращение, и конвертирует его в удобный и читаемый вид.

Шаг 4. Извлечение номера процедуры

Далее представлен формат кода, который обрабатывает форматную строку с целью извлечь номер вызываемой процедуры.

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

Вредоносные техники: какие они бывают

Опасные действия злоумышленников проще всего изучать на примерах. Что ж, приступим.

T1529: System Shutdown/Reboot

Возьмем вредоносную технику System Shutdown/Reboot из фреймворка MITRE ATT&CK. Хакеры применяют данный метод, чтобы, перезаписав главную загрузочную запись и отправив на перезагрузку атакуемый компьютер, инициировать выполнение кода через буткит. Еще одна их цель при перезагрузке системы — выполнить свой код на автозапуске до момента, когда загрузится средство защиты на компьютере.

Так, в 2018 году чистильщик Olympic Destroyer, одним из зловредных действий которого было отключение ОС после завершения выполнения деструктивных действий, использовался в атаке на инфраструктуру южнокорейских Олимпийских игр.

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

Чтобы понять, как в этих случаях проявлялся удаленный вызов процедур, рассмотрим команду shutdown.exe /s /f /t 0.

Берем утилиту shutdown.exe → загружаем в интерактивный дизассемблер IDA Pro → смотрим функцию main → находим функцию InitiateShutdownW, чтобы изучить ее детальнее.

Эта функция организована в библиотеке advapi32 (выяснили это в таблице импорта). Далее изучаем, как в этой библиотеке реализована наша функция: появляется внутренняя неэкспортируемая функция WsdpInitiateShutdown, в которой происходит вызов NdrClientCall3 функции, отвечающей за удаленный вызов процедур.

Отметим, что в этой статье мы рассматриваем только 64-битные версии библиотек Windows 10. Если в случае выше была бы взята 32-битная версия библиотеки из подсистемы SysWOW64, то вызов NdrClientCall был бы другой, например 2-й или 4-й. В целом значения это не имеет, так как мы можем распознать целевые endpoint-обращения во всех случаях.

В этом примере есть небольшое изменение: вместо форматной строки сразу передается номер процедуры, вызываемой на эндпоинте, — некая функция под номером 0. В данном случае берем первый параметр и, соблюдя шаги выше, получаем последовательность байтов, которую конвертируем в уникальный идентификатор интерфейса (GUID). На скриншоте ниже видно, что есть четырехбайтовое значение 60. Обратите внимание, что это не ошибка: первое четырехбайтовое поле отвечает за размер всей структуры, в которой в числе прочего находится идентификатор целевого интерфейса.

ID интерфейса: D95AFE70-A6D5-4259-822E-2C84DA1DDB0D

Далее берем полученный идентификатор → забиваем его в поисковую систему → находим в интернете дамп RPC-эндпоинтов с машины одного из исследователей (он выложил этот дамп к себе в проект на Github) → по идентификатору выясняем, что это интерфейс процесса объединения wininit, отвечающего за загрузку основных служб ОС.

В нашем случае значение второго параметра — 0, что совпадает с вызываемой функцией WsdrInitiateShutdown. Таким образом, получив идентификатор эндпоинта по номеру вызываемой процедуры, мы выяснили, какое целевое действие собирался совершить злоумышленник.

Если используется система DRAKVUF, то в журнале появится следующее текстовое сообщение:

Следует отметить, что в данном сообщении корректно указан инициатор этого действия — утилита shutdown.exe (а не wininit.exe, который обслуживает непосредственно вызов и инициирует выключение ОС), зафиксированы вызванный метод NdrClientCall3 и номер процедуры и именно тот идентификатор, который был получен из дизассемблера.

Как это реализовано в PT Sandbox? В песочнице появляется событие, сообщающее о потенциально опасном поведении. Согласно принятому в продукте подходу к наименованию, первый термин обозначает общее действие с целевым объектом (создание, чтение, запись, удаление) — в нашем случае Delete. Кроме того, рассматриваемое нами действие принято как достаточно важное и редко случающееся в песочнице (в легитимном порядке такого, как правило, не бывает), поэтому PT Sandbox сразу заподозрила троянскую активность и был получен красный детект обобщенного плана о фиксации Trojan.

T1087: Account Discovery

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

К примеру, у Turla APT есть бэкдор ComRAT, с помощью которого на стадии разведки реально получить много информации, включая данные об учетных записях и их свойствах. Ниже представлены действия злоумышленников после заражения компьютера.

В 2013—2014 годах вредоносная программа ProjectSauron APT имела модульную архитектуру, и один из плагинов — Users — был предназначен для получения информации о пользователях в системе.

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

Берем утилиту net.exe из системного каталога → загружаем в интерактивный дизассемблер IDA Pro → смотрим функцию main → в ней есть неэкспортируемая функция xx_parser.

В этой функции мы видим создание нового процесса. На самом деле утилита net вызывает рядом лежащую утилиту net1.exe, в которую передается все управление.

Далее будет вызвана неэкспортируемая функция user_enum, в результате чего управление передается в API-функцию NetUserEnum. Данная функция реализована в библиотеке netapi32. Посмотрев в библиотеке, куда дальше передается реализация кода, выясним, что в нашем случае это трамплин, то есть нет реализации кода, а управление по указателю кода передается дальше.

Ниже показано, как выставляли точку останова на вызове функции NetUserEnum и выяснили, что код находится в библиотеке samcli.

Интересно: с некоторых пор библиотеки Microsoft переконфигурированы таким образом, что тела функций находятся не в тех библиотеках, которые обозначены в документации. В библиотеках, как правило, находятся трамплины, а сам код разнесен на нижележащие библиотеки.

Уходя в samcli, выясняем, как реализована функция NetUserEnum: появляется еще одна функция SamEnumerateUsersInDomain, реализованная в библиотеке samlib.

В новой библиотеке смотрим, как реализована функция выше, и наконец доходим до удаленного вызова процедур NdrClientCall3. В первом случае будет вызвана процедура 72, во втором — 13.

Получаем новый идентификатор интерфейса → приводим его в понятный вид → забиваем в поисковую систему → находим всю необходимую нам информацию в документации Microsoft, выяснив, что MS-SAMR будет работать с пользовательскими учетными записями. На примере процедуры 13 видим описание вызванной функции SamrEnumerateUsersInDomain.

В журнале событий системы DRAKVUF появится плагин rpcmon cо следующим сообщением:

Как обнаруживается в PT Sandbox? Подробности — ниже.

Следует отметить, что в подобных случаях в продукте фиксируется л

юбое взаимодействие с эндпоинтом SAM независимо от того, какие действия затем последуют: получение списков пользователей, добавление или удаление нового пользователя, перемещение в другую группу или какие-то другие Рассматриваемый пример более легитимный, чем первый, и встречается чаще, поэтому такого потенциально опасного поведения недостаточно, чтобы однозначно зарегистрировать вредоносное поведение в системе (в PT Sandbox это событие отмечено желтым). Факт запуска утилиты Net также зафиксирован, так как она популярна у хакеров.

T1563/002: Remote Service Session Hijacking

Эта техника заточена на получение списков удаленных сессий ОС. Перехват активных RDP-сессий необходим хакерам, чтобы извлекать из них учетные данные пользователей с целью дальнейшего продвижения по инфраструктуре, повышения привилегий и развития своих атак.

Один из последних примеров — операция North Star, где было задействовано вредоносная программа Torisma.

Другой пример — червь WannaCry, многокомпонентный вредонос, один из инструментов которого был нацелен именно на получение списка активных RDP-сессий в системе.

Разберем команду вызова API-функции WTSEnumerateSessionsW из библиотеки wtsapi32.dll.

Действуем абсолютно так же, как в предыдущих примерах: берем библиотеку → обнаруживаем функцию WinStationEnumerateW, которая реализована в библиотеке winsta. Видим, что есть внутренняя функция tsrpcEnumerate.

Вызываем метод GetEnumResult из объекта CEnum → получаем NdrClientCall3 и номер процедуры (в нашем случае — 5) → анализируем первый параметр → извлекаем идентификатор → берем его → забиваем его в поисковик и т. д.

ID интерфейса: 88143FD0-C28D-4B2B-8FEF-8D882F6A9390

В этот раз мы тоже вышли на документацию Microsoft, где у нас опять совпадение — 5-му номеру соответствует функция RPCGetEnumResult, которая предоставляет список активных сессий в системе.

Сообщение в журнале событий DRAKFUV показано ниже:

Как отображается в PT Sandbox? В продукте фиксируется потенциально опасное поведение, сообщающее о попытке кражи списка RDP-сессий. Так как в легитимном порядке подобное происходит нечасто, для песочницы это веский повод зафиксировать вредоносную активность.

PT Sandbox: главное

В материале не раз заходила речь о PT Sandbox, поэтому стоит рассказать об этом решении чуть подробнее.

PT Sandbox — песочница для защиты от целевых и массовых атак с применением неизвестного вредоносного ПО и угроз нулевого дня. Возможности продукта позволяют анализировать файлы в статике и динамике: для статического анализа предназначен IAR-движок с правилами PT Expert Security Center, который дополняет антивирусный SDK сторонних вендоров. В ходе динамического анализа предусмотрены поведенческий анализ образцов, получение журналов поведения, а также обнаружение вредоносных и околовредоносных действий, в результате корреляции которых происходит детект. Кроме того, проводится анализ по косвенным признакам — анализ сетевого трафика, анализ созданных в системе файлов, снимаются дампы процессов на предмет вредоносного кода.

Присоединяйтесь к экспертным вторникам PT Expert Security Center и узнавайте больше о нашей песочнице. Расписание ближайших вебинаров можно посмотреть на сайте.

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


Автор:

Алексей Вишняков

Руководитель отдела обнаружения вредоносного ПО PT ESC

Комментарии (0)