Skip to content

Commit c15c8f5

Browse files
authored
Merge pull request #1594 from HackTricks-wiki/research_update_src_binary-exploitation_libc-heap_off-by-one-overflow_20251123_014951
Research Update Enhanced src/binary-exploitation/libc-heap/o...
2 parents 95e82ac + 3455543 commit c15c8f5

File tree

1 file changed

+40
-3
lines changed

1 file changed

+40
-3
lines changed

src/binary-exploitation/libc-heap/off-by-one-overflow.md

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,40 @@ This image explains perfectly the attack:
7373
7474
<figure><img src="../../images/image (1247).png" alt=""><figcaption><p><a href="https://heap-exploitation.dhavalkapil.com/attacks/shrinking_free_chunks">https://heap-exploitation.dhavalkapil.com/attacks/shrinking_free_chunks</a></p></figcaption></figure>
7575
76+
### Modern glibc hardening & bypass notes (>=2.32)
77+
78+
- Safe-Linking now protects every singly linked bin pointer by storing `fd = ptr ^ (chunk_addr >> 12)`, so an off-by-one that only flips the low byte of `size` usually also needs a heap leak to recompute the XOR mask before Tcache poisoning works.
79+
- A practical leakless trick is to "double-protect" a pointer: encode a pointer you already control with `PROTECT_PTR`, then reuse the same gadget to encode your forged pointer so the alignment check passes without revealing new addresses.
80+
- Workflow for safe-linking + single-byte corruptions:
81+
1. Grow the victim chunk until it fully covers a freed chunk you already control (overlapping-chunk setup).
82+
2. Leak any heap pointer (stdout, UAF, partially controlled struct) and derive the key `heap_base >> 12`.
83+
3. Re-encode free-list pointers before writing them—stage the encoded value inside user data and memcpy it later if you only own single-byte writes.
84+
4. Combine with [Tcache bin attacks](tcache-bin-attack.md) to redirect allocations into `__free_hook` or `tcache_perthread_struct` entries once the forged pointer is properly encoded.
85+
86+
A minimal helper to rehearse the encode/decode step while debugging modern exploits:
87+
88+
```python
89+
def protect(ptr, chunk_addr):
90+
return ptr ^ (chunk_addr >> 12)
91+
92+
def reveal(encoded, chunk_addr):
93+
return encoded ^ (chunk_addr >> 12)
94+
95+
chunk = 0x55555555c2c0
96+
encoded_fd = protect(0xdeadbeefcaf0, chunk)
97+
print(hex(reveal(encoded_fd, chunk))) # 0xdeadbeefcaf0
98+
```
99+
100+
### Recent real-world target: glibc __vsyslog_internal off-by-one (CVE-2023-6779)
101+
102+
- In January 2024 Qualys detailed CVE-2023-6779, an off-by-one inside `__vsyslog_internal()` that triggers when `syslog()/vsyslog()` format strings exceed `INT_MAX`, so the terminating `\0` corrupts the next chunk’s least-significant `size` byte on glibc 2.37–2.39 systems ([Qualys advisory](https://www.qualys.com/2024/01/30/cve-2023-6246/syslog.txt)).
103+
- Their Fedora 38 exploit pipeline:
104+
1. Craft an overlong `openlog()` ident so `vasprintf` returns a heap buffer next to attacker-controlled data.
105+
2. Call `syslog()` to smash the neighbor chunk’s `size | prev_inuse` byte, free it, and force consolidation that overlaps attacker data.
106+
3. Use the overlapped view to corrupt `tcache_perthread_struct` metadata and aim the next allocation at `__free_hook`, overwriting it with `system`/a one_gadget for root.
107+
- To reproduce the corrupting write in a harness, fork with a gigantic `argv[0]`, call `openlog(NULL, LOG_PID, LOG_USER)` and then `syslog(LOG_INFO, "%s", payload)` where `payload = b"A" * 0x7fffffff`; `pwndbg`’s `heap bins` immediately shows the single-byte overwrite.
108+
- Ubuntu tracks the bug as [CVE-2023-6779](https://ubuntu.com/security/CVE-2023-6779), documenting the same INT truncation that makes this a reliable off-by-one primitive.
109+
76110
## Other Examples & References
77111

78112
- [**https://heap-exploitation.dhavalkapil.com/attacks/shrinking_free_chunks**](https://heap-exploitation.dhavalkapil.com/attacks/shrinking_free_chunks)
@@ -83,7 +117,7 @@ This image explains perfectly the attack:
83117
- It's possible to abuse an off by one to leak an address from the heap because the byte 0x00 of the end of a string being overwritten by the next field.
84118
- Arbitrary write is obtained by abusing the off by one write to make the pointer point to another place were a fake struct with fake pointers will be built. Then, it's possible to follow the pointer of this struct to obtain arbitrary write.
85119
- The libc address is leaked because if the heap is extended using mmap, the memory allocated by mmap has a fixed offset from libc.
86-
- Finally the arbitrary write is abused to write into the address of \_\_free_hook with a one gadget.
120+
- Finally the arbitrary write is abused to write into the address of `__free_hook` with a one gadget.
87121
- [**plaidctf 2015 plaiddb**](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/off_by_one/#instance-2-plaidctf-2015-plaiddb)
88122
- There is a NULL off by one vulnerability in the `getline` function that reads user input lines. This function is used to read the "key" of the content and not the content.
89123
- In the writeup 5 initial chunks are created:
@@ -112,7 +146,10 @@ This image explains perfectly the attack:
112146
- Then, a chunk of 0x68 is allocated so the fake fast bin chunk in `__malloc_hook` is the following fast bin chunk
113147
- Finally, a new fast bin chunk of 0x68 is allocated and `__malloc_hook` is overwritten with a `one_gadget` address
114148

115-
{{#include ../../banners/hacktricks-training.md}}
116-
149+
## References
117150

151+
- [Qualys Security Advisory – CVE-2023-6246/6779/6780](https://www.qualys.com/2024/01/30/cve-2023-6246/syslog.txt)
152+
- [Ubuntu Security – CVE-2023-6779](https://ubuntu.com/security/CVE-2023-6779)
153+
- [Breaking Safe-Linking in Modern Glibc – Google CTF 2022 "saas" analysis](https://blog.csdn.net/2402_86373248/article/details/148717274)
118154

155+
{{#include ../../banners/hacktricks-training.md}}

0 commit comments

Comments
 (0)