Overview

Overview of official_template.py found in cryptocat’s github.

Python Exploitation Template (pwntools)

This script is a general-purpose binary exploitation skeleton designed for vulnerability research and Capture the Flag (CTF) challenges. It leverages pwntools to streamline tasks such as process launching, debugging, and payload construction.


Imports

from pwn import *
  • Imports the pwntools library, which provides utilities for exploitation:
    • Process interaction (process, remote).
    • Payload generation (cyclic, flat).
    • Debugger integration (gdb.debug).
    • ELF binary inspection (ELF).

Execution Context Management

def start(argv=[], *a, **kw):
    if args.GDB:
        return gdb.debug([exe] + argv, gdbscript=gdbscript, *a, **kw)
    elif args.REMOTE:
        return remote(sys.argv[1], sys.argv[2], *a, **kw)
    else:
        return process([exe] + argv, *a, **kw)
  • Purpose: Provides a flexible way to launch the binary in three modes:
    • --GDB: Run the binary under GDB with a predefined script.
    • --REMOTE: Connect to a remote service with remote(host, port).
    • Default: Launches the binary locally.
  • Benefit: Single function to handle local debugging, remote exploitation, and automated testing without modifying the code.

Finding Instruction Pointer (EIP/RIP) Offset

def find_ip(payload):
    p = process(exe, level='warn')
    p.sendlineafter(b'>', payload)
    p.wait()
    # ip_offset = cyclic_find(p.corefile.pc)  # x86
    ip_offset = cyclic_find(p.corefile.read(p.corefile.sp, 4))  # x64
    warn('located EIP/RIP offset at {a}'.format(a=ip_offset))
    return ip_offset
  • Purpose: Identifies the offset to the instruction pointer (EIP on x86, RIP on x64).
  • Workflow:
    1. Launches the vulnerable binary with reduced logging (warn level).
    2. Sends a cyclic pattern as input to trigger a buffer overflow.
    3. Waits for the crash, then reads the crash address from the core dump.
    4. Uses cyclic_find to compute the exact offset where execution control is overwritten.
  • Notes:
    • p.corefile.pc: Program counter (for x86).
    • p.corefile.read(p.corefile.sp, 4): Reads 4 bytes from stack pointer (for x64).
    • Essential for payload construction, as it determines where to place the return address overwrite.

Debugger Script

Can be modified by adding breakpoints in key areas for register/memory analysis.

gdbscript = '''
init-pwndbg
continue
'''.format(**locals())
  • Purpose: Preloaded GDB script for debugging.
  • init-pwndbg: Loads pwndbg extensions.
  • continue: Immediately continues execution upon debugger start.
  • Benefit: Eliminates repetitive GDB setup during iterative testing.

Binary and ELF Context

Modify this depending on binary name, level of logging.

exe = './vuln'
elf = context.binary = ELF(exe, checksec=False)
context.log_level = 'debug'
  • exe: Path to the target binary.
  • ELF: Loads binary into pwntools’ ELF object for symbol resolution.
  • checksec=False: Skips security feature checks (NX, PIE, RELRO) for faster loading.
  • context.log_level = 'debug': Provides verbose runtime output for troubleshooting.

Exploit Development Section

Modify this to match the remote target’s libc library.

# Lib-C library, can use pwninit/patchelf to patch binary
# libc = ELF("./libc.so.6")
# ld = ELF("./ld-2.27.so")
  • Placeholder for loading external libc and dynamic loader files.
  • Useful when dealing with remote binaries where custom libc is required.
  • Tools:
    • pwninit: Automates patching binaries with correct libc.
    • patchelf: Manually patches binary’s dynamic dependencies.

Finding Offset

offset = find_ip(cyclic(500))
  • Generates a cyclic pattern of 500 bytes.
  • Calls find_ip() to determine instruction pointer overwrite offset.
  • Output: An integer representing the exact location in the buffer where RIP/EIP is overwritten.

Exploit Execution

io = start()
  • Starts the target process depending on the chosen mode (GDB, REMOTE, or local).

Payload Construction

Add payload here.

payload = flat({
    offset: [
 
    ]
})
  • flat(): Creates a structured payload with precise control over offsets.
  • Key Idea: Place exploit primitives at the correct buffer offset.
  • Example Payloads (to be added depending on technique):
    • Shellcode.
    • Return-to-libc (system + “/bin/sh”).
    • ROP chains.
    • Jump to win() function.

Payload Delivery

Modify this depending on binary’s prompt.

io.sendlineafter(b'>', payload)
io.recvuntil(b'Thank you!')
io.interactive()
  • sendlineafter: Waits for prompt > before sending payload.
  • recvuntil: Ensures synchronization by reading output up to Thank you!. Could use recvall()
  • interactive(): Drops into an interactive shell if exploitation is successful.

Key Takeaways

  1. Template Usage: Flexible, modular structure suitable for CTF and real-world exploitation.
  2. Offset Discovery: Automates the tedious process of finding buffer overflow offsets.
  3. GDB Integration: Streamlines debugging with pwndbg and predefined scripts.
  4. Payload Building: Provides a clean scaffold for various exploitation techniques (ROP, shellcode injection, ret2libc).
  5. Remote Support: Easily switches between local and remote environments for exploit testing.

Resources