Skip to content
This repository has been archived by the owner on Jan 20, 2020. It is now read-only.

How to use Maxfuzz

Everest Stefan Munro-Zeisberger edited this page May 3, 2018 · 4 revisions

🚀 Getting Started

This guide assumes you have Docker, docker-compose and make installed. For more on getting set up, please check out our Development Environment Setup wiki page

🐞 Find your first bug

First, build the base Maxfuzz Docker image: make build

Then spin up a local instance of Maxfuzz, running some sample fuzzers: make deploy-dev

This launches a basic fuzzer that fuzzes some vulnerable C code, which can be found in ./fuzzers/vulnerable/.

Upon deploying the fuzzer locally you should see some crashes appear fairly quickly in ./sync/afl-vulnerable/crashes/.

As these crashers are uncovered by AFL, you should see corresponding logs from the Docker containers in the docker-compose view.

⚙️ Fuzzer Setup & Configuration

🔧 How to set up fuzzers

Adding new fuzzers

  1. run ruby new_fuzzer.rb <go|afl> <new_fuzzer_name>

  2. Follow the instructions in <new_fuzzer_name>/README.md

AFL Fuzzers

Take a look at ./fuzzers/vulnerable/ for an example.

Each AFL fuzzer definition consists of three key components:

  1. Test harness: this file should include the library you wish to test, receive input appropriately, and then call the desired methods to fuzz. For an example of a simple harness that takes input and passes it to an imported method, take a look at asan-opencv-2/harness.cpp, a basic test harness that passes input to OpenCV's imdecode method.

  2. Compilation instructions: defined in build_steps and environment, these instructions describe how to compile and link the test harness with the libraries necessary. Dependencies can either be included in the repository, or downloaded at runtime via build_steps if they come from a trusted source.

  3. Example inputs: AFL works best with a small selection of valid input files from which to begin it's fuzz generation. Ensure that these input files are as small as possible, don't cause your code to crash, and that they produce varied results (i.e. don't provide files that will take the same path through the code). Place them in the examples directory.

For details on how to write these files, check out the Fuzzer Reference page.

Gofuzz Fuzzers

Take a look at ./fuzzers/go-ethereum for an example.

Each Gofuzz fuzzer definition consists of two key components:

  1. Gofuzz zip file: the zip file compiled by go-fuzz-build.

  2. Run instructions: defined in build_steps and environment. For gofuzz, the build_steps file remains empty. The only required addition is setting the GO_FUZZ_ZIP variable in environment.

For more details, check out the Fuzzer Reference page.

🖥 How to deploy fuzzers

Locally deploy a fuzzer

Deploying Maxfuzz from latest stable release

To spin up a local instance of Maxfuzz from the latest stable release, running some sample fuzzers (found in ./fuzzers/): make deploy-stable

Deploying Maxfuzz with local changes

First, build the base Maxfuzz Docker image: make build

Then spin up a local instance of Maxfuzz, running some sample fuzzers (found in ./fuzzers/): make deploy-dev

To ensure everything is cleaned up: make teardown

Deploy a fuzzer remotely

Since everything is self-contained in a Docker Container, deploying a fuzzer is as simple as spinning up a VM using Amazon ECS (or equivalent) - just be sure to send all crashes to an S3 Bucket, so they're not lost when you restart your VM.

Components

Maxfuzz currently has two components to it: fuzzers and reproducers.

For Gofuzz, you only need to deploy a fuzzer (by starting up a Docker container that runs the command /root/fuzzer-files/<your fuzzer name>/start). Since Gofuzz automatically saves command output, nothing else is necessary.

For AFL, you must deploy both a fuzzer and a reproducer to take full advantage of Maxfuzz. The reproducer takes the inputs that have been found to crash the code, and re-runs the code against these inputs to save the stacktrace and output. Start the fuzzer with /root/fuzzer-files/<your fuzzer name>/start and the reproducer with /root/fuzzer-files/<your fuzzer name>/start reproduce, each in their own container.

The two boxes talk via a Redis instance. You can see an example of this configuration in /docker-compose-dev.yml, and read more about configuring this Redis connection in the Environment Variables section further down.

🔍 Uncovering Bugs

Basics

Running make deploy-(stable|dev) with the default docker-compose configuration launches a basic fuzzer that fuzzes some vulnerable C code, which can be found in /fuzzers/vulnerable/.

Upon deploying the fuzzer locally you should see some crashes appear fairly quickly under /sync/afl-vulnerable/crashes/. These will appear in the form of files containing the input that crashes the code, along with .output files that show you the corresponding stacktrace.

As these crashers are uncovered by fuzzers, you should see corresponding logs from the Docker containers in the docker-compose view, as Maxfuzz uncovers bugs and passes them to the reproduction box to save their stacktrace.

Details

When crashes are found, they are sent either to the local sync directory (when S3 Syncing is turned off), or to the specified AWS S3 Bucket (when configured to do so - see the next section on Environment Variables).

The filenames are formatted as follows:

<fuzzer instance name>_<afl/gofuzz-generated filename>_<time of crash>_<current git SHA>(.output)

Where files without .output contain the actual input that produces a bug, with the .output file containing the stacktrace and output as a result of the crash.

📑 Environment Variable Reference

Maxfuzz has the following environment variables for configuration:

File management:

  • MAXFUZZ_ENABLE_S3: 0 to save crashes to /root/sync in the Docker container (which can then be volumed out to save to local filesystem), or 1 to save crashes & backups to S3

  • AWS_ACCESS_KEY_ID: ID for AWS key - used to talk to S3

  • AWS_SECRET_ACCESS_KEY: Secret AWS key - used to talk to S3

  • CRASH_BUCKET: S3 bucket name

  • AWS_REGION: defaults to us-east-1

Other:

  • REDIS_QUEUE_URL: URL for a redis queue, used to transmit data about crash reproduction between fuzzer container and reproduction container

  • MAXFUZZ_ENV: set to test to stub out actual Amazon S3 method calls, and stub out redis calls - used when running unit tests

  • NO_REPRODUCTION: 1 to not attempt to reproduce AFL crashes. Can be used in testing to turn off extra functionality