House of Roman
Tip
Learn & practice AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Learn & practice GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Learn & practice Az Hacking:HackTricks Training Azure Red Team Expert (AzRTE)
Support HackTricks
- Check the subscription plans!
- Join the 💬 Discord group or the telegram group or follow us on Twitter 🐦 @hacktricks_live.
- Share hacking tricks by submitting PRs to the HackTricks and HackTricks Cloud github repos.
Basic Information
This was a very interesting technique that allowed for RCE without leaks via fake fastbins, the unsorted_bin attack and relative overwrites. However it has been patched.
Applicability in 2026
- glibc window: Works reliably on 2.23–2.27 (the how2heap PoC tested 2.23–2.25). Starting 2.28, the “additional checks for unsorted bin integrity” patch makes the unsorted‑bin write unreliable, so success drops sharply. From 2.34 onward
__malloc_hook/__free_hookwere removed, making the original target unavailable. Use it only on old libc’s (or custom builds that keep the hooks) or for CTF challenges that ship an old libc. - Tcache era (≥2.26): Tcache will eat your 0x70 allocations and stop the fastbin/unsorted primitives. Disable it (
setenv("GLIBC_TUNABLES","glibc.malloc.tcache_count=0",1);) before any allocation or fill each 0x70 tcache bin with 7 frees to drain it. - Safe-linking: It applies to tcache/fastbin in ≥2.32, but House of Roman only needs partial pointer overwrite of a libc address already present in fd/bk, so safe-linking does not help the defender here (the attacker never forges a fresh pointer). The real stopper is the hook removal and the unsorted-bin checks.
Code
- You can find an example in https://github.com/shellphish/how2heap/blob/master/glibc_2.23/house_of_roman.c
Goal
- RCE by abusing relative pointers
Requirements
- Edit fastbin and unsorted bin pointers
- 12 bits of randomness must be brute forced (0.02% chance) of working
Attack Steps
Part 1: Fastbin Chunk points to __malloc_hook
Create several chunks:
fastbin_victim(0x60, offset 0): UAF chunk later to edit the heap pointer later to point to the LibC value.chunk2(0x80, offset 0x70): For good alignmentmain_arena_use(0x80, offset 0x100)relative_offset_heap(0x60, offset 0x190): relative offset on the ‘main_arena_use’ chunk
Then free(main_arena_use) which will place this chunk in the unsorted list and will get a pointer to main_arena + 0x68 in both the fd and bk pointers.
Now it’s allocated a new chunk fake_libc_chunk(0x60) because it’ll contain the pointers to main_arena + 0x68 in fd and bk.
Then relative_offset_heap and fastbin_victim are freed.
/*
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_victimhas afdpointing torelative_offset_heaprelative_offset_heapis an offset of distance fromfake_libc_chunk, which contains a pointer tomain_arena + 0x68- Changing the last byte of
fastbin_victim.fdmakesfastbin_victimpoint tomain_arena + 0x68.
For the previous actions, the attacker needs to be capable of modifying the fd pointer of fastbin_victim.
Then, main_arena + 0x68 is not that interesting, so let’s modify it so the pointer points to __malloc_hook.
Note that __memalign_hook usually starts with 0x7f and zeros before it, then it’s possible to fake it as a value in the 0x70 fast bin. Because the last 4 bits of the address are random there are 2^4=16 possibilities for the value to end pointing where we are interested. So a BF attack is performed here so the chunk ends like: 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).
Then, 2 mallocs are performed to remove the 2 initial fast bin chunks and a third one is allocated to get a chunk in __malloc_hook.
malloc(0x60);
malloc(0x60);
uint8_t* malloc_hook_chunk = malloc(0x60);
Part 2: Unsorted_bin attack
For more info you can check:
But basically it allows to write main_arena + 0x68 to any location specified in chunk->bk. For the attack we choose __malloc_hook. Then, after overwriting it we will use a relative overwrite to point to a one_gadget.
For this we start getting a chunk and putting it into the 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)
Step 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.
Modern tips & variants
- Unsorted-bin hardening (2.28+): The extra integrity checks on unsorted chunks (size sanity + list linkage) make the classic unsorted‑bin write fragile. To survive
_int_malloc, you must keepfd/bklinks consistent and sizes plausible, which usually requires stronger primitives than a simple partial overwrite. - Hook removal (2.34+): With
__malloc_hookgone, adapt the primitive to land on any writable GOT/global you can later reuse (e.g., overwriteexit@GOTin non-PIE binaries) or pivot to a House of Pie style top‑chunk hijack to controltopinstead of a hook. - Any‑address fastbin alloc (romanking98 writeup): The second part shows repairing the 0x71 freelist and using the unsorted‑bin write to land a fastbin allocation over
__free_hook, then placingsystem("/bin/sh")and triggering it viafree()on libc‑2.24 (pre-hook removal).
References
- https://github.com/shellphish/how2heap
- https://github.com/shellphish/how2heap/blob/master/glibc_2.23/house_of_roman.c
- https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/house_of_roman/
- https://halloween.synacktiv.com/publications/heap-tricks-never-get-old-insomnihack-teaser-2022.html
- https://gist.github.com/romanking98/9aab2804832c0fb46615f025e8ffb0bc
- https://sourceware.org/git/?p=glibc.git;a=blob_plain;f=NEWS;hb=glibc-2.34
- https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=b90ddd08f6dd688e651df9ee89ca3a69ff88cd0c
Tip
Learn & practice AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Learn & practice GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Learn & practice Az Hacking:HackTricks Training Azure Red Team Expert (AzRTE)
Support HackTricks
- Check the subscription plans!
- Join the 💬 Discord group or the telegram group or follow us on Twitter 🐦 @hacktricks_live.
- Share hacking tricks by submitting PRs to the HackTricks and HackTricks Cloud github repos.


