ptmalloc consolidation abuse¶
glibc'in
malloc_consolidate()rutinini attacker-chosen bir anda fastbin chunk'larını unsorted bin'e (veya top'a) merge etmeye zorlamak; bu sayede fastbin invariant'larını kırıp double-free, overlap veya libc leak kurmak.
Mechanism¶
glibc'in ptmalloc'u, yakın zamanda free edilmiş küçük chunk'ları hız için
singly-linked fastbins içinde tutar ve coalescing'lerini erteler.
malloc_consolidate(), bu ertelenmiş fastbin'leri sonradan boşaltan rutindir:
her fastbin'i dolaşır ve her chunk için in-use bit'i temizler, komşu free
chunk'larla backward/forward merge eder ve sonucu doubly-linked unsorted bin'e
taşır (ya da top chunk'a merge eder). Çalıştıktan sonra fastbinY array girdisi
NULL'a reset edilir.
Note
Exploit edilebilir özellik consolidation'ın ne yaptığı kadar ne zaman
tetiklendiğidir. Bir chunk'ın muhasebesi consolidate edildiği an değişir:
"bir fastbin'de, in-use bit set, singly linked" durumundan "unsorted bin'de,
free, doubly linked" durumuna geçer. Bir pointer'ı ya da bir free-list
varsayımını consolidation'dan önce donduran kod artık yanlıştır.
malloc_consolidate() (glibc internals'a göre) birkaç yerde tetiklenir,
özellikle: _int_malloc bir large-bin boyutunda request servis ederken;
_int_malloc hiçbir bin request'i karşılayamadığında ve top chunk çok
küçük olduğunda; _int_free free edilen chunk'ın boyutu
>= FASTBIN_CONSOLIDATION_THRESHOLD (0x10000 / 65536) olduğunda; ve
koşulsuz olarak malloc_trim() ile mallopt() içinde. Allocation boyutlarını
kontrol eden bir attacker bu yüzden consolidation'ı talep üzerine çağırabilir
— en basitiyle tek bir büyük malloc ile — ve sebep olduğu state transition'ı
silaha dönüştürebilir.
İki kazanç öne çıkar. İlki, fastbin double-free check'ini bypass etmek: bir
fastbin'e free edilmiş chunk hâlâ kendi in-use bit'ini taşır; consolidation bunu
temizleyip chunk'ı unsorted bin'e taşır, böylece aynı pointer'ı tekrar free
etmek artık "double free or corruption (fasttop)" guard'ına takılmaz — sonuç bir
duplicate chunk olur. İkincisi, bir libc leak / write target: fastbin
chunk'ları yalnızca ileri bir heap pointer saklar, ama doubly-linked unsorted
bin'e consolidate edildiğinde bir chunk'ın fd/bk alanları main_arena'ya
(libc) işaret eder, dolayısıyla bir read-after-free artık sadece bir heap adresi
değil bir libc adresi leak eder.
Walkthrough¶
shellphish'in how2heap'indeki fastbin_dup_consolidate.c, consolidation'ı bir
double-free'ye dönüştürür. Modern glibc'de (tcache mevcut) önce tcache'i doldurur
ki hedef free fastbin'e ulaşsın:
/* fill the 0x40 tcache bin so the next free goes to the fastbin */
for (int i = 0; i < 7; i++) tcache[i] = malloc(0x40);
for (int i = 0; i < 7; i++) free(tcache[i]);
void *p1 = malloc(0x40);
free(p1); /* tcache full -> p1 lands in the 0x40 fastbin */
void *p2 = malloc(0x400); /* LARGE request -> triggers malloc_consolidate */
/* p1's fastbin chunk consolidates into top; */
/* p2 is carved from top and p1 == p2 (alias!) */
free(p1); /* p1 is no longer "in a fastbin" -> no fasttop
double-free abort; it re-enters a bin */
void *p3 = malloc(0x400); /* hands back the same chunk again: p2 == p3 */
malloc(0x400) buradaki kaldıraçtır: malloc_consolidate'i zorlar ve p1'in
fastbin üyeliğini temizler, böylece sonraki free(p1) bir double free olarak
tespit edilmez. Sonuç tek bir chunk'a işaret eden iki canlı pointer'dır (p2,
p3).
fastbin_dup_consolidate.c'nin beklenen sonucu
İki (veya üç) bağımsız allocation aynı adrese çözümlenir — fastbin double-free guard'ına hiç takılmadan elde edilmiş bir duplicate chunk.Warning
Boyutlar versiyona duyarlıdır. "Large" request, large-bin/consolidation
yolunu tetikleyecek kadar büyük olmalıdır (≈0x400+) ve glibc ≥ 2.26'da
tcache'i hesaba katmalısın (doldur ya da tcache aralığı dışındaki boyutları
kullan), aksi hâlde free fastbin'e hiç ulaşmaz. FASTBIN_CONSOLIDATION_THRESHOLD
(0x10000) yolu farklı bir trigger'dır (büyük bir free sırasındaki
consolidation), bu PoC'nin kullandığı değildir.
Detection¶
Consolidation'dan sonra programın hâlâ canlı sandığı stale bir pointer bir
use-after-free / double-free'dir; duplicate chunk yanlış kullanıldığında ASan ve
glibc'in kendi malloc(): ... / free(): double free or corruption mesajları
tetiklenir. Bir büyük allocation boyunca bin durumunu diff'leyen heap tracker'lar,
fastbin'lerin beklenmedik şekilde unsorted bin'e boşaldığını fark edebilir.
Mitigation¶
Bu istismar bir double-free ya da
use-after-free üzerine biner; dangling/duplicate pointer'ı
elemek onu kaldırır. tcache double-free key'leri, fastbin fasttop check'leri ve
unsorted-bin consistency check'leri pek çok takip eden corruption'ı yakalar.
Eager şekilde coalesce eden (ertelenmiş fastbin'i olmayan) hardened allocator'lar,
consolidation-zamanı boşluğunu tamamen ortadan kaldırır.