AFLGo环境搭建
AFLGo搭建及使用
2017年,Directed fuzzing这个概念在 B¨ohme等人的论文 Directed Greybox Fuzzing 中第一次被提出,文章开源了一个名为 AFLGo 的工具,是在 AFL 的基础上,实现了一个可以快速到达指定目标点的模糊测试工具。后续出现的 Directed fuzzing,基本都无法完全脱离 AFLGo 的方法,可以说,AFLGo 开创了导向型模糊测试的先河。
环境搭建
为了方便各种编译环境的管理,这里使用docker搭建
aflgo/aflgo: Directed Greybox Fuzzing with AFL (github.com)
根据官方文档,使用ubuntu20.04的镜像进行搭建
sudo docker pull ubuntu:20.04
拉取完成后,构建容器
sudo docker run -it --privileged --name aflgo [image id]
需要加上 --privileged
参数,否则执行fuzzing时会失败。
因为在执行 afl-fuzz
前,如果系统配置为将核心转储文件(core)通知发送到外部程序,将导致将崩溃信息发送到Fuzzer之间的延迟增大,进而可能将崩溃被误报为超时。所以得临时修改 core_pattern
文件:
echo core > /proc/sys/kernel/core_pattern
如果没有加上 --privileged
参数,会报错:
bash: /proc/sys/kernel/core_pattern: Read-only file system
大约在0.6版,privileged被引入docker。使用该参数,container内的root拥有真正的root权限。否则,container内的root只是外部的一个普通用户权限。
使用privileged启动的容器,可以看到很多host上的设备,并且可以执行mount。甚至允许你在docker容器中启动docker容器。引自
这个容器只提供了最基本的ubuntu运行环境,一些使用到的工具需要进行手动安装,比如vim,git等等,需要先使用 apt update
更新一下软件包,然后再安装软件。
尽量在宿主机设置外网代理避免因网络问题安装失败。
进入到容器里的home下,直接使用脚本安装aflgo,export是临时环境变量,每次fuzzing前需要进行设置。
git clone https://github.com/aflgo/aflgo.git
cd aflgo
export AFLGO=$PWD
# Build AFLGo
sudo ./build.sh
# When you fuzz for the very first time...
sudo sh -c 'echo core > /proc/sys/kernel/core_pattern'
漫长的等待后安装成功!
使用--以libxml2为例
aflgo给了几个模糊测试样例,都在examples目录下,直接执行里面的脚本文件即可运行。
这里以libxml2为例(也是官网的默认示例),详细的跟进每个步骤。
下载libxml2项目
# Clone subject repository
git clone https://gitlab.gnome.org/GNOME/libxml2
export SUBJECT=$PWD/libxml2
设置fuzzing目标
设置要进行fuzzing的目标,即设置要进行fuzzing的函数或代码行,这里以libxml2的ef709ce2这次变更点为fuzzing目标。
这次提交应该是修复了一个空指针引起的bug,更改详情查看上面的链接。
由于目标点是通过项目提交记录获取的,所以这里使用了而外的辅助工具,目标点根据需求自定义,所以下面的步骤并不是通用的。
# Setup directory containing all temporary files
mkdir temp
export TMP_DIR=$PWD/temp
# Download commit-analysis tool
wget https://raw.githubusercontent.com/jay/showlinenum/develop/showlinenum.awk
chmod +x showlinenum.awk
mv showlinenum.awk $TMP_DIR
# Generate BBtargets from commit ef709ce2
pushd $SUBJECT
git checkout ef709ce2
git diff -U0 HEAD^ HEAD > $TMP_DIR/commit.diff
popd
cat $TMP_DIR/commit.diff | $TMP_DIR/showlinenum.awk show_header=0 path=1 | grep -e "\.[ch]:[0-9]*:+" -e "\.cpp:[0-9]*:+" -e "\.cc:[0-9]*:+" | cut -d+ -f1 | rev | cut -c2- | rev > $TMP_DIR/BBtargets.txt
# Print extracted targets.
echo "Targets:"
cat $TMP_DIR/BBtargets.txt
使用git将记录回溯到ef709ce2更改处,即漏洞点。
然后将更改记录提取了出来。
设置fuzzing目标,格式为 代码文件:代码行
。
到这一步,关于BBtargets.txt文件我们完全可以自己手动写入需要进行fuzzing的点。
生成函数调用图和控制流图
# Set aflgo-instrumenter
export CC=$AFLGO/instrument/aflgo-clang
export CXX=$AFLGO/instrument/aflgo-clang++
# Set aflgo-instrumentation flags
export COPY_CFLAGS=$CFLAGS
export COPY_CXXFLAGS=$CXXFLAGS
export ADDITIONAL="-targets=$TMP_DIR/BBtargets.txt -outdir=$TMP_DIR -flto -fuse-ld=gold -Wl,-plugin-opt=save-temps"
export CFLAGS="$CFLAGS $ADDITIONAL"
export CXXFLAGS="$CXXFLAGS $ADDITIONAL"
# Build libxml2 (in order to generate CG and CFGs).
# Meanwhile go have a coffee ☕️
export LDFLAGS=-lpthread
pushd $SUBJECT
./autogen.sh
./configure --disable-shared
make clean
make xmllint
popd
这里第一次编译软件源代码是为了获取函数调用图和控制流图,为后面计算距离做准备。
$SUBJECT/xmllint --valid --recover $SUBJECT/test/dtd3
ls $TMP_DIR/dot-files
echo "Function targets"
cat $TMP_DIR/Ftargets.txt
验证编译成功。
距离计算
先清理代码块文件和函数调用块文件,其实就是清理插桩点,以便后面计算插桩点到fuzzing目标的距离。
# Clean up
cat $TMP_DIR/BBnames.txt | grep -v "^$"| rev | cut -d: -f2- | rev | sort | uniq > $TMP_DIR/BBnames2.txt && mv $TMP_DIR/BBnames2.txt $TMP_DIR/BBnames.txt
cat $TMP_DIR/BBcalls.txt | grep -Ev "^[^,]*$|^([^,]*,){2,}[^,]*$"| sort | uniq > $TMP_DIR/BBcalls2.txt && mv $TMP_DIR/BBcalls2.txt $TMP_DIR/BBcalls.txt
开始距离计算。
# Generate distance ☕️
# $AFLGO/distance/gen_distance_orig.sh is the original, but significantly slower, version
$AFLGO/distance/gen_distance_fast.py $SUBJECT $TMP_DIR xmllint
已经成功生成了对应的文件。
重新构建项目
加入距离信息后重新编译fuzzing对象。
export CFLAGS="$COPY_CFLAGS -distance=$TMP_DIR/distance.cfg.txt"
export CXXFLAGS="$COPY_CXXFLAGS -distance=$TMP_DIR/distance.cfg.txt"
# Clean and build subject with distance instrumentation ☕️
pushd $SUBJECT
make clean
./configure --disable-shared
make xmllint
popd
得到插桩后的程序。
开始fuzing
# Construct seed corpus
mkdir in
cp -r $SUBJECT/test/dtd* in
cp $SUBJECT/test/dtds/* in
$AFLGO/afl-2.57b/afl-fuzz -S ef709ce2 -z exp -c 45m -i in -o out $SUBJECT/xmllint --valid --recover @@
将示例拷贝到temp目录下的in目录中。
提示这个输入样本执行太慢,这里我们直接删除目录下这个文件即可。
11分钟跑出了43个crashes。