Exploiting Vulnserver!
My work/code
View my work/code for this blog post at:
https://github.com/HenryFBP/VagrantPackerFiles/tree/e6b73090ed23bda867f36a7f23951da6a54b55b6
The course
As part of on-the-job training, I got the chance to take a really nice course on UDemy called ‘Ethical Hacking & Bug Hunting: Buffer Overflow For Beginners’ by Eslam Medhat.
https://www.udemy.com/course/buffer-overflow-course-exploit-development/
It uses Kali and Windows VMs that communicate with eachother in order to perform DLL injection that leads to a reverse shell being opened.
As someone who has never exploited this vulnerability before, this course gave me an intimate look into exactly how these attacks occur and how to craft one from scratch, provided you have the binary of the exploitable program.
The tools
- Kali VM
- Metasploit Framework
- Used for creating payloads like reverse shells
- pattern_create.rb
- Used to create a pattern (
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1
…) that is unique every 3 bytes to determine where data is injected into a buffer if you are only able to see 3-4 bytes, like in CPU registers - This is useful when attempting to determine exactly when a buffer begins to overflow into the stack.
- Used to create a pattern (
- pattern_offset.rb
- Used to identify a sub-pattern to a position (i.e.
a1A
would be position 3)
- Used to identify a sub-pattern to a position (i.e.
- NetCat / nc
- Used to poke simple TCP programs like vulnserver to see if they expose vulnerable functionality.
- spike / tcp_send_packet
- Used to fuzz inputs to TCP programs, to see what causes a server to crash or do other interesting things…
- Python 2
- Used to send our payload, concatenate our buffer overflow buf with the payload, print things nicely, etc…
- Metasploit Framework
- Windows VM
- vulnserver
- The star of the show! Some odd TCP server that’s very vulnerable.
- Loads a DLL called essfunc.dll with no memory protections.
- ImmunityDebugger
- Used to debug Windows binary programs.
- Break on specific memory locations being executed.
- Inspect CPU registers and go to memory locations to see if a payload has been injected or not.
- mona
- An extension for ImmunityDebugger.
- Search for loaded DLLs and display their memory protections
- ??? Much more. We did not use other functionality of mona in the lab.
- vulnserver
Setup
-
Set up a windows machine Use a VM or segregate the windows machine as this server allows attackers to gain admin access remotely.
-
Download vulnserver.
-
Download Immunity Debugger.
-
-
Set up Kali Linux or any other linux distro with the tools listed above.
-
Make sure the VMs can communicate. Windows does not respond to pings AFAIK.
The research
NetCat
I ran NetCat against the windows vulnserver and was greeted with a prompt. vulnserver is a simple application that uses TCP TELNET-style communications that are ended with newlines, so netcat was able to easily communicate with it.
Spike
I used spike to see what command would cause the server to crash. Spike is a TCP fuzzer.
I only tested TRUN as the guide spared me the tedium of testing all of the other commands.
command.spk:
s_readline();
s_string("TRUN ");
s_string_variable("0");
This file contains c code that SPIKE uses to fuzz packets that are sent to the server.
You can perform the fuzzing like this:
generic_send_tcp 192.168.33.16 9999 command.spk 0 0
Before you do this, make sure that:
-
vulnserver is actually running. Keep in mind that this command will crash it.
-
You’re recording the packets sent to vulnserver with Wireshark or
tcpdump
or another tool. Alternatively you can attach Immunity Debugger to vulnserver and inspect the registers when it crashes. This is important to craft the payload later.
tcpdump to see the fuzzer’s successful payload
I used sudo tcpdump port 9999 -vv --interface eth1
to view the payloads sent by SPIKE.
After the fuzzing, you should get a ****load of output from the tcpdump
command. The last TCP sequence will be the
one that crashed vulnserver so that contains the beginning of a payload.
You might be able to see the TRUN command in that buffer.
Note that the .
character does not mean literally a PERIOD character, but it means either a space or non-printable
character, such as EOF or NUL character.
0x20, or 32, is the SPACE character.
The last command sent by SPIKE before vulnserver crashed was:
5452 554e 202f 2e3a
2f41 4141 4141 4141
or,
T R U N / . :
/ A A A A A A A
...
or,
TRUN /.:/AAAAAAA...
The exact amount of ‘A’ characters must be determined.
Before we do that using Python, let’s take a look at the fuzzed payload in a different way.
Immunity Debugger to view the successfull fuzzed payload
Alternatively, you can use Immunity Debugger to view the fuzzed payload.
-
In Windows, start vulnserver as an admin by right-clicking on it. Do NOT use cmd.exe or powershell.exe to do this.
-
Then, start Immunity Debugger as an admin and attach it to the process. Make sure to resume the process as attaching Immunity Debugger will pause it.
-
Finally, in Kali, fuzz the payload again.
Back in Windows, Immunity Debugger should have paused on an exception.
You can see that the EAX register points to a buffer that contains our command.
Something very important here is that the ASCII A
character’s hexadecimal value is 0x41.
Look at the EIP register! We have filled it up with the A
character from our payload!
We don’t know which exact location overwrites the EIP register though. This is where Python comes in.
The EIP register stands for ‘Extended Instruction Pointer’. It is the memory location for the next command that the CPU will execute. It will allow us to tell a program to execute instructions from anywhere in memory if we can control it.
In order to modify the EIP register reliably, we need to:
- Determine the rough length of the payload
- Generate and inject a sequence of data that is unique for every 4 bytes of data
- Generated with
pattern_create.rb
- Then, look at the EIP register and determine the position of that 4-byte chunk of data found in the EIP register
- This allows us to determine the EXACT position that data overflows into the EIP register
- Generated with
Python fuzzing script, pattern_create.rb, pattern_offset.rb
The next step was to create a Python script to get within about 1000 characters of the payload that crashes the server.
We don’t need to be precise because as long as any 4 bytes of our payload is injected into the EIP register, we can
use the pattern_offset.rb
tool to determine what position those 4 bytes were injected at.
Finding the rough position of when the payload gets injected
options.py:
1
2
3
PORT = 9999
HOST = '192.168.33.16'
<...>
fuzz.py:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#!/usr/bin/env python2
"""
Determines the length of bytes necessary to trigger a buffer overflow in vulnserver
"""
import sys, socket
from time import sleep
from options import HOST, PORT
buffer = 'A' * 100
while True:
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((HOST, PORT))
cmd = ('TRUN /.:/' + buffer)
# print("SEND "+cmd)
s.send(cmd)
print("sent %d bytes" % len(buffer))
s.close()
sleep(1)
buffer = buffer + ("A" * 100)
except:
print("crashed at %d bytes" % len(buffer))
# print(e)
sys.exit()
This code is pretty simple.
It starts on line 11 with 100 A
characters, and then from line 13-29 slowly increments the A
characters by 100 until
either an exception is thrown or the server stops responding. Line 25 does the increment.
TODO show pics of it running and our length
Creating a pattern that is unique every 4 bytes
TODO explain pattern_create.rb
and determine_injection_position.py
TODO show the pattern being created
TODO show the pattern being sent
TODO show the pattern fragment in the EIP register
TODO show pattern_offset.rb
showing us the exact position
The attack
TODO