fuzzing(三)
fuzz101:https://github.com/antonio-morales/Fuzzing101
可以以上面的练习来熟悉并学一些fuzz的操作,下面是正文libfuzzer的简要介绍。
一:libfuzzer介绍
libfuzzer是clang中的一个工具,新版本的clang已经内涵libcfuzzer了,可以在编译时通过-fsanitize=fuzzer来启动,但是libfuzzer与普通的fuzzer有什么不同呢?libFuzzer 倾向于对某个功能或者函数来进行fuzzing,AFL 则是对整体程序进行fuzzing。
二:实战篇
首先先git一下我们需要用到的脚本,可以为各种目标构建模糊器。
1 | git clone https://github.com/google/fuzzer-test-suite |
假设已经git下来整个项目,就可以进行下一步了。
1.Heartbleed
Heartbleed(CVE-2014-0160)是openssl加密库中的一个严重安全漏洞。
1 | cd ~ |
然后在fuzzing_openssl就可以看到openssl-1.0.1f-fsanitize_fuzzer
1 | ./openssl-1.0.1f-fsanitize_fuzzer |
就可以看到下面的代码,是一个堆溢出,我只复制了一小部分,fuzzer过程大概要花费10s
1 | ==21150==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x629000009748 at pc 0x00000051d75a bp 0x7fffeb0ab2f0 sp 0x7fffeb0aaab8 |
2.Seed corpus
看到名字就会想到此训练是关于种子库的作用,在一些平常fuzz时,如果没有根据的进行会很慢并且拖慢效率,如果有种子库的话,效率会很大提升。
1 | cd ~ |
在fuzzing_woff下就会看到woff2-2016-05-06-fsanitize_fuzzer
1 | ./woff2-2016-05-06-fsanitize_fuzzer |
运行会发现fuzzer会卡住,因为发现不了新的路径。刚刚执行的build.sh脚本会构建.woff2文件(在seeds目录下)
1 | mkdir MY_CORPUS |
当一个基于libfuzzer的fuzzer以另一个目录作为参数执行时,首先会递归的从每个目录中读取文件,并在所有目录下执行目标函数,然后触发新路径的输入都会被写入MY_CORPUS
3.Dictionaries
提高fuzzing效率还有一个方法,就是用字典,如果被fuzz的输入由tokens和magic vaules组成,我们就可以用这种方法
1 | cd ~ |
在fuzzing_libxml下会看到libxml2-v2.9.2-fsanitize_fuzzer
不使用字典:
1 | ./libxml2-v2.9.2-fsanitize_fuzzer |
使用字典:
1 | ./libxml2-v2.9.2-fsanitize_fuzzer -dict=/usr/local/share/afl/dictionaries/xml.dict |
如果跑相同时间的情况下,使用字典的方法应该是比不使用字典的效率高很多的。
4.Cross-checking
交叉检查,目标函数将数据提供给预计会产生相同结果的两个不同函数并进行验证。
1 | cd ~ |
在fuzzing_openssl_d下会看到openssl-1.0.2d-fsanitize_fuzzer
1 | ./openssl-1.0.2d-fsanitize_fuzzer -max_len=256 CORPUS -jobs=8 -workers=8 |
会出现很多crash,不过也会报出问题所在

5.Competing bugs
目标中存在一个易于发现的错误,会阻止我们找到更多错误。在这种情况下,最好的方法是修复浅层错误并重新启动模糊测试。可以通过简单地多次重新启动 libFuzzer 来向前推进一点。-jobs=1000
会为你做这件事。
1 | cd ~ |
在fuzzing_pcre2中发现了pcre2-10.00-fsanitize_fuzzer
1 | mkdir CORPUS |
1 | grep ERROR *.log | sort -k 3 |

6.Minimizing a corpus
精简语料库:创建具有相同覆盖率的语料库子集
1 | mkdir NEW_CORPPUS |
下面的命令会将发现新的路径的输入加入语料库
1 | ./your-fuzzer EXISTING_CORPUS SOME_MORE_INPUTS -merge=1 |
7.Minimizing a reproducer
最小化导致程序崩溃的输入,libfuzzer自带这种功能,用参数-runs和-minimize_crash来使用
1 | ./openssl-1.0.2d-fsanitize_fuzzer -minimize_crash=1 -runs=10000 ./crash-02c37c384e69b70652a91c81dad4b4852ef93dd8 |
此命令是尝试通过在每次迭代中应用多达10000个突变,以迭代方式最小化crash reproducer,然后查看生成的crash文件大小,进行对比。

8.Visualizing Coverage
可视化覆盖范围,就是以可视化的形式显示代码覆盖率。
1 | clang -fprofile-instr-generate -fcoverage-mapping ~/fuzzing/tutorial/libFuzzer/fuzz_me.cc \ |
下面看不同输入的例子
1 | echo -n A > CORPUS/A && ./a.out CORPUS/* && \ |

红色部分是未覆盖到的部分。
1 | echo -n AAA > CORPUS/AAA && ./a.out CORPUS/* && \ |
可以看到,改变了输入,然后看一下覆盖率的情况。

参考资料:https://github.com/google/fuzzing/blob/master/tutorial/libFuzzerTutorial.md#cross-checking