TL;DR
This guide shows you how to find the memory address of your shellcode and use it as input for a buffer overflow exploit. We’ll cover using GDB (GNU Debugger) to locate the address, then crafting an input string that includes this address so the program overwrites its return pointer with it.
Finding the Shellcode Address
- Compile your vulnerable program: Make sure you compile without stack protection and ASLR (Address Space Layout Randomisation) for simplicity. For example:
gcc -fno-stack-protector -z execstack vulnerable_program.c -o vulnerable_program - Start GDB: Launch the debugger with your program.
gdb vulnerable_program - Set a breakpoint: Set a breakpoint just *before* the buffer copy function (e.g., `strcpy`, `memcpy`) is called. This lets you inspect memory before it’s overwritten.
break main - Run the program: Start execution.
run - Locate shellcode in memory: Once at the breakpoint, find where your shellcode is loaded into memory. You can do this by searching for the unique byte sequence of your shellcode. For example, if your shellcode starts with `x31c0`, use:
search 31 c0 - Note the address: GDB will show you addresses where that byte sequence is found. The relevant address is usually on the stack, and it’s important to note this *exact* address (e.g., `0xbffff780`). This is your shellcode’s starting address.
Crafting the Overflow Input
- Determine buffer size: Find out how much data your program allows into the vulnerable buffer. You can often do this by running the program with a pattern (e.g., using `msf-pattern_create` from Metasploit) and then observing where it crashes.
- Calculate offset to return address: Figure out how many bytes you need to send *before* overwriting the saved return address on the stack. This depends on your program’s architecture (32-bit or 64-bit). For a typical 32-bit system, this is often around 4 bytes; for 64-bit, it’s usually 8 bytes.
- Create the input string: Build your input string. It will consist of:
- Padding to fill the buffer.
- The shellcode address (in little-endian format).
- Any remaining padding needed to complete the overflow.
- Little-Endian Conversion: Remember that most systems use little-endian byte order. This means you need to reverse the order of bytes in your shellcode address.
# Example for address 0xbffff780 (32-bit)# Little endian: x80xf7xffxbf - Example Input String (Python): This example assumes a 4-byte offset to the return address.
padding = b'A' * 20 # Adjust length as neededshellcode_address = b'x80xf7xffxbf' # Little endian format of 0xbffff780overflow_input = padding + shellcode_address - Send the input: Provide this crafted input string to your vulnerable program. This can be done through standard input, a file, or network connection depending on how the program is designed.
Important Considerations
- ASLR: If ASLR is enabled, the shellcode address will change each time you run the program. You’ll need techniques like Return-Oriented Programming (ROP) to bypass this.
- Non-Executable Stack: Some systems prevent code execution from the stack. You may need to disable this protection or use other exploitation methods.
- Debugging: Use GDB extensively to verify your calculations and ensure the return address is being overwritten correctly.