exit handler hijack via PTR_MANGLE bypass¶
glibc'nin
__exit_funcslistesinde encrypted bir entry forge ederek__run_exit_handlers'ın attacker kodunu çağırmasını sağla; PTR_MANGLE pointer guard'ını bir leak ya da sıfır/bilinen bir guard ile yen.
Mechanism¶
Note
atexit/__cxa_atexit ile register edilen fonksiyonlar exit_function_list
node'larında saklanır — head __exit_funcs'tır ve initial bir blok libc'nin
writable data/.bss'inde yaşar, her node 32 entry'ye kadar tutar. Saklanan her
function pointer PTR_MANGLE ile korunur: register sırasında pointer,
fs:0x30'da saklanan per-thread pointer guard ile rotate edilir ve XOR'lanır
(rol reg,0x11 ; xor reg,fs:0x30 tarzı); exit() zamanında
__run_exit_handlers listeyi ters yürür ve her entry'yi call etmeden önce
demangle eder (ror reg,0x11 ; xor reg,fs:0x30). Güvenlik sınırı o guard'ın
gizliliğidir. Eğer attacker guard'ı leak'leyebilirse (ya da guard sıfırsa —
static-link bug'ı CVE-2013-4788), herhangi bir target adresi için geçerli bir
ciphertext hesaplayabilir; böylece exit-function bloğuna yapılan tek bir arbitrary
write, process teardown sırasında controlled code execution'a dönüşür. İlgili
"House of Banana" varyantı, mevcut bir entry'yi düzenlemek yerine bütün bir fake
node forge eder ve __exit_funcs'ı ona yönlendirir.
Walkthrough¶
Kavramsal mangle/demangle ilişkisi (x86-64):
encoded = rol(target ^ pointer_guard, 0x11) /* registration */
target = ror(encoded, 0x11) ^ pointer_guard /* __run_exit_handlers */
Public writeup'lardan derlenen yüksek seviyeli adımlar:
__exit_funcs'ı (export edilmemiş) bul — örn. bir libc leak'i üzerinden ya da__cxa_atexitiçindeki RIP-relativelea'yı okuyarak.- Bilinen bir mangled/plaintext çiftinden (örn. initial
_dl_finihandler'ı) guard'ı kurtar:guard = ror(encoded, 0x11) ^ known_addr. - İstenen target'ı yeniden mangle et:
encoded = rol(target ^ guard, 0x11); entry'nin flavour'unu (ef_cxa/ef_on) ve argument field'larını uygun şekilde ayarla. - Mevcut bir handler entry'sini forge edilmiş değerinle overwrite et (ya da
House-of-Banana tarzı,
__exit_funcs'ı tamamen controlled bir fake node'a işaret ettir). __run_exit_handlers'ı tetiklemek içinexit()'e ulaş /main'den return et.
Warning
__exit_funcs'ın, initial bloğun ve fs:0x30'un offset'leri glibc ve
architecture'a göre değişir; target libc'ye karşı doğrula. Modern glibc (2.34+),
exit'e ulaşmak için sık kullanılan malloc/free hook'larını kaldırdı, ama
exit-handler path'inin kendisi kalır.
Detection¶
__run_exit_handlers'dan.text/PLT dışına düşen indirect call.- Demangle edilmiş target'ı loaded bir modülün koduna işaret etmeyen exit-function
entry'leri ya da heap'e işaret eden
__exit_funcs. - Runtime'da
.bss/data initial exit bloğuna veya TCBfs:0x30'a yapılan write'lar.
Mitigation¶
- Pointer guard'ın randomize edildiğinden emin ol (zero-guard static path'i CVE-2013-4788'de düzeltildi); predictable bir guard'la bir build asla ship'leme.
- ASLR artı agresif info-leak önleme, guard'ı kurtarmanın maliyetini yükseltir.
- Exit-handler indirect call üzerinde CFI /
-fcf-protection; sonraki glibc çalışmaları bu struct'ları korumaya doğru ilerliyor.