hacktricks/binary-exploitation/heap/README.md

193 lines
12 KiB
Markdown
Raw Normal View History

# Heap
## Osnove Heap-a
Heap je osnovno mesto gde program može skladištiti podatke kada zahteva podatke pozivajući funkcije poput **`malloc`**, `calloc`... Osim toga, kada ti podaci više nisu potrebni, oni se oslobađaju pozivom funkcije **`free`**.
Kao što je prikazano, heap se nalazi odmah nakon što se binarni fajl učita u memoriju (proverite `[heap]` sekciju):
<figure><img src="../../.gitbook/assets/image (1241).png" alt=""><figcaption></figcaption></figure>
### Osnovna Aloakcija Blokova
Kada se zahteva da se neki podatak skladišti u heap-u, određeni prostor heap-a se alocira za to. Taj prostor će pripadati binu i rezervisaće se samo za traženi podatak + prostor za zaglavlja binova + minimalno pomeranje veličine binova za blok. Cilj je rezervisati što manje memorije bez komplikovanja pronalaženja svakog bloka. Za to se koriste informacije o metapodacima bloka kako bi se znalo gde se nalazi svaki korišćeni/slobodan blok.
Postoje različiti načini rezervisanja prostora, uglavnom zavisno o korišćenom binu, ali opšta metodologija je sledeća:
* Program počinje sa zahtevanjem određene količine memorije.
* Ako u listi blokova postoji dovoljno veliki blok koji može ispuniti zahtev, on će biti korišćen.
* To može značiti da će deo dostupnog bloka biti korišćen za ovaj zahtev, a ostatak će biti dodat u listu blokova.
* Ako nema dostupnog bloka u listi, ali još uvek postoji prostor u alociranoj memoriji heap-a, menadžer heap-a kreira novi blok.
* Ako nema dovoljno prostora u heap-u da se alocira novi blok, menadžer heap-a traži od kernela da proširi memoriju alociranu za heap, a zatim koristi tu memoriju da generiše novi blok.
* Ako sve propadne, `malloc` vraća null.
Imajte na umu da ako tražena **memorija pređe prag**, **`mmap`** će se koristiti za mapiranje tražene memorije.
### Arene
U **višenitnim** aplikacijama, menadžer heap-a mora sprečiti **trke za stanjem** koje bi mogle dovesti do rušenja. Početno je to bilo postignuto korišćenjem **globalne međusobne isključivosti** kako bi se osiguralo da samo jedna nit može pristupiti heap-u u isto vreme, ali to je uzrokovalo **probleme sa performansama** zbog uskog grla koje je prouzrokovala međusobna isključivost.
Da bi se to rešilo, ptmalloc2 allocator heap-a je uveo "arene", gde **svaka arena** deluje kao **zaseban heap** sa svojim **sopstvenim** podacima **strukture** i **međusobnom isključivošću**, omogućavajući više niti da obavljaju operacije heap-a bez mešanja, pod uslovom da koriste različite arene.
Podrazumevana "glavna" arena upravlja operacijama heap-a za aplikacije sa jednom niti. Kada se dodaju **nove niti**, menadžer heap-a im dodeljuje **sekundarne arene** kako bi smanjio sukob. Prvo pokušava da svaku novu nit poveže sa neiskorišćenom arenom, kreirajući nove ako je potrebno, do granice od 2 puta broja CPU jezgara za 32-bitne sisteme i 8 puta za 64-bitne sisteme. Kada se dostigne granica, **niti moraju deliti arene**, što može dovesti do potencijalnih sukoba.
Za razliku od glavne arene, koja se proširuje korišćenjem `brk` sistemskog poziva, sekundarne arene kreiraju "pod-heapove" korišćenjem `mmap` i `mprotect` kako bi simulirale ponašanje heap-a, omogućavajući fleksibilnost u upravljanju memorijom za višenitne operacije.
### Pod-heapovi
Pod-heapovi služe kao rezerve memorije za sekundarne arene u višenitnim aplikacijama, omogućavajući im da rastu i upravljaju svojim sopstvenim regionima heap-a odvojeno od glavnog heap-a. Evo kako se pod-heapovi razlikuju od početnog heap-a i kako funkcionišu:
1. **Početni Heap vs. Pod-heapovi**:
* Početni heap se nalazi odmah nakon binarnog fajla programa u memoriji, i proširuje se korišćenjem `sbrk` sistemskog poziva.
* Pod-heapovi, korišćeni od strane sekundarnih arena, kreiraju se kroz `mmap`, sistemski poziv koji mapira određeni memorijski region.
2. **Rezervacija Memorije sa `mmap`**:
* Kada menadžer heap-a kreira pod-heap, rezerviše veliki blok memorije kroz `mmap`. Ova rezervacija ne alocira memoriju odmah; jednostavno označava region koji druge sistemskih procesi ili alokacije ne bi trebali koristiti.
* Podrazumevana veličina rezervacije za pod-heap je 1 MB za 32-bitne procese i 64 MB za 64-bitne procese.
3. **Postepeno Proširenje sa `mprotect`**:
* Rezervisani memorijski region je prvobitno označen kao `PROT_NONE`, što znači da kernel ne mora alocirati fizičku memoriju za ovaj prostor još.
* Da bi "proširio" pod-heap, menadžer heap-a koristi `mprotect` da promeni dozvole stranica sa `PROT_NONE` na `PROT_READ | PROT_WRITE`, što podstiče kernel da alocira fizičku memoriju na prethodno rezervisane adrese. Ovaj postepeni pristup omogućava pod-heapu da se proširi po potrebi.
* Kada se ceo pod-heap iscrpi, menadžer heap-a kreira novi pod-heap da nastavi sa alokacijom.
### malloc\_state
**Svaki heap** (glavna arena ili arene drugih niti) ima **`malloc_state` strukturu.**\
Važno je primetiti da je **`malloc_state` struktura glavne arene** globalna promenljiva u libc-u (stoga se nalazi u prostoru memorije libc-a).\
U slučaju **`malloc_state`** struktura heap-ova niti, one se nalaze **unutar sopstvenog "heap-a" niti**.
Postoje neke zanimljive stvari koje treba primetiti iz ove strukture (videti C kod ispod):
* `mchunkptr bins[NBINS * 2 - 2];` sadrži **pokazivače** na **prvi i poslednji blokove** malih, velikih i nesortiranih **binova** (-2 je zato što se indeks 0 ne koristi)
* Stoga, **prvi blok** ovih binova će imati **pokazivač unazad na ovu strukturu** i **poslednji blok** ovih binova će imati **pokazivač unapred** na ovu strukturu. Što u osnovi znači da ako možete **procureti ove adrese u glavnoj areni** imaćete pokazivač na strukturu u **libc-u**.
* Strukture `struct malloc_state *next;` i `struct malloc_state *next_free;` su povezane liste arena
* Blok `top` je poslednji "blok", koji je u osnovi **sav preostali prostor heap-a**. Kada je top blok "prazan", heap je potpuno iskorišćen i potrebno je zatražiti više prostora.
* Blok `last reminder` dolazi iz slučajeva kada nije dostupan tačno određen blok veličine i stoga se veći blok deli, a preostali deo pokazivača se smešta ovde.
```c
// From https://heap-exploitation.dhavalkapil.com/diving_into_glibc_heap/malloc_state
struct malloc_state
{
/* Serialize access. */
__libc_lock_define (, mutex);
/* Flags (formerly in max_fast). */
int flags;
/* Fastbins */
mfastbinptr fastbinsY[NFASTBINS];
/* Base of the topmost chunk -- not otherwise kept in a bin */
mchunkptr top;
/* The remainder from the most recent split of a small request */
mchunkptr last_remainder;
/* Normal bins packed as described above */
mchunkptr bins[NBINS * 2 - 2];
/* Bitmap of bins */
unsigned int binmap[BINMAPSIZE];
/* Linked list */
struct malloc_state *next;
/* Linked list for free arenas. Access to this field is serialized
by free_list_lock in arena.c. */
struct malloc_state *next_free;
/* Number of threads attached to this arena. 0 if the arena is on
the free list. Access to this field is serialized by
free_list_lock in arena.c. */
INTERNAL_SIZE_T attached_threads;
/* Memory allocated from the system in this arena. */
INTERNAL_SIZE_T system_mem;
INTERNAL_SIZE_T max_system_mem;
};
typedef struct malloc_state *mstate;
```
### malloc\_chunk
Ova struktura predstavlja određeni deo memorije. Različita polja imaju različito značenje za alocirane i nealocirane delove.
```c
// From https://heap-exploitation.dhavalkapil.com/diving_into_glibc_heap/malloc_chunk
struct malloc_chunk {
INTERNAL_SIZE_T mchunk_prev_size; /* Size of previous chunk, if it is free. */
INTERNAL_SIZE_T mchunk_size; /* Size in bytes, including overhead. */
struct malloc_chunk* fd; /* double links -- used only if this chunk is free. */
struct malloc_chunk* bk;
/* Only used for large blocks: pointer to next larger size. */
struct malloc_chunk* fd_nextsize; /* double links -- used only if this chunk is free. */
struct malloc_chunk* bk_nextsize;
};
typedef struct malloc_chunk* mchunkptr;
```
Kao što je ranije komentarisano, ovi delovi takođe imaju neke metapodatke, veoma dobro predstavljene na ovoj slici:
<figure><img src="../../.gitbook/assets/image (1242).png" alt=""><figcaption><p><a href="https://azeria-labs.com/wp-content/uploads/2019/03/chunk-allocated-CS.png">https://azeria-labs.com/wp-content/uploads/2019/03/chunk-allocated-CS.png</a></p></figcaption></figure>
Metapodaci obično su 0x08B što ukazuje na trenutnu veličinu dela koristeći poslednja 3 bita da označe:
* `A`: Ako je 1, dolazi iz pod-heapa, ako je 0, nalazi se u glavnoj areni
* `M`: Ako je 1, ovaj deo je deo prostora alociranog sa mmap i nije deo heap-a
* `P`: Ako je 1, prethodni deo je u upotrebi
Zatim, prostor za korisničke podatke, i na kraju 0x08B da označi veličinu prethodnog dela kada je deo dostupan (ili za skladištenje korisničkih podataka kada je alociran).
Osim toga, kada su dostupni, korisnički podaci se koriste i za sadržavanje nekih podataka:
* Pokazivač na sledeći deo
* Pokazivač na prethodni deo
* Veličina sledećeg dela na listi
* Veličina prethodnog dela na listi
<figure><img src="../../.gitbook/assets/image (1243).png" alt=""><figcaption><p><a href="https://azeria-labs.com/wp-content/uploads/2019/03/chunk-allocated-CS.png">https://azeria-labs.com/wp-content/uploads/2019/03/chunk-allocated-CS.png</a></p></figcaption></figure>
{% hint style="info" %}
Primetite kako organizovanje liste na ovaj način sprečava potrebu za imanjem niza gde je svaki pojedinačni deo registrovan.
{% endhint %}
### Brzi primer Heap-a
Brzi primer heap-a sa [https://guyinatuxedo.github.io/25-heap/index.html](https://guyinatuxedo.github.io/25-heap/index.html) ali u arm64:
```c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void main(void)
{
char *ptr;
ptr = malloc(0x10);
strcpy(ptr, "panda");
}
```
Postavite prekidnu tačku na kraju glavne funkcije i saznajmo gde je informacija sačuvana:
<figure><img src="../../.gitbook/assets/image (1239).png" alt=""><figcaption></figcaption></figure>
Moguće je videti da je string panda sačuvan na `0xaaaaaaac12a0` (što je adresa data kao odgovor od strane malloc unutar `x0`). Proveravajući 0x10 bajtova pre toga, moguće je videti da `0x0` predstavlja da **prethodni blok nije korišćen** (dužina 0) i da je dužina ovog bloka `0x21`.
Dodatni prostor rezervisan (0x21-0x10=0x11) dolazi od **dodatnih zaglavlja** (0x10) i 0x1 ne znači da je rezervisano 0x21B već poslednja 3 bita dužine trenutnog zaglavlja imaju neka posebna značenja. Pošto je dužina uvek poravnata na granicu od 16 bajtova (na 64-bitnim mašinama), ovi bitovi zapravo nikada neće biti korišćeni od strane broja dužine.
```
0x1: Previous in Use - Specifies that the chunk before it in memory is in use
0x2: Is MMAPPED - Specifies that the chunk was obtained with mmap()
0x4: Non Main Arena - Specifies that the chunk was obtained from outside of the main arena
```
## Bins & Aloakcije/Memorija
Proverite šta su to binovi, kako su organizovani i kako se memorija alocira i oslobađa u:
{% content-ref url="bins-and-memory-allocations.md" %}
[bins-and-memory-allocations.md](bins-and-memory-allocations.md)
{% endcontent-ref %}
## Provere Bezbednosti Funkcija Heap-a
Funkcije uključene u heap će izvršiti određene provere pre nego što obave svoje akcije kako bi se osiguralo da heap nije oštećen:
{% content-ref url="heap-functions-security-checks.md" %}
[heap-functions-security-checks.md](heap-functions-security-checks.md)
{% endcontent-ref %}
## Reference
* [https://azeria-labs.com/heap-exploitation-part-1-understanding-the-glibc-heap-implementation/](https://azeria-labs.com/heap-exploitation-part-1-understanding-the-glibc-heap-implementation/)
* [https://azeria-labs.com/heap-exploitation-part-2-glibc-heap-free-bins/](https://azeria-labs.com/heap-exploitation-part-2-glibc-heap-free-bins/)