ROP Development
Goal: produce reliable, reproducible chains — not one-shot lucky payloads. Build from ABI facts, memory disclosures, and deterministic gadget policies.
When to activate
- You need a chain for
ret2libc, ret2syscall, ret2csu, SROP, or Windows API-call ROP (VirtualProtect, NtProtectVirtualMemory)
- Exploit crashes exist but NX/DEP + ASLR/PIE prevent direct shellcode
- Gadget discovery returns too many noisy candidates and chain stability is poor
- A working chain breaks across OS versions or minor binary rebuilds
- You must reason about CET/Shadow Stack / CFG feasibility before investing in ROP
Core operating model
- Establish control primitive: RIP control + controllable stack window.
- Choose objective:
- Leak addresses (stage 1) for ASLR/PIE
- Invoke function/syscall with controlled arguments (stage 2)
- Change memory perms (RW->RX) or pivot to existing executable pages
- Collect gadgets deterministically (Ropper/ROPgadget/pwntools), score, then freeze selection.
- Assemble chain using exact ABI (register args, stack alignment, shadow space on Windows x64).
- Validate under debugger and rerun multiple times against same binary + randomized layouts.
- Generalize by replacing hardcoded addresses with leak-derived bases and symbol offsets.
Agentic execution loop (recommended)
- Survey pass: protections, ABI, candidate primitives, chain budget (input length / bad chars).
- Hypothesis: pick the shortest viable route (e.g.,
ret2libc vs ret2csu vs ret2dlresolve vs SROP).
- Prototype: build the smallest chain that proves one objective (single leak or single call).
- Instrument: log gadget addresses, leak bytes, parsed base, and alignment state (
rsp % 16).
- Replan: if a gate fails (canary, full RELRO, CET/CFG), switch route early rather than extending a broken chain.
- Stabilize: replay locally with randomization, then with remote-like libc/loader parity.
Chain patterns that actually survive
Leak-first (preferred)
- Stage 1: call a known print/write primitive (
puts@plt, write, etc.) on GOT/IAT pointer.
- Compute module base from leak.
- Stage 2: build final chain from base + offsets.
Use this by default on ASLR/PIE targets instead of guessing static offsets.
ret2libc / ret2syscall (Linux)
pop rdi; ret -> /bin/sh -> system, or
- syscall chain: set
rax=59, rdi=/bin/sh, rsi=0, rdx=0, then syscall; ret.
ret2csu (ELF with limited gadgets)
Use __libc_csu_init sequences to load multiple registers when clean pop gadgets are missing.
Windows API-call ROP
- Build register/stack state for
VirtualProtect or NtProtectVirtualMemory.
- Respect x64 calling convention and stack alignment.
- Prefer module-backed return sites/gadgets for better call-stack plausibility.
Mitigation-aware decisions
- NX/DEP on, no leak yet: prioritize infoleak stage.
- PIE + full ASLR: absolute gadget addresses are disposable; keep only relative offsets.
- Full RELRO: avoid GOT overwrite plans; use call-oriented chains/leaks instead.
- No/Partial RELRO:
ret2dlresolve can be a strong option when direct libc resolution/leaks are constrained.
- CET Shadow Stack: classic RET-chain often non-viable without a compatible bypass primitive.
- CFG (Windows): indirect call targets must pass CFG checks; prefer allowed call edges or syscall-oriented paths.
If CET/CFG blocks your intended path, pivot early to alternate technique (JOP/SROP/data-only).
Gadget quality rules
- Prefer shortest side-effect-free gadgets.
- Reject gadgets that clobber required registers unless immediately restored.
- Avoid random candidate picking: sort + score + choose deterministically.
- Preserve a strict fallback cascade (module A -> B -> C) when ideal gadget not found.
- Re-verify every selected gadget after binary/toolchain updates.
Reliability checklist
- Stack 16-byte aligned at each call boundary.
- Bad bytes filtered at payload generation time.
- Chain survives repeated runs (at least 20 local iterations).
- Leak parsing robust to partial output / newline differences.
- All hardcoded bases removed before finalization.
- Local environment mirrors target runtime (
libc/loader parity) before remote claims.
- Ifunc-sensitive offsets (
mem*, str* families) validated at runtime when relevant.
Debug loop
- Build minimal chain (single call objective).
- Break before first gadget; inspect stack and registers.
- Single-step gadget transitions; confirm intended side effects only.
- Expand chain one block at a time.
- Record failure class: bad pivot, alignment, clobber, wrong base, mitigations.
Anti-patterns
- Treating ROP as static addresses under ASLR/PIE.
- Overlong chains when a shorter call-oriented path exists.
- Mixing conventions (SysV vs Windows x64) in cross-platform exploits.
- Ignoring tool disagreement (Ropper vs ROPgadget) without byte-level verification.
- Shipping chains not tested under randomized layouts.
Resources
- references/tooling-and-workflow.md — Load when selecting gadget tooling, debugger flow, and leak/chain instrumentation.
- references/reliability-patterns.md — Load when chains work once but fail across runs, libc variants, or layout changes.
- references/examples-and-resources.md — Load for compact chain templates and common failure fixes such as alignment, IFUNC, CET, CFG, and leak instability.
- Upstream methodology:
offensive-techniques/binary-exploitation-technique (when to choose ROP vs data-only, chain staging) and offensive-ctf/pwn-ctf/references/rop.md (concrete chain recipes).
1---2name: rop-development-dev3description: Auth/lab dev: ROP chain research; gadget quality, calling conventions, pivots, leak-first ASLR labs, NX/DEP modeling, reliability.4license: MIT5---67# ROP Development89Goal: produce **reliable, reproducible chains** — not one-shot lucky payloads. Build from ABI facts, memory disclosures, and deterministic gadget policies.1011## When to activate1213- You need a chain for `ret2libc`, `ret2syscall`, `ret2csu`, SROP, or Windows API-call ROP (`VirtualProtect`, `NtProtectVirtualMemory`)14- Exploit crashes exist but NX/DEP + ASLR/PIE prevent direct shellcode15- Gadget discovery returns too many noisy candidates and chain stability is poor16- A working chain breaks across OS versions or minor binary rebuilds17- You must reason about CET/Shadow Stack / CFG feasibility before investing in ROP1819## Core operating model20211. **Establish control primitive**: RIP control + controllable stack window.222. **Choose objective**:23 - Leak addresses (stage 1) for ASLR/PIE24 - Invoke function/syscall with controlled arguments (stage 2)25 - Change memory perms (RW->RX) or pivot to existing executable pages263. **Collect gadgets deterministically** (Ropper/ROPgadget/pwntools), score, then freeze selection.274. **Assemble chain using exact ABI** (register args, stack alignment, shadow space on Windows x64).285. **Validate under debugger and rerun multiple times** against same binary + randomized layouts.296. **Generalize** by replacing hardcoded addresses with leak-derived bases and symbol offsets.3031### Agentic execution loop (recommended)32331. **Survey pass**: protections, ABI, candidate primitives, chain budget (input length / bad chars).342. **Hypothesis**: pick the shortest viable route (e.g., `ret2libc` vs `ret2csu` vs `ret2dlresolve` vs SROP).353. **Prototype**: build the smallest chain that proves one objective (single leak or single call).364. **Instrument**: log gadget addresses, leak bytes, parsed base, and alignment state (`rsp % 16`).375. **Replan**: if a gate fails (canary, full RELRO, CET/CFG), switch route early rather than extending a broken chain.386. **Stabilize**: replay locally with randomization, then with remote-like libc/loader parity.3940## Chain patterns that actually survive4142### Leak-first (preferred)4344- Stage 1: call a known print/write primitive (`puts@plt`, `write`, etc.) on GOT/IAT pointer.45- Compute module base from leak.46- Stage 2: build final chain from base + offsets.4748Use this by default on ASLR/PIE targets instead of guessing static offsets.4950### ret2libc / ret2syscall (Linux)5152- `pop rdi; ret` -> `/bin/sh` -> `system`, or53- syscall chain: set `rax=59`, `rdi=/bin/sh`, `rsi=0`, `rdx=0`, then `syscall; ret`.5455### ret2csu (ELF with limited gadgets)5657Use `__libc_csu_init` sequences to load multiple registers when clean `pop` gadgets are missing.5859### Windows API-call ROP6061- Build register/stack state for `VirtualProtect` or `NtProtectVirtualMemory`.62- Respect x64 calling convention and stack alignment.63- Prefer module-backed return sites/gadgets for better call-stack plausibility.6465## Mitigation-aware decisions6667- **NX/DEP on, no leak yet**: prioritize infoleak stage.68- **PIE + full ASLR**: absolute gadget addresses are disposable; keep only relative offsets.69- **Full RELRO**: avoid GOT overwrite plans; use call-oriented chains/leaks instead.70- **No/Partial RELRO**: `ret2dlresolve` can be a strong option when direct libc resolution/leaks are constrained.71- **CET Shadow Stack**: classic RET-chain often non-viable without a compatible bypass primitive.72- **CFG (Windows)**: indirect call targets must pass CFG checks; prefer allowed call edges or syscall-oriented paths.7374If CET/CFG blocks your intended path, pivot early to alternate technique (JOP/SROP/data-only).7576## Gadget quality rules7778- Prefer shortest side-effect-free gadgets.79- Reject gadgets that clobber required registers unless immediately restored.80- Avoid random candidate picking: **sort + score + choose deterministically**.81- Preserve a strict fallback cascade (module A -> B -> C) when ideal gadget not found.82- Re-verify every selected gadget after binary/toolchain updates.8384## Reliability checklist8586- Stack 16-byte aligned at each call boundary.87- Bad bytes filtered at payload generation time.88- Chain survives repeated runs (at least 20 local iterations).89- Leak parsing robust to partial output / newline differences.90- All hardcoded bases removed before finalization.91- Local environment mirrors target runtime (`libc`/loader parity) before remote claims.92- Ifunc-sensitive offsets (`mem*`, `str*` families) validated at runtime when relevant.9394## Debug loop95961. Build minimal chain (single call objective).972. Break before first gadget; inspect stack and registers.983. Single-step gadget transitions; confirm intended side effects only.994. Expand chain one block at a time.1005. Record failure class: bad pivot, alignment, clobber, wrong base, mitigations.101102## Anti-patterns103104- Treating ROP as static addresses under ASLR/PIE.105- Overlong chains when a shorter call-oriented path exists.106- Mixing conventions (SysV vs Windows x64) in cross-platform exploits.107- Ignoring tool disagreement (Ropper vs ROPgadget) without byte-level verification.108- Shipping chains not tested under randomized layouts.109110## Resources111112- [references/tooling-and-workflow.md](references/tooling-and-workflow.md) — Load when selecting gadget tooling, debugger flow, and leak/chain instrumentation.113- [references/reliability-patterns.md](references/reliability-patterns.md) — Load when chains work once but fail across runs, libc variants, or layout changes.114- [references/examples-and-resources.md](references/examples-and-resources.md) — Load for compact chain templates and common failure fixes such as alignment, IFUNC, CET, CFG, and leak instability.115- Upstream methodology: `offensive-techniques/binary-exploitation-technique` (when to choose ROP vs data-only, chain staging) and `offensive-ctf/pwn-ctf/references/rop.md` (concrete chain recipes).