ret2csu
TL;DR: The compiler-emitted
__libc_csu_initfunction in any non-PIE x86_64 ELF contains two gadgets that set rbx, rbp, r12–r15 and then call[r12+rbx*8]— enough to satisfy the SysV calling convention without an exhaustive gadget search.
What it is
ret2csu is a return-orientated programming primitive published by Marco-Alvarez (HITB 2018) that abuses the loop epilogue and prologue inside __libc_csu_init, the static initialiser GCC links into every x86_64 ELF using glibc. Because every binary contains it, the gadget pair is “universal” — exploits can call any imported function (e.g. system, execve) without finding pop rdi, pop rsi, pop rdx gadgets individually.
Preconditions / where it applies
- Non-PIE x86_64 ELF (or PIE with a binary-base leak)
- glibc-linked binary built with classic SysV
_init— most pre-LTO targets - Stack-pivot or buffer overflow primitive that can place at least ~7 qwords of controlled data
Technique
The two gadgets:
1
2
3
4
5
6
7
8
9
10
11
12
gadget_pop:
pop rbx ; pop rbp ; pop r12 ; pop r13 ; pop r14 ; pop r15 ; ret
gadget_call:
mov rdx, r15
mov rsi, r14
mov edi, r13d
call qword [r12 + rbx*8]
add rbx, 1
cmp rbp, rbx
jne gadget_call_start
; epilogue restores rbx..r15 and returns
Chain layout (right-to-left as it gets pushed):
gadget_pop0→ rbx1→ rbp (socmp rbp, rbx+1is equal and loop exits)&GOT[target]→ r12 (pointer to fn pointer)arg1→ r13 (lands in edi — 32-bit!)arg2→ r14 (→ rsi)arg3→ r15 (→ rdx)gadget_call- epilogue padding (7 qwords)
- next-stage return (e.g. ret2libc to
system("/bin/sh"))
Common follow-up: call gets@plt first to read a second-stage chain into .bss, then pivot.
Detection and defence
- PIE + FORTIFY + RELRO: PIE forces the gadget to depend on a leak; FULL RELRO removes writable GOT
- Compile-time hardening (
-Wl,-z,now,-fcf-protection=full) — Intel CET IBT marks indirect-call targets and breaks thecall [r12+rbx*8]step on CET-capable CPUs - Newer GCC + LLD strip
__libc_csu_initwhen--no-call-graph-profile-sortand_init/_finiare inlined; that’s why the technique fails on many recent binaries - Static signatures: ROP detectors flag the 7-pop epilogue followed by the indirect call
References
- Original paper (Marco-Alvarez) — the technique introduction
- HackTricks: ret2csu — worked walkthrough
- PayloadsAllTheThings: Linux ROP — chain patterns
Related: ret2libc, srop, heap-exploitation-linux