Skip to content

House of Pig

glibc 2.31+ için bir calloc-only exploitation chain'i: bir large-bin attack, __free_hook yakı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 internal malloc/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 mallocmemcpyfree 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.

  1. Large-bin attack #1 — __free_hook yakınına yerleştir. UAF'i kullanarak bir large-bin chunk'ının bk_nextsize'ını (ve fd/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.
largebin insert -> *(__free_hook - 0x8) = heap_ptr
  1. 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 - 0x10 döndürecek ve sonraki bir free/copy'nin __free_hook üzerine inmesine izin verecek.

  2. 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 bir FILE olarak muamele eder.

largebin insert -> _IO_list_all = &fake_file (heap)
  1. _IO_str FILE'ı 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.

  2. 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_hook set edilir ve takip eden free system("/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_nextsize corruption'ı gerektirir; insert'lerin sıralaması önemli.
  • _IO_str_overflow size 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_hook sadece 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-system path'i veya başka bir function pointer).

Detection

  • *_nextsize pointer'ları __free_hook/_IO_list_all komş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_nextsize validation'ı) 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.

References