VMware Workstation PVSCSI LFH Escape (VMware-vmx on Windows 11)
Tip
Ucz się i ćwicz Hacking AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz Hacking GCP:HackTricks Training GCP Red Team Expert (GRTE)
Ucz się i ćwicz Hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Wsparcie dla HackTricks
- Sprawdź plany subskrypcyjne!
- Dołącz do 💬 grupy Discord lub grupy telegramowej lub śledź nas na Twitterze 🐦 @hacktricks_live.
- Dziel się trikami hackingowymi, przesyłając PR-y do HackTricks i HackTricks Cloud repozytoriów na githubie.
Bug anatomy: fixed-size realloc + scattered OOB writes
PVSCSI_FillSGIkopiuje guest scatter/gather entries do wewnętrznej tablicy. Zaczyna od statycznego bufora na 512 wpisów (0x2000). Powyżej 512 wpisów wykonuje realloc do 0x4000 bajtów i, z powodu błędu funkcjonalnego, wywołuje realloc przy każdej iteracji.- Rozmiar realokacji nigdy nie rośnie: 0x4000 / 0x10‑bajtowych wpisów = 1024 użyteczne wpisy. Gdy guest dostarczy >1024 wpisów, każdy nowy wpis jest zapisywany 16 bajtów poza świeżo zaalokowanym chunkiem 0x4000, uszkadzając nagłówek sąsiedniego chunku lub obiekt.
- Zawartość overflowu: VMware przechowuje
{u64 addr; u64 len}; guest dostarcza{u64 addr; u32 len; u32 flags}. 32‑bitowylenjest zero‑rozszerzany, więc ostatni dword każdego 16‑bajtowego OOB elementu jest zawsze 0x00000000.
LFH constraints & deterministic “Ping-Pong” placement
- Alokacje 0x4000 trafiają do Windows 11 LFH (16 chunks/bucket, 0x10‑bajtowe metadata z keyed checksum). Każdy chunk, którego checksum nagłówka zostanie później naruszony, zakończy proces, więc uszkodzone nagłówki nie mogą być nigdy ponownie użyte.
- LFH zwraca losowy wolny chunk, ale faworyzuje bucket zawierający najświeżej zwolniony chunk. Wymuś tylko dwa wolne sloty:
- Zaalokuj wszystkie wolne chunki 0x4000, by wyalignować allocator; sprayiuj 32 SVGA shaders aby wypełnić buckety B1 i B2.
- Zwolnij B1 poza jednym przypiętym shaderem (Hole0), żeby B1 pozostał aktywny; zaalokuj 15 URBs do B1.
- Zwolnij jeden shader w B2 (PONG), a następnie natychmiast zwolnij Hole0. LFH będzie na przemian alokować między dwoma dostępnymi slotami PING (B1) i PONG (B2).
- Iteracja 1025 uszkadza nagłówek za PONG (nigdy już nieużywany); iteracja 1026 trafia w pierwsze 16 bajtów URB za PING (bezpieczne obejście metadata). Odbuduj PING/PONG placeholderowymi shaderami, by utrzymać stabilny i powtarzalny layout.
Reap Oracle: labeling contiguous holes
- UHCI URBs żyją w kolejce FIFO i są zwalniane gdy są w pełni reaped. Ograniczony 16‑bajtowy overwrite zawsze zeruje
actual_len, co daje znacznik. - Reapuj URBy w kolejności; gdy zobaczysz zzerowane
actual_len, natychmiast wypełnij zwolnione miejsce rozpoznawalnym shaderem. Iteracja pozwala namapować Hole0–Hole3 jako cztery sąsiednie chunki w znanym porządku do późniejszych prymitywów zależnych od sąsiedztwa.
Turning constrained writes into arbitrary overwrite (coalescing abuse)
PVSCSI łączy (coalesces) sąsiednie wpisy używając warunku AddrA + LenA == AddrB i kompaktuje późniejsze wpisy w górę.
- Two-pass overflow: Wywołaj błąd zaczynając od PING (nieparzyste indeksy) i wyjdź wcześnie, aby pominąć coalescing; wywołaj ponownie zaczynając od PONG (parzyste indeksy) aby zapełnić luki i kontynuować zapis do sprejowanego shaderu zawierającego fałszywe S/G wpisy.
- Vacuum + payload: Ustaw wpisy
[1023..2047]na{addr=0,len=0}, tak aby coalescing zwinął je w jeden, tworząc logiczną dziurę. Wpisy payloadu umieszczone później (w shaderze) są przenoszone w górę do wcześniejszej pamięci, lądując wewnątrz ofiary URB. - Adjacency-check bypass: Ustawiając
LenA=0warunek staje sięAddrA==AddrB. Skomponuj pary
{addr = X, len = 0}
{addr = X, len = Y}
tak aby coalescing scalił je w {addr=X,len=Y}. Elementy o parzystych indeksach o zerowym rozmiarze pochodzą z ograniczonego overflowu; nieparzyste wartości żyją w shaderze. Efekt: dowolne 16‑bajtowe wzorce mimo wymuszonego zerowego dworda.
Hybrid URB infoleak via coalescing side-effects
- Ułóż sąsiednie chunki:
[Hole0 (free/PING), URB1 (target), URB2 (valid, actual_len=0), URB3 (leak target)]. - Wypełnij URB1 kontynuuującymi się fałszywymi wpisami (rozmiary
0xFFFFFFFF), dotykając URB2 minimalnie. Coalescing scala je w jeden wpis; suma0xFFFFFFFF * 0x401ustawia górny dword na offsetcieactual_lenURB1 na 0x400. - Kompaktowanie kopiuje następujące dane w górę, przeciągając nagłówek URB2 do URB1. URB1 ma teraz poprawny nagłówek (pipe/list pointers),
actual_len=0x400i wskaźnik danych już na końcu bufora URB2. - Reaping URB1 kopiuje 0x400 bajtów zaczynając tuż przed URB3, dając OOB read nagłówka/self‑referencji URB3, co ujawnia absolutne adresy heapu i łamie ASLR dla następnych sfałszowanych struktur.
Post-leak primitives (no re-triggering the bug)
- Sfałszuj strukturę URB wewnątrz shaderu zajmującego Hole0, następnie użyj coalescingowego “przeniesienia w górę” aby zastąpić URB1 sfałszowanymi danymi.
- Utrwal URB: ustaw
URB1.next = Hole0i zwiększrefcount; reaping URB1 umieszcza Hole0‑backed fake URB na głowie FIFO. Przyszłe prymitywy to już tylko realokacje Hole0 z nowymi fake URBami. - Arbitrary read: sfałszowany URB z wybranym
data_ptriactual_len, potem reap aby skopiować pamięć hosta do guest. - Arbitrary write (32-bit): sfałszowany URB którego
pipewskazuje na kontrolowaną pamięć i nadużycie UHCI TDBuffer writeback, by zapisać wybrany dword pod arbitralnym adresem. - Arbitrary call: nadpisanie callbacka USB pipe; host wywoła go z kontrolowanymi danymi w
RCX+0x90. RozwiążWinExecdynamicznie (guest‑side odczyt Kernel32) i pivotuj przez CFG‑valid gadget w vmware-vmx który ładuje argumenty zRCX+0x100przed dispatchem doWinExec("calc.exe").
LFH timing side-channel to learn the initial bucket offset
- Deterministyczne Ping‑Pong wymaga poznania offsetu wolnego chunku w LFH (który z 16 slotów będzie trafiony pierwszy). Użyj VMware backdoor instrukcji (
inl %%dx, %%eax) z synchroniczną komendą VMware Toolsvmx.capability.unified_loopi 0x4000‑bajtowym stringiem, co wymusza dwie alokacje 0x4000 na wywołanie. - Mierz czas 8 wywołań (16 alokacji) przez
gettimeofday; jedno wywołanie pokaże spójny spike gdy LFH tworzy nowy bucket. Powtórz z jedną dodatkową alokacją: jeśli spike zostanie na tym samym indeksie offset jest nieparzysty, jeśli przesunie się — parzysty; w przeciwnym razie restartuj ze względu na szum. - Uwaga:
unified_loopprzechowuje unikalne stringi w liście niezwalnialnej, powodując O(n) lookup overhead i rosnący szum, więc side‑channel musi zbiec się szybko.
References
Tip
Ucz się i ćwicz Hacking AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz Hacking GCP:HackTricks Training GCP Red Team Expert (GRTE)
Ucz się i ćwicz Hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Wsparcie dla HackTricks
- Sprawdź plany subskrypcyjne!
- Dołącz do 💬 grupy Discord lub grupy telegramowej lub śledź nas na Twitterze 🐦 @hacktricks_live.
- Dziel się trikami hackingowymi, przesyłając PR-y do HackTricks i HackTricks Cloud repozytoriów na githubie.


