Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions src/binary-exploitation/libc-heap/house-of-orange.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

- Find an example in [https://github.com/shellphish/how2heap/blob/master/glibc_2.23/house_of_orange.c](https://github.com/shellphish/how2heap/blob/master/glibc_2.23/house_of_orange.c)
- The exploitation technique was fixed in this [patch](https://sourceware.org/git/?p=glibc.git;a=blobdiff;f=stdlib/abort.c;h=117a507ff88d862445551f2c07abb6e45a716b75;hp=19882f3e3dc1ab830431506329c94dcf1d7cc252;hb=91e7cf982d0104f0e71770f5ae8e3faf352dea9f;hpb=0c25125780083cbba22ed627756548efe282d1a0) so this is no longer working (working in earlier than 2.26)
- Same example **with more comments** in [https://guyinatuxedo.github.io/43-house_of_orange/house_orange_exp/index.html](https://guyinatuxedo.github.io/43-house_of_orange/house_orange_exp/index.html)
- Same example **with more comments** in [https://guyinatuxedo.github.io/43-house_of_orange/house_orange_exp/index.html](https://guyinatuxedo.github.io/43-house_of_orange/house_orange_exp/index.html)<sup>[[2]](#references)</sup>

### Goal

Expand All @@ -21,21 +21,21 @@

### Background

Some needed background from the comments from [**this example**](https://guyinatuxedo.github.io/43-house_of_orange/house_orange_exp/index.html)**:**
Some needed background from the comments from [**this example**](https://guyinatuxedo.github.io/43-house_of_orange/house_orange_exp/index.html)**:**<sup>[[2]](#references)</sup>

Thing is, in older versions of libc, when the `malloc_printerr` function was called it would **iterate through a list of `_IO_FILE` structs stored in `_IO_list_all`**, and actually **execute** an instruction pointer in that struct.\
This attack will forge a **fake `_IO_FILE` struct** that we will write to **`_IO_list_all`**, and cause `malloc_printerr` to run.\
Then it will **execute whatever address** we have stored in the **`_IO_FILE`** structs jump table, and we will get code execution<sup>[[2]](#references)</sup>

### Attack

The attack starts by managing to get the **top chunk** inside the **unsorted bin**. This is achieved by calling `malloc` with a size greater than the current top chunk size but smaller than **`mmp_.mmap_threshold`** (default is 128K), which would otherwise trigger `mmap` allocation. Whenever the top chunk size is modified, it's important to ensure that the **top chunk + its size** is page-aligned and that the **prev_inuse** bit of the top chunk is always set.<sup>[[1]](#references)</sup>
The attack starts by managing to get the **top chunk** inside the **unsorted bin**. This is achieved by calling `malloc` with a size greater than the current top chunk size but smaller than **`mmp_.mmap_threshold`** (default is 128K), which would otherwise trigger `mmap` allocation. Whenever the top chunk size is modified, it's important to ensure that the **top chunk + its size** is page-aligned and that the **prev_inuse** bit of the top chunk is always set.

To get the top chunk inside the unsorted bin, allocate a chunk to create the top chunk, change the top chunk size (with an overflow in the allocated chunk) so that **top chunk + size** is page-aligned with the **prev_inuse** bit set. Then allocate a chunk larger than the new top chunk size. Note that `free` is never called to get the top chunk into the unsorted bin.
To get the top chunk inside the unsorted bin, allocate a chunk to create the top chunk, change the top chunk size (with an overflow in the allocated chunk) so that **top chunk + size** is page-aligned with the **prev_inuse** bit set. Then allocate a chunk larger than the new top chunk size. Note that `free` is never called to get the top chunk into the unsorted bin.<sup>[[1]](#references)</sup>

The old top chunk is now in the unsorted bin. Assuming we can read data inside it (possibly due to a vulnerability that also caused the overflow), it’s possible to leak libc addresses from it and get the address of **\_IO_list_all**.

An unsorted bin attack is performed by abusing the overflow to write `topChunk->bk->fwd = _IO_list_all - 0x10`. When a new chunk is allocated, the old top chunk will be split, and a pointer to the unsorted bin will be written into **`_IO_list_all`**.
An unsorted bin attack is performed by abusing the overflow to write `topChunk->bk->fwd = _IO_list_all - 0x10`. When a new chunk is allocated, the old top chunk will be split, and a pointer to the unsorted bin will be written into **`_IO_list_all`**.<sup>[[2]](#references)</sup>

The next step involves shrinking the size of the old top chunk to fit into a small bin, specifically setting its size to **0x61**. This serves two purposes:

Expand Down Expand Up @@ -69,7 +69,7 @@ This approach exploits heap management mechanisms, libc information leaks, and h

## References

- [1] [CTF-wiki - House of Orange](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/house_of_orange/)
- [2] [Nightmare - House of Orange (guyinatuxedo)](https://guyinatuxedo.github.io/43-house_of_orange/house_orange_exp/index.html)
- [1] [House of Orange - CTF Wiki](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/house_of_orange/)
- [2] [House of Orange exploitation walkthrough - guyinatuxedo](https://guyinatuxedo.github.io/43-house_of_orange/house_orange_exp/index.html)

{{#include ../../banners/hacktricks-training.md}}
10 changes: 6 additions & 4 deletions src/binary-exploitation/libc-heap/house-of-rabbit.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

### POC 1: Modify the size of a fast bin chunk

**Objective**: Create an overlapping chunk by manipulating the size of a fastbin chunk.
**Objective**: Create an overlapping chunk by manipulating the size of a fastbin chunk.<sup>[[1]](#references)[[2]](#references)</sup>

- **Step 1: Allocate Chunks**

Expand Down Expand Up @@ -57,7 +57,7 @@ After consolidation, `chunk1` overlaps with `chunk2`, allowing for further explo

### POC 2: Modify the `fd` pointer

**Objective**: Create a fake chunk by manipulating the fast bin `fd` pointer.
**Objective**: Create a fake chunk by manipulating the fast bin `fd` pointer.<sup>[[1]](#references)[[2]](#references)</sup>

- **Step 1: Allocate Chunks**

Expand Down Expand Up @@ -108,7 +108,9 @@ The fake chunk becomes part of the fastbin list, making it a legitimate chunk fo

The **House of Rabbit** technique involves either modifying the size of a fast bin chunk to create overlapping chunks or manipulating the `fd` pointer to create fake chunks. This allows attackers to forge legitimate chunks in the heap, enabling various forms of exploitation. Understanding and practicing these steps will enhance your heap exploitation skills.

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

## References

- [1] [House_of_Rabbit - shift-crops (original technique/PoC)](https://github.com/shift-crops/House_of_Rabbit)
- [2] [House of Rabbit - CTF Wiki EN](https://ctf-wiki.mahaloz.re/pwn/linux/glibc-heap/house_of_rabbit/)

{{#include ../../banners/hacktricks-training.md}}
10 changes: 5 additions & 5 deletions src/binary-exploitation/libc-heap/large-bin-attack.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ It's possible to find a great example in [**how2heap - large bin attack**](https

Basically here you can see how, in the latest "current" version of glibc (2.35), it's not checked: **`P->bk_nextsize`** allowing to modify an arbitrary address with the value of a large bin chunk if certain conditions are met.

In that example you can find the following conditions:
In that example you can find the following conditions:<sup>[[1]](#references)</sup>

- A large chunk is allocated
- A large chunk smaller than the first one but in the same index is allocated
Expand Down Expand Up @@ -52,14 +52,14 @@ You can find another great explanation of this attack in [**guyinatuxedo**](http
### Other examples

- [**La casa de papel. HackOn CTF 2024**](https://7rocky.github.io/en/ctf/other/hackon-ctf/la-casa-de-papel/)<sup>[[3]](#references)</sup>
- Large bin attack in the same situation as it appears in [**how2heap**](https://github.com/shellphish/how2heap/blob/master/glibc_2.35/large_bin_attack.c).
- Large bin attack in the same situation as it appears in [**how2heap**](https://github.com/shellphish/how2heap/blob/master/glibc_2.35/large_bin_attack.c).<sup>[[1]](#references)</sup>
- The write primitive is more complex, because `global_max_fast` is useless here.
- FSOP is needed to finish the exploit.

## References

- [1] [how2heap - large bin attack](https://github.com/shellphish/how2heap/blob/master/glibc_2.35/large_bin_attack.c)
- [2] [guyinatuxedo - Large Bin Attack explanation](https://guyinatuxedo.github.io/32-largebin_attack/largebin_explanation0/index.html)
- [3] [La casa de papel. HackOn CTF 2024](https://7rocky.github.io/en/ctf/other/hackon-ctf/la-casa-de-papel/)
- [1] [how2heap - large_bin_attack.c (glibc 2.35)](https://github.com/shellphish/how2heap/blob/master/glibc_2.35/large_bin_attack.c)
- [2] [Large Bin Attack explanation - guyinatuxedo](https://guyinatuxedo.github.io/32-largebin_attack/largebin_explanation0/index.html)
- [3] [La casa de papel. HackOn CTF 2024 - 7rocky](https://7rocky.github.io/en/ctf/other/hackon-ctf/la-casa-de-papel/)

{{#include ../../banners/hacktricks-training.md}}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ Root cause (allocation clamped, memcpy at unclamped offset)

Why the write offset matters
- The vulnerable path is not just "write more than 64KiB". The missing check was that `*pos` was not validated against the current stream length (`v_len`) before the append/copy logic ran.
- Upstream fixed this by rejecting writes where `*pos >= v_len` with `-EINVAL`. Pre-fix, an attacker could reuse a valid authenticated handle to a named stream and send a raw SMB2 WRITE whose `file_offset` already points at or past the end of the existing stream, which turns the post-clamp `memcpy()` into a deterministic page overflow.<sup>[[1]](#references)[[2]](#references)</sup>
- Upstream fixed this by rejecting writes where `*pos >= v_len` with `-EINVAL`.<sup>[[2]](#references)</sup> Pre-fix, an attacker could reuse a valid authenticated handle to a named stream and send a raw SMB2 WRITE whose `file_offset` already points at or past the end of the existing stream, which turns the post-clamp `memcpy()` into a deterministic page overflow.
- The public PoC demonstrates this by authenticating with `libsmb2`, opening a stream path such as `1337:`, extracting `SessionId`/`TreeId`/`FileId`, and then sending a handcrafted SMB2 WRITE with `file_offset = 0x10018` and a small `Length`.<sup>[[1]](#references)[[3]](#references)</sup>

<details>
Expand Down Expand Up @@ -53,12 +53,12 @@ static int ksmbd_vfs_stream_write(struct ksmbd_file *fp, char *buf, loff_t *pos,
</details>

Offset steering and OOB length
- Example: set file offset (pos) to 0x10018 and original length (count) to 8. After clamping, count' = (0x10018 + 8) - 0x10000 = 0x20, but memcpy writes 32 bytes starting at stream_buf[0x10018], i.e., 0x18 bytes beyond the 16-page allocation.
- Example: set file offset (pos) to 0x10018 and original length (count) to 8. After clamping, count' = (0x10018 + 8) - 0x10000 = 0x20, but memcpy writes 32 bytes starting at stream_buf[0x10018], i.e., 0x18 bytes beyond the 16-page allocation.<sup>[[1]](#references)</sup>

Triggering the bug via SMB streams write
- Use the same authenticated SMB connection to open a file on the share and issue a write to a named stream (streams_xattr). Set file_offset ≥ 0x10000 with a small length to generate a deterministic OOB write of controllable size.
- libsmb2 can be used to authenticate and craft such writes over SMB2/3.
- In practice, reusing the negotiated SMB session is convenient because the exploit only needs to patch a few dynamic fields in the WRITE request (`TreeId`, `SessionId`, `FileId`) and can then transmit the malformed packet directly on the same socket.
- In practice, reusing the negotiated SMB session is convenient because the exploit only needs to patch a few dynamic fields in the WRITE request (`TreeId`, `SessionId`, `FileId`) and can then transmit the malformed packet directly on the same socket.<sup>[[1]](#references)[[3]](#references)</sup>

Minimal reachability (concept)
```c
Expand All @@ -71,12 +71,12 @@ smb2_pwrite(fd, payload, 8, 0x0000010018ULL); // yields 32-byte OOB
Allocator behavior and why page shaping is required
- kvmalloc(0x10000, GFP_KERNEL|__GFP_ZERO) requests an order-4 (16 contiguous pages) allocation from the buddy allocator when size > KMALLOC_MAX_CACHE_SIZE. This is not a SLUB cache object.
- memcpy occurs immediately after allocation; post-allocation spraying is ineffective. You must pre-groom physical memory so that a chosen target lies immediately after the allocated 16-page block.
- On Ubuntu, GFP_KERNEL often pulls from the Unmovable migrate type in zone Normal. Exhaust order-3 and order-4 freelists to force the allocator to split an order-5 block into an adjacent order-4 + order-3 pair, then park an order-3 slab (kmalloc-cg-4k) directly after the stream buffer.
- On Ubuntu, GFP_KERNEL often pulls from the Unmovable migrate type in zone Normal. Exhaust order-3 and order-4 freelists to force the allocator to split an order-5 block into an adjacent order-4 + order-3 pair, then park an order-3 slab (kmalloc-cg-4k) directly after the stream buffer.<sup>[[1]](#references)</sup>

Practical page shaping strategy
- Spray ~1000–2000 msg_msg objects of ~4096 bytes (fits kmalloc-cg-4k) to populate order-3 slabs.
- Receive some messages to punch holes and encourage adjacency.
- Trigger the ksmbd OOB repeatedly until the order-4 stream buffer lands immediately before a msg_msg slab. Use eBPF tracing to confirm addresses and alignment if available.
- Trigger the ksmbd OOB repeatedly until the order-4 stream buffer lands immediately before a msg_msg slab. Use eBPF tracing to confirm addresses and alignment if available.<sup>[[1]](#references)</sup>

Useful observability
```bash
Expand All @@ -89,25 +89,25 @@ sudo ./bpf-tracer.sh
What to trace while tuning
- `kvmalloc_node(0x10000)` confirms when the vulnerable stream write actually consumes an order-4 allocation.
- `load_msg`/`kretprobe:load_msg` lets you estimate how many `msg_msgseg` allocations are attached to each sprayed message, which is useful when tuning primary/secondary message sizes for a specific kernel build.
- If the exploit is ported to a different distro/kernel, re-check cache names, inline `msg_msg` payload sizes, `anon_pipe_buf_ops` offsets, and gadget addresses rather than assuming the Ubuntu 22.04 LTS `5.15.0-153-generic` constants still match.
- If the exploit is ported to a different distro/kernel, re-check cache names, inline `msg_msg` payload sizes, `anon_pipe_buf_ops` offsets, and gadget addresses rather than assuming the Ubuntu 22.04 LTS `5.15.0-153-generic` constants still match.<sup>[[1]](#references)</sup>

Exploitation plan (msg_msg + pipe_buffer), adapted from CVE-2021-22555<sup>[[1]](#references)</sup>
Exploitation plan (msg_msg + pipe_buffer), adapted from CVE-2021-22555
1) Spray many System V msg_msg primary/secondary messages (4KiB-sized to fit kmalloc-cg-4k).
2) Trigger ksmbd OOB to corrupt a primary message’s next pointer so that two primaries share one secondary.
3) Detect the corrupted pair by tagging queues and scanning with msgrcv(MSG_COPY) to find mismatched tags.
4) Free the real secondary to create a UAF; reclaim it with controlled data via UNIX sockets (craft a fake msg_msg).
5) Leak kernel heap pointers by abusing m_ts over-read in copy_msg to obtain mlist.next/mlist.prev (SMAP bypass).
6) With an sk_buff spray, rebuild a consistent fake msg_msg with valid links and free it normally to stabilize state.
7) Reclaim the UAF with struct pipe_buffer objects; leak anon_pipe_buf_ops to compute kernel base (defeat KASLR).
8) Spray a fake pipe_buf_operations with release pointing to a stack pivot/ROP gadget; close pipes to execute and gain root.
8) Spray a fake pipe_buf_operations with release pointing to a stack pivot/ROP gadget; close pipes to execute and gain root.<sup>[[1]](#references)</sup>

Bypasses and notes
- KASLR: leak anon_pipe_buf_ops, compute base (kbase_addr) and gadget addresses.
- SMEP/SMAP: execute ROP in kernel context via pipe_buf_operations->release flow; avoid userspace derefs until after disable/prepare_kernel_cred/commit_creds chain.
- Hardened usercopy: not applicable to this page overflow primitive; corruption targets are non-usercopy fields.
- Hardened usercopy: not applicable to this page overflow primitive; corruption targets are non-usercopy fields.<sup>[[1]](#references)</sup>

Reliability
- High once adjacency is achieved; occasional misses or panics (<10%). Tuning spray/free counts improves stability. Overwriting two LSBs of a pointer to induce specific collisions was reported as effective (e.g., write 0x0000_0000_0000_0500 pattern into the overlap).
- High once adjacency is achieved; occasional misses or panics (<10%). Tuning spray/free counts improves stability. Overwriting two LSBs of a pointer to induce specific collisions was reported as effective (e.g., write 0x0000_0000_0000_0500 pattern into the overlap).<sup>[[1]](#references)</sup>

Key parameters to tune
- Number of msg_msg sprays and hole pattern
Expand All @@ -116,7 +116,7 @@ Key parameters to tune

Mitigations and reachability
- Fix: clamp both allocation and destination/length or bound memcpy against the allocated size; upstream patches track as CVE-2025-37947.<sup>[[2]](#references)</sup>
- Remote exploitation would additionally require a reliable infoleak and remote heap grooming; this write-up focuses on local LPE.
- Remote exploitation would additionally require a reliable infoleak and remote heap grooming; this write-up focuses on local LPE.<sup>[[1]](#references)</sup>

See also

Expand All @@ -130,6 +130,7 @@ References PoC and tooling
- Minimal reachability PoC and full local exploit are publicly available (see References)

## References

- [1] [ksmbd - Exploiting CVE-2025-37947 (3/3) — Doyensec](https://blog.doyensec.com/2025/10/08/ksmbd-3.html)
- [2] [Linux upstream fix: `ksmbd: prevent out-of-bounds stream writes by validating *pos`](https://github.com/torvalds/linux/commit/0ca6df4f40cf4c32487944aaf48319cb6c25accc)
- [3] [KSMBD-CVE-2025-37947 PoC repository](https://github.com/doyensec/KSMBD-CVE-2025-37947)
Expand Down
Loading