tcache relative write¶
Bir tcache chunk'ının
nextpointer'ının kısmi (düşük-byte) bir overwrite'ı; tam bir adres leak'i olmadan sonraki allocation'ı yakındaki bir heap objesine yönlendirir.
Mechanism¶
Suistimal edilen invariant: aynı heap page içine işaret etmek için yalnızca next'in düşük byte'larının değişmesi gerekir
Standart tcache-poisoning, kuyruğa alınmış bir tcache_entry'nin tüm
next (fd) word'ünü overwrite eder:
tcache_get, e->next'i hiçbir bounds kontrolü olmadan list head'ine
yükseltir, dolayısıyla sonraki malloc, next neyi adlandırıyorsa onu
döndürür. Göreli varyant yalnızca next'in düşük 1–2 byte'ını
yeniden yazar. Heap allocation'lar adreslerinin üst bit'lerini paylaştığı
için (aynı arena page / mmap region'ı), düşük byte'ı çevirmek döndürülen
pointer'ı birkaç slot ötedeki farklı bir chunk'a taşır — bitişik bir
in-use objeyle overlap eder — yalnızca tek-byte'lık bir overflow kullanarak
(örneğin bir off-by-one ya da null-byte overflow). Üst bit'ler için hiçbir
heap leak gerekmez, yalnızca göreli offset bilgisi; bu da onu tcache için
birincil bir heap-ASLR bypass'ı yapar.
glibc ≥ 2.32'de next,
PROTECT_PTR(pos, ptr) = ((pos >> 12) ^ ptr) ile mangle edilir. XOR key'i
(pos >> 12) bir page içinde sabittir, dolayısıyla düşük 12 bit mangling'i
değişmeden atlatır: en anlamsız byte hâlâ doğrudan düzenlenebilir, bu da
relative-write hilesini safe-linking altında canlı tutar.
Walkthrough¶
tcache-poisoning'in üzerine kurulur; burada write kısmidir.
char *a = malloc(0x40); // ... a, b, c laid out adjacently on the heap
char *b = malloc(0x40);
char *t = malloc(0x40); // the object we want a second handle to
free(b); // tcache[0x40]: [ b ] (b->next = mangled 0)
// VULNERABILITY: 1-byte relative overwrite of b->next's LSB
// shift the head from b to point at t's user data within the same page
*(unsigned char *)b = (unsigned char)((size_t)t & 0xff); // low byte only
malloc(0x40); // returns b
char *dup = malloc(0x40); // returns ~t -> overlapping handle to t
Beklenen çıktı: ikinci allocation t'nin içine (ya da bir slot ötesine)
düşer, canlı bir objeyi alias'layan overlapping bir pointer verir — tipik olarak
hiç tam bir heap adresi leak'lemeden bitişik bir struct'ın size/pointer alanlarını
corrupt etmek için kullanılır.
Alignment ve düşük nibble
Forge edilmiş düşük byte 16-byte alignment'ı korumalı (& 0xf == 0) yoksa
tcache_get, malloc(): unaligned tcache chunk detected ile abort eder.
Düşük nibble'ı zaten 0 olan bir hedef seç. Tek bir byte yalnızca aynı
256-byte pencere içindeki hedeflere ulaşır; daha büyük sıçramalar için iki
byte overwrite et (ve pos >> 12'nin farklılaştığı bir page sınırını geçmeye
dikkat et).
Mitigation¶
tcache_get'tekialigned_OKkontrolü, forge edilmiş LSB'nin 16-byte aligned kalmasını zorlar.- Safe-Linking bir düşük-byte düzenlemesini durdurmaz (key page-sabittir), dolayısıyla relative write hayatta kalır; tam hardening, glibc'nin sağlamadığı, page granülaritesinden daha ince bir heap layout randomization gerektirir.