Уроки форензики. Изучаем поведение стилера при помощи INetSim и IDA Pro

Содержание статьи

  • Используемые утилиты
  • Первичный анализ
  • Исследуем загрузчик
  • Исследуем основную нагрузку
  • Взаимодействие с управляющим сервером
  • Сбор информации о системе
  • Выводы

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

Мы будем раз­бирать задание 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, в сек­ции .text — самое высокое зна­чение. Зна­чит, иссле­дуемый файл упа­кован.

     

    Исследуем загрузчик

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

    Псев­докод фун­кции WinMain

    Пе­рей­дем в дан­ную фун­кцию двой­ным нажати­ем и деком­пилиру­ем, нажав 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 и рас­шифров­ки основной наг­рузки.

    Фун­кция получе­ния адре­сов Windows API

    Пре­обра­зуем деком­пилиру­емый код в чита­емый вид. Для это­го выберем перемен­ную a1, клик­нем пра­вой кноп­кой мыши и выберем пункт Create Struct. IDA сфор­миру­ет струк­туру. Далее пере­име­новы­ваем каж­дое зна­чение поля (горячая кла­виша N).

    Для получе­ния фун­кций WinAPI LoadLibraryA и GetProcAddress из биб­лиоте­ки kernel32.dll исполь­зует­ся хеширо­вание. Из поля 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.dll.

    Фун­кция рас­шифров­ки основной наг­рузки

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

    Про­цесс рас­шифров­ки и разар­хивиро­вания

    Ал­горитм рас­шифров­ки тот же, а вот алго­ритм деком­прес­сии силь­но обфусци­рован и содер­жит мно­жес­тво перехо­дов (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.

    Ин­форма­ция об основной наг­рузке

    Источник: xakep.ru

    Ответить

    Ваш адрес email не будет опубликован. Обязательные поля помечены *