diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 2effde835b5..1b98160be56 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -892,6 +892,7 @@ - [Pixel Bigwave Bigo Job Timeout Uaf Kernel Write](binary-exploitation/linux-kernel-exploitation/pixel-bigwave-bigo-job-timeout-uaf-kernel-write.md) - [Linux kernel exploitation - toctou](binary-exploitation/linux-kernel-exploitation/posix-cpu-timers-toctou-cve-2025-38352.md) - [PS5 compromission](binary-exploitation/freebsd-ptrace-rfi-vm_map-prot_exec-bypass-ps5.md) +- [Vmware Workstation Pvscsi Lfh Escape](binary-exploitation/vmware-workstation-pvscsi-lfh-escape.md) - [Windows Exploiting (Basic Guide - OSCP lvl)](binary-exploitation/windows-exploiting-basic-guide-oscp-lvl.md) - [Windows Vectored Overloading](binary-exploitation/windows-vectored-overloading.md) - [iOS Exploiting](binary-exploitation/ios-exploiting/README.md) diff --git a/src/binary-exploitation/vmware-workstation-pvscsi-lfh-escape.md b/src/binary-exploitation/vmware-workstation-pvscsi-lfh-escape.md new file mode 100644 index 00000000000..7ed74bf72ee --- /dev/null +++ b/src/binary-exploitation/vmware-workstation-pvscsi-lfh-escape.md @@ -0,0 +1,63 @@ +# VMware Workstation PVSCSI LFH Escape (VMware-vmx on Windows 11) + +{{#include ../banners/hacktricks-training.md}} + +## Bug anatomy: fixed-size realloc + scattered OOB writes + +- `PVSCSI_FillSGI` copies guest scatter/gather entries into an internal array. It starts with a 512-entry static buffer (0x2000). Above 512 entries it reallocates to **0x4000** bytes and, because of a functional bug, **reallocates on every iteration**. +- The reallocation size never grows: 0x4000 / 0x10-byte entries = **1024 usable entries**. When the guest supplies **>1024 entries**, each new entry is written **16 bytes past the freshly allocated 0x4000 chunk**, corrupting the adjacent chunk header or object. +- Overflow content: VMware stores `{u64 addr; u64 len}`; guest provides `{u64 addr; u32 len; u32 flags}`. The 32-bit `len` is **zero-extended**, so the last dword of every 16-byte OOB element is **always 0x00000000**. + +## LFH constraints & deterministic "Ping-Pong" placement + +- 0x4000 allocations land in the **Windows 11 LFH** (16 chunks/bucket, 0x10-byte metadata with keyed checksum). Any chunk whose header checksum is hit later will terminate the process, so corrupted headers must never be reused. +- LFH returns a random free chunk, but **prefers the bucket containing the most recently freed chunk**. Force two free slots only: + 1. Allocate all free 0x4000 chunks to align the allocator; spray **32 SVGA shaders** to fill **B1** and **B2** buckets. + 2. Free B1 except one pinned shader (**Hole0**) so B1 stays active; allocate **15 URBs** into B1. + 3. Free one shader in B2 (**PONG**), then immediately free **Hole0**. LFH will alternate allocations between the two available slots **PING (B1)** and **PONG (B2)**. +- Iteration 1025 corrupts the header after PONG (never touched again); iteration 1026 hits the first 16 bytes of the URB after PING (safe metadata bypass). Reclaim PING/PONG with placeholder shaders to keep the layout stable and repeatable. + +## Reap Oracle: labeling contiguous holes + +- UHCI URBs live in a FIFO queue and are freed when fully **reaped**. The constrained 16-byte overwrite always zeroes `actual_len`, giving a marker. +- Reap URBs in order; when a zeroed `actual_len` is seen, immediately refill the freed slot with a recognisable shader. Iterating lets you map **Hole0–Hole3** as four contiguous chunks in known order for later adjacency-dependent primitives. + +## Turning constrained writes into arbitrary overwrite (coalescing abuse) + +`PVSCSI` coalesces adjacent entries using `AddrA + LenA == AddrB` and **compacts** later entries upward. + +- **Two-pass overflow:** Trigger starting at PING (odd indices) and exit early to skip coalescing; trigger again starting at PONG (even indices) to fill the gaps and continue writing into a sprayed shader containing fake S/G entries. +- **Vacuum + payload:** Set entries `[1023..2047]` to `{addr=0,len=0}` so coalescing collapses them into one, creating a logical hole. Payload entries placed afterwards (in the shader) are **moved up** into earlier memory, landing inside the victim URB. +- **Adjacency-check bypass:** By setting `LenA=0`, the condition becomes `AddrA==AddrB`. Craft pairs + ``` + {addr = X, len = 0} + {addr = X, len = Y} + ``` + so coalescing merges them into `{addr=X,len=Y}`. Even-indexed zero-size elements come from the constrained overflow; odd-indexed values live in the shader. Result: **arbitrary 16-byte patterns** despite the forced zero dword. + +## Hybrid URB infoleak via coalescing side-effects + +- Arrange contiguous chunks: `[Hole0 (free/PING), URB1 (target), URB2 (valid, actual_len=0), URB3 (leak target)]`. +- Fill URB1 with contiguous fake entries (sizes `0xFFFFFFFF`), touching URB2 minimally. Coalescing merges them into one entry; the sum `0xFFFFFFFF * 0x401` sets the upper dword at URB1’s `actual_len` offset to **0x400**. +- Compaction copies the following data **upward**, pulling **URB2’s header into URB1**. URB1 now has a valid header (pipe/list pointers), `actual_len=0x400`, and a data pointer already at the end of URB2’s buffer. +- Reaping URB1 copies 0x400 bytes starting just before URB3, yielding an **OOB read** of URB3’s header/self-references, which reveals absolute heap addresses and defeats ASLR for subsequent forged structures. + +## Post-leak primitives (no re-triggering the bug) + +- Forge a URB structure inside a shader occupying **Hole0**, then use the coalescing "move up" to replace URB1 with the forged data. +- Make the URB persistent: set `URB1.next = Hole0` and increment `refcount`; reaping URB1 puts the **Hole0-backed fake URB** at the FIFO head. Future primitives are just reallocations of Hole0 with new fake URBs. +- **Arbitrary read:** fake URB with chosen `data_ptr` and `actual_len`, then reap to copy host memory to the guest. +- **Arbitrary write (32-bit):** fake URB whose `pipe` points to controlled memory and abuse the UHCI **TDBuffer writeback** to store a chosen dword at an arbitrary address. +- **Arbitrary call:** overwrite a USB pipe callback; the host calls it with controlled data at `RCX+0x90`. Resolve `WinExec` dynamically (guest-side read of Kernel32) and pivot through a **CFG-valid gadget inside vmware-vmx** that loads args from `RCX+0x100` before dispatching to `WinExec("calc.exe")`. + +## LFH timing side-channel to learn the initial bucket offset + +- Deterministic Ping-Pong requires knowing the LFH free-chunk offset (which of 16 slots will be hit first). Use the **VMware backdoor** instruction (`inl %%dx, %%eax`) with the synchronous VMware Tools command `vmx.capability.unified_loop` and a **0x4000-byte string**, which forces **two 0x4000 allocations** per call. +- Time 8 calls (16 allocations) via `gettimeofday`; one call shows a consistent spike when the LFH creates a new bucket. Repeat with one extra allocation: if the spike stays at the same index the offset is odd, if it shifts it is even; otherwise restart due to noise. +- Caveat: `unified_loop` stores unique strings in an unfreeable list, causing **O(n) lookup overhead** and rising noise, so the side-channel must converge quickly. + +## References + +- [Synacktiv – On the clock: Escaping VMware Workstation at Pwn2Own Berlin 2025](https://www.synacktiv.com/en/publications/on-the-clock-escaping-vmware-workstation-at-pwn2own-berlin-2025.html) + +{{#include ../banners/hacktricks-training.md}} diff --git a/src/binary-exploitation/windows-vectored-overloading.md b/src/binary-exploitation/windows-vectored-overloading.md index f931c962dbd..33032facdd2 100644 --- a/src/binary-exploitation/windows-vectored-overloading.md +++ b/src/binary-exploitation/windows-vectored-overloading.md @@ -2,6 +2,13 @@ {{#include ../banners/hacktricks-training.md}} +> [!TIP] +> Looking for Windows 11 LFH heap shaping and VMware Workstation PVSCSI (vmware-vmx) escape techniques? +> +> {{#ref}} +> vmware-workstation-pvscsi-lfh-escape.md +> {{#endref}} + ## Technique overview Vectored Overloading is a **Windows PE injection primitive** that fuses classic [Module Overloading](https://github.com/hasherezade/module_overloading) with **Vectored Exception Handlers (VEHs)** and **hardware breakpoints**. Instead of patching `LoadLibrary` or writing its own loader, the adversary: