unsorted bin into stack¶
Freed bir unsorted-bin chunk'ının
bk'sini stack'teki sahte bir chunk'a yönelt, böylece sonrakimallocnear-arbitrary (stack) bir pointer döndürür.
Mechanism¶
Düz unsorted-bin-attack unlink write'ı suistimal ederken, bu varyant döndürülen pointer'ı
suistimal eder. Unsorted bin'i dolaşırken, _int_malloc, victim'in size'ı mevcut request'i
karşılarsa ("exact fit" yolu) veya taşınan son chunk ise, onu doğrudan caller'a geri verebilir.
Allocator, değerlendirilecek sonraki chunk'ı bulmak için victim->bk'yi takip eder:
victim = unsorted_chunks(av)->bk; /* last chunk in the bin */
...
/* if it does not exactly fit the request, it is sorted into a bin and
the loop advances via victim = bck (= victim->bk) */
victim->bk'yi stack'e yerleştirilmiş sahte bir malloc_chunk'ı gösterecek şekilde
overwrite ederek, attacker allocator'ın o stack region'ını free bir chunk olarak ele almasını
sağlar. Request size'ı sahte chunk ile eşleşecek şekilde tasarlanırsa, malloc stack'in
içine bir pointer döndürür — return address ve canary etrafındaki region dahil olmak üzere bir
stack frame üzerinde kontrollü allocation verir.
Note
Sahte chunk'ın size field'ı minimum-size sanity check'ini geçmeli (size >= 2*SIZE_SZ,
yani x86-64'te > 16) ve tetikleyen request'ten farklı olmalı, böylece chunk yanlış pass'te
döndürülmek yerine sorted (re-linked) edilir. Tüm teknik glibc 2.29 unsorted-bin integrity
check'inden öncedir ve glibc < 2.29 için geçerlidir.
Walkthrough¶
how2heap unsorted_bin_into_stack biçimi (glibc 2.27):
unsigned long stack_buffer[4] = {0};
unsigned long *victim = malloc(0x410);
malloc(0x20); /* guard against top consolidation */
free(victim); /* victim enters the unsorted bin */
/* craft a fake chunk on the stack */
stack_buffer[1] = 0x30; /* fake prev_size / size area */
/* size field for the fake chunk; must pass 2*SIZE_SZ check */
/* vulnerability: redirect victim->bk to the stack */
victim[1] = (unsigned long)stack_buffer; /* victim->bk -> stack */
unsigned long *p = malloc(0x30); /* allocator follows bk onto the stack */
/* p now points into stack_buffer */
memcpy((char *)p + 40, &shellcode_addr, 8); /* write past the canary slot */
Beklenen çıktı (how2heap unsorted_bin_into_stack)
"canary'nin üzerinden atlama" write'ı, bir stack allocation'ının neden güçlü olduğunu gösterir: stack canary'yi geçmeden (ve bozmadan) kaydedilmiş return address'i ezmene olanak verir.
Mitigation¶
glibc 2.29'un unsorted-bin consistency check'i (bck->fd != victim artı have_fastchunks/size
validation'ları), ilgisiz bir (stack) region'ı gösteren bir bk'yi reddeder, dolayısıyla tam
olarak bu PoC yalnızca daha eski glibc'de çalışır. Stack canary'ler hâlâ "canary'nin ötesine
yaz" hilesini zorunlu kılar; relro ve hardened bir allocator (safe-linking, randomize
edilmiş key'ler) takipleri daha da kısıtlar.