AFL Test Guide for Classic Fuzzer Tool

AFL (American Fuzzy Lop) is a fuzzy testing tool based on Coverage-guided developed by security researcher Michał Zalewski. By recording the code coverage of input samples, the input is continuously mutated to achieve higher code coverage. AFL uses a new type of compile-time instrumentation and genetic algorithm to automatically discover new test cases that will trigger new internal states in the target binary. This greatly improves the code coverage of fuzz testing. 1

  1. Insert the instrument when compiling the program from the source code to record the code coverage (Code Coverage);
  2. Select some input files to join the input queue as the initial test set;
  3. Mutate the files in the queue according to a certain strategy ";
  4. If the coverage is updated through the mutation file, it will be retained and added to the queue;
  5. The above process will continue to circulate, and the file that triggered the crash will be recorded.

Insert picture description here


0x10 install afl

Choose one of the following three versions (the second one is recommended. I have tried all three. In normal afl mode, all three have no problems. But when it comes to deeper usage, there are some bugs; the second This is a relatively good version)

AFLplusplus introduces a stronger compilation algorithm. If the source code is inserted, AFLplusplus is more suitable. Enter into the downloaded project, install afl, the command is as follows

make	# 编译 afl
sudo make install

This is a screenshot of successful compilation
Insert picture description here

0x20 build the program under test (white box test)

The purpose of using AFL to compile the target source code is to insert instrumentation so that the compiled program can be covered by the feedback path. AFL comes with customized versions of gcc and clang compilers, it is recommended to choose LLVM's clang compiler, which can speed up the speed of fuzz .

0x21 Use afl-gcc for source code insertion

For a single file, just use afl-gcc instead of gcc

afl-gcc test.c -o test

For a complete project, you need to specify the compiler as afl-gcc, and then compile

./configure CC="afl-gcc" CXX="afl-g++"	# 或者直接修改 Makefie 文件,将编译器改位 afl-gcc
make

If you need to fuzz shared library , you can set LD_LIBRARY_PATHthe program to load .so files instrumented through the AFL, but the easiest way is to build a static, achieved by

./configure --disable-shared CC="afl-gcc" CXX="afl-g++"

0x22 Use LLVM mode for source code instrumentation

AFL also supports the use of LLVM mode, which can get faster fuzzing speed, and has more options. The front-end representation of LLVM is the clang compiler, so you need to install clang yourself, and then you can compile

afl-clang test.c -o test

0x23 error while loading shared libraries error 2

After the build is completed, the following error may occur. This is because the compiler will only use library files in the two directories / lib and / usr / lib by default . Install the program by source code compilation. If not specified --prefix, the library will be installed in the /usr/local/libdirectory; when running the program, you need to link When the dynamic library is displayed, it prompts that the relevant .so library cannot be found, and an error will be reported. In other words, the / usr / local / lib directory is not in the system's default library search directory, and the directory needs to be added.
Insert picture description here
Solution

  1. Open /etc/ld.so.conffile
  2. Add the directory where the dynamic library file is located: execute vi /etc/ld.so.conf, include ld.so.conf.d/*.conf"add under ""/usr/local/lib"
  3. After saving, execute the command line terminal: /sbin/ldconfig -v; its role is to file /etc/ld.so.confcaching library file in the path listed to /etc/ld.so.cachefor use, so when you install some of the libraries, or modify etc/ld.so.confadded a new library search path, got to run ldconfig, so that all the library files are cached to file /etc/ld.so.cache, if not done, you could not find the newly installed libraries.

0x30 select corpus

In fact, it is to feed the test program with appropriate test cases. Afl will generate a large number of use cases based on these original seeds and mutations. Under ideal conditions, the provided corpus (that is, the original test case) can allow the program to execute different paths , so as to maximize code coverage.

0x31 Select use case

Here, borrowing the materials provided by Freebuf, give some open source corpora

In fact, many programs will also bring some cases, which can also be used as test cases.


0x32 condensed corpus

After finding the corpus, it is best to be able to trim, merge repeated use cases, and trim the volume. afl The recommended use case volume is less than 1KB , otherwise it will affect the efficiency of fuzz.

Deduplication

afl-cmin It is a very useful tool provided by afl, which can streamline the corpus and remove possible duplicate test cases. It is very useful for some complex corpora and can greatly reduce useless fuzz use cases.

afl-cmin -i input_dir -o output_dir -- /path/to/tested/program [params]

More often, we get input from the file, so we often use @@ instead of params (parameters), that is

afl-cmin -i input_dir -o output_dir -- /path/to/tested/program @@

Reduce volume

afl-tminThe file size can be shortened because afl requires that the size of test cases is preferably less than 1KB, so it is best to further reduce the size of the simplified use cases. afl-tmin has two working modes, instrumented modeand crash mode. The default working mode is instrumented mode

afl-tmin -i input_file -o output_file -- /path/to/tested/program [params] @@

Because afl-cmin can only simplify a single file at a time, if there are many use cases, it takes a long time to manually, in fact, a simple shell script can be completed

for i in *; do afl-tmin -i $i -o tmin-$i -- ~/path/to/tested/program [params] @@; done;

0x40 fuzzing

Before formally Fuzz program, may be used afl-mapto track a single execution path with the embodiment, it will print out and output tuples procedures

afl-showmap -m none -o /dev/null

The command to formally execute the fuzz test is as follows

afl-fuzz -m none -i in -o out target_binary @@

0x50 black box fuzz

The above fuzz process depends on the source code of the program we have, and the instrumentation is carried out during the compilation process, but many times, we do not have the source code, at this time we rely on the qemu_mode mode provided by afl. The original version of the afl qemu mode is too old to run normally. It is recommended to use AFLplusplus or afl-unicorn on github . AFLplusplusEasier to install and afl-unicornmore user-friendly for qemu mode.

No matter which version of afl is downloaded, there will be a qemu_mode folder in the root directory, enter this directory, run the following script, if there is no error, it means that qemu_mode succeeded

cd qemu_mode
sudo ./build_qemu_support.sh

If there is an error, please visit: In- depth analysis of afl / qemu-mode (qemu mode) / afl-unicorn compilation and installation problems and corresponding solutions

If you want to black-box fuzz binary files of different architectures, you need to specify the corresponding architecture before compiling the qemu script . For example, to run the fuzz arm architecture program under the x86 architecture, you need to run the following command

CPU_TARGET=arm ./build_qemu_support.sh

After the compilation is successful, you can perform black box fuzz

afl-fuzz -Q -m none -i in -o out target_binary @@

0x60 actual combat analysis

0x61 source code analysis

Write a demo, for example. Here, in order to reflect the af's instrumentation function, several if branches are intentionally written. In the depth of the branch, a stack overflow will occur.

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/fcntl.h>

int main(int argc, char const *argv[])
{
	if(argc != 2)
	{
		printf("null args!\n");
		return -1;
	}

	/* Get file state */
	struct stat fstat;
	if(stat(argv[1], &fstat))
	{
		printf("Failed ^_^\n");
		return -1;
	}

	/* Open file */
	FILE * fd = NULL;
	fd = open(argv[1], O_RDONLY);
	if(fd == -1)
	{
		printf("open file failed!\n");
		return -1;
	}

	/* Select */
	char buf[15];
	if(read(fd, buf, 2) == -1)
	{
		printf("read failed!");
		return -1;
	}

	if(buf[0] == 'a' && buf[1] == 'b')
	{
		if(read(fd, buf, 4) != -1)
		{
			if(buf[2] == 's')
			{
				read(fd, buf, fstat.st_size - 6);
				printf("%s\n", buf);
			}
		}
	}

	return 0;
}

0x62 source code insertion

Compile with afl's LLVM mode, that is, instrument the source code

afl-clang afl_demo.c -o afl_demo

Each if statement represents each conditional branch, and what appears in IDA's disassembly window is a basic block. An if statement is a new branch. As shown below, we use afl-clang to compile the disassembled code. As you can see, in each if statement, it has been automatically instrumented. It _afl_maybe_logis an instrumentation function that is used to feedback the path.
Insert picture description here

0x63 Generate corpus

Create a new in directory, create a new file in the directory, write a seed, and the mutation algorithm will generate various test cases based on this seed mutation and feed it to the program, such as writing the following information (according to the code, when the first character is a, the second Characters are b, the fifth character is s, overflow may occur)

abttdcccccccccccccccccccccccccaaaaaaaaaaaaaaaaaaaaaaadddddddddddddddddddddddddddd

0x64 start fuzzing

root@lys-virtual-machine:~/Documents/test# afl-fuzz -m none -i in -o out ./afl_demo @@
afl-fuzz++2.60d based on afl by Michal Zalewski and a big online community
[+] afl++ is maintained by Marc "van Hauser" Heuse, Heiko "hexcoder" Eißfeldt and Andrea Fioraldi
[+] afl++ is open source, get it at https://github.com/vanhauser-thc/AFLplusplus
[+] Power schedules from github.com/mboehme/aflfast
[+] Python Mutator and llvm_mode whitelisting from github.com/choller/afl
[+] afl-tmin fork server patch from github.com/nccgroup/TriforceAFL
[+] MOpt Mutator from github.com/puppet-meteor/MOpt-AFL
[*] Getting to work...
[+] Using exploration-based constant power schedule (EXPLORE)
[+] You have 8 CPU cores and 2 runnable tasks (utilization: 25%).
[+] Try parallel jobs - see /usr/local/share/doc/afl/parallel_fuzzing.md.
[*] Checking CPU core loadout...
[+] Found a free CPU core, try binding to #0.
[*] Checking core_pattern...
[!] WARNING: Could not check CPU scaling governor
[*] Setting up output directories...
[+] Output directory exists but deemed OK to reuse.
[*] Deleting old session data...
[+] Output dir cleanup successful.
[*] Scanning 'in'...
[+] No auto-generated dictionary tokens to reuse.
[*] Creating hard links for all input files...
[*] Validating target binary...
[*] Attempting dry run with 'id:000000,time:0,orig:testcases.txt'...
[*] Spinning up the fork server...
[+] All right - fork server is up.
    len = 81, map size = 9, exec speed = 199 us
[+] All test cases processed.

[+] Here are some useful stats:

    Test case count : 1 favored, 0 variable, 1 total
       Bitmap range : 9 to 9 bits (average: 9.00 bits)
        Exec timing : 199 to 199 us (average: 199 us)

[*] No -t option specified, so I'll use exec timeout of 20 ms.
[+] All set and ready to roll!

In the fuzz window,
Insert picture description here
you can see that there has been a crash. When cycles done is green, it means that the fuzz can be stopped.

0x65 result analysis

Let's analyze the results, according to the commands entered during fuzz, our results are output in the out directory

root@lys-virtual-machine:~/Documents/test/out# tree
.
├── cmdline
├── crashes
│   ├── id:000000,sig:11,src:000001,time:600493+000003,op:splice,rep:64
│   ├── id:000001,sig:11,src:000003,time:600898,op:havoc,rep:64
│   └── README.txt
├── fuzz_bitmap
├── fuzzer_stats
├── hangs
├── plot_data
└── queue
    ├── id:000000,time:0,orig:testcases.txt
    ├── id:000001,src:000000,time:3,op:flip1,pos:0,+cov
    ├── id:000002,src:000000,time:6,op:flip1,pos:1,+cov
    └── id:000003,src:000000,time:3406,op:havoc,rep:2,+cov

3 directories, 11 files
  • crashes : Unique test cases that cause the target to crash with a fatal signal
  • fuzzer_stats: running status of afl-fuzz
  • hangs: unique test cases that cause the target to time out
  • plot_data: used for afl-plot plotting
  • queue: store all test cases with unique execution paths

afl-plot can draw more intuitive results, using the plot_data file generated by the fuzzer. Of course, to use afl-plot, you need to installapt-get install gnuplot

root@lys-virtual-machine:~/Documents/test# afl-plot out result/
progress plotting utility for afl-fuzz by Michal Zalewski

[*] Generating plots...
[*] Generating index.html...
[+] All done - enjoy your charts!

In this way, you can generate html and picture files in the result directory, as shown below
Insert picture description here

  • The first picture: when the path coverage changes, the number of pending fav becomes zero, and the number of total paths has basically not increased, it means that the fuzzer is less likely to find new ones
  • Crash and timeout changes
  • Changes in execution speed

To find the bug again, simply enter the test case in the crash directory.

0x70 Summary

As an excellent fuzz tool, AFL calculates code coverage through source code insertion, and then uses this as a basis to continuously mutate the corpus (seed file) to achieve the effect of increasing code coverage. This article mainly explains its general usage, and its most efficient is also the source code insertion in LLVM mode, combined with specific examples, to conduct fuzz testing. For binary files compiled from C / C ++ code, although AFL also provides qemu-based source-less black box fuzz, the efficiency is low and the possibility of finding vulnerabilities is small. Therefore, it is best to use the general model of AFL, that is, the fuzz test based on source code instrumentation.

In the case of no source code, if you want to use binary instrumentation directly, you need to install qemu-mode or unicorn mode. There may be many problems with the installation. Welcome to another blog: in-depth analysis of afl / qemu-mode (qemu mode) / afl-unicorn compilation and installation problems and corresponding solutions .


  1. https://www.freebuf.com/articles/system/191543.html ↩︎

  2. https://www.cnblogs.com/codingmengmeng/p/7456539.html ↩︎

Published 52 original articles · Like 30 · Visits 50,000+

Guess you like

Origin blog.csdn.net/song_lee/article/details/104777149