This is an old revision of the document!
Table of Contents
Session 07
Stateless Fuzzing
Slides
Tutorials
“To fuzz or not to fuzz ?”
Fuzzing is a software testing technique, often automated, that involves providing invalid, unexpected or random data as input to a program. From a security perspective, it's imperative for discovering new software vulnerabilities in applications where you don't have access to the underlying source code and even in applications where you do have the source code. The phases of the fuzzing process are presented in the following figure.
The first step in the fuzzing process is to identify the target which you would like to fuzz. While this is generally an application running on a system, there may be different data input vectors for it such as:
- command line parameters
- files (configuration/application specific files) that the application parses
- network sockets
- stdin
The next logical step is to try to understand the structure of the input data in order to see what fields should be fuzzed and with what values. Following this, we generate the fuzzed data . Depending on how you derive the fuzzing data, you can have:
- Mutation-based fuzzers where you take valid data and then modify it
- Generation-based fuzzers where you contruct the data from the ground up based on its specific structure
Following this, the generated fuzz data is executed against the target application and we monitor succesively for exceptions. After each fuzz test, the application is killed and restored to its initial state. Once a crash/hang has been found, we proceed to determine whether the vulnerability is exploitable.
Stateless vs. Stateful Fuzzing
We've hinted a bit in the preceding section about restoring the application to its initial state after each fuzz test is run. This can be as simple as just restarting the application in the case of stateless fuzzing where we have a fixed state from which we're trying to fuzz to performing the necessary operations to get the application into a specific state before performing the fuzz test in the case of stateful fuzzing. In this session we'll be covering only stateless fuzzing but we will also go into stateful fuzzing in the next session which will build on the knowledge gained in this one.
Fuzzing Frameworks
A fuzzing framework is mostly concerned with generating the fuzzing data, but it can also serve the following aditional functions:
- Orchestrate running the program against the generated test data and see whether it crashed
- Automate collecting debugging and run information for the test cases that crashed or caused the application to go into an abnormal state
- Track the progress and time needed to run the fuzz tests
- Generate reports and automatically assess the exploitability of the discovered vulnerability
Most fuzzing frameworks are designed only for the data generation stage, leaving the test execution to the user. For this particular lab we will be using the Sulley Fuzzing Framework which, as we'll see, covers all of the above functionality.
The Sulley Fuzzing Framework
Sulley is a fuzzer development and fuzz testing framework consisting of multiple extensible components. It's also Python based so it can basically run on any platform.
Overall usage of Sulley breaks down to the following:
- Data Representation: First step in using any fuzzer. Run your target and tickle some interfaces while snagging the packets. Break down the protocol into indvidual requests and represent that as blocks in Sulley.
- Session: Link your developed requests together to form a session, attach the various available Sulley monitoring agents (network, debugger, etc…) and commence fuzzing.
- Post Mortem: Review the generated data and monitored results. Replay individual test cases.
Setting up Sulley
The first step in installing Sulley is to clone the Github repository for it:
git clone https://github.com/OpenRCE/sulley.git
Sulley depends upon the following libraries:
- pcapy: a python library that knows how to capture packets
apt-get install python-pcapy python-impacket
If everything is set up appropriately you should be able to run the following commands:
sulley$ sudo python network_monitor.py ERR> USAGE: network_monitor.py <-d|--device DEVICE #> device to sniff on (see list below) [-f|--filter PCAP FILTER] BPF filter string [-P|--log_path PATH] log directory to store pcaps to [-l|--log_level LEVEL] log level (default 1), increase for more verbosity [--port PORT] TCP port to bind this agent to Network Device List: [0] eth0 [1] virbr0 [2] usbmon1 [3] usbmon2 [4] any [5] lo
sudo python process_monitor_unix.py ERR> USAGE: process_monitor_unix.py -c|--crash_bin File to record crash info too [-P|--port PORT] TCP port to bind this agent too [-l|--log_level LEVEL] log level (default 1), increase for more verbosity
Running a fuzz scenario with Sulley
Without going into all the details in the user manual, there are some basics that we need to know. When fuzzing with Sulley, we need to write a python script that defines all required objects that Sulley needs in order to fuzz specific target. Those objects are:
- Data Model: data model defines the properties of the network protocol that we’re going to fuzz. Example of FTP protocol: data model should define the structure of all possible FTP commands.
- State Model: state model is used to define possible interactions between different states of the fuzzed network protocol. Example of FTP protocol: state model should state that at first, we’re only allowed to enter a few commands to authenticate to the FTP server, like USER and PASS commands. After we’re authenticated, more commands become available, therefore we’re changing the state from non-authenticated to authenticated.
- Target: target defines what we’re going to fuzz. Example of FTP protocol: here we should specify the IP and port of the FTP server we’ll be fuzzing.
- Agents: agents are special programs running on the target computer, which do various things, amongst others are: monitoring the fuzzed process for crashes, intercepting the relevant network packets, restarting the crashed process, etc.
- Monitoring Interface: monitoring interface allows us to easily see the result of fuzzing process, how many of the test cases were already sent, how many of them caused a crash, etc.
Tasks
Manual Fuzzing
Download the following archive containing a linux binary server.tgz. Unpack it and run the program to see what it does. Try to discover at least one vulnerability by sending manual input to it through the network socket it's listening on.