winafl: fuzzing tool for coverage-guided fuzzing

winafl

AFL is a popular fuzzing tool for coverage-guided fuzzing. The tool combines fast target execution with clever heuristics to find new execution paths in the target binary. It has been successfully used to find a large number of vulnerabilities in real products. For more info about the original project, please refer to the original documentation at:

http://lcamtuf.coredump.cx/afl/

Unfortunately, the original AFL does not work on Windows due to very *nix-specific design (e.g. instrumentation, forkserver etc). This project is a fork of AFL that uses different instrumentation approach which works on Windows even for black box binary fuzzing.

The WinAFL approach

Instead of instrumenting the code at compilation time, WinAFL relies on dynamic instrumentation using DynamoRIO (http://dynamorio.org/) to measure and extract target coverage. This approach has been found to introduce an overhead about 2x compared to the native execution speed, which is comparable to the original AFL in the binary instrumentation mode.

afl-fuzz.exe

To improve the process startup time, WinAFL relies heavily on persistent fuzzing mode, that is, executing multiple input samples without restarting the target process. This is accomplished by selecting a target function (that the user wants to fuzz) and instrumenting it so that it runs in a loop.

WinAFL has been successfully used to identify bugs in Windows software, such as

  • CVE-2016-7212 – found by Aral Yaman of Noser Engineering AG
  • CVE-2017-0073, CVE-2017-0190, CVE-2017-11816 – found by Symeon Paraschoudis of SensePost

Building WinAFL

  1. Download and build DynamoRIO sources or download DynamoRIO Windows binary package from https://github.com/DynamoRIO/dynamorio/wiki/Downloads
  2. Open Visual Studio Command Prompt (or Visual Studio x64 Win64 Command Prompt if you want a 64-bit build). Note that you need a 64-bit winafl.dll build if you are fuzzing 64-bit targets and vice versa.
  3. Go to the directory containing the source: git clone https://github.com/ivanfratric/winafl.git
  4. Type the following commands. Modify the -DDynamoRIO_DIR flag to point to the location of your DynamoRIO cmake files (either full path or relative to the source directory).
For a 32-bit build:

mkdir build32
cd build32
cmake .. -DDynamoRIO_DIR=..\path\to\DynamoRIO\cmake
cmake --build . --config Release
For a 64-bit build:
mkdir build64
cd build64
cmake -G"Visual Studio 10 Win64" .. -DDynamoRIO_DIR=..\path\to\DynamoRIO\cmake
cmake --build . --config Release

 

Usage

The command line for afl-fuzz on Windows is different than on Linux. Instead of:

%s [ afl options ] — target_cmd_line

it now looks like this:

afl-fuzz [afl options] — [instrumentation options] — target_cmd_line

The following afl-fuzz options are supported:

  -i dir        - input directory with test cases

-o dir - output directory for fuzzer findings
-D dir - directory containing DynamoRIO binaries (drrun, drconfig)
-t msec - timeout for each run
-f file - location read by the fuzzed program
-M \\ -S id - distributed mode
-x dir - optional fuzzer dictionary
-m limit - memory limit for the target process

 

The following instrumentation options are used:

  -covtype         - the type of coverage being recorded. Supported options are

bb (basic block, default) or edge.

-coverage_module - module for which to record coverage. Multiple module flags
are supported.

-target_module - module which contains the target function to be fuzzed.
Either -target_method or -target_offset need to be
specified together with this option.

-target_method - name of the method to fuzz in persistent mode. For this to
work either the method needs to be exported or the symbols
for target_module need to be available. Otherwise use
-target_offset instead.

-target_offset - offset of the method to fuzz from the start of the module.

-fuzz_iterations - Maximum number of iterations for the target function to run
before restarting the target process.

-nargs - Number of arguments the fuzzed method takes. This is used
to save/restore the arguments between runs.

-debug - Debug mode. Does not try to connect to the server. Outputs
a log file containing loaded modules, opened files and
coverage information.

-logdir - specifies in which directory the log file will be written
(only to be used with -debug).

-call_convention - The default calling convention is cdecl on 32-bit x86
platforms and Microsoft x64 for Visual Studio 64-bit
applications. Possible values:
* fastcall: fastcall
* ms64: Microsoft x64 (Visual Studio)
* stdcall: cdecl or stdcall
* thiscall: thiscall

-thread_coverage - If set, WinAFL will only collect coverage from a thread
that executed the target function

 

Tutorial

Original AFL code was written by Michal Zalewski <lcamtuf@google.com>

Windows fork wrote and maintained by Ivan Fratric <ifratric@google.com>

Copyright 2016 Google Inc. All Rights Reserved.

Source: https://github.com/ivanfratric/