Requirements and system Setup
In order to follow along with the fuzzing exercises in this article, you will need two networked systems – one Windows system (Windows XP, Vista or Windows 7) running the vulnerable application Vulnserver which will act as our fuzzing target, and one Linux system to perform the fuzzing using SPIKE. I recommend using a copy of BackTrack 4 Final or later as your Linux system, as all of the software that we require to perform our fuzzing work comes already included. Either (or both) of these required systems can be run as virtual machines. In a number of the steps in the exercises that follow, I will run commands and scripts that access my fuzzing target system by its IP address. My fuzzing target system was listening on the IP address 192.168.56.101. If yours is listening on a different address, make sure you enter this in place of 192.168.56.101 in any of the commands that follow. The software we will need on each of the systems is as follows: Fuzzing target (Windows):
Vulnserver. Can be obtained here http://sites.google.com/site/lupingreycorner/vulnserver.zip OllyDbg 1.10. Can be obtained here http://www.ollydbg.de/
Fuzzing system (Linux)
SPIKE. See below. Wireshark. Should be available from your distributions package management system or from here http://www.wireshark.org/. Perl. Should come preinstalled. Netcat. Is likely to come preinstalled, otherwise should be available from your distributions package management system.
If you use BackTrack as your fuzzing system all of these prerequisite pieces of software will come pre-installed. If you are using another variety of Linux you will likely need to install SPIKE from source which you can download from here: http://www.immunitysec.com/resources-freesoftware.shtml. Before you actually compile SPIKE, I recommend making a small change to the source first. Edit the file spike.c in SPIKE/SPIKE/src from the source tarball, and find the two “return 0;” strings that immediately follow the lines “printf(“tried to send to a closed socket!n”);”. Replace these two “return 0;” lines with “exit(1);”. This change will essentially cause SPIKE to exit with a non zero return code when it tries to send data to a closed socket – this becomes useful when we run SPIKE from a wrapper script later on in this article. Once this change is made you can compile SPIKE using the normal “./configure; make” commands run from the src directory. On your fuzzing target system you will require Administrative rights to be able to run the Ollydbg debugger. On Vista or Windows 7 make sure you right click and select run as Adminstrator to ensure that the debugger is run with the proper privileges. Running the Vulnserver application itself is not particularly difficult. Just place the two binary files from the distribution – vulnserver.exe and essfunc.dll – into the same directory and launch the program by using the Open command in OllyDbg or just double clicking on the executable. The program by default listens on TCP port 9999, but if you want it to listen on another port just provide the port number as a command line parameter to vulnserver.exe.
What is fuzzing?
Fuzzing is a process of sending deliberately malformed data to a program in order to generate failures, or errors in the application. When performed by those in the software exploitation community, fuzzing usually focuses on discovery of bugs that can be exploited to allow an attacker to run their own code, and along with binary and source code analysis fuzzing is one of the primary ways in which exploitable software bugs are discovered. There are a number of popular and free software based fuzzers available, but during this article we will focus on one of the first fuzzers to become popular within the Information Security community – SPIKE.
The SPIKE fuzzer
Technically speaking, SPIKE is actually a fuzzer creation kit, providing an API that allows a user to create their own fuzzers for network based protocols using the C programming language. SPIKE defines a number of primitives that it makes available to C coders, which allows it to construct fuzzed messages called “SPIKES” that can be sent to a network service to hopefully induce errors. SPIKE was specifically designed to focus on finding exploitable bugs, so it’s an excellent choice for our purposes. As I mentioned, SPIKE is a C based fuzzer creation kit, but you don’t have to know how to write C programs to use SPIKE. SPIKE also includes a simple scripting capability, and within the SPIKE distribution there are a few command line tools which can act as interpreters to simple text files containing SPIKE primitives. SPIKE is notoriously badly documented, however by reviewing some of the SPIKE scripts provided in the distribution, and scanning through elements of the SPIKE C code, we can begin to build a listing of some of the primitives that can be used. To save you having to do this, some of these primitives will be listed later in this document. There are also a number of papers and presentations available on SPIKE, with one of the most interesting being an older presentation from SPIKE author “Daily” Dave Aitel. (This presentation is available here http://www.immunitysec.com/downloads/usingspike3.ppt) While the presentation is rather lacking in detailed examples, it does outline a lot of the things that make SPIKE such a great fuzzer to use for discovering software vulnerabilities. Let’s discuss some of these features, and see how they might be useful to us. What are some of the useful features of SPIKE?
SPIKE has a large number of in-built strings to use for fuzzing that are very effective at producing a wide variety of errors in programs. SPIKE does a lot of the work for you in determining the values that can best be sent to an application to cause it to fail in a useful way. This means you don’t have to come up with these values yourself, and you benefit from the considerable experience of the programs author in choosing good fuzzing strings. SPIKE has a concept of “blocks”, which can be used to calculate the size of specified sections within the SPIKES that are generated by the SPIKE code. These size values can then be inserted into the SPIKES themselves, in a variety of different formats. This is a real benefit when fuzzing protocols that require accurate size values to be specified for particular fields within a message, and saves you the effort of doing these calculations yourself. SPIKE can support a number of different data types that are commonly used in network protocols, and can accept them in a variety of different formats that allow easy cutting and pasting from many different programs.
SPIKE scripting
As previously mentioned, SPIKE also includes a basic scripting capability that allows you to use SPIKE primitives to fuzz applications without having to code your own SPIKE fuzzer in C. A variety of different interpreters are available with the SPIKE distribution that allow you to specify certain relevant subsets of these SPIKE primitives to send against various types of network applications. In order to simplify things for the rest of this article, I am going to refer to this subset of SPIKE primitives that can be used in SPIKE scripts as “commands”. In the case of TCP based server applications, we can make use of this scripting capability by writing SPIKE commands into .spk script files, and running them using the TCP SPIKE script interpreter generic_send_tcp, which will send the specified SPIKE at a particular IP address and TCP port. There is also a generic_send_udp, which will do something similar, however in with this interpreter the SPIKES will be sent over UDP. The generic_send_tcp interpreter, which we will be using to fuzz our application, is found in /pentest/fuzzers/spike/ on BackTrack (or in the src directory if you downloaded and compiled SPIKE yourself), and running it without any command line parameters shows the following: root@bt4r1vm:/pentest/fuzzers/spike/# ./generic_send_tcp argc=1 Usage: ./generic_send_tcp host port spike_script SKIPVAR SKIPSTR ./generic_send_tcp 192.168.1.100 701 something.spk 0 0 Hopefully the first three required command line options are self explanatory, with parameters one and two defining the host and TCP port to connect to for fuzzing, and the third parameter defining the name of the SPIKE script file. Parameters 4 and 5 may require some more explanation. These parameters, SKIPVAR and SKIPSTR, essentially allow you to jump into the middle of the fuzzing session defined by a SPIKE script. Within a SPIKE script, you may specify “s_string_variables”, which are the commands used to insert the actual fuzzed strings into each SPIKE that you send. If you use more than one of these “s_string_variables” in your script, you can skip using the earlier instances of “s_string_variables” by setting an appropriate value for SKIPVAR. For example, if you include three “s_string_variables” in your SPIKE script, and you want to ignore the first two variables and only fuzz the third, you would set SKIPVAR to 2 (the numbering of the variables starts counting upwards from 0, so the third variable is referred to by the number 2). Each of the “s_string_variables” also has an array of different fuzz string values inbuilt into SPIKE that it will iterate through within a SPIKE fuzzing session. If you want to skip the first 10 of these strings, and start fuzzing at string 11, you can set SKIPSTR to 10 (again, counting starts from 0). When you use generic_send_tcp, it will output information to the command line about which variable and string it is currently testing, so if a SPIKE session gets interrupted and you need to continue it later on you can do so with the use of these two command line parameters. To start a fuzzing session from the beginning, just use “0 0” for these parameters, so to start a fuzzing session against host 192.168.1.101 on port 9999 using script file “test.spk” from the beginning, use the following command line (assuming generic_send_tcp is in /pentest/fuzzers/spike/): root@bt4r1vm:~# /pentest/fuzzers/spike/generic_send_tcp 192.168.56.101 9999 test.spk 0
SPIKE scripting commands
To write a SPIKE script for our fuzzing exercise, we first need to know what some of the available commands are and what they do. If you want to hunt through the SPIKE distribution directory, the available primitives that we can use as commands in our script file can be discovered by examining some of the example .spk files as well as the SPIKE header file spike.h. The spike.h file will list the available primitives (commands), and the .spk files will provide examples of how those commands can be used. Keep in mind that the SPIKE scripting capability will only support a subset of the primitives in spike.h – the scripting “interpreter” program performs the work of creating the “SPIKE” and making the network connection, so you can only use the commands that define the content of the SPIKE itself in the scripts. To save you the trouble of hunting through those files, I will list some of the more useful SPIKE primitives for scripting below. The spike.h file, being written in C, lists each of the SPIKE commands in C syntax, using C data types, but for the benefit of those unfamiliar with C syntax I am going to specify the commands using an “example” format that you can more easily reproduce when writing your scripts. The “//” notation is used in C to designate line based comments (everything after that point is ignored by the compiler), so I have used this syntax below to provide additional explanatory detail for each of the commands. You can leave these comments in when you create your SPIKE scripts, or add your own comments, and this text will be ignored by the SPIKE interpreter. I have broken the commands below into a number of high level categories relating to strings, binary data, blocks and other useful functions. Strings The string commands provide a way of adding ASCII character data into your SPIKES. Also included within the string commands is the s_string_variable command, one of the most important commands within SPIKE as it actually allows you to add fuzz strings to your SPIKE.
s_string(“string”); // simply prints the string “string” as part of your “SPIKE” s_string_repeat(“string”,200); // repeats the string “string” 200 times s_string_variable(“string”); // inserts a fuzzed string into your “SPIKE”. The string “string” will be used for the first iteration of this variable, as well as for any SPIKES where other s_string_variables are being iterated
Binary data The binary commands provide a way of adding binary data to your SPIKES. They support a wide variety of ways to specify the binary data.
s_binary(“x41”); // inserts binary representation of hex 0x41 = ASCII “A” s_binary_repeat(“x41”, 200); //inserts binary representation of 0x41 200 times
For the binary commands in SPIKE, various other methods for specifying the same data are also available. To output the same hex character as shown above, we could use “41” or “0x41” as well, and we can also mix and match these values, (e.g. “410x41x42” to output ASCII “AAB”). Any added white space is also ignored. All of this combines to allows easy cutting and pasting from a variety of different applications that represent data in Hex format, such as packet capture tools, debuggers, etc. Defining blocks Block defining commands allow you to specify the start and end points of a named block within a SPIKE script. This allows you to define the size of those sections of data in your SPIKES using block size commands.
s_block_start(“block1”); // defines the start of block “block1” s_block_end(“block1”); // defines the end of block “block1”
Block sizes Block size commands allow you to insert the size of data inside a named block inside the SPIKES generated by your script, using a variety of different size formats.
s_blocksize_string(“block1”, 2); // adds a string 2 characters long to the SPIKE that represents the size of block “block1” s_binary_block_size_byte(“block1”); //adds a 1 byte value to the SPIKE that represents the size of block “block1”
These are just two examples from the many ways of how block size can be added to a SPIKE. There are other methods too, that can allow you to represent block size in a large variety of formats, and some that even allow you to add preset values to the block size before it is To see some of the other options, simply perform a grep on the spike.h file in the SPIKE src directory for the strings “block_size” or “blocksize”. Other useful commands Other useful commands are those that don’t fit into any of the other categories previously mentioned.
s_read_packet(); // Reads and prints to screen data received from the server s_readline(); // Reads a single line of input from the server
You can also use general C language functions within SPIKE scripts, to give you additional scripting capabilities. One particularly useful function is printf(), which can be used to output data to the terminal, which can give our scripts more informative console output. An example SPIKE script The following is an example SPIKE script that could be used to fuzz the inputvar variable in php script testme.php via a POST request to testserver.example.com. s_string(“POST /testme.php HTTP/1.1rn”); s_string(“Host: testserver.example.comrn”); s_string(“Content-Length: “); s_blocksize_string(“block1”, 5); s_string(“rnConnection: closernrn”); s_block_start(“block1”); s_string(“inputvar=”); s_string_variable(“inputval”); s_block_end(“block1”); This script essentially specifies a message like the below, where [fuzz_string] represents the location where the SPIKE fuzz strings will be inserted into the message, and [size_of_data] represents the size of the data section of the POST request, which contains the fixed string “inputvar=” and the variable data of the fuzz string. This size field will be automatically updated as the fuzz string changes. POST /testme.php HTTP/1.1 Host: testserver.example.com Content-Length: [size_of_data] Connection: close inputvar=[fuzz_string]
Understanding the fuzzed protocol
Successful fuzzing often requires that malformed or unexpected data be inserted into quite specific areas of an applications input. This is because the program usually needs to perform some sort of processing on the user supplied data in order for an exploitable crash to be triggered, and this requires that we enter the fuzz values into areas of a network protocol where the application is expecting to find the right sort of input. Data fields, size fields, command arguments, input strings and sometimes even commands themselves are all examples of the types of input that can be used to generate these types of errors. In other words, to get the “wrong” data into the “right” place, we need to have an understanding of the structure of the network protocol that we are using to communicate with the target application, so that our fuzzing data is directed into the appropriate areas of the application. This understanding of the network protocol can be gained in a number of ways – by reviewing RFC documents, by generating traffic using a client application and using a tool such as Wireshark or tcpdump to capture the result, or, for very simple protocols, you can just directly interact with the application to see how it works. This is what we will do in the case of Vulnserver. So we can begin, we first we need to start it up. Since we are fuzzing Vulnserver and we want to see what is happening to it if we manage to cause an exception, we will run the program in a Debugger. Start up OllyDbg on your Windows system, and use it to open vulnserver.exe from its location on disk, then either press the F9 key, hit the Play button on the OllyDbg toolbar or select Run from the OllyDbg Debug menu to allow the program to run within the debugger. At this point, the program is running more or less as normal, however if we trigger a crash in the Vulnserver process, the debugger will take control and will allow us to see what is going on in the processors registers and the programs memory at the time of the crash.
Now, from our Linux fuzzing system, we can connect to the running instance of Vulnserver using netcat. We will run netcat in double verbose mode (-vv) in order to get some additional information about the connection, and we will disable DNS resolution (-n). root@bt4r1vm:~# nc -nvv 192.168.56.101 9999 (UNKNOWN) [192.168.56.101] 9999 (?) open Welcome to Vulnerable Server! Enter HELP for help. The response we receive after connecting to Vulnserver tells us that we can enter HELP to obtain, some help. Lets try that and see what happens: root@bt4r1vm:~# nc -nvv 192.168.56.101 9999 (UNKNOWN) [192.168.56.101] 9999 (?) open 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 OK, asking for HELP has provided us a list of Valid Commands that are apparently accepted by the program. Lets try entering some of these commands, as well as some other random strings, and see what happens. STATS UNKNOWN COMMAND Running the STATS command with no parameters doesn’t seem to be supported. What about if we try it again, but this time with some generic text thrown in after the command. STATS test STATS VALUE NORMAL OK, that seemed to work. What about if we change the case of the STATS command? stats test UNKNOWN COMMAND OK, commands look to be case sensitive. Now lets try some other random text that wasn’t listed as a supported command. BLAH UNKNOWN COMMAND OK, it appears as though any incorrect/unsupported commands generate an UNKNOWN COMMAND response. Now lets try another supported command, along with a random parameter. TRUN hhh TRUN COMPLETE OK, that gave a different response as well. Now lets see if we can get more information about one of the supported commands. HELP STATS Command specific help has not been implemented No, nothing helpful there. As you may realize by now, what I’m trying to accomplish by interrogating the program in this fashion is to figure out what types of messages are accepted by the program in order to work out how I will structure my fuzzing requests. Based on what we have seen so far, it appears as though this program accepts a number of “supported commands”, and certain of these commands seem to somehow utilise an input parameter. Considering this, some of the ways in which we could introduce fuzzed data into the application could be to insert it:
In place of a supported command As a parameter to each of the supported commands that indicate that they support parameters (STATS, RTIME, LTIME, etc). As a parameter to each of the supported commands that don’t indicate that they support parameters (HELP, and maybe EXIT). In reality this is probably the least likely method to provide good results, but since there are not many commands that fall into this category it’s probably worth giving this a go anyway.
So now we have an idea of how we can communicate with the Vulnserver application, and where in the Vulnserver “protocol” we might be able to insert our fuzz data. Lets close our session with the Vulnserver application. EXIT GOODBYE This is an extremely simple example of protocol analysis, but I believe it demonstrates the general pre-fuzzing process fairly well – we determine how the program receives input data from the user, and use that method to insert fuzzed data into the application.
Fuzzing vulnserver using SPIKE
So now lets use the knowledge gained from analysing the Vulnserver “protocol” to actually fuzz the application using SPIKE. In the previous section, we identified that it might be useful to send fuzzed strings in place of a supported command, and as parameters to supported commands that do, and do not seem to support parameters. Lets start off with the simplest case first – sending a fuzzed string in place of a supported command. A SPIKE script to achieve this looks like the following: s_readline(); //print received line from server s_string_variable(“COMMAND”); //send fuzzed string Here, we are waiting to receive the initial “Welcome” message from the server that we see when we connect, then we send the fuzzed string to the application. Save this content to disk on your Linux fuzzing system as “vscommand.spk”. Before we actually go and launch this script with SPIKE, lets start a packet capture with Wireshark on our Linux system so that we can see what is actually being sent by SPIKE. My target copy of Vulnserver is listening on a machine with the IP address 192.168.56.101 on the default port of 9999, so I will setup a capture filter to ignore all other traffic. The filter looks like the below – if you have your target system on a different IP address, or Vulnserver is listening on a different port adjust your filter accordingly. host 192.168.56.101 and tcp port 9999
Start the Wireshark capture and then kick off your SPIKE fuzzer, using a command like the one specified below. This command assumes that you are performing your fuzzing from BackTrack, which by default stores SPIKE in /pentest/fuzzers/spike, and that you have saved your vscommand.spk file into the present working directory. If you have downloaded SPIKE yourself generic_send_tcp will be located in the SPIKE/SPIKE/src directory inside the SPIKE archive (see the Requirements and System Setup section for some detail on installing SPIKE). root@bt4r1vm:~/vulnserver# /pentest/fuzzers/spike/generic_send_tcp 192.168.56.101 9999 vscommand.spk 0 0 Total Number of Strings is 681 Fuzzing Fuzzing Variable 0:0 line read=Welcome to Vulnerable Server! Enter HELP for help. Fuzzing Variable 0:1 Variablesize= 5004 Fuzzing Variable 0:2 line read=Welcome to Vulnerable Server! Enter HELP for help. Variablesize= 5005 […SNIP…] Fuzzing Variable 0:2041 line read=Welcome to Vulnerable Server! Enter HELP for help. Fuzzing Variable 0:2042 line read=Welcome to Vulnerable Server! Enter HELP for help. Fuzzing Variable 0:2043 line read=Welcome to Vulnerable Server! Enter HELP for help. Done. If you leave it running, this SPIKE script should complete after a few minutes, and if you check VulnServer running in its debugger, you will notice that it seems to be running fine – there has been no crash. So it appears that just sending bad data in place of a supported command does not cause VulnServer to crash (or at least sending the bad strings generated by SPIKE in place of a command does not cause Vulnserver to crash.) That’s OK, we still have plenty of other areas in the program into which we can insert bad data, but before we move on, lets have a look at the data we captured in Wireshark, so we can see what SPIKE was doing. If we scroll up to the very top of the Wireshark window, select the very first packet, and right click and choose Follow TCP Stream from the menu, we should be able to see the content of the first SPIKE that was sent.
The first SPIKE looks like the following. You can see what’s happened here, SPIKE has simply received the Welcome message from the server and then sent the string COMMAND to the application. This string, not coincidentally, is exactly the string that we specified within the s_string_variable command from our SPIKE script file. So far, SPIKE has not done anything particularly interesting, but maybe when we look at some of the other requests…
One other thing to note here before we move on is that we are seeing the response from the server to this input we provided – namely the string “UNKNOWN COMMAND” – being sent back to the client. This indicates that after receiving this string from SPIKE, the Vulnserver application was still able to send back a response – meaning it had not at this stage crashed. Later on when we get to the point of actually causing a crash, this type of information will become important in recognising which fuzz string did the damage. Lets have a look at the next request. Hit the Filter Out This Stream button at the bottom of the Follow TCP Stream window, and then right click on the first packet in the newly filtered Wireshark view and select Follow TCP Stream once more. This time we see something a lot more interesting. Instead of the text “COMMAND” that we saw in the last request, SPIKE has instead sent a very long string of upper case “A” characters, preceded by a few other random characters.
You can continue to Filter Out This Stream and check some of the other fuzzed values that SPIKE has sent if you’re curious. The main thing to understand here though, is that every time the s_string_variable command is used in a SPIKE script, SPIKE will first send the text specified in brackets after the command, and it will then iterate through its list of predefined fuzz strings, sending each one in turn to the application until it is done. If you have multiple variables in your script, it will iterate through all possible values for each variable in turn, starting with the first one that appears, and all other variables will be replaced with their specified text value (the one you provided in brackets) until their turn comes. What you cant do with SPIKE scripts however, is create multiple separate SPIKES using one script. If you have multiple different message types with fixed data that you want to fuzz, such as the strings that represent our various supported commands such as STATS, RTIME, LTIME, etc, you therefore need to use individual SPIKE scripts that specify this data using constructs such as the s_string command. This demonstrates the basic process for running a single SPIKE script, but for Vulnserver there are a number of other areas in the program we want to fuzz, and it wont be very convenient to individually execute and watch each required SPIKE scripts as it runs to see when it crashes our program. In Part 2 we cover fuzzer automating using SPIKE and VULNSERVER.