Unsorted Bin Attack
Reading time: 11 minutes
tip
Učite i vežbajte AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Učite i vežbajte GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Učite i vežbajte Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Podržite HackTricks
- Proverite planove pretplate!
- Pridružite se 💬 Discord grupi ili telegram grupi ili pratite nas na Twitteru 🐦 @hacktricks_live.
- Podelite hakerske trikove slanjem PR-ova na HackTricks i HackTricks Cloud github repozitorijume.
Osnovne informacije
Za više informacija o tome šta je unsorted bin pogledajte ovu stranicu:
Unsorted lists mogu upisati adresu unsorted_chunks (av)
u bk
polje chanka. Dakle, ako napadač može izmeniti adresu bk
pokazivača u chunk-u koji se nalazi u unsorted bin, mogao bi biti u mogućnosti da upise tu adresu na proizvoljnu adresu, što može pomoći da se leak-uje Glibc adresa ili zaobiđu neke zaštite.
Dakle, u suštini, ovaj napad omogućava da se postavi veliki broj na proizvoljnu adresu. Taj veliki broj je adresa, koja može biti heap adresa ili Glibc adresa. Tradicionalni cilj je bio global_max_fast
da bi se omogućilo kreiranje fast bin-ova većih veličina (i preći iz unsorted bin attack u fast bin attack).
- Moderno zabeleška (glibc ≥ 2.39):
global_max_fast
je postao 8‑bitni global. Besciljno upisivanje pokazivača tamo preko unsorted-bin write će prebrisati susedne podatke u libc-u i više neće pouzdano podići limit fastbina. Preferirajte druge ciljeve ili druge primitive protiv glibc 2.39+. Pogledajte "Modern constraints" ispod i razmotrite kombinovanje sa drugim tehnikama kao što su large bin attack ili fast bin attack kad imate stabilnu primitivu.
tip
T> Uzimajući u obzir primer iz https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/unsorted_bin_attack/#principle i koristeći 0x4000 i 0x5000 umesto 0x400 i 0x500 kao veličine chunk-ova (da biste izbegli Tcache) moguće je videti da sada greška malloc(): unsorted double linked list corrupted
biva pokrenuta.
Dakle, ovaj unsorted bin attack sada (između ostalih provera) takođe zahteva da se dvostruko vezana lista može popraviti da bi se izbeglo abortovanje victim->bk->fd == victim
ili victim->fd == av (arena)
, što znači da adresa na koju želimo da upišemo mora imati adresu lažnog chanka na svojoj fd
poziciji i da lažni chunk fd
pokazuje na arena.
caution
Imajte na umu da ovaj napad korumpira unsorted bin (a time i small i large). Dakle sada možemo koristiti samo alokacije iz fast bin-a (kompleksniji program može izvršiti druge alokacije i srušiti se), i da bismo to pokrenuli moramo alocirati istu veličinu ili će se program srušiti.
Imajte na umu da prepisivanje global_max_fast
može pomoći u ovom slučaju uz verovanje da će fast bin moći da se pozabavi svim ostalim alokacijama dok exploit ne bude završen.
Kod od guyinatuxedo to vrlo dobro objašnjava, mada ako modifikujete malloc-ove da alociraju memoriju dovoljno veliku da ne završe u Tcache, možete videti da se pojavljuje ranije pomenuta greška koja ovu tehniku onemogućava: malloc(): unsorted double linked list corrupted
Kako se zapravo vrši upis
- The unsorted-bin write se pokreće pri
free
kada se oslobođeni chunk ubacuje na početak unsorted liste. - Tokom umetanja, allocator izvršava
bck = unsorted_chunks(av); fwd = bck->fd; victim->bk = bck; victim->fd = fwd; fwd->bk = victim; bck->fd = victim;
- Ako možete podesiti
victim->bk
na(mchunkptr)(TARGET - 0x10)
pre pozivafree(victim)
, poslednja naredba će izvršiti upis:*(TARGET) = victim
. - Kasnije, kada allocator procesuira unsorted bin, integritet provere će potvrditi (između ostalog) da je
bck->fd == victim
ivictim->fd == unsorted_chunks(av)
pre unlink-ovanja. Pošto je umetanje već upisalovictim
ubck->fd
(našTARGET
), ove provere mogu biti zadovoljene ako je upis uspeo.
Moderni zahtevi (glibc ≥ 2.33)
Da biste pouzdano koristili unsorted‑bin writes na savremenom glibc:
- Tcache interferencija: za veličine koje spadaju u tcache, free-ovi su preusmereni tamo i neće dotaknuti unsorted bin. Ili
- pravite zahteve sa veličinama > MAX_TCACHE_SIZE (≥ 0x410 na 64‑bit po defaultu), ili
- napunite odgovarajući tcache bin (7 unosa) tako da dodatni free-ovi dosegnu global bins, ili
- ako je okruženje podesivo, onemogućite tcache (npr. GLIBC_TUNABLES glibc.malloc.tcache_count=0).
- Integritet provere na unsorted listi: na sledećem putu alokacije koji pregleda unsorted bin, glibc proverava (pojednostavljeno):
bck->fd == victim
ivictim->fd == unsorted_chunks(av)
; u suprotnom abortuje samalloc(): unsorted double linked list corrupted
.
- To znači da adresa koju ciljate mora podneti dva upisa: prvo
*(TARGET) = victim
pri free‑vremenu; kasnije, dok se chunk uklanja,*(TARGET) = unsorted_chunks(av)
(allocator ponovo upisujebck->fd
nazad na bin head). Birajte ciljeve gde samo forsiranje velike nenulte vrednosti ima smisla. - Tipični stabilni ciljevi u modernim exploit-ima
- Stanje aplikacije ili globalno stanje koje tretira "velike" vrednosti kao flags/limits.
- Indirektne primitive (npr., priprema za naredni [fast bin attack](Fast Bin Attack) ili za pivot kasnijeg write‑what‑where).
- Izbegavajte
__malloc_hook
/__free_hook
na novom glibc: uklonjeni su u 2.34. Izbegavajteglobal_max_fast
na ≥ 2.39 (vidi sledeću napomenu). - O
global_max_fast
na novijim glibc verzijama- Na glibc 2.39+,
global_max_fast
je 8‑bitni global. Klasičan trik upisivanja heap pokazivača u njega (da bi se uvećali fastbin-ovi) više ne radi čisto i verovatno će korumpirati susedno stanje allocator‑a. Preferirajte druge strategije.
- Na glibc 2.39+,
Minimalni recept za exploit (moderni glibc)
Cilj: ostvariti jedan arbitrarni upis heap pointer-a na proizvoljnu adresu koristeći unsorted‑bin insertion primitive, bez rušenja.
- Layout/grooming
- Alocirajte A, B, C veličina dovoljno velikih da zaobiđu tcache (npr. 0x5000). C sprečava konsolidaciju sa top chunk-om.
- Corruption
- Overflow iz A u B‑ev chunk header da se postavi
B->bk = (mchunkptr)(TARGET - 0x10)
.
- Overflow iz A u B‑ev chunk header da se postavi
- Trigger
free(B)
. U trenutku umetanja allocator izvršavabck->fd = B
, dakle*(TARGET) = B
.
- Continuation
- Ako planirate da nastavite sa alokacijama i program koristi unsorted bin, očekujte da će allocator kasnije postaviti
*(TARGET) = unsorted_chunks(av)
. Obe vrednosti su tipično velike i mogu biti dovoljne da promene semantiku veličine/limita za ciljeve koji samo proveravaju "veliko".
- Ako planirate da nastavite sa alokacijama i program koristi unsorted bin, očekujte da će allocator kasnije postaviti
Skelet pseudokoda:
// 64-bit glibc 2.35–2.38 style layout (tcache bypass via large sizes)
void *A = malloc(0x5000);
void *B = malloc(0x5000);
void *C = malloc(0x5000); // guard
// overflow from A into B’s metadata (prev_size/size/.../bk). You must control B->bk.
*(size_t *)((char*)B - 0x8) = (size_t)(TARGET - 0x10); // write fake bk
free(B); // triggers *(TARGET) = B (unsorted-bin insertion write)
note
• Ako ne možete zaobići tcache preko veličine, napunite tcache bin za izabranu veličinu (7 frees) pre nego što oslobodite korumpirani chunk, tako da free ode u unsorted.
• Ako program odmah abortira pri sledećoj alokaciji zbog unsorted-bin checks, ponovo proverite da li victim->fd
i dalje jednak bin head-u i da li vaš TARGET
drži tačan victim
pokazivač nakon prvog upisa.
Unsorted Bin Infoleak Attack
Ovo je zapravo vrlo osnovan koncept. Chunk-ovi u unsorted bin-u će imati pokazivače. Prvi chunk u unsorted bin-u će zapravo imati fd
i bk
linkove koji pokazuju na deo main arena (Glibc).
Dakle, ako možete staviti chunk u unsorted bin i pročitati ga (use after free) ili ponovo ga alocirati bez prepisivanja bar jednog od pokazivača i onda ga pročitati, možete dobiti Glibc info leak.
Sličan attack used in this writeup je iskorišćavao strukturu od 4 chunka (A, B, C i D - D je samo da spreči konsolidaciju sa top chunk-om) tako da je null byte overflow u B iskorišćen da natera C da indikuje da je B neiskorišćen. Takođe, u B je polje prev_size
izmenjeno tako da veličina, umesto da bude veličina B, postane A+B.
Zatim je C deallocated i konsolidovan sa A+B (dok je B i dalje bio u upotrebi). Novi chunk veličine A je alociran i onda su libc leaked addresses upisane u B odakle je izvršen leak.
Reference i drugi primeri
- https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/unsorted_bin_attack/#hitcon-training-lab14-magic-heap
- Cilj je prepisati globalnu promenljivu sa vrednošću većom od 4869 kako bi bilo moguće dobiti flag i PIE nije omogućen.
- Moguće je generisati chunk-ove proizvoljne veličine i postoji heap overflow odgovarajuće veličine.
- Napad počinje kreiranjem 3 chunka: chunk0 da se iskoristi overflow, chunk1 koji će biti overflow-ovan i chunk2 da top chunk ne konsoliduje prethodne.
- Zatim se chunk1 oslobodi i chunk0 se overflow-uje tako da
bk
pokazivač chunk1 pokazuje na:bk = magic - 0x10
- Zatim se alocira chunk3 iste veličine kao chunk1, što će pokrenuti unsorted bin attack i izmeniti vrednost globalne promenljive, čime postaje moguće dobiti flag.
- https://guyinatuxedo.github.io/31-unsortedbin_attack/0ctf16_zerostorage/index.html
- Merge funkcija je ranjiva zato što, ako su oba prosleđena indeksa ista, izvrši realloc na tom regionu i potom ga free-uje, ali vrati pokazivač na to oslobođeno područje koji se može iskoristiti.
- Dakle, kreiraju se 2 chunka: chunk0 koji će biti merged sa samim sobom i chunk1 da spreči konsolidaciju sa top chunk-om. Zatim se merge funkcija poziva sa chunk0 dva puta što će prouzrokovati use after free.
- Zatim se poziva
view
funkcija sa indeksom 2 (koji je indeks use after free chunka), što će leak a libc address. - Pošto binarni ima zaštite koje dozvoljavaju malloc samo za veličine veće od
global_max_fast
pa se ne koriste fastbin-ovi, koristiće se unsorted bin attack da se prepiše globalna promenljivaglobal_max_fast
. - Zatim je moguće pozvati edit funkciju sa indeksom 2 (use after free pokazivač) i prepisati
bk
pokazivač da pokazuje nap64(global_max_fast-0x10)
. Kreiranje novog chunka će koristiti prethodno kompromitovanu free adresu (0x20) i to će pokrenuti unsorted bin attack koji prepisujeglobal_max_fast
velikom vrednošću, omogućavajući sada kreiranje chunk-ova u fast bin-ovima. - Sada se izvodi fast bin attack:
- Pre svega, otkriveno je da je moguće raditi sa fast chunk-ovima veličine 0x200 na lokaciji
__free_hook
: gef➤ p &__free_hook
$1 = (void (**)(void *, const void *)) 0x7ff1e9e607a8 <__free_hook> gef➤ x/60gx 0x7ff1e9e607a8 - 0x59 0x7ff1e9e6074f: 0x0000000000000000 0x0000000000000200 0x7ff1e9e6075f: 0x0000000000000000 0x0000000000000000 0x7ff1e9e6076f <list_all_lock+15>: 0x0000000000000000 0x0000000000000000 0x7ff1e9e6077f <_IO_stdfile_2_lock+15>: 0x0000000000000000 0x0000000000000000
- Ako uspemo da dobijemo fast chunk veličine 0x200 na toj lokaciji, biće moguće prepisati funkcioni pokazivač koji će biti izvršen.
- Za ovo se kreira novi chunk veličine
0xfc
i merge funkcija se poziva sa tim pokazivačem dva puta; na taj način dobijamo pokazivač na oslobođeni chunk veličine0xfc*2 = 0x1f8
u fast bin-u. - Zatim se na tom chunku poziva edit funkcija da izmeni adresu
fd
ovog fast bina tako da pokazuje na prethodnu lokaciju__free_hook
. - Zatim se kreira chunk veličine
0x1f8
da se iz fast bin-a izuzme prethodni beskorisni chunk, pa se još jedan chunk veličine0x1f8
kreira da bi se dobio fast bin chunk u__free_hook
, koji se prepisuje adresom funkcijesystem
. - I na kraju, chunk koji sadrži string
/bin/sh\x00
se free-uje pozivom delete funkcije, što pokreće__free_hook
funkciju koja sada pokazuje na system sa/bin/sh\x00
kao argumentom. - CTF https://guyinatuxedo.github.io/33-custom_misc_heap/csaw19_traveller/index.html
- Još jedan primer zloupotrebe 1B overflow-a da se konsoliduju chunk-ovi u unsorted bin i dobiju libc infoleak, a zatim izvede fast bin attack da se overwrite-uje malloc hook jednim gadgetom.
- Robot Factory. BlackHat MEA CTF 2022
- Mogu se alocirati samo chunk-ovi veličine veće od
0x100
. - Prepisivanje
global_max_fast
koristeći Unsorted Bin attack (radi 1/16 puta zbog ASLR-a, zato što treba modifikovati 12 bitova, ali moramo modifikovati 16 bitova). - Fast Bin attack da se izmeni globalni niz chunk-ova. Ovo daje arbitrarni read/write primitiv, koji omogućava izmenu GOT-a i postavljanje neke funkcije da pokazuje na
system
.
Reference
- Glibc malloc unsorted-bin integrity checks (primer u 2.33 source): https://elixir.bootlin.com/glibc/glibc-2.33/source/malloc/malloc.c
global_max_fast
i srodne definicije u modernom glibc (2.39): https://elixir.bootlin.com/glibc/glibc-2.39/source/malloc/malloc.c
tip
Učite i vežbajte AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Učite i vežbajte GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Učite i vežbajte Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Podržite HackTricks
- Proverite planove pretplate!
- Pridružite se 💬 Discord grupi ili telegram grupi ili pratite nas na Twitteru 🐦 @hacktricks_live.
- Podelite hakerske trikove slanjem PR-ova na HackTricks i HackTricks Cloud github repozitorijume.