Skip to content

Commit e49eec0

Browse files
authored
Merge pull request #1727 from HackTricks-wiki/update_Flagvent_2025__Hard___FV25_08_Kellerspeicher_aufm__20260101_014946
Flagvent 2025 (Hard) FV25.08 Kellerspeicher aufm Haufen (GNU...
2 parents 6aa3380 + 53aa0f4 commit e49eec0

File tree

3 files changed

+72
-0
lines changed

3 files changed

+72
-0
lines changed

src/SUMMARY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -843,6 +843,7 @@
843843
- [Use After Free](binary-exploitation/libc-heap/use-after-free/README.md)
844844
- [First Fit](binary-exploitation/libc-heap/use-after-free/first-fit.md)
845845
- [Double Free](binary-exploitation/libc-heap/double-free.md)
846+
- [Gnu Obstack Function Pointer Hijack](binary-exploitation/libc-heap/gnu-obstack-function-pointer-hijack.md)
846847
- [Overwriting a freed chunk](binary-exploitation/libc-heap/overwriting-a-freed-chunk.md)
847848
- [Heap Overflow](binary-exploitation/libc-heap/heap-overflow.md)
848849
- [Unlink Attack](binary-exploitation/libc-heap/unlink-attack.md)

src/binary-exploitation/libc-heap/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -535,6 +535,10 @@ Study allocator-specific primitives derived from real-world bugs:
535535
virtualbox-slirp-nat-packet-heap-exploitation.md
536536
{{#endref}}
537537
538+
{{#ref}}
539+
gnu-obstack-function-pointer-hijack.md
540+
{{#endref}}
541+
538542
## References
539543
540544
- [https://azeria-labs.com/heap-exploitation-part-1-understanding-the-glibc-heap-implementation/](https://azeria-labs.com/heap-exploitation-part-1-understanding-the-glibc-heap-implementation/)
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# GNU obstack function-pointer hijack
2+
3+
{{#include ../../banners/hacktricks-training.md}}
4+
5+
## Overview
6+
7+
GNU obstacks embed allocator state together with two indirect call targets:
8+
9+
- `chunkfun` (offset `+0x38`) with signature `void *(*chunkfun)(void *, size_t)`
10+
- `freefun` (offset `+0x40`) with signature `void (*freefun)(void *, void *)`
11+
- `extra_arg` and a `use_extra_arg` flag select whether `_obstack_newchunk` calls `chunkfun(new_size)` or `chunkfun(extra_arg, new_size)`
12+
13+
If an attacker can corrupt an application-owned `struct obstack *` or its fields, the next growth of the obstack (when `next_free == chunk_limit`) triggers an indirect call through `chunkfun`, enabling code execution primitives.
14+
15+
## Primitive: size_t desync → 0-byte allocation → pointer OOB write
16+
17+
A common bug pattern is using a **32-bit register** to compute `sizeof(ptr) * count` while storing the logical length in a 64-bit `size_t`.
18+
19+
- Example: `elements = obstack_alloc(obs, sizeof(void *) * size);` is compiled as `SHL EAX,0x3` for `size << 3`.
20+
- With `size = 0x20000000` and `sizeof(void *) = 8`, the multiplication wraps to `0x0` in 32-bit, so the pointer array is **0 bytes**, but the recorded `size` remains `0x20000000`.
21+
- Subsequent `elements[curr++] = ptr;` writes perform **8-byte OOB pointer stores** into adjacent heap objects, giving a controlled cross-object overwrite primitive.
22+
23+
## Leaking libc via `obstack.chunkfun`
24+
25+
1. Place two heap objects adjacent (e.g., two stacks built with separate obstacks).
26+
2. Use the pointer-array OOB write from object A to overwrite object B’s `elements` pointer so that a `pop`/read from B dereferences an address inside object A’s obstack.
27+
3. Read `chunkfun` (`malloc` by default) at offset `0x38` to disclose a libc function pointer, then compute `libc_base = leak - malloc_offset` and derive other symbols (e.g., `system`, `"/bin/sh"`).
28+
29+
## Hijacking `chunkfun` with a fake obstack
30+
31+
Overwrite a victim’s stored `struct obstack *` to point at attacker-controlled data that mimics the obstack header. Minimal fields needed:
32+
33+
- `next_free == chunk_limit` to force `_obstack_newchunk` on next push
34+
- `chunkfun = system_addr`
35+
- `extra_arg = binsh_addr`, `use_extra_arg = 1` to select the two-argument call form
36+
37+
Then trigger an allocation on the victim obstack to execute `system("/bin/sh")` through the indirect call.
38+
39+
Example fake obstack layout (glibc 2.42 offsets):
40+
41+
```python
42+
fake = b""
43+
fake += p64(0x1000) # chunk_size
44+
fake += p64(heap_leak) # chunk
45+
fake += p64(heap_leak) # object_base
46+
fake += p64(heap_leak) # next_free == chunk_limit
47+
fake += p64(heap_leak) # chunk_limit
48+
fake += p64(0xF) # alignment_mask
49+
fake += p64(0) # temp
50+
fake += p64(system_addr) # chunkfun
51+
fake += p64(0) # freefun
52+
fake += p64(binsh_addr) # extra_arg
53+
fake += p64(1) # use_extra_arg flag set
54+
```
55+
56+
## Attack recipe
57+
58+
1. **Trigger size wrap** to create a 0-byte pointer array with a huge logical length.
59+
2. **Groom adjacency** so an OOB pointer store reaches a neighbor object containing an obstack pointer.
60+
3. **Leak libc** by redirecting a victim pointer to the neighbor obstack’s `chunkfun` and reading the function pointer.
61+
4. **Forge obstack** data with controlled `chunkfun`/`extra_arg` and force `_obstack_newchunk` to land in the forged header, yielding a function-pointer call of the attacker’s choice.
62+
63+
## References
64+
65+
- [Flagvent 2025 FV25.08 obstack exploit (0xdf)](https://0xdf.gitlab.io/flagvent2025/hard)
66+
67+
{{#include ../../banners/hacktricks-training.md}}

0 commit comments

Comments
 (0)