VMware Workstation PVSCSI LFH Escape (VMware-vmx on Windows 11)
Tip
Learn & practice AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Learn & practice GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Learn & practice Az Hacking:HackTricks Training Azure Red Team Expert (AzRTE)
Support HackTricks
- Check the subscription plans!
- Join the 💬 Discord group or the telegram group or follow us on Twitter 🐦 @hacktricks_live.
- Share hacking tricks by submitting PRs to the HackTricks and HackTricks Cloud github repos.
Bug anatomy: fixed-size realloc + scattered OOB writes
PVSCSI_FillSGIcopies 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-bitlenis 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:
- Allocate all free 0x4000 chunks to align the allocator; spray 32 SVGA shaders to fill B1 and B2 buckets.
- Free B1 except one pinned shader (Hole0) so B1 stays active; allocate 15 URBs into B1.
- 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_lenis 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 becomesAddrA==AddrB. Craft pairs
so coalescing merges them into{addr = X, len = 0} {addr = X, len = Y}{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 sum0xFFFFFFFF * 0x401sets the upper dword at URB1’sactual_lenoffset 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 = Hole0and incrementrefcount; 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_ptrandactual_len, then reap to copy host memory to the guest. - Arbitrary write (32-bit): fake URB whose
pipepoints 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. ResolveWinExecdynamically (guest-side read of Kernel32) and pivot through a CFG-valid gadget inside vmware-vmx that loads args fromRCX+0x100before dispatching toWinExec("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 commandvmx.capability.unified_loopand 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_loopstores unique strings in an unfreeable list, causing O(n) lookup overhead and rising noise, so the side-channel must converge quickly.
References
Tip
Learn & practice AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Learn & practice GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Learn & practice Az Hacking:HackTricks Training Azure Red Team Expert (AzRTE)
Support HackTricks
- Check the subscription plans!
- Join the 💬 Discord group or the telegram group or follow us on Twitter 🐦 @hacktricks_live.
- Share hacking tricks by submitting PRs to the HackTricks and HackTricks Cloud github repos.


