Skip to content

jemalloc exploitation

jemalloc'ta inline free-list pointer'ları ya da dlmalloc tarzı unlinking yoktur, dolayısıyla exploitation run/chunk metadata'sını corrupt etmeye ya da same-size region'ları groom ederek malloc()'a hâlâ kullanımda olan memory'ye bir pointer döndürtmeye odaklanır.

Mechanism

Invariant: jemalloc out-of-band run/chunk bookkeeping'inin gerçekte canlı olanla tutarlı olduğuna güvenir

dlmalloc/ptmalloc'un aksine, jemalloc neredeyse hiç allocator metadata'sını user data'nın yanında inline saklamaz ve (argp & huku'ya göre) "dlmalloc'un exploitation'ı için catalytic olduğu kanıtlanmış 'unlinking' ya da 'frontlinking' gibi kavramları implemente etmez." Bunun yerine bookkeeping'i ayrı yapılarda tutar ve onlara güvenir. Exploitation amacı dolayısıyla bir linked-list operasyonunu hijack etmekten malloc()'u zaten canlı bir region'a pointer döndürmeye zorlamaya (region duplication / overlap) kayar; bu ya o out-of-band metadata'yı corrupt ederek ya da aynı size-class'taki free list'leri groom ederek başarılır. Aynı size class'taki region'lar bir run içinde araya giren metadata olmadan contiguous şekilde paketlendiği için, linear bir overflow allocator header'ları yerine doğrudan sonraki region'ın user data'sını corrupt eder — yani victim bir chunk header değil, komşu bir objedir.

Walkthrough

jemalloc'un allocation hiyerarşisi, Pseudomonarchia jemallocum (Phrack 68)'de tarif edildiği gibi:

arena  (arena_t)         highest abstraction; per-thread to reduce lock contention,
  |                      owns the chunks and bins below it
  +-- chunk (arena_chunk_t)  large mmap'd region (1-4 MB); keeps a back-pointer to its arena
  |     +-- run (arena_run_t)   contiguous pages serving ONE size class;
  |     |                       carries a bitmask of region alloc state
  |     |     +-- region        the actual malloc() return value
  +-- bin  (arena_bin_t)  tracks the free regions / runs for a size class

Makaledeki size class'lar: small/medium region'lar bir page'den küçüktür; large region'lar small/medium'dan büyük ama huge'dan (chunk size eksi header'lar) küçüktür.

Primitive 1 — adjacent same-size region overflow. Aynı size-class'taki region'lar aralarında metadata olmadan bir run'ı paylaşır, dolayısıyla bir heap overflow sonraki region'ın içeriğini corrupt eder. jemalloc exploitation'ının yoğun şekilde heap grooming / feng shui'ye yaslanmasının nedeni budur: overflow eden region'ın hemen ardındaki region'a bir target obje (örn. vtable pointer'ı olan bir C++ objesi ya da bir length field) yerleştirirsin.

Primitive 2 — run-header metadata corruption. Bir run, region'larından hangilerinin free olduğunu bir bitmask ile takip eder. Makale, ilk free element'i kaydeden run-header field'ının overwrite edilmesini tarif eder ki malloc() zaten allocate edilmiş bir region'a pointer döndürmeye yönlendirilir; bu da overlapping memory'ye iki canlı pointer üretir (region duplication).

Tam run/region field adları versiyona özgüdür

jemalloc'un internal struct layout'u (ve run'ın free-element index'i, regions bitmask'i ve arena_chunk_t arena pointer'ı gibi field adları) Firefox'un mozjemalloc'u, stand-alone jemalloc ve sonraki Android/FreeBSD versiyonları arasında esaslı şekilde değişti. Herhangi bir spesifik corruption'a güvenmeden önce field offset'lerini tam target build'e karşı unmask_jemalloc gibi bir tool ile doğrula — offset'leri 2012 write-up'larından kopyalama.

Primitive 3 — chunk-header corruption. Her region, adresini chunk sınırına kadar maskeleyerek kendisine ait arena_chunk_t'yi bulabilir. Chunk header'ı corrupt etmek — özellikle sakladığı arena pointer'ını — o chunk'taki bir region'ın sonraki bir free()'sinin attacker-influenced data'yı dereference etmesi demektir.

Primitive 4 — thread-cache (magazine) targeting. Preallocate edilmiş region'ların per-thread cache'leri de normal path üzerinden allocate edilir, dolayısıyla sıradan region'lar arasında yaşarlar ve gelecek allocation'ların hangi pointer'ları döndüreceğini etkilemek için diğer herhangi bir obje gibi corrupt edilebilirler.

Canlı jemalloc state'ini unmask_jemalloc ile incelemek

argp'nin unmask_jemalloc'u (Black Hat USA 2012 talk'uyla yayımlandı) canlı arena'ları/chunk'ları/run'ları gezen bir debugger plugin'idir; böylece size class'ları ve region layout'unu tahmin etmek yerine gerçek target üzerinde doğrulayabilirsin:

# under gdb/lldb with the plugin loaded
jemalloc_dump_arenas      # enumerate arenas and their chunks
jemalloc_dump_runs        # per-run size class + region bitmap state
(Subcommand adları tool'un dokümantasyonunu takip eder; mesele layout'u canlı okumaktır, struct offset'lerini hardcode etmek değil.)

Detection

  • Komşu region'lara overflow'ları ve duplicate edilmiş region'ların use-after-free'sini yakalamak için target'ları AddressSanitizer / debug MALLOC_OPTIONS/junk fill altında çalıştır.
  • İki ayrı allocation'ın overlapping adreslere çözülmesini (region duplication) gözle.

Mitigation

  • Allocator metadata'sını ve guard logic'ini güncel tut; modern jemalloc debug build'lerde redzone/junk-filling ekler ve burada incelenen 2012 dönemi koduna göre daha fazla bookkeeping doğrular.
  • Grooming'i zorlaştırmak için untrusted, attacker-sized objeleri dedicated arena'lara/size class'lara izole et.
  • Tasarımın açığa çıkardığı adjacent-region overflow'larını tespit etmek için compile-time/ASan instrumentation.

References