时时勤拂拭,勿使惹尘埃

TOC

Categories

AFL(一)源码fuzz


0x0 概述

American Fuzz Lop简称 AFL,号称是当前最高级的Fuzzing测试工具之一,由lcamtuf所开发的开源模糊测试工具。
AFL同时支持两种Fuzz模式:
有源码模式:使用AFL来进行有源码fuzz基本上是依赖于AFL中的代码插桩。
无源码模式(afl-qemu):AFL的无源码模式的fuzz依赖于qemu虚拟化。
使用有源码模式需要使用afl-clang或afl-clang++来编译工程代码,然后以文件(尽量 <1K)为输入,然后启动afl-fuzz程序,将testcase(seed) 喂给程序代码,然后程序接收此次输入执行程序,如果发现新的路径则保存此testcase到一个queue中,afl-fuzz继续编译testcase,因此程序每次接收不同的输入,如果程序崩溃,则记录crash。
与其他基于插桩技术的fuzzers相比,afl-fuzz具有较低的性能消耗,有各种高效的fuzzing策略和tricks最小化技巧, 不需要先行复杂的配置,能无缝处理复杂的现实中的程序。

0x1 安装

0x11 包管理器安装

macOS:
$ brew install afl-fuzz
Linux:
$ apt install afl

0x12 源码编译安装

如果需要较新版本的AFL,也可通过AFL的官网下载源码自行编译:
$ wget http://lcamtuf.coredump.cx/afl/releases/afl-latest.tgz
$ tar xvf afl-latest.tgz
$ make
$ sudo make install

0x2 使用有源码模式

0x21 AFL Fuzzing步骤

  1. 使用afl-gcc编译项目代码,将编译脚本中的CC=afl-gcc/CXX=afl-g++
  2. 新建两个文件夹,如fuzz_in/fuzz_out,文件夹名随意;
  3. 将初始化testcase放到fuzz_in目录下;
  4. 执行afl-fuzz -i fuzz_in -o fuzz_out ./xxx @@,xxx为可执行程序名,@@表示从文件中读入
  5. 观察fuzzing结果,如有crash,定位问题。

0x22 fuzz测试示例

0x221 示例代码afl_test.c

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <string.h> 
#include <signal.h> 

int vuln(char *Data) {
int num = rand() % 100 + 1;
printf("Data is generated, num is %d\n", num);
if(Data[0] == 'C' && num == 25)
{
    raise(SIGSEGV);
}
else if(Data[0] == 'F' && num == 90)
{
    raise(SIGSEGV);
}
else{
    printf("it is good!\n");
}
return 0;
}

int main(int argc, char *argv[])
{
char buf[40]={0};
FILE *input = NULL;
input = fopen(argv[1], "r");
if(input != 0)
{
    fscanf(input, "%s", &buf);
    printf("buf is %s\n", buf);
    vuln(buf);
    fclose(input);
}
else
{
    printf("bad file!");
}
return 0;
}
如果输入的数据第一个字母是’C’并且num=25 或者第一个字母是’F’并且num=90,那么程序异常退出。

0x222 编译

$ afl-clang -g -o afl_test afl_test.c

0x223 准备环境

  1. 新建输入、输出文件夹:
    $ mkdir fuzz_in fuzz_out
    
  2. 准备初始化testcase, 将testcase内容随意写成aaa:
    $ echo aaa > fuzz_in/testcase
    
    另外官网提供了部分测试集,里面有大量的各种格式的且经过修剪处理的测试用例

0x224 开始Fuzz

使用如下指令即可开始fuzz
$ afl-fuzz -i fuzz_in -o fuzz_out ./afl_test @@
启动afl-fuzz中往往会报错,表示某些环境变量没有配置或者配置错误,如:
afl-fuzz 2.52b by <[email protected]>
[+] You have 4 CPU cores and 4 runnable tasks (utilization: 100%).
[-] Whoops, your system is configured to forward crash notifications to an
    external crash reporting utility. This will cause issues due to the
    extended delay between the fuzzed binary malfunctioning and this fact
    being relayed to the fuzzer via the standard waitpid() API.
    To avoid having crashes misinterpreted as timeouts, please run the
    following commands:
    SL=/System/Library; PL=com.apple.ReportCrash
    launchctl unload -w ${SL}/LaunchAgents/${PL}.plist
    sudo launchctl unload -w ${SL}/LaunchDaemons/${PL}.Root.plist
[-] PROGRAM ABORT : Crash reporter detected
         Location : check_crash_handling(), afl-fuzz.c:7247
按照提示配置即可:
$ SL=/System/Library; PL=com.apple.ReportCrash
$ launchctl unload -w ${SL}/LaunchAgents/${PL}.plist
$ sudo launchctl unload -w ${SL}/LaunchDaemons/${PL}.Root.plist
重新执行fuzz,运行成功如下
$ afl-fuzz -i fuzz_in -o fuzz_out ./afl_test @@

0x225 重现crash

从fuzz界面可以看到2分29秒时候afl已经发现了3个crash,afl会在./fuzz_out/crashes目录下记录crash文件:

将crash文件用作输入可以使程序崩溃
$ ./afl_test fuzz_out/crashes/id:000001,sig:06,src:000001,op:havoc,rep:16
然后调试分析即可

0x23 fuzz开源软件

0x231 编译fuzz目标

libpng是开源的png解析库
$ wget https://nchc.dl.sourceforge.net/project/libpng/libpng16/1.6.36/libpng-1.6.36.tar.xz
$ tar xvf libpng-1.6.36.tar.xz
$ cd libpng-1.6.36
$ ./autogen.sh 
$ CC=afl-clang CXX=afl-g++ ./configure --enable-static
$ make -j4
--enable-static : 用于生成静态库,fuzz开源库时会需要

0x232 准备环境

获取官网提供的测试集作为输入
$ mkdir fuzz_in fuzz_out
$ cd fuzz_in
$ wget http://lcamtuf.coredump.cx/afl/demo/afl_testcases.tgz
$ tar xvf afl_testcases.tgz

0x233 开始fuzz

$ afl-fuzz -i ../fuzz_in/png/full/images -o ../fuzz_out ../.libs/pngimage @@
其中,../fuzz_in/png/full/images为afl官网提供的测试集,里面有大量的各种格式的且经过修剪处理的测试用例,../.libs/pngimage是编译出来的被测试程序,@@代表测试输入样本,即../fuzz_in/png/full/images目录下的.png文件,在实际执行时@@会被替换成实际的测试样本。
之后就等待crash了

2 条评论:

  1. 梓源大佬最近更新很频繁啊。

    回复删除
  2. 运行./autogen.sh的时候会报错:
    autogen.sh is intended only to generate 'configure' on systems
    that do not have it. You have a complete 'configure', if you
    need to change Makefile.am or configure.ac you also need to
    run configure with the --enable-maintainer-mode option.
    尝试了先./configure --enable-maintainer-mode再./autogen.sh,报同样错;
    尝试./configure --enable-maintainer-mode ./autogen.sh和./configure ./autogen.sh --enable-maintainer-mode,报如下错:
    configure: WARNING: you should use --build, --host, --target
    configure: WARNING: invalid host type: ./autogen.sh
    checking for a BSD-compatible install... /usr/bin/install -c
    checking whether build environment is sane... yes
    checking for a thread-safe mkdir -p... ./install-sh -c -d
    checking for gawk... no
    checking for mawk... no
    checking for nawk... no
    checking for awk... awk
    checking whether make sets $(MAKE)... yes
    checking whether make supports nested variables... yes
    checking whether to enable maintainer-specific portions of Makefiles... yes
    checking for ./autogen.sh-gcc... no
    checking for gcc... gcc
    checking whether the C compiler works... yes
    checking for C compiler default output file name... a.out
    checking for suffix of executables...
    checking whether we are cross compiling... no
    checking for suffix of object files... o
    checking whether we are using the GNU C compiler... yes
    checking whether gcc accepts -g... yes
    checking for gcc option to accept ISO C89... none needed
    checking whether gcc understands -c and -o together... yes
    checking whether make supports the include directive... yes (GNU style)
    checking dependency style of gcc... gcc3
    checking dependency style of gcc... gcc3
    checking build system type... Invalid configuration `./autogen.sh': machine `./autogen.sh' not recognized
    configure: error: /bin/sh ./config.sub ./autogen.sh failed
    请问解决办法?

    回复删除