一、AFL简介
AFL(American Fuzzy Lop)是由安全研究员Micha Zalewski(@lcamtuf)开发的一款基于覆盖引导(Coverage-guided)的模糊测试工具,它通过记录输入样本的代码覆盖率,从而调整输入样本以提高覆盖率,增加发现漏洞的概率。
①从源码编译程序时进行插桩,以记录代码覆盖率(Code Coverage);
②选择一些输入文件,作为初始测试集加入输入队列(queue);
③将队列中的文件按一定的策略进行“突变”;
④如果经过变异文件更新了覆盖范围,则将其保留添加到队列中;
⑤上述过程会一直循环进行,期间触发了crash的文件会被记录下来。
二、AFL简单测试
这部分采用fuzzing101提供的练习进行快速熟悉AFL的基本操作
获取fuzz目标
创建一个文件夹用来存放fuzz目标(xpdf)
cd $HOME
mkdir fuzzing_xpdf && cd fuzzing_xpdf/
安装开发必要的软件包,build-essential包含gcc、g++等开发必要的包
具体包括
dpkg-dev fakeroot g++ g+±4.6 libalgorithm-diff-perl
libalgorithm-diff-xs-perl libalgorithm-merge-perl
libdpkg-perl libstdc++6-4.6-dev libtimedate-perl
sudo apt install build-essential
下载Xpdf 3.02:
wget https://dl.xpdfreader.com/old/xpdf-3.02.tar.gz
tar -xvzf xpdf-3.02.tar.gz
Build Xpdf:
cd xpdf-3.02
sudo apt update && sudo apt install -y build-essential gcc
./configure --prefix="$HOME/fuzzing_xpdf/install/"
make
make install
./configure make make install 具体解释可见
为了测试,先下载测试样例
cd $HOME/fuzzing_xpdf
mkdir pdf_examples && cd pdf_examples
wget https://github.com/mozilla/pdf.js-sample-files/raw/master/helloworld.pdf
wget http://www.africau.edu/images/default/sample.pdf
wget https://www.melbpc.org.au/wp-content/uploads/2017/10/small-example-pdf-file.pdf
测试pdfinfo二进制文件
$HOME/fuzzing_xpdf/install/bin/pdfinfo -box -meta $HOME/fuzzing_xpdf/pdf_examples/helloworld.pdf
You should see something like this:
安装AFL++
安装必要的依赖
sudo apt-get update
sudo apt-get install -y build-essential python3-dev automake git flex bison libglib2.0-dev libpixman-1-dev python3-setuptools
sudo apt-get install -y lld-11 llvm-11 llvm-11-dev clang-11 || sudo apt-get install -y lld llvm llvm-dev clang
sudo apt-get install -y gcc-$(gcc --version|head -n1|sed 's/.* //'|sed 's/\..*//')-plugin-dev libstdc++-$(gcc --version|head -n1|sed 's/.* //'|sed 's/\..*//')-dev
获取和构建AFL++
cd $HOME
git clone https://github.com/AFLplusplus/AFLplusplus && cd AFLplusplus
export LLVM_CONFIG="llvm-config-11"
make distrib-
sudo make install
通过输入下面的命令可以查看afl-fuzz的具体命令参数
afl-fuzz
可以看到
afl-fuzz命令格式
afl-fuzz -i testcase_dir -o findings_dir -- /path/to/tested/program [...program's cmdline...]
用@@会自动替换为输入文件名
afl-fuzz 基本参数说明:
-
-i:指定测试样本所在目录;
-
-o:指定测试结果存放目录;
-
-M:运行主(Master) Fuzzer;
-
-S:运行从属(Slave) Fuzzer;
-
-t:设置程序运行超时值,单位为 ms;
-
-m:最大运行内存,单位为 MB;
-
-s: 表示要使用的静态随机种子
-
@@ 占位符,AFL 将用每个输入文件名替换它
更多参数信息可通过命令afl-fuzz
来得知
开始fuzzing
前面说到,AFL从源码编译程序时进行插桩,以记录代码覆盖率。这个工作需要使用其提供的两种编译器的wrapper编译目标程序,和普通的编译过程没有太大区别
首先,我们清理所有以前编译的目标文件和可执行文件:
rm -r $HOME/fuzzing_xpdf/install
cd $HOME/fuzzing_xpdf/xpdf-3.02/
make clean
现在我们开始用afl-clang-fast 用编译xpdf:
export LLVM_CONFIG="llvm-config-11"
CC=$HOME/AFLplusplus/afl-clang-fast CXX=$HOME/AFLplusplus/afl-clang-fast++ ./configure --prefix="$HOME/fuzzing_xpdf/install/"
make
make install
现在我们可以就可以用下面的命令开始fuzzing了
afl-fuzz -i $HOME/fuzzing_xpdf/pdf_examples/ -o $HOME/fuzzing_xpdf/out/ -s 123 -- $HOME/fuzzing_xpdf/install/bin/pdftotext @@ $HOME/fuzzing_xpdf/output
对于每个输入文件,the fuzzer都会执行下面的命令
$HOME/fuzzing_xpdf/install/bin/pdftotext <input-file-name> $HOME/fuzzing_xpdf/output
如果遇到错误 “Hmm, your system is configured to send core dump notifications to an external utility…”,
这是因为在执行
afl-fuzz
前,如果系统配置为将核心转储文件(core)通知发送到外部程序。 将导致将崩溃信息发送到Fuzzer之间的延迟增大,进而可能将崩溃被误报为超时,所以我们得临时修改core_pattern
文件,如下所示:sudo su echo core >/proc/sys/kernel/core_pattern exit
成功开始fuzzing后我们可以看到下面的界面
等待……三个多小时后终于出现了一个crash
crash复现
在$HOME/fuzzing_xpdf/out/文件夹下我们可以我们的crash
用这个crash作为input来进行复现
/home/zino/fuzzing_xpdf/install/bin/pdftotext '/home/zino/fuzzing_xpdf/out/default/crashes/id:000000,sig:11,src:001820,time:12475087,op:havoc,rep:8' /home/zino/fuzzing_xpdf/output
可以看到,这个crash会导致段错误并导致程序崩溃。
我们用gdb来调试一下,看一下原因
首先需要清除原先的二进制文件,重新构建xpdf以加入调试信息
rm -r $HOME/fuzzing_xpdf/install
cd $HOME/fuzzing_xpdf/xpdf-3.02/
make clean
CFLAGS="-g -O0" CXXFLAGS="-g -O0" ./configure --prefix="$HOME/fuzzing_xpdf/install/"
make
make install
然后就可以用GDB调试了
gdb --args /home/zino/fuzzing_xpdf/install/bin/pdftotext '/home/zino/fuzzing_xpdf/out/default/crashes/id:000000,sig:11,src:001820,time:12475087,op:havoc,rep:8' /home/zino/fuzzing_xpdf/output
首先r
然后卡住后我们用bt(backtrace)回溯
可以看到getObj函数被反复递归调用,这个漏洞被记录为CVE-2019-13288
原因是在 Xpdf 4.01.01 中,Parser.cc 中的 Parser::getObj() 函数可能会通过精心制作的文件导致无限递归。远程攻击者可以利用它进行 DoS 攻击。
参考链接: