В конце 2023 года команда Solar 4RAYS в рамках проведения Compromise Assessment обнаружила атаку на один из органов исполнительной власти. Мы выявили образцы многоступенчатого ВПО, которое на финальной стадии разворачивает на целевой системе имплант, названный нами DFKRAT. Разработанный в шпионских целях вредонос позволяет атакующим, среди прочего, похищать данные из файловой системы жертвы. Мы провели расширенное исследование и нашли другие образцы, отличающиеся технически, но используемые той же группой злоумышленников на протяжении 2021–2023 годов против русскоязычных целей. В настоящий момент мы не можем отнести кластер этой активности к какой-либо известной группировке, поэтому обозначили его как NGC2180. В статье мы подробно опишем найденное ВПО и приведем индикаторы компрометации.
Краткое содержание отчета
- Мы обнаружили шпионский имплант DFKRAT на системах одного из заказчиков в конце 2023 года.
- В открытых источниках были найдены и другие версии этого ВПО и прослежена их эволюционная цепочка с 2021 года, кластер этой активности мы назвали NGC2180.
- Первичный вектор заражения в случае ранних версий, по всей видимости — таргетированное фишинговое письмо, начиненное загрузчиком. В последних версиях вектор остался неизвестным.
- Вредоносная активность осуществляется полезной нагрузкой, которая доставляется загрузчиками в более ранних версиях и дропперами, эксплуатирующими DLL side-loading, — в последних.
- Ключевой функционал DFKRAT -— эксфильтрация файлов, поддержка интерактивного шелла, потенциальная загрузка дополнительного ВПО с сервера управления С2.
- В качестве С2 для актуальной версии имплантов использовались скомпрометированные серверы Национального центра научных исследований в Греции и индонезийской компании.
- Нам удалось найти и проанализировать фрагмент управляющего сервера.
В публичном пространстве не было найдено образцов последней версии вредоноса, обнаруженной нами на зараженных системах, однако мы нашли более ранние версии, отличающиеся менее продвинутой реализацией.
II версия — конец 2023 года (актуальная)
Во время расследования инцидента на системах жертвы были обнаружены два различных образца ВПО, представляющих собой промежуточную стадию дропперов, при этом финальная стадия с полезной нагрузкой в обоих случаях была одинаковой.
В то время как первичный вектор заражения в этой версии остался не определен, известно, что вредонос-дроппер в обоих случаях доставлялся на хост в виде трех файлов:
- легитимный исполняемый файл, импортирующий функцию из вредоносной библиотеки;
- вредоносная библиотека, внедряющая шелл-код в легитимный процесс;
- бинарный файл, содержащий шелл-код и конечную нагрузку в виде зашифрованного PE-файла.
C:\Program Files\CUAssistant\Download\
C:\Program Files\HP\Shared\bin\
Дроппер #1
В первом исследованном случае все файлы, принимающие участие в атаке, находились в директории C:\Program Files\CUAssistant\Download\:
- ExportController.exe — легитимный исполняемый файл, импортирующий функцию из вредоносной библиотеки;
- CoreFoundation.dll — вредоносная библиотека, внедряющая шелл-код;
- config — бинарный файл, содержащий шелл-код и конечную нагрузку в виде зашифрованного PE-файла.
Цепочка запуска вредоносного компонента начинается с исполняемого файла ExportController.exe (MD5: 379b72a6fadeb462ec884ca868025b6c). Он является компонентом QuickTime (разработанная Apple мультимедийная платформа) и подписан цифровой подписью, отозванной еще в 2017 году:
Name | Apple Inc. |
Issuer | VeriSign Class 3 Code Signing 2010 CA |
Valid From | 12:00 AM 07/29/2015 |
Valid To | 11:59 PM 08/27/2017 |
Thumbprint | 173A28539CA6DAB5AC8C3B995ABAA692F95C5FC4 |
Serial Number | 2B 20 EB 33 80 79 2A B0 11 F6 62 C0 64 FD B4 73 |
Для запуска вредоносного функционала злоумышленники эксплуатируют технику DLL Side-Loading — так ExportController.exe импортирует и вызывает пару функций CFDataCreate и CFRelease из библиотеки CoreFoundation.dll. Обе функции не несут в себе никакого функционала, а их импорт носит символический характер для вызова функции DllEntryPoint, внутри которой и находится вредоносный код
MD5 | bb64fcb014d913b92975fccd5fa3e9b1 |
SHA1 | 277624720ede4ed518ac7af599147c7f6bbdf7a4 |
SHA256 | 144572ee5214f7289d1f71a44d90eb4ba2ac7d48f6e6b5b166f8ca7fe89afe9c |
File name | CoreFoundation.dll |
File type | PE32 executable (DLL) Intel 80386 |
File size | 139 Kb |
Comp. timestamp | 2023-08-05 06:53:19 UTC |
Вредоносный код стартует созданием изначально легитимного процесса со следующей командной строкой:
C:\Windows\System32\dllhost.exe /Processid:{C59AY5E4-1B4C-90A8-0907-A28FABCA1221}
После чего открывается файл config, который располагается в директории с исполняемым файлом и его содержимое инжектится в предварительно созданный процесс с помощью функций:
- ZwAllocateVirtualMemory
- ZwWriteVirtualMemory
- ZwQueueApcThread
- ZwResumeThread
Данный способ не создает дополнительного потока, а переводит созданный при инициализации процесса поток на необходимый адрес.
Интересной особенностью данного дроппера также является прямая работа с вызовами функций WinAPI, которые импортируются напрямую из ntdll.dll. Работая в 32-битном режиме, он сначала находит номер нужного API вызова, а затем через WinAPI вызывает эту функцию по ID следующей инструкцией:
call dword ptr fs:[0C0h]; wow64cpu!X86SwitchTo64BitMode
Для поиска номера нужной функции на первом этапе cоставляется таблица из адресов функций и их захешированных имен (используются только те, названия которых начинаются с Zw). Далее таблица сортируется по адресу функций, а последовательный номер в ней является номером искомой функции. Код алгоритма можно найти в Приложении I.
Внедренное таким образом содержимое файла config представляет собой шелл-код, который расшифровывает себя при помощи ключа 0x9708767C, используя следующий алгоритм:
key = 0x9708767C
_DWORD *encrypted_shellcode;
for (int i = 0; i < shellcode_length; i++) {
encrypted_shellcode[i] ^= key;
key += encrypted_shellcode[i];
}
Далее управление передается на расшифрованную часть, которая содержит в себе PE-файл полезной нагрузки (MD5: 8ce681f1c9ddf69a4ad4d53de57e404f) и код, который загружает его в память и передает управление на Entrypoint.
Дроппер #2
Во втором исследованном случае все файлы, участвовавшие в атаке, находились в директории C:\Program Files\HP\Shared\bin\:
- cdosys.dll.exe — легитимный исполняемый файл, импортирующий функцию из вредоносной библиотеки;
- d3d10_1.dll — вредоносная библиотека, внедряющая шелл-код;
- Dfk — бинарный файл, содержащий шелл-код и конечную нагрузку в виде зашифрованного PE-файла.
Работа вредоноса начинается с запуска cdosys.dll.exe (MD5: d7881fc5e3f93b39d3e84ccf988cc392) и дальнейшей эксплуатации метода DLL Side-Loading. Файл является компонентом ManyCam — софта для стриминга видео от компании Visicom Media, его оригинальное имя в составе легитимного ПО — hw_feature_tester.exe. Он подписан соответствующей валидной цифровой подписью:
Name | Visicom Media Inc. |
Issuer | DigiCert Trusted G4 Code Signing RSA4096 SHA384 2021 CA1 |
Valid From | 12:00 AM 01/19/2022 |
Valid To | 11:59 PM 01/18/2025 |
Thumbprint | 1CF5550BA6165341E28D773228634AE84CECBF23 |
Serial Number | 0E 8A C3 0E E7 30 1E BF FE 46 B4 FE 3E D0 76 EB |
В процессе работы файл загружает вредоносную библиотеку d3d10_1.dll и вызывает одну из экспортных функций D3D10CreateDevice1. Сама библиотека предназначена для загрузки шелл-кода в память вновь созданного целевого процесса.
MD5 | 1da3ce8c4267bf982e43472a08fa2ca1 |
SHA1 | 88c5c02581b4b7fd3897d440f41d2bada9b6e704 |
SHA256 | a7aa8a58a7f78b56623ed6475cb952ce82aec84e6ceebb2a8ffeea76edd3b486 |
File name | d3d10_1.dll |
File type | PE32 executable (DLL) Intel 80386 |
File size | 284 Kb |
Comp. timestamp | 2013-02-20 12:18:18 UTC |
По всей видимости, в этом случае NGC2180 воспользовались техникой Timestomping, а именно: подделали дату компиляции вредоносной библиотеки, чтобы ввести в заблуждение потенциальных исследователей и системы защиты.
Примечательно, как атакующие воспользовались уже существующими возможностями выбранного ими исполняемого файла. В зависимости от аргументов командной строки, с которыми осуществлялся запуск cdosys.dll.exe, менялся и поток исполнения:
- сdosys.dll.exe
Создает и запускает службу WinInit (display name WinInit Start Service).
binPath= C:\Program Files\HP\Shared\bin\cdosys.dll.exe check
Таким образом обеспечивается персистентность импланта на хосте жертвы; - cdosys.dll.exe check
Создает дочерний процесс cdosys.dll.exe check -s; - cdosys.dll.exe check -s
Запускает основной функционал дроппера.
При запуске основного функционала вызовом CreateProcessW создается легитимный процесс с валидной цифровой подписью C:\Windows\System32\winrshost.exe (Host Process for WinRM's Remote Shell plugin). Далее открывается файл Dfk для инжекта его содержимого в созданный процесс. Внедрение выполняется с помощью следующих вызовов:
- NtAllocateVirtualMemory;
- NtWriteVirtualMemory;
- GetThreadContext;
- SetThreadContext;
- ResumeThread.
MD5 | dc9f192bb1f6db275feab8e8cfef28b9 |
SHA1 | c899f4ae89f38ce5c8d25a2878cef43980930f2b |
SHA256 | 144572ee5214f7289d1f71a44d90eb4ba2ac7d48f6e6b5b166f8ca7fe89afe9c |
File name | Dfk |
File type | Shellcode |
File size | 13.13 Kb |
struct Dfk {
char shellcode[1136];
char egg[10] = { 0x02, 0x06, 0x12, 0x16, 0x22, 0x26, 0x32, 0xA8, 0xB6, 0x3B };
int rc4_key_size = 0x400; // 1024 bytes
char rc4_key[rc4_key_size]; // Ключ RC4 для расшифровки полезной нагрузки
int pe_file_size = 0x2c00;
char pe_file[pe_file_size]; // Полезная нагрузка
}
Перед записью нагрузки расшифровываются первые 1136 байт шелл-кода кастомным алгоритмом (код расшифровки можно найти в Приложении I). Далее с помощью функции NtWriteVirtualMemory происходит запись содержимого Dfk в созданный процесс и передача управления на расшифрованный шелл-код.
В процессе анализа мы заметили интересную особенность: вызов CreateProcessW без установленного флага 0x00000004 (CREATE_SUSPENDED). Таким образом, управление на шелл-код передается в running-потоке и исполняется в штатном режиме, что противоречит документации вызова GetThreadContext из MSDN:
Сам шелл-код расшифровывает уже PE-файл, следующий далее в структуре файла Dfk, с помощью алгоритма RC4 и зашитого ключа длиной 1024 байт
343638440F253B4F60541D332E5C44522B324A466033310D5338405250251E63522A2B42180C14474A16181B5610353B5B163345333B51534A2B400E1D5A4A4D4B26474441272C3E5E1C1F1A4E3722565951543B0C3B5A4541424516524B5237235B480E4A2A114D5360450E353B16551B45291B3A4A521B145B1512620B57441B3B33360C3D3D2F46294340142F1D3111240F47232A0D2322234A11160C214E192A12203060344D220C1D32571830251047315360362B1E3A1B2622333B12634248123A283B4E3A48452E5A3B525427190B2112390E0D3F522A22291A4D32281C2A45352B1C604D3B455E2D0E185D554E233A1C2C513E3D160C3020101E155D34
На последнем этапе осуществляется подготовка к исполнению расшифрованного файла:
- Резолв необходимых API-вызовов по хешу для дальнейшей загрузки PE в память (LoadLibraryExA, GetProcAddress, VirtualAlloc);
- Выделение RWX секции в памяти текущего процесса под загрузку PE;
- Маппинг секций PE-файла на выделенную память;
- Заполнение таблицы импорта;
- Передача управления на entrypoint PE-файла (MD5: 2e131ee69a4eee238a5353f34a81faed).
Финальная стадия — полезная нагрузка DFKRAT
Как мы отмечали ранее, первый и второй дроппер заметно отличаются друг от друга используемыми техниками, но в конечном счете оба разворачивают на системе один и тот же имплант, названный нами DFKRAT. Его образцы в обоих исследованных нами случаях имели минимальные различия, поэтому рассмотрим функционал DFKRAT на примере одного из них:
MD5 | 2e131ee69a4eee238a5353f34a81faed |
SHA1 | da491c0e1dfdf632c7e03b223d975f1b5c84c63f |
SHA256 | 173ef7cc57507c21606926fbd2f2d8ea1c65fc911585ca857a2865d890be4eff |
C2 | hxxps://mail.inn.demokritos[.]gr/yui/2.7.0/fonts/foot.jsp |
File type | PE32 executable Intel 80386 |
File size | 11 Kb |
Comp. timestamp | 2023-10-12 06:20:23 UTC |
После запуска импланта в памяти целевого процесса устанавливается мьютекс с именем «loasd6asdg6». Если такой мьютекс уже существует, то вредонос завершает работу.
Далее вычисляется уникальный ID жертвы, использующийся при коммуникации с управляющим сервером (С2). Для этого в ключ реестра (HKLM | HKCU):SOFTWARE\Classes\CLSID:CLSID записывается значение, вычисляемое вызовом QueryPerformanceCounter. Данная ветка реестра является перенаправляемой, поэтому при запуске исследуемых сэмплов на системах с архитектурой процессора отличной от x86 актуальной веткой реестра будет: HKCU:SOFTWARE\Classes\WOW6432Node\CLSID:CLSID.
Конечный ID жертвы вычисляется по формуле:
victim_id = HKCU:SOFTWARE\Classes\WOW6432Node\CLSID:CLSID + 0x4C
Вредонос коммуницирует с С2 с помощью POST-запросов, которые формируются по следующему шаблону:
%s?name=%x&id=%08x
Где id – ранее вычисленный ID жертвы, а параметр name характеризует тип запроса к С2 и может принимать следующие значения:
name | Название | Описание |
---|---|---|
1000 | QueryControl | Первичное соединение |
1111 | WriteHost | Получить команду |
1112 | WriteSDat | Отправить результат команды |
Перед отправкой на С2 тело запроса шифруется алгоритмом RC4 на ключе Y%523^%$3fttT3f. Кроме того, используется специфичное значение User-Agent, которое также захардкожено в импланте - Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.04472.106 Safari/537.36.
Перед описанием протокола общения с С2, рассмотрим особенность реализации обертки над функцией Sleep. При расчете времени ожидания используются криптографически случайное значение длиной 4 байта – rnd, генерируемое WinAPI CryptGenRandom(), и два значения, передающиеся аргументами функции-обертки, min_lim и max_lim:
Sleep(min_lim + rnd % (max_lim - min_lim))
Итоговая продолжительность “сна” при такой реализации будет варьироваться в интервале (max_lim, min_lim):
Данная реализация функции Sleep используется для ухода от систематичности обращений (запросы через одинаковые промежутки времени) к С2, которая характерна для различных семейств ВПО. По-видимому, такая техника является попыткой замаскировать сетевую активность импланта от защитных решений.
Для инициализации первичного соединения с С2 имплант отправляет запрос со значением параметра name = 1000:
- Если сервер не вернул данные, то вредонос засыпает на 5-15 минут перед повторной попыткой инициализации.
- Если же данные были получены, то вредонос переходит к отправке следующего типа запроса.
Запрос с параметром name = 1111 информирует сервер о готовности получать команды:
- При успешном соединении с сервером, имплант парсит полученные данные.
В ином случае вызывается Sleep протяженностью 30-60 секунд, после чего запрос повторяется. - Если же после четырех таких попыток соединение с сервером не установлено, то имплант засыпает на 10-20 минут и возвращается к этапу инициализации соединения.
- Если сервер доступен и данные корректно распарсились, то имплант выполняет команду, отправляет результат на С2 и ожидает 1-3 секунды новых данных от сервера. Если сервер не отвечает, он возвращается к этапу инициализации соединения.
Запрос с параметром name = 1112 предназначен для отправки на С2 результата выполненной команды.
Протокол взаимодействия импланта и С2 имеет следующую структуру данных, которая справедлива как для соединений server → host, так и для host → server:
- cmd_number – уникальный идентификатор команды
- cmd_data_size – размер зашифрованных полезных данных
- encr_cmd_data – зашифрованные алгоритмом RC4 полезные данные (имя и содержимое прочитанного\записанного файла, ввод\вывод интерактивного шелла, время ожидания для команды Sleep).
Список команд, которые способен выполнять имплант:
cmd_number | Описание |
---|---|
0x2121 | Запустить интерактивный шелл (cmd.exe) |
0x2122 | Выгрузить файл с сервера в директорию %PUBLIC% |
0x2123 | Загрузить файл на север |
0x2124 | Ждать указанное время |
0x2125 | Завершить работу (ExitProcess) |
Отдельно отметим реализацию команды ожидания (0x2124). Ее выполнение происходит за счет функции Sleep, но вызывается она не один раз с установленным временем сна, а каждую секунду до тех пор, пока заданное количество секунд не истечет. Такая реализация имеет смысл, если процесс сна будет прерываться или состояние контролируется какой-либо переменной и необходимо не блокировать поток. Но в данном случае никаких параметров, кроме счетчика оставшегося времени, не проверяется.
Как видно из списка возможных команд, имплант предоставляет злоумышленнику расширяемые возможности по манипуляциям в атакуемой системе (от эксфильтрации пользовательских данных до потенциальной загрузки с С2 другого ВПО).
I версия – 2022
В ходе расследования мы обнаружили несколько исторических образцов. По всей видимости, они относятся к атакам, произошедшим в 2021-22 годах, которые мы атрибуцируем к тому же кластеру NGC2180. Речь идет о версии импланта DFKRAT, отличающейся от описанной выше, а также о другом механизме его доставки на целевую систему, а именно с помощью загрузки с удаленного сервера.
Загрузчик
В этом случае нам удалось восстановить практически весь процесс kill-chain, который начинается с документа-приманки, по-видимому, присланного жертве на почту:
MD5 | 97cb6c20b98cac47fd2e68049c8ce3e1 |
SHA1 | 8075ba19ebbfc6fdd43aeccf1453b61aaac11ec9 |
SHA256 | 0de1ddd6598e97e4e54ad09fb507e99ebfea4c2d6215b13fe5fd2fee0460499c |
File name | конфиденциальный.docx |
File type | Microsoft Word 2007+ |
File size | 35.99 Kb |
Документ написан на русском языке, но по его содержанию можно предположить, что русский – не родной для его авторов.
Файл документа включает в себя OLE-объект, который активируется при нажатии на изображение. Последнее и предлагается сделать жертве. При активации происходит запуск исполняемого файла, который зашит в OLE-объект. Сам файл представляет собой следующую стадию загрузчика DFKRAT.
Исполняемый файл изначально запускается из директории %TEMP% с именем decrypt.exe
MD5 | e84bdb0848b48148507f53d6dc1eee08 |
SHA1 | f5092196c498a9c30c5a45273d3d37d678132634 |
SHA256 | 16dc482c4bcb1655c7d4d72545425889a732443aaa50ba17378505b16fabb9f6 |
C2 | hxxps://windowscer[.]shop/admin/login[.]php |
Filename | decrypt.exe |
File type | PE32 executable Intel 80386 (downloader) |
File size | 42.5 Kb |
Comp. timestamp | 2022-03-14 05:52:09 UTC |
Запущенный процесс проверяет количество аргументов командной строки и соответствие второго аргумента символу “i”:
- Если проверка не пройдена, то процесс копирует свой файл в “C:\ProgramData\WinKs\vmtoolsd.exe” и перезапускается с новыми аргументами: "C:\ProgramData\WinKs\vmtoolsd.exe i”. А текущий процесс завершает работу.
- Если же командная строка процесса удовлетворяет условиям, то загрузчик переходит к основному функционалу.
Работа загрузчика начинается с формирования POST-запроса по уже знакомому в актуальной версии шаблону:
%s?name=%x&id=%08x
В отличие от актуальной версии DFKRAT, параметр name принимает захардкоженное значение “1473”, а параметр id – заполняется нулями.
Также имеются минимальные различия в используемом User-Agent:
DFKRAT v.2 | Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.04472.106 Safari/537.36 |
Загрузчик v.1 | Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36 |
Сформированный запрос отправляется на C2 с целью получить полезную нагрузку – зашифрованный имплант и шелл-код, расшифровывающий и запускающий его.
Если в ответ от сервера приходят данные, то загрузчик читает их (InternetReadFile) и помещает в ранее выделенную область памяти размером 0x100000 с помощью вызова VirtualAlloc, далее приступает к выполнению полученного шелл-кода, передавая импланту аргументом тот же самый адрес C2.
Еще один обнаруженный загрузчик имеет минимальные отличия от описанного, мы полагаем, что он использовался в аналогичной атаке в 2022 году. Его характеризуют другой С2, отсутствие User-Agent и иная директория для дальнейшего перезапуска: "C:\Users\Public\vmtoolsd.exe"
MD5 | 0aba8aa717171fdcc5f501eded8f685c |
SHA1 | 6ba3cd97f36709c4316c19ef724c80b6109110a6 |
SHA256 | a2f079a1919336c552c4a147e6ab77515734fd51624561342cc2f505697af9c2 |
C2 | hxxps://152.89.244[.]99/admin/login[.]php |
Filename | vmtoolsd.exe |
File type | PE32 executable Intel 80386 |
File size | 42 Kb |
Comp. timestamp | 2022-04-13 03:15:10 UTC |
На момент анализа этой версии С2 были уже недоступны, поэтому получить шелл-код напрямую не удалось. Но в результате поиска в открытых источниках мы смогли получить дамп памяти окружения, в котором содержался PE-имплант первой версии.
Таким образом, цепочка доставки вредоносных компонентов выглядит следующим образом:
Финальная стадия – полезная нагрузка DFKRAT
В ходе нашего исследования в публичных источниках был найден образец, максимально подходящий на роль импланта DFKRAT для загрузчиков первой версии, что также подтверждалось полным соответствием с обнаруженным дампом памяти загрузчика.
MD5 | 7a90445dfb62f5d7b759b48c071b352c |
SHA1 | 804b14241e39eba26a6e6b1d678bb66791de1d2a |
SHA256 | 069f69df3dabe637c552739bd3274234dacf0f68f88fb18868fa43fb97a57bc1 |
File type | PE32 executable Intel 80386 |
File size | 10.5 Kb |
Comp. timestamp | 2021-04-19 14:44:14 UTC |
Примечательно, что согласно временной метке компиляции, он был создан за год до использующих его загрузчиков. Это может говорить о том, что данная версия использовалась достаточно долго и в дикой природе существуют еще более ранние версии средств доставки.
Сравнив функционал данного образца с актуальной версией DFKRAT, мы выяснили, что он имеет тот же набор команд и схожий протокол общения с управляющим сервером, однако есть некоторые минорные отличия. Помимо отсутствия шифрования хранимых строк и другого мьютекса “php5”, в этой версии адрес С2 не захардкожен в импланте, а передается в Entrypoint загрузчиком.
Коммуникация с С2 осуществляется при помощи POST-запросов с использованием шифрования RC4 на том же ключе. Однако ID жертвы передается в теле запроса, а не в параметрах, и выглядит следующим образом:
<CLSID>|<HOST_NAME>|<USER_NAME>|
Параметр запроса name также принимает иные от актуальной версии значения:
- name=1361 – при инициализации первичного соединения с сервером;
- name=1362 – при передаче на С2 результата выполнения команд.
Команды и их идентификаторы совпадают практически полностью, за исключением команды завершения работы импланта. В этом случае помимо остановки процесса, также удаляется собственный исполняемый файл. Для этого создается и выполняется BAT-скрипт с именем исполняемого файла + ".bat" (т.е. ) со следующим содержанием:
schtasks /delete /tn FileUpdate /f
:AAA
del "%s"
if exist "%s" goto AAA
del "%s"
В скрипте удаляется запланированная задача “FileUpdate”, однако в исследованных образцах не было замечено установки задачи с таким именем. Это может говорить о существовании других модулей импланта ITW.
Последнее отличие касается цикла обработки команд. В отличие от актуальной версии в этом образце интервал запросов не является случайным числом, а зашит в код и зависит от ответа управляющего сервера:
- Если сервер вернул ошибку или он недоступен, то повторное соединение будет происходить каждые 10 минут.
- Если сервер доступен, но не вернул данные, то повторное соединение произойдет через 2 секунды. Также добавляется 3 минуты ожидания за каждые две минуты такого простоя.
- Если сервер ответил корректно, то имплант будет опрашивать С2 каждые 2 секунды.
Подводя итоги анализа этой находки, можно отметить, что с переходом к актуальной версии злоумышленники начали эксплуатировать технику DLL Side-Loading и отказались от поэтапной передачи полезной нагрузки с сервера управления на целевую систему, при этом внеся минорные изменения в финальный имплант DFKRAT. Такие действия разработчиков могут быть связаны с попыткой уменьшить вероятность обнаружения вредоносной активности средствами защиты на конечном хосте.
Сетевая инфраструктура
С изменением вредоносов от версии к версии, менялась и инфраструктура группы NGC2180. Анализируя загрузчики первой версии 2022 года, мы идентифицировали два С2 – windowscer[.]shop и 152.89.244[.]99.
Домен windowscer[.]shop был зарегистрирован 2022-03-16, что практически совпадает с датой компиляции использующего его сэмпла – 2022-03-14. Изначально он был оформлен на год, но 2023-03-17 NGC2180 продлили срок действия еще на год:
Domain Name: WINDOWSCER.SHOP
Registry Domain ID: DO6621200-GMO
Registrar WHOIS Server: whois.registrar.eu
Registrar URL: http://www.registrar.eu
Updated Date: 2023-03-17T00:11:38.0Z
Creation Date: 2022-03-16T07:06:28.0Z
Сам домен резолвился в 172.245.93[.]126 на протяжении 5 месяцев (с 2022-03-18 по 2022-08-17). По-видимому, именно в этот период и произошла атака.
Больше внимания привлекают С2 имплантов актуальной версии – iam.ottodigital[.]id и mail.inn.demokritos[.]gr.
Так iam.ottodigital[.]id относится к легитимной инфраструктуре индонезийской компании OttoDigital Group и, скорее всего, был взломан NGC2180 для размещения своей управляющей платформы по адресу:
hxxps://iam[.]ottodigital[.]id/emailotpauthenticationendpoint/css/css[.]jsp
Компрометация легитимного хоста для размещения С2-инфраструктуры позволяет атакующим обходить защитные решения жертвы, которые могут пропускать соединения с серверами из белой зоны.
Сложно выделить точный таймфрейм, когда происходила эта атака, так как обычные кроулеры не сканируют так глубоко. Но по состоянию на 2023-11-17 управляющий сервер уже был недоступен. О чем свидетельствуют данные одного публичного сервиса. Образец, использующий этот С2, был скомпилирован за три месяца до этого 2023-08-10.
Ситуация со вторым С2 – mail.inn.demokritos[.]gr – аналогична. Для координации работы импланта использовался скомпрометированный компонент сервера Института нанонауки и нанотехнологий Национального центра научных исследований «Демокрит» в Греции:
hxxps://mail.inn.demokritos[.]gr/yui/2.7.0/fonts/foot[.]jsp
На момент исследования, в декабре 2023 года, этот путь уже был недоступен, поэтому временное окно для атаки в этом случае было еще уже, т.к. использующий его имплант был скомпилирован в октябре того же года.
Отметим высокий уровень работы NGC2180 со своей инфраструктурой: она функционирует ограниченный промежуток времени, по-видимому, только до достижения целей атаки, не переиспользуется и практически никак не пересекается между собой, что делает процесс поиска других ее элементов затруднительным.
Управляющий сервер
В ходе нашего исследования мы обнаружили в публичном пространстве фрагмент JavaServer Pages (JSP) кода, который с высокой долей вероятности является частью инфраструктуры управляющего сервера DFKRAT.
MD5 | eeb1f109fc8185cfe9fb5393a0b6335b |
SHA1 | 051d4e42f2aff932f7e97355d1e9f6332fc9fa8c |
SHA256 | 92c942ba2f010153a2929934946878151a2145f705e45c153c2855baf2e3ab9a |
File name | config.jsp |
File size | 7.2 Kb |
First seen | 2024-01-03 12:26:53 UTC |
В коде имеются явные пересечения с тем, что мы видели в образцах DFKRAT. В частности, использование того же самого RC4-ключа:
Особый интерес вызывает обнаруженный список возможных запросов к С2. Он частично пересекается с тем, что мы видели в имплантах актуальной версии 2023 года (1000, 1111, 1112), но, кроме этого, имеются неизвестные типы запросов (1222, 1223). Это еще раз подчеркивает версионированность этого ВПО, а также указывает на потенциальное существование большего количества образцов ITW.
Согласно данным одного публично сервиса, файл был загружен туда 2024-01-03 под именем config.jsp с IP-адреса Саудовской Аравии. Исходя из анализа сетевой инфраструктуры, вероятно, это была промежуточная жертва, сервер которой скомпрометировали с целью размещения на нем С2.
Заключение
Мы с высокой уверенностью атрибутируем все найденные образцы к одной группе, временно названной нами NGC2180. Многочисленные пересечения в используемых ключах шифрования, значениях User-Agent и протоколе общения с С2 не оставляют в этом сомнений. Пока сложно говорить о конкретном регионе происхождения группы. Мы отметили несколько индикаторов вроде использования техники DLL side-loading, но их недостаточно, чтобы выносить однозначный вердикт.
Нам удалось проследить активности NGC2180 за последние 3 года, что говорит о персистентном характере этого кластера. Компрометация легитимных серверов для развертывания инфраструктуры С2, а также нацеленность NGC2180 на организации высокого ранга указывают на системный подход и возможную политическую мотивацию группы.
На основании анализа фрагмента С2 мы полагаем, что существует еще больше ITW-образцов, относящихся к описанному кластеру, поэтому призываем сообщество воспользоваться индикаторами, приведенными в этом исследовании, для их поиска.
А если вы столкнулись с признаками компрометации, сообщите об этом нашей команде Solar 4RAYS. Мы поможем выявить инцидент и ограничить его распространение, а также защитить вашу инфраструктуру от подобных атак в будущем.
IOCs
File hashes
97cb6c20b98cac47fd2e68049c8ce3e1 - ver.1 Delivery Doc
e84bdb0848b48148507f53d6dc1eee08 - ver.1 Downloader
0aba8aa717171fdcc5f501eded8f685c - ver.1 Downloader
7a90445dfb62f5d7b759b48c071b352c - ver.1 Payload
bb64fcb014d913b92975fccd5fa3e9b1 - ver.2 Dropper
1da3ce8c4267bf982e43472a08fa2ca1 - ver.2 Dropper
8ce681f1c9ddf69a4ad4d53de57e404f - ver.2 Payload
2e131ee69a4eee238a5353f34a81faed - ver.2 Payload
C2
windowscer[.]shop - ver.1
152.89.244[.]99 - ver.1
hxxps://iam[.]ottodigital[.]id/emailotpauthenticationendpoint/css/css[.]jsp - ver.2
hxxps://mail[.]inn.demokritos[.]gr/yui/2.7.0/fonts/foot[.]jsp - ver.2
Mutexes
loasd6asdg6
php5
Yara
rule NGC2180_DFKRAT {
meta:
description = "DFKRAT payload and downloader v.1"
author = "Solar 4RAYS"
md5 = "e84bdb0848b48148507f53d6dc1eee08"
md5 = "7a90445dfb62f5d7b759b48c071b352c"
md5 = "8ce681f1c9ddf69a4ad4d53de57e404f"
strings:
$u1 = "Y%523^%$3fttT3f" fullword ascii
$u2 = "schtasks /delete /tn FileUpdate /f\r\n:AAA\r\ndel \"%s\"\r\nif exist \"%s\" goto AAA\r\ndel \"%s\"\r\n" fullword ascii
$s1 = "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.04472.106 Safari/537.36"
$s2 = "%s?name=%x&id=%08x" fullword ascii
$s3 = "C:\\ProgramData\\WinKs" fullword ascii
$s4 = "loasd6asdg6" fullword ascii
$s5 = "%08x|%s|%s|" fullword ascii
$s6 = "%s?name=%x&id=%08x" fullword ascii
condition:
uint16(0) == 0x5A4D and (
any of ($u*) or
2 of ($s*)
)
}
rule NGC2180_DFKRAT_dropper {
meta:
description = "DFKRAT dropper v2"
author = "Solar 4RAYS"
md5 = "bb64fcb014d913b92975fccd5fa3e9b1"
strings:
$s_1 = "Awesome 4K" ascii
$s_2 = "width" ascii fullword
$s_3 = "height" ascii fullword
$s_4 = "resolutions" ascii fullword
$s_5 = "Checking monitor \"%s\"\n" ascii fullword
$s_6 = "Error before: %s\n" ascii fullword
$imp_f_hash_0 = { 37 CC 8D 12 }
$imp_f_hash_1 = { C0 CE 5E CD }
$imp_f_hash_2 = { 91 34 0E 14 }
$imp_f_hash_3 = { 73 15 93 0D }
$imp_f_hash_4 = { BC E3 0C AF }
$imp_f_hash_5 = { 1B 03 95 05 }
condition:
uint16(0) == 0x5A4D and (
(3 of ($imp_f_hash*) and 3 of ($s*)) or
(all of ($imp_f_hash*))
)
}
Приложение I
Алгоритм поиска функций из NTDLL дроппером #1.
def find_func_by_hash(hash_to_find):
ntdll = lief.PE.parse("ntdll.dll")
funcs = [(func, custom_hash_algo(func.name))
for func in ntdll.exported_functions
if func.name[:2] == "Zw"]
funcs = sorted(funcs, key=lambda x: x[0].address)
for i, (f, h) in enumerate(funcs):
if hash_to_find == h:
return i
return -1
Расшифровка первых 1136 байт шелл-кода из файла Dfk дроппером #2.
with open(r"Dfk", 'rb') as f:
data = f.read()
dec_data = bytearray(data)
i = 0
for i, v in enumerate(data[:1136]):
if i % 3:
if i % 3 == 1:
dec_data[i] = ((i+42) & 0xFF) ^ v
else:
dec_data[i] = ((i-25) & 0xFF) ^ v
else:
dec_data[i] = ((i-51) & 0xFF) ^ v
i += 1
with open(r"dec_data.bin", 'wb') as f:
f.write(dec_data)