Skoči na vsebino

SI-CERT TZ013 / Zlonamerna koda v NSIS nameščevalniku

Na SI-CERT smo pred kratkim prejeli prijavo neobičajnega sporočila, ki ga prejemnik ni pričakoval:

From: Univerza v Lljubljani
Subject: ZAHTEVA ZA PONUDBO
Sumljivo sporočilo

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:

File name, File Type, File Info, File Size, PE Size, Created, Modified, MD5, SHA1
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:

Command prompt
http://nsis.sf.net/NSIS_Error
NSIS Error

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"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
    <assemblyIdentity version="1.0.0.0" processorArchitecture="*" name="Nullsoft.NSIS.exehead" type="win32"/>
    <description>Nullsoft Install System v3.02</description><trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
        <security>
            <requestedPrivileges>
                <requestedExecutionLevel level="asInvoker" uiAccess="false"/>
            </requestedPrivileges>
        </security>
    </trustInfo>
    <compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
        <application><supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
            <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
            <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
            <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
        </application>
    </compatibility>
</assembly>

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.

EF BE AD DE
Orodje HxD (Hex urejevalnik)

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.

$PLUGINSDIR, Fraughan, nonselected, NSIS.nsi
Vsebina exe datoteke

Če uporabimo 7-Zip verzijo 15.05, lahko pridobimo datoteke in razstavljeno NSIS skripto (.nsi).

Notepad++
NSIS.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
File Refulge131.Uds130      ; Shrani Refulge131.Uds130 v %APPDATA%\Beset\Fraughan\Phototypography
File Uopsigeligheden.Bla    ; Shrani Uopsigeligheden.Bla v %APPDATA%\Beset\Fraughan\Phototypography
 
$4 = "$APPDATA\Beset\Fraughan\Phototypography\Uopsigeligheden.Bla"
FileOpen $file "$APPDATA\Beset\Fraughan\Phototypography\Refulge131.Uds130" ; Odpri Refulge131.Uds130
 
$index = 9755
$str = ""
$chr = 0
 
loop:
  StrCmp $chr "j" loop_end  ; Če je v $chr vrednost "j" (ascii vrednost 0x6A), potem skoči na loop_end:
  FileSeek $file $index     ; Postavi kazalec datoteke (Refulge131.Uds130) na vrednost spremenljivke $index
  FileRead $file $chr 1     ; Preberi 1 bajt iz Refulge131.Uds130 in vrednost shrani v $chr
  StrCpy $str $str$chr      ; Dodaj $chr na konec $str
  IntOp $index $index + 22  ; Povečaj $index za 22
  GoTo loop                 ; Skoči na začetek zanke (loop:)
loop_end:
 
System::Call $str   ; Pokliči funkcijo $str
$str = ""
$chr = 0
GoTo loop

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.

Preberite tudi

Strah hitro zleze v kosti

Izkušnje stanovskih kolegov kažejo, da napadi onemogočanja na spletne strani državnih ustanov ne pojenjajo. Podobne napade lahko pričakujemo tudi v Sloveniji.
Več

Onemogočanje spletnega mesta predsednice Republike Slovenije

Danes popoldne, 27. marca 2024 okoli 15:30, je prišlo do onemogočanja spletnega mesta predsednice Republike Slovenije. Na dogodek so se takoj odzvale pristojne institucije. Nacionalni odzivni center za kibernetsko varnost …
Več

SI-CERT TZ015 / Analiza bančnega trojanca Anatsa za Android mobilne naprave

V analizo smo prejeli dve sumljivi aplikaciji za Android naprave. Izkazalo se je, da gre za virus vrste Anatsa.
Več