The previous blog explains the Stack-Based Buffer Overflow Attack and its steps. In this article, we will understand and perform the first 2 steps, Spiking & Fuzzing in detail.
Before proceeding, disable Defender’s Real Time Protection so we don’t face issues during the process.
Buffer Overflow Steps
The steps for performing BOF are as follows and we will discuss the first 2 of them in this article
- Spiking
- Fuzzing
- Finding Offset
- Overwriting the EIP
- Finding Bad Characters
- Finding Right Module
- Generating Shellcode
Setting up environment
The very first step is spiking which is the method of finding the vulnerable part of a program. Start the vulnserver
as administrator and you will see the following screen
Also, start the Immunity Debugger
as administrator and you will see the debugger window is split into 4 parts as follows
For now, the debugger screen is blank as you can see in the above image.
Note: The reason for running vulnserver as admin is so that when we exploit it, we get shell with maximum privileges. The reason for running Immunity Debugger as admin is so that we can see the vulnserver process and interact with it
Attaching the Program
The next step is to attach the process with Immunity Debugger
. For this, in Immunity Debugger
, click on File
option in the top menu and choose Attach
option
A new window will appear listing the running processes that we can attach
Choose the vulnserver process and click Attach.
Once you attach the process, you will see that the debugger split windows are no longer blank
The 4 windows provide the following useful information
- Top-Left window is the
Disassembly Window
that shows the assembly code of the program or process. - Top-Right window is the
Register Window
that displays the values of registers during the program execution. - Bottom-Left window is the
Stack Window
that shows the contents of the program’s stack memory. - Bottom-Right window is the
Breakpoints Window
that is for managing the breakpoints.
Running the Program
At the very bottom, the grey bar shows Attached process paused at ntdll.DbgBreakPoint
and in the right corner, you can see that the process is paused
Now we need to make the program running. We can do this by clicking the Play
button just below Debug
in the top options bar
As soon you press this button, the status in the bottom-right corner will change to Running
as below
Connecting to vulnserver
As we have the program running, we now connect to the vulnserver and see what it offers. So, go to Kali machine and in the terminal run the following command where IP is the IP address of Windows Machine and 9999 is the default port at which vulnserver listens
nc 192.168.37.131 9999
Also if you look at the vulnserver window, it will show a received connection
As we now have a connection with the vulnserver, we can see the welcome banner and command to print help. So executing HELP
we will have the following output
We can see the list of valid commands that this vulnserver can process/execute. We will try to find which command is vulnerable using Spiking
.
Buffer Overflow Steps (1)
Spiking (Finding Vulnerable Command)
To find the vulnerable command, we will test each one of them and send a bunch of characters to see if we can overflow the buffer. If the program crashes, then the command might be vulnerable or otherwise we move on to the next command. So before starting, execute the EXIT
command to disconnect from the server.
Now, the tool that we will be using is generic_send
and its usage is as follows_tcp
generic_send_tcp HOST PORT SPIKE_SCRIPT SKIPVAR SKIPSTR
- HOST will be the IP of the Windows Machine at which vulnserver is running
- PORT will be 9999 (default port of vulnserver)
- SPIKE_SCRIPT will be the script that iterates through the command and crashes the program
- SKIPVAR will be set to 0
- SKIPSTR will be set to 0
Now, the spike_script
for the command STATS
will be as follows
s_readline();
s_string("STATS ");
s_string_variable("0");
When we spike this, we will Save the script with the extension .spk
like stats.spk
Now that we have everything, we execute the following command in our Kali terminal
generic_send_tcp 192.168.37.131 9999 stats.spk 0 0
Upon running, we will see a lot of commands being sent to the vulnserver as below
Also, if you look into vulnserver
window, it has a bunch of connections as below
Now looking into Immunity Debugger
(while the script is running), you will be able to see that the vulnserver is receiving commands rapidly and not crashing. It indicates that this STATS
command is not vulnerable to BOF.
Ideally, you can check for all commands one by one. But we know TRUN
command is the vulnerable one, so we slightly modify the spike script as follows
s_readline();
s_string("TRUN ");
s_string_variable("0");
Save it as trun.spk
and run the command
generic_send_tcp 192.168.37.131 9999 trun.spk 0 0
Sometime after running the command, the state in debugger
will be changed to Paused
because of the exception Access violation when executing
as below
The vulnserver has crashed but is not showing the error message as it is being debugged by the debugger.
Examining Registers
Now, as the program crashes, we can now look into the register window in the debugger
We can see EAX has a bunch of A
characters and if the command was not vulnerable, this should fill in the buffer space. But here, it has exceeded buffer space, filled EBP with 41414141
(4 A characters; 41 is hex of A character), also ESP as well with the A
characters and has overwritten EIP as well with 41414141
.
The important point here is that we can overwrite EIP which indicates the next instruction to execute and we can abuse this for our own usage.
To undertsand the memory and registers better, you can refer to a good resource here
Buffer Overflow Steps (2)
Fuzzing
Now that we know that TRUN
is the vulnerable point. Fuzzing is similar to Spiking but here we know what part is vulnerable whereas, in spiking, we test for vulnerable commands. Now we will FUZZ the TRUN command using the following Python script fuzz.py
import sys, socket
from time import sleep
buffer = "A" * 100
while True:
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('192.168.37.131',9999))
s.send(('TRUN /.:/' + buffer))
s.close()
sleep(1)
buffer = buffer + "A" * 100
except:
print(f"Fuzzing crashed at {str(len(buffer))} bytes")
sys.exit()
Code Explanation
The above code starts an infinite loop. In the loop, it connects to the vulnserver with a one-second break and sends 100 A characters (100 bytes) along with the TRUN command with some special characters /.:/
that can also be seen with the TRUN command in the register window while spiking. The number of A characters is increased by 100 after every iteration to see at what point the program crashes.
Note: Before running the code, close both Immunity and vulnserver and start them again as admin. Make sure to attach the vulnserver and hit play button to change status to Running.
Now, run the program from the Kali terminal using the command python3 fuzz.py and you will see payloads sending output. You will reach a point where the output will get stuck and hit CTRL+C and you will see the exception showing the bytes at which the crash occurred.
The exception indicates the approximate bytes at which the program crashed.
Go back to Immunity Debugger
and you will see the crash as follows
Here we can see that program crashed but it did not overwrite the EIP or any other register, it just overflew the buffer. We need to find the EIP to overwrite it and abuse it. This will be discussed in the next article.
Leave a Reply