Skip to content

PTR_MANGLE / pointer guard bypass

glibc'in pointer_guard'ını (fs:0x30'da) geri kazanmak; böylece PTR_MANGLE korumasına rağmen mangled function pointer'lar — exit handler'lar, TLS destructor'lar, _IO_cookie callback'leri — forge edilebilir.

Mechanism

Invariant

glibc bazı saklanan function pointer'ları pointer mangling ile korur. PTR_MANGLE makrosu bir pointer'ı yazılabilir belleğe yazılmadan önce dönüştürür, PTR_DEMANGLE ise pointer kullanılmadan (örn. call edilmeden) hemen önce dönüşümü tersine çevirir. x86-64'te şema şudur:

  • PTR_MANGLE(p) = rol( p XOR guard, 0x11 ) — gizli pointer_guard ile XOR, ardından 17 bit sola rotate.
  • PTR_DEMANGLE(p) = ( ror(p, 0x11) ) XOR guard — 17 bit sağa rotate, ardından XOR.

Gizli guard, Thread Control Block içinde fs:0x30'da yaşar ve process başlangıcında kernel'in sağladığı entropy'den (AT_RANDOM) initialize edilir. Güvenlik sınırı şudur: bir mangled pointer slot'unu bozan bir attacker (örn. __exit_funcs ya da bir TLS dtor_list içine heap overflow ile), byte'larının hangi cleartext adrese demangle olacağını tahmin edemez, dolayısıyla control flow'u hedefleyemez.

Attacker guard'ı öğrenirse bu sınır çöker. XOR ve rotation tam olarak tersinir olduğundan, bir tane leak edilmiş (mangled, known-cleartext) çift gizliyi tamamen açığa çıkarır:

guard = ror(mangled, 0x11) XOR known_plaintext_pointer

O andan itibaren attacker herhangi bir hedef adresi kendisi mangle edip ona demangle olan bir forged pointer yazabilir.

Walkthrough

Tek bir leak'ten high-level recovery (örn. initial/__exit_funcs içindeki mangled bir _dl_fini girdisinin arbitrary read'i; cleartext adresi bir libc base leak'ten hesaplanabilir):

# pseudo-recovery, conceptual
guard   = ror(leaked_mangled_ptr, 0x11) ^ (libc_base + dl_fini_offset)
# now forge any pointer:
forged  = rol(target_addr ^ guard, 0x11)

Yaygın bir chain bunu exit-handler-hijack-via-ptr-mangle-bypass ile eşler: bir exit_function slot'unu forged ile overwrite et, böylece exit() çağrısında glibc onu target_addr'a geri demangle eder ve çağırır.

NULL/known-cookie kısayolu

Guard sıfırlanabiliyor ya da bilinen bir değere ayarlanabiliyorsa (örn. bir arbitrary write fs:0x30'u null'lar, ya da eski/zayıf bir initialization), mangling saf bir rotation'a indirgenir. O zaman hiçbir leak gerekmez — attacker hedefi basitçe önceden rotate eder:

forged = rol(target_addr, 0x11) (guard == 0 olduğunda)

Kapsam ve uyarılar

  • glibc pointer'larının yalnızca bir kısmı mangle edilir (exit handler'lar, tls_dtor_list, bazı jmp_buf/__libc_start_main callback'leri). GOT girdileri, vtable'lar ve çoğu heap function-pointer mangle edilmez — bunlara bu adım olmadan doğrudan saldırılır.
  • Rotate miktarı (0x11) ve fs:0x30 offset'i x86-64'e özgüdür; diğer mimariler farklıdır. Kesin offset'leri versiyona/mimariye bağlı say.
  • Tarihsel olarak CVE-2013-4788, guard'ı başlangıçta sabit/sıfır bir değerde bırakılmış statically linked binary'ler için PTR_MANGLE'ın etkisiz olduğunu gösterdi (glibc 2.4–2.17 static build'leri). Ayrıca LD_POINTER_GUARD env değişkeni tarihsel olarak set-uid program'larda bile dikkate alınıyordu — yanlış yapılandırılmış privileged binary'lerde guard env'den sabitlenebilirdi.

Detection

  • Bir process __run_exit_handlers/__call_tls_dtors'tan beklenmedik bir adrese çağrı yapmadan kısa süre önce TCB'ye komşu belleğin (fs:0x30) ya da libc exit-handler yapılarının anomalik okunması.
  • Attacker verisine inen, rol(x,0x11) pattern'leriyle tutarlı bir değer taşıyan crash'ler/control-flow transfer'ları; EDR, hedefi yazılabilir bir mapping'de olan indirect call'ları işaretleyebilir.
  • Mangled slot'u bozan upstream overflow'u yakalayan stack/heap canary ve ASan instrumentation.

Mitigation

  • ASLR/PIE'yi güçlü tut ve info leak'lerden kaçın — libc-base + known-plaintext leak olmadan guard geri kazanılamaz.
  • pointer_guard'ın düzgün seed edildiğinden emin ol (modern glibc; CVE-2013-4788 static-binary regression'ı düzeltildi).
  • Full RELRO ve hardened allocator'lar, mangled slot'lara ulaşan corruption primitive'lerini azaltır.
  • Intel CET shadow stack / IBT ve CFI, bir pointer forge edilse bile nihai indirect call'ı kırar.

References

Ayrıca bkz: exit-handler-hijack-via-ptr-mangle-bypass, address-leak, arbitrary-write-primitive.