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

Bug anatomy: fixed-size realloc + scattered OOB writes

  • PVSCSI_FillSGI kopiuje 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‑bitowy len jest 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:
    1. Zaalokuj wszystkie wolne chunki 0x4000, by wyalignować allocator; sprayiuj 32 SVGA shaders aby wypełnić buckety B1 i B2.
    2. Zwolnij B1 poza jednym przypiętym shaderem (Hole0), żeby B1 pozostał aktywny; zaalokuj 15 URBs do B1.
    3. 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=0 warunek 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; suma 0xFFFFFFFF * 0x401 ustawia górny dword na offsetcie actual_len URB1 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=0x400 i 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 = Hole0 i zwiększ refcount; 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_ptr i actual_len, potem reap aby skopiować pamięć hosta do guest.
  • Arbitrary write (32-bit): sfałszowany URB którego pipe wskazuje 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ąż WinExec dynamicznie (guest‑side odczyt Kernel32) i pivotuj przez CFG‑valid gadget w vmware-vmx który ładuje argumenty z RCX+0x100 przed dispatchem do WinExec("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 Tools vmx.capability.unified_loop i 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_loop przechowuje 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