Skip to content

House of Mind

Bir chunk'ın NON_MAIN_ARENA bit'ini corrupt et ki free() heap_for_ptr() alignment matematiği üzerinden fake bir arena çözsün ve attacker'ın allocator write'larını seçtiği belleğe yönlendirmesine izin versin.

Mechanism

Suistimal edilen invariant: arena kimliği chunk address + bir size flag'inden türetilir, authenticate edilmez

ptmalloc bir chunk'a hangi arena'nın sahip olduğuna tamamen, güvenilir bir list'e karşı hiç validate etmediği metadata'dan karar verir. NON_MAIN_ARENA flag'i (bir chunk'ın size field'ının üçüncü bit'i) global main_arena ile chunk address'ini bir HEAP_MAX_SIZE sınırına maskeleyerek bulunan heap-local bir arena pointer'ı arasında seçim yapar:

#define heap_for_ptr(ptr) \
  ((heap_info *) ((unsigned long) (ptr) & ~(HEAP_MAX_SIZE - 1)))

#define arena_for_chunk(ptr) \
  (chunk_non_main_arena (ptr) ? heap_for_ptr (ptr)->ar_ptr : &main_arena)

Eğer attacker bir chunk'ta NON_MAIN_ARENA set ederse ve onun altındaki HEAP_MAX_SIZE-hizalı address'teki belleği kontrol ederse, o zaman heap_for_ptr(ptr)->ar_ptr attacker'ın seçtiği bir arena pointer'ı okur. free() sonra tamamen forge edilmiş bir malloc_state üzerinde çalışır. Arena seçimi gerçek arena registry'sine karşı check edilmeyip hesaplandığı için, tüm free path yeniden yönlendirilebilir.

Walkthrough

Köken: Phantasmal Phantasmagoria, The Malloc Maleficarum (2005). Orijinal GOT-overwrite formu patch'lendi (unsorted-bin validation, ~glibc 2.11). Fastbin varyantı (Maxwell Dulin tarafından canlandırıldı) sürümler boyunca bir write-where primitive olarak hayatta kalır ve bugün pratik formdur.

Fastbin varyantı bir WRITE-WHERE verir: fastbin-boyutlu bir chunk'ın free()'si o chunk'ın address'ini fake_arena->fastbinsY[idx]'e yazar. Attacker yazılan konumu kontrol eder (fake arena'yı yerleştirerek), ama değer freed chunk'ın address'idir (farklı heap offset'lerinde chunk'lar free ederek ayarlanabilir).

  1. Alignment için heap feng shui. Allocation'ları spray et ki kontrol edilebilir bir bölge HEAP_MAX_SIZE-hizalı bir address'te otursun (writeup HEAP_MAX_SIZE'ı ampirik olarak ölçtü ve 64-bit Ubuntu'da alignment'ı tutturmak için ~0x20000000x4000000 churn olduğunu not eder). heap_for_ptr() victim chunk'ı bu base'e maskeleyecek.

  2. heap_info + fake arena forge et. Hizalı base'de, ar_ptr'si senin fake malloc_state'ine işaret eden bir heap_info yaz. Fake arena'da şunları set et:

  3. fastbinsY array'ini doğru struct offset'inde (2.23'te 0x8; 2.27+'da 0x10, çünkü have_fastchunks eklendi) ve
  4. next-size sanity check'ini geçecek kadar büyük system_mem (2.23'te ~0x880 / 2.29'da ~0x888 offset).

  5. Write'ı nişanla. Hedef fake_arena + fastbinsY_offset + (fastbin_index * 8)'dir. Belirli bir chunk size'ıyla bir target address T'ye write indirmek için, fake arena base'ini bu offset'ler tekrar T'ye toplanacak şekilde set et (örn. 2.23, 0x30 chunk, target 0x5555554444 → arena 0x5555554444 - 8 - 8'de).

!!! warning "Footgun: overflow yapılan chunk main arena'da yaşamalı" Non-main arena'lar bir size cap dayatır, dolayısıyla corrupt edilen fastbin chunk'ın kendisi main_arena'ya ait olmalı; sadece onun forge edilmiş NON_MAIN_ARENA bit'i resolution'ı yeniden yönlendirir. glibc 2.26+'da ilgili tcache bin'i dolu olmalı ki chunk tcache yerine fastbin path'ini alsın.

  1. Chunk'ı corrupt et. Target chunk'ın size field'ında NON_MAIN_ARENA bit'ini set et (tek-byte'lık bir overflow yeter). Sonraki chunk'ın size'ı fastbin sanity check'ini geçmek için 0x10 <= size < arena->system_mem'i sağlamalı — fake arena'da system_mem'in büyük forge edilmesinin nedeni budur.

  2. Write'ı tetikle. Corrupt edilen chunk'ı free() et. arena_for_chunk() fake arena'ya yönlendirir; _int_free chunk pointer'ını fake_arena->fastbinsY[idx]'e insert eder, yani seçtiğin target'a bir heap pointer yazar.

??? example "Primitive özeti"

controlled: WHERE  (address = fake_arena + fastbin offset)
value:      freed chunk address (tune by freeing different chunks)
=> overwrite a function pointer / adjacent metadata with a heap pointer

Detection

  • NON_MAIN_ARENA bit'i set olan ama hizalı heap_info'su gerçek bir registered arena'ya karşılık gelmeyen bir freed chunk tutarsızdır.
  • Allocator'ın fastbinsY sandığı ama bilinen herhangi bir arena'nın dışında olan belleğe yapılan write'lar allocator instrumentation'ı tarafından yakalanabilir.

Mitigation

  • Orijinal unsorted-bin formu glibc ~2.11 validation'ı tarafından öldürüldü.
  • Fastbin size sanity'si (<= 0x10 / >= system_mem) fastbin varyantını kısıtlar ama büyük bir system_mem'li fake arena sağlandığında durdurmaz.
  • tcache (2.26+) küçük boyutlar için araya girer, dolayısıyla attacker fastbin path'ine ulaşmak için önce eşleşen tcache bin'ini tüketmeli.

References