January 19

Исследование Badger BRC4

Сегодня проанализируем шелл-код Badger Brute Ratel C4, файл. Проведем динамичесий и статический анализ вредоносного кода, восстановим алгоритм декодирования функций (API Hashing), расшифруем полезную нагрузку и конфигурацию модуля.

Больше информации об информационной безопасности, реверсу малвари и расследованию инцидентов в канале https://t.me/threathunt_pedia.

Используемые утилиты:

  1. Blobrunner - инструмент для отладки шелл-кода.
  2. SpeakEasy - эмулятор, предназначенный для эмуляции вредоносных программ ядра и пользовательского режима Windows.
  3. Ghidra - это платформа обратного проектирования программного обеспечения (SRE)/
  4. IDA Pro - инструмент для анализа двоичного кода.
  5. x64Debug - бинарный отладчик с открытым исходным кодом для Windows
  6. Die.

Исследование шелл-кода

Для статического анализа шелл-кода будем использовать Ghidra. Испортируем файл и выберем компилятор.

Выбираем x86 архитектуру, 64 разрядный процесс и компилятор gcc. Если код не преобразовался, то нажмем горячую клавишу D или Правая клавиша мыши->Disassemble.

Командами PUSH в стек складывается большой объем данных. Спустимся по коду ниже и разберем дальнейшие действия шелл-кода.

Начнем проводить динамический анализ шелл-кода, чтобы подробнее разобрать реализию, запустим blobrunner.

blobrunner64.exe 4f88738e04447344100bb9532c239032b86e71d8037ccb121e2959f37fff53cf.unknown

Помним, что мы отлаживаем x64 разрядный шелл-код, поэтому нам необходимо в x64dbg поставить точку останова на потоке с идентификатором, указаном в строке Created Thread: утилиты Blobrunner. Присоединяемся к созданному процессу, ставим точку останова и начинаем отлаживать код.

аходим в функцию 13a69d944d7 (Горячая клавиша F7 в x64dbg).

Спускаемся ниже и видим вызов функции call 13a69d93e67, на вход ей поступает значение 0x3e192526. Зайдем в данную функцию.

В данной функции реализована следующая логика. Получение адреса динамической библиотеки ntdll.dll, далее адреса всех функций экспорта, следующим этапом имя экспортируемой функции подается на вход call 13a69d94557 для расчета хэш-значения.

Полученное хэш-значение сравнивается со значением 0x3e192526. Разберем алгоритм хэширования и напишем его алгоритм на Python3. Для этого зайдем в функцию 13a69d94557

Код реализации хэширования представлен ниже.

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

def hash_api_brc4(name_api):
    sum = 0
    for i in  name_api:
        c = ord(i)
        sum = ((ror(sum,0xd,max_bits) & 0xffffffffffffffff) + c) &0xffffffffffffffff
    return hex(sum)

В Ghidra найдем все хэш-значения и преобразуем их. Горячей клавишей ; можно добавить комментарий к строке в дизассемблере.

kernel32.dll->GetProcAddress  0x7c0dfcaa
kernel32.dll->LoadLibraryA 0xec0e4e8e
kernel32.dll->WaitForSingleObject 0xce05d9ad
ntdll.dll->LdrGetDllHandleEx 0xec6b915d
ntdll.dll->LdrGetProcedureAddress 0xe54cc407
ntdll.dll->NtAllocateVirtualMemory 0xd33bcabd
ntdll.dll->NtFlushInstructionCache 0x534c0ab8
ntdll.dll->NtProtectVirtualMemory 0x8c394d89
ntdll.dll->RtlAllocateHeap 0x3e192526
ntdll.dll->RtlFreeHeap 0xda12b8
ntdll.dll->NtAllocateVirtualMemory 0xd33bcabd
ntdll.dll->RtlAllocateHeap 0x3e192526
ntdll.dll->RtlFreeHeap 0xda12b8

Значение хэш-суммы 0x3e192526 соответствует функции RtlAllocateHeap.

В функции 13a69d944d7 реализован алгоритм выделения кучи с помощью функции RtlAllocateHeap и копирование полезной нагрузки размером 0x39410 из стека в выделенную оласть памяти.

Во втором выполнении функции13a69d944d7 копируется закодированная Base64 конфигурация модуля размером 0x13c в выделенную область кучи.

Далее проанализируем функцию `call 13A69D94587`, в которой реализован основной функционал по расшифрованию и запуску основной нагрузки.

В данной функции происходит получение адресов функций: RtlFreeHeap, NtProtectVirtualMemory, LdrGetHandleEx, LdrGetProcedureAddress.

Спустимся ниже и увидим еще одно константное значение 0x6a4abc5b, которое поступает на вход функции `...f97`. Расмотрим его подробнее.

Код функции хэширования имени DLL библиотеки.

В данной функции реализован алгоритм хэширования имени DLL библиотеки. Напишем его на Python3.

def dll_hashing(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
    return sum

Функция 0x6a4abc5b является хэш значением динамической библиотеки KERNEL32.DLL.

Далее с помощью функции LdrGetDllHandleEx загружает динамическую функцию Kernel32.dll.

Следующим этапом начинается процесс расшифрования полезной нагрузки Badger BRC3 в функции call 13a69d948a7.

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

В качестве ключа передаются последние 8 байтов скопированной полезной нагрузки. Ключ равен 23 64 66 26 2F 61 2E 65. Расшифруем полезную нагрузку.

В итоге получили PE файл с удаленной MZ сигнатурой.

Далее полученный код загружается в процесс методом ReflectiveDLLInjection.

Код расшифрования файла конфигурации расположен в основной DLL Badger. Но не много опишу его тут.

Конфигурация расположена в Base64 данных, зашифрованных по алгоритму RC4. Ключом является предпоследние 8 байтов расшифрованной полезной нагрузки DLL Badger BRC4. Последние 8 байт это зашифрованный ключ расшифрования полезной нагрузки, тот что мы получили на предыдущем шаге.

Расшифруем с помощью утилиты CyberChef.

В конфигурации каждый параметр отделен вертикальной чертой. В выявленном нам конфигурации указан управляющий сервер deve.dread.ie. Так конфигурация хранится В памяти процесса конфигурация хранится в зашифрованном blob-объекте (RC4+base64), но ключ шифрования для RC4 указан в основной нагрузки DLL Badger BRC4.

На данном этапе мы с вами разобрали загрузчик основной нагрузки DLL Badger BRC4. Нам удалось разобрать алгоритм хэширования API функций, который схож с реализацией в CobaltStrike. Расшифровали полезную нагрузку, которая представляет из себя DLL без заголовка MZ, а также расшифровали конфигурацию вредоноса.