TL;DR
This guide shows you how to calculate the address where your shellcode needs to be placed in a vulnerable program’s memory to successfully exploit a buffer overflow. We’ll cover debugging techniques and practical steps using GDB.
Understanding the Problem
A buffer overflow happens when a program writes data beyond the allocated space of a buffer. Exploiters use this to overwrite important parts of the program’s memory, like the return address on the stack. By controlling the return address, you can redirect execution to your shellcode – malicious code that performs actions like spawning a shell.
Steps to Find Your Shellcode Address
- Compile the Vulnerable Program: Ensure the program is compiled with debugging symbols (-g flag) for easier analysis. For example:
gcc -g vulnerable_program.c -o vulnerable_program - Identify the Buffer: Locate the buffer in the source code that’s susceptible to overflow. This is where you’ll be injecting your shellcode.
- Determine the Offset to the Return Address: Use a debugger (like GDB) to find how many bytes you need to write before overwriting the return address on the stack. A common technique involves sending a pattern of unique characters and observing where it lands on the stack.
- Start GDB:
gdb vulnerable_program - Set a breakpoint just before the return from the vulnerable function:
break vulnerable_function - Run the program with a pattern (e.g., using
msf-pattern_create):./vulnerable_program AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA - When the breakpoint is hit, examine the stack:
info frameLook for the return address. The pattern should be visible there.
- Use a pattern matching tool (e.g.,
msf-pattern_offset) to find the offset of the return address within your pattern:msf-pattern_offset AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
- Start GDB:
- Find the Base Address of the Program: The base address is where the program is loaded into memory. This changes each time you run the program, so it’s important to find it dynamically.
- In GDB, after setting a breakpoint in the vulnerable function:
info filesThis will show you the executable file and its loading address. Note this address; it’s your base address.
- In GDB, after setting a breakpoint in the vulnerable function:
- Calculate the Shellcode Address: The shellcode address is calculated by adding the offset to the return address (from step 3) to the base address of the program (from step 4).
- Let’s say:
- Base Address = 0x555555554000
- Offset to Return Address = 28 bytes
- Shellcode will be placed at the beginning of the buffer.
- Then, Shellcode Address = Base Address + Offset.
In this example: 0x555555554000 + 28 = 0x555555554028. This is where you need to place your shellcode in memory.
- Let’s say:
- Inject Shellcode and Return Address: Construct the payload containing your shellcode, padding bytes (to reach the return address), and the calculated shellcode address.
- Example Payload:
shellcode + "A" * (offset - len(shellcode)) + pack(shellcode_address)
- Example Payload:
- Test the Exploit: Run the program with your crafted payload. If successful, you should gain control of the shell.
Important Considerations
- Address Space Layout Randomization (ASLR): ASLR randomizes the base address each time the program runs. To bypass this, techniques like information leaks are often used to determine the base address at runtime.
- Non-Executable Stack: Modern systems typically prevent code execution from the stack. You may need to disable this protection (e.g., using
setarch -R) or use Return-Oriented Programming (ROP) techniques.

