Application Security and Software Consulting

Advanced usage of American Fuzzy Lop with real world examples

After getting American Fuzzy Lop set up and fuzzing tcpdump at a basic level, we can move onto some more advanced features of afl that allow you to get quite a few speed increases, which is of the utmost importance when fuzzing.

Previously, I introduced afl-gcc as a wrapper for gcc that will instrument the resulting binary as it compiles in order to provide feedback during the fuzzing process. However, this time we will use afl-clang-fast which allows for a nice speedboost.

In order to enable the use of afl-clang-fast, I will need to install clang in the chroot that I created for the first tutorial.

apt-get install clang -y

Inside the afl-1.83b folder is another folder called llvm_mode, which contains the source for the afl-clang-fast clang wrapper. Changing to this directory, we can build these binaries and use them to build tcpdump again in a slightly different way.

cd /root/afl-1.83b/llvm_mode
LLVM_CONFIG=llvm-config-3.4 make
cd ../
make install
which afl-clang-fast

Running the previous commands should build and install afl-clang-fast, then print the location to the new afl-clang-fast binary (in /usr/local/bin). Now I can rebuild tcpdump using the afl-clang-fast binary, which should give me a nice speed boost.

cd /root/tcpdump-4.6.2/
make clean
CC=afl-clang-fast ./configure

During compilation, you should see similar printouts to what afl-gcc provided:

afl-clang-fast 1.83b by <lszekeres@google.com>
afl-llvm-pass 1.83b by <lszekeres@google.com>
[+] Instrumented 268 locations (non-hardened mode, ratio 100%).

Once compiled, in order to have clean results, the findings directory used in previous examples needs to be removed and recreated so I can begin fuzzing the new binary with the same afl-fuzz command.

cd /root
rm -rf findings && mkdir findings
afl-fuzz -i testcases/ -o findings/ tcpdump-4.6.2/tcpdump -nr @@

With this, I now get upwards of 1000 executions per second, when using afl-gcc to create the tcpdump binary, I was having trouble maintaining 900 executions per second. That’s about a 10% increase and that adds up over time!

A speed increase from afl-gcc using afl-clang-fast

Now, afl-fuzz only takes up a single core, so on most modern systems, a single instance of afl-fuzz leaves a whole lot of system left doing nothing. I can use a master/slave feature of afl that lets one afl-fuzz instance (the master) perform deterministic fuzzing while the slaves perform more traditional random fuzzing.

In order to achieve this, I will remove the findings directory completely and create a new directory called syncdir which all the afl-fuzz instances will use.

cd /root
rm -rf findings && mkdir syncdir

I am also going to use screen this time so that I can start my afl-fuzz processes in the background without worrying about keeping them alive in an open terminal window. The first afl-fuzz instance I will create is the ‘master’ instance whose only job is to perform deterministic fuzzing.

afl-fuzz -i testcases/ -o syncdir/ -M fuzzer1 tcpdump-4.6.2/tcpdump -nr @@

Notice that I am adding a new argument to afl-fuzz. -M means that this process will be a master process, and that the name of the process will be ‘fuzzer1’. My amateurish fuzzing server has 6 cores, so I can easily add 3 slave processes and still have some room left for other processes if need be. If you are still in the screen session for the master fuzzer, hit ctrl-a, then ctrl-d to background the master screen session. I can create the next three afl-fuzz processes in a similar way

afl-fuzz -i testcases/ -o syncdir/ -S fuzzer2 tcpdump-4.6.2/tcpdump -nr @@

Instead of using the -M argument, I am now using -S which means that this process will be a slave process, performing nondeterministic random fuzzing. In order to add 2 more afl-fuzz processes, I run the exact same commands, but naming the new fuzzers fuzzer3 and fuzzer4.

When I list the contents of the syncdir directory, I see the names of my fuzzers that are currently running.

# ls syncdir/
fuzzer1  fuzzer2  fuzzer3  fuzzer4

You might be wondering, how can I keep track of where each fuzzer is and how it is doing if each process is running in a screen session in the background? Running a single terminal for each fuzzer takes up a lot of real estate and is cumbersome. Luckily, afl comes with a utility to remedy just this scenario called afl-whatsup. If you point afl-whatsup to the syncdir that all the fuzzer instances are using to store their data, it will give a nice summary of what is currently happening.

# afl-whatsup syncdir/
status check tool for afl-fuzz by <lcamtuf@google.com>

Individual fuzzers

>>> fuzzer4 (0 days, 0 hrs) <<<

cycle 1, lifetime speed 1058 execs/sec, path 73/855 (8%)
pending 392/831, coverage 4.65%, crash count 3 (!)

>>> fuzzer1 (0 days, 0 hrs) <<<

cycle 1, lifetime speed 943 execs/sec, path 83/821 (10%)
pending 381/797, coverage 4.65%, crash count 1 (!)

>>> fuzzer3 (0 days, 0 hrs) <<<

cycle 1, lifetime speed 1040 execs/sec, path 76/859 (8%)
pending 396/833, coverage 4.77%, crash count 1 (!)

>>> fuzzer2 (0 days, 0 hrs) <<<

cycle 1, lifetime speed 1012 execs/sec, path 61/860 (7%)
pending 392/841, coverage 4.61%, crash count 1 (!)

Summary stats

Fuzzers alive : 4
Total run time : 0 days, 0 hours
Total execs : 3 million
Cumulative speed : 4030 execs/sec
Pending paths : 1561 faves, 3302 total
Pending per fuzzer : 390 faves, 825 total (on average)
Crashes found : 6 locally unique

On my fuzzing machine, I actually use the watch command to refresh the output of afl-whatsup every couple of seconds on a passive monitor that I can just glance at. If you notice, cumulatively we are achieving 4000 executions a second, as opposed to the paultry 900-1000 a single fuzzer was giving. Letting this sit for a week will yield some excellent test cases that causes crashes and hangs.