Fuzzing101 Execise1~5
前言
这是我做Fuzzing101的一些笔记,通过复现CVE的方式熟悉AFL++的基本使用方式,过程对我这样的萌新十分友好,同时中间涉及到的代码审计等方面还是值得后续学习的。
Exercise 1 - Xpdf
CVE-2019-13288 in XPDF 3.02 (infinite recursion)
安装调试目标
从github等途径下载并解压
1 2 | wget https: / / dl.xpdfreader.com / old / xpdf - 3.02 .tar.gz
tar - xvzf xpdf - 3.02 .tar.gz
|
安装依赖和目标
1 2 3 4 | sudo apt update && sudo apt install - y build - essential gcc
. / configure - - prefix = "$HOME/fuzz_target/fuzzing_xpdf/install/"
make
make install
|
配置configure时有各种环境变量需要设置,比较常用的有
- AS:汇编程序名称
- CC:C编译器名称
- CXX:C++编译器名称
- CPP:C预编译器名称
- **FLAGS:**为不同编译器名称,表示对应编译器的参数
- LD:链接器名称
- AR:归档器archiver名称
- RANLIB:符号表添加器名称(AR和RANLIB是什么具体看这里)
获取样本
自己随便写,fuzzer会自己变异,但效率较低
从网上(github、官网、压缩包自带)找现成的样本sample
1 2 3 4 5 | cd $HOME / fuzz_target / 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
|
测试安装程序运行
1 | $HOME / fuzz_target / fuzzing_xpdf / install / bin / pdfinfo - box - meta $HOME / fuzz_target / fuzzing_xpdf / pdf_examples / helloworld.pdf
|
使用fuzz编译器编译(afl-clang-fast)
先删除原先的安装,重新编译安装库
1 2 3 4 5 6 7 | rm - r install
cd xpdf - 3.02
make clean
export LLVM_CONFIG = "llvm-config-12"
CC = afl - clang - fast CXX = afl - clang - fast + + . / configure - - prefix = "$HOME/fuzz_target/fuzzing_xpdf/install/"
make
make install
|
fuzz
1 | afl - fuzz - i $HOME / fuzz_target / fuzzing_xpdf / pdf_examples / - o $HOME / fuzz_target / fuzzing_xpdf / out / - s 123 - - $HOME / fuzz_target / fuzzing_xpdf / install / bin / pdftotext @@ $HOME / fuzz_target / fuzzing_xpdf / output
|
参数
- -i:输入样本路径
- -o:输出存储路径
- -s:fuzzing时随机数使用的种子,这里为了尽量保证复现结果,设为123
- --:目标程序
这里的@@
不能少,虽然初始输入都来源于设置的-i参数,但我们需要根据程序读取输入的方式进行调整此参数
- 加
@@
:被fuzz的程序从文件读取输入
- 不加
@@
:被fuzz的程序从标准输入输出流读取输入
跑一会就能出结果

动态调试
源码编译出带调试符号的文件
1 2 3 4 | make clean
CFLAGS = "-g -O0" CXXFLAGS = "-g -O0" . / configure - - prefix = "$HOME/fuzz_target/fuzzing_xpdf/install/"
make
make install
|
运行gdb
1 | gdb - - args $HOME / fuzz_target / fuzzing_xpdf / install / bin / pdftotext $HOME / fuzz_target / fuzzing_xpdf / out / default / crashes / <your_filename> $HOME / fuzz_target / fuzzing_xpdf / output
|
追踪crash路径
从xpdf/Parse.cc 94行的makeStream调用,一路跟着报错往下翻就会找到这个套娃,这里就不细说了。

漏洞修复
下个xpdf4.02源码对比一下就好,修复方式比较简单,加了个变量,记录循环次数,超过一定次数就结束进程。
1 | wget https: / / dl.xpdfreader.com / old / xpdf - 4.02 .tar.gz
|
Exercise 2 - libexif
CVE-2009-3895 (heap-based buffer overflow)and CVE-2012-2836 (Out-of-bounds Read)in libexif 0.6.14
安装调试目标
从github等途径下载并解压
1 | tar - xzvf libexif - 0_6_14 - release.tar.gz
|
安装依赖
配置configure并安装
1 2 3 4 5 | autoreconf - fvi 用于适配系统环境,简化config命令
/ / 安装autoreconf sudo apt - get install autopoint libtool gettext libpopt - dev
. / configure - - enable - shared = no (如果是库文件,必须编译成静态库) - - prefix = "/root/fuzz_target/fuzzing_libexif/install/"
make
make install
|
获取交互应用(如果调试的是库,需要调用接口fuzz)
- 自己写一个c程序调用接口,用afl提供的编译器编译出来
- 直接找调用了库文件的应用,这是这题采用的方法
使用fuzz编译器编译(afl-clang-lto)
先删除原先的安装,重新编译安装库
1 2 3 4 5 | make clean
export LLVM_CONFIG = "llvm-config-12"
CC = / root / fuzz / AFLplusplus / afl - clang - lto . / configure - - enable - shared = no - - prefix = "/root/fuzz_target/fuzzing_libexif/install/"
make
make install
|
如果编译不通过,可以加 AR=llvm-ar RANLIB=llvm-ranlib LD=afl-clang-lto
重新编译应用
1 2 3 4 5 | make clean
export LLVM_CONFIG = "llvm-config-12"
CC = / root / fuzz / AFLplusplus / afl - clang - lto . / configure - - enable - shared = no - - prefix = "$HOME/fuzz_target/fuzzing_libexif/install/" PKG_CONFIG_PATH = $HOME / fuzz_target / fuzzing_libexif / install / lib / pkgconfig
make
make install
|
测试运行
1 | $HOME / fuzz_target / fuzzing_libexif / install / bin / exif $HOME / fuzz_target / fuzzing_libexif / exif - samples - master / jpg / Canon_40D_photoshop_import.jpg
|
fuzz
1 | afl - fuzz - i $HOME / fuzz_target / fuzzing_libexif / exif - samples - master / jpg / - o $HOME / fuzz_target / fuzzing_libexif / out / - s 123 - - $HOME / fuzz_target / fuzzing_libexif / install / bin / exif @@
|

动态调试
编译出带调试信息的可执行文件
1 2 3 4 5 6 7 8 9 10 11 | cd libexif - libexif - 0_6_14 - release
make clean
CFLAGS = "-g -O0" CXXFLAGS = "-g -O0" . / configure - - prefix = "$HOME/fuzz_target/fuzzing_libexif/install/"
make
make install
cd exif - exif - 0_6_15 - release
make clean
CFLAGS = "-g -O0" CXXFLAGS = "-g -O0" PKG_CONFIG_PATH = $HOME / fuzz_target / fuzzing_libexif / install / lib / pkgconfig . / configure - - prefix = "$HOME/fuzz_target/fuzzing_libexif/install/"
make
make install
|
丢进gdb,跑出crash
crash1
1 | gdb - - args . / install / bin / exif . / out / default / crashes / id \: 000000 \,sig\: 11 \,src\: 000281 \,time\: 64869 \,execs\: 64957 \,op\:havoc\,rep\: 16
|

- 报错信息
Program received signal SIGSEGV, Segmentation fault.
,存在内存泄漏
- 报错位置
exif_get_sshort (buf=0x555655563195 <error: Cannot access memory at address 0x555655563195>, order=EXIF_BYTE_ORDER_MOTOROLA) at exif-utils.c:92
,注意这里的报错,内存地址无法访问,再看地址,估计为堆缓冲区溢出
crash2
1 | gdb - - args . / install / bin / exif . / out / default / crashes / id \: 000002 \,sig\: 11 \,src\: 000301 \,time\: 126417 \,execs\: 126621 \,op\:havoc\,rep\: 8
|

- 报错信息
Program received signal SIGSEGV, Segmentation fault.
,存在内存泄露
- 报错位置
__memmove_avx_unaligned_erms () at ../sysdeps/x86_64/multiarch/memmove-vec-unaligned-erms.S:345
crash3
1 | gdb - - args . / install / bin / exif . / out / default / crashes / id \: 000006 \,sig\: 11 \,src\: 000492 + 000181 \,time\: 341313 \,execs\: 358541 \,op\:splice\,rep\: 8
|

- 报错信息
Program received signal SIGSEGV, Segmentation fault
,存在内存泄露
- 报错位置
exif_get_slong (b=0x555555582000 <error: Cannot access memory at address 0x555555582000>, order=EXIF_BYTE_ORDER_MOTOROLA) at exif-utils.c:135
,与1类似
漏洞修复
- https://github.com/libexif/libexif/commit/8ce72b7f81e61ef69b7ad5bdfeff1516c90fa361
- https://github.com/libexif/libexif/commit/00986f6fa979fe810b46e376a462c581f9746e06
Exercise 3 - tcpdump(使用ASAN)
CVE-2017-13028 in TCPdump 4.9.2(Out-of-bounds Read)
libcap是tcpdump的依赖库,可以不install,但需要保证目录位置与tcpdump根目录相同,且名称可识别
使用ASAN编译
1 2 3 4 5 6 7 8 9 10 | cd $HOME / fuzz_target / fuzzing_tcpdump / libpcap - 1.8 . 0 /
export LLVM_CONFIG = "llvm-config-12"
CC = / root / fuzz / AFLplusplus / afl - clang - lto . / configure - - enable - shared = no - - prefix = "$HOME/fuzz_target/fuzzing_tcpdump/install/"
AFL_USE_ASAN = 1 make
AFL_USE_ASAN = 1 make install
cd $HOME / fuzz_target / fuzzing_tcpdump / tcpdump - tcpdump - 4.9 . 2 /
AFL_USE_ASAN = 1 CC = / root / fuzz / AFLplusplus / afl - clang - lto . / configure - - prefix = "$HOME/fuzz_target/fuzzing_tcpdump/install/"
AFL_USE_ASAN = 1 make
AFL_USE_ASAN = 1 make install
|
这里配置tcpdump的configure时也要加AFL_USE_ASAN=1,因为它的依赖库也加了ASAN
fuzz
1 | afl - fuzz - m none - i . / tcpdump - tcpdump - 4.9 . 2 / tests / - o . / afl_out / - s 123 - - . / install / sbin / tcpdump - vvvvXX - ee - nn - r @@
|
ASAN会消耗大量内存,使用-m none
不限制内存使用
这个我跑了比较久(挂着进程容易忘关)

动态调试
有ASAN就不用再重新编译整个文件来调试了(这里如果用普通编译来运行crash反而得不到报错信息,显然这里的内存泄露不会直接导致crash)
1 | . / install / sbin / tcpdump - vvvvXX - ee - nn - r . / afl_out / default / crashes / id \: 000000 \,sig\: 06 \,src\: 011483 \,time\: 43941578 \,execs\: 17770128 \,op\:havoc\,rep\: 8
|
直接运行crash,ASAN会给出较为详细的报错和调用栈

- 报错信息:
AddressSanitizer: heap-buffer-overflow /root/fuzz_target/fuzzing_tcpdump/tcpdump-tcpdump-4.9.2/./extract.h:184:20 in EXTRACT_16BITS
,直接说明是堆溢出
漏洞修复
- https://github.com/the-tcpdump-group/tcpdump/commit/85078eeaf4bf8fcdc14a4e79b516f92b6ab520fc#diff-05f854a9033643de07f0d0059bc5b98f3b314eeb1e2499ea1057e925e6501ae8L381
Exercise 4 - libtiff(coverage优化)
CVE-2016-9297 in libtiff 4.0.4 (Out-of-bounds Read)
使用lvoc(覆盖率检测)编译libtiff
1 2 3 | CFLAGS = "--coverage" LDFLAGS = "--coverage" . / configure - - prefix = "$HOME/fuzz_target/fuzzing_tiff/install/" - - disable - shared
make
make install
|
获取覆盖率
1 2 3 4 5 | cd $HOME / fuzzing_tiff / tiff - 4.0 . 4 /
lcov - - zerocounters - - directory . /
lcov - - capture - - initial - - directory . / - - output - file app.info
$HOME / fuzz_target / fuzzing_tiff / install / bin / tiffinfo - D - j - c - r - s - w $HOME / fuzz_target / fuzzing_tiff / tiff - 4.0 . 4 / test / images / palette - 1c - 1b .tiff
lcov - - no - checksum - - directory . / - - capture - - output - file app2.info
|
lcov --zerocounters --directory ./
:重置计数器
lcov --capture --initial --directory ./ --output-file app.info
:为每个instrumented line返回覆盖率数据的初始化基准
$HOME/fuzzing_tiff/install/bin/tiffinfo -D -j -c -r -s -w $HOME/fuzzing_tiff/tiff-4.0.4/test/images/palette-1c-1b.tiff0
:运行需要分析的应用,可以用多个样本运行多次
lcov --no-checksum --directory ./ --capture --output-file app2.info
:保存覆盖率状态
将结果转化生成HTML输出
1 | genhtml - - highlight - - legend - output - directory . / html - coverage / . / app2.info
|
编译文件
1 2 3 4 5 | export LLVM_CONFIG = "llvm-config-12"
CC = / root / fuzz / AFLplusplus / afl - clang - lto . / configure - - prefix = "$HOME/fuzz_target/fuzzing_tiff/install/" - - disable - shared
AFL_USE_ASAN = 1 make - j4
AFL_USE_ASAN = 1 make install
afl - fuzz - m none - i $HOME / fuzz_target / fuzzing_tiff / tiff - 4.0 . 4 / test / images / - o $HOME / fuzz_target / fuzzing_tiff / out / - s 123 - - $HOME / fuzz_target / fuzzing_tiff / install / bin / tiffinfo - D - j - c - r - s - w @@
|
这里使用尽可能多的参数,增大fuzz到漏洞代码的概率
fuzz
1 | afl - fuzz - m none - i $HOME / fuzz_target / fuzzing_tiff / tiff - 4.0 . 4 / test / images / - o $HOME / fuzz_target / fuzzing_tiff / afl_out / - s 123 - - $HOME / fuzz_target / fuzzing_tiff / install / bin / tiffinfo - D - j - c - r - s - w @@
|

动态调试
查看报错
1 | . / install / bin / tiffinfo - D - j - c - r - s - w . / out / default / crashes / id \: 000000 \,sig\: 06 \,src\: 000016 \,time\: 556815 \,execs\: 377779 \,op\:havoc\,rep\: 4
|

- 报错信息:
AddressSanitizer: heap-buffer-overflow (/root/fuzz_target/fuzzing_tiff/install/bin/tiffinfo+0x2aaf11) in fputs
,堆溢出
漏洞修复
- https://github.com/vadz/libtiff/commit/30c9234c7fd0dd5e8b1e83ad44370c875a0270ed
Exercise 5 - libxml2(自定义字典、并行)
CVE-2017-9048 in LibXML2 2.9.4(stack buffer overflow)
字典用途
本质上就是有一定意义的字符串token
- Override:直接覆盖样本中的n个字节
- Insert:在样本中插入n个字节
AFL++提供了先成的字典(可以凑合)
也可以自己手动构建,用codeql(在线平台LGTM)可以快速查询我们需要的特征字符串如
- 判断的条件
- strcmp、memcmp中的参数
- 声明的常量等
并行
将fuzzer分为master和slave,实现共享instance
1 | . / afl - fuzz - i afl_in - o afl_out - M Master - - . / program @@
|
1 2 3 4 | . / afl - fuzz - i afl_in - o afl_out - S Slave1 - - . / program @@
. / afl - fuzz - i afl_in - o afl_out - S Slave2 - - . / program @@
...
. / afl - fuzz - i afl_in - o afl_out - S SlaveN - - . / program @@
|
编译文件
1 2 3 4 | sudo apt - get install python - dev
CC = / root / fuzz / AFLplusplus / afl - clang - lto CXX = / root / fuzz / AFLplusplus / afl - clang - lto + + CFLAGS = "-fsanitize=address" CXXFLAGS = "-fsanitize=address" LDFLAGS = "-fsanitize=address" . / configure - - prefix = "$HOME/fuzz_target/fuzzing_libxml2/libxml2/install" - - disable - shared - - without - debug - - without - ftp - - without - http - - without - legacy - - without - python LIBS = '-ldl'
AFL_USE_ASAN = 1 AFL_MAP_SIZE = 262144 make - j$(nproc)
AFL_USE_ASAN = 1 AFL_MAP_SIZE = 262144 make install
|
这里在编译时没有直接用ASAN,而是用了编译器自带的fsanitize
,功能如下
-fsanitize=leak
:检测内存泄漏
-fsanitize=address
:检测内存越界,这等于ASAN
编译时设置AFL_MAP_SIZE=262144,决定共享空间大小,因为程序较大,不改成一个较大值会给弹一个警告,最好设置一下。
获取样本和字典
这里用的是fuzzing101提供的样本以及test中的dtd9(DTD,它们会定义 XML 文档的结构和合法元素/属性,并用于确定 xml 文档是否有效)。
1 2 3 | mkdir afl_in && cd afl_in
wget https: / / raw.githubusercontent.com / antonio - morales / Fuzzing101 / main / Exercise % 205 / SampleInput.xml
cd ..
|
使用AFL++提供的字典
1 2 3 | mkdir dictionaries && cd dictionaries
wget https: / / raw.githubusercontent.com / AFLplusplus / AFLplusplus / stable / dictionaries / xml. dict
cd ..
|
fuzz
1 2 | afl - fuzz - m none - i . / afl_in - o afl_out - s 123 - x . / dictionaries / xml. dict - D - M master - - . / xmllint - - memory - - noenc - - nocdata - - dtdattr - - loaddtd - - valid - - xinclude @@
afl - fuzz - m none - i . / afl_in - o afl_out - s 234 - S slave1 - - . / xmllint - - memory - - noenc - - nocdata - - dtdattr - - loaddtd - - valid - - xinclude @@
|
- -D:打开persistent mutations
然后要跑很久,居然是靠havoc出的让我很意外

动态调试
先手动编译出不插桩的程序,丢进gdb里调试
1 | gdb - - args . / xmllint - - memory - - noenc - - nocdata - - dtdattr - - loaddtd - - valid - - xinclude . / afl_out / slave1 / crashes / id : 000009 ,sig: 06 ,src: 009269 ,time: 119653664 ,execs: 60774850 ,op:havoc,rep: 4
|

- 报错信息
*** stack smashing detected ***: terminated
,判断为栈溢出漏洞
- 漏洞位置
__GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:50
,找到问题代码
漏洞修复
- https://github.com/GNOME/libxml2/commit/932cc9896ab41475d4aa429c27d9afd175959d74
VMProtect分析与还原
最后于 2022-7-25 19:08
被Azyka编辑
,原因: