House of Tangerine¶
Top chunk'ın (wilderness) size'ını corrupt et; böylece sonraki oversized bir istek
sysmalloc'un eski top'u unsorted bin/tcache'e free etmesine yol açar — hiçfree()olmayan bir heap overflow'u leak + tcache-poisoning primitive'ine çevirir.
Mechanism¶
Invariant: sysmalloc heap'i genişletirken eski top chunk'ı free eder
House of Tangerine, House of Orange'ın tcache çağına yönelik "freeless"
(free'siz) bir modernizasyonudur. Suistimal ettiği temel allocator davranışı
sysmalloc'ta yaşar: bir istek mevcut top chunk'tan karşılanamayıp heap
büyütüldüğünde (brk/mmap), glibc fencepost'ları yerleştirdikten sonra
eski top chunk'ı _int_free aracılığıyla freelist'e geri koyar. Kullanıcı
free()'sine gerek yoktur.
Bunu silaha dönüştürmek için attacker, top chunk'ın size field'ına overflow
eder ve onu sysmalloc'un geçerlilik kapısını hâlâ geçen bir değere küçültür:
MINSIZE'dan büyük,PREV_INUSE(bit 0) set,- page-aligned (
0x1000'in katı) — aksi halde glibcsysmalloctutarlılık kontrolü sırasında "corrupted top size" ile abort eder.
Sonra forge edilen top size'dan daha büyük bir istek heap'i büyümeye
zorlar. sysmalloc yeni top'u oyar, eski bölgeyi fencepost'lar ve eski top
chunk'ı free eder:
- Free edilen size tcache/fastbin aralığına düşerse oraya gider; daha
büyükse unsorted bin'e girer; orada
fd/bk'sı artık birmain_arenapointer'ı tutar — chunk geri okunduğunda biraddress-leak/ libc leak primitive'i. - Kontrol edilen chunk'ları yeniden corrupt edip yeniden free etmek tcache
poisoning verir: safe-linking'i yenmek için bir heap leak ile (glibc ≥
2.32), attacker encryption key'i çözer,
fd = target XOR (chunk_addr >> 12)ayarlar ve iki allocation sonramallockeyfi bir adres döndürür.
glibc 2.34 ve 2.39 üzerinde test edildi (x86-64, x86, aarch64). free
gerektirmediği için "no-delete" CTF/menu binary'lerine uygundur.
Walkthrough¶
shellphish/how2heap glibc_2.39/house_of_tangerine.c demosu (born0monday &
Sir_X tarafından) yalnızca malloc çağrıları artı out-of-bounds write'lar
(OOB) kullanır — free yok.
// Sizes chosen so the old top, once freed, becomes a 0x40 tcache chunk.
#define PAGESIZE sysconf(_SC_PAGESIZE)
#define CHUNK_HDR_SZ (2*sizeof(size_t))
#define CHUNK_SIZE_1 0x40
// 1) Allocate so our writable chunk sits adjacent to the top chunk header.
char *a = malloc(SIZE_1); // a few setup chunks bring us up to `top`
// 2) OOB-write the top chunk size: shrink it, keep PREV_INUSE, keep page align.
// *top_size_ptr = <page-aligned value | 1>;
// e.g. reduce remaining wilderness to PAGESIZE-(2*MALLOC_ALIGN)-CHUNK_SIZE_1
// 3) Request more than the forged top size -> sysmalloc grows heap and
// _int_free()s the old top. With the right sizes it lands in tcache/unsorted.
char *grow = malloc(CHUNK_SIZE_3); // forces the old top into a bin
// 4a) LEAK: allocate back the unsorted-bin chunk and read its fd/bk (main_arena).
// 4b) POISON: OOB-write the freed tcache entry's fd. Safe-linking (>=2.32):
// fd = target ^ (chunk_addr >> 12); // needs a heap leak for chunk_addr>>12
// malloc(); malloc(); // 2nd malloc returns `target`
Footgun'lar
- Forge edilen top size'ın page alignment'ı modern glibc'de zorunludur.
Page-aligned olmayan bir top size
sysmalloc'ta "corrupted top size"'a takılır. - Fencepost hesabı.
sysmallocfencepost'lar için iki chunk header (2*CHUNK_HDR_SZ, yani0x20) çıkarır; free edilen eski-top size'ıforged_size - fencepost'tur, dolayısıyla hedef bin size'larını ham forge değerinden değil bundan hesapla. - Safe-linking (glibc ≥ 2.32). tcache
fd'sichunk_addr >> 12ile XOR-obfuscate edilir. Bir heap leak olmadan kullanılabilir birfdforge edemezsin; 4a adımındaki unsorted-bin leak'i genellikle libc adresini sağlar ve ayrı bir heap leak (ya da alignment side-channel) heap base'ini sağlar. freeolmaması burada tcachee->keydouble-free kontrollerinin alakasız olduğu anlamına gelir — chunk allocator'ın kendisi tarafından free edilir.
Expected behavior
Detection¶
- Page-aligned ve daha önce gözlemlenen wilderness'tan küçük bir top-chunk
size'ının hemen ardından oversized bir istek gelmesi imzadır. fd'si (safe-linking sonrası) heap-dışı bir adrese decode olan bir unsorted/tcache chunk'ı, bu primitive'in downstream'inde poisoning'e işaret eder.
Mitigation¶
- glibc'nin
sysmalloc"corrupted top size" kontrolü (top size aklı başında ve page-aligned olmalı) corruption yüzeyini sınırlar ama ortadan kaldırmaz. - Safe-linking (≥ 2.32) tcache
fdforge'u kullanılabilir olmadan önce ek bir heap leak'i zorunlu kılar. - Out-of-line metadata allocator'ları ve son chunk ile top chunk arasındaki guard page'ler wilderness header'a overflow'u engeller.