
AFL/QEMU fuzzing with full-system emulation.
New: For those looking to play with TriforceAFL and TLSF, Richard Johnson created a Dockerfile which installs both (and even builds a Linux kernel for you). It's available here https://hub.docker.com/r/moflow/afl-triforce/tags/.
Also new: afl-tmin now works with the forkserver!
https://github.com/nccgroup/TriforceAFL Jesse Hertz [email protected] Tim Newsham [email protected]
This is a patched version of AFL that supports full-system fuzzing using QEMU. The included QEMU has been updated to allow tracing of branches when running a system emulator for x86_64. Extra instructions have been added to start AFL's forkserver, make fuzz settings, and mark the start and stop of test cases.
Note: not all of the AFL tools have been tested with the new changes. These tools have seen some testing:
To build:
make
To get a coverage map:
echo hello > /tmp/hello
./afl-showmap -o coverage.txt -QQ --
./afl-qemu-system-trace -kernel ../bzImage
-initrd ../initramfs.cpio.gz -m 1G -nographic
-append "console=ttyS0" -aflFile /tmp/hello
cat coverage.txt
To fuzz:
egrep ' (panic|log_store)$' ../mykern/kallsyms ffffffff8108e570 t log_store ffffffff8181064b T panic
mkdir inputs
echo hello > inputs/hello
./afl-fuzz -i inputs -o outputs -QQ --
afl-qemu-system-trace -kernel bzImage -initrd root.cpio.gz
-m 1G -nographic -append "console=ttyS0"
-aflPanicAddr ffffffff8181064b -aflDmesgAddr ffffffff8108e570
-aflFile @@
(Note: unlike when using the "-Q" option, you must specify the full command line to afl-qemu-system-trace when using the "-QQ" option).
For more details on how to use this modified version of AFL, see our Linux syscall fuzzer at https://github.com/nccgroup/TriforceLinuxSyscallFuzzer.
New AFL flags: -QQ - use qemu in full-system emulation rather than user-mode (-Q)
New QEMU flags: -aflFile - The name of the file containing fuzzer inputs -aflPanicAddr - A address of a kernel panic address for panic detection -aflDmesgAddr - Linux kernel address of dmesg logging function for detecting logging and intercepting log messages
New QEMU instructions: 0f 24 - aflCall edi=1 startForkserver(esi=enableTicks) Start AFL's fork server. After this point each test will run in a separate forked child. If enableTicks is non-zero, QEMU will re-enable the CPUs timer after forking a child, otherwise it will not be enabled. edi=2 getWork(esi=ptr, edx=sz) Fill ptr[0..sz] with the next input test case. Returns the actual size filled (<= sz). edi=3 startWork(esi=ptr) Tell AFL to start tracing. The argument points to a buffer with two quadwords giving the start and end address of the code to trace. Instructions outside of this range are not traced. edi=4 doneWork(esi=exitCode) Tell AFL that the test case has completed. If a panic is detected, AFL will stop the test case immediately. Otherwise it will run until doneWork is called. The exitCode specified is returned to AFL. (The code can, but currently does not, OR in the value 64 to all exit codes if any dmesg logs were detected during the test case.)
New QEMU block driver: -drive filename=privmem: This block driver keeps the drive's image in copy-on-write memory so that changes are never persisted to disk. Changes made by on test case are isolated from other test cases.
Written and maintained by Michal Zalewski [email protected]
Copyright 2013, 2014, 2015, 2016 Google Inc. All rights reserved. Released under terms and conditions of Apache License, Version 2.0.
For new versions and additional information, check out: http://lcamtuf.coredump.cx/afl/
To compare notes with other users or get notified about major new features, send a mail to [email protected].
** See QuickStartGuide.txt if you don't have time to read this file. **
Fuzzing is one of the most powerful and proven strategies for identifying security issues in real-world software; it is responsible for the vast majority of remote code execution and privilege escalation bugs found to date in security-critical software.
Unfortunately, fuzzing is also relatively shallow; blind, random mutations make it very unlikely to reach certain code paths in the tested code, leaving some vulnerabilities firmly outside the reach of this technique.
There have been numerous attempts to solve this problem. One of the early approaches - pioneered by Tavis Ormandy - is corpus distillation. The method relies on coverage signals to select a subset of interesting seeds from a massive, high-quality corpus of candidate files, and then fuzz them by traditional means. The approach works exceptionally well, but requires such a corpus to be readily available. In addition, block coverage measurements provide only a very simplistic understanding of program state, and are less useful for guiding the fuzzing effort in the long haul.
Other, more sophisticated research has focused on techniques such as program flow analysis ("concolic execution"), symbolic execution, or static analysis. All these methods are extremely promising in experimental settings, but tend to suffer from reliability and performance problems in practical uses - and currently do not offer a viable alternative to "dumb" fuzzing techniques.
American Fuzzy Lop is a brute-force fuzzer coupled with an exceedingly simple but rock-solid instrumentation-guided genetic algorithm. It uses a modified form of edge coverage to effortlessly pick up subtle, local-scale changes to program control flow.
Simplifying a bit, the overall algorithm can be summed up as:
Load user-supplied initial test cases into the queue,
Take next input file from the queue,
Attempt to trim the test case to the smallest size that doesn't alter the measured behavior of the program,
Repeatedly mutate the file using a balanced and well-researched variety of traditional fuzzing strategies,
If any of the generated mutations resulted in a new state transition recorded by the instrumentation, add mutated output as a new entry in the queue.
Go to 2.
The discovered test cases are also periodically culled to eliminate ones that have been obsoleted by newer, higher-coverage finds; and undergo several other instrumentation-driven effort minimization steps.
As a side result of the fuzzing process, the tool creates a small, self-contained corpus of interesting test cases. These are extremely useful for seeding other, labor- or resource-intensive testing regimes - for example, for stress-testing browsers, office applications, graphics suites, or closed-source tools.
The fuzzer is thoroughly tested to deliver out-of-the-box performance far superior to blind fuzzing or coverage-only tools.
When source code is available, instrumentation can be injected by a companion tool that works as a drop-in replacement for gcc or clang in any standard build process for third-party code.