link_map / _dl_fini corruption¶
Bir
link_mapnode'unu forge ya da corrupt et ki dynamic linker'ın exit-time finalizer walk'u attacker-controlled bir pointer'ı çağırsın.
Mechanism¶
Kırılan invariant
Normal process exit'inde, glibc'nin dynamic linker'ı her loaded object'in destructor'larını
çalıştırır. _dl_fini() (elf/dl-fini.c) l_next'i takip ederek
_rtld_global._dl_ns[ns]._ns_loaded'dan link_map list'ini gezer, objeleri toplar,
sort'lar ve l_init_called set olan her map için finalizer'ları invoke eder. Modern
glibc'de call _dl_call_fini()'de (elf/dl-call_fini.c) gerçekleşir; bu
map->l_info[DT_FINI_ARRAY]'i okur, array'i map->l_addr + d_un.d_ptr olarak hesaplar,
count'u DT_FINI_ARRAYSZ'den okur ve her entry'yi ters sırada bir function pointer
olarak çağırır, sonra legacy DT_FINI entry'sini onurlandırır. Bu pointer'lar
attacker'a ilgili link_map field'larından türetildiği için, onları corrupt etmek
exit-time walk'u bir arbitrary call'a çevirir — House of Banana ailesi.
Walkthrough¶
Üst düzey, public House of Banana write-up'ından ve glibc source'undan:
_rtld_global(loaded-objects list head'i) içindeki bir pointer'ı overwrite edebilen ve fake bir yapı sahneleyebilen bir write primitive elde et (write-up'lar genelde bir large-bin attack kullanır).- Field'ları traversal'ı karşılayan ve
l_info[DT_FINI_ARRAY]/DT_FINI_ARRAYSZ'i attacker-controlled bir function-pointer array'ine referans veren bir fakelink_maphazırla. - Fake node'u list'e splice et ki
_dl_fini()onu ziyaret etsin. - Process exit'ini tetikle (
main'den return /exit);_dl_call_fini()forge edilmiş finalizer'ları çağırır, control'ü yönlendirir (genelde bir one-gadget'a ya da ROP'a bir stack-pivot'a).
Tutarlı kalması gereken field'lar
l_real fake node'un kendisine işaret eder (l == l->l_real check'ini geçer),
l_init_called set, l_info[DT_FINI_ARRAY] geçerli bir Elf64_Dyn şeklindeki entry'ye
işaret eder ve küçük, eşleşen bir DT_FINI_ARRAYSZ. Tam offset'ler çıkarılmıştır.
Uygulanabilirlik
_rtld_global ld.so içinde yaşar, dolayısıyla teknik bir libc/loader leak'i ister ama
hiçbir IO/FSOP veya __free_hook gerektirmez. Kaynaklar glibc 2.23–2.36 boyunca
uygulanabilirlik bildirir (setcontext-tabanlı ORW chaining'i glibc ≥ 2.29 ister).
Detection¶
- Exit'te
_rtld_global/link_mapchain consistency'si (l_next/l_real) üzerinde integrity check'leri. - Large-bin pointer manipulation'ını flag'leyen heap-corruption detector'ları / hardened allocator'lar.
_dl_fini/_dl_call_fini'den non-text ya da heap adreslerine yönelen anormal control transfer'leri (CFI / telemetry).
Mitigation¶
- CFI / CET shadow stack'ler + IBT ile forge edilmiş finalizer pointer'ların indirect-call validation'ında başarısız olması.
- Full RELRO (GOT/relocation data'sını read-only yapar; linker-data tamper yüzeyini azaltır).
- Write primitive'ini reddetmek için allocator hardening (glibc large-bin pointer check'leri, safe-linking).
- Loader-internal sanity check'leri ve loader/glibc yapıları üzerinde ASLR.