June 9, 2022

Хакер - Уроки форензики. Реверсим шифровальщика

https://t.me/hacker_frei

rayhunt454

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

  • Инструментарий
  • Статический анализ
  • Заключение

В этой статье мы иссле­дуем вре­донос­ный файл на при­мере лабора­тор­ной работы Ransomed с ресур­са CyberDefenders. Мы научим­ся вруч­ную рас­паковы­вать код, опре­делим тех­нику внед­рения вре­донос­ной прог­раммы в про­цесс и отве­тим на ряд воп­росов.

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

INFO

Ис­сле­дова­ние вре­донос­ного фай­ла необ­ходимо про­водить в изо­лиро­ван­ной сре­де. Как соз­дать лабора­торию для ана­лиза вре­доно­сов, под­робно рас­ска­зано в статье «Код под над­зором. Соз­даем вир­туаль­ную лабора­торию для ана­лиза мал­вари».

Итак, заг­ружа­ем вре­донос и начина­ем его иссле­довать. По резуль­татам решения кей­са необ­ходимо отве­тить на нес­коль­ко воп­росов, но я покажу, толь­ко как его решать, и не буду при­водить отве­ты. Луч­ше пов­тори весь про­цесс самос­тоятель­но, что­бы разоб­рать­ся и зак­репить матери­ал.

ИНСТРУМЕНТАРИЙ

Для иссле­дова­ния вре­донос­ного фай­ла вос­поль­зуем­ся сле­дующим соф­том.

  1. DIE — прог­рамма для опре­деле­ния типов фай­лов.
  2. PeStudio — прог­рамма для поис­ка арте­фак­тов исполня­емых фай­лов.
  3. IDA Pro — инте­рак­тивный дизас­сем­блер, исполь­зуемый для реверс‑инжи­нирин­га.
  4. Wireshark — инс­тру­мент для ана­лиза сетево­го тра­фика.
  5. Burp Suite — исполь­зует­ся в качес­тве проз­рачно­го прок­си‑сер­вера с целью ана­лиза вза­имо­дей­ствия вре­донос­ного фай­ла по про­токо­лу HTTPS.
  6. Loki Scanner — ска­нер IOCs.
  7. YaraEditor — прог­рамма для тес­тирова­ния и соз­дания пра­вил YARA.
  8. ApiLoger — ути­лита для ана­лиза вызыва­емых WinAPI-фун­кций иссле­дуемо­го вре­доно­са.
  9. x64dbg — отладчик с откры­тым исходным кодом для Windows, пред­назна­чен­ный для ана­лиза вре­донос­ных прог­рамм.

Ана­лизи­ровать вре­донос­ный модуль мы будем в четыре эта­па:

  1. Ста­тичес­кий ана­лиз.
  2. По­веден­ческий ана­лиз.
  3. Ди­нами­чес­кий ана­лиз.
  4. Соз­дание инди­като­ров ком­про­мета­ции.

СТАТИЧЕСКИЙ АНАЛИЗ

В пер­вую оче­редь получим MD5-хеш‑сум­му исполня­емо­го фай­ла и про­верим его на VirusTotal. По MD5 a2f33095ef25b4d5b061eb53a7fe6548 VirusTotal выда­ет нам пер­вичную информа­цию об ис­полня­емом фай­ле.

Да­лее скор­мим иссле­дуемый файл ути­лите DIE и выяс­ним, какой ком­пилятор и ком­понов­щик исполь­зовал­ся при соз­дании вре­доно­са, а так­же опре­делим, упа­кован он или нет.

Ин­форма­ция о ком­пилято­ре и ком­понов­щике

Итак, мы узна­ли, что вре­донос­ный модуль раз­работан на C/C++ и соб­ран для 32-раз­рядных опе­раци­онных сис­тем. DIE опре­деля­ет упа­ков­щик с помощью заг­ружен­ных сиг­натур, но иден­тифици­ровать руч­ной упа­ков­щик не поз­воля­ет. Для это­го необ­ходимо пос­мотреть энтро­пию фай­ла по сек­циям.

INFO

Что такое энтро­пия исполня­емо­го фай­ла, рас­ска­зано в статье «Эн­тро­пия. Как хаос помога­ет искать вирусы».

Ин­форма­ция об энтро­пии исполня­емо­го фай­ла

Зна­чение энтро­пии 7,677, зна­чит, файл упа­кован. Из рисун­ка выше вид­но, что иссле­дуемый файл име­ет четыре сек­ции, энтро­пия сек­ции .text рав­на 7,844.

Заг­рузим файл в ути­литу PeStudio, что­бы най­ти все­воз­можные арте­фак­ты. Нам инте­рес­ны вре­мен­ные мет­ки ком­пиляции фай­ла, заг­ружа­емые биб­лиоте­ки, исполь­зуемые ресур­сы, информа­ция о вер­сии исполня­емо­го фай­ла, харак­терные стро­ки, а так­же отла­доч­ная информа­ция и файл сбор­ки (Manifest). Все это при­годит­ся нам при соз­дании фай­ловой сиг­натуры.

От­ладоч­ная информа­ция

Стро­ка C:\moz\vidaj.pdb нам инте­рес­на для соз­дания пра­вила детек­тирова­ния. На дан­ном эта­пе мы выяс­нили, что исполня­емый файл упа­кован, и получи­ли харак­терные стро­ки.

Преж­де чем прис­тупить к динами­чес­кому ана­лизу, изу­чим поведе­ние вре­донос­ного модуля. На этом эта­пе выявим сетевое вза­имо­дей­ствие с управля­ющим сер­вером, а так­же исполь­зуемые фун­кции Windows API.

За­пус­тим ути­литу INetSim в вир­туаль­ной машине Kali Linux. Так­же запус­тим Burp Suite для ана­лиза вза­имо­дей­ствия по HTTPS и будем слу­шать сетевой тра­фик вза­имо­дей­ствия, исполь­зуя Wireshark.

За­пус­тим Api Loger, выберем исполня­емый файл chalenge.exe и нач­нем писать логи.

Вы­зыва­емые Windows API фун­кции

Ис­полня­емый файл исполь­зует фун­кцию IsDebbugerPresent с целью анти­отладки. Далее запущен­ный про­цесс счи­тыва­ется с помощью фун­кции ReadProcessMemory, фун­кция VirtualAllocEx выделя­ет память и дан­ные записы­вают­ся в буфер в адресное прос­транс­тво про­цес­са WriteProcessMemory. Этот механизм похож на тех­нику внед­рения в про­цесс ProcessHollowing.

Те­перь давай пос­мотрим на сетевой тра­фик.

Се­тевое вза­имо­дей­ствие вре­донос­ного модуля

Как вид­но из рисун­ка выше, исполня­емый файл вза­имо­дей­ству­ет со сле­дующи­ми домена­ми: api.2ip[.]uakotob[.]toptzgl[.]org.

В Burp Suite вид­но вза­имо­дей­ствие по про­токо­лу HTTPS.

Зап­рос к api.2ip.ua
Зап­рос к tzgl.org

Для опре­деле­ния IP-адре­са исполня­емый файл дела­ет зап­рос к https://api.2ip.ua, а далее заг­ружа­ет с ресур­са https://tzgl.org/files/1/ исполня­емый файл build3.exe.

Как мы пом­ним, в INetSim есть фай­лы‑заг­лушки. Пос­ле зап­роса к tzgl.org заг­ружен­ный файл build3.exe запус­кает­ся.

За­пуск заг­ружен­ного фай­ла build3.exe

Пос­коль­ку мы соб­рали лабора­торию для ана­лиза вре­донос­ных фай­лов, в нашем слу­чае заг­ружа­ется файл‑заг­лушка ути­литы INetSim. Так­же обна­ружен HTTP-зап­рос к ресур­су tzgk.org.

HTTP-зап­рос к домену tzgk.org

Ис­поль­зуя ути­литу Process Hacker 2, рас­смот­рим поведе­ние запущен­ного фай­ла.

До­чер­ние про­цес­сы исполня­емо­го фай­ла challenge.exe

Как вид­но из рисун­ка, про­цесс challenge.exe запус­кает дочер­ние про­цес­сы build2.exe и build3.exe, которые, в свою оче­редь, запус­кают conhost.exe.

Да­лее про­исхо­дит шиф­рование всех фай­лов, которым наз­нача­ется рас­ширение .shgv. В кон­це каж­дого зашиф­рован­ного фай­ла хра­нит­ся оди­нако­вая струк­тура, в которой записа­ны иден­тифика­тор и дан­ные в фор­мате base64.

Со­дер­жимое зашиф­рован­ного фай­ла

На дан­ном эта­пе мы выяви­ли сетевое вза­имо­дей­ствие вре­донос­ного фай­ла, а так­же обна­ружи­ли тех­нику внед­рения в про­цесс Process Hollowing.

Ав­торы вре­доно­са час­то исполь­зуют фун­кции Windows API для выделе­ния памяти, что­бы даль­ше заг­рузить в это мес­то полез­ную наг­рузку, которая будет рас­паковы­вать исполня­емый код. Зна­чит, наша задача — обна­ружить этот учас­ток кода и выяс­нить, какие при­виле­гии ему выдава­лись. Далее мы будем шаг за шагом идти по коду в поис­ках фун­кции рас­паков­ки.

Пос­ле заг­рузки фай­ла нажима­ем F9 и попада­ем в точ­ку вхо­да исполня­емо­го фай­ла.

Точ­ка вхо­да

Нас инте­ресу­ет фун­кция VirtualAlloc, основная задача которой — выделе­ние памяти в адресном прос­транс­тве про­цес­са.

Для это­го нажима­ем Ctrl + G, набира­ем VirtualAlloc и перехо­дим в этот учас­ток кода.

По­иск фун­кции VirtualAlloc

Ста­вим точ­ку оста­нова на вхо­де в дан­ную фун­кцию (кла­виша F2).

Точ­ка оста­нова на вхо­де в фун­кцию VirtualAlloc

Спус­каем­ся пошаго­во ниже (F8), находим учас­ток выхода из дан­ной фун­кции и попада­ем на сле­дующий учас­ток кода.

Учас­ток кода переда­чи выпол­нения шелл‑коду

Пос­ле выхода из фун­кции VirtualAlloc в регис­тре EAX 029E0000 хра­нит­ся адрес выделен­ной памяти. Затем фун­кция call 2836512 записы­вает код в выделен­ное адресное прос­транс­тво, инс­трук­ция jmp dword ptr ss:[ebp-4] исполь­зует­ся для переда­чи выпол­нения в шелл‑код. Оста­новим­ся на этой инс­трук­ции, щел­кнем пра­вой кноп­ки мыши, выберем переход к кар­те памяти и пос­мотрим, какие пра­ва исполь­зуют­ся для выделен­ной памяти по адре­су ss:[ebp-4].

Пра­ва дос­тупа выделен­ного учас­тка кода

Как вид­но из рисун­ка выше, в выделен­ной памяти уста­нов­лены пра­ва ERW на чте­ние, запись и выпол­нение. Далее мы попада­ем в учас­ток исполня­емо­го кода по адре­су, выделен­ному с помощью фун­кции Windows API VirtualAlloc.

Учас­ток шелл‑кода

Здесь вре­донос­ный код получа­ет адре­са фун­кций в биб­лиоте­ках user32.dllkernel32.dllntdll.dll.

По­луче­ние адре­сов исполь­зуемых WinAPI-фун­кций из биб­лиотек user32, kernel32, ntdll

Ес­ли про­лис­тать ниже, то из биб­лиоте­ки kernel32 заг­ружа­ется 16 фун­кций: WinExecCreateFileWriteFileCloseHandleCreateProcessAGetThreadContextVirtualAllocVirtualAllocExVirtualFreeReadProcessMemoryWriteProcessMemorySetThreadContextResumeThreadWaitForSingleObjectGetModuleFileNameAGetCommandLineA.

Да­вай погово­рим о методе, который вре­донос исполь­зует, что­бы скры­вать стро­ки от иссле­дова­теля, — Stack Strings. Основная идея это­го метода зак­люча­ется в переме­щении стро­ки в стек по одно­му сим­волу. Обыч­но для это­го выделя­ется блок памяти, далее с помощью инс­трук­ции MOV сим­вол помеща­ется в выделен­ную область.

Пос­ле это­го вре­донос вызыва­ет фун­кцию RegisterClassExA, а затем запуты­вает две стро­ки — saodkfnosa9uin и mfoaskdfnoa. Спус­тись ниже в коде, и уви­дишь опи­сан­ный про­цесс.

Во вре­мя поведен­ческо­го ана­лиза мы обна­ружи­ли, что пос­ле запус­ка фай­ла соз­дает­ся дочер­ний про­цесс, в который переда­ется выпол­нение, а так­же из биб­лиоте­ки kernel32.dll заг­ружа­ются фун­кции CreateProcessAVirtualAllocExGetThreadContextWriteProcessMemorySetThreadContext и ResumeThread. Зна­чит, вре­донос­ный модуль исполь­зует тех­нику Process Hollowing.

Так называ­ется один из популяр­ных методов внед­рения вре­донос­ного кода в память про­цес­са. Что­бы добить­ся резуль­тата, вре­донос­ное ПО уда­ляет легитим­ный код из памяти целево­го про­цес­са и переза­писы­вает это прос­транс­тво памяти сво­им исполня­емым фай­лом.

Сна­чала вре­донос­ная прог­рамма соз­дает новый про­цесс в при­оста­нов­ленном режиме CreateProces с фла­гом CREATE_SUSPENDED (0x00000004) и CREATE_NO_WINDOW (0x08000000). Основной поток нового про­цес­са находит­ся в при­оста­нов­ленном сос­тоянии и ждет, пока будет выз­вана фун­кция ResumeThread. Затем память целево­го про­цес­са отклю­чают с исполь­зовани­ем ZwUnmapViewOfSection либо NtUnmapViewOfSection и содер­жимое легитим­ного фай­ла заменя­ется вре­донос­ной полез­ной наг­рузкой.

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

Спус­каем­ся ниже по коду, исполь­зуя кла­вишу F8, и попада­ем к сле­дующе­му учас­тку кода.

Вы­зов фун­кции CreateProcessA

В регис­тре ECX содер­жится адрес фун­кции CreateProcessA, которая выпол­няет­ся с парамет­ром dwCreationFlags, рав­ным 0x08000004.

Да­лее про­исхо­дит выделе­ние памяти с помощью фун­кции VirtualAlloc.

Вы­деле­ние памяти

Па­мять выделя­ется по адре­су 001F0000. Перей­дем к дам­пу и уви­дим, что он пока пуст.

Дамп выделен­ной памяти

Сле­дующим эта­пом вызыва­ется фун­кция GetThreadContext с целью получить кон­текст потока.

Вы­зов фун­кции GetThreadContext

Вы­зыва­ется фун­кция ReadProcessMemory для получе­ния дес­крип­тора про­цес­са.

Вы­зов фун­кции ReadProcessMemory

Про­исхо­дит вызов фун­кции ZmUnmapViewOfSection, которая отклю­чает память целево­го про­цес­са.

Вы­зов фун­кции ZmUnmapViewOfSection

И наконец, выпол­няет­ся вызов фун­кции VirtualAllocEx, что­бы выделить память для вре­донос­ного модуля.

Учас­ток вызова фун­кции VirtualAllocEx
Стек вызыва­емой фун­кции

Вы­зыва­емая фун­кция име­ет пять аргу­мен­тов, что мы и видим в сте­ке: дес­крип­тор про­цес­са, ука­затель на адрес области кода, раз­мер выделя­емой области, тип выделе­ния памяти и защита памяти для выделен­ной области. Как вид­но из сте­ка, параметр 0x00003000 озна­чает MEM_COMMIT (0x00001000) | MEM_RESERVE (0x00002000). Зна­чение 0x00000040 (PAGE_EXECUTE_READWRITE) говорит нам о том, что в выделен­ной области раз­решен дос­туп на выпол­нение, запись и чте­ние.

Ад­рес 0x00400000 ука­зыва­ет на адрес, где будет рас­полагать­ся вре­донос­ный код. Далее вызыва­ется фун­кция NtWriteVirtualMemory.

Вы­зов фун­кции NtWriteVirtualMemory

Вы­зов про­исхо­дит со сле­дующи­ми парамет­рами, пред­став­ленны­ми в сте­ке.

Зна­чение сте­ка вызова фун­кции NtWriteVirtualMemory

Зна­чение 0x00000270 — это дес­крип­тор про­цес­са, 0x00400000 — базовый адрес для записи в ука­зан­ном про­цес­се, 0x29915A0 — адрес буфера, который содер­жит содер­жимое для записи в адресное прос­транс­тво про­цес­са, 0x00000400 — раз­мер для записи в про­цесс.

Здесь вре­донос­ный код записы­вает каж­дый сег­мент исполня­емо­го фай­ла в новое адресное прос­транс­тво. Ниже пред­став­лено содер­жимое сте­ка при каж­дом вызове фун­кции NtWriteVirtualMemory.

За­пись сег­мента .text
За­пись сег­мента .rdata
За­пись сег­мента .reloc

Спус­каем­ся ниже и видим выпол­нение фун­кции WriteProcessMemory, которая исполь­зует­ся для записи из буфера в адресное прос­транс­тво про­цес­са.

Вы­пол­нение фун­кции WriteProcessMemory

Стек содер­жит сле­дующие дан­ные.

Зна­чение сте­ка

Зна­чение 0x029016EC — это адрес, который содер­жит дан­ные для записи.

Пос­ле это­го вызыва­ется фун­кция SetThreadContext, которая соз­дает кон­текст для ука­зан­ного потока, и фун­кция ResumeThread для возоб­новле­ния работы нового исполня­емо­го фай­ла.

Вы­зов фун­кции SetThreadContext
Вы­зов фун­кции ResumeThread

Пе­ред выпол­нени­ем фун­кции ResumeThread мы получим дамп соз­данно­го про­цес­са. Для это­го вос­поль­зуем­ся пла­гином ScyllaHide. Наж­ми на вклад­ку «Модули → Scylla».

За­пуск пла­гина ScyllaHide

Сле­дующим эта­пом мож­но ана­лизи­ровать рас­пакован­ный код в IDA Pro, которая име­ет удоб­ный пла­гин HexRays для деком­пиляции кода. Необ­ходимо най­ти код генера­ции клю­ча для шиф­рования фай­лов и алго­ритм шиф­рования, но такое иссле­дова­ние выходит за рам­ки нашей статьи.

На текущем эта­пе нам уда­лось рас­паковать вре­донос­ный модуль, мы разоб­рались с тех­никой Process Hollowing в коде. Теперь нуж­но раз­работать инди­като­ры ком­про­мета­ции.

Соз­дадим прос­тое YARA-пра­вило для детек­тирова­ния вре­доно­са. При соз­дании сиг­натур для это­го семей­ства шиф­роваль­щиков необ­ходимо про­ана­лизи­ровать мно­жес­тво фай­лов, най­ти общие учас­тки кода и стро­ки. А для это­го может при­годить­ся полез­ный пла­гин mkYARA в IDA Pro.

rule detect_ransomware

{

meta:

description = "Detect malware ransomware"

autor = "rayhunt454"

strings:

$s = "gdi32.dll" nocase

$s1 = "moz\\vidaj.pdb" nocase

$s3 = "<!<-<C<O<X<^<g<s<|<"

condition:

uint16(0) == 0x5A4D and all of them

}

Вы­пишем так­же инди­като­ры ком­про­мета­ции (IOCs), которые мож­но заг­рузить в Loki Scanner и Suricata.

  • MD5: a2f33095ef25b4d5b061eb53a7fe6548
  • SHA1: b38a8cb06507adb966dfdb809403f8f7f64ca534
  • URLs: https://api[.]2ip[.]ua,https://tzgl[.]org/files/1/build3.exe,http://tzgl[.]org/fhsgtsspen6/get[.]php?pid=AD4334DBE387EF198B77CC7408B38C8F&first=false`
  • Domains: api.2ip.uakotob.toptzgl.org

ЗАКЛЮЧЕНИЕ

В этой лабора­тор­ной работе мы рас­пакова­ли вре­донос­ный файл, иссле­дова­ли его поведе­ние. При динами­чес­ком ана­лизе разоб­рали тех­нику внед­рения в про­цесс Process Hollowing, раз­работа­ли собс­твен­ные инди­като­ры ком­про­мета­ции. Мы выяс­нили, что вре­донос­ный файл отно­сит­ся к шиф­роваль­щикам, глав­ная задача которых — зашиф­ровать важ­ные дан­ные, что­бы затем пот­ребовать выкуп.

Читайте ещё больше платных статей бесплатно: https://t.me/hacker_frei