Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
A direct command skips the review prompt. Inspect the source before running it.
During authorized exploitation when you control the saved return address (via stack overflow, write-what-where, etc.)
but NX/DEP prevents executing injected shellcode on the stack.
When you need to call an existing function (system, execve, mprotect) or invoke a syscall with attacker-chosen
arguments by chaining small ...; ret gadgets.
When choosing between ret2libc (call a libc function), ret2syscall (raw sys_execve, common in static binaries),
ret2dlresolve, SROP (when gadgets are scarce), or stack pivoting (off-by-one / short overflows).
On ARM64 targets where ret jumps to x30 and instructions cannot be entered mid-instruction, requiring JOP or
pivot-based approaches.
Critical: Concepts/Steps Most Often Missed
16-byte stack alignment on x86-64. The SysV ABI requires RSP be 16-byte aligned at a call. libc functions use
SSE (movaps) and will SIGSEGV if misaligned. If system() crashes inside libc, insert a bare ret gadget before
it to realign. This is the single most common reason a "correct" chain crashes.
Argument passing differs by arch/ABI. x86 cdecl pushes args on the stack (right-to-left); x86-64 SysV uses
RDI, RSI, RDX, RCX, R8, R9; Windows x64 uses RCX, RDX, R8, R9. You need pop rdi; ret-style gadgets to load
registers, not just stack values.
The function needs a return slot. After system you must place a return address (e.g. exit) or the chain
crashes on system's own return. CTFs often get away with garbage, real targets do not.
ARM64 entry-point pitfall. When jumping to a function via ROP on ARM64, jump to the function's second
instruction to avoid re-storing the stack pointer and looping forever.
NUL bytes and bad chars in gadget addresses. A pop rdi; ret gadget at 0x400686 is fine, but addresses with
NULs break string-copy overflows. Pick alternate gadgets or use ret2dlresolve/SROP.
How to CONFIRM
Confirm gadget control in gdb: set a breakpoint at the ret of the vulnerable function, single-step into the first
gadget, and verify each register holds the intended value (, ) before the /. Confirm the
final primitive by observing the spawned shell ( yields an interactive ) or, for , by
checking the target page is now in . A chain that returns cleanly but spawns nothing usually means an
alignment or argument-register error, not a missing gadget.
When the libc base is unknown/remote, first leak it (e.g. ROP-call puts(puts@got) to leak puts's runtime address),
identify the version at libc.blukat.me, then set libc.address = leak - libc.symbols['puts'].
Step 3: ret2syscall — Raw execve (static binaries)
ROPgadget --binary vuln --ropchain auto-generates such a chain. If gadgets are scarce, use SROP to set every register
from a forged sigcontext frame.
Step 4: Handle Alignment, one_gadget, and Re-use
# After leaking libc, a single-shot shell gadget avoids argument setup
one_gadget ./libc.so.6 # prints constraints (e.g. [rsp+0x40]==NULL) — satisfy them
# Make the bug reusable: return to main() / the vuln to leak then exploit in two passes
payload += p64(elf.symbols['main'])
For JOP (ARM64 / no ret gadgets), chain gadgets ending in br xN. For off-by-one or tiny overflows, pivot the stack
(mov sp, x0-style or leave; ret) into a controlled buffer holding the full chain.
Key Concepts
Concept
Description
Gadget
A short instruction sequence ending in ret (ROP) or br/jmp (JOP), reused as a building block.
ret2libc
Redirect execution to a library function (e.g. system) with crafted arguments instead of shellcode.
ret2syscall
Set up registers and invoke a raw syscall (e.g. execve); common in static binaries with many gadgets.
Calling convention
x86 cdecl (stack args), x86-64 SysV (RDI/RSI/RDX/RCX/R8/R9), Windows x64 (RCX/RDX/R8/R9).
Stack alignment
x86-64 requires RSP 16-byte aligned at a call; fix with an extra ret gadget.
one_gadget
A single libc address that execs /bin/sh if certain register/memory constraints hold.
SROP
Sigreturn-Oriented Programming: forge a sigcontext to load all registers at once when gadgets are scarce.
Stack pivoting
Redirect RSP/SP to a controlled region (heap/buffer) to run a chain that didn't fit in the overflow.
JOP
Jump-Oriented Programming: gadgets end in indirect jumps; used on ARM where ret is uncommon.
Tools & Systems
Tool
Purpose
ROPgadget
Find gadgets, search by pattern, auto-build execve chains (--ropchain).
ropper
Alternative gadget finder; works on .so/.dylib, semantic search (e.g. --search "mov x0").
iOS/macOS: list loaded images and extract libraries to mine gadgets.
Common Scenarios
Scenario 1: NX-enabled CTF, known libc
Overflow with offset 72; chain ret (align) -> pop rdi; ret -> &/bin/sh -> system. The alignment ret is the
difference between a shell and a crash inside movaps.
Scenario 2: Remote, unknown libc
ROP-call puts(puts@got) to leak the runtime address of puts, fingerprint the libc version online, rebase, then send
a second-stage chain calling system("/bin/sh") or a one_gadget.
Scenario 3: Statically linked binary
No libc to call, but abundant gadgets. Plant /bin/sh in a writable .data/.bss page with a write-what-where gadget,
set rax=59, args, and syscall to execve.
Scenario 4: ARM64 with NX
No useful ret gadgets; use JOP gadgets ending in br x2 loaded from a controlled heap object, or a stack pivot
(mov sp, x0; ... ret) to relocate the stack onto the controlled buffer, then run an mprotect+shellcode chain.
Output Format
## ROP Exploitation Finding
**Vulnerability**: Stack overflow exploited via Return-Oriented Programming (CWE-121 + CWE-787)
**Severity**: Critical (arbitrary code execution, bypasses NX/DEP)
**Binary**: ./vuln (x86-64, NX enabled, No PIE, No canary)
### Control & Chain
- Overflow offset to saved RIP: 72
- Gadgets: ret @0x40101a, pop rdi;ret @0x401213
- Path: ret2libc -> system("/bin/sh") with exit() return slot
- Alignment: extra `ret` inserted to satisfy 16-byte ABI alignment
### Proof
Chain executed system("/bin/sh"); obtained interactive shell as service user (id: uid=1000).
### Impact
Full arbitrary code execution despite non-executable stack.
### Recommendation
1. Eliminate the underlying memory-corruption bug (bounded copies, input validation).
2. Enable Full RELRO, PIE/ASLR, and stack canaries to raise the cost of gadget reuse.
3. Adopt CET/shadow-stack (Intel) or PAC/BTI (ARM) where available to break ROP/JOP.
4. Minimize statically linked, gadget-rich binaries; keep libc/ASLR entropy high.