Use feedback-driven Fuzzer tool Honggfuzz for vulnerability mining

Introduction to honggfuzz

honggfuzz is a fuzzer based on code coverage developed by google, which keeps pace with afl and libfuzzer. It is also a very efficient feedback driven fuzz tool .

project Honggfuzz
project address https://github.com/google/honggfuzz
Developers Google
Whether to update Keep updating

honggfuzz features

  • Multi-process and multi-thread , so fuzz is very fast
  • Support persistent fuzz (Persistent Fuzzing) , the process of calling the API for repeated fuzzing for a long time
  • Easy to use, provide it to a simple corpus catalog (may even be empty for feedback-driven fuzz testing), it will evolve gradually, and expand it using feedback-based coverage metrics
  • Use the underlying interface to monitor the process , and are more likely to find and report signals that are hijacked and ignored from the crash
  • Supports multiple fuzz modes (hardware-based (CPU: branch / instruction count, Intel BTS, Intel PT) and software-based feedback-driven fuzzy mode) (more than other feedback-driven fuzzers based on coverage)

Download project

$ git clone https://github.com/google/honggfuzz

Compile and install

$ make
$ sudo make install

Practical analysis

The test demo is as follows (can be compared with afl: the classic Fuzzer tool AFL fuzzy test guide ), here to reflect the afl's instrumentation function, I specifically wrote a few if branches, and in the depth of the branch, 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;
}

If the above code goes to the deepest point, stack overflow is very likely. When the first character entered by the user is a, the second character is b, and the fifth character is s, the condition is satisfied. Our goal is to give only one use case that conforms to the format (original seed, here is a test case that allows the program to run, that is, a string). The fuzz tool will automatically mutate to generate more other test cases, looking for whether the code can go to different branches (similar to brute force).

Source code instrumentation

hfuzz-clang hfuzzDemo.c -o hfuzzDemo

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 hfuz-clang to compile the disassembly code. In each if statement, it has been automatically instrumented. It _sanitizer_cov_trace_constis an instrumentation function that is used to record taint. This is an optimization option that comes with the LLVM compiler and can roughly calculate code coverage.
Insert picture description here

Generate a 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)

hello world

Start fuzzing

honggfuzz -e txt -u -z -Q -i ./in -W ./result -- ./hgfuzzDemo ___FILE___

Parameter analysis

  • e specifies the extension of the test case
  • u Save all test cases
  • z Source code instrumentation
  • Q Print the output of the program under test
  • i Corpus, that is, the seed, which is the original test case
  • W working directory
  • --Separate honggfuzz from the program under test
  • ___FILE___ The parameters of the program under test use placeholders instead of file names, similar to @@ in AFL

Run screenshot
Insert picture description here

Result analysis

storing the result directory results, including the HONGGFUZZ.REPORT.TXTwell such that the crash test cases
Insert picture description here

Q & A problems

Question one:

linux/bfd.c:28:10: fatal error: bfd.h: No such file or directory
 #include <bfd.h>
          ^~~~~~~
compilation terminated.
Makefile:259: recipe for target 'linux/bfd.o' failed
make: *** [linux/bfd.o] Error 1

This is because there is no binutils-dev

apt-get install binutils-dev

Question two:

linux/unwind.c:27:10: fatal error: libunwind-ptrace.h: No such file or directory
 #include <libunwind-ptrace.h>
          ^~~~~~~~~~~~~~~~~~~~
compilation terminated.
Makefile:259: recipe for target 'linux/unwind.o' failed
make: *** [linux/unwind.o] Error 1

If the following error is prompted, this is because there is no libunwind-dev

apt-get install libunwind-dev

Question 3:
Ubuntu 18.0.4 crashes, so the test environment is Kali

to sum up

Compared with traditional fuzz tools, the biggest advantage of honggfuzz is that fuzzing is extremely fast. The advantages of multi-threading and multi-process allow honggfuzz to fully utilize CPU resources and greatly improve the rate of finding crash test cases. Here, the example we use, and the author of classic Fuzzer AFL fuzzing tool guide mentioned example is the same, however,

Here I used a very casual corpus hello world and quickly found the crash ; compared to the afl mentioned earlier, the author deliberately set up a test case that is highly similar to the test case of the program crash * as the original corpus, which took a long time Only found crash *. So the efficiency of honggfuzz is obvious.

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

Guess you like

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