Hrúguárásir (e. Heap Exploitation)
Kynning
Hrúguárásir (e. heap exploitation) eru flóknari en stack overflow, en mjög algengar í CTF og raunverulegum veikleikum (e. vulnerabilities).
Þegar malloc() er kallað, gefur libc þér blokk (e. chunk) úr hrúgunni. Þessar blokkur eru raktar í gagnaskipan (e. data structure) sem libc heldur utan um.
Forsendir
Gott er að þekkja Stack/heap minnislíkanið og C forritun áður en þú heldur áfram.
Uppbygging malloc chunk
Hverri malloc blokk fylgir hausgögn (e. metadata):
┌─────────────────┐
│ prev_size │ 8 bæti — stærð fyrri blokkar (ef laus)
├─────────────────┤
│ size | flags │ 8 bæti — stærð + flaggar (P/M/A bits)
├─────────────────┤ ← malloc() skilar bendi HINGAÐ
│ │
│ notendagögn │ ← Þetta er það sem þú notar
│ │
└─────────────────┘
; Næsta blokk byrjar beint á eftir
Flaggar í size-reitnum: - P (PREV_INUSE): fyrri blokk er í notkun - M (IS_MMAP): úthlutað með mmap - A (NON_MAIN_ARENA): notað í þráðum (e. threads)
Laus blokka (e. Free Lists)
Þegar free(p) er kallað, fer blokkin í lista yfir lausar blokkur (e. free list / bin).
libc hefur nokkrar tegundir af bins:
| Bin | Stærð | Lýsing |
|---|---|---|
| tcache | < ~1032 bæti | Hraðinn cache (e. per-thread cache), per-thread |
| fastbin | 16–80 bæti | Hraðinn listi, LIFO |
| smallbin | 16–1008 bæti | Tvítengdur listi (e. doubly linked list) |
| largebin | > 1008 bæti | Stærri blokkir |
| unsorted bin | Allt | Tímabundin geymsla áður en flokkun |
Hrúguyfirflæði (e. Heap Overflow)
Svipað og stack overflow, en hér skrifum við yfir hausgögn eða notendagögn næstu blokkar á hrúgunni.
char *a = malloc(32);
char *b = malloc(32); // Beint á eftir a í minni
strcpy(a, long_input); // Skrifar yfir í b!
┌──────────┐
│ chunk a │ ← Við skrifum hér
│ gögn │
├──────────┤
│ chunk b │ ← En við yfirskrifum hingað
│ gögn │ ← Við getum breytt gögnum eða size/flags
└──────────┘
Dæmi: Breyting á stærð
Ef við yfirskrifum size reit næstu blokkar, getur libc misskilið minnisuppbygginguna og við getum nýtt okkur til að fá blokkur sem skarast (e. overlapping chunks).
Use-After-Free (UAF)
Use-After-Free (notkun eftir losun) á sér stað þegar forrit notar bendi á minni sem hefur þegar verið losað með free().
char *p = malloc(64);
free(p);
// p bendir enn á sama vistfang!
printf("%s\n", p); // Óskilgreind hegðun (e. undefined behavior)
p[0] = 'A'; // Skrifar á losað minni, hættulegt!
Nýting UAF
- Losa blokk
A, fer í tcache/bin - Úthluta nýja blokk
Baf sömu stærð →Bfær sama minnið ogAhafði - Skrifa í
B→ þar sem gamli bendirinnAbendir enn á sama stað, getum við stjórnað hvaðAles/skrifar
struct User {
char name[32];
void (*print_fn)(char*); // Fallbendi (e. function pointer)
};
User *u = malloc(sizeof(User));
u->print_fn = safe_print;
free(u);
// Árásarmaður fær úthlutað yfir sama minni og skrifar sinn fallbenda
// Þegar kóðinn kallar u->print_fn(u->name) → keyrðu kóði árásarmanns
Double Free
Double free (tvöföld losun) á sér stað þegar free() er kallað tvisvar á sama bendi.
char *p = malloc(64);
free(p);
free(p); // VILLA! p er þegar laus
Í eldri útgáfum af libc var þetta nýtt til að fá tvær malloc úthlutanir á sama minni, þ.e. tvær blokkur sem sýnast ólíkar en eru á sama vistfangi.
tcache poisoning
Í nýlegri libc (tcache, frá glibc 2.26) geymir laus blokk next bendi (á næstu lausa blokk). Double free leyfir okkur að:
- Losa chunk
Atvisvar →Aer tvisvar í tcache-listanum - Úthluta
A, við getum breyttnextbendinum - Næsta
mallocskilarAaftur, en síðan skilar það hvað sem við skrifuðum ínext
# Þetta er mjög einfaldað
# Eftir double free og poisoning:
# malloc() → skilar chunk A
# skrifa: fake_chunk_addr í A->next
# malloc() → skilar chunk A aftur
# malloc() → skilar fake_chunk_addr ← við stjórnum þessu!
Fastbin dup
Svipað og tcache poisoning en notar fastbin lista:
void *a = malloc(40);
void *b = malloc(40);
free(a);
free(b);
free(a); // fastbin: a -> b -> a (hringtenging!)
void *p1 = malloc(40); // = a
void *p2 = malloc(40); // = b
// Skrifa á p1 → breytir 'a->next'
void *p3 = malloc(40); // = a aftur
void *p4 = malloc(40); // = hvað sem við skrifuðum í a->next!
Tcache
Frá glibc 2.26 hefur hvert þráð (e. thread) sitt eigið tcache (per-thread cache). Það geymir allt að 7 lausar blokkur af hverri stærð.
tcache hefur færri öryggisathuganir (e. security checks) en fastbin/smallbin, þetta gerir það auðveldara í nýtingu.
tcache poisoning (nútímalegt)
Frá glibc 2.32 var bætt við safe-linking, þar sem next bendi eru dulkóðuð (e. obfuscated):
stored = (pos >> 12) XOR next
Til að afkóða:
# Ef við getum lesið gildi úr tcache
leak = leaked_next_ptr
heap_key = leak >> 12
real_next = leak ^ heap_key # Ef heap_key er þekkt
Gagnleg tól (e. Tooling)
# í pwndbg:
heap # Yfirlit yfir hrúguna
bins # Sýnir alla bins (tcache, fastbin, osfrv.)
vis_heap_chunks # Fallegt myndrænt yfirlit
malloc_chunk 0x... # Skoða tiltekna blokk
# pwntools heap hjálparföll
from pwn import *
p = process('./challenge')
# ...
gdb.attach(p, 'heap\nbins\nvis_heap_chunks\nc')
Gátlisti fyrir heap verkefni
- [ ] Greina minnisstjórnun forritsins: hvaða föll eru notuð?
- [ ] Leita að UAF, double free, eða heap overflow
- [ ] Athuga glibc útgáfu:
./libc.so.6→strings libc.so.6 | grep "GNU C Library" - [ ] Ákveða markmiðið: skrifa á
__free_hook,__malloc_hook, GOT, eða return address - [ ] Nota heap debug tól í pwndbg (heap, bins, vis_heap_chunks)