大家好,欢迎来到IT知识分享网。
文章目录
官方文档:https://afl-1.readthedocs.io/en/latest/fuzzing.html
其他文章:
- https://www.freebuf.com/articles/system/191536.html
- https://xz.aliyun.com/t/4314
1. 安装
https://afl-1.readthedocs.io/en/latest/INSTALL.html
Ubuntu直接在AFL根目录make编译安装即可:
sudo make && sudo make install
2. 插桩
https://afl-1.readthedocs.io/en/latest/instrumenting.html
如果有目标程序的源码,就可以对源码进行编译时插桩。AFL也可以使用AFL的QEMU mode
对二进制文件进行插桩,但是编译时插桩效率要高很多。
afl-gcc/afl-g++作为gcc/g++的wrapper, 用法与gcc/g++完全一样, 大概提供了这么一些:
afl-gcc,afl-g++,
afl-clang, afl-clang++,
afl-clang-fast, afl-clang-fast++
配置一下就能用:
./configure CC="afl-gcc" CXX="afl-g++"
如果目标是共享库,可以设置LD_LIBRARY_PATH
让程序加载经过AFL插桩的.so文件:
./configure --disable-shared CC="afl-gcc" CXX="afl-g++"
划重点,Linux版的校验器~, 有大佬说,“AFL Fuzzing without ASAN is just a waste of CPU”.
AFL配备了谷歌自家的Address Sanitizer(ASAN),一个内存检测工具,相当于windows下的verifier校验器:
CC=afl-gcc CFLAGS="-g -fsanitize=address -O1 -fno-omit-frame-pointer" AFL_USE_ASAN=1 ./configure
make clean all
# or
afl-gcc -fsanitize=address -O1 -fno-omit-frame-pointer ...
项目地址:https://github.com/google/sanitizers, wiki很详细。
其它校验器还有MemorySanitizer, ThreadSanitizer, LeakSanitizer。
-fsanitize=memory -fPIE -pi
-fsanitize=leak
...
如果没有目标程序源码,就要对目标程序(Non-instrumented binaries)进行黑盒测试,需要-Q
参数使用QEMU 模式。需要先下载依赖并执行afl下的脚本:
$ sudo apt-get install libini-config-dev libtool-bin automake bison libglib2.0-dev -y
$ cd qemu_mode && build_qemu_support.sh
3. Quick Start
https://afl-1.readthedocs.io/en/latest/fuzzing.html
corpus
译为语料,有时也叫样本。
语料大小最好1Kb,可参考/testcases子目录。
如果语料很多很大,可以使用afl-cmin工具来筛选,假设有多个文件,都覆盖了相同的代码,那么就丢掉多余的文件。
afl-cmin [ options ] -- /path/to/target_app [ ... ]
afl-cmin -i input_dir -o output_dir -- /path/to/tested/program [params] @@
# @@ 会替换为语料文件
测试一个项目时,项目目录里一般也会有输入用例,直接拿来用就行。
另外还有很多开源的语料库:
- https://github.com/google/fuzzer-test-suite
- http://samples.ffmpeg.org/
基本使用
如果已经配置了崩溃转储,可能会让afl-fuzz把崩溃误判为超时,所以修改下core_pattern文件:
echo core >/proc/sys/kernel/core_pattern
我测试时,如果没有修改core_pattern,afl-fuzz是会报错提示的。
针对读取stdin的程序进行fuzz:
afl-fuzz -i testcase_dir -o findings_dir /path/to/program [...params...]
针对读取文件的程序进行fuzz:
afl-fuzz -i testcase_dir -o findings_dir /path/to/program @@
# @@ 会替换为语料文件
其它选项,如-f, -d
,可以查看-h帮助信息。
可以搭配元老级工具screen。
如果没有源码,那么带上-Q使用qemu模式进行黑盒测试:
afl-fuzz -Q -m none -i in -o out /path/to/tested/program [params] @@
如何看输出信息,可参考Understanding the status screen。
输出
Fuzz过程中会生成3个目录:
- queue, 语料库,可以用afl-cmin进一步优化;
- crashes,导致崩溃(SIGSEGV, SIGILL, SIGABRT)的语料;
- hangs,导致超时/卡死/死循环的语料。
尝试复现崩溃时,记着设置与afl-fuzz参数相同的参数,如-m和LIMIT_MB.
如果安装了gnuplot ,可以用afl-plot生成统计图。
多线程
如何多线程fuzz,可参考Tips for parallel fuzzing,这里还提到如何与其它fuzzer联动。
字典
AFL适合比较紧凑的文件格式,如图像、多媒体、压缩文件、正则表达式、shell脚本等,不适合html、sql这种特别复杂的语言。
AFL-fuzz支持用-x参数指定语料字典,可参考dictionaries/README.dictionaries
,该目录下也提供了sql、js等例子。
即使没有-x指定,afl-fuzz也会通过插桩从输入的预料中提取关键字,不过效果没有-x好。
崩溃分析
出现崩溃后,我们的目的之一是判断这是不是可利用的漏洞。
每一个崩溃语料都能追溯到它的上一个没有崩溃的语料(父语料),这有助于分析原因。
一般操作:
- 用xxd, 010editor之类的工具看下崩溃语料的十六进制数据;
- gdb调试。
AFL-fuzz的-C选项可以进入崩溃探索模式(crash exploration mode),该模式通过输入崩溃语料反馈代码路径。
除了agl-cmin,还有另一个语料优化工具afl-tmin , 它可以减小语料文件的大小, 有插桩模式和崩溃模式:
# default instrumented mode
afl-tmin -i test_case -o minimized_result -- /path/to/program [...]
afl-tmin -i test_case -o minimized_result -- /path/to/program @@
# crash mode
afl-tmin -x -i test_case -o minimized_result -- /path/to/program [...]
afl-tmin -x -i test_case -o minimized_result -- /path/to/tested/program @@
AFL还提供了分析工具afl-analyze, 可参考How AFL works页面的末尾 【The afl-analyze tool】 部分。
AFL的experimental目录下还提供了triage_crashes.sh脚本,可触发收集到的崩溃。
对于被测试的程序,使用一些宏有助于减少随机数带来的影响,可参考libFuzzer文档:
void MyInitPRNG() {
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
// In fuzzing mode the behavior of the code should be deterministic.
srand(0);
#else
srand(time(0));
#endif
}
AFL专有的宏是__AFL_COMPILER
。
其它崩溃分析工具:
- https://github.com/bnagy/crashwalk
- https://github.com/rc0r/afl-utils
- afl-cov, 计算覆盖率
4. 用户手册
https://afl-1.readthedocs.io/en/latest/user_guide.html
如何查看结果
包括字段的颜色以及含义
关注点:
- last new path 如果报错那么要及时修正命令行参数,不然继续fuzz也是徒劳(因为路径是不会改变的);
- cycles done 如果变绿就说明后面及时继续fuzz,出现crash的几率也很低了,可以选择在这个时候停止
- uniq crashes 代表的是crash的数量
afl-fuzz永远不会停止(所以推荐搭配screen),所以何时停止测试是依靠fuzz状态来决定的,除了cycles done字段颜色,还有以下方法:
- afl-whatsup
- afl-stat, 类似afl-whatsup
- afl-plot
- pythia
如何配置(环境变量)
比如启用ASAN:
多线程
除了单机上多线程,文档还提供了分布式教程,源码位于/experimental/distributed_fuzzing/
其它开源实现:
- https://github.com/MartijnB/disfuzz-afl
- https://github.com/richo/roving
5. Using ASAN with AFL
6. Tips
Fuzz优化
https://afl-1.readthedocs.io/en/latest/tips.html#performance-tips
7. More about AFL
AFL原理
More about AFL
AFL使用了fork server来提高性能,目标程序只需要执行一次execve()、链接和libc初始化,利用写时拷贝基址克隆进程。
但不断fork也会影响性能,于是提供了Persistent Mode。可以参考/experimental/persistent_demo
示例。
8. Demo
以tcpdump为例,源码tests目录下提供了很多pcap用例,可以作为语料。
另外还需要libcap源码。
正常查看pcap的命令:
sudo tcpdump -vv -nnr tests/tftp-heapoverflow.pcap
reading from file tests/tftp-heapoverflow.pcap, link-type LINUX_SLL (Linux cooked)
09:10:59.680304 IP (tos 0x30, ttl 48, id 12336, offset 0, flags [DF], proto UDP (17), length 12336, bad cksum 3030 (->299d)!)
48.48.48.48.69 > 48.48.48.48.12336: 12308 RRQ "00" [|tftp]
用afl-cmin精简一下:
$ sudo afl-cmin -i tests/ -o mintests -m none tcpdump -vv -r @@
corpus minimization tool for afl-fuzz by <lcamtuf@google.com>
[-] Error: binary '/usr/sbin/tcpdump' doesn't appear to be instrumented.
报错tcpdump无法插桩,尴尬了,本想试试-Q黑盒测试来着。
那就试试白盒吧,先编译libcap:
CC=afl-gcc CFLAGS="-g -fsanitize=address -O1 -fno-omit-frame-pointer" AFL_USE_ASAN=1 ./configure
sudo make && sudo make install
再编译tcpdump:
$ CC=afl-gcc CFLAGS="-g -fsanitize=address -O1 -fno-omit-frame-pointer" LDFLAGS="-lpcap" AFL_USE_ASAN=1 ./configure
$ sudo make && sudo make install
# 添加so的搜索路径,不然找不到libpcap.so
$ sudo vim /etc/ld.so.conf
$ cat /etc/ld.so.conf
include /etc/ld.so.conf.d/*.conf
/usr/local/lib
/usr/lib
$ sudo ldconfig
$ sudo ./tcpdump --version
tcpdump version 5.0.0-PRE-GIT
libpcap version 1.11.0-PRE-GIT (with TPACKET_V3)
OpenSSL 1.1.1 11 Sep 2018
Compiled with AddressSanitizer/GCC.
再次执行afl-cmin精简语料库,等了大概十分钟:
$ sudo afl-cmin -i tests/ -o mintests -m none ./tcpdump -vv -r @@
corpus minimization tool for afl-fuzz by <lcamtuf@google.com>
[*] Testing the target binary...
[+] OK, 1090 tuples recorded.
[*] Obtaining traces for input files in 'tests/'...
Processing file 20/1313...
Processing file 32/1313...
Processing file 1313/1313...
[*] Sorting trace sets (this may take a while)...
[+] Found 28291 unique tuples across 1313 files.
[*] Finding best candidates for each tuple...
Processing file 1313/1313...
[*] Sorting candidate list (be patient)...
[*] Processing candidates and writing output files...
Processing tuple 28291/28291...
[+] Narrowed down to 442 files, saved in 'mintests'.
$ ll tests/ | wc -l
1317
$ ll fuzz_tcpdump_output/ | wc -l
445
开始fuzz:
$ sudo afl-fuzz -i mintests/ -o fuzz_tcpdump_output -m none ./tcpdump -vv -r @@
...
[*] Attempting dry run with 'id:000008,orig:DECnet_Phone.pcap'...
len = 7678, map size = 1147, exec speed = 3372 us
[*] Attempting dry run with 'id:000009,orig:DTP.pcap'...
len = 934, map size = 1144, exec speed = 3268 us
[*] Attempting dry run with 'id:000010,orig:EIGRP_adjacency.pcap'...
[-] The program took more than 1000 ms to process one of the initial test cases.
This is bad news; raising the limit with the -t option is possible, but
will probably make the fuzzing process extremely slow.
If this test case is just a fluke, the other option is to just avoid it
altogether, and find one that is less of a CPU hog.
[-] PROGRAM ABORT : Test case 'id:000010,orig:EIGRP_adjacency.pcap' results in a timeout
Location : perform_dry_run(), afl-fuzz.c:2806
总是会有语料爆出timeout超时错误,而mintests这个目录最好不要动它,目录本身是故意设置成非root用户不可写的。
最后只用一个文件作为语料库测试了。。。
$ cp tests/reason_code-10.pcap in/
$ sudo afl-fuzz -i in/ -o fuzz_tcpdump_output -m none ./tcpdump -vv -r @@
9. 其它参考资料
AFL漏洞挖掘技术漫谈(一):用AFL开始你的第一次Fuzzing – FreeBuf网络安全行业门户
Linux终端命令神器–Screen命令详解。助力Linux使用和管理 – 云+社区 – 腾讯云 (tencent.com)
模糊测试之AFL总结 (myfzy.top)
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/14456.html