Address
304 North Cardinal St.
Dorchester Center, MA 02124
Work Hours
Monday to Friday: 7AM - 7PM
Weekend: 10AM - 5PM
Address
304 North Cardinal St.
Dorchester Center, MA 02124
Work Hours
Monday to Friday: 7AM - 7PM
Weekend: 10AM - 5PM
This post is long overdue, but I wanted to present an AFL introduction, and how to install/use it.
If you are not familiar, AFL stands for american fuzzy lop, which is an instrumented fuzzer developed by lcamtuf.
As you can tell my some of my previous posts, I’ve been using BooFuzz recently for a lot of my fuzzing. That said, I’ve found a few vulnerabilities in the past using AFL, and it’s definitely an amazing fuzzer.
For another basic introduction, I recommend checking out the following blog post.
The AFL installation is quite simple now, as you can just use apt to get the required packages.
root@kali:~# apt-get install afl
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following packages were automatically installed and are no longer required:
libssl-doc libwhisker2-perl ruby-dm-serializer ruby-geoip ruby-libv8 ruby-ref ruby-therubyracer
Use 'apt autoremove' to remove them.
The following additional packages will be installed:
afl-clang afl-doc clang-6.0 libclang-common-6.0-dev libclang1-6.0 libllvm6.0 llvm-6.0 llvm-6.0-dev
llvm-6.0-runtime
Suggested packages:
gnustep gnustep-devel clang-6.0-doc llvm-6.0-doc
The following NEW packages will be installed:
afl afl-clang afl-doc clang-6.0 libclang-common-6.0-dev libclang1-6.0 libllvm6.0 llvm-6.0 llvm-6.0-dev
llvm-6.0-runtime
0 upgraded, 10 newly installed, 0 to remove and 613 not upgraded.
Need to get 69.2 MB of archives.
After this operation, 351 MB of additional disk space will be used.
Do you want to continue? [Y/n] y
While this is a contrived example, you can find a sample “vulnerable” program below. If a user passes “bad!” to the test function, then the program will crash.
#include <stdlib.h> #include <stdio.h> #include <signal.h> void test(char *buf) { int n = 0; if(buf[0] == 'b') n++; if(buf[1] == 'a') n++; if(buf[2] == 'd') n++; if(buf[3] == '!') n++; if(n == 4) { raise(SIGSEGV); } } int main(int argc, char *argv[]) { char buf[5]; FILE* my_file = NULL; my_file = fopen(argv[1], "r"); if (my_file != 0) { fscanf(my_file, "%4c", &buf); test(buf); fclose(my_file); } return 0; }
Although static analysis or reverse engineering could find this easily, it would take a brute force program a little bit of time to find this vulnerability. That said, that is where AFL’s code coverage comes into play.
First, I compiled the application using the afl-gcc compiler. This will add the instrumentation where necessary, and allow AFL to determine code coverage.
root@kali:~# afl-gcc -o crash crasher.c afl-cc 2.52b byafl-as 2.52b by [+] Instrumented 9 locations (32-bit, non-hardened mode, ratio 100%).
Next, I created a directory for my input files (testcase) and AFL’s findings (findings). I also created a generic input file with ‘hello’. Note that this does not match the ‘bad!’ string, but AFL will run this through various mutations to reach all of the code paths.
root@kali:~# mkdir testcases root@kali:~# mkdir findings root@kali:~# echo 'hello' > testcases/infile
Finally, I ran afl-fuzz with my input and output directories, and passed the output directly to my vulnerable application. You denote STDIO using ‘@@’, so you would need to modify your application if it took input in another manner, or create a harness program
root@kali:~# afl-fuzz -i testcases/ -o findings/ ./crash @@ afl-fuzz 2.52b by[+] You have 4 CPU cores and 2 runnable tasks (utilization: 50%). [+] Try parallel jobs - see /usr/share/doc/afl-doc/docs/parallel_fuzzing.txt. [*] Checking CPU core loadout... [+] Found a free CPU core, binding to #0. [*] Checking core_pattern... [*] Setting up output directories... [+] Output directory exists but deemed OK to reuse. [*] Deleting old session data... [+] Output dir cleanup successful. [*] Scanning 'testcases/'... [+] No auto-generated dictionary tokens to reuse. [*] Creating hard links for all input files... [*] Validating target binary... [*] Attempting dry run with 'id:000000,orig:infile'... [*] Spinning up the fork server... [+] All right - fork server is up. len = 6, map size = 6, exec speed = 830 us [+] All test cases processed. [+] Here are some useful stats: Test case count : 1 favored, 0 variable, 1 total Bitmap range : 6 to 6 bits (average: 6.00 bits) Exec timing : 830 to 830 us (average: 830 us) [*] No -t option specified, so I'll use exec timeout of 20 ms. [+] All set and ready to roll!
As you can see, AFL detected one unique crash in the span of just a few minutes!
american fuzzy lop 2.52b (crash) �"��"� process timing �"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"� overall results �"��"��"��"��"��"� �"� run time : 0 days, 0 hrs, 3 min, 5 sec �"� cycles done : 387 �"� �"� last new path : 0 days, 0 hrs, 2 min, 53 sec �"� total paths : 3 �"� �"� last uniq crash : 0 days, 0 hrs, 0 min, 12 sec �"� uniq crashes : 1 �"� �"� last uniq hang : none seen yet �"� uniq hangs : 0 �"� �"��"� cycle progress �"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"� map coverage �"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"� �"� now processing : 1 (33.33%) �"� map density : 0.01% / 0.01% �"� �"� paths timed out : 0 (0.00%) �"� count coverage : 1.00 bits/tuple �"� �"��"� stage progress �"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"� findings in depth �"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"� �"� now trying : havoc �"� favored paths : 3 (100.00%) �"� �"� stage execs : 183/256 (71.48%) �"� new edges on : 3 (100.00%) �"� �"� total execs : 584k �"� total crashes : 1 (1 unique) �"� �"� exec speed : 3069/sec �"� total tmouts : 0 (0 unique) �"� �"��"� fuzzing strategy yields �"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"� path geometry �"��"��"��"��"��"��"��"��"� �"� bit flips : 1/96, 0/93, 0/87 �"� levels : 3 �"� �"� byte flips : 0/12, 0/9, 0/3 �"� pending : 0 �"� �"� arithmetics : 0/670, 0/2, 0/0 �"� pend fav : 0 �"� �"� known ints : 0/67, 0/248, 0/132 �"� own finds : 2 �"� �"� dictionary : 0/0, 0/0, 0/0 �"� imported : n/a �"� �"� havoc : 1/272k, 1/310k �"� stability : 100.00% �"� �"� trim : 33.33%/1, 0.00% �"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"� ^C�"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"��"� [cpu000: 53%] +++ Testing aborted by user +++ [+] We're done here. Have a nice day!
To view what crashed the file, I took a look in my findings directory. As expected, a file containing the string ‘bad!’ was the culprit!
root@kali:~# cat findings/crashes/id\:000000\,sig\:11\,src\:000001+000002\,op\:splice\,rep\:2 bad!
While this was a contrived scenario, I wanted to provide a very basic example and introduction to AFL.
I’ve found a few vulnerabilities in the past with it, and I hope to share my fuzzing process for those as well.
I also want to use AFL (and other tools) more this year, to increase my vulnerability research and exploit development skills.
If you have any suggestions for targets, then please let me know.
Ray Doyle is an avid pentester/security enthusiast/beer connoisseur who has worked in IT for almost 16 years now. From building machines and the software on them, to breaking into them and tearing it all down; he’s done it all. To show for it, he has obtained an OSCE, OSCP, eCPPT, GXPN, eWPT, eWPTX, SLAE, eMAPT, Security+, ICAgile CP, ITIL v3 Foundation, and even a sabermetrics certification!
He currently serves as a Senior Staff Adversarial Engineer for Avalara, and his previous position was a Principal Penetration Testing Consultant for Secureworks.
This page contains links to products that I may receive compensation from at no additional cost to you. View my Affiliate Disclosure page here. As an Amazon Associate, I earn from qualifying purchases.