Non-paged pool overflow exploitation (POOL_HEADER + object spray)¶
NonPagedPoolNx allocation'ında lineer bir out-of-bounds write, komşu pool chunk'ına taşar; onun
_POOL_HEADER'ını ve groom'lanmış bir victim object'i corrupt eder, ardından bu arbitrary read/write ve SYSTEM'e çevrilir.
Mechanism¶
Note
Her Windows kernel pool chunk'ının başında bir _POOL_HEADER bulunur. Lineer bir
overflow'un uyması gereken invariant şudur: bir chunk free edildiğinde _POOL_HEADER'ı
hâlâ valid olmalıdır — "when a _POOL_HEADER structure is freed and it isn't a valid
header, a system crash will occur." Yani overflow önce bir sonraki chunk'ın header'ına,
sonra data'sına iner; attacker header'ı hâlâ validate olan bir değerle yeniden yazmak
zorundadır.
_POOL_HEADER (x64, 0x10 byte, kLFH bucket'ını seçen allocation size'a dâhil olur)
PreviousSize/PoolIndex/BlockSize/PoolType, bir PoolTag (örn. "Hack") ve offset 0x8'de bir
union paketler — ProcessBilled (quota allocation yapan _EPROCESS) ile
AllocatorBackTraceIndex/PoolTagHash üst üste biner.
Win10 19H1+ üzerinde segment heap / kLFH sabit boyutlu bucket'lara hizmet verir; bu allocator'a karşı genel strateji (allocator metadata'sını corrupt etmek yerine bitişik bir victim object'i corrupt etmek) Bayet & Fariello'nun "Scoop the Windows 10 Pool!" çalışmasında formüle edilmiştir. İki özellik overflow'u pratik kılar:
- kLFH chunk'ları unencoded bir
_POOL_HEADERtutar (Variable-Size segment chunk'larının_HEAP_VS_CHUNK_HEADER'ının aksine XOR cookie yoktur), böylece attacker header'ı birebir hardcode edip tekrar üretebilir (örn. 16 byte'lık0x6b63614802020000değeri). - kLFH coalesce yapmaz, dolayısıyla layout öngörülebilirdir — ama bucket önce activate edilmelidir (~16–17 ardışık aynı boyutta request).
Bir overflow sadece aynı bucket içinde tam olarak aynı boyutta bir chunk'a ulaşabildiği
için grooming VULN | VICTIM | VULN | VICTIM şeklinde bir layout'a zorlar.
Walkthrough¶
İki tane public, reproduce edilebilir recipe (HEVD tabanlı):
Connor McGarr — ARW helper object
- ~5.000 helper object spray et; aynı boyutta gap açmak için her ikincisini free et
(örn. defrag filler olarak
CreateEventAobject'leri). - Komşu chunk'ın
_POOL_HEADER'ını aynı valid hardcoded değerle overflow et ki sonraki free crash etmesin. - Komşu 16 byte'lık helper object'in
Namepointer'ını corrupt et; iki object'lik bir indirection arbitrary read/write, ardından SYSTEM verir.
insideyourkernel — NP_DATA_QUEUE_ENTRY (Win11 x64)
- ~10.000 named-pipe queue entry groom et; gap delmek için son 5.000 içinde ~her 64'üncüsünü free et.
- Overflow, komşu bir
NP_DATA_QUEUE_ENTRY'ninDataSize'ını 512 yapar veFlink'ini kontrollü birSystemBuffer'a sahip userland IRP'ye referans veren bir userland queue entry'ye yönlendirir → arbitrary read.
Data-only / header-only yol: komşu header'ı PoolType, PoolQuota flag'ini taşıyacak
şekilde corrupt et ve ProcessBilled'i overwrite et; free sırasında kernel,
attacker'ın kontrol ettiği pointer üzerinden dereference/decrement yapar — explicit bir
victim object olmadan privilege escalation için EPROCESS.Token'ı decrement etmekte
kullanılabilir.
Warning
Overflow sadece aynı bucket içindeki aynı boyutta chunk'lara ulaşır, dolayısıyla reliability corruption'ın kendisinde değil grooming'de yaşar ya da ölür (bucket activation + defrag filler'lar + gap punching).
Detection¶
- Special Pool / Verifier, OOB write'ları ve free sırasında invalid
_POOL_HEADER'ı yakalar. BAD_POOL_HEADER(0x19) /BAD_POOL_CALLER(0xC2) bugcheck'leri çoğu zaman başarısız bir overflow'un ardından gelir.
Mitigation¶
- Segment-heap metadata korumaları: Variable-Size chunk'larındaki encoded
_HEAP_VS_CHUNK_HEADERcookie'leri çıtayı yükseltir (kLFH header'ları unencoded kalır, bu yüzden odak kLFH boyutlu overflow'lardadır). - kCFG / kernel CFI, naif function-pointer hijack'lerini engeller ve attacker'ları data-only
ProcessBilled/token tekniklerine doğru iter.
References¶
- Connor McGarr — Swimming in the (Kernel) Pool, Part 1
- Connor McGarr — Swimming in the (Kernel) Pool, Part 2
- insideyourkernel — Windows 11 x64 Kernel Exploitation: NonPaged Pool Overflow using HEVD (Part 1, Arbitrary Read)
- Scoop the Windows 10 Pool! — Corentin Bayet & Paul Fariello, SSTIC 2020 (paper)
- LFH Kernel Pool Allocator Challenges the Incumbent — OSR