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

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

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