This blog post explores my first experience with AFL (american fuzzy lop). I targeted Xpdf, a PDF viewer for Linux distributions. This post is mostly designed to document my trial and error approach to optimizing the fuzzing process of Xpdf by using various AFL tools.
All of this was performed on a standard Ubuntu 14.04 build. No updates were installed. This was because I wanted a more vulnerable setup, so that I could have a higher likelihood of success with AFL.
cd ~/bin wget "http://lcamtuf.coredump.cx/afl/releases/afl-latest.tgz" tar -xf afl-latest.tgz rm afl-latest.tgz mv afl* afl
sudo apt-get install g++
Prepare the Xpdf source code.
cd ~/Downloads wget "ftp://ftp.foolabs.com/pub/xpdf/xpdf-3.04.tar.gz" tar -xf xpdf-3.04.tar.gz rm xpdf-3.04.tar.gz cd xpdf-3.04
Install the dependencies.
sudo apt-get install libpng12-dev libfreetype6-dev libmotif-dev libxt-dev
Configure Xpdf using AFL.
CXX=~/bin/afl/afl-g++ ./configure --with-freetype2-includes=/usr/include/freetype2 make clean all AFL_HARDEN=1
Note the absence of
--disable-shared in the command above. If I included it, I received the following error:
configure: WARNING: unrecognized options: --disable-shared
According to Michal Zalewski, in these cases,
--disabled-shared can simply be left out of the configure command.
The compilation process took under a minute.
I used a set of PDF samples that I obtained from a guy at a place. I put these samples in
~/Downloads/pdfsamples. Next ran
afl-cmin against these samples to find a minimized set of useful samples:
cd ~/Downloads mkdir pdfsamples-minimized ~/bin/afl/afl-cmin -t 500 -i pdfsamples -o pdfsamples-minimized xpdf-3.04/xpdf/xpdf
I tried running the following command, but it would just hang after opening the first file:
~/bin/afl/afl-cmin -i pdfsamples -o pdfsamples-minimized xpdf-3.04/xpdf/xpdf
So in another terminal, I started a hackish way to kill any files that do not crash Xpdf. I know there are far more elegant solutions, but I was looking to fuzz, not create beautiful bash:
for i in `seq 1 1000`; do killall xpdf; sleep 1; done
This reduced the fileset by a significant amount. But I wanted the smallest set possible, so I reduced the fileset a bit more, by repeating this process a few times until the number of input files was the same as the number of output files. For example:
~/bin/afl/afl-cmin -i pdfsamples-minimized-1/ -o pdfsamples-minimized-2/ \ xpdf-3.04/xpdf/xpdf @@ ~/bin/afl/afl-cmin -i pdfsamples-minimized-2/ -o pdfsamples-minimized-3/ \ xpdf-3.04/xpdf/xpdf @@ ~/bin/afl/afl-cmin -i pdfsamples-minimized-3/ -o pdfsamples-final/ \ xpdf-3.04/xpdf/xpdf @@
I tried running the following command:
~/bin/afl/afl-fuzz -i pdfsamples-final/ -o pdf-out xpdf-3.04/xpdf/xpdf @@
However, I recieved the following error:
[-] Hmm, your system is configured to send core dump notifications to an external utility. This will cause issues due to an extended delay between the fuzzed binary malfunctioning and this information being eventually relayed to the fuzzer via the standard waitpid() API. To avoid having crashes misinterpreted as hangs, please log in as root and temporarily modify /proc/sys/kernel/core_pattern, like so: echo core >/proc/sys/kernel/core_pattern
After running that command as root, and re-attempting
afl-fuzz, I got a new error:
[-] Hmm, looks like the target binary terminated before we could complete a handshake with the injected code. There are two probable explanations: - The current memory limit (50.0 MB) is too restrictive, causing an OOM fault in the dynamic linker. This can be fixed with the -m option. A simple way to confirm the diagnosis may be: ( ulimit -Sv $[49 << 10]; /path/to/fuzzed_app ) Tip: you can use http://jwilk.net/software/recidivm to quickly estimate the required amount of virtual memory for the binary.
At the suggestion of a friend, I added the
-m2G parameter to the
~/bin/afl/afl-fuzz -m2G -i pdfsamples-final/ -o pdf-out xpdf-3.04/xpdf/xpdf @@
This did the trick. However, once it was fuzzing away, I noticed a very slow execution rate:
So I tried following instructions from this blog.
cat << EOF > ~/bin/set-up-ramdisk.sh #!/bin/bash if grep -qs '/tmp/afl-ramdisk' /proc/mounts; then sudo umount /tmp/afl-ramdisk rm -rf /tmp/afl-ramdisk fi sudo mkdir /tmp/afl-ramdisk && sudo chmod 777 /tmp/afl-ramdisk sudo mount -t tmpfs -o size=1G tmpfs /tmp/afl-ramdisk cp -R ~/Downloads/xpdf-3.04 /tmp/afl-ramdisk cp -R ~/bin/afl /tmp/afl-ramdisk cp -R ~/Downloads/pdfsamples-minimized-4 /tmp/afl-ramdisk/samples EOF chmod +x ~/bin/set-up-ramdisk.sh sudo -E env "PATH=$PATH" set-up-ramdisk.sh
Next, the following commands kicked off the new setup on the RAM disk:
cd /tmp/afl-ramdisk ./afl/afl-fuzz -m2G -i samples/ -o pdf-out xpdf-3.04/xpdf/xpdf @@
The results actually dropped a bit to 22-24 execs/second. After setting the VM to use 6 cores, it only slightly increased up to about 45-48 execs/second.
So to utilize all 6 cores, I tried using bnagy’s afl-launch:
go get -u github.com/bnagy/afl-launch cat << EOF >> ~/.bashrc export GOPATH=\$HOME/.go export PATH="\$PATH:\$GOPATH/bin" EOF
And to set up the ramdisk afresh, I ran the script once more:
sudo -E env "PATH=$PATH" set-up-ramdisk.sh
And finally kicked it off:
cd /tmp/afl-ramdisk export PATH="$PATH:/tmp/afl-ramdisk/afl" sudo chown $(whoami):$(whoami) -R afl/ samples/ xpdf-3.04/ afl-launch -m="2G" -i samples -o pdf-out -n 4 xpdf-3.04/xpdf/xpdf @@
To watch the progress, I ran:
watch afl-whatsup -s pdf-out
Time for a more dramatic approach: run the entire VM in RAM.
Since I’m running a Windows host, I used imdisk to set up a RAM disk. This has served me well in the past, so let’s give it another go. I set up a disk to run the Ubuntu VM (7.4 gigs):
# Run the following from an Administrator prompt. imdisk -a -m Z: -o rw,fix,hd -s 15G -p "/fs:ntfs /q /y" # Copy virtual machine to ramdisk. cp -R E:\vms\fuzz-machine Z:\fuzz-machine
Next I started the machine and then just ran the fuzzing commands from the
cd ~/Downloads export PATH="$PATH:/home/$(whoami)/bin/afl" afl-launch -m="2G" -i pdfsamples-final -o pdf-out -n 4 xpdf-3.04/xpdf/xpdf @@
Checking on the performance, there is no improvement:
watch afl-whatsup -s pdf-out
I don’t even.
Given that this is my first endeavor with AFL, I’m sure there are things that I’m overlooking and/or that I could have done in a much more efficient manner. I hope to follow this post up at some point with lessons learned, and perhaps a better approach.
For those who are looking for a large set of PDF files, but who don’t know a guy at a place, then I suggest checking out the huge PDF repository of both clean and malicious PDFs, which are made available here. Huge thanks to Mila for making this available.