AFL Introduction – Installation and Basic Fuzzing

This post is long overdue, but I wanted to present an AFL introduction, and how to install/use it.

AFL Introduction

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.

Installation

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

"Vulnerable" Application

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.

Basic Fuzzing

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 by 
afl-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!

AFL Introduction - Results

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!

AFL Introduction - Conclusion

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.

doyler on Githubdoyler on Twitter
doyler
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 Principal Penetration Testing Consultant for Secureworks. His previous position was a Senior Penetration Tester for a major financial institution.

When he's not figuring out what cert to get next or side project to work on, he enjoys playing video games, traveling, and watching sports.

Leave a Comment

Filed under Security Not Included

Leave a Reply

Your email address will not be published. Required fields are marked *

*

This site uses Akismet to reduce spam. Learn how your comment data is processed.