D2
Администратор
- Регистрация
- 19 Фев 2025
- Сообщения
- 4,380
- Реакции
- 0
В декабре 2023 года, в ходе постоянного отслеживания новых угроз ИБ, изучая в PT Sandbox и других песочницах вредоносные образцы и генерируемый ими трафик, мы обнаружили подозрительное сетевое взаимодействие, с которого наше дальнейшее исследование и началось. Надо сказать, обратили мы внимание на это еще и благодаря внезапно увеличившемуся количеству похожих семплов. Сами злоумышленники, видимо призрачно надеясь на убедительность, назвали в коде свой троян удаленного действия SafeRAT, с именованием которого мы, конечно, не согласны, но довольно спойлеров! Ниже мы постарались детально описать вредонос, который ранее исследователям не встречался, чтобы показать его НЕбезопасность.
Предполагаем, что код загрузки взят из примера MSDN, поскольку в некоторых семплах используется User-Agent:WinHTTP Example/1.0.
Загрузчики незначительно различаются между собой, однако их функции идентичны. Ознакомиться подробнее с хешами можно в блоке «Индикаторы компрометации. Загрузчики».
Значение User-Agent не всегда такое, как на скриншоте выше. Например, мы встречали такие User‑Agent, как
Далее исполнение стартует с 0-го байта.
Шеллкод получает свой адрес с помощью простого выражения.
В конце шеллкода указаны адрес C2 и порт, как выделено на скриншоте выше. Они хранятся в следующем виде:
Код: Скопировать в буфер обмена
После этого шеллкод получает адреса API-функций с помощью кастомного алгоритма хеширования их имен:def hash_exp(name, poly):
Код: Скопировать в буфер обмена
В процессе исследования мы столкнулись с двумя последовательными шеллкодами, имеющими как похожие функции, так и различия.
Шеллкод загружает библиотеку ws2_32.dll, а также получает адрес ее функции для создания сокета (TCP) и запроса шеллкода следующего этапа. Для этого отправляет следующий пакет на тот адрес C2, который зашит в конце шеллкода.
Первый DWORD — это длина пакета, далее следует захардкоженная строка efaSnigoL (перевернутая строка LoginSafe).
В ответ на этот пакет приходит шеллкод второго этапа, которому передается управление. Также шеллкод № 1 передает шеллкоду № 2 адрес C2.
Назначение шеллкода — загрузка PE-модуля, который располагается после самого шеллкода.
После загрузки модуля шеллкод находит в таблице экспорта функцию Online и передает ей управление.
После этого модуль избавляется от перехватов библиотечных функций, которые могли быть установлены антивирусом или XDR-системой.
Суть метода состоит в том, что бинарный файл с помощью CreateFileMappingA отображает в памяти файл библиотеки из системной директории, затем устанавливает на секцию TEXT загруженного в процесс модуля права RWX и перезаписывает секцию в модуле содержимым отображенного файла — чтобы содержание модуля соответствовало файлу. После этого возвращаются ранее установленные права на секцию.
Среди других функций
Упомянутое выше новое значение сервера хранится в параметре
Основные функции семпла выполняются в отдельном потоке, который создается из функции Online. В начале этого потока создается объект класса CClientSocket, который отвечает за сетевое взаимодействие.
Стоит отметить, что в этом объекте есть несколько вложенных объектов класса CBuffer, который предоставляет динамический буфер для хранения отправляемых и принимаемых данных. Далее объект клиента подключается к серверу по TCP. Прием и обработка входящих пакетов выполняются в отдельном потоке. Следующим этапом становится создание объекта класса CKernelManager, который наследуется от класса CManager и служит своего рода оркестратором для рабочих потоков и плагинов, получаемых от C2. В конструкторе CKernelManager создается отдельный поток, отвечающий за работу кейлоггера. Причем получение данных с клавиатуры выполняется через интерфейс IDirectInput8A и устройство SysKeyboard.
После этого семпл собирает начальную информацию о системе для отправки на сервер. В нее входят:
Код: Скопировать в буфер обмена
Данные о системе отправляются на сервер. Для этого они сжимаются Zlib и шифруются RC4. Для шифрования генерируется случайный ключ с помощью
Структуру пакета клиента можно представить следующим образом:
Код: Скопировать в буфер обмена
Стоит отметить, что указывается длина разжатого пейлоада в переменной
Расшифрованную сессию можно посмотреть в «Кибершефе».
После расшифровки и распаковки пакета от сервера семпл проверяет нулевой байт, в котором содержится идентификатор команды (в данном случае
Судя по именам классов (CKernelManager, CClientSocket) и общей архитектуре кода, можно сделать вывод, что SafeRAT — это очередная поделка, основанная на утекших исходниках Gh0st, только с урезанной функциональностью.
Автор Ксения Наумова, Антон Белоусов
Источник habr.com
Загрузчик
Каждый загрузчик представляет собой довольно простой бинарный файл формата PE (EXE) с единственной функцией. Загрузчик распространяется по почте в письмах с расширением .bat. Оказавшись на компьютере жертвы, загрузчик с помощью функций библиотеки WinHTTP обращается к зашитому внутри него удаленному серверу (C2) за получением дополнительной полезной нагрузки следующего этапа.
Предполагаем, что код загрузки взят из примера MSDN, поскольку в некоторых семплах используется User-Agent:WinHTTP Example/1.0.

Загрузчики незначительно различаются между собой, однако их функции идентичны. Ознакомиться подробнее с хешами можно в блоке «Индикаторы компрометации. Загрузчики».
Шеллкод
64-битный шеллкод отдается C2 в ответ на GET-запрос /payload.bin в открытом виде.
Значение User-Agent не всегда такое, как на скриншоте выше. Например, мы встречали такие User‑Agent, как
Chromium, Google, souhu, sougou, File Downloader, baidu, cpp-httplib/0.14.3, ShellcodeDownloader, python-requests/2.25.1, Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)
Далее исполнение стартует с 0-го байта.

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

В конце шеллкода указаны адрес C2 и порт, как выделено на скриншоте выше. Они хранятся в следующем виде:
Код: Скопировать в буфер обмена
Код:
struct C2 {
uint32_t port;
char addr[256];
};
Код: Скопировать в буфер обмена
Код:
def hash_exp(name, poly):
result = poly
for i in range(len(name)):
result = (result * 0x21) & 0xFFFFFFFFFFFFFFFF
v = struct.unpack_from('<b', name, i)[0]
i += 1
result += v
return result
Шеллкод № 1 (payload.bin)
В этом шеллкоде параметр poly равен0x85967AEFDADF5658
. Он находит следующие функции из ntdll
:LdrLoadDll (0xD33201CB07BB2036)
RtlInitUnicodeString (0x4E80BBE9CCE6585C)
NtAllocateVirtualMemory (0xD1A4739FEC736F3F)
Шеллкод загружает библиотеку ws2_32.dll, а также получает адрес ее функции для создания сокета (TCP) и запроса шеллкода следующего этапа. Для этого отправляет следующий пакет на тот адрес C2, который зашит в конце шеллкода.

Первый DWORD — это длина пакета, далее следует захардкоженная строка efaSnigoL (перевернутая строка LoginSafe).

В ответ на этот пакет приходит шеллкод второго этапа, которому передается управление. Также шеллкод № 1 передает шеллкоду № 2 адрес C2.

Шеллкод № 2
Второй шеллкод вначале также получает адреса API-функции из ntdll по тому же хеш-алгоритму, что и первый, только в этом случае используется следующее значение poly:0x8596741254585658
.Назначение шеллкода — загрузка PE-модуля, который располагается после самого шеллкода.

После загрузки модуля шеллкод находит в таблице экспорта функцию Online и передает ей управление.
Основной модуль
Модуль является x64 DLL с единственным экспортом — Online. Дата и время компиляции (из заголовка) — 05.11.2023 03:00:19. Имя библиотеки в таблице экспорта —online.dll
.Online
Вначале создается событие Global\safeRat — именно по нему мы и дали впоследствии название вредоносу.
После этого модуль избавляется от перехватов библиотечных функций, которые могли быть установлены антивирусом или XDR-системой.

Суть метода состоит в том, что бинарный файл с помощью CreateFileMappingA отображает в памяти файл библиотеки из системной директории, затем устанавливает на секцию TEXT загруженного в процесс модуля права RWX и перезаписывает секцию в модуле содержимым отображенного файла — чтобы содержание модуля соответствовало файлу. После этого возвращаются ранее установленные права на секцию.
Среди других функций
Online
:- установка обработчика исключений верхнего уровня, единственная задача которого состоит в том, чтобы перезапустить процесс в случае необрабатываемого исключения;
- поиск адреса функции
NtTraceEvent
и патчинг первого байта этой функции на 0xC3 (ret), чтобы от вредоносного процесса не регистрировались ETW-события для EDR-системы и других средств защиты; - поиск и сохранение номера syscall NtQueryInformationProcess для дальнейшего использования;
- создание путей для файлов wallet.safe и clip.safe в директории
C:\ProgramData
(файлclip.safe
— для сохранения содержимого буфера обмена, а файлwallet.safe
— для результатов работы кейлоггера); - считывание из реестра сохраненного адреса C2 (в дальнейшем семпл может запросить у текущего сервера новый адрес и сохранить его в реестре, но вначале это значение отсутствует);
- хранение адреса C2 и других значений по пути
HKCU\Software\<computer_name>
(если имя компьютера получить не удалось, то вместо него используется строкаUnKnow
).

Упомянутое выше новое значение сервера хранится в параметре
Mov
, закодированное base64 и зашифрованное побайтным XOR (0x46
).
Основные функции семпла выполняются в отдельном потоке, который создается из функции Online. В начале этого потока создается объект класса CClientSocket, который отвечает за сетевое взаимодействие.
Стоит отметить, что в этом объекте есть несколько вложенных объектов класса CBuffer, который предоставляет динамический буфер для хранения отправляемых и принимаемых данных. Далее объект клиента подключается к серверу по TCP. Прием и обработка входящих пакетов выполняются в отдельном потоке. Следующим этапом становится создание объекта класса CKernelManager, который наследуется от класса CManager и служит своего рода оркестратором для рабочих потоков и плагинов, получаемых от C2. В конструкторе CKernelManager создается отдельный поток, отвечающий за работу кейлоггера. Причем получение данных с клавиатуры выполняется через интерфейс IDirectInput8A и устройство SysKeyboard.

После этого семпл собирает начальную информацию о системе для отправки на сервер. В нее входят:
- IP-адрес зараженного устройства,
- имя компьютера,
- имя пользователя,
- PID вредоносного процесса,
- список установленных антивирусов,
- статус пользователя (является ли он администратором),
- разность тиков процессора:
GetTickCount64 − GetTickCount64()
(вероятно, для проверки работы в ВМ), - локальное время.
Код: Скопировать в буфер обмена
Код:
#pragma pack(push, 1)
struct system_info
{
char sz;
char host_ip_addr[130];
char reg_remark_or_comp_name[50];
char username[51];
uint32_t curr_pid;
char gap_EC[64];
char AVs[128];
char reg_cfg_Group_val;
char gap_1AD[63];
char is_admin;
char module_filename[255];
char reg_cfg_Run_val[3];
char gap_2EF[5];
uint32_t ticks_diff;
SYSTEMTIME localtime;
};
#pragma pack(pop)
rand % 511
. Либо задается как 123. Далее это число форматируется в виде строки и используется для RC4.
Структуру пакета клиента можно представить следующим образом:
Код: Скопировать в буфер обмена
Код:
struct packet
{
uint32_t key;
uint32_t packet_size;
uint32_t payload_size;
uint8_t payload[payload_size];
};
payload_size
. От C2 приходит пакет аналогичной структуры, за исключением того, что поля key и packet_size поменяны местами, то есть размер пакета содержится в нулевом DWORD, а ключ — в первом. В трафике это выглядит следующим образом:
Расшифрованную сессию можно посмотреть в «Кибершефе».
После расшифровки и распаковки пакета от сервера семпл проверяет нулевой байт, в котором содержится идентификатор команды (в данном случае
0e
). Обработку команд выполняет объект CKernelManager
. В ответ клиент посылает серверу отстук в виде той же самой команды.
Идентификатор команды | Описание |
0 | Разлогинивает текущего пользователя Windows |
2 | Устанавливает флаг завершения работы |
3 | Сохраняет в реестре новое значение параметра Remark |
4 | Сохраняет в реестре новое значение параметра Group |
6–12, 14–17, 19–21, 25, 32–34 | Запускает плагин (номер команды — идентификатор плагина) |
13 | Вызывает BSOD с помощью NtRaiseHardError, предварительно получив привилегию SeShutdownPrivilege |
18 | Запускает поток клиппера (стилер буфера обмена) |
22 | Обновляет C2 |
23 | Запускает кейлоггер |
24 | Запускает поток клиппера (стилер буфера обмена) |
26–31 | Получает и запускает новый модуль |
35 | Сохраняет в реестре новое значение параметра Run |
36–42 | В зависимости от номера команды стилер похищает данные: · QQBrowser, · Telegram, · Chrome, · Firefox, · 360 Secure Browser, · Sogou Explorer |
Заключение
Исходя из оригинального имени в сервисе VirusTotal и некоторых целей SafeRAT (Sogou, 360 Secure Browser, QQBrowser), предполагаем, что вредонос рассчитан на китайскоговорящих пользователей.Судя по именам классов (CKernelManager, CClientSocket) и общей архитектуре кода, можно сделать вывод, что SafeRAT — это очередная поделка, основанная на утекших исходниках Gh0st, только с урезанной функциональностью.
Автор Ксения Наумова, Антон Белоусов
Источник habr.com