Skip to content

Win32k user-mode callback abuse (KeUserModeCallback r0->r3)

Kernel'den user mode'a geri çağrı yapan meşru win32k mekanizması (KeUserModeCallback / KernelCallbackTable), xxxClient* callback'lerini intercept etmek ve syscall'ın ortasında kernel state'ini mutate etmek için abuse ediliyor.

Mechanism

Invariant: kernel state re-entrant bir sınır boyunca tutarlı kalmalı

win32k bir syscall'ın ortasında sık sık user mode'a geri çağrı yapmak zorunda kalır — application hook'larını çalıştırmak, window class extra byte'larını allocate etmek, paint etmek vb. için. Bunu KeUserModeCallback üzerinden yapar; bu da user mode'daki KiUserCallbackDispatcher aracılığıyla pointer'ı PEB'de duran bir function table'a dispatch eder (PEB.KernelCallbackTable, yani USER32'nin apfnDispatch'i) ve bir ApiNumber ile index'lenir.

Sınırın kendisi bir bug değil — tasarım gereği böyle. Tehlike şu: callback'i tetikleyen kernel routine'i çoğu zaman zaten pointer'ları, flag'leri ya da object reference'larını capture etmiş durumdadır ve callback geri döndüğünde bunların hâlâ geçerli olduğunu varsayar. Callback attacker'ın kontrol ettiği user code'u çalıştırdığı için, attacker win32k'ya yeniden girebilir (bir window'u free etmek, bir object'in type/flag'ini değiştirmek, extra byte'ları resize etmek vb.) ve böylece kernel'in cache'lediği varsayımlar stale hale gelir. Bu re-entrancy, koca bir win32k LPE ailesinin ("smash-the-ref" UAF'leri, type/flag desync bug'ları) kök kolaylaştırıcısıdır.

Walkthrough

Kavramsal; public analizlerden derlenmiştir (j00ru, Mandt BH US 2011, CVE-2021-1732 writeup'ları):

  1. user32.dll'i load et ki process'in PEB'inde initialize edilmiş bir KernelCallbackTable olsun.
  2. Bir callback slot'unu hook'la: hedeflenen xxxClient* dispatch'i için PEB.KernelCallbackTable içindeki entry'yi overwrite et (ya da shadow'la) (örn. window oluşturma sırasında çağrılan routine), onu attacker code'una yönlendir.
  3. O callback'i gerçekleştiren bir win32k operasyonunu tetikle (bir window oluşturmak, bir message işlemek vb.). Execution r0 -> r3 geçişiyle hook'a girer.
  4. Hook'un içinde, kernel'in gördüğü state'i mutate et: inşa edilmekte olan object'i free et veya reallocate et, başka bir syscall üzerinden bir type/length flag'ini flip'le, ya da kernel'in hâlâ reference ettiği bir buffer'ı küçült/büyüt.
  5. NtCallbackReturn ile geri dön (isteğe bağlı olarak kontrollü bir return değeri vererek). Kernel, artık stale olan state'e güvenerek devam eder; bu da bir OOB write, UAF ya da type confusion doğurur.
Desync neden önemli (şematik)
kernel: capture ptr P / flag F   --->  KeUserModeCallback (r0->r3)
                                        attacker hook: free(P) or set F'
kernel: <-- NtCallbackReturn      <---  resumes using P / F  (now stale)

Detection

  • PEB callback table üzerindeki telemetry: kendi KernelCallbackTable bölgesine yazan / onu remap eden, ya da entry'leri user32.dll dışına yönlendiren bir user process son derece anormaldir ve güçlü bir hunting sinyalidir.
  • Tek bir thread'in, bir window-management syscall'ının derinlerindeyken, bir callback penceresi sırasında object-mutating çağrılarla (NtUserConsoleControl, NtUserSetWindowLongPtr, DestroyWindow) win32k'ya yeniden girdiği diziler.
  • Olağandışı/büyük return değerleriyle sık görülen NtCallbackReturn'lerin, ardından gelen out-of-bounds davranış veya bugcheck'lerle korele olması.
  • Post-exploitation: düşük yetkili bir process'in, yoğun GDI/USER syscall aktivitesinin hemen ardından SYSTEM token'a geçiş yapması.

Mitigation

  • Win32k system-call filtering (process-mitigation policy ProcessSystemCallDisablePolicy): GDI/USER'a hiç ihtiyaç duymayan process'ler için (birçok browser ve sandboxed renderer), bu win32k surface'ini — dolayısıyla callback surface'ini — tamamen kaldırır.
  • Microsoft, callback'leri kademeli olarak sertleştirdi: pre-callback capture'larına güvenmek yerine callback geri döndükten sonra object state'ini yeniden valide ederek (bu bug sınıfı için standart patch şekli, örn. CVE-2021-1732 / CVE-2022-21882).
  • win32k patch'lerini güncel tut; callback'ten erişilebilir herhangi bir type/flag handling'ini en yüksek riskli surface olarak değerlendir.
  • Defence-in-depth: HVCI/VBS, SMEP (bir callback abuse edilse bile kernel'in user page'leri çalıştırmasını engeller) ve pool hardening.

References

See also