Unsorted Bin Attack
Tip
Lernen & ĂŒben Sie AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Lernen & ĂŒben Sie GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Lernen & ĂŒben Sie Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
UnterstĂŒtzen Sie HackTricks
- ĂberprĂŒfen Sie die AbonnementplĂ€ne!
- Treten Sie der đŹ Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter đŠ @hacktricks_live.
- Teilen Sie Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repos senden.
Grundlegende Informationen
FĂŒr mehr Informationen darĂŒber, was ein unsorted bin ist, siehe diese Seite:
Unsorted lists sind in der Lage, die Adresse von unsorted_chunks (av) in das bk-Feld des Chunks zu schreiben. Daher, wenn ein Angreifer die Adresse des bk-Pointers in einem Chunk innerhalb des unsorted bin Àndern kann, könnte er diese Adresse an eine beliebige Adresse schreiben, was hilfreich sein kann, um Glibc-Adressen zu leaken oder einige Schutzmechanismen zu umgehen.
Kurz gesagt erlaubt dieser Angriff, eine groĂe Zahl an einer beliebigen Adresse zu setzen. Diese groĂe Zahl ist eine Adresse, die eine Heap-Adresse oder eine Glibc-Adresse sein kann. Ein traditionelles Ziel war global_max_fast, um fast bin bins mit gröĂeren GröĂen zu erlauben (und vom unsorted bin attack zu einem fast bin attack ĂŒberzugehen).
- Moderne Anmerkung (glibc â„ 2.39):
global_max_fastwurde zu einer 8âBit-Globalvariablen. Das blinde Schreiben eines Pointers dorthin via unsortedâbin write ĂŒberschreibt angrenzende libc-Daten und erhöht das fastbin-Limit nicht mehr zuverlĂ€ssig. Bevorzuge andere Ziele oder andere Primitive gegen glibc 2.39+. Siehe âModerne EinschrĂ€nkungenâ weiter unten und erwĂ€ge die Kombination mit anderen Techniken wie einem large bin attack oder einem fast bin attack, sobald du ein stabiles Primitive hast.
Tip
Ein Blick auf das Beispiel in https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/unsorted_bin_attack/#principle und die Verwendung von 0x4000 und 0x5000 statt 0x400 und 0x500 als Chunk-GröĂen (um Tcache zu vermeiden) zeigt, dass heutzutage der Fehler
malloc(): unsorted double linked list corruptedausgelöst wird.Daher erfordert dieser unsorted bin attack jetzt (neben anderen Checks) auch, die doppelt verkettete Liste so zu reparieren, dass die ĂberprĂŒfungen
victim->bk->fd == victimundvictim->fd == av (arena)erfĂŒllt sind, was bedeutet, dass die Adresse, an die wir schreiben wollen, in ihrerfd-Position die Adresse des gefĂ€lschten Chunks haben muss und dass dasfddes gefĂ€lschten Chunks auf die arena zeigt.
Caution
Beachte, dass dieser Angriff das unsorted bin korruptiert (und damit auch small und large). Daher können wir jetzt nur noch Allocations aus den fast bin verwenden (ein komplexeres Programm könnte andere Allocations durchfĂŒhren und abstĂŒrzen), und um dies auszulösen, mĂŒssen wir die gleiche GröĂe allozieren, sonst stĂŒrzt das Programm ab.
Beachte, dass das Ăberschreiben von
global_max_fastin diesem Fall helfen kann, sofern das fast bin alle anderen Allocations bis zum Abschluss des Exploits ĂŒbernehmen kann.
Der Code von guyinatuxedo erklÀrt das sehr gut; wenn man jedoch die mallocs so Àndert, dass sie Speicher groà genug allozieren, um nicht in einen Tcache zu fallen, sieht man, dass der zuvor erwÀhnte Fehler auftritt und diese Technik verhindert: malloc(): unsorted double linked list corrupted
Wie der Schreibvorgang tatsÀchlich ablÀuft
- Der unsortedâbin write wird bei
freeausgelöst, wenn der freigegebene Chunk am Kopf der unsorted list eingefĂŒgt wird. - WĂ€hrend der EinfĂŒgung fĂŒhrt der Allocator aus: bck = unsorted_chunks(av); fwd = bck->fd; victim->bk = bck; victim->fd = fwd; fwd->bk = victim; bck->fd = victim;
- Wenn du
victim->bkauf(mchunkptr)(TARGET - 0x10)setzen kannst bevor dufree(victim)aufrufst, wird die letzte Anweisung die Schreiboperation ausfĂŒhren:*(TARGET) = victim. - SpĂ€ter, wenn der Allocator das unsorted bin verarbeitet, werden IntegritĂ€tsprĂŒfungen (unter anderem) verifizieren, dass
bck->fd == victimundvictim->fd == unsorted_chunks(av)bevor unlinking erfolgt. Da die EinfĂŒgung bereitsvictiminbck->fd(unserTARGET) geschrieben hat, können diese Checks erfĂŒllt sein, wenn der Write erfolgreich war.
Moderne EinschrÀnkungen (glibc ℠2.33)
Um unsortedâbin Writes auf aktuellen glibc zuverlĂ€ssig zu verwenden:
- Tcache-Interferenz: FĂŒr GröĂen, die in den tcache fallen, werden frees dorthin umgeleitet und berĂŒhren nicht das unsorted bin. Entweder
- mache Anfragen mit GröĂen > MAX_TCACHE_SIZE (â„ 0x410 auf 64âBit standardmĂ€Ăig), oder
- fĂŒlle die entsprechende tcache-Bin (7 EintrĂ€ge), sodass zusĂ€tzliche frees die global bins erreichen, oder
- wenn die Umgebung kontrollierbar ist, deaktiviere tcache (z. B. GLIBC_TUNABLES glibc.malloc.tcache_count=0).
- IntegritĂ€tsprĂŒfungen auf der unsorted list: auf dem nĂ€chsten Allocations-Pfad, der das unsorted bin prĂŒft, kontrolliert glibc (vereinfacht):
bck->fd == victimundvictim->fd == unsorted_chunks(av); andernfalls bricht es mitmalloc(): unsorted double linked list corruptedab.- Das bedeutet, dass die Adresse, die du targetest, zwei Writes tolerieren muss: zuerst
*(TARGET) = victimzur FreeâZeit; spĂ€ter, wenn der Chunk entfernt wird,*(TARGET) = unsorted_chunks(av)(der Allocator schreibtbck->fdzurĂŒck auf den BinâKopf). WĂ€hle Ziele, bei denen das Erzwingen eines groĂen NichtâNullâWertes nĂŒtzlich ist. - Typische stabile Ziele in modernen Exploits:
- Applikations- oder globaler Zustand, der âgroĂeâ Werte als Flags/Limits behandelt.
- Indirekte Primitive (z. B. Vorbereitung fĂŒr einen nachfolgenden [fast bin attack](Fast Bin Attack) oder um einen spĂ€teren writeâwhatâwhere zu pivotieren).
- Vermeide
__malloc_hook/__free_hookin neuem glibc: sie wurden in 2.34 entfernt. Vermeideglobal_max_fastauf â„ 2.39 (siehe vorherige Anmerkung). - Zu
global_max_fastauf neueren glibc: - Auf glibc 2.39+ ist
global_max_fastein 8âBitâGlobal. Der klassische Trick, einen HeapâPointer dorthin zu schreiben (um fastbins zu vergröĂern), funktioniert nicht mehr sauber und wird wahrscheinlich angrenzenden AllocatorâZustand korruptieren. Bevorzuge andere Strategien.
Minimales ExploitâRezept (moderner glibc)
Ziel: einen einzelnen arbitrĂ€ren Write eines HeapâPointers an eine beliebige Adresse mittels des unsortedâbin InsertionsâPrimitives erreichen, ohne das Programm abstĂŒrzen zu lassen.
- Layout/Grooming
- Alloziere A, B, C mit GröĂen, die groĂ genug sind, um tcache zu umgehen (z. B. 0x5000). C verhindert Konsolidierung mit dem top chunk.
- Korruption
- Overflow von A in Bs ChunkâHeader, um
B->bk = (mchunkptr)(TARGET - 0x10)zu setzen. - Auslösen
free(B). Zur EinfĂŒgezeit fĂŒhrt der Allocatorbck->fd = Baus; daher wird*(TARGET) = B.- Fortsetzung
- Wenn du weiter alloziieren willst und das Programm das unsorted bin verwendet, erwarte, dass der Allocator spÀter
*(TARGET) = unsorted_chunks(av)setzt. Beide Werte sind typischerweise groĂ und können ausreichen, um GröĂen-/LimitâSemantiken in Zielen zu Ă€ndern, die nur auf âgroĂâ prĂŒfen.
PseudocodeâSkelett:
// 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
âą Wenn du tcache nicht ĂŒber die GröĂe umgehen kannst, fĂŒlle das tcache-Bin fĂŒr die gewĂ€hlte GröĂe (7 frees), bevor du den korrupten Chunk freigibst, damit das free in das unsorted geht. âą Wenn das Programm beim nĂ€chsten Allocation sofort aufgrund der unsorted-binâChecks abbricht, ĂŒberprĂŒfe nochmal, dass
victim->fdnoch dem Bin-Head entspricht und dass deinTARGETnach dem ersten Schreibvorgang genau denvictim-Pointer enthÀlt.
Unsorted Bin Infoleak Attack
This is actually a very basic concept. The chunks in the unsorted bin are going to have pointers. The first chunk in the unsorted bin will actually have the fd and the bk links pointing to a part of the main arena (Glibc).
Therefore, if you can put a chunk inside a unsorted bin and read it (use after free) or allocate it again without overwriting at least 1 of the pointers to then read it, you can have a Glibc info leak.
A similar attack used in this writeup, was to abuse a 4 chunks structure (A, B, C and D - D is only to prevent consolidation with top chunk) so a null byte overflow in B was used to make C indicate that B was unused. Also, in B the prev_size data was modified so the size instead of being the size of B was A+B.
Then C was deallocated, and consolidated with A+B (but B was still in used). A new chunk of size A was allocated and then the libc leaked addresses was written into B from where they were leaked.
Referenzen & Weitere Beispiele
- https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/unsorted_bin_attack/#hitcon-training-lab14-magic-heap
- Das Ziel ist, eine globale Variable mit einem Wert gröĂer als 4869 zu ĂŒberschreiben, damit es möglich ist, die Flag zu bekommen, und PIE ist nicht aktiviert.
- Es ist möglich, Chunks beliebiger GröĂen zu erzeugen und es gibt einen Heap-Overflow mit der gewĂŒnschten GröĂe.
- Der Angriff beginnt mit dem Erstellen von 3 Chunks: chunk0 zum Ausnutzen des Overflows, chunk1, das ĂŒberlaufen wird, und chunk2, damit der top chunk nicht die vorherigen konsolidiert.
- Danach wird chunk1 freed und chunk0 so ĂŒberlaufen, dass das
bk-Pointer von chunk1 zeigt auf:bk = magic - 0x10 - Dann wird chunk3 mit derselben GröĂe wie chunk1 alloziiert, was den unsorted bin attack auslöst und den Wert der globalen Variable verĂ€ndert, wodurch es möglich wird, die Flag zu bekommen.
- https://guyinatuxedo.github.io/31-unsortedbin_attack/0ctf16_zerostorage/index.html
- Die merge-Funktion ist verwundbar, weil, wenn beide ĂŒbergebenen Indizes gleich sind, sie ein realloc darauf macht und es dann freed, aber dabei einen Pointer auf diesen freed Bereich zurĂŒckgibt, der weiterverwendet werden kann.
- Daher werden 2 Chunks erstellt: chunk0, das mit sich selbst gemerged wird, und chunk1, um eine Konsolidierung mit dem top chunk zu verhindern. Dann wird die merge-Funktion mit chunk0 zweimal aufgerufen, was zu einem use after free fĂŒhrt.
- Danach wird die
view-Funktion mit Index 2 aufgerufen (das ist der Index des use after free Chunks), welche eine libc Adresse leaked. - Da das Binary Protections hat, nur mallocs gröĂer als
global_max_fastzu erlauben, sodass kein fastbin verwendet wird, wird ein unsorted bin attack benutzt, um die globale Variableglobal_max_fastzu ĂŒberschreiben. - Danach ist es möglich, die edit-Funktion mit Index 2 (dem use after free Pointer) aufzurufen und den
bk-Pointer zu ĂŒberschreiben, sodass er aufp64(global_max_fast-0x10)zeigt. Dann erzeugt man einen neuen Chunk, der die zuvor kompromittierte free-Adresse (0x20) verwendet und so den unsorted bin attack auslöst, derglobal_max_fastmit einem sehr groĂen Wert ĂŒberschreibt, wodurch es nun möglich ist, Chunks in fast bins zu erstellen. - Jetzt wird ein fast bin attack durchgefĂŒhrt:
- Zuerst wird entdeckt, dass es möglich ist, mit fast Chunks der GröĂe 200 an der Stelle von
__free_hookzu arbeiten: -
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
- Wenn es gelingt, einen fast Chunk der GröĂe 0x200 an dieser Stelle zu bekommen, wird es möglich sein, einen Funktionspointer zu ĂŒberschreiben, der ausgefĂŒhrt wird.
- DafĂŒr wird ein neuer Chunk der GröĂe
0xfcerstellt und die merge-Funktion mit diesem Pointer zweimal aufgerufen; so erhĂ€lt man einen Pointer auf einen freed Chunk der GröĂe0xfc*2 = 0x1f8im fast bin. - Dann wird die edit-Funktion auf diesem Chunk aufgerufen, um die
fd-Adresse dieses fast bins zu Ă€ndern, sodass sie auf das vorherige__free_hookzeigt. - Danach wird ein Chunk mit GröĂe
0x1f8alloziiert, um aus dem fast bin den vorherigen nutzlosen Chunk zu bekommen; ein weiterer Chunk der GröĂe0x1f8wird erstellt, um einen fast bin Chunk in__free_hookzu erhalten, der mit der Adresse dersystem-Funktion ĂŒberschrieben wird. - Und schlieĂlich wird ein Chunk, das den String
/bin/sh\x00enthĂ€lt, per delete freed, wodurch die__free_hook-Funktion aufgerufen wird, die nun auf system zeigt und/bin/sh\x00als Parameter ĂŒbergeben bekommt. - CTF https://guyinatuxedo.github.io/33-custom_misc_heap/csaw19_traveller/index.html
- Ein weiteres Beispiel, wie ein 1B-Overflow genutzt wird, um Chunks im unsorted bin zu konsolidieren und einen libc info leak zu bekommen und anschlieĂend einen fast bin attack durchzufĂŒhren, um malloc hook mit einem one gadget zu ĂŒberschreiben.
- Robot Factory. BlackHat MEA CTF 2022
- Wir können nur Chunks der GröĂe gröĂer als
0x100alloziieren. - Ăberschreibe
global_max_fastmittels eines Unsorted Bin attack (funktioniert 1/16 mal wegen ASLR, weil wir 12 Bits Ă€ndern mĂŒssen, aber 16 Bits Ă€ndern). - Fast Bin attack, um ein globales Array von Chunks zu modifizieren. Das gibt ein beliebiges read/write-Primitive, was erlaubt, die GOT zu Ă€ndern und eine Funktion auf
systemzu setzen.
References
- Glibc malloc unsorted-bin integrity checks (example in 2.33 source): https://elixir.bootlin.com/glibc/glibc-2.33/source/malloc/malloc.c
global_max_fastand related definitions in modern glibc (2.39): https://elixir.bootlin.com/glibc/glibc-2.39/source/malloc/malloc.c
Tip
Lernen & ĂŒben Sie AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Lernen & ĂŒben Sie GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Lernen & ĂŒben Sie Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
UnterstĂŒtzen Sie HackTricks
- ĂberprĂŒfen Sie die AbonnementplĂ€ne!
- Treten Sie der đŹ Discord-Gruppe oder der Telegram-Gruppe bei oder folgen Sie uns auf Twitter đŠ @hacktricks_live.
- Teilen Sie Hacking-Tricks, indem Sie PRs an die HackTricks und HackTricks Cloud GitHub-Repos senden.


