Skip to content

Use-after-free heap grooming

Allocator'ı öyle şekillendir ki freed bir object, aynı size class'tan attacker-controlled bir allocation tarafından reclaim edilsin — geride kalan stale veriye güvenmek yerine, bir dangling pointer'ı kontrollü içeriğe veya bir type confusion'a çevirerek.

Mechanism

Suistimal edilen invariant: allocator'lar freed belleği size class'a göre yeniden kullanır ve free etmek ona olan alias'ları geçersiz kılmaz

Bir object free() edildiğinde, onu destekleyen bellek size class'a göre anahtarlanmış bir free list'e döner (glibc'de tcache/fastbin, jemalloc'ta size-class slab'leri, Windows'ta LFH bucket'ı). Allocator'ın sözleşmesi first/best-fit reuse'dur: eşleşen boyuttaki sonraki allocation request'ine büyük olasılıkla az önce free edilen chunk'ın tam kendisi verilir ve byte'lar sıfırlanmaz. Program freed object'e hâlâ bir pointer tutuyorsa (bir dangling pointer), o pointer artık attacker'ın reclaim eden allocation'a yerleştirdiği her ne ise onu alias'lar.

Grooming, bu race-free yeniden kullanımın kasıtlı mühendisliğidir. Stale verinin yararlı olmasını ummak yerine, attacker:

  • victim object'i free eder, sonra tamamen kontrol ettiği aynı size class'tan bir object'i hemen reallocate eder (klasik free-then-realloc), böylece dangling pointer attacker'ın seçtiği byte'ları okur; veya
  • adjacent placement'i önceden ayarlar — victim ile kontrollü bir object'i contiguous inmeye veya örtüşmeye zorlayan bir desende allocate/free ederek — böylece dangling pointer üzerinden yapılan sonraki bir işlem, bilinen tipte bir komşuyu bozar.

Aşılan sınır temporal'dir: dil object'i ölü sayar, ama allocator ile hâlâ canlı olan alias onun lifetime'ı konusunda anlaşmazlığa düşer ve attacker yeniden kullanımı kimin kazanacağını kontrol eder.

Bu not, kök neden use-after-free bug'ından (CWE-416) ayrı olarak reclaim'i deterministik kılma tekniğine odaklanır: UAF "neyin yanlış olduğu", grooming ise "freed slot'a güvenilir biçimde nasıl inildiği"dir.

Walkthrough

Public UAF exploitation materyalini (örn. Will's Root heap serisi, BlackHat "Use-After-Use-After-Free") takip eden yüksek seviyeli reprodüksiyon.

  1. Size class'ı profille. Bir reclaim eden allocation'ın aynı bin'e inmesi için victim object'in byte boyutunu belirle. C++/COM hedeflerinde bu, vtable pointer'ı dahil object'tir; kernel hedeflerinde kmalloc/slab cache boyutudur.

  2. Victim'i free et, alias'ı koru. Bug'ı tetikle, böylece object kullanılabilir bir reference (dangling pointer, saklanmış handle, vtable dispatch site) kalırken free edilir.

  3. Kontrollü içerikle reclaim et. Byte'larını attacker'ın tamamen kontrol ettiği same-size bir object allocate et — genellikle verbatim kopyalanan bir string/buffer. Allocator az önce free edilen chunk'ı yeniden kullandığından, dangling pointer artık attacker byte'larını gösterir.

free(victim)                 // chunk -> free list (size class N)
alloc(N, attacker_bytes)     // allocator returns the SAME chunk
use(dangling_ptr)            // dispatch/read/write through controlled bytes
  1. Bir primitive'e dönüştür. Yeniden kullanılan object typed bir object olarak dereference edilirse (ilk qword'ü bir vtable / function pointer olarak ele alınırsa), attacker kontrollü bir indirect call'a sahip olur (type confusion). Yalnızca field'lar okunursa, attacker read/write primitive'leri inşa etmek için length/pointer field'larını forge eder.
Adjacent-placement varyantı

Victim'in kendisini değiştirmek yerine, attacker heap'i öyle groom eder ki kontrollü bir object victim'in hemen önüne/arkasına yerleştirilir, sonra victim'in tip tanımlayan field'larını bozmak için bir UAF write (veya kontrollü object'ten bir overflow) kullanır. Bu, layout'u deterministik yapmak için heap feng shui ve allocation-primitive shaping ile eşleşir.

Determinizm tüm oyunun kendisidir

Güvenilirlik, önce ilgili bin'i defragment etmekten gelir (look-aside/tcache'i boşalt, kararlı bir duruma kadar spray'le), böylece reclaim eden allocation'ın freed chunk'a vurması garanti olur. İlgisiz allocation'lardan gelen gürültü, ana başarısızlık modudur.

Detection

  • CI'da sanitizer'lar: AddressSanitizer'ın quarantine + redzone'ları heap-use-after-free'yi güvenilir şekilde işaretler; MemorySanitizer/Valgrind reclaim edilmiş belleğin okumalarını yakalar. GWP-ASan / MTE (ARM) production'da örneklenen bir kesri yakalar.
  • Allocation telemetrisi/anomalileri: içeriği daha sonra bir vtable olarak dispatch edilen bir same-size allocation'ın hemen ardından gelen bir free veya olağandışı düzenli alloc/free spray desenleri ("grooming churn"), davranışsal sinyallerdir.
  • Crash adli analizi: target'ı bir data/heap region'ında (kod değil) oturan bir pointer üzerinden yapılan ve bir free'nin hemen ardından object dispatch'inde fault veren indirect call'lar, core'larda/EDR backtrace'lerinde bir UAF-reclaim imzasıdır.
  • ASan altında fuzzing, kök neden UAF'yi silahlaştırılmadan önce ortaya çıkarmanın en yüksek verimli yoludur.

Mitigation

  • Hardened allocator'lar / gecikmeli yeniden kullanım: quarantine ve randomize edilmiş yeniden kullanım (GWP-ASan, Scudo, hardened_malloc, kernel SLAB_FREELIST_RANDOM / init_on_free, type-isolated kmem cache'leri) bu tekniğin dayandığı deterministik same-bin reclaim'i kırar.
  • Memory tagging (ARM MTE): freed chunk'ı tag'ler, böylece stale bir alias use'da fault verir ve kimin reclaim ettiğine bakılmaksızın dangling pointer'ı etkisizleştirir.
  • Kaynak hijyeni: free'den sonra pointer'ları NULL'a ayarla, dangling alias'ı kaldırmak için smart pointer'lar/unique_ptr, RAII ve reference counting kullan; testte -fsanitize=address ile compile et.
  • İzolasyon: separate-heap / per-type partitioning (modern browser'lardaki gibi), bir tipin kontrollü bir allocation'ının başka bir tipin freed object'ini reclaim etmesini önler.

References