LibFuzzer学习笔记
环境配置
- Ubuntu 22.04
安装源码:验证:showLineNumbers 1
2
3
4
5
6
7
8
9Install git and get this tutorial
sudo apt-get --yes install git
git clone https://github.com/google/fuzzing.git fuzzing
Get fuzzer-test-suite
git clone https://github.com/google/fuzzer-test-suite.git FTS
./fuzzing/tutorial/libFuzzer/install-deps.sh # Get deps
./fuzzing/tutorial/libFuzzer/install-clang.sh # Get fresh clang binaries结果应该是ASAN检测到内存错误:1
2clang++ -g -fsanitize=address,fuzzer fuzzing/tutorial/libFuzzer/fuzz_me.cc
./a.out 2>&1 | grep ERROR
入门Fuzzer编写
fuzz target
fuzz target定义:有如下格式定义的对参数进行操作的函数
1 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t **Data, size_t Size) { |
查看刚刚运行的./fuzz_me.cc
源码,当输入长度大于等于3时,会判断前四个元素是否为FUZZ
,即存在越界读取问题。
1 |
|
为了编译一个fuzzer二进制程序,需要使用Clang工具编译源码,并添加以下flags:
-fsanitize=fuzzer
(required):为libFuzzer提供进程内的覆盖率信息,并将其与libFuzzer运行时进行链接;-fsanitize=address
(recommended):开启ASAN检测;-fno-omit-frame-pointer
:更好看的函数调用栈信息;-O1
:编译优化;-g
(recommended):开启调试信息,令错误信息更易于阅读。
例如:然后执行./a.out即可出现上面的结果截图。1
clang++ -g -fsanitize=address,fuzzer fuzzing/tutorial/libFuzzer/fuzz_me.cc
输出信息解读
其中有一段信息:INFO: Seed: 4055535767
,表明fuzzer由此随机种子开始进行模糊测试。使用-seed=4055535767
参数可以指定种子获得相同结果。
1 | INFO: -max_len is not provided; libFuzzer will not generate inputs larger than 4096 bytes |
默认情况下,libFuzzer假定所有输入都小于等于4096字节。可以使用-max_len=N
或者添加种子来修改。
1 | #2 INITED cov: 3 ft: 3 corp: 1/1b exec/s: 0 rss: 30Mb |
以上信息表示libFuzzer已经尝试了28392次输入,并且发现了5个种子14字节长度,实现覆盖7个点。点可以理解为代码中的基本块(入门可以先这么理解,其实应该叫边吧)。
1 | ==4197==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x6020000b5af3 at pc 0x56907ee52f3c bp 0x7fff01c7e4f0 sp 0x7fff01c7e4e8 |
存在一个输入使ASAN检测到heap-buffer-overflow
错误并停止运行。
1 | artifact_prefix='./'; Test unit written to ./crash-0eb8e4ed029b774d80f2b66408203801cb982a60 |
在退出前libFuzzer将引发crash的输入保存为文件,查看文件:
1 | base ❯ cat crash-0eb8e4ed029b774d80f2b66408203801cb982a60 |
因为FUZ
,导致通过了前面的一系列检查,并且对data[3]
进行了访问,导致越界。
心脏滴血漏洞实验
fuzzer-test-suite包含了openssl-1.0.1f存在该漏洞
执行以下命令来编译fuzzer
1 | mkdir -p ~/heartbleed; rm -rf ~/heartbleed/*; cd ~/heartbleed |
编译完成后运行目标fuzzer,过一会后产生crash如下:

种子语料库
设置多个参数指定种子目录时,会递归将所有目录中文件用于种子输入,然后如果模糊测试过程中出现了产生新覆盖率的种子,会将其保存在第一个目录中。
1 | mkdir MY_CORPUS |
字典
使用-dict参数设置字典目录:
1 | ./libxml2-v2.9.2-fsanitize_fuzzer -dict=afl/dictionaries/xml.dict # Press Ctrl-C in 10-20 seconds |
将libFuzzer作为库
如果目标代码必须提供main
函数,那么需要将libFuzzer作为库函数调用执行。需要在编译时传递-fsanitize=fuzzer-no-link
参数,并指定无main函数的libFuzzer版本,其路径为。
1 | /usr/lib/<llvm-version>/lib/clang/<clang-version>/lib/linux/libclang_rt.fuzzer_no_main-<architecture>.a |
代码可以执行正常功能,当需要开始模糊测试时,可以调用LLVMFuzzerRunDriver
,传入程序参数和回调函数。类似LLVMFuzzerTestOneInput
,且声明相同:
1 | extern "C" int LLVMFuzzerRunDriver(int *argc, char ***argv, |