
Template-driven binary format fuzzer that generates and parses valid test inputs at high speed, with AFL++ integration for coverage-guided fuzzing.
FormatFuzzer is a framework for high-efficiency, high-quality generation and parsing of binary inputs.
It takes a binary template that describes the format of a binary input and generates an executable that produces and parses the given binary format.
From a binary template for GIF, for instance, FormatFuzzer produces a GIF generator - also known as GIF fuzzer.
Generators produced by FormatFuzzer are highly efficient, producing thousands of valid test inputs per second - in sharp contrast to mutation-based fuzzers, where the large majority of inputs is invalid. Inputs generated by FormatFuzzer are independent from the program under test (or actually, any program), so you can also use them in black-box settings. However, FormatFuzzer also integrates with AFL++ to produce valid inputs that also aim for maximum coverage. In our experiments, this "best of two worlds" approach surpasses all other settings; see our paper for details.
The binary templates used by FormatFuzzer come from the 010 editor.
There are more than 170 binary templates, which either can be used directly for FormatFuzzer or adapted for its use. Out of the box, FormatFuzzer produces formats such as AVI, BMP, GIF, JPG, MIDI, MP3, MP4, PCAP, PNG, WAV, and ZIP; and we keep on extending this list every week.
Contributors are welcome! Visit the FormatFuzzer project page for filing ideas and issues, or adding pull requests. For details on how FormatFuzzer works and how it compares, read our paper for more info.
FormatFuzzer is available from the FormatFuzzer project page. You can download and unpack the latest release from the releases page.
For the very latest and greatest, you can also clone its git repository:
git clone https://github.com/uds-se/FormatFuzzer.git
All further actions take place in its main folder:
cd FormatFuzzer
To run FormatFuzzer, you need the following:
getopt_long()) such as clang or gccpy010parser, six, and intervaltreezlib library (for compression functions)boost library (for checksum functions)If you plan to edit the build and configuration scripts (.ac and .am files), you will also need
sudo apt install git g++ make automake python3-full zlib1g-dev libboost-dev
python3 -m venv ~/fuzz
source ~/fuzz/bin/activate
pip3 install py010parser six intervaltree
xcode-select --install
brew install python3 automake boost
pip3 install py010parser six intervaltree
On all systems, using pip:
pip install py010parser
pip install six
pip install intervaltree
Note: all building commands require you to be in the same folder as this README file. Building a fuzzer outside of this folder is not yet supported.
There's a build.sh script which automates all construction steps.
Simply run
./build.sh gif
to create a GIF fuzzer.
This works for all file formats provided in templates/; if there is a file templates/FOO.bt, then ./build.sh FOO will build a fuzzer.
There's a Makefile (source in Makefile.am) which automates all construction steps.
(Requires GNU make.)
First do
touch configure Makefile.in
then
./configure
and then
make gif-fuzzer
to create a GIF fuzzer.
This works for all file formats provided in templates/; if there is a file templates/FOO.bt, then make FOO-fuzzer will build a fuzzer.
If the above make method does not work, or if you want more control, you may have to proceed manually.
Run the ffcompile compiler to compile the binary template into C++ code. It takes two arguments: the .bt binary template, and a .cpp C++ file to be generated.
./ffcompile templates/gif.bt gif.cpp
Use the following commands to create a fuzzer gif-fuzzer.
First, compile the generic command-line driver:
g++ -c -I . -std=c++17 -g -O3 -Wall fuzzer.cpp
(-I . denotes the location of the bt.h file; -std=c++17 sets the C++ standard.)
Then, compile the binary parser/compiler:
g++ -c -I . -std=c++17 -g -O3 -Wall gif.cpp
Finally, link the binary parser/compiler with the command-line driver to obtain an executable. If you use any extra libraries (such as -lz), be sure to specify these here too.
g++ -O3 gif.o fuzzer.o -o gif-fuzzer -lz
FormatFuzzer can be run as a standalone parser, generator or mutator of specific formats. In addition, it can called by general-purpose fuzzers such as AFL++ to integrate those format-specific capabilities into the fuzzing process (see the section below on AFL++ integration).
The generated fuzzer takes a command as first argument, followed by options and arguments to that command.
The most important command is fuzz, for producing outputs. Its arguments are files to be generated in the appropriate format.
Run the generator as
./gif-fuzzer fuzz output.gif
to create a random binary file output.gif, or
./gif-fuzzer fuzz out1.gif out2.gif out3.gif
to create three GIF files out1.gif, out2.gif, and out3.gif.
Note that the gif.bt template we provide has been augmented with special functions to make generation of valid files easier. If you use an original .bt template files without adaptations, you may get warnings during generation and create invalid files.
You can also run the fuzzer as a parser for binary files, using the parse command. This is useful if you want to test the accuracy of the binary template, or if you want to mutate an input (see `Decision Files', below).
To run the parser, use
./gif-fuzzer parse input.gif
You will see error messages if input.gif cannot be successfully parsed.
While parsing, you can also store all parsing decisions (i.e. which parsing alternatives were taken) in a decision file. This is a sequence of bytes enumerating the decisions taken.
Each byte stands for a single parsing decision. A byte value of 0 means that the first alternative was taken, a byte value of 1 means that the second alternative was taken, and so on.
You can generate such a decision file when parsing an input:
./gif-fuzzer parse --decisions input.dec input.gif
Here, input.dec stores the decisions made for parsing `input.gif'.