Исследуем Spyder – еще один бэкдор группировки Winnti

В конце прошлого года в нашу лабораторию за помощью обратилась зарубежная телекоммуникационная компания, сотрудники которой обнаружили в корпоративной сети подозрительные файлы. В ходе поиска следов вредоносной активности аналитики выявили образец весьма интересного бэкдора. Его анализ показал, что мы имеем дело с очередным модульным APT-бэкдором, использующимся хакерской группой Winnti.

Последний раз деятельность Winnti попадала в наше поле зрения, когда мы анализировали модификации бэкдоров ShadowPad и PlugX в рамках расследования атак на государственные учреждения стран Центральной Азии. Оба эти семейства оказались схожи концептуально и имели примечательные пересечения в коде. Сравнительному анализу 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

Также мы нашли следы запуска других служб со случайными именами, их файлы располагались в директориях вида  C:\Windows\Temp\\, где random1 и random2 являются строками случайной длины из случайных символов латинского алфавита. На момент проведения исследования исполняемые файлы этих служб отсутствовали.

Интересной находкой стала служба, свидетельствующая об использовании утилиты для удаленного исполнения кода smbexec.py из состава набора Impacket. С её помощью злоумышленники организовали удаленный доступ к командной оболочке в полуинтерактивном режиме.

b0334bbb07c6e9b48fd02ff0d2d83155.png

Исследуемый вредоносный модуль oci.dll был добавлен в вирусную базу Dr.Web как BackDoor.Spyder.1. Это название пришло к нам из артефактов бэкдора. В одном из найденных образцов остались функции ведения отладочного журнала и сами сообщения, при этом те из них, которые использовались при коммуникации с управляющим сервером, содержали строку «Spyder».

7b2dc27fe2f2638a2af31c39f8081d54.png

Бэкдор примечателен рядом интересных особенностей. Во-первых, oci.dll содержит основной PE-модуль, но с отсутствующими файловыми сигнатурами. Заполнение сигнатур заголовка нулями предположительно было сделано с целью затруднения детектирования бэкдора в памяти зараженного устройства. Во-вторых, полезная нагрузка сама по себе не несет вредоносной функциональности, но служит загрузчиком и координатором дополнительных плагинов, получаемых от управляющего сервера. С помощью этих подключаемых плагинов бэкдор выполняет основные задачи. Таким образом, это семейство имеет модульную структуру, как и другие семейства бэкдоров, используемые Winnti, — упомянутые ранее ShadowPad и PlugX.

Анализ сетевой инфраструктуры Spyder выявил связь с другими атаками Winnti. В частности инфраструктура, используемая бэкдорами Crosswalk и ShadowPad, описанными в исследовании Positive Technologies, перекликается с некоторыми образцами Spyder. График ниже наглядно показывает выявленные пересечения.

Пожалуйста, масштабируйте страницу для чтения надписей, спасибо :)Пожалуйста, масштабируйте страницу для чтения надписей, спасибо :)

Принцип действия

Бэкдор представляет собой вредоносную DLL-библиотеку. Имена функций в таблице экспорта образца дублируют экспортируемые функции системной библиотеки apphelp.dll.

630d7ec567e075cbb0771c56528abe3d.png

Функционально образец является загрузчиком для основной полезной нагрузки, которую хранит в секции .data в виде DLL, при этом некоторые элементы DOS и PE заголовков равны нулю.

9fc17a381baf8de17769ccc3e906ad34.png266bb45411155f0c2fd5d6020d206725.png

Работа загрузчика

Загрузка выполняется в функции, обозначенной как malmain_3, вызываемой из точки входа DLL через две промежуточные функции-переходника.

64268e88ece5fac8963cec0dc6dd0a6f.png

Далее следует стандартный процесс загрузки PE-модуля в память и вызов точки входа загруженного модуля (DllMain) с аргументом DLL_PROCESS_ATTACH, а после выхода из нее — повторный вызов с DLL_PROCESS_DETACH.

Работа основного модуля

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

  • IMAGE_DOS_HEADER.e_magic

  • IMAGE_NT_HEADERS64.Signature

  • IMAGE_NT_HEADERS64.FileHeader.Magic

Кроме того, TimeDateStamp и имена секций также имеют нулевое значение. Остальные значения корректны, поэтому после ручной правки необходимых сигнатур файл можно загрузить для анализа в виде PE-модуля.

Анализ основного модуля затруднен, так как периодически используются нетипичные способы вызова функций. Для хранения и обработки структур используется библиотека UT hash. Она позволяет преобразовывать стандартные C-структуры в хеш-таблицы путем добавления одного члена типа ut_hash_handle. При этом все функции библиотеки, такие как добавление элементов, поиск, удаление и т. д., реализованы в виде макросов, что приводит к их принудительному разворачиванию и встраиванию (inline) компилятором в код основной (вызывающей) функции.

Для взаимодействия с управляющим сервером используется библиотека mbedtls.

Функция DllMain

В начале исполнения проверяется наличие события Global\\BFE_Notify_Event_{65a097fe-6102–446a-9f9c-55dfc3f45853}, режим исполнения (из конфигурации) и командная строка, затем происходит запуск рабочих потоков.

b3e3b919c7fa6a87e1f11b3a54b42a04.png

Модуль имеет встроенную конфигурацию следующей структуры:

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];
};

Поле hash содержит некое значение, которое может являться идентификатором. Это значение используется при взаимодействии с управляющим сервером и может быть представлено в виде строки b2e4936936c910319fb3d210bfa55b18765db9cc, которая по длине совпадает с SHA1-хешами.

 Поле string содержит строку из одного символа: 1.

 CA_cert — сертификат центра сертификации в формате DER. Он используется для установки соединения с управляющим сервером по протоколу TLS 1.2.

029f95eeaff1e7600fe0291903208a06.png

В функции DllMain предусмотрено создание нескольких рабочих потоков в зависимости от ряда условий.

  • Основной поток — thread_1_main

  • Поток запроса нового сервера — thread_2_get_new_C2_start_communication

  • Поток исполнения зашифрованного модуля — thread_4_execute_encrypted_module

 Основной поток

Вначале бэкдор проверяет версию ОС, затем подготавливает структуру для инициализации функций и структуру для хранения некоторых полей конфигурации. Процедура выглядит искусственно осложненной.

13c1986ca28e7ccaf32853f6dd798ad2.png

В структуру funcs_struc типа funcs_1 заносятся 3 указателя на функции, которые будут поочередно вызваны внутри функции init_global_funcs_and_allocated_cfg.

9d5115fed0ba670485a8ae5fde750d1d.png

 В функции set_global_funcs_by_callbacks происходит вызов каждой функции-инициализатора по очереди.

Общий порядок формирования структур выглядит следующим образом:

1) каждой функции передаются две структуры: первая содержит указатели на некоторые функции, вторая — пустая;

2) каждая функция переносит указатели на функции из одной структуры в другую;

3) после вызова функции-инициализатора происходит очередное перемещение указателей на функции из локальной структуры в глобальный массив структур по определенному индексу.

В итоге после всех нестандартных преобразований получается некоторое количество глобальных структур, которые объединены в один массив.

acd49328ac1ee4fc5b26cab2f54129ee.png

 В конечном итоге вызов функций можно представить следующим образом.

ed3a59d203ca4718e7bfc0129ac6d92b.png

Сложные преобразования — копирование локальных структур с функциями и их перенос в глобальные структуры — вероятно, призваны усложнить анализ вредоносного образца.

Затем бэкдор при помощи библиотеки UT hash формирует хеш-таблицу служебных структур, ответственных за хранение контекста сетевого соединения, параметров подключения и т. д.

Фрагмент кода формирования хеш-таблицы.

ea8d5cf3304587d97270e30ba22a5680.png

 Стоит отметить, что здесь располагается значение сигнатуры, которое позволяет определить используемую библиотеку: g_p_struc_10→hh.tbl→signature = 0xA0111FE1; .

Для рассматриваемого бэкдора характерно распределение значимых полей и данных по нескольким создаваемым для этого структурам. Эта особенность при анализе затрудняет создание осмысленных имен для структур.

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

Инициализация соединения с управляющим сервером

После ряда подготовительных действий бэкдор разрешает хранящийся в конфигурации адрес управляющего сервера и извлекает порт. Адреса в конфигурации хранятся в виде строк: koran.junlper[.]com:80 и koran.junlper[.]com:443. Далее программа создает TCP-сокет для подключения. После этого создает контекст для защищенного соединения и выполняет TLS-рукопожатие.

904549ba3efd7563d62aa9d90143c3fe.png

После установки защищенного соединения бэкдор ожидает от управляющего сервера пакет с командой. Программа оперирует двумя форматами пакетов:

  • пакет, полученный после обработки протокола TLS, — «транспортный» пакет»;

  • пакет, полученный после обработки транспортного пакета, — «пакет данных». Содержит идентификатор команды и дополнительные данные.

Заголовок транспортного пакета представлен следующей структурой.

struct transport_packet_header
{
  DWORD signature;
  WORD compressed_len;
  WORD uncompressed_len;
};

Данные располагаются после заголовка и упакованы алгоритмом LZ4. Бэкдор проверяет значение поля signature, оно должно быть равно 0×573F0A68.

 После распаковки полученный пакет данных имеет заголовок следующего формата.

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 в совокупности определяют действие бэкдора, то есть обозначают идентификатор команды.

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

Порядок обработки команд сервера:

  • верификация клиента;

  • отправка информации о зараженной системе;

  • обработка команд по идентификаторам.

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

Этап верификации

Для выполнения этапа верификации значения полей tag и id в полученном от управляющего сервера первичном пакете должны быть равны 1.

Процесс верификации состоит в следующем:

1. Бэкдор формирует буфер из 8-байтного массива, который следует после заголовка пакета и поля hash_id, взятого из конфигурации. Результат можно представить в виде структуры:

struct buff
{
    BYTE packet_data[8];
    BYTE hash_id[20];
}

 2. Вычисляется SHA1-хеш данных в полученном буфере, результат помещается в пакет (после заголовка) и отправляется на сервер.

Отправка информации о системе

Следующий полученный пакет от управляющего сервера должен иметь значения 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;
};

 Поле sysinfo_packet_data.id содержит константу — 0×19C0001.

 Примечателен процесс определения бэкдором значений MAC-адреса и IP-адреса. Вначале программа ищет сетевой интерфейс, через который прошло наибольшее количество пакетов, затем получает его MAC-адрес и далее по нему ищет IP-адрес этого интерфейса.

42f01be50bda0f8478c257f7e9dacaa6.png

Версия ОС кодируется значением от 1 до 13 (0, если возникла ошибка), начиная с 5.0 и далее по возрастанию версии.

В поле sysinfo_packet_data.block_1.cfg_string помещается значение string из конфигурации бэкдора, которое равно символу 1.

Обработка команд

После верификации и отправки системной информации BackDoor.Spyder.1 приступает к обработке главных команд. В отличие от большинства бэкдоров, команды которых имеют вполне конкретный характер (забрать файл, создать процесс и т. д.), в данном экземпляре они носят скорее служебный характер и отражают инструкции по хранению и структурированию получаемых данных. Фактически все эти служебные команды нацелены на загрузку новых модулей в PE-формате, их хранение и вызов тех или иных экспортируемых функций. Стоит отметить, что модули и информация о них хранятся в памяти в виде хеш-таблиц с помощью UT-hash.

tag

id

Описание

6

1

Отправить на сервер количество полученных модулей.

2

Сохранить в памяти параметры получаемого модуля.

3

Сохранить в памяти тело модуля.

4

Загрузить сохраненный ранее модуль. Поиск выполняется в хеш-таблице по идентификатору, полученному в пакете с командой. Модуль загружается в память, вызывается его точка входа, затем получаются адреса 4 экспортируемых функций, которые сохраняются в структуре для дальнейшего вызова. Вызвать экспортируемую функцию № 1.

5

Вызвать экспортируемую функцию № 4 одного из загруженных модулей, затем выгрузить его.

6

Отправить в ответ пакет, состоящий только из заголовка  data_packet_header, в котором поле unk_2 равно 0xFFFFFFFF.

7

Вызвать экспортируемую функцию № 2 одного из загруженных модулей.

8

Вызвать экспортируемую функцию № 3 одного из загруженных модулей.

5

2

Отправить на сервер информацию о текущих параметрах подключения.

4

-

Предположительно экспортируемая функция № 1 может возвращать таблицу указателей на функции, и по этой команде программа вызывает одну из данных функций.

После обработки каждого полученного от сервера пакета бэкдор проверяет разницу между двумя значениями результата GetTickCount. Если значение превышает заданное контрольное значение, то отправляет на сервер значение сигнатуры 0×573F0A68 без каких-либо дополнительных данных и преобразований.

a70c190f3e1d0a4f15d254f7763e840e.png

Заключение

Рассмотренный образец бэкдора для целевых атак BackDoor.Spyder.1 примечателен в первую очередь тем, что его код не исполняет прямых вредоносных функций. Его основные задачи — скрытое функционирование в зараженной системе и установление связи с управляющим сервером с последующим ожиданием команд операторов. При этом он имеет модульную структуру, что позволяет масштабировать его возможности, обеспечивая любую функциональность в зависимости от нужд атакующих. Наличие подключаемых плагинов роднит рассмотренный образец с ShadowPad и PlugX, что, вкупе с пересечениями сетевых инфраструктур, позволяет нам сделать вывод о его принадлежности к деятельности Winnti.

© Habrahabr.ru