Shiva is a fuzzer library in Python. It is currently in early development stages, but aims to be an effective tool.
In a generic sense, a fuzzer is an application that tests program input for security vulnerabilities. Fuzz testing is a black box vulnerability discovery technique, meaning it does not involve source code or reverse engineering. Any input is a possible vector for a security vulnerability and should be fuzzed. Some possible inputs are files, command line arguments, sockets, and environment variables (these go overlooked, a lot). Fuzzers use many different techniques to detect crashes. Some are "dumb" and will run through all test cases and the user has to manually inspect for crashes, some use crash dumps, others have built in debuggers. There are also several types of data generation, fuzzers can be totally random, have a set number of test cases, among other techniques.
Shiva was designed to be implemented as a Python library. It supports file fuzzing, command line argument fuzzing, socket fuzzing, and environment variable fuzzing. It has a built in debugger (using the python-ptrace library).
$ git clone https://bitbucket.org/vorbis/python-ptrace.git $ cd python-ptrace $ sudo python setup.py install
Then, download Shiva.
$ git clone https://bitbucket.org/vorbis/python-shiva.git $ cd python-shiva $ sudo python setup.py install
The library can be imported with:
from shiva.shiva import Shiva
This imports the Shiva class from the library. The arguments to instantiate the class are filename, mode, arguments, hostname, port, and outfile. Not all of these are required for every fuzzer mode, however the filename and mode arguments are mandatory. Filename is the path to the binary to be fuzzed, mode is the type of fuzzer to use, valid strings are "file", "args", "env", "client", and "server." The "file" argument is for file fuzzing and the outfile variable is required. outfile is the path to the output file for fuzz cases. Command line argument fuzzing can be selected by passing "args" to the mode argument, this only requires the arguments variable. "env" fuzzes environment variables, it does not require any other arguments. The "client" and "server" modes fuzz a client or server socket respectively and require the hostname and port arguments. The arguments variable is optional in all modes except for "args" mode.
There are three functions that the user will use, Shiva.load(), Shiva.start(), and Shiva.stop().
Shiva.load() creates the fuzzcases, in socket modes it will send() the fuzzcase, as well. The index argument is required, this is the position the fuzzer is at in the Shiva.cases tuple. This variable should be incremented by the user, it does not autoincrement (this allows the user to have more control). In all but command line argument mode, the file argument is required (in command line argument mode, Shiva.arguments is fuzzed). In file and sockets modes, this argument specifies the file to retrieve fuzzcases from. In environment variable mode, this should be the value of the environment variable to be fuzzed, the name will be passed to Shiva.start(). This function should be ran previous to Shiva.start() in all modes except for socket modes. In socket modes, this should be after Shiva.start() and can be ran multiple times (i.e. once per packet).
This function uses "||" as the delimeter for fuzz cases, so if your input file is:
GET || HTTP\1.1
It will become:
GET A HTTP\1.1
Shiva.start() starts the process to be fuzzed. Only environment variable mode requires an argument for this function, this is the name of the environment variable to be fuzzed. This function starts the target process, starts the debugger, and starts the fuzzer socket (in the case of socket modes).
Shiva.stop() kills the process and removes any open sockets. This does not take any arguments. Keep in mind, this function cannot run without having first started the fuzzer.
This section describes the techniques used by Shiva.
In this version, the data generation is fairly static, it creates a tuple (Shiva.cases) of the fuzz cases. This is a range of character strings (using the characters "A", "P", and ASCII 0x15). It also has tests for format string bugs and integer overflows. In future versions, this will improve, become more intelligent and dynamic.
Currently, the fuzzer uses python-ptrace for fault detection. Python-ptrace is a wrapper for ptrace, its constants and other functions like wait(), strsignal(), etc. It works for 32-bit and 64-bit processors running Mac OS X and Linux. It outputs the EIP and fuzz string to a file (filename.log). This will also improve in the future.
from shiva import Shiva fuzzer = Shiva("/usr/bin/ncat", "server", arguments="-lp4444", hostname="127.0.0.1", port=4444) fuzzer.start() fuzzer.load(0, "test/packet1") for i in range(1, len(fuzzer.cases)): fuzzer.load(i, "test/packet2") if fuzzer.crash: fuzzer.stop() fuzzer.stop()
test/packet1: "GET || HTTP\1.1" test/packet2: "HEAD || HTTP\1.1"