House of Pig¶
glibc 2.31+ için bir
calloc-only exploitation chain'i: bir large-bin attack,__free_hookyakınına yazmak için bir tcache-stashing-unlink primitive'i kurar, ikinci bir large-bin attack_IO_list_all'u yeniden yönlendirir ve_IO_str_overflow'un internalmalloc/memcpy/free'si FSOP'u code execution'a sürükler.
Mechanism¶
Suistimal edilen invariant
calloc bilerek tcache'i atlar, dolayısıyla döndürülen pointer'ın tcache poisoning'ine dayanan technique'ler bir calloc-only allocator'a karşı çalışmaz. House of Pig bunu, calloc'un asla poison'lanmış bir chunk geri vermesine ihtiyaç duymayarak atlatır. Bunun yerine _IO_str_overflow'a yaslanır, ki bu internal olarak malloc → memcpy → free yapan bir IO rutinidir. O free tcache ile etkileşime girdiği için, tcache linked list'ini önceden seed etmiş (bir tcache-stashing-unlink attack üzerinden, ki o da __free_hook yakınına kontrollü bir pointer yerleştiren bir large-bin attack ile kurulmuştur) bir attacker, IO mekanizmasının allocation'ını __free_hook'a bir write'a çevirebilir. İkinci bir large-bin attack _IO_list_all'u overwrite eder ki IO flush sırasında forge edilmiş _IO_FILE'a ulaşılsın. Tüm chain dolayısıyla başka türlü mütevazı üç primitive'i, malloc/calloc'un attacker belleğini doğrudan döndürmesine hiç bağlı kalmadan FSOP code execution'a besteler.
Walkthrough¶
glibc 2.31 ve sonrasına uygulanır. Freed chunk'lar üzerinde read/write'lı bir UAF ve erişilebilir bir IO flush (exit, abort veya main return) gerektirir.
- Large-bin attack #1 —
__free_hookyakınına yerleştir. UAF'i kullanarak bir large-bin chunk'ınınbk_nextsize'ını (vefd/bk'sini) corrupt et ki large-bin insertion__free_hook - 0x8'e kontrollü bir heap address yazsın. Bu tcache list head target'ını kurar.
-
Tcache-stashing-unlink attack — list'in head'ini
__free_hook'a koy. Bir tcache count/stash sür ki stashing-unlink path__free_hook - 0x10'u bir tcache bin'in head'ine yerleştirsin. Şimdi o boyutun bir sonraki tcache allocation'ı__free_hook - 0x10döndürecek ve sonraki bir free/copy'nin__free_hooküzerine inmesine izin verecek. -
Large-bin attack #2 —
_IO_list_all'u hijack et. İkinci bir large-bin attack_IO_list_all'a bir heap address yazar, böylece IO flush sırasında glibc o heap address'i birFILEolarak muamele eder.
-
_IO_strFILE'ı forge et. Fake_IO_FILE'ı flush_IO_str_overflow'a ulaşacak şekilde inşa et. O rutin yeni bir buffer size hesaplar,malloc'u/allocator'ı çağırır, eski buffer'ımemcpy'ler, sonra eski buffer'ıfree'ler. tcache head'i__free_hook - 0x10'a yönlendirilmişken, allocation/free dizisi attacker'ın değerini (örn.system)__free_hook'a yazar ve yaptığıfree(ptr)onu kontrollü bir argument'la invoke eder. -
Trigger. IO flush'a (
exit/abort/return) neden ol._IO_flush_all_lockp_IO_list_all'u dolaşır, forge edilmiş str-file'ı dispatch eder,_IO_str_overflowçalışır,__free_hookset edilir ve takip eden freesystem("/bin/sh")'i çalıştırır.
Footgun'lar
- İki large-bin attack'ın her biri tam-boyutlu bir chunk tüketir ve doğru
fd_nextsize/bk_nextsizecorruption'ı gerektirir; insert'lerin sıralaması önemli. _IO_str_overflowsize aritmetiği, freed eski chunk'ı prime ettiğin tcache bin'ine düşen bir buffer size üretmeli — size class'ını yanlış yaparsan stashing-unlink head'i asla tüketilmez.__free_hooksadece glibc 2.33'e kadar var; 2.34+'ta hook kaldırılmış, dolayısıyla son write target'ı değişmeli (örn. bir FSOP-to-systempath'i veya başka bir function pointer).
Detection¶
*_nextsizepointer'ları__free_hook/_IO_list_allkomşuluklarına referans veren large-bin chunk'ları.- Heap'e işaret eden
_IO_list_all. - Head'i tam
__free_hook'un altına işaret eden bir tcache bin'i.
Mitigation¶
- glibc 2.34:
__malloc_hook/__free_hook'un kaldırılması son write target'ını kırar ve yeniden tasarlanmış bir kuyruğu zorlar. - Sonraki glibc'de eklenen large-bin insertion integrity check'leri (
bk_nextsize/fd_nextsizevalidation'ı) large-bin-attack güvenilirliğini azaltır. - Safe-linking (2.32+) ve tcache count sanity check'leri stashing-unlink aşamasının maliyetini yükseltir.