Skip to content

Commit 6d62615

Browse files
authored
Merge pull request #1682 from HackTricks-wiki/update_Thinking_Outside_the_Box__Exploiting_VirtualBox_Sl_20251217_013518
Thinking Outside the Box Exploiting VirtualBox Slirp NAT Hea...
2 parents b768950 + aec03e9 commit 6d62615

File tree

3 files changed

+106
-0
lines changed

3 files changed

+106
-0
lines changed

src/SUMMARY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -872,6 +872,7 @@
872872
- [WWW2Exec - .dtors & .fini_array](binary-exploitation/arbitrary-write-2-exec/www2exec-.dtors-and-.fini_array.md)
873873
- [WWW2Exec - GOT/PLT](binary-exploitation/arbitrary-write-2-exec/aw2exec-got-plt.md)
874874
- [WWW2Exec - \_\_malloc_hook & \_\_free_hook](binary-exploitation/arbitrary-write-2-exec/aw2exec-__malloc_hook.md)
875+
- [Virtualbox Slirp Nat Packet Heap Exploitation](binary-exploitation/libc-heap/virtualbox-slirp-nat-packet-heap-exploitation.md)
875876
- [Common Exploiting Problems](binary-exploitation/common-exploiting-problems.md)
876877
- [Adreno A7xx Sds Rb Priv Bypass Gpu Smmu Kernel Rw](binary-exploitation/linux-kernel-exploitation/adreno-a7xx-sds-rb-priv-bypass-gpu-smmu-kernel-rw.md)
877878
- [Arm64 Static Linear Map Kaslr Bypass](binary-exploitation/linux-kernel-exploitation/arm64-static-linear-map-kaslr-bypass.md)

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -527,6 +527,14 @@ Functions involved in heap will perform certain check before performing its acti
527527
heap-memory-functions/heap-functions-security-checks.md
528528
{{#endref}}
529529
530+
## Case Studies
531+
532+
Study allocator-specific primitives derived from real-world bugs:
533+
534+
{{#ref}}
535+
virtualbox-slirp-nat-packet-heap-exploitation.md
536+
{{#endref}}
537+
530538
## References
531539
532540
- [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: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
# VirtualBox Slirp NAT Packet Heap Exploitation
2+
3+
{{#include ../../banners/hacktricks-training.md}}
4+
5+
## TL;DR
6+
7+
- VirtualBox ships a heavily modified fork of Slirp whose packet buffers (mbufs) live in a custom zone allocator with inline metadata and function-pointer callbacks (`pfFini`, `pfDtor`).
8+
- A guest can rewrite the trusted `m->m_len` with an attacker-controlled IP header length, which destroys all later bounds checks and yields both infoleak and overwrite primitives.
9+
- By abusing UDP packets with checksum `0` and oversized `ip_len`, the guest can exfiltrate mbuf tails and the metadata of neighbouring chunks to learn heap and zone addresses.
10+
- Providing crafted IP options forces `ip_stripoptions()` to `memcpy()` too much data in-place, so the attacker can overwrite the next mbuf's `struct item` header and point its `zone` field at fully controlled data.
11+
- Freeing the corrupted mbuf triggers `zone->pfFini()` with attacker-supplied arguments; pointing it to `memcpy@plt` gives an arbitrary copy/write primitive that can be steered toward GOT entries or other control data inside the non-PIE VirtualBox binary.
12+
13+
## Packet allocator anatomy
14+
15+
VirtualBox allocates every ingress Ethernet frame from a per-interface zone named `zone_clust`. Each 0x800-byte data chunk is preceded by an inline header:
16+
17+
```c
18+
struct item {
19+
uint32_t magic; // 0xdead0001
20+
void *zone; // uma_zone_t pointer with callbacks
21+
uint32_t ref_count;
22+
LIST_ENTRY(item) list; // freelist / used list links
23+
};
24+
```
25+
26+
When an mbuf is freed the call stack `m_freem -> ... -> slirp_uma_free()` trusts the inline header:
27+
28+
1. `uma_zfree_arg()` recomputes `item = (struct item *)mem - 1` and *should* validate `item->zone`, but `Assert()` is compiled out in release builds.
29+
2. `slirp_uma_free()` loads `zone = item->zone` and unconditionally executes `zone->pfFini(zone->pData, data_ptr, zone->size)` followed by `zone->pfDtor(...)`.
30+
31+
Therefore, any write-what-where into the mbuf header translates into a controlled indirect call during `free()`.
32+
33+
## Infoleak via `m->m_len` override
34+
35+
At the top of `ip_input()` VirtualBox added:
36+
37+
```c
38+
if (m->m_len != RT_N2H_U16(ip->ip_len))
39+
m->m_len = RT_N2H_U16(ip->ip_len);
40+
```
41+
42+
Because the assignment happens **before** verifying the IP header, a guest can advertise any length up to 0xffff. The rest of the stack (ICMP, UDP, fragmentation handlers, etc.) assumes `m->m_len` is trustworthy and uses it to decide how many bytes to copy off the mbuf.
43+
44+
Use UDP packets with checksum `0` (meaning "no checksum"). The NAT fast-path forwards `m->m_len` bytes without inspecting payload integrity, so inflating `ip_len` causes Slirp to read past the real buffer and return heap residues to the guest or to a cooperating external helper beyond the NAT. Because the chunk size is 2048 bytes, the leak can include:
45+
46+
- The next mbuf's inline `struct item`, revealing the freelist order and the real `zone` pointer.
47+
- Heap cookies such as `magic` fields, helping to craft valid-looking headers when performing corruptions later.
48+
49+
## Overwriting neighbouring chunk headers with IP options
50+
51+
The same bogus length can be turned into an overwrite primitive by forcing the packet through `ip_stripoptions()` (triggered when the IP header has options and the payload is UDP/TCP). The helper computes a copy length from `m->m_len` and then calls `memcpy()` to slide the transport header over the stripped options:
52+
53+
1. Supply a long `ip_len` so the computed move length extends past the current mbuf.
54+
2. Include a small number of IP options so Slirp enters the stripping path.
55+
3. When `memcpy()` runs, it reads from the following mbuf and writes over the current mbuf's payload and inline header, corrupting `magic`, `zone`, `ref_count`, etc.
56+
57+
Because the allocator keeps packets from the same interface contiguous on the freelist, this overflow deterministically hits the next chunk after modest heap grooming.
58+
59+
## Forging `uma_zone_t` to hijack `pfFini`
60+
61+
Once the adjacent `struct item` is corruptible, the exploit proceeds as follows:
62+
63+
1. Use leaked heap addresses to build a fake `uma_zone` structure inside a mbuf fully controlled by the guest. Populate:
64+
- `pfFini` with the PLT entry of `memcpy()`.
65+
- `pData` with the desired destination pointer (e.g. GOT entry, vtable slot, function pointer array).
66+
- `size` with the number of bytes to copy.
67+
- Optional: `pfDtor` as a second stage call (e.g. to invoke the newly-written function pointer).
68+
2. Overwrite the target mbuf's `zone` field with the pointer to the fake structure; adjust `list` pointers so freelist bookkeeping remains consistent enough to avoid crashes.
69+
3. Free the mbuf. `slirp_uma_free()` now executes `memcpy(dest=pData, src=item_data, n=size)` while the mbuf still contains guest-controlled data, yielding an arbitrary write.
70+
71+
Because the Linux VirtualBox binary is non-PIE, PLT addresses for `memcpy` and `system` are fixed and can be used directly. The guest can also stash strings such as `/bin/sh` inside another mbuf that remains referenced when the hijacked call executes.
72+
73+
## Heap grooming via fragmentation
74+
75+
Slirp's per-interface zone is 3072 chunks deep and initially carved as a contiguous array whose freelist is traversed from high addresses downward. Deterministic adjacency can be achieved by:
76+
77+
- Flooding the NAT with many `IP_MF` fragments of constant size so the reassembly code allocates predictable mbuf sequences.
78+
- Recycling specific chunks by sending fragments that time out, forcing frees back into the freelist in LIFO order.
79+
- Using knowledge of the freelist walk to place the future victim mbuf right after the mbuf that will carry the IP options overflow.
80+
81+
This grooming ensures the overflow hits the targeted `struct item` and that the fake `uma_zone` remains in-bounds of the leak primitive.
82+
83+
## From arbitrary write to host code execution
84+
85+
With the memcpy-on-free primitive:
86+
87+
1. Copy an attacker-controlled `/bin/sh` string and command buffer into a stable mbuf.
88+
2. Use the primitive to overwrite a GOT entry or indirect callsite (e.g. a function pointer inside the NAT device state) with the PLT entry of `system()`.
89+
3. Trigger the overwritten call. Because VirtualBox runs the NAT device inside the host process, the payload executes with the privileges of the user running VirtualBox, allowing a guest-to-host escape.
90+
91+
Alternative payloads include planting a miniature ROP chain in heap memory and copying its address into a frequently-invoked callback, or repointing `pfFini`/`pfDtor` themselves to chained gadgets for repeated writes.
92+
93+
## References
94+
95+
- [Thinking Outside The Box: Exploiting VirtualBox Slirp NAT Heap Corruption](https://projectzero.google/2025/12/thinking-outside-the-box.html)
96+
97+
{{#include ../../banners/hacktricks-training.md}}

0 commit comments

Comments
 (0)