You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: src/binary-exploitation/libc-heap/house-of-roman.md
+26-15Lines changed: 26 additions & 15 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -4,7 +4,13 @@
4
4
5
5
## Basic Information
6
6
7
-
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 ben [**patched**](https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=b90ddd08f6dd688e651df9ee89ca3a69ff88cd0c).
7
+
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**](https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=b90ddd08f6dd688e651df9ee89ca3a69ff88cd0c).
8
+
9
+
### Applicability in 2026
10
+
11
+
-**glibc window:** Works reliably on **2.23–2.28**. On **2.29** the additional `unsorted_chunks` integrity checks make the unsorted‑bin write unreliable, so success drops sharply. From **2.34** onward `__malloc_hook/__free_hook` were 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.
12
+
-**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.
13
+
-**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.
8
14
9
15
### Code
10
16
@@ -46,24 +52,24 @@ Current heap layout:
46
52
0x190: relative_offset_heap - size 0x70
47
53
48
54
bin layout:
49
-
fastbin: fastbin_victim -> relative_offset_heap
50
-
unsorted: leftover_main
55
+
fastbin: fastbin_victim -> relative_offset_heap
56
+
unsorted: leftover_main
51
57
*/
52
58
```
53
59
54
60
-`fastbin_victim` has a `fd` pointing to `relative_offset_heap`
55
61
-`relative_offset_heap` is an offset of distance from `fake_libc_chunk`, which contains a pointer to `main_arena + 0x68`
56
-
-Just changing the last byte of `fastbin_victim.fd`it's possible to make `fastbin_victim points`to `main_arena + 0x68`
62
+
-Changing the last byte of `fastbin_victim.fd`makes `fastbin_victim` point to `main_arena + 0x68`.
57
63
58
64
For the previous actions, the attacker needs to be capable of modifying the fd pointer of `fastbin_victim`.
59
65
60
-
Then, `main_arena + 0x68` is not that interesting, so lets modify it so the pointer points to **`__malloc_hook`**.
66
+
Then, `main_arena + 0x68` is not that interesting, so let's modify it so the pointer points to **`__malloc_hook`**.
61
67
62
-
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 are interested. So a BF attack is performed here so the chunk ends like: **`0x70: fastbin_victim -> fake_libc_chunk -> (__malloc_hook - 0x23)`.**
68
+
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)`.**
63
69
64
-
(For more info about the rest of the bytes check the explanation in the [how2heap](https://github.com/shellphish/how2heap/blob/master/glibc_2.23/house_of_roman.c)[ example](https://github.com/shellphish/how2heap/blob/master/glibc_2.23/house_of_roman.c)). If the BF don't work the program just crashes (so start gain until it works).
70
+
(For more info about the rest of the bytes check the explanation in the [how2heap](https://github.com/shellphish/how2heap/blob/master/glibc_2.23/house_of_roman.c)[ example](https://github.com/shellphish/how2heap/blob/master/glibc_2.23/house_of_roman.c)). If the brute force fails the program just crashes (restart until it works).
65
71
66
-
Then, 2 mallocs are performed to remove the 2 initial fast bin chunks and the a third one is alloced to get a chunk in the **`__malloc_hook:`**
72
+
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`**.
But basically it allows to write `main_arena + 0x68` to any location by specified in `chunk->bk`. And for the attack we choose `__malloc_hook`. Then, after overwriting it we will use a relative overwrite) to point to a `one_gadget`.
88
+
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`.
84
89
85
90
For this we start getting a chunk and putting it into the **unsorted bin**:
86
91
@@ -102,20 +107,26 @@ So, to trigger the write of `main_arena + 0x68` in `__malloc_hook` we perform af
102
107
103
108
### Step 3: Set \_\_malloc_hook to system
104
109
105
-
In the step one we ended controlling a chunk containing `__malloc_hook` (in the variable `malloc_hook_chunk`) and in the second step we managed to write `main_arena + 0x68`in here.
110
+
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.
106
111
107
-
Now, we abuse a partial overwrite in `malloc_hook_chunk` to use the libc address we wrote there(`main_arena + 0x68`) to **point a `one_gadget` address**.
112
+
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**.
108
113
109
114
Here is where it's needed to **bruteforce 12 bits of randomness** (more info in the [how2heap](https://github.com/shellphish/how2heap/blob/master/glibc_2.23/house_of_roman.c)[ example](https://github.com/shellphish/how2heap/blob/master/glibc_2.23/house_of_roman.c)).
110
115
111
-
Finally, one the correct address is overwritten, **call `malloc` and trigger the `one_gadget`**.
116
+
Finally, once the correct address is overwritten, **call `malloc` and trigger the `one_gadget`**.
117
+
118
+
## Modern tips & variants
119
+
120
+
-**Unsorted-bin check in 2.29+:** If you must run on 2.29–2.33, corrupt both `fd`**and**`bk` to satisfy the integrity check before triggering the write; otherwise `_int_malloc` aborts. Success rate is very low and usually only viable in brute-force CTF settings.
121
+
-**Hook removal (2.34+):** With `__malloc_hook` gone, adapt the primitive to land on any writable GOT/global you can later reuse (e.g., overwrite `exit@GOT` in non-PIE binaries) or pivot to a **House of Pie** style top‑chunk hijack to control `top` instead of a hook.
122
+
-**Any‑address fastbin alloc (2024 gist):** A recent writeup shows reusing the same grooming to fastbin‑allocate over `__free_hook` or other globals by first landing a libc pointer in fastbin and then re‑pointing it before the fixup. This works on 2.24–2.28 but still dies on 2.29 integrity checks.
0 commit comments