AFL入门笔记

2 篇文章 0 订阅


官方文档: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

如何查看结果

包括字段的颜色以及含义

关注点:

  1. last new path 如果报错那么要及时修正命令行参数,不然继续fuzz也是徒劳(因为路径是不会改变的);
  2. cycles done 如果变绿就说明后面及时继续fuzz,出现crash的几率也很低了,可以选择在这个时候停止
  3. 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)

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值