Return-Oriented Programming (ROP) is an exploitation technique that bypasses non-executable memory protections by chaining together small code sequences (gadgets) ending in return instructions, already present in the program or libraries.
Instead of injecting shellcode, the attacker controls the stack to chain addresses of existing code snippets (gadgets). Each gadget performs a small operation and returns, jumping to the next gadget's address on the stack.
Stack Layout:
┌─────────────────┐
│ gadget1 address │ → pop rdi; ret
├─────────────────┤
│ "/bin/sh" addr │ → value for rdi
├─────────────────┤
│ gadget2 address │ → pop rax; ret
├─────────────────┤
│ 0x3b (execve) │ → syscall number
├─────────────────┤
│ gadget3 address │ → syscall; ret
└─────────────────┘
Result: execve("/bin/sh", 0, 0)
# Using ROPgadget
ROPgadget --binary ./vulnerable_app
# Using ropper
ropper --file ./vulnerable_app --search "pop rdi"
# Common useful gadgets:
pop rdi; ret # Load argument 1
pop rsi; ret # Load argument 2
pop rax; ret # Load syscall number
syscall; ret # Trigger syscall