Stack-based buffer overflows are the foundational technique of Windows exploit development. If you’ve never written one, this is the right place to start. We’ll go from a crash all the way to popping a shell.
The Target
For this walkthrough, we’re using a deliberately vulnerable Windows application. The same principles apply to real-world targets — older VoIP software, FTP servers, media players, and various legacy applications still have this attack surface.
Step 1: Fuzzing — Finding the Crash
Start with a simple fuzzer that sends progressively longer strings until the application crashes:
| |
Step 2: Confirming the Crash in Immunity Debugger
Load the application into Immunity Debugger (File > Attach or open directly). Run the fuzzer. When the crash happens, Immunity will pause execution and show you the register state.
Look at the EIP register. If it reads 41414141, you’ve confirmed that your A characters have overwritten the instruction pointer. 0x41 is the hex value of the ASCII character A.
EIP = 41414141 ← We control the return address
ESP = 0041F9A8
EBP = 41414141
This is the key moment. Controlling EIP means you control where the processor jumps next — which means you control execution flow.
Step 3: Finding the Exact Offset
Use Metasploit’s pattern_create to generate a unique string, then pattern_offset to find the exact offset at which EIP is overwritten:
| |
Step 4: Controlling EIP
Verify control with a targeted payload:
| |
Immunity should now show EIP = 42424242. You have precise control.
Step 5: Finding a JMP ESP
Instead of hardcoding a return address (which changes between systems), we look for a JMP ESP instruction in a loaded module that doesn’t use ASLR or SafeSEH:
| |
Mona will list modules and JMP ESP gadgets. Pick an address from a module without memory protections. This becomes your new EIP — when execution hits your overwritten return address, it jumps to ESP, which is pointing right at your shellcode.
Step 6: Generating Shellcode
| |
Step 7: Final Exploit
| |
Start your netcat listener (nc -lvnp 4444) before running. A shell should arrive.
What’s Next
This is the basic stack overflow — no ASLR, no DEP, no SafeSEH. Real targets have protections. The next post in this series covers SEH-based overflows and how to bypass SafeSEH. After that: egghunters for situations where you have limited buffer space.