Spalio 27 d. „Microsoft“ išleido naują įrankį pavadinimu EMET (Enhanced Mitigation Evaluation Toolkit), kuris jų teigimu padeda apsaugoti programas nuo įvairių kodo vykdymo atakų jų neperkompiliuojant. Pabandykime trumpai apžvelgti ir paanalizuoti šio įrankio veikimo principą.
Taigi, „Enhanced Mitigation Evaluation Toolkit“ yra pakankamai sunkiai į lietuvių kalbą išverčiamas pavadinimas, kuriuo norėta pasakyti, jog tai „pagerintas“ (enhanced) „įrankis“ (toolkit) skirtas „įvertinti/išbandyti“ (evaluation) įvairioms „apsaugoms“ (mitigation) prieš kodo vykdymo atakas. Žodžiu „išbandyti“, turbūt turėta omeny tai, jog pasinaudoję šia programa galime įjungti kelias apsaugas atskiroms programoms neįjungiant jų visai sistemai.
EMET pagalba kiekvienai jau sukompiliuotai programai, t.y. neturint priėjimo prie išeities tekstų, galime įjungti šias apsaugas:
SEHOP - apsaugo nuo SEH (Structured Exception Handler) perrašymo panaudojimo įvairių pažeidžiamumų išnaudojime. SEH - tai mechanizmas skirtas apdoroti išimtinėm situacijom (exceptions). SEH sudaro vienkryptis apdorojimo funkcijų (handler'ių) sąrašas esantis steke. Šios funkcijos yra kviečiamos įvykus kokiai nors išimtinei situacijai, pvz. dalybai iš nulio, ar bandymui įrašyti į neprieinamą atmintį. Vienkryptį SEH sąrašą sudaro du elementai - nuoroda į sekantį handler'į bei dabartinio handler'io adresas (iškvietus kokį nors handler'į jis gali atsisakyti apdoroti išimtinę situaciją priklausomai nuo jos tipo ir pan., o tokiu atveju kviečiamas sekantis sąraše esantis handler'is). Taigi esant kokiam nors steko perpildymui, perrašius SEH įrašą ir sukėlus kokią nors išimtinę situaciją bus paleidžiamas kodas mūsų perrašytu adresu. SEHOP nuo šito apsaugo vienkrypčio sąrašo gale įdėdamas įrašą. Prieš paleidžiant kiekvieną handler'į yra pereinama per visą sąrašą ir patikrinama ar anksčiau minėtas įrašas egzistuoja, jei ne - handler'is nevykdomas. Perrašant SEH įrašus būtina perrašyti ir nuorodą į sekantį handler'į, tos nuorodas reikšmę atspėti yra nepraktiška, todėl ji bus sugadinta ir tikrinimo metu nebus pasiekiamas SEHOP įrašas ir perrašytas handler'is nebus vykdomas.
Dynamic DEP (Data Execution Prevention) - apsaugo nuo kodo vykdymo atakų pažymint atminties gabalus nevykdomais pvz. nevykdomais pažymimi stekas bei heap'as kas padeda apsaugoti nuo steko bei heap'o perpildymo pažeidžiamumų.
NULL page allocation - apsaugo nuo NULL rodyklės panaudojimui kodo vykdymui. Windows operacinėse sistemose tai nėra labai praktiška, tačiau NULL rodyklės panaudojimą (NULL pointer dereference) įmanoma panaudoti kodo vykdymui. Nuo to apsaugoma išskiriant atminties gabalą ties nuliniu adresu.
Heap spray allocation - padeda apsaugoti programą nuo heap'o užpildymo panaudojimo pažeidžiamumams išnaudoti. Pasiekus kodo vykdymą kartais yra neįmanoma sužinoti tikslaus adreso į kurį galime nukreipti kodą, todėl kai kuriose programose, pavyzdžiui interneto naršyklėje, panaudodami „JavaScript“ galime užpildyti heap'ą shellkodu bei šokti į kokį nors aukštą adresą, kurį galime prieš tai apskaičiuoti stebėdami programos veiklą. Apsaugoti nuo šio metodo padeda kai kurių atminties gabalų išskyrimas, tai apsunkina tinkamo adreso nuspėjimą.
Taigi, parsisiunčiame EMET, platinamą „Zip“ archyvo pavidalu, išarchyvuojame ir matome žemiau esančiame paveikslėlyje esančius failus.
Atsidarome readme.rtf, jį perskaitę sužinome tik informaciją reikalingą šio įrankio konfigūracijai, t.y. aprašomas tik EMET_conf.exe. Ši, komandinės eilutės pagalba valdoma, programa naudojama pažymėti kurios programos turi būti apsaugomos, kaip jos bus apsaugomos ir t.t. mus tai nelabai domina, todėl įdėmiai perskaitę kitų failų pavadinimus galime nuspėti kelis dalykus:
- Na ne iš failų pavadinimų tačiau iš apsaugų tipo galime spręsti, jog kai kurioms apsaugoms realizuoti reikės vykdyti kodą apsaugomos programos proceso kontekste (pvz. NULL atminties gabalo išskyrimas).
- Todėl pastebime, kad egzistuoja failas pavadinimu EMET_injector.exe - jis turbūt yra naudojamas „įskiepyti“ EMET.dll biblioteką, kuri ir atliks visą darbą apsaugomo proceso kontekste.
- Taipogi egzistuoja EMET_Launcher.exe bei EMET_Launcher64.exe. Iš pavadinimo, manau, aišku, kad tai dvi versijos skirtos dviem skirtingų tipų operacinėms sistemoms. Ką jie konkrečiai paleidžia (launch) ar programą, ar EMET_injector.exe kol kas neaišku.
Norėdami išsiaiškinti kaip viskas tikrai vyksta atlikime eksperimentą - apsaugokime kokią nors programą bei stebėkime jos paleidimą su „Sysinternals“ įrankiu „Procmon“. Eksperimentą atliksime operacinėje sistemoje „Windows Vista SP2 x64“.
Apsaugojimui pasirinkau su operacine sistema kartu platinamą calc.exe 32 bitų versiją, nors iš esmės galima būtų naudoti bet kokią programą.
Su EMET_conf.exe apsaugome calc.exe, pasinaudoję šia komandine eilute:
Paleidžiame „Procmon“, padarome, jog filtruotų pagal procesų pavadinimus EMET_Launcher.exe, EMET_Launcher64.exe, EMET_injector.exe bei calc.exe. Paleidžiame calc.exe, jis pasileidžia be problemų, sustabdome „Procmon“ ir einame žiūrėti jo įrašų. Screenshot'ų ar paties įrašų žurnalo čia nepateiksiu, nes jis labai ilgas, tiesiog nupasakosiu procesą kurio metu pasileido calc.exe.
Visų pirma, paspaudus ant calc.exe, pasileido ne calc.exe, o EMET_Launcher64.exe. Kaip taip galėjo nutikti? Greičiausiai buvo panaudotas PE image'o nukreipimas (Image file hijacking). Tą galime greit patikrinti su dar vienu „Sysinternals“ įrankiu - autoruns. Pasileidę jį nueiname į skiltį „Image Hijacks“ ir matome:
Jog vietoj calc.exe vieno registro įrašo pagalba paleidžiamas EMET_Launcher64.exe. Grįžtame prie pasileidimo proceso. Po EMET_Launcher64.exe pasileidimo jis paleidžia calc.exe po to paleidžia EMET_injector.exe, kuris iš disko nuskaito EMET.dll bei jį „įšvirkščia“ į calc.exe procesą, po ko abu EMET procesai išsijungia. Taigi, dabar jau drąsiai galime teigti, jog pagrindinį darbą atlieką EMET.dll, todėl įsijungiame IDA ir nagrinėjame toliau.
Išanalizuojame EMET.dll su IDA ir sukame galvą nuo ko pradėti ieškoti mums reikalingų funkcijų, kuriose atliekamas pats apsaugojimas. Kadangi skaitėme „readme“ - prisiminame, jog apsaugos nustatymai saugomi registre, pasižiūrėję EMET.dll importuojamas funkcijas matome, jog naudojamos registro funkcijos. Peržiūrėję kelias funkcijas, kuriose naudojami registro API, nieko gero nerandame, todėl galvojame toliau. Prisimename, jog viena iš apsaugų - tai atminties gabalo ties NULL adresu išskyrimas, kadangi teko susidūrti su „Windows“ programavimu, suvokiame, jog tam greičiausiai bus naudojamos „VirtualXXX“ šeimos funkcijos, todėl prie importuojamų API susirandame „VirtualAlloc“ ir žiūrime iš kur ji kviečiama. Pasirinkę pirmą funkciją iš naudojančių „VirtualAlloc“ sąrašo matome, jog pataikėme tiesiai ten kur reikia.
Matome, jog tai ganėtinai paprasta funkcija, kurios pagalba įdiegiamos visos apsaugos. Prieš įdiegiant kiekvieną apsaugą iškviečiama sub_11070, kuri iš registro paima tam tikrą reikšmę, pagal kurią nustatoma ar reikia tą apsaugą įdiegti. Viena iš apsaugų - DEP įjungimas atliekama be papildomų procedūrų, tiesiogiai šioje funkcijoje, nuo jos paaiškinimo ir pradėsiu.
Registro pagalba patikrinama ar reikia įjungti šią apsaugą, jei reikia, panaudojus „GetModuleHandleW“ API paimamas handle į kernel32.dll, tas „handle“ paduodamas API „GetProcAddress“ - API, kuriam taip pat paduodamas ieškomos funkcijos pavadinimas - „SetProcessDEPPolicy“, jis grąžina adresą į tą funkciją, kuri po to iškviečiama per „eax“ registrą su prieš tai į steką įstumtu parametru - „3“. Taip įjungiamas DEP'as šiam procesui.
Kita apsauga taipogi tiesiogiai įjungiama šioje funkcijoje tai atminties išskyrimas ties NULL adresu.
Patikrinama ar registre „null_allocation“ reikšmė yra 1 ir ta pati reikšmė panaudojama „VirtualAlloc“ API iškvietimui. Šis API išskiria 0x400 dydžio atminties gabalą ties 0x00000001 adresu su „flProtect“ parametru „1“ (atitinka „PAGE_N OACCESS“ opciją) t.y. kiekvienas bandymas skaityti ar rašyti į šį atminties regioną bus neprieinamas ir sukels išimtinę situaciją.
Sekanti apsauga - heap'o atminties išskyrimas, ji jau susideda iš didesnio kiekio funkcijų, todėl visų jų nerodysiu. Esmė šios apsaugos ta, jog iš registro „heap_pages“ rakto paimamos adresų reikšmės atskirtos kabliataškiais. Štai visos šios reikšmės:
0x0a040a04; 0x0a0a0a0a; 0x0b0b0b0b; 0x0c0c0c0c; 0x0d0d0d0d; 0x0e0e0e0e; 0x04040404; 0x05050505; 0x06060606; 0x07070707; 0x08080808; 0x09090909; 0x14141414
Ties kiekvienu šiuo adresu, kaip ir su NULL adresu, išskiriamas 0x400 dydžio atminties gabalas su „flProtect“ parametru „1“.
Paskutinė, sudėtingiausia, apsauga - SEHOP. Visų pirma patikrinama ar ties „HKLM\System\CurrentControlSet\Control\Session Manager\Kernel“ esantis raktas „DisableExceptionChainValidation“ yra lygus „0“, jei jis lygus reiškia, jog SEHOP jau yra įjungtas visai sistemai, todėl apsaugos įjungti nebereikia. Jei SEHOP neįjungtas visai sistemai tai įdiegiamas SEH įrašas SEH sąrašo gale, bei su „AddVectoredExceptionHandler“ pagalba įdiegiamas vektorinis išimtinių situacijų handler'is, kuris turi prioritetą prieš SEH. Todėl įvykus išimtinei situacijai prieš kviečiant SEH iškviečiamas įdiegtas vektorinis handler'is, kuris patikrina ar anksčiau įrašytas SEH įrašas egzistuoja sąrašo pabaigoje , jei jis neegzistuoja, reiškia kažkas sujaukė SEH sąrašą, todėl procesas iškarto išsijungia su „TerminateProcess“ API pagalba.
Išsiaiškinome kaip veikia EMET, tai turėtų padėti mums suvokti kam šis įrankis reikalingas ir kur jį galime pritaikyti. Deja, EMET nėra saugumo panacėja, tik laiko klausimas, kada įsilaužėliai ras būdą kaip apeiti ankščiau aptartas apsaugas, tačiau dabar šios programos pagalba neįdedant didelių pastangų galime žymiai padidinti mūsų kritinės programinės įrangos patikimumą.