diff --git a/src/binary-exploitation/libc-heap/off-by-one-overflow.md b/src/binary-exploitation/libc-heap/off-by-one-overflow.md index a1d558a85a0..fa226165886 100644 --- a/src/binary-exploitation/libc-heap/off-by-one-overflow.md +++ b/src/binary-exploitation/libc-heap/off-by-one-overflow.md @@ -73,6 +73,40 @@ This image explains perfectly the attack:

https://heap-exploitation.dhavalkapil.com/attacks/shrinking_free_chunks

+### Modern glibc hardening & bypass notes (>=2.32) + +- 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. +- 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. +- Workflow for safe-linking + single-byte corruptions: + 1. Grow the victim chunk until it fully covers a freed chunk you already control (overlapping-chunk setup). + 2. Leak any heap pointer (stdout, UAF, partially controlled struct) and derive the key `heap_base >> 12`. + 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. + 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. + +A minimal helper to rehearse the encode/decode step while debugging modern exploits: + +```python +def protect(ptr, chunk_addr): + return ptr ^ (chunk_addr >> 12) + +def reveal(encoded, chunk_addr): + return encoded ^ (chunk_addr >> 12) + +chunk = 0x55555555c2c0 +encoded_fd = protect(0xdeadbeefcaf0, chunk) +print(hex(reveal(encoded_fd, chunk))) # 0xdeadbeefcaf0 +``` + +### Recent real-world target: glibc __vsyslog_internal off-by-one (CVE-2023-6779) + +- 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)). +- Their Fedora 38 exploit pipeline: + 1. Craft an overlong `openlog()` ident so `vasprintf` returns a heap buffer next to attacker-controlled data. + 2. Call `syslog()` to smash the neighbor chunk’s `size | prev_inuse` byte, free it, and force consolidation that overlaps attacker data. + 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. +- 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. +- 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. + ## Other Examples & References - [**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: - 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. - 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. - The libc address is leaked because if the heap is extended using mmap, the memory allocated by mmap has a fixed offset from libc. - - Finally the arbitrary write is abused to write into the address of \_\_free_hook with a one gadget. + - Finally the arbitrary write is abused to write into the address of `__free_hook` with a one gadget. - [**plaidctf 2015 plaiddb**](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/off_by_one/#instance-2-plaidctf-2015-plaiddb) - 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. - In the writeup 5 initial chunks are created: @@ -112,7 +146,10 @@ This image explains perfectly the attack: - Then, a chunk of 0x68 is allocated so the fake fast bin chunk in `__malloc_hook` is the following fast bin chunk - Finally, a new fast bin chunk of 0x68 is allocated and `__malloc_hook` is overwritten with a `one_gadget` address -{{#include ../../banners/hacktricks-training.md}} - +## References +- [Qualys Security Advisory – CVE-2023-6246/6779/6780](https://www.qualys.com/2024/01/30/cve-2023-6246/syslog.txt) +- [Ubuntu Security – CVE-2023-6779](https://ubuntu.com/security/CVE-2023-6779) +- [Breaking Safe-Linking in Modern Glibc – Google CTF 2022 "saas" analysis](https://blog.csdn.net/2402_86373248/article/details/148717274) +{{#include ../../banners/hacktricks-training.md}}