House of Roman

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

Grundlegende Informationen

Dies war eine sehr interessante Technik, die RCE ohne leaks über gefälschte fastbins, den unsorted_bin-Angriff und relative overwrites erlaubte. Allerdings wurde dies behoben.

Anwendbarkeit im Jahr 2026

  • glibc-Fenster: Arbeitet zuverlässig auf 2.23–2.27 (der how2heap PoC testete 2.23–2.25). Ab 2.28 macht der Patch “additional checks for unsorted bin integrity” den unsorted‑bin write unzuverlässig, sodass die Erfolgsrate stark abfällt. Ab 2.34 wurden __malloc_hook/__free_hook entfernt, was das ursprüngliche Ziel unzugänglich macht. Nutze es nur auf alten libc-Versionen (oder benutzerdefinierten Builds, die die hooks behalten) oder für CTF-Challenges, die eine alte libc mitliefern.
  • Tcache-Ära (≥2.26): Tcache frisst deine 0x70-Allocations und unterbindet die fastbin/unsorted-Primitives. Deaktiviere ihn (setenv("GLIBC_TUNABLES","glibc.malloc.tcache_count=0",1);) vor jeder Allocation oder fülle jedes 0x70-tcache-Bin mit 7 frees, um es zu leeren.
  • Safe-linking: Gilt für tcache/fastbin in ≥2.32, aber House of Roman benötigt nur eine partielle Pointer-Überschreibung einer libc-Adresse, die bereits in fd/bk vorhanden ist, sodass safe-linking dem Verteidiger hier nicht hilft (der Angreifer fälscht nie einen frischen Pointer). Der eigentliche Stopper ist die Hook-Entfernung und die unsorted-bin-Checks.

Code

Ziel

  • RCE durch Ausnutzung relativer Pointer

Anforderungen

  • Fastbin- und unsorted_bin-Pointer bearbeiten
  • 12 Bits Zufall müssen per Brute-Force erraten werden (0,02% Wahrscheinlichkeit für Erfolg)

Angriffsschritte

Teil 1: Fastbin-Chunk zeigt auf __malloc_hook

Erzeuge mehrere Chunks:

  • fastbin_victim (0x60, offset 0): UAF-Chunk, um später den Heap-Pointer zu bearbeiten und auf den libc-Wert zeigen zu lassen.
  • chunk2 (0x80, offset 0x70): Zur besseren Ausrichtung
  • main_arena_use (0x80, offset 0x100)
  • relative_offset_heap (0x60, offset 0x190): relativer Offset auf dem ‘main_arena_use’-Chunk

Dann free(main_arena_use), wodurch dieser Chunk in die unsorted-Liste gelegt wird und sowohl fd als auch bk einen Pointer auf main_arena + 0x68 erhalten.

Nun wird ein neuer Chunk fake_libc_chunk(0x60) alloziert, da er die Pointer auf main_arena + 0x68 in fd und bk enthalten wird.

Dann werden relative_offset_heap und fastbin_victim freigegeben.

/*
Current heap layout:
0x0:   fastbin_victim       - size 0x70
0x70:  alignment_filler     - size 0x90
0x100: fake_libc_chunk      - size 0x70 (contains a fd ptr to main_arena + 0x68)
0x170: leftover_main        - size 0x20
0x190: relative_offset_heap - size 0x70

bin layout:
fastbin:  fastbin_victim -> relative_offset_heap
unsorted: leftover_main
*/
  • fastbin_victim hat ein fd, das auf relative_offset_heap zeigt
  • relative_offset_heap ist ein Offset des Abstands von fake_libc_chunk, das einen Pointer auf main_arena + 0x68 enthält
  • Durch Ändern des letzten Bytes von fastbin_victim.fd zeigt fastbin_victim auf main_arena + 0x68.

Für die vorherigen Aktionen muss der Angreifer in der Lage sein, den fd-Pointer von fastbin_victim zu verändern.

Dann ist main_arena + 0x68 nicht besonders interessant, also modifizieren wir es so, dass der Pointer auf __malloc_hook zeigt.

Beachte, dass __memalign_hook normalerweise mit 0x7f beginnt und davor Nullen stehen, daher lässt es sich als Wert im 0x70 fast bin faken. Da die letzten 4 Bits der Adresse random sind, gibt es 2^4=16 Möglichkeiten, dass der Wert schließlich auf die gewünschte Stelle zeigt. So wird hier ein BF attack durchgeführt, sodass der chunk endet wie: 0x70: fastbin_victim -> fake_libc_chunk -> (__malloc_hook - 0x23).

(For more info about the rest of the bytes check the explanation in the how2heap example). If the brute force fails the program just crashes (restart until it works).

Dann werden 2 mallocs durchgeführt, um die 2 initialen fast bin chunks zu entfernen, und ein dritter wird alloziert, um einen chunk in __malloc_hook zu bekommen.

malloc(0x60);
malloc(0x60);
uint8_t* malloc_hook_chunk = malloc(0x60);

Teil 2: Unsorted_bin attack

Für mehr Informationen siehe:

Unsorted Bin Attack

Kurz gesagt erlaubt es, main_arena + 0x68 an jede durch chunk->bk angegebene Adresse zu schreiben. Für den Angriff wählen wir __malloc_hook. Anschließend, nachdem wir es überschrieben haben, verwenden wir einen relativen overwrite, um auf ein one_gadget zu zeigen.

Dazu holen wir zunächst einen Chunk und legen ihn in den unsorted bin:

uint8_t* unsorted_bin_ptr = malloc(0x80);
malloc(0x30); // Don't want to consolidate

puts("Put chunk into unsorted_bin\n");
// Free the chunk to create the UAF
free(unsorted_bin_ptr);

Use an UAF in this chunk to point unsorted_bin_ptr->bk to the address of __malloc_hook (we brute forced this previously).

Caution

Note that this attack corrupts the unsorted bin (hence small and large too). So we can only use allocations from the fast bin now (a more complex program might do other allocations and crash), and to trigger this we must alloc the same size or the program will crash.

So, to trigger the write of main_arena + 0x68 in __malloc_hook we perform after setting __malloc_hook in unsorted_bin_ptr->bk we just need to do: malloc(0x80)

Schritt 3: Set __malloc_hook to system

In step one we controlled a chunk containing __malloc_hook (in the variable malloc_hook_chunk) and in the second step we managed to write main_arena + 0x68 there.

Now, we abuse a partial overwrite in malloc_hook_chunk to use the libc address we wrote there (main_arena + 0x68) to point to a one_gadget address.

Here is where it’s needed to bruteforce 12 bits of randomness (more info in the how2heap example).

Finally, once the correct address is overwritten, call malloc and trigger the one_gadget.

Moderne Tipps & Varianten

  • Unsorted-bin hardening (2.28+): Die zusätzlichen Integritätsprüfungen an unsorted chunks (Größenprüfung + Listenzusammenhang) machen den klassischen unsorted‑bin‑Write fragil. Um _int_malloc zu überstehen, musst du die fd/bk-Links konsistent und die Größen plausibel halten, was in der Regel stärkere Primitives als einen einfachen partiellen Overwrite erfordert.
  • Hook removal (2.34+): Da __malloc_hook entfernt wurde, passe das Primitive so an, dass es auf ein beliebiges beschreibbares GOT/global landet, das du später wiederverwenden kannst (z. B. überschreibe exit@GOT in non-PIE Binaries) oder pivot zu einem House of Pie-ähnlichen top‑chunk‑Hijack, um top statt eines Hooks zu kontrollieren.
  • Any‑address fastbin alloc (romanking98 writeup): Der zweite Teil zeigt die Reparatur der 0x71‑Freeliste und die Nutzung des unsorted‑bin‑Writes, um eine fastbin‑Allocation über __free_hook zu landen, dann system("/bin/sh") zu platzieren und dies via free() unter libc‑2.24 (vor der Hook‑Entfernung) auszulösen.

Referenzen

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