FUZZ(2):AFL结果分析和代码覆盖率
196082 慢慢好起来

本来不打算做AFL的源码分析,但是看到了一篇文章吸引到了我,当然这篇文章还是不会涉及到源码分析,在后续的FUZZ相关文章中会进行进一步分析。

fuzzer工作状态

首先可以查看在output目录下的fuzzer_state文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
➜  afl-2.52b cat ./afl_test/output_dir/fuzzer_stats
start_time : 1679542022
last_update : 1679542022
fuzzer_pid : 541718
cycles_done : 0
execs_done : 24
execs_per_sec : 387.10
paths_total : 3
paths_favored : 2
paths_found : 0
paths_imported : 0
max_depth : 1
cur_path : 0
pending_favs : 2
pending_total : 3
variable_paths : 0
stability : 100.00%
bitmap_cvg : 0.05%
unique_crashes : 0
unique_hangs : 0
last_path : 0
last_crash : 0
last_hang : 0
execs_since_crash : 24
exec_timeout : 20
afl_banner : test
afl_version : 2.52b
target_mode : qemu
command_line : ./afl-fuzz -i ./afl_test/input_dir -o ./afl_test/output_dir -Q ./afl_test/test

不过这里我在运行时cat几次内容都没有发生变化所以我猜测应该是运行开始时产生,运行结束时才修改内容。那么如果想要实时的查看运行情况的话可以用afl-whatsup

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
➜  afl-2.52b ./afl-whatsup ./afl_test
status check tool for afl-fuzz by <lcamtuf@google.com>

Individual fuzzers
==================

>>> test (0 days, 0 hrs) <<<

cycle 1, lifetime speed 2 execs/sec, path 0/3 (0%)
pending 2/3, coverage 0.05%, no crashes yet

Summary stats
=============

Fuzzers alive : 1
Total run time : 0 days, 0 hours
Total execs : 0 million
Cumulative speed : 2 execs/sec
Pending paths : 2 faves, 3 total
Crashes found : 0 locally unique

➜ afl-2.52b ./afl-whatsup ./afl_test
status check tool for afl-fuzz by <lcamtuf@google.com>

Individual fuzzers
==================

>>> test (0 days, 0 hrs) <<<

cycle 96, lifetime speed 1480 execs/sec, path 3/4 (75%)
pending 0/0, coverage 0.05%, crash count 3 (!)

Summary stats
=============

Fuzzers alive : 1
Total run time : 0 days, 0 hours
Total execs : 0 million
Cumulative speed : 1480 execs/sec
Pending paths : 0 faves, 0 total
Crashes found : 3 locally unique

虽然但是,我感觉我这里好像使用有问题,但是先不管那么多了。

再简单介绍一下afl-plot,这个工具总结出来的内容更为直观,可以直接图形化显示。这里存在一定依赖问题

1
2
apt-get install gnuplot
afl-plot afl_state_dir graph_output_dir

下面就是输出出来的结果,但是不知道为什么这里的total paths没有显示,我猜测可能是因为这里不是使用afl-gcc进行编译或者就是我的电脑性能太拉了。这里的uniq crashes开始在增加随后逐渐趋于平稳。最后一个就是执行速度,随着时间的推移也是越来越慢了,当然也可能是因为占用了太多的系统资源。image-20230323142824705

然后再说说pythia插件吧,这个插件可以看到发现新的crash和path的概率。他与原版也只是差了几个字段。

image-20230323153710947

这里在process timing里面框中出现了两个新的字段分别是correctinessfuzzability,他们的含义分别是在没有发现crash时,发现一个导致crash输入的概率,表示在该程序中发现新路径的难度,该数值越高代表程序越容易Fuzz。在overall results框中也多了两个,第一个是当前发现的路径,一个是路径覆盖率。

何时关闭fuzz

用过就能知道的是fuzz其实是无限执行下去的,这里可以用上面的几种方法来观察是否该结束,当然这里也可以直接在原始的AFL中看到何时该结束,注意这里cycles done的颜色,在fuzz的过程中这个颜色是一直会变化的,可以看到上面的图中颜色为紫色,这里为蓝色。所以他的变化顺序为紫色->黄色->蓝色->绿色,当为绿色是就代表很难再找到新的crash了,而这个时候就可以结束了。(下图为蓝色主要是受我电脑性能影响的)image-20230323140202009

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
➜  output_dir tree
.
├── crashes
│   ├── id:000000,sig:06,src:000001,op:havoc,rep:64
│   ├── id:000001,sig:11,src:000000,op:flip1,pos:1
│   ├── id:000002,sig:11,src:000000,op:havoc,rep:16
│   └── README.txt
├── fuzz_bitmap
├── fuzzer_stats
├── hangs
├── plot_data
└── queue
├── id:000000,orig:in.txt
├── id:000001,orig:in1.txt
├── id:000002,orig:in2.txt
└── id:000003,src:000001,op:arith8,pos:0,val:-27,+cov

queue:存放所有具有独特执行路径的测试用例。
crashes:导致目标接收致命signal而崩溃的独特测试用例。
crashes/README.txt:保存了目标执行这些crash文件的命令行参数。
hangs:导致目标超时的独特测试用例。
fuzzer_stats:afl-fuzz的运行状态。
plot_data:用于afl-plot绘图。

处理测试结果

这里只介绍两种方式,一是crashwalk再就是afl-collect

crashwalk

安装过程这里就不再说了,网上很多,搜搜就有。

首先这个有两种模式,一是Manual Mode其次就是AFL Mode,他们的命令新式分别如下。

1
2
~/tools/go/bin/cwtriage -root syncdir/fuzzer1/crashes/ -match id -- ~/parse @@
~/tools/go/bin/cwtriage -root syncdir -afl

image-20230323190851304

这里使用的是第一种方式(用AFL时我这里会出现无法no crash detected错误)。

可以看到这里的描述中写上了栈溢出漏洞。

afl-collect

这个工具使用命令如下:

1
python3 ./afl-collect -j 8 -d crashes.db -e gdb_script ./afl_sync_dir ./collection_dir --  /path/to/target --target-opts

image-20230323195200830

结果比上面的更为直观。

代码覆盖率

代码覆盖率是模糊测试中一个极其重要的概念,使用代码覆盖率可以评估和改进测试过程,执行到的代码越多,找到bug的可能性就越大,毕竟,在覆盖的代码中并不能100%发现bug,在未覆盖的代码中却是100%找不到任何bug的,所以本节中就将详细介绍代码覆盖率的相关概念。

代码覆盖率是一种度量代码的覆盖程度的方式,也就是指源代码中的某行代码是否已执行;对二进制程序,还可将此概念理解为汇编代码中的某条指令是否已执行。其计量方式很多,但无论是GCC的GCOV还是LLVM的SanitizerCoverage,都提供函数(function)、基本块(basic-block)、边界(edge)三种级别的覆盖率检测,更具体的细节可以参考LLVM的官方文档

基本块

只有一个入口点,BB中的指令不是任何跳转指令的目标。

只有一个退出点,只有最后一条指令使执行流程转移到另一个BB

如下图中的代码就可以被切割为4个基本块,平时我们在IDA图形模式中看到的就是一个一个的基本块

拿一个程序举例,在ida中每一块就代表一个基本块。

image-20230323200531347

依旧是上面ida的图,每一条线,也就是每一个箭头就代表一个边。

元组

在AFL中,使用二元组(branch_src, branch_dst)来记录当前基本块 + 前一基本块的信息,从而获取目标的执行流程和代码覆盖情况,伪代码如下:

1
2
3
cur_location = <COMPILE_TIME_RANDOM>;            //用一个随机数标记当前基本块
shared_mem[cur_location ^ prev_location]++; //将当前块和前一块异或保存到shared_mem[]
prev_location = cur_location >> 1; //cur_location右移1位区分从当前块到当前块的转跳

实际插入的汇编代码,如下图所示,首先保存各种寄存器的值并设置rcx,然后调用__afl_maybe_log,这个方法的内容相当复杂,这里就不展开讲了,但其主要功能就和上面的伪代码相似,用于记录覆盖率,放入一块共享内存中。image-20230323200655405

计算代码覆盖率

这里计算代码覆盖率主要是介绍两个工具,一是GCOV另一个则是LCOV它是GCOV的前端。

image-20230323214327472

可以看到这里有覆盖率之类的东西,当然也可以在网页中打开

image-20230323214409463

image-20230323214533298

点开文件会有更为详细的数据,每行代码前的数字代表被执行的次数,其中红色的代表未执行过的。


参考链接:
https://paper.seebug.org/842/#4-afl-collect

 评论
评论插件加载失败
正在加载评论插件
由 Hexo 驱动 & 主题 Keep
本站由 提供部署服务
总字数 335.6k 访客数 访问量