tagWND.cbWndExtra arbitrary write primitive¶
Bir window'un
tagWND.cbWndExtra'sını ("extra bytes" length'i) corrupt et, böyleceSetWindowLongPtrobject'in ötesine, kernel desktop heap'ine yazsın; sınırlı bir window field'ını controlled bir relative/arbitrary write'a çevirerek (CVE-2021-1732'nin çekirdeği).
Mechanism¶
Note
Her window object'i (tagWND), class-tanımlı bir blok extra bytes taşıyabilir; length
tagWND.cbWndExtra'da yaşar ve veri, kernel'in cbWndExtra'ya karşı bounds-check ettiği,
caller'ın seçtiği bir offset'te SetWindowLongPtr/GetWindowLongPtr ile erişilebilir.
Korunan invariant şudur: offset, object'in kendi extra-bytes bölgesinin içinde kalır.
CVE-2021-1732 bunu, bir user-mode callback sırasında bir flag'i field'dan desync ederek
kırar. win32kfull!xxxCreateWindowEx, xxxClientAllocWindowClassExtraBytes üzerinden user
mode'a callback yaptığında, attacker window'u bir console window'a çevirmek için
NtUserConsoleControl'ı çağırır — bu da bir flag set eder (örn. dwExtraFlag'te 0x800),
böylece pExtraBytes bir user-mode pointer yerine bir kernel desktop heap offset olarak
yorumlanır — ve ardından NtCallbackReturn, flag set kalırken extra-bytes field'ına düşen
bir attacker değeri döndürür. Sonuç: cbWndExtra (ya da offset mekanizması) artık
attacker-etkili'dir ve sonraki bir SetWindowLongPtr, victim object'in ötesindeki kernel
desktop-heap belleğine yazar.
Bu, bir state-desync win32k callback bug'ından desktop heap üzerinde generic bir
write-what-where'e giden köprüdür; orada komşu tagWND object'leri hassas biçimde
yerleştirilebilir.
Walkthrough¶
Public CVE-2021-1732 analizlerinden (Unit 42, iamelli0t) kavramsal yeniden üretim. Yalnızca mantıksal adımlar ve fragment seviyesi:
- Desktop heap'i groom et, böylece bir victim window'un extra bytes'ı, field'larını kontrol etmek istediğin bir manager window'un bitişiğinde dursun.
- Alloc callback'ini hook et:
xxxClientAllocWindowClassExtraBytesCreateWindowExsırasında senin kodunu callback edecek şekilde register ol. - Flag vs. field'ı desync et: callback içinde console flag'ini set etmek için
NtUserConsoleControl'ı çağır, sonra arbitrary bir değerNtCallbackReturnet — kernel onu extra-bytes field'ına yazar ama flag'i temizlemez.
xxxCreateWindowEx
-> xxxClientAllocWindowClassExtraBytes (user-mode callback)
NtUserConsoleControl(...) // flag now says "offset is kernel heap"
NtCallbackReturn(value) // value lands in tagWND, flag still set
<- kernel resumes with desynced state
- Write penceresini büyüt:
cbWndExtraetkin olarak oversized iken, victim üzerindeSetWindowLongPtrbitişik window'untagWND'sine yazar (örn. onuncbWndExtra'sını overwrite eder), bir relative write verir ve bu sonra arbitrary write'a pivot edilir.
Bir arbitrary read ile eşleştirme
Exploit'ler genelde controlled bir window'un extra bytes'ında fake bir spmenu (menu)
forge eder ve GetMenuBarInfo'yu çağırır; bu da kernel'in fake menu'yü dereference edip
veri döndürmesine neden olur — write'ı tamamlayan bir arbitrary read. Farklı bir
object'ten kurulu benzer bir read/write eşleştirmesi için bkz.
GDI bitmap arbitrary R/W primitive.
Altta yatan kusur bir win32k user-mode callback abuse state desync'idir; yakından ilişkili offset confusion, win32k consolecontrol offset confusion içinde görülür.
Detection¶
- Class-extra-bytes alloc callback'ini hook eden ve non-console, low-integrity bir
context'ten
CreateWindowExsırasındaNtUserConsoleControl'ı çağıran bir process, güçlü bir davranışsal sinyaldir. - Bir window'un declare ettiği
cbWndExtra'da veya ötesinde anormalSetWindowLongPtroffset'leri. - Cross-object
tagWNDwrite'larını yakalayan Driver Verifier / desktop-heap consistency check'leri; corrupt komşucbWndExtrailewin32kfullwindow-field path'lerindeki bugcheck'ler.
Mitigation¶
- Patch: Microsoft,
xxxCreateWindowEx'teki flag/field desync'ini düzeltti; CVE-2021-1732 update'inin (ve ilgili CVE-2022-21882 regression fix'inin) kurulu olduğundan emin ol. - Type isolation: win32k type isolation, window object'lerini dedicated pool'lara ayırır ve adjacency grooming'i engeller. Bkz. win32k type isolation mitigation.
- Surface azaltma: sandbox'lı process'ler için win32k syscall filtering, çağrı surface'ini kaldırır; KASLR/kCFG post-primitive maliyeti artırır.