VMware Workstation PVSCSI LFH Escape (VMware-vmx on Windows 11)

Tip

AWS Hacking’i öğrenin ve pratik yapın:HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking’i öğrenin ve pratik yapın: HackTricks Training GCP Red Team Expert (GRTE) Azure Hacking’i öğrenin ve pratik yapın: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks'i Destekleyin

Hata anatomisi: fixed-size realloc + scattered OOB writes

  • PVSCSI_FillSGI guest scatter/gather girdilerini dahili bir diziye kopyalar. 512-entry statik bir buffer ile (0x2000) başlar. 512 girişin üstünde 0x4000 byte’a realloc eder ve fonksiyonel bir hata nedeniyle her iterasyonda yeniden realloc eder.
  • Reallocation boyutu hiç büyümez: 0x4000 / 0x10-byte entry = 1024 kullanılabilir entry. Guest >1024 entry sağladığında, her yeni entry taze allocate edilmiş 0x4000 chunk’ının 16 byte sonrasına yazılır ve bitişik chunk header veya objeyi bozar.
  • Overflow içeriği: VMware {u64 addr; u64 len} saklar; guest {u64 addr; u32 len; u32 flags} sağlar. 32-bit len zero-extended olduğu için her 16-byte OOB elementinin son dword’u her zaman 0x00000000 olur.

LFH constraints & deterministic “Ping-Pong” placement

  • 0x4000 allocasyonları Windows 11 LFH içine düşer (16 chunks/bucket, 0x10-byte metadata ile keyed checksum). Header checksum’u bozulan herhangi bir chunk daha sonra kullanılırsa process sonlanır; bu yüzden bozulmuş header’lar asla yeniden kullanılmamalıdır.
  • LFH rastgele bir free chunk döndürür, ama en son free edilmiş chunk’ı içeren bucket’ı tercih eder. Sadece iki boş slot zorlayın:
  1. Allocator’ı hizalamak için tüm boş 0x4000 chunk’ları ayırın; B1 ve B2 bucket’larını doldurmak için 32 SVGA shader spreyleyin.
  2. B1’i, bir tane sabitlenmiş shader (Hole0) dışında free edin ki B1 aktif kalsın; B1’e 15 URB allocate edin.
  3. B2’de bir shader’ı free edin (PONG), sonra hemen Hole0’ı free edin. LFH iki mevcut slot arasında tahsisleri PING (B1) ve PONG (B2) olarak dönüşümlü yapacaktır.
    1. iterasyon PONG’un hemen sonrasındaki header’ı bozar (bir daha dokunulmaz); 1026. iterasyon PING’den sonraki ilk 16 byte’ı URB içinde hedefler (metadata bypass için güvenli). Yerleşimi stabil ve tekrarlanabilir tutmak için PING/PONG’u placeholder shader’larla geri alın.

Reap Oracle: labeling contiguous holes

  • UHCI URB’leri FIFO kuyruğunda yaşar ve tamamen reaped edildiğinde free edilir. Kısıtlı 16-byte overwrite her zaman actual_len’i sıfırlar, bu da bir işaretleyici verir.
  • URB’leri sırayla reap edin; sıfırlanmış bir actual_len görüldüğünde hemen freed slot’u tanınabilir bir shader ile doldurun. İterasyonlar sayesinde daha sonra adjacency’e dayalı primitifler için Hole0–Hole3’ü bilinen sırada dört bitişik chunk olarak eşleyebilirsiniz.

Turning constrained writes into arbitrary overwrite (coalescing abuse)

PVSCSI bitişik entry’leri AddrA + LenA == AddrB kontrolü ile coalesce eder ve sonraki entry’leri yukarı doğru compact eder.

  • İki geçişli overflow: PING’den (tek indeksler) başlayarak tetikleyin ve coalescing’i atlamak için erken çıkın; PONG’dan (çift indeksler) başlayarak tekrar tetikleyin ki boşluklar doldurulsun ve fake S/G entry’leri içeren spreylənmiş bir shader’a yazma devam etsin.
  • Vacuum + payload: [1023..2047] entry’lerini {addr=0,len=0} olarak ayarlayın, böylece coalescing bunları tek bir entry içinde çökerterek mantıksal bir delik oluşturur. Daha sonra (shader içindeki) payload entry’leri yukarı doğru taşınır, kurban URB içine yerleşir.
  • Adjacency-check bypass: LenA=0 koyarak koşul AddrA==AddrB olur. Çiftleri şöyle hazırlayın:
{addr = X, len = 0}
{addr = X, len = Y}

böylece coalescing bunları {addr=X,len=Y} olarak birleştirir. Çift indeksli sıfır-boyutlu elemanlar kısıtlı overflow’dan gelir; tek indeksliler shader’da yaşar. Sonuç: zorunlu sıfır dword’a rağmen arbitrary 16-byte pattern’ler elde edilir.

Hybrid URB infoleak via coalescing side-effects

  • Bitişik chunk’ları şöyle düzenleyin: [Hole0 (free/PING), URB1 (target), URB2 (valid, actual_len=0), URB3 (leak target)].
  • URB1’i bitişik fake entry’lerle doldurun (boyutlar 0xFFFFFFFF), URB2’ye minimal dokunun. Coalescing bunları tek entry’e birleştirir; 0xFFFFFFFF * 0x401 toplamı URB1’in actual_len offset’indeki üst dword’u 0x400 yapar.
  • Compact işlemi aşağıdaki veriyi yukarı doğru kopyalarak URB2’nin header’ını URB1 içine çeker. URB1 şimdi geçerli bir header’a (pipe/list pointer’ları), actual_len=0x400’e ve URB2 buffer’ının sonuna işaret eden bir data pointer’a sahip olur.
  • URB1’i reap etmek URB3’ten hemen önce başlayan 0x400 byte kopyalanmasına yol açar ve URB3’ün header/self-referanslarının OOB okunmasını sağlar; bu da mutlak heap adreslerini açığa çıkarır ve sonraki sahte yapıların ASLR’ını bozar.

Post-leak primitives (no re-triggering the bug)

  • Hole0 içinde yer alan bir shader’a sahte bir URB yapısı forge edin, sonra coalescing “move up” ile URB1’i bu forge edilmiş veriyle değiştirin.
  • URB’yi persistent yapın: URB1.next = Hole0 koyun ve refcount’u artırın; URB1’i reap etmek Hole0 destekli sahte URB’yi FIFO başına getirir. Gelecek primitifler sadece Hole0’ın yeni sahte URB’lerle yeniden allocate edilmesidir.
  • Arbitrary read: seçilen data_ptr ve actual_len ile sahte URB; sonra reap ile host belleğini guest’e kopyalayın.
  • Arbitrary write (32-bit): pipe’ı kontrollü belleğe işaret eden sahte URB ve UHCI TDBuffer writeback’i suistimal ederek seçilmiş bir dword’u rastgele bir adrese yazdırın.
  • Arbitrary call: bir USB pipe callback’i overwrite edin; host bunu RCX+0x90’da kontrollü veri ile çağırır. WinExec’i dinamik olarak çözün (guest tarafında Kernel32 okuması) ve argümanları RCX+0x100’den yükleyen ve ardından WinExec("calc.exe")’ye yönlendiren vmware-vmx içindeki CFG-valid gadget üzerinden pivot yapın.

LFH timing side-channel to learn the initial bucket offset

  • Deterministik Ping-Pong için LFH free-chunk offset’ini (16 slottan hangisinin önce vurulacağı) bilmek gerekir. Senkron VMware Tools komutu vmx.capability.unified_loop ile VMware backdoor instruction (inl %%dx, %%eax) kullanın ve 0x4000-byte string gönderin; bu çağrı başına iki 0x4000 allocasyon zorlar.
  • gettimeofday ile 8 çağrıyı (16 allocasyon) zamanlayın; LFH yeni bir bucket oluşturduğunda tek bir çağrı tutarlı bir spike gösterir. Bir ekstra allocation ile tekrar edin: spike aynı indekste kalıyorsa offset tek (odd), kayıyorsa çift (even); aksi takdirde gürültü nedeniyle yeniden başlayın.
  • Uyarı: unified_loop benzersiz string’leri free edilemeyen bir listede saklar, bu da O(n) lookup overhead ve artan gürültüye sebep olur; bu yüzden side-channel hızlıca yakınsamalıdır.

References

Tip

AWS Hacking’i öğrenin ve pratik yapın:HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking’i öğrenin ve pratik yapın: HackTricks Training GCP Red Team Expert (GRTE) Azure Hacking’i öğrenin ve pratik yapın: HackTricks Training Azure Red Team Expert (AzRTE)

HackTricks'i Destekleyin