Skip to content

ret2csu without __libc_csu_init

glibc 2.34+'ta klasik __libc_csu_init "universal gadget"'ı yoktur, dolayısıyla ret2csu-tarzı argüman yükleme bunun yerine başka CRT/libc rutinlerinden (örn. setcontext-benzeri ya da geniş register-restore gadget'ları) sağlanmalıdır.

Mechanism

Invariant

ret2csu, __libc_csu_init içinde compiler-emitted bir epilogue'a dayanıyordu; bu epilogue her non-PIE glibc binary'sinde güvenilir şekilde görünüyor ve attacker'lara rdx'in (kıt üçüncü System V argument register'ı) kontrolünü veriyordu. glibc 2.34'ten itibaren C startup kodu hardened edildi: __libc_csu_init artık emit edilmiyor ve startup __libc_start_main / __libc_start_call_main etrafında yeniden düzenlendi. glibc 2.34+'a karşı build edilen binary'ler (örn. Ubuntu 22.04'ün 2.35'i) bu yüzden universal pop rdi/rsi + mov rdx,...; call gadget çiftinden yoksundur.

Kırılan invariant availability'dir: teknik hiçbir zaman bir memory-safety sınırı olmadı, toolchain'in garanti ettiği bir kolaylıktı. Garantili gadget'ı kaldırmak argüman yüklemeyi durdurmaz — sadece attacker'ı hedef binary'de ya da map'lenmiş kütüphanelerde eşdeğer bir register-loading primitive'i başka yerde bulmaya zorlar. Savunma değeri şudur: küçük/static binary'ler kolay rdx kontrolünü kaybeder, bu da mprotect/write-tarzı 3-argümanlı call'lar için çıtayı yükseltir.

Walkthrough

Klasik CSU gadget'ı yokken high-level seçenekler:

  1. Gadget'ları libc'nin kendisinden sağla. Bir libc base leak ile, yüklü libc'de pop rdx; ret, pop rdx; pop r12; ret ya da mov rdx, ...; ret tarzı sequence'lar ara. CRT epilogue'u gitmiş olsa bile libc'de bir yerde mevcutturlar.

  2. Geniş bir register-restore gadget'ı kullan. setcontext-tarzı rutinler (ve setcontext/swapcontext ailesi), tek bir kontrollü register'ın işaret ettiği bir bellek bloğundan, uygun glibc versiyonlarında rdx dâhil birçok register yükler. Bu ret2csu'yu kapsar — bkz. setcontext-magic-gadget-pivot.

  3. Hedefte artık bir CSU-benzeri gadget bul. Bazı binary'ler hâlâ başka static object'lerden benzer bir mov reg, regN; call [...] epilogue'u içerir; gittiğini varsaymak yerine asıl hedefi disassemble et.

# conceptual: prefer a single powerful gadget over the old CSU pair
[ leak libc base ]              # required since gadgets now live in libc
[ pop rdi; ret ] -> &ctx        # point at attacker-built register block
[ setcontext+off ]             # bulk-load rdx/rsi/rdi/rsp from the block
Üçüncü argüman neden bütün meseleydi

mprotect(addr, len, PROT_RWX) ve write(fd, buf, n) gibi call'lar rdx'e ihtiyaç duyar. Klasik CSU gadget'ının değeri, rdx'i adanmış bir pop rdx olmadan ayarlamasıydı. Modern chain'ler bu tek numarayı ya bir libc pop rdx gadget'ı (bir leak'ten sonra) ya da tek seferlik bir context loader ile değiştirir.

Versiyon ve build özellikleri

__libc_csu_init'in varlığı/yokluğu, kesin setcontext register layout'u ve herhangi bir artık gadget kesinlikle versiyona ve build'e bağlıdır. Her zaman gadget'ları asıl hedef image'da enumerate et; offset'leri varsayma.

Detection

  • Kendisi bir bug değildir — altta yatan overflow'u (ASan, stack canary'ler) ve ROP chain'i runtime'da CFI / Intel CET shadow stack + IBT üzerinden tespit et.
  • Non-standard call site'lardan setcontext/swapcontext'e indirect transfer'lar ya da rdx'i yükleyip hemen mprotect çağıran chain'ler şüpheli telemetry'dir.

Mitigation

  • glibc 2.34 hardening'inin kendisi klasik gadget için mitigation'dır — libc'yi güncel tut.
  • PIE + ASLR ki libc/binary gadget adresleri bir leak gerektirsin.
  • Intel CET (shadow stack + IBT) ve compiler CFI, ROP return'lerini ve bu chain'lerin dayandığı indirect call'ları kırar.
  • Full RELRO ve seccomp ile, geri kazanılan bir argüman-yüklemenin ne kazandırdığını kısıtla (örn. mprotect'i blokla).

References

Ayrıca bkz: ret2csu, setcontext-magic-gadget-pivot, ret2mprotect, one-gadget.