House of Lore¶
Bir smallbin chunk'ının
bkpointer'ını corrupt et kimallocdoubly-linked smallbin'i attacker belleğine doğru dolaşsın ve seçtiğin bir address'te fake bir chunk döndürsün.
Mechanism¶
Suistimal edilen invariant: smallbin servisi bk chain'ine güvenir
Small bin'ler exact-size, FIFO, doubly-linked list'lerdir. malloc bir
smallbin'den bir request servis ettiğinde, list'in bk (backward) pointer'larını
takip ederek tail'deki chunk'ı unlink eder; victim = last(bin) alır ve sonra
bin->bk = victim->bk yapar. Eski glibc bu unlink'i hiç validation olmadan
yapardı, dolayısıyla kuyruğa alınmış bir chunk'ın bk'sini overwrite etmek
allocator'ın o pointer'ın işaret ettiği herhangi bir address'i geri vermesini
sağlar — tipik olarak stack'te veya bir global'de fake bir chunk. Technique bir
size field'ı değil, list-traversal güvenini suistimal eder.
Hardened glibc smallbin partial-unlink check'ini ekledi:
if (__glibc_unlikely (bck->fd != victim))
malloc_printerr ("malloc(): smallbin double linked list corrupted");
burada bck = victim->bk. House of Lore bunu, fake target'ın fd'sini gerçek
önceki node'a geri işaret ettirerek atlatır; böylece victim->bk->fd == victim
geçerli olur ve check geçer.
Walkthrough¶
Referans: shellphish how2heap house_of_lore.c (glibc 2.23'ten 2.39'a kadar
maintain ediliyor). Freed/bin'lenmiş bir chunk'ın bk'sini overwrite edebilen bir
heap overflow ve fake chunk'lar için writable bir target bölge (stack/global)
gerektirir.
- Target bellekte fake chunk chain'ini inşa et. İki fake chunk (örn. stack'te) yerleştir ve corruption-detection check'i allocator onlara ulaştığında geçecek şekilde önceden link'le:
stack_buffer_1[2] = victim_chunk; /* fake_1->fd = victim (passes check) */
stack_buffer_1[3] = stack_buffer_2; /* fake_1->bk = fake_2 */
stack_buffer_2[2] = stack_buffer_1; /* fake_2->fd = fake_1 (reciprocal) */
Karşılıklı fd/bk link'leri her unlink adımında victim->bk->fd == victim'i
sağlayan şeydir.
- Victim'i bir smallbin'e taşı.
victim = malloc(0x100)ve bir referans tut.free(victim)→ unsorted bin'e iner.-
malloc(1200)(daha büyük bir request) unsorted bin'in bir taranmasını zorlar ki buvictim'i exact-size smallbin'ine sort eder. -
Smallbin
bk'sini corrupt et.victim->bk'yistack_buffer_1'e (fake chain'in head'i) işaret edecek şekilde overwrite et:
- Bin'i boşalt.
malloc(0x100)gerçekvictim'i döndürür ve list head'ini corrupt edilmişbkboyunca fake chain'e ilerletir.malloc(0x100)tekrar artık fake chunk'ın içine (yani attacker'ın seçtiği stack belleğine) bir pointer döndürür.
??? example "Sonuç"
p = malloc(0x100); /* p points into stack_buffer_2's user region */
/* writing through p overwrites a saved return address / local state */
!!! warning "Footgun: size ve link field'ları tutarlı olmalı"
Fake chunk'lar boşaltılan smallbin'e uyan bir size sunmalı ve fd/bk
karşılıklı link'leri geçerli olmalı, yoksa partial-unlink check
malloc(): smallbin double linked list corrupted ile ateşlenir. Size
class'ını yanlış yaparsan chunk adım 2'de beklenen bin'e hiç sort edilmez.
- Escalate et.
mallockontrollü belleğe bir pointer döndürürken, oraya bir payload yaz — klasik olarak control-flow hijack için saklı bir return address.
Detection¶
- Herhangi bir heap arena'sının dışına (örn. stack'e) işaret eden bir smallbin
bkanormaldir ve allocator instrumentation'ı tarafından yakalanabilir. victim->bk->fd != victimtutarlılık invariant'ı, enforce edildiğinde, naif formu hem tespit eder hem bloklar.
Mitigation¶
- glibc 2.32+'da eklenen smallbin partial-unlink check'i (
malloc(): smallbin double linked list corrupted) attacker'ı fake target'ınfd'sini de kontrol etmeye zorlar; çıtayı yükseltir ama yeterli bellek kontrol edildiğinde technique'i kapatmaz. - Pointer-mangling / safe-linking (glibc 2.32+) smallbin
fd/bk'yi kapsamaz (bunlar raw pointer'lardır), dolayısıyla primitive yeterli bir write verildiğinde güncel glibc'de geçerliliğini korur.