Fuzzing with simple fuzzers like zzuf will expose easy to find bugs, but there are much more advanced fuzzing strategies. One is to write fuzzers that are aware of the file format used. You may for example try to set all fields in a file header to maximum or minimum values. However format aware fuzzing is cumbersome, because you'll need a fuzzer for every input format you are fuzzing.
Compile-time instrumented fuzzing goes another route: It adds instructions to an application's code that allow the fuzzer to detect code paths in the application. It can then use promising fuzzing samples that expose large parts of the code for further fuzzing.
american fuzzy lop (afl) does instrumented fuzzing and is probably the best fuzzing tool available at the moment. When installed it will provide you wrappers for gcc that add the instrumentation code. The use of afl can lead to quite surprising results.
Let's assume again you have a tool that uses an autoconf-based configure script. Compile your code with afl:
./configure CC="afl-gcc" CXX="afl-g++" --disable-shared; make
Again we use --disable-shared to statically compile if possible and avoid LD_PRELOAD calls.
Now we need one or several input samples. Preferrably they should be small. We place them in a directory we will call in. Now we start afl-fuzz:
afl-fuzz -i in -o out [path_to_tool] @@
The @@ is replaced by the fuzzed input files. If you skip that it will pass the fuzzed file on the standard input. When we do this afl-fuzz will usually complain that you should change your CPUFREQ settings to performance because the automatic frequency scaling by the Linux kernel doesn't work well with afl. You can do this by running this command as root:
echo performance | tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor
Alternatively you can also just tell afl to ignore the CPUFREQ settings:
AFL_SKIP_CPUFREQ=1 afl-fuzz -i in -o out [path_to_tool] @@
You may also get a warning that your terminal is too small, in this case just make your terminal window a bit larger. When we're done we will see an interface like this:
When everything is done correct you should see new paths every now and then. If total paths stays at 1 you probably have set up something wrong. The most interesting value is the uniq crashes. There you will see if you found any segfaults, most of them will likely be memory access errors.
The samples that create crashes will be collected in out/crashes. You will also find potential hangs in out/hangs, however you should check if they really hang your tool. The default timeout of afl is quite low so you'll see a lot of false positives here.
american fuzzy lop does a lot of file writes (hundreds or thousands per second). this blog post suggests using a ram disk to avoid too much stress for your SSD. This is probably a good idea.
We learned in part 2 that Address Sanitizer can greatly improve your bug finding capabilities and in this chapter that american fuzzy lop is one of the most advanced fuzzers available. Obviously what we'd like to do is get the power of both.
Unfortunately this comes with a number of difficulties. Address Sanitizer needs a lot of virtual memory and by default afl will limit the amount of memory a fuzzed software gets. The easiest way around this is to just disable the memory limit (-m none). However be warned: Your fuzzed software may actually try to really allocate and use a lot of memory due to your fuzzed samples. This may lead to random crashes in your system. You shouldn't do any important work while doing so.
To enable the use of Address Sanitizer you need to set the environment variable AFL_USE_ASAN to 1 during compilation. You should also set AFL_HARDEN to 1 which will enable additional compile time hardening features:
AFL_USE_ASAN=1 AFL_HARDEN=1 ./configure CC=afl-gcc CXX=afl-g++ --disable-shared; make
Fuzzing itself is the same as above. Please note that using Address Sanitizer will give you fuzzing samples that often won't crash the vanilla application. To help upstream developers it's wise to include the address sanitizer crash dump to help them in their analysis.
Please note that using afl with Address Sanitizer will significantly slow down your fuzzing efforts. But it will likely still find more bugs.
That's it. Please also consult the official american fuzzy lop documentation. Now start the fuzzing!
The Fuzzing Project is run by Hanno Böck