Исследование Golang дроппера с нагрузкой CobaltStrike
Сегодня мы с вами проведем исследование вредоносного файла, представляющий собой Golang дроппер. Основная задача исследуемого модуля установка шелл-кода CobaltStrike. Мы с вами научимся проводить динамический и статичесикй анализ, разберем алгоритм хэширования API функций и разработаем собственный декодер на Python3.
Используемые утилиты:
- Blobrunner - инструмент для отладки шелл-кода.
- SpeakEasy - эмулятор, предназначенный для эмуляции вредоносных программ ядра и пользовательского режима Windows.
- Ghidra - это платформа обратного проектирования программного обеспечения (SRE)/
- IDA Pro - инструмент для анализа двоичного кода.
- x64Debug - бинарный отладчик с открытым исходным кодом для Windows
- Die.
Информация об исполняемом файле
Первоначально получим инфорамацию об исполняемом файле, для этого загрузим в утилиту Die.
Исследование дроппера
При исследования файлов на Go возникает множество трудностей: потерянные имена функций, нераспознанные строки в файле. Проблем анализа бинарных файлов на Go описаны в статье Реверс бинарных файлов Golang с использованием Ghidra. Часть 1 . Для решения данных проблем разработана коллекция скриптов AlphaGolang для IDA Pro 7.6 и Ghidra Script для Ghidra.
Загрузим вредонос в IDA Pro x64 и проведем его статичесский анализ. На вкладке Function
находим функцию main.main
и приступаем к анализу.
На вкладке псевдокод, сгенерированный Hex Rays можно увидеть строку LeslieCheungKwok
, декодирование данных из Base 64 и функцию main_DecrptogAES
.
Посмотрим содержимое функции main_DecrptogAES
.
Также содежимое полезной нагрузки.
Вышеописанные участок кода расшифровывает полезную нагрузку по следующему алгоритму: дкодирование из Base64, далее расшифрования по алгоритму AES в режиме CBC, ключ и вектор инициализации равен LeslieCheungKwok
.
Расшифруем полезную нагрузку и проанализруем полученный шелл-код, размером 1600 байт, для этого воспользуемся утилитой CyberChef.
Далее в функции main_build
происходит запуск расшифрованного шелл-кода с помощью Golang пакета Syscal.
Анализ шелл-кода CobaltStrike
После получения шелл-кода определим его функциональность с помощью утилиты SpeakEasy. Сохраним результат отчета в файл mem.zip.
speakeasy -t cobalt.sc -r -a x64 -d mem.zip
Основная задача вредоносного кода загрузка полезной нагрузки с управляющего сервера 124.221.100.99
. Взглянем глубже на шелл-код, проведем его динамический и статический анализ.
Проведем статический анализ шелл-кода в Ghidra. Импортируем файл в наш проект, далее выбираем архитектуру, компилятор и порядок байт.
Код будет представлять байтовую последовательность, нам необходимо его преобразовать в ассемблерные инструкции, для этого нажмем горячую клавишу D
или Правая клавиша мыши->Disassemble.
Все вызовы функций в шелл-коде будут выполнятся посредством хэширования API. Функция поиска хэша функции выполняется в инструкции call RBP
. Восстановим алгоритм хэширования с помощью динамического анализа. Для этого нам понадобится blobrunner.64exe и x64dbg.
Для поддержки отладки x64 шелл-кода загрузчик Blobrunner создает приостановленный поток, в нашем случае его идентификатор 6092.
Далее открываем x64dbg, нажимаем на вкладку Файл->Присоединиться и выбираем процесс blobrunner64.exe.
В отладчике x64dbg переходим во вкладку Потоки и ставим точку останова на вход потока с идентификатором 6092. Не забываем, что идентификатор и точка входа при новом запуске будет разный. Далее при запуске Blobrunner64 нажимаем на любую клавишу и в x64dbg попадем на точку входа шелл-кода.
Нам необходимо зайти в функцию call rbp
, как видно из рисунка на вход подается хэш сумма 0x726774c.
Первое что приосходит это формирование константы от имени dll функции.
Следующим этапом имя экспортированной функции из динамической библиотеки по байтово преобразуется по алгоритму ror13 и сумируется.
Напишем алгоритм хэширования API функций Cobalt Strike на Python.
def generate_const(name_dll): sum = 0 for i in name_dll: c = ord(i) if c >= 0x61: c -= 0x20 sum = ((ror(sum,0xd,max_bits) & 0xffffffffffffffff) + c) &0xffffffffffffffff sum = ((ror(sum,0xd,max_bits) & 0xffffffffffffffff)) &0xffffffffffffffff sum = (ror(sum,0xd,max_bits)&0xffffffffffffffff ) sum = (ror(sum,0xd,max_bits)&0xffffffffffffffff ) return sum def hash_api_cs(name_api,name_dll): const_ = generate_const(name_dll) sum = 0 for i in name_api: c = ord(i) sum = ((ror(sum,0xd,max_bits) & 0xffffffffffffffff) + c) &0xffffffffffffffff sum = (ror(sum,0xd,max_bits)&0xffffffffffffffff ) sum = (sum + const_) & 0xffffffff return hex(sum)
ExitProcess 0x56a2b5f0 VirtualAlloc 0xe553a458 HttpOpenRequestA 0x3b2e55eb HttpSendRequestA 0x7b18062d InternetConnectA 0xc69f8957 InternetOpenA 0xa779563a InternetReadFile 0xe2899612
Заключение
При разборе данной малвари мы с вами расшифровали полезную нагрузку, научились отлаживать шелл-код с помощью утилиты blobrunner, написали декодер хэш-сумм используемых API функций.