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. 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 at the links below:
Intro to fuzzing Fuzzer automation with Spike
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:
Debugging fundamentals for exploit development In-depth SEH exploit-writing tutorial using-ollydbg
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 should check out the previous entries on exploiting buffer overflows in this series before attempting this article, especially the one linked below:
Stack-based Buffer Overflow Tutorial
The remaining entries in the Vulnserver series are linked below:
SEH-exploit Buffer overflow vulnserver/
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 A copy of the generatecodes.pl script from my website here: http://sites.google.com/site/lupingreycorner/generatecodes.pl.
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:
http://en.wikipedia.org/wiki/Data_Execution_Prevention http://support.microsoft.com/kb/875352
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 LTER command of Vulnserver. We can trigger an exception in the program by sending a LTER command with a parameter consisting of a long (~2010 characters or more) string including at least one full stop (.) character. To demonstrate this, we can use the following script, which will send “LTER .” followed by 2100 “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 lter-exploit-vs.pl. 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. (Remember to mark the script as executable using chmod!) 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.
We can see that the EIP register has a value of 0x41414141, indicating that the data we have sent to the application has caused an overflow and has been used to directly overwrite EIP. So far so good, that’s step one of the process complete already, we have control of the instruction pointer. Now let’s use the pattern_create tool from Metasploit to create a pattern to find the offset within our sent data where EIP is overwritten. For my output shown below I am piping the output of pattern_create into a small Perl script which will format it a little better with line breaks to make it more readable. You can feel free to avoid this if you wish and just paste the data directly into your skeleton exploit as we have done in previous entries in this series, however if you want more readable output the code I am using is below. Save the above code as split.pl and make it executable using chmod, then pipe the data from pattern_create into the script as shown below. Please note that the pattern_create tool might sit in another location on your system depending on what version of Metasploit you originally installed, and how you installed it, so modify this part of the command as required. Paste the output into your exploit code like so: Now restart Vulnserver in the debugger, hit F9 to let the program run and execute the exploit code once more. The program will crash, with EIP now pointing to 0x396f4338.
let’s feed this value into pattern_offset to find out where in our data EIP is overwritten. This tells us the overwrite occurred at 2006 bytes in to our data. let’s modify our exploit to confirm this, and let’s also try and add some additional bytes onto the end of this block of data to see if we can get enough room for shellcode after the overwrite. If this works, we should see EIP overwritten with 0x42424242 and hopefully a large amount of 0x43 characters on the stack after our entry that overwrites EIP. Restart the program in the debugger and run the exploit one more. (From this point on I wont be listing the commands to restart the program in the debugger and run the exploit – Im assuming you know how to do this by now.) We should see the following in our debugger:
EIP has been overwritten with 0x42424242 and we see a large number of 43 characters on our stack. It looks as though we have more than enough room to introduce shellcode into this application for our exploit to run. Is there a way to redirect execution to this section of memory? Yes, as we have seen in previous entries in this series, the ESP register again seems to point to the address in memory that stores the data that followed the bytes that were used to overwrite EIP. This is fairly common in exploits that perform an overwrite of the return pointer stored on the stack. As before, we can use the address of a “JMP ESP” instruction sitting in a predictable location in memory to overwrite EIP and redirect code execution to this location. As covered in the previous tutorials, we can look for this JMP ESP instruction by picking a module loaded with the application, such as essfunc.dll, viewing it in the disassembler pane, and performing a search using the right click Search for->Command option. One such “JMP ESP” is located at 0x625011AF. Restart Vulnserver in the debugger and use the F2 key to set a breakpoint at this location (the address should turn red)…
…and then modify your exploit code as follows. In the code below we have added our JMP ESP address to use in overwriting EIP, and we have also replaced the 0x43 characters with 0xCC INT3 breakpoints to cause our application to pause in the debugger when an attempt is made to execute this data as code. So far this is all pretty familiar stuff, covered in the previous tutorials in this series. Ensure your breakpoint at 0x625011AF is still active (restarting the program in the debugger may delete it, so check!) and let’s see what happens when we execute this new version of the exploit:
Uh oh. After running this most recent version of our exploit, our breakpoint at 0x625011AF did not get hit, EIP is pointing to 0x62501109 and we have the program crashing with an access violation when reading memory at 0x41414135. What is going on here? Let’s have a closer look at our stack.
There’s one thing here that we can immediately recognise as being wrong. Look at all those 0x4D bytes. We sent a number of 0xCC bytes to the application, yet in the area of the stack where we expect to see these 0xCC characters, we instead see 0x4Ds. Have our 0xCC characters been transformed by the application, or is this some sort of weird coincidence? And look at address 0x00B6FA0C in the stack pane in the screenshot above. We see a pointer to 0x62501156 in essfunc.dll. That’s very close to the 0x625011AF address we sent to the application for our intended EIP overwrite – only the final byte of the address is different. Did the 0xAF from the end of our overwrite address get mangled by this application in the same way as our 0xCC characters appear to have been? You will also notice that some of the other entries on the stack don’t appear to match the data that we sent, such as the present stack entry highlighted in grey in the screenshot above. One possible explanation for this is that execution of the application has been sent to a point within its code base (perhaps 0x62501156 if our predictions above are correct), resulting in stack operations being performed that modified the data previously stored in these areas of memory. A likely conclusion that we can come to from these observations is that we might be dealing with a bad character problem here, whereby certain characters cannot be used in our exploit due to problems with the target application parsing them. How can we confirm that this is the case, and actually work our way around the problem to produce a working exploit? Bad Characters The simplest way to check if we are in fact facing a bad character problem here is to send a list of all possible characters to the application and see which ones are still faithfully represented in memory one the overflow occurs. As you may be able to work out from our experience above however, we need to be strategic about the way that we do this in order to avoid any unpredictable outcomes caused by characters we send that turn out to be bad. To minimise the chance of bad characters causing problems, we will only use known good characters to actually perform the overflow, and we will insert the complete set of characters to test after this point. This minimises the opportunity for a bad character to potentially send the application down an unpredictable and invalid path, which might result in data on the stack (and potentially elsewhere) being modified. For the purpose of finding bad characters, we want the application to immediately stop executing as soon as possible after the overwritten return pointer is used, so we can see the contents of memory at this time in the programs execution, before anything gets changed. Once this is done we can then examine the systems memory in the debugger at the time of the exception to see which characters made it through, and which did not. The characters that make it through unmangled will be considered “good”, and the ones that do not will be considered “bad”. If some of the characters that we sent in the previous version of the exploit are in fact “bad” then this might be causing the problem we experienced above. Now to actually generate the list of characters to test for “badness” we can use a small program I wrote a while ago, specifically for this purpose, called generatecodes.pl. All you need to do is run it and provide an optional list of characters you want to exclude, and it will print out all other characters in order from 0x00 to 0xFF. I will run it to exclude the common bad characters 0x00, 0x0A and 0x0D. As usual, I am making an assumption that these characters are bad, because they often are. In the case of this exploit, making this assumption does not cause any great difficulties, because the use of these particular characters does not seem to be critical, nor do we need to be that precise about listing every character that is good for this exploit. If this was not the case I would make sure to actually test these characters to confirm whether they were good or bad. In some circumstances, which we may discuss in future articles, this might actually be necessary, but for this exploit, we can take a lazy shortcut and make some assumptions about these characters. Here is how we can run the generatecodes.pl script to generate a list of characters to test. Now we can take the output above and paste it into our re-modified exploit as shown below. Don’t forget to edit the output above to add a “;” at the end of the last line and a ” .” at the end of every other line to ensure proper Perl syntax. We will send this list of bad characters to the application after a large series of 0x41 characters to lead up to the overwrite, and four 0x42 characters for the overwrite itself. We know these characters are good from previous experience, so using them in this fashion should maximise our chances of overwriting the return pointer and triggering an immediate exception, considering that 0x42424242 is an invalid memory address. Now restart Vulnserver in the debugger and run the exploit again. The application should now crash with EIP pointing to the expected address of 0x42424242, and if you look at the stack you should see the characters we want to test counting upwards from one.
These characters will however be listed in the stack pane in little endian order (a feature of Ollydbg that takes into account the endianness of X86 compatible processors), so my preferred method is to view this data in the memory dump pane, which will show the characters in the same order in which they are stored in memory. Right click on the ESP register in the registers pane and select Follow in Dump.
You should now be able to see the data you have sent (the data located at the address in memory stored in the ESP register) in a more easily readable fashion.
A look at this memory dump will reveal something interesting. As soon as we get to byte 0x7F, we don’t see the expected byte 0x80 following it, instead we see 0x01, followed by 0x02, 0x03 and so on all the way through to 0x80. For all characters over 0x7F the program seems to be subtracting 0x7F from the byte value sent. This essentially means that all characters over 0x7F are bad.
Is there something significant about the byte value 0x7F that might account for this? As it turns out, yes, there is, and the ASCII representation of the bytes shown above provides a clue to what that is. The byte 0x7F is actually the point where the ASCII character set terminates. This program is obviously only expecting to receive ASCII characters into this field, and somewhere in its execution it mangles any characters that don’t fall into this range. This limitation essentially means that to get our exploit to work, we can only use allowed characters within the 0x01 – 0x7F range (assuming that 0x00, 0x0A and 0x0D will probably also be bad and unusable). This means that both our address with the “JMP ESP” instruction AND our shellcode cannot contain these bytes. Is this going to be a problem? let’s look at each part individually and see how we can work around this limitation. Dealing with Bad Characters First of all we need to find a “JMP ESP” instruction at an address in memory that does not require the use of any of our identified bad characters. We should already be somewhat familiar with the idea of this – we have already had to avoid the use of zero bytes in our overwrite addresses, as well as the 0x0A and 0x0D characters as well, we just now need to extend this idea and look for addresses that don’t use a wider range of characters. To help in our search for a usable address, let’s search for all “JMP ESP” instructions within essfunc.dll. Switch to essfunc.dll in the disassembler pane and right click and select Search for->All commands.
Now type “JMP ESP” in the window that appears and hit Find.
And a window with all the “JMP ESP” commands in the essfunc module will appear.
Looking at the addresses of the instructions, we can see two addresses that should be suitable, at 0x62501203 and 0x62501205. let’s use the 0x62501203 address for our overwrite. Set a breakpoint at this address and let’s modify our exploit as shown below to test if this address will work. (You will probably want to set the breakpoint after restarting the program in the debugger first, sometimes restarting a program in the debugger will erase breakpoints). Now run the exploit and execution should stop at your breakpoint at 0x62501203.
We have found an overwrite address that will comply with our bad character restrictions, the next step is to find a way to make our shellcode work within the character limitations. Alphanumeric Shellcode As it turns out, there are shellcodes and shellcode encoders written specifically to deal with the problem of alphanumeric character set limitations, and one such encoder exists in Metasploit! If you run msfencode with the list encoders option, you will see encoders that deal with all sorts of limitations. Our allowed set makes both upper and lower case characters available to us, so we will use the x86/alpha_mixed encoder, which allows alphanumeric mixed case characters (e.g. upper and lower case). There is one thing to be aware of when using this encoder however – it is a Metasploit implementation of SkyLined’s (Berend-Jan Wevers) ALPHA2 encoder, which needs to know its position in memory in order to function. By default, if you don’t provide this information, the Metasploit implementation adds its own code to determine its position in memory to the start of the encoder, and this code is unfortunately not alphanumeric compatible. To work around this, we can provide a sparsely documented command line option “BufferRegister” to msfencode to specify a register that contains the position of the shellcode in memory. In this case, that register would be ESP, which contains the start address of our shellcode in this particular exploit. Note: Props to the Metasploit Unleashed site for documenting this BufferRegister option. Until I ran across their entry mentioning this option I was using this ALPHA2 encoder via the original Python implementation, which while being quite workable is not quite as easy or convenient to use as msfencode. We can generate some bindshell shellcode (listening on port 4567), encoded with ALPHA2 using the command below. There we have it, shellcode, using only characters within the alphanumeric range, from 0x00 to 0x7f. Its a little large, but it does fit within our character set limitations! That code can now be pasted into our final exploit, as follows: Restart the program in the debugger and run the new exploit. Now attempt to connect to port 4567 on the victim system… We have shell! Another exploit complete!