Уроки форензики
Изучаем поведение стилера при помощи INetSim и IDA Pro
Мы будем разбирать задание UnPackMe Blue Team Lab с площадки Cyber Defenders. Уровень задания — сложный. В лабораторной работе тебе потребуется ответить на ряд вопросов по итогам прохождения, однако приводить ответы мы не будем — если ты повторишь прохождение, то без труда ответишь на всё сам.
warning
Анализ вредоносных файлов необходимо проводить в изолированной среде. О том, как собрать лабораторию для анализа вредоносов, подробно рассказано в статье «Код под надзором. Создаем виртуальную лабораторию для анализа малвари».
Используемые утилиты
- DIE — программа для определения типов файлов.
- PeStudio — программа для поиска артефактов исполняемых файлов.
- IDA Pro — интерактивный дизассемблер, используемый для реверс‑инжиниринга.
- Wireshark — инструмент для анализа сетевого трафика.
- Burp Suite — платформа, которая используется в качестве прозрачного прокси‑сервера для анализа взаимодействия вредоносного файла по протоколу HTTPS.
- x64dbg — опенсорсный отладчик для Windows, предназначенный для анализа вредоносных программ.
- INetSim — эмулятор работы с интернетом.
Первичный анализ
Получим первичную информацию об исследуемом образце. Загрузим файл в DIE и выберем анализатор Nauz File Detector.

Исследуемый образец собран для 32-разрядных систем, разработан на языке C/C++ и скомпилирован в Microsoft Visual Studio. Получим энтропию исполняемого файла по секциям. Перейдем на вкладку Entropy и определим его показатель.

Энтропия исследуемого файла — 7,389, в секции .
— самое высокое значение. Значит, исследуемый файл упакован.
Исследуем загрузчик
Загрузим файл в IDA и приступим к анализу. Точка входа указывает на функцию WinMain
, а основной поток выполнения реализован в функции sub_468480
.

Перейдем в данную функцию двойным нажатием и декомпилируем, нажав F5.

В функции WrapGlobalAlloc
реализовано получение адреса GlobalAlloc и выделение в куче памяти, равной длине шелл‑кода. Далее в функции WrapVirtualProtect
выделенному участку памяти назначаются права на выполнение, чтение и запись (PAGE_EXECUTE_READWRITE
) с помощью функции VirtualProtect. Следующим этапом начинается процесс расшифровки шелл‑кода.
Шифрование состоит из преобразования ключа и операции XOR.


Начальное значение ключа — 0xD5AF2F45
. Для расшифровки шелл‑кода мы разработаем скрипт для IDA, на вход которого передадим адрес зашифрованного шелл‑кода, его размер, начальное значение ключа и имя файла для сохранения данных.
import structimport idaapiHIWORD = lambda x: x >> 16def GenerateKey(key): key = (key * 0x343fd) & 0xffffffff key = (key + 0x269ec3) & 0xffffffff return keydef DecryptShellcode(data,key): result = bytearray() for i in data: key = GenerateKey(key) k = HIWORD(key) & 0xFF result.append(i ^ k) return resultdef main(start,size,key,filename): w = open(filename,'wb') b = bytearray() for i in range(size): x = idaapi.get_byte(start + i) b.append(x) d = DecryptStage(b,key) w.write(d) w.close()
Расшифровывать будем в режиме отладки. Поставим точку останова на функции WrapDecryptShellcode
(горячая клавиша F2) и запустим отладку (F9). Двойным нажатием на переменную shellcode
получим адрес исполняемого кода, а его размер узнаем из переменной size_shellcode
.
Загрузим разработанный скрипт, для этого зайдем на вкладку File → Script File. В командной строке Python вызовем функцию main
.
main(start=0x7B96E8,size=0x4e9d3,key=0xD5AF2F45,filename='stage01')
Мы получили значение расшифрованного исполняемого кода. Загрузим его в IDA и проведем статический анализ. Полученный шелл‑код состоит из функций получения адресов используемых WinAPI и расшифровки основной нагрузки.

Преобразуем декомпилируемый код в читаемый вид. Для этого выберем переменную a1
, кликнем правой кнопкой мыши и выберем пункт Create Struct. IDA сформирует структуру. Далее переименовываем каждое значение поля (горячая клавиша N).
Для получения функций WinAPI LoadLibraryA и GetProcAddress из библиотеки kernel32.
используется хеширование. Из поля InMemoryOrderModuleList
структуры PEB процесса считываются имена динамических библиотек. Из каждого имени вычисляется значение хеша и сравнивается со значением 0xd4e88
. Такая же процедура производится с именами функций экспорта найденной динамической библиотеки.
Алгоритм хеширования представлен ниже.
def ApiHashing(name_func,hashing): res = 0 for i in name_func: v5 = (ord(i) | 0x60) & 0xff res = (res + v5) * 2 if res == hashing: return True return False
Значение 0xd4e88
соответствует kernel32.
.

Процесс получения основной нагрузки состоит из этапов расшифровки и разархивирования.

Алгоритм расшифровки тот же, а вот алгоритм декомпрессии сильно обфусцирован и содержит множество переходов (goto
). Распакуем нашу нагрузку. Для этого в режиме отладки переходим к выполнению шелл‑кода и находим функцию DecryptUnpackShellcode
. Далее спускаемся к выполнению функции Unpack
, переходим на вкладку Hex View (клавиша G) и вводим адрес, который хранится в переменной data
. Размер получаем из значения переменной unpack_size
.
Дампим полученный после разархивирования шелл‑код с помощью IDA API. Для этого переходим в командную оболочку Python и вводим следующую команду:
idc.savefile('path_filename', 0, address_shellcode, unpack_size)
Мы получили основную нагрузку, она представляет собой шелл‑код, задача которого — загрузить методом Process Hollowing исполняемый файл и начать выполнение с его точки входа. Загрузим полученный файл в Hex-редактор, скопируем данные, начиная с сигнатуры MZ
, и приступим к его анализу.

На этом этапе мы с тобой распаковали основную нагрузку, которая представляет собой исполняемый файл. Работа загрузчика разделена на несколько этапов: сначала расшифровывается исполняемый код, основная задача которого — расшифровать и распаковать шелл‑код следующего этапа. Шелл‑код следующего этапа загружает в память исполняемый файл и продолжает выполнение с его точки входа.

Исследуем основную нагрузку
Получим информацию об исполняемом файле, для этого загрузим его в утилиту DIE.

Основная нагрузка разработана на C/C++, скомпилирована в Microsoft Visual Studio и собрана для 32-разрядных систем. Загрузим файл в IDA и приступим к статическому анализу. Код вредоноса сильно обфусцирован, и граф потока выполнения очень большой.

Все строки, используемые в процессе работы модуля, зашифрованы при помощи XOR с однобайтовым ключом. Давай набросаем скрипт для IDA, который будет расшифровывать строки.
def decrypt_str(data): result = '' key = data & 0xff data = data >> 8 while data > 0: result += chr(~((data & 0xff) ^ key)&0xff) data = data >> 8 return result
На первом этапе модуль проверяет, запущен ли в системе экземпляр, с помощью функции OpenMutexA.

В командной строке Python запустим функцию расшифровки названия мьютекса:
decrypt_str(0xBABCABAFACA4B832)
Имя мьютекса формируется из константного значения uiabfqwfu
, сложенного с именем пользователя. Если мьютекс с таким названием существует, модуль прекращает свою работу.
Далее модуль с помощью функции GetLocaleInfoA узнаёт, какие в системе установлены языки. Если присутствует язык из определенного списка (в него входит русский), то модуль прекращает работу.

Следом начинается процесс взаимодействия с управляющим сервером. Адрес C2-сервера зашифрован алгоритмом RC4 и закодирован в Base64.

Расшифруем ключ, который хранится в переменной RC4_KEY
.
decrypt_str(0x9498D7AB8CAEB2808B9A8E9DDCB4CA11)
Ключ шифрования — $Z2s'ten\
для алгоритма RC4.
Расшифруем адрес управляющего сервера, для этого воспользуемся утилитой CyberChef.

Мы получили адрес управляющего сервера:
https://tttttt.me/ch0koalpengold
Взаимодействие с управляющим сервером
При обращении к управляющему серверу https://
исследуемый образец получает адрес основного сервера C2. Адрес расположен в блоке div
, содержащем следующие атрибуты.

Основной адрес управляющего сервера зашифрован алгоритмом RC4. Ключ:
6af7fae138b9752d1d76736dcb534c9d

При обращении к основному адресу управляющего сервера исследуемый образец получает конфиг, зашифрованный алгоритмом RC4 с ключом $Z2s'ten\
.
Приступим к настройке INetSim. Открываем файл sample.
вот по такому пути:
/var/lib/inetsim/http/fakefiles/sample.html
И добавляем блок div
с перечисленными выше атрибутами. Значение gzWH3jR7snsUFO5aZbvXyda3vfp8cjiu
зашифровано алгоритмом RC4 с ключом 6af7fae138b9752d1d76736dcb534c9d
. В зашифрованную строку добавлены символы, которые удаляются в процессе расшифровки.

В каталоге /
создадим файл config.
, содержащий зашифрованные настройки.

{ "_id":"123", "au":"files/", "ip":"10.10.10.1", "location":{"country":"qwe","country_code":"qwe","state":null,"state_code":null,"city":null,"zip":null}, "c":{"m":null,"lu":null}, "lu":null, "rm":1, "is_screen_enabled":1, "is_history_enabled":0, "depth":3}
Этот конфиг получен в результате статического анализа кода и нужен для работы образца. Параметр au
содержит URL для загрузки библиотеки sqlite3.
, параметры ip
и location
— информацию о сетевом адресе зараженной машины, параметр is_screen_enabled
необходим для получения снимка рабочего стола, а параметр rm
нужен на случай, если потребуется удалить себя после окончания сбора информации.
Также в каталог /
загрузим файл sqlite3.
.
В файле /
в блоке https_static_fakefile
добавим статичные URL.

Каждый раз, когда малварь обращается к адресам с подстрокой /
, загружается файл config.
(конфигурация модуля), а при открытии /
— библиотека sqlite3.dll.
Перезапустим утилиту INetSim.
sudo inetsim
Приступим к динамическому анализу исследуемого образца. При динамической отладке не забывай обходить проверку языкового стандарта, если в твоей виртуалке установлен русский язык.
Получив основной адрес управляющего сервера, вредоносный файл начинает устанавливать свое первое соединение.

Значения в POST-запросе сформированы следующим образом:
b=<MachineGuid>_<User>&c=c021300d0074689fde86c87568e215c582272721&f=json
Параметр b
описывает идентификатор зараженной машины, который формируется из имени пользователя системы и значения MachineGuid
ключа реестра:
HKLM:\SOFTWARE\Microsoft\Cryptography\MachineGuid
В параметре c
указано константное значение. Сформированная строка шифруется по алгоритму RC4 с ключом $Z2s'ten\
. В ответ от сервера управления приходит конфигурация модуля.
Для работы функции сбора данных из браузеров вредоносу необходима динамическая библиотека sqlite3.
. Параметр au
в конфиге указывает на URL, по которому малварь может получить эту библиотеку.

Сбор информации о системе
Рабочий каталог вредоносного файла:
C:\User\<User>\AppData\LocalLow
В этот каталог загружаются дополнительные модули, а также собранные файлы из системы.
Функция сбора находится по смещению 454A
(в моем случае функция sub_56454A
), для перехода к коду необходимо на вкладке Function ввести значение смещения. На этапе сбора данных о системе исследуемый образец формирует файл System
в рабочей директории.

Содержимое файла System
:
- Строка
Raccoon
описывает версию вредоносного файла, это значение зашифровано алгоритмом шифрования строк.| 1. 7. 3 -
Build
установлена в виде константы и указывает на дату компиляции файла.compile date -
Launched
содержит дату и время запуска.at - В блоке
System
собрана информация об имени хоста, временной зоне, установленном в системе языке, процессоре, объеме оперативной памяти и дисплеях.Information - В блоке
Installed
собрана информация об установленных приложениях, данный список получен из ключа реестраApps SOFTWARE\
.Microsoft\ Windows\ CurrentVersion\ Uninstall
Если в конфиге, полученном с управляющего сервера, есть значение is_screen_enabled:
, делается снимок рабочего стола пользователя. Функция создания скриншота расположена по смещению 951B
.

После захвата экрана растровое изображение сохраняется в рабочую директорию с именем screen.
.
После сбора всей информации с хоста в рабочей директории создается ZIP-архив. Имя файла берется из параметра _id
в конфиге, полученном с C2.


Если значение параметра rm
— «истина», то вредоносный файл начинает процесс самоудаления. Функция удаления расположена по смещению 5D47
.

В переменной cmd
формируется команда для удаления следов присутствия малвари в системе. Давай расшифруем значение.
decrypt_str(0x8FD1DE98D1DE929BBADED8DE928BB0DEC0DEB5BFBBACBCB1B0D1DECECFDEAAD1DE8A8B919B93978ADEBDD1DE9B869BD09A939D01)
Вот что получилось:
cmd.exe /C timeout /T 10 /NOBREAK > Nul & Del /f /q
Также при первичном анализе исполняемого файла я нашел полный путь к каталогу сборки на компьютере злоумышленника:
A:\_Work\rc-build-v1-exe\
Выводы
Эта лаборатория помогла нам научиться эмулировать работу управляющего сервера с помощью утилиты INetSim. Мы разобрали механизм работы стилера, задачей которого была кража криптокошельков, файлов cookie, паролей от браузеров и почтовых серверов и многого другого. Мы изучили работу загрузчика и распаковали основную нагрузку, а также написали скрипты для IDA и потренировались в проведении статического и динамического анализа вредоносных файлов.