Zafl (Zipr-based AFL)
Welcome to Zafl, a project to fuzz X86 64-bit binary programs.
Key features of Zafl:
- Uses Zipr, a fast, space-efficient binary rewriter to inline AFL-style instrumentations. Preliminary overhead:
- 20% slower than afl/source code
- 15% faster than afl/dyninst
- a lot faster than afl/QEMU
- Platform for experimenting with other instrumentation to guide afl, e.g., add calling context to the edge-profile function (a la Angora)
Installation
Note that you will need sudo privileges to get and install all the required packages.
Getting packages and compiling Zafl
git clone --recurse-submodules git@git.zephyr-software.com:allnp/zafl_umbrella.git
cd zafl_umbrella
. set_env_vars
./get-packages.sh
./build-all.sh
Setting up local postgres tables
Next we need to setup the proper tables in a local copy of the postgres database (email admin for instructions if you want to use a remote Postgres database).
cd $ZAFL_HOME/zipr_umbrella
./postgres_setup.sh
If all goes well with the postgres setup, you should be able to login into the database by typing: psql
The output of psql should look something like this:
psql (9.3.22)
SSL connection (cipher: DHE-RSA-AES256-GCM-SHA384, bits: 256)
Type "help" for help.
peasoup_XXX=>
Testing Zafl
Before running Zafl, always make sure to have your environment variable set
cd <zafl_top_level_directory> # in this example, the top level dir is: zafl_umbrella
. set_env_vars
Testing Zipr
Test that the binary rewriting infrastructure by rewriting /bin/ls
cd /tmp
$PSZ /bin/ls ls.zipr
Your terminal's output should look like this:
Using Zipr backend.
Detected ELF file.
Performing step gather_libraries [dependencies=mandatory] ...Done. Successful.
Performing step meds_static [dependencies=mandatory] ...Done. Successful.
Performing step pdb_register [dependencies=mandatory] ...Done. Successful.
Performing step fill_in_cfg [dependencies=mandatory] ...Done. Successful.
Performing step fill_in_indtargs [dependencies=mandatory] ...Done. Successful.
Performing step clone [dependencies=mandatory] ...Done. Successful.
Performing step fix_calls [dependencies=mandatory] ...Done. Successful.
Program not detected in signature database.
Performing step zipr [dependencies=clone,fill_in_indtargs,fill_in_cfg,pdb_register] ...Done. Successful.
Invoke the rewritten version of /bin/ls and make sure it runs normally:
./ls.zipr
Testing Zafl
Download afl and install it locally
wget http://lcamtuf.coredump.cx/afl/releases/afl-latest.tgz
tar -xzvf afl-latest.tgz
cd <afl_dir>
make
# (optional) build qemu support
cd qemu_mode
./build_qemu_support.sh
Test afl
cd /tmp
mkdir in
echo "1" > in/1
afl-fuzz -i in -o out -Q -- /bin/ls @@
Alternatively, you may opt to build afl without QEMU support. In that case, you will need to make sure that afl works for you.
You may see afl error messages such as this one that will need to be fixed:
afl-fuzz 2.52b by <lcamtuf@google.com>
[+] You have 24 CPU cores and 1 runnable tasks (utilization: 4%).
[+] Try parallel jobs - see docs/parallel_fuzzing.txt.
[*] Checking CPU core loadout...
[+] Found a free CPU core, binding to #0.
[*] Checking core_pattern...
[-] Hmm, your system is configured to send core dump notifications to an
external utility. This will cause issues: there will be an extended delay
between stumbling upon a crash and having this information relayed to the
fuzzer via the standard waitpid() API.
To avoid having crashes misinterpreted as timeouts, please log in as root
and temporarily modify /proc/sys/kernel/core_pattern, like so:
echo core >/proc/sys/kernel/core_pattern
[-] PROGRAM ABORT : Pipe at the beginning of 'core_pattern'
Location : check_crash_handling(), afl-fuzz.c:7275
or:
[-] Whoops, your system uses on-demand CPU frequency scaling, adjusted
between 1558 and 2338 MHz. Unfortunately, the scaling algorithm in the
kernel is imperfect and can miss the short-lived processes spawned by
afl-fuzz. To keep things moving, run these commands as root:
cd /sys/devices/system/cpu
echo performance | tee cpu*/cpufreq/scaling_governor
You can later go back to the original state by replacing 'performance' with
'ondemand'. If you don't want to change the settings, set AFL_SKIP_CPUFREQ
to make afl-fuzz skip this check - but expect some performance drop.
Fix any afl-related errors until you can run:
afl-fuzz -i in -o out -Q -- /bin/ls @@
Running Zafl smoke tests
cd $ZAFL_HOME/zfuzz/test/bc
./test_bc.sh
The test will run afl on bc, instrumented with the proper instrumentation inlined. The output should end with:
execs_since_crash : 77855
exec_timeout : 20
afl_banner : bc.stars.zafl
afl_version : 2.52b
target_mode : default
command_line : afl-fuzz -i zafl_in -o zafl_out -- ./bc.stars.zafl -f
TEST PASS: ./bc.stars.zafl: ran zafl binary: execs_per_sec : 2000.00
TEST PASS: all tests passed: zafl instrumentation operational on bc
There are also other smoke tests you can run in $ZAFL_HOME/zfuzz/test
Final sanity check
cd /tmp
zafl.sh /bin/ls ls.zafl
zafl.sh is the primary script for adding afl instrumentation to binaries. You should see:
zafl.sh /bin/ls ls.zafl
Zafl: Transforming input binary /bin/ls into ls.zafl
Zafl: Issuing command: /home/zafl_guest/zafl_umbrella/install/zipr_umbrella/peasoup_examples/tools/ps_zipr.sh /bin/ls ls.zafl -c move_globals=on -c zafl=on -o move_globals:--elftables -o zipr:--traceplacement:on -o zipr:true -o zafl:--stars
Using Zipr backend.
Detected ELF file.
Performing step gather_libraries [dependencies=mandatory] ...Done. Successful.
Performing step meds_static [dependencies=mandatory] ...Done. Successful.
Performing step pdb_register [dependencies=mandatory] ...Done. Successful.
Performing step fill_in_cfg [dependencies=mandatory] ...Done. Successful.
Performing step fill_in_indtargs [dependencies=mandatory] ...Done. Successful.
Performing step clone [dependencies=mandatory] ...Done. Successful.
Performing step fix_calls [dependencies=mandatory] ...Done. Successful.
Program not detected in signature database.
Performing step move_globals [dependencies=none] ...Done. Successful.
Performing step zafl [dependencies=none] ...Done. Successful.
Performing step zipr [dependencies=clone,fill_in_indtargs,fill_in_cfg,pdb_register] ...Done. Successful.
You can run ls.zafl as you would ls: ./ls.zafl
Zafl'd binaries can be run normally. There is no extra output.
To make sure the binary has been instrumented properly: ZAFL_DEBUG=1 ./ls.zafl
The output should start with:
Error getting shm environment variable - fake allocate AFL trace map
Error getting shm environment variable - fake allocate AFL trace map
zafl_initAflForkServer(): Bad file descriptor
Let's now run the Zafl'd binary with afl:
afl-fuzz -i in -o out -- ./ls.zafl @@
You can also run the usual afl utilities, e.g:
afl-showmap -o map.out -- ./ls.zafl
afl-cmin -i out/queue/ -o out.cmin -- ./ls.zafl @@
Et voila!
TL;DR
Once everything is installed properly:
zafl.sh <target_binary> <zafl_output_binary>