В конце 2023 года команда Solar 4RAYS в рамках проведения Compromise Assessment обнаружила атаку на один из органов исполнительной власти. Мы выявили образцы многоступенчатого ВПО, которое на финальной стадии разворачивает на целевой системе имплант, названный нами DFKRAT. Разработанный в шпионских целях вредонос позволяет атакующим, среди прочего, похищать данные из файловой системы жертвы. Мы провели расширенное исследование и нашли другие образцы, отличающиеся технически, но используемые той же группой злоумышленников на протяжении 2021–2023 годов против русскоязычных целей. В настоящий момент мы не можем отнести кластер этой активности к какой-либо известной группировке, поэтому обозначили его как NGC2180. В статье мы подробно опишем найденное ВПО и приведем индикаторы компрометации.

Краткое содержание отчета

  • Мы обнаружили шпионский имплант DFKRAT на системах одного из заказчиков в конце 2023 года.
  • В открытых источниках были найдены и другие версии этого ВПО и прослежена их эволюционная цепочка с 2021 года, кластер этой активности мы назвали NGC2180.
  • Первичный вектор заражения в случае ранних версий, по всей видимости — таргетированное фишинговое письмо, начиненное загрузчиком. В последних версиях вектор остался неизвестным.
  • Вредоносная активность осуществляется полезной нагрузкой, которая доставляется загрузчиками в более ранних версиях и дропперами, эксплуатирующими DLL side-loading, — в последних.
  • Ключевой функционал DFKRAT -— эксфильтрация файлов, поддержка интерактивного шелла, потенциальная загрузка дополнительного ВПО с сервера управления С2.
  • В качестве С2 для актуальной версии имплантов использовались скомпрометированные серверы Национального центра научных исследований в Греции и индонезийской компании.
  • Нам удалось найти и проанализировать фрагмент управляющего сервера.

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

таймлайн основных событий кластера ngc2180
Таймлайн основных событий кластера NGC2180

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
Файл Dfk имеет следующую структуру:
	
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.

Screenshot 2024-02-05 at 14.25.34.png
Адрес С2, RC4 ключ и User-Agent, захардкоженные в DFKRAT

Перед описанием протокола общения с С2, рассмотрим особенность реализации обертки над функцией Sleep. При расчете времени ожидания используются криптографически случайное значение длиной 4 байта – rnd, генерируемое WinAPI CryptGenRandom(), и два значения, передающиеся аргументами функции-обертки, min_lim и max_lim:

Sleep(min_lim + rnd % (max_lim - min_lim))

Итоговая продолжительность “сна” при такой реализации будет варьироваться в интервале (max_lim, min_lim):

mw_random_sleep.PNG
Функция-обертка Sleep

Данная реализация функции 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

Документ написан на русском языке, но по его содержанию можно предположить, что русский – не родной для его авторов.

doc.png
Содержимое документа-приманки

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

oleObj1.png
Исполняемый файл внутри OLE-объекта

Исполняемый файл изначально запускается из директории %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”. А текущий процесс завершает работу.
  • Если же командная строка процесса удовлетворяет условиям, то загрузчик переходит к основному функционалу.
process_tree.PNG
Цепочка порождаемых процессов

Работа загрузчика начинается с формирования 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
СnC_UA.PNG
User-Agent и C2 захардкожены в загрузчик

Сформированный запрос отправляется на 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-ключа:

Screenshot 2024-02-01 at 11.58.23.png
Использование уникального RC4-ключа в инфраструктуре С2

Особый интерес вызывает обнаруженный список возможных запросов к С2. Он частично пересекается с тем, что мы видели в имплантах актуальной версии 2023 года (1000, 1111, 1112), но, кроме этого, имеются неизвестные типы запросов (1222, 1223). Это еще раз подчеркивает версионированность этого ВПО, а также указывает на потенциальное существование большего количества образцов ITW.

Screenshot 2024-02-01 at 12.06.08.png
Варианты различных запросов на С2, обнаруженные в серверной части DFKRAT

Согласно данным одного публично сервиса, файл был загружен туда 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)