Pool lookaside list confusion (BlockSize corruption)¶
Free edilmiş bir chunk'ın
POOL_HEADERyapısındakiBlockSizealanını corrupt ederek kernel'in onu yanlış lookaside / free list üzerine dosyalamasını (veya oradan servis etmesini) sağlamak; böylece küçük bir allocation'a sonradan daha büyük bir bölge dönen — ya da tam tersi — bir size confusion ortaya çıkar.
Mechanism¶
Note
Windows kernel pool, küçük ve sık kullanılan free chunk'ları, chunk'ın yuvarlanmış boyutuna göre indekslenen lookaside list'ler (per-pool-descriptor ve per-processor) üzerinde cache'ler. Boyut, POOL_HEADER.BlockSize alanında block unit cinsinden (x64'te 16 byte) tutulur. Free sırasında allocator BlockSize'ı okur, lookaside index'ini hesaplar ve chunk'ı o boyuta ait singly-linked list'e link'ler; aynı boyutta sonraki bir allocation'da chunk o list'ten unlink edilip caller'a döndürülür.
Dolayısıyla list seçimi BlockSize'a mutlak doğru gibi güvenir. Free edilmek üzere olan bir chunk'ın BlockSize'ı komşu bir overflow ya da off-by-one ile corrupt edilirse, chunk forge edilmiş boyutun list'ine dosyalanır. Bu forge edilmiş boyuta uyan sonraki bir allocation isteği chunk'ı unlink edip geri verir — ama hem caller hem de sistemin o belleğe dair geri kalan görüşü onu hâlâ gerçek boyutuyla ele alır. Sonuç bir size confusion'dır: A boyutu için yapılan istek, başka kodun B boyutunda sandığı bir chunk ile karşılanır, allocation'lar üst üste biner veya attacker'ın kontrol ettiği bir slack bırakılır. Bu, userland heap'teki "wrong-bin" reallocation'ın pool karşılığıdır.
x64'te POOL_HEADER (alttan üste) PreviousSize, PoolIndex, BlockSize (her biri block unit cinsinden küçük bir bitfield), ardından PoolType ve 4 byte'lık bir PoolTag paketler. BlockSize ile PreviousSize bitişik ve dar alanlar olduğundan, bir sonraki header'a taşan tek byte'lık/QWORD bir overflow görünen size class'ı değiştirmeye yeter — ki bu da yapıyı yaygın linear-overflow bug'larından erişilebilir kılan şeydir.
Warning
Alanların tam genişlikleri, lookaside-list'in maksimum block size'ı ve hangi path'lerin lookaside'ı, hangilerinin segment/LFH free list'lerini kullandığı Windows 7 → Windows 10/11 boyunca esaslı şekilde değişti (segment pool, kLFH). Aşağıdaki mekanizma kavramsal olarak anlatılıyor; güncel offset'lere güvenmeden önce bunlar hedef build'in symbol'lerine karşı mutlaka doğrulanmalı.
Walkthrough¶
Yapı seviyesinde akıl yürütme (Mandt'ın pool internals'ına dayanarak; temsili, build'e bağlı):
Kavramsal POOL_HEADER (x64).
// Representative layout — confirm field widths against target symbols (dt nt!_POOL_HEADER)
typedef struct _POOL_HEADER {
USHORT PreviousSize : 8; // size of previous chunk, in 16-byte blocks
USHORT PoolIndex : 8; // pool descriptor index
USHORT BlockSize : 8; // THIS chunk size, in 16-byte blocks <-- corruption target
USHORT PoolType : 8; // allocation type bits
ULONG PoolTag; // 4-char tag, e.g. 'enoN'
} POOL_HEADER;
Corruption'dan confusion'a giden dizilim.
1. Groom: place [ overflow chunk ][ victim chunk V ] adjacent (see pool-feng-shui).
2. Overflow writes into V's POOL_HEADER, changing V.BlockSize from 0x4 (0x40 bytes)
to 0x10 (0x100 bytes). <-- forged larger size class
3. Free V. The allocator reads BlockSize=0x10 and links V onto the 0x100 lookaside/free list.
4. Allocate size 0x100. The allocator unlinks V (it is on that list) and returns it,
but only 0x40 bytes were ever V's real footprint.
5. The 0x100 "allocation" overlaps whatever followed V in memory -> overlapping objects.
Size confusion sonucu (örnekleme amaçlı)
Exploit değeri overlap'ten gelir: over-sized alias üzerinden yazmak, komşu canlı object'in header'ını ya da pointer'larını corrupt eder; bu da kontrollü bir callback'e veya arbitrary write'a kadar takip edilir.
Detection¶
- Free/alloc sırasında
BlockSize'ı chunk'ın gerçek boyutuna ve bir sonraki chunk'ınPreviousSizedeğerine karşı validate et (safe-unlinking / header consistency check'leri). - Checked build'lerde lookaside/free-list integrity assert'leri; eşleşmeyen size alanlarında
BAD_POOL_HEADER/BAD_POOL_CALLERile etiketlenen bugcheck'ler.
Mitigation¶
- Pool header cookie'leri / integrity check'leri (Windows 8+), chunk relink edilmeden önce tahrif edilmiş
POOL_HEADERalanlarını tespit eder. - kLFH / segment pool randomization'ı ve out-of-line metadata, corrupt eden overflow için erişilebilir ve öngörülebilir adjacency'yi azaltır.
- Safe unlinking, list pointer'larını validate eder ve aksi halde confusion'ı izleyecek unlink primitive'ini bloklar.
See also: pool-feng-shui, non-paged-pool-overflow-exploitation, kernel-pool-overflow-from-restrictive-chunk-size, hevd-pool-buffer-overflow-scenario.