Null-byte overflow¶
Komşu bir object'in size/length metadata'sına yapılan tek byte'lık (çoğunlukla NUL) off-by-one write, allocator'ın chunk sınırlarına dair görüşünü bozar; bu da overlapping allocation'lar ve arbitrary read/write primitive üretir.
Mechanism¶
Note
Allocator'lar bir buffer'ın hemen ardından gelen size/length field'ına güvenir. buf[len-1]'de
durmak yerine buf[len]'e yazan bir loop, ya da sona terminating '\0''ı bir byte ileri ekleyen
bir string rutini, sonraki object'in metadata'sının ilk byte'ını overwrite eder. Little-endian
size field'ları en anlamlı byte'larını daha yüksek adreslerde tuttuğu için, en düşük byte'ı
0x00 ile clobber etmek bir size'ı yalnızca küçültür (örn. 0x511 -> 0x500) — allocator'ın
reddetmediği, küçük ve "makul" görünen bir corruption. Bunun sonucunda allocator, bir chunk'ın
nerede bitip diğerinin nerede başladığı konusunda gerçekle çelişir.
Kırılan invariant şu: bir chunk'ın kayıtlı size'ı, sonraki chunk'ın header'ına olan boşlukla eşleşmeli. Poison'lanmış bir null byte bunu sessizce ihlal eder, dolayısıyla sonraki bir free/coalesce hâlâ kullanımda olan memory'yi merge eder ve overlapping chunk'lar üretir.
Walkthrough¶
Klasik userland örneği shellphish'in how2heap poison_null_byte'ıdır (glibc). Şekli, özüne
indirgenmiş hâliyle:
- Henüz hiçbir şey consolidate olmasın diye
prev,victimve bir barrier chunk olmak üzere komşu chunk'lar allocate et. - Forge edilmiş bir "previous chunk"a erişilebilir olsun diye unsorted/large bin'leri kuracak şekilde free/relink yap.
prev'in size'ını0x10kadar küçült ve boşluğu köprülemek için sonraki header'ınprev_size'ını ayarla:
victim'i free etmek, forge edilmiş previous chunk'a karşı backward consolidation'ı tetikler.fd/bkgroom edildiği için unlink check geçer; böylece glibc büyük bir region'ı unsorted bin'e merge eder.- Ardından gelen iki
mallocartık overlapping pointer'lar döndürür — birinden write yapmak diğerinin içeriğini düzenler (ve dolayısıyla oraya denk gelen herhangi bir hassas pointer'ı da).
how2heap expected outcome
Kernel'de aynı primitive slab object'lerine de uygulanır: bir kmalloc-N object'inin sonundan
taşan bir-byte'lık overflow, komşu object'in ilk byte'larına denk gelir. O komşu bir length/count
field ile başlıyorsa (elastik object'ler, msg_msg vb. için yaygın), bu field'ı küçültmek veya
sıfırlamak sonraki read/write'ları desenkronize eder; uygun bir heap grooming sonrası komşu victim
object'lere overlapping ya da oversized erişim verir.
Warning
Modern glibc (>= 2.29) chunksize(p) != prev_size (next_chunk) ve unlink integrity check'leri
ekledi, dolayısıyla naive poison-null-byte başarısız olur; çalışan sürümler bunları sağlamak için
bin pointer'larını önceden hazırlar (glibc'ye özgü how2heap varyantlarına bakın). Kernel'de
hardened freelist check'leri ve CONFIG_SLAB_FREELIST_HARDENED benzer şekilde hangi komşu field'ın
corrupt edilmesinin güvenli olduğunu kısıtlar.
Detection¶
ASan/KASAN bir-byte'lık OOB write'ı doğrudan işaretler. Allocator integrity assertion'ları
(malloc(): corrupted ..., slab redzone/poison uyuşmazlıkları) bir sonraki free'deki desync'te
tetiklenir.
Mitigation¶
- Loop/copy'yi bounds açısından düzelt (off-by-one kök nedendir); length-aware string API'leri kullan.
- Heap hardening: glibc unlink/size check'leri,
CONFIG_SLAB_FREELIST_HARDENED, redzone'lar ve randomize edilmiş freelist'ler (bkz. freelist poisoning) maliyeti yükseltir.