Автор doctorweb
источник https://news.drweb.ru
источник https://news.drweb.ru
В конце прошлого года в нашу лабораторию за помощью обратилась зарубежная телекоммуникационная компания, сотрудники которой обнаружили в корпоративной сети подозрительные файлы. В ходе поиска следов вредоносной активности аналитики выявили образец весьма интересного бэкдора. Его анализ показал, что мы имеем дело с очередным модульным APT-бэкдором, использующимся хакерской группой Winnti.
Последний раз деятельность Winnti попадала в наше поле зрения, когда мы анализировали модификации бэкдоров ShadowPad и PlugX в рамках расследования атак на государственные учреждения стран Центральной Азии. Оба эти семейства оказались схожи концептуально и имели примечательные пересечения в коде.
В сегодняшней статье мы разберем бэкдор Spyder — именно так окрестили найденный вредоносный модуль наши вирусные аналитики. Мы рассмотрим алгоритмы и особенности его работы и выявим его связь с другими известными инструментами APT-группы Winnti.
Чем примечателен Spyder
Вредоносный модуль представляет собой DLL-библиотеку, которая на зараженном устройстве располагалась в системной директории C:\Windows\System32 под именем oci.dll. Таким образом, модуль был подготовлен для запуска системной службой MSDTC при помощи метода DLL Hijacking. По нашим данным, файл попал на компьютеры в мае 2020 года, однако способ первичного заражения остался неизвестным. В журналах событий мы обнаружили записи о создании служб, предназначенных для старта и остановки MSDTC, а также для исполнения бэкдора.
Код:
Log Name: System
Source: Service Control Manager
Date: 23.11.2020 5:45:17
Event ID: 7045
Task Category: None
Level: Information
Keywords: Classic
User:
Computer:
Description:
A service was installed in the system.
Service Name: IIJVXRUMDIKZTTLAMONQ
Service File Name: net start msdtc
Service Type: user mode service
Service Start Type: demand start
Service Account: LocalSystem
Код:
Log Name: System
Source: Service Control Manager
Date: 23.11.2020 5:42:20
Event ID: 7045
Task Category: None
Level: Information
Keywords: Classic
User:
Computer:
Description:
A service was installed in the system.
Service Name: AVNUXWSHUNXUGGAUXBRE
Service File Name: net stop msdtc
Service Type: user mode service
Service Start Type: demand start
Service Account: LocalSystem
Интересной находкой стала служба, свидетельствующая об использовании утилиты для удаленного исполнения кода smbexec.py из состава набора Impacket. С её помощью злоумышленники организовали удаленный доступ к командной оболочке в полуинтерактивном режиме.
Исследуемый вредоносный модуль oci.dll был добавлен в вирусную базу Dr.Web как BackDoor.Spyder.1. Это название пришло к нам из артефактов бэкдора. В одном из найденных образцов остались функции ведения отладочного журнала и сами сообщения, при этом те из них, которые использовались при коммуникации с управляющим сервером, содержали строку «Spyder».
Бэкдор примечателен рядом интересных особенностей. Во-первых, oci.dll содержит основной PE-модуль, но с отсутствующими файловыми сигнатурами. Заполнение сигнатур заголовка нулями предположительно было сделано с целью затруднения детектирования бэкдора в памяти зараженного устройства. Во-вторых, полезная нагрузка сама по себе не несет вредоносной функциональности, но служит загрузчиком и координатором дополнительных плагинов, получаемых от управляющего сервера. С помощью этих подключаемых плагинов бэкдор выполняет основные задачи. Таким образом, это семейство имеет модульную структуру, как и другие семейства бэкдоров, используемые Winnti, — упомянутые ранее ShadowPad и PlugX.
Анализ сетевой инфраструктуры Spyder выявил связь с другими атаками Winnti. В частности инфраструктура, используемая бэкдорами Crosswalk и ShadowPad, описанными в исследовании Positive Technologies, перекликается с некоторыми образцами Spyder. График ниже наглядно показывает выявленные пересечения.
Пожалуйста, масштабируйте страницу для чтения надписей, спасибо
Принцип действия
Бэкдор представляет собой вредоносную DLL-библиотеку. Имена функций в таблице экспорта образца дублируют экспортируемые функции системной библиотеки apphelp.dll.
Функционально образец является загрузчиком для основной полезной нагрузки, которую хранит в секции .data в виде DLL, при этом некоторые элементы DOS и PE заголовков равны нулю.
Работа загрузчика
Загрузка выполняется в функции, обозначенной как malmain_3, вызываемой из точки входа DLL через две промежуточные функции-переходника.
Далее следует стандартный процесс загрузки PE-модуля в память и вызов точки входа загруженного модуля (DllMain) с аргументом DLL_PROCESS_ATTACH, а после выхода из нее — повторный вызов с DLL_PROCESS_DETACH.
Работа основного модуля
В основном модуле значения всех сигнатур, необходимых для корректной загрузки файла, приравнены к нулю.
- IMAGE_DOS_HEADER.e_magic
- IMAGE_NT_HEADERS64.Signature
- IMAGE_NT_HEADERS64.FileHeader.Magic
Анализ основного модуля затруднен, так как периодически используются нетипичные способы вызова функций. Для хранения и обработки структур используется библиотека UT hash. Она позволяет преобразовывать стандартные C-структуры в хеш-таблицы путем добавления одного члена типа ut_hash_handle. При этом все функции библиотеки, такие как добавление элементов, поиск, удаление и т. д., реализованы в виде макросов, что приводит к их принудительному разворачиванию и встраиванию (inline) компилятором в код основной (вызывающей) функции.
Для взаимодействия с управляющим сервером используется библиотека mbedtls.
Функция DllMain
В начале исполнения проверяется наличие события Global\\BFE_Notify_Event_{65a097fe-6102-446a-9f9c-55dfc3f45853}, режим исполнения (из конфигурации) и командная строка, затем происходит запуск рабочих потоков.
Модуль имеет встроенную конфигурацию следующей структуры:
Код:
struct cfg_c2_block
{
int type;
char field_4[20];
char addr[256];
}
struct cfg_proxy_data
{
DWORD dw;
char str[256];
char proxy_server[256];
char username[64];
char password[32];
char unk[128];
};
struct builtin_config
{
int exec_mode;
char url_C2_req[100];
char hash_id[20];
char string[64];
char field_BC;
cfg_c2_block srv_1;
cfg_c2_block srv_2;
cfg_c2_block srv_3;
cfg_c2_block srv_4;
cfg_proxy_data proxy_1;
cfg_proxy_data proxy_1;
cfg_proxy_data proxy_1;
cfg_proxy_data proxy_1;
int CA_cert_len;
char CA_cert[cert_len];
};
Поле string содержит строку из одного символа: 1.
CA_cert — сертификат центра сертификации в формате DER. Он используется для установки соединения с управляющим сервером по протоколу TLS 1.2.
В функции DllMain предусмотрено создание нескольких рабочих потоков в зависимости от ряда условий.
- Основной поток — thread_1_main
- Поток запроса нового сервера — thread_2_get_new_C2_start_communication
- Поток исполнения зашифрованного модуля — thread_4_execute_encrypted_module
Вначале бэкдор проверяет версию ОС, затем подготавливает структуру для инициализации функций и структуру для хранения некоторых полей конфигурации. Процедура выглядит искусственно осложненной.
В структуру funcs_struc типа funcs_1 заносятся 3 указателя на функции, которые будут поочередно вызваны внутри функции init_global_funcs_and_allocated_cfg.
В функции set_global_funcs_by_callbacks происходит вызов каждой функции-инициализатора по очереди.
Общий порядок формирования структур выглядит следующим образом:
1) каждой функции передаются две структуры: первая содержит указатели на некоторые функции, вторая — пустая;
2) каждая функция переносит указатели на функции из одной структуры в другую;
3) после вызова функции-инициализатора происходит очередное перемещение указателей на функции из локальной структуры в глобальный массив структур по определенному индексу.
В итоге после всех нестандартных преобразований получается некоторое количество глобальных структур, которые объединены в один массив.
В конечном итоге вызов функций можно представить следующим образом.
Сложные преобразования — копирование локальных структур с функциями и их перенос в глобальные структуры — вероятно, призваны усложнить анализ вредоносного образца.
Затем бэкдор при помощи библиотеки UT hash формирует хеш-таблицу служебных структур, ответственных за хранение контекста сетевого соединения, параметров подключения и т. д.
Фрагмент кода формирования хеш-таблицы.
Стоит отметить, что здесь располагается значение сигнатуры, которое позволяет определить используемую библиотеку: g_p_struc_10->hh.tbl->signature = 0xA0111FE1;.
Для рассматриваемого бэкдора характерно распределение значимых полей и данных по нескольким создаваемым для этого структурам. Эта особенность при анализе затрудняет создание осмысленных имен для структур.
После подготовительных действий переходит к инициализации подключения к управляющему серверу.
Инициализация соединения с управляющим сервером
После ряда подготовительных действий бэкдор разрешает хранящийся в конфигурации адрес управляющего сервера и извлекает порт. Адреса в конфигурации хранятся в виде строк: koran.junlper[.]com:80 и koran.junlper[.]com:443. Далее программа создает TCP-сокет для подключения. После этого создает контекст для защищенного соединения и выполняет TLS-рукопожатие.
После установки защищенного соединения бэкдор ожидает от управляющего сервера пакет с командой. Программа оперирует двумя форматами пакетов:
- пакет, полученный после обработки протокола TLS, — «транспортный» пакет»;
- пакет, полученный после обработки транспортного пакета, — «пакет данных». Содержит идентификатор команды и дополнительные данные.
Код:
struct transport_packet_header
{
DWORD signature;
WORD compressed_len;
WORD uncompressed_len;
};
После распаковки полученный пакет данных имеет заголовок следующего формата.
Код:
struct data_packet_header
{
WORD tag;
WORD id;
WORD unk_0;
BYTE update_data;
BYTE id_part;
DWORD unk_1;
DWORD unk_2;
DWORD len;
};
Данные структуры заголовков используются в обоих направлениях взаимодействия.
Порядок обработки команд сервера:
- верификация клиента;
- отправка информации о зараженной системе;
- обработка команд по идентификаторам.
Этап верификации
Для выполнения этапа верификации значения полей tag и id в полученном от управляющего сервера первичном пакете должны быть равны 1.
Процесс верификации состоит в следующем:
1. Бэкдор формирует буфер из 8-байтного массива, который следует после заголовка пакета и поля hash_id, взятого из конфигурации. Результат можно представить в виде структуры:
Код:
struct buff
{
BYTE packet_data[8];
BYTE hash_id[20];
}
Отправка информации о системе
Следующий полученный пакет от управляющего сервера должен иметь значения tag, равное 5, и id, равное 3. Данные о системе формируются в виде структуры sysinfo_packet_data.
Код:
struct session_info
{
DWORD id;
DWORD State;
DWORD ClientBuildNumber;
BYTE user_name[64];
BYTE client_IPv4[20];
BYTE WinStationName[32];
BYTE domain_name[64];
};
struct sysinfo_block_2
{
WORD field_0;
WORD field_2;
WORD field_4;
WORD system_def_lang_id;
WORD user_def_lang_id;
DWORD timezone_bias;
DWORD process_SessionID;
BYTE user_name[128];
BYTE domain_name[128];
DWORD number_of_sessions;
session_info sessions[number_of_sessions];
};
struct sysinfo_block_1
{
DWORD unk_0; //0
DWORD bot_id_created;
DWORD dw_const_0; //0x101
DWORD os_version;
WORD dw_const_2; //0x200
BYTE cpu_arch;
BYTE field_13;
DWORD main_interface_IP;
BYTE MAC_address[20];
BYTE bot_id[48];
WCHAR computer_name[128];
BYTE cfg_string[64];
WORD w_const; //2
WORD sessions_size;
};
struct sysinfo_packet_data
{
DWORD id;
sysinfo_block_1 block_1;
sysinfo_block_2 block_2;
};
Примечателен процесс определения бэкдором значений MAC-адреса и IP-адреса. Вначале программа ищет сетевой интерфейс, через который прошло наибольшее количество пакетов, затем получает его MAC-адрес и далее по нему ищет IP-адрес этого интерфейса.
Версия ОС кодируется значением от 1 до 13 (0, если возникла ошибка), начиная с 5.0 и далее по возрастанию версии.
В поле sysinfo_packet_data.block_1.cfg_string помещается значение string из конфигурации бэкдора, которое равно символу 1.
Обработка команд
После верификации и отправки системной информации BackDoor.Spyder.1 приступает к обработке главных команд. В отличие от большинства бэкдоров, команды которых имеют вполне конкретный характер (забрать файл, создать процесс и т. д.), в данном экземпляре они носят скорее служебный характер и отражают инструкции по хранению и структурированию получаемых данных. Фактически все эти служебные команды нацелены на загрузку новых модулей в PE-формате, их хранение и вызов тех или иных экспортируемых функций. Стоит отметить, что модули и информация о них хранятся в памяти в виде хеш-таблиц с помощью UT-hash.
После обработки каждого полученного от сервера пакета бэкдор проверяет разницу между двумя значениями результата GetTickCount. Если значение превышает заданное контрольное значение, то отправляет на сервер значение сигнатуры 0x573F0A68 без каких-либо дополнительных данных и преобразований.
Заключение
Рассмотренный образец бэкдора для целевых атак BackDoor.Spyder.1 примечателен в первую очередь тем, что его код не исполняет прямых вредоносных функций. Его основные задачи — скрытое функционирование в зараженной системе и установление связи с управляющим сервером с последующим ожиданием команд операторов. При этом он имеет модульную структуру, что позволяет масштабировать его возможности, обеспечивая любую функциональность в зависимости от нужд атакующих. Наличие подключаемых плагинов роднит рассмотренный образец с ShadowPad и PlugX, что, вкупе с пересечениями сетевых инфраструктур, позволяет нам сделать вывод о его принадлежности к деятельности Winnti.