TL;DR
A buffer overflow attack lets you overwrite parts of a program’s memory to change how it works. This guide shows how an attacker can use this to make the program run code that wasn’t meant to be executed, specifically an uncalled function within the program itself.
Understanding the Attack
Buffer overflows happen when a program writes data beyond the allocated space for a buffer. This overwrites adjacent memory locations, potentially changing important values like return addresses or function pointers. In this scenario, we’ll focus on overwriting the return address to point to an uncalled function within the same executable.
Prerequisites
- A vulnerable program (compiled C code example provided below).
- Basic understanding of assembly language and stack frames.
- Debugging tools like GDB or a similar debugger.
Vulnerable Program Example (C)
#include <stdio.h>
#include <string.h>
void secret_function() {
printf("Secret function executed!n");
}
int main(int argc, char *argv[]) {
char buffer[64];
if (argc > 1) {
strcpy(buffer, argv[1]);
}
printf("Buffer contents: %sn", buffer);
return 0;
}
This program has a classic buffer overflow vulnerability in the strcpy function. It copies user input into a fixed-size buffer without checking its length.
Steps to Exploit
- Identify the Offset: Determine how many bytes you need to write before overwriting the return address on the stack.
- Run the program in a debugger (e.g., GDB).
- Set a breakpoint after the
strcpycall. - Examine the stack using commands like
info frameorx/20xw $rspto find the return address. - Calculate the distance between the beginning of the buffer and the return address. This is your offset. In this example, it will likely be around 72 bytes (64 for the buffer + some padding).
- Find the Address of the Uncalled Function: Locate the memory address of the function you want to execute.
- Use a debugger or disassembler (e.g.,
objdump -d executable_name) to find the starting address ofsecret_function(). - Note this address; it will be needed in the next step.
- Use a debugger or disassembler (e.g.,
- Craft the Payload: Create a string that overwrites the return address with the address of the uncalled function.
- The payload will consist of:
- Padding to fill the buffer up to the return address. This is usually ‘A’ characters.
- The address of
secret_function(), in little-endian format (because most systems are little-endian).
- Example payload (assuming offset is 72 and function address is 0x401166):
"A" * 72 + "x66x11x40x00"
- The payload will consist of:
- Execute the Attack: Run the program with the crafted payload as input.
- In this example:
./vulnerable_program $(python3 -c 'print("A" * 72 + "x66x11x40x00")') - The program should now execute the
secret_function().
- In this example:
Important Considerations
- Address Space Layout Randomization (ASLR): ASLR randomizes memory addresses, making it harder to predict the address of functions. Bypassing ASLR often requires information leaks or other techniques.
- Stack Canaries: Stack canaries are values placed on the stack to detect buffer overflows. Overwriting a canary will cause the program to terminate.
- Non-Executable Stack (NX bit): The NX bit prevents code execution from the stack, making it harder to inject and run shellcode directly.

