🔥 Advanced

ROP Chains

Return-Oriented Programming (ROP) is an exploit technique that allows an attacker to execute code in the presence of security defenses such as non-executable memory (NX/DEP).

The Problem: NX/DEP

Modern operating systems mark the stack as non-executable (NX bit). This means even if you can overwrite EIP and jump to your shellcode on the stack, the CPU will refuse to execute it and crash the program.

The Solution: Code Reuse

Instead of injecting new code, ROP reuses existing code chunks (gadgets) already present in the binary or loaded libraries (like libc). These gadgets typically end with a `ret` instruction.

Gadgets

A gadget is a small sequence of instructions ending in `ret`. By chaining these gadgets on the stack, an attacker can perform arbitrary operations.

asm

# Example Gadgets
0x4005a0: pop rdi; ret
0x4005a2: pop rsi; ret
0x4005a4: pop rdx; ret
  

The Stack as a Program

In ROP, the stack pointer (RSP/ESP) acts as the instruction pointer. The `ret` instruction pops the next value off the stack and jumps to it.

ROP Chain Execution Flow

  1. Attacker overwrites Return Address with Address of Gadget 1.
  2. Function returns -> Jumps to Gadget 1.
  3. Gadget 1 executes (e.g., `pop rdi`) -> Pops value from stack into RDI.
  4. Gadget 1 returns -> Jumps to Gadget 2 (next address on stack).
  5. ...and so on.

Common Goals

  • ret2libc: Call `system("/bin/sh")` using gadgets to set up arguments (RDI, RSI, RDX) and then jump to `system` address in libc.
  • mprotect: Call `mprotect` to change memory permissions of the stack to RWX (Read-Write-Execute), then jump to shellcode.
  • Write Primitive: Use gadgets like `mov [rdi], rsi; ret` to write data to arbitrary memory locations.

Tools & Usage

ROPgadget

bash

# Find gadgets
ROPgadget --binary vuln_binary

# Search for specific instructions
ROPgadget --binary vuln_binary | grep "pop rdi"

# Generate a chain automatically (sometimes works)
ROPgadget --binary vuln_binary --ropchain
  

Ropper

bash

ropper --file vuln_binary --search "pop rdi"
  

Example: ret2libc (x64)

To call `system("/bin/sh")` on x64 Linux, we need: 1. `rdi` = address of "/bin/sh" string. 2. Address of `system` function.

python

from pwn import *

# ... setup context ...

rop = ROP(elf)
pop_rdi = rop.find_gadget(['pop rdi', 'ret'])[0]
bin_sh = next(libc.search(b'/bin/sh'))
system = libc.symbols['system']

payload = flat(
    b"A" * offset,
    pop_rdi,
    bin_sh,
    system
)