20199124 2019-2020-2《网络攻防实践》综合实践

《Full-speed Fuzzing: Reducing Fuzzing Overhead through Coverage-guided Tracing》论文分析


1 Fuzzing

1.1 概述

​ 模糊测试技术是通过向待测的程序中输入大量随机的半合法数据,并观察目标程序是否有异常情况出现来检测漏洞。使用模糊测试技术进行漏洞检测主要分为六个步骤,其基本流程图如图1所示。

1.2 覆盖引导的模糊测试

​ 模糊测试是一种很有效的测试技术,但传统的fuzzing工具由于生成测试用例时过于随机,其测试存在盲目性,而且存在着测试用例覆盖率低的缺陷,许多的代码漏洞需要更大的路径覆盖率才能触发,而不是通过纯粹的随机尝试。为了解决这一问题,覆盖引导的 fuzzing 策略出现,并被广泛使用。

​覆盖引导的fuzzing具体流程如上图所示。

  1. 将所有初始种子进行排列,等待变异;
  2. 选择种子进行多次迭代,生成测试用例;
  3. 将测试用例输入到被测软件中开始运行,追踪其覆盖率,并检测软件是否崩溃;
  4. 若测试用例的覆盖率增加则将其作为初始种子,若覆盖率没有增加则丢弃;
  5. 若测试用例引起软件崩溃,系统将其记录,以便产生最后的测试报告;
  6. 返回第2步,重复步骤。

1.3传统覆盖引导的fuzzing缺陷

代码覆盖追踪是覆盖引导的fuzzing的一个重要组成部分,同时也是由覆盖引导的模糊测试的开销的主要来源。目前,覆盖引导的fuzzing追踪所有测试用例的代码覆盖率,然而绝大部分的测试用例和他们的覆盖信息实际是无用的,因为他们并不会增加代码覆盖率。追踪这些无用的测试用例极大的增加了模糊测试工具的开销。

​ 下图展示了8个真实程序的测试用例,随时间增长,覆盖率增加的测试用例越来越少,将每个测试用例的覆盖范围都追踪一遍实在是浪费。


2 Full Fuzzing

2.1方案设计

​ 为了减少对这些无用测例的追踪以提高模糊测试的性能,文章《Full-speed Fuzzing: Reducing Fuzzing Overhead through Coverage-guided Tracing》提出了一种由覆盖引导的追踪技术,来对过滤这些无用测例。该技术可以在不对测例进行追踪的情况下,检测出一个新生成的测例会不会引起代码覆盖率的增加,只有当新测例会引起代码覆盖率增加,才对该测例进行覆盖追踪,以获得完整的覆盖率信息。

​ 上图是引入了由覆盖引导的追踪技术后,模糊测试工具的流程图。可以看到在原有代码覆盖追踪(标号2)之前引入了一个新的步骤 the interest oracle(标号1)。

​ Interest Oracle的基本原理是,对于待模糊测试的目标二进制程序,在每一个未覆盖的基本块的开始处插入一个特殊的中断指令,生成一个新的程序。对于每一个新生成的测试用例,先在the interest oracle上运行,如果触发了该特殊的中断指令,说明这个测例到达了一个之前未到达过的基本块,因此这个测例会引起覆盖率的增加,是一个我们感兴趣的测例;如果没有触发中断,则说明这个输入到达的都是之前已经测试过的基本块,会被直接抛弃。只有当一个新的测例被确定是覆盖率增加的测例,才会被传递给后续模块进行真正的代码覆盖追踪(标号2)。代码覆盖追踪可以确定这个测例所到达的所有之前未到达的基本块,the interest oracle中这些块头部的中断指令就会被移除(标号3)。

​ 经过多轮覆盖率增加的测试用例被执行追踪,the interest oracle中越来越多的中断被删除,the interest oracle文件与源文件越来越接近,测试用例覆盖率增加的范围变小,不断进行下去,追踪测试用例的开销渐渐变为0.

由覆盖引导的追踪技术使用了一个轻量的技术方案,来确定一个测例是否会到达新的基本块,增加代码覆盖率,避免对无效的测例进行覆盖追踪,从而提升整体的性能。

2.2 工具UnTracer

​ UnTracer是建立在修改版灰盒测试工具AFL 2.52b上的模糊测试工具。UnTracer要生成两个不同版本的二进制文件,一个是用来判断测试用例覆盖率是否增长的the interest oracle,一个是用来进行追踪以获得新覆盖率的tracer。AFL的forkserver执行模式让我们可以灵活使用这两个文件。算法1展示了UnTracer的工作流程。

​ the interest oracle文件主要用来过滤覆盖率没有增长的测试用例,生成这个文件需要知道被测文件中所有的基本块,并在每个基本块前插入中断。这一工作可以使angr或者Dyninst工具来实现,在插入中断时需要注意两点,一是基本块的中断不可以与测试文件中的中断冲突,特别时bug中断;二是,中断指令的长度不得超过基本块本身的长度。

​ tracer用来追踪测试用例的覆盖范围,测试用例执行时肯定会出现重复执行的基本块,这会增加测试的开销。一方面,重复记录执行多次的基本块,影响写效率;另一方面,在之后更新the interest oracle的步骤中需要读取每一条记录,这会影响读效率。为了解决这个问题,我们在执行测试用例前先初始化一个hashmap,用它来记录已经被覆盖的所有基本块,执行基本块时,先在hashmap中查找这个基础块在在此次执行中是否已经覆盖了,如果没有就更新追踪日志和hashmap。

​ 当出现覆盖率增加的测试用例时,the interest oracle就需要更新,需要将一些中断从基础块中移除,一般我们使用被测文件中含有的删除指令移除基本块的中断。通过对tracer的分析我们可以知道,tracer会记录测试用例运行的所有基础块,而这些基础块肯定不全是这次测试才被覆盖的,所以一些基础块前的中断已经被移除了,按照tracer的记录将每一个基本块前的中断都查看一遍会增加测试开销。为了解决这个问题,我们再次使用hashmap,我们将已经移除中断的基本块用hashmap进行记录,将tracer记录中的基本块与hashmap进行对比,找出那些还没有移除中断的基本块,将其中断移除,这就就节省了开销


3 Evaluate

3.1评估标准

​ 为了对比UnTracer和传统覆盖引导的模糊测试之间的性能差异,作者选取了8个不同种类的真实世界程序作为测试集,比较用不同追踪技术运行测例,与直接运行测例相比,额外花费的时间。图10展示了8个不同种类的真实世界程序的基本信息。

3.2白盒测试场景

​ 在白盒测试场景下,作者选用了较为流行的AFL-Clang与UnTracer进行比较。AFL-Clang是使用AFL-Clang进行编译运行。下图为两个迷糊测试其对8个真是程序的测试结果,可以看出,Untracer只有0.3%额外开销,而AFL-Clang则有36%的额外开销。

3.3黑盒测试场景

​ 在黑盒测试场景下,作者选择了较为流行的AFL-QEMU、AFL-Dyninst与Untracer进行对比。下图展示了AFL-QEMU、AFL-Dyninst与Untracer对8个真实程序的测试结果,可以看出,Untracer平均有20%的额外开销,而其他工具有500%-600%的额外开销。


4 Install And Use UnTracer

4.1UnTracer的安装

1.下载并安装Dyninst

Dyninst的官方下载地址下载(http://www.dyninst.org/downloads/archive/)

sudo apt-get install cmake m4 zlib1g-dev libboost-all-dev libiberty-dev 
wget https://github.com/dyninst/dyninst/archive/v9.3.2.tar.gz 
tar -xf v9.3.2.tar.gz dyninst-9.3.2/ 
mkdir dynBuildDir 
cd dynBuildDir 
cmake ../dyninst-9.3.2/ -DCMAKE_INSTALL_PREFIX=`pwd` 
make 
make install

2.下载Untracer-AFL

Untracer-AFL的源码链接如下,可直接下载。https://github.com/FoRTE-Research/UnTracer-AFL

3.设置环境变量

环境变量设置如下,直接输入代码即可。

export DYNINST_INSTALL=/path/to/dynBuildDir 
export UNTRACER_AFL_PATH=/path/to/Untracer-AFL  

export DYNINSTAPI_RT_LIB=$DYNINST_INSTALL/lib/libdyninstAPI_RT.so 
export LD_LIBRARY_PATH=$DYNINST_INSTALL/lib:$UNTRACER_AFL_PATH 
export PATH=$PATH:$UNTRACER_AFL_PATH 

4.编译UnTracer-AFL

将UnTracer-AFL/Makefile中的DYN_ROOT移动到Dyninst的安装目录下,然后运行命令make clean && make all

4.2UnTracer的使用

​ 首先,使用“forkserver-only”工具编译所有目标二进制文件。与afl一样,需要我们手动设置c编译器(untracer-clang 或 untracer-gcc)或c + +编译器(untracer-clang + 或 untracer-g + +)。

​ 然后我们运行以下命令:

untracer-afl -i [/path/to/seed/dir] -o [/path/to/out/dir] [optional_args] -- [/path/to/target] [target_args]

​ 这里提供一个测试用例:https://github.com/FoRTE-Research/FoRTE-FuzzBench。

​ 下图为UnTracer-AFL运行界面。

  • calib execs和trim execs:测试用例校准和微调执行的次数;block coverage表示已覆盖的基本块数占全部基本块的百分比(左)和总基本块数(右);
  • traced/queued:表示追踪测试用例与排队测试用例的比例,理想情况下这个比率应该是1:1,但追踪超时时会增加;
  • trace tmouts (discarded):表示在跟踪过程中超时的测试用例的数量;
  • no new bits (discarded):通过oracle检测覆盖率增加,而实际上覆盖率没有增加的测试用例个数,理想情况下这里应该为0

5 总结

​ 作者从模糊测试过程中,绝大部分生成的测试用例都无法增加代码覆盖率这一对现实的观察出发,选取了代码覆盖率追踪为切入点,使用了一种较为简单的技术,对由覆盖引导的模糊追踪技术进行优化,并且取得了不错的性能提升。但这种优化对由覆盖引导的模糊测试工具的效果的影响是未知的。比如在相同的运行时间下,引入由覆盖引导的追踪技术的模糊测试,能否比原来的工具获得更高的覆盖率,对于这类问题,本文并没有回答。


6.课程学习总结

不知不觉一个学期就在家里度过了,也以这种特殊的形式结束了《网空攻防实践》这门课程。学习这门课实我收获颇多,本人是一个计算机小白,对于计算机方面的知识了解不深,而要想学习这门课必须有较好的计算机知识基础,所以这门课不仅让我学习了网络攻防知识,这也逼着我完成了对于计算机知识的学习。从实践环境的搭建,到学习网络攻防的每一个步骤,查点、扫描、渗透、提权等等,虽然每周写博客写到深夜也是头疼不已,面对虚拟机各种复杂操作也是身心俱疲,但完成各种实验后也是小有成就,也明白了自学得到的知识,也永远理解最透彻的知识。也感谢老师一个学期以来的教导,虽然严格,但着实也是在推我们前进。虽然这门课结束了,但是我对于网络攻防实践的学习还没有结束,以后也不会忘记这门的所学所感。

posted @ 2020-07-04 15:00  20199124-马璐瑶  Views(629)  Comments(0Edit  收藏  举报