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 make
During compilation, you should see similar printouts to what afl-gcc provided:
afl-clang-fast 1.83b by <email@example.com> afl-llvm-pass 1.83b by <firstname.lastname@example.org> [+] 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
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!
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.
screen afl-fuzz -i testcases/ -o syncdir/ -M fuzzer1 tcpdump-4.6.2/tcpdump -nr @@
Notice that I am adding a new argument to
-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
screen 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
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 <email@example.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.