前言
在之前关于AFL的程序执行路径在AFL第三节讲过,首先是afl-gcc对每个基本块随机赋予一个随机值,然后在执行的时候,通过fork()后的“子进程”去执行插桩的部分代码,把随机值亦或后的字节加一,通过共享的bitmap存储区域就可以知道执行当前种子的bitmap(执行路径)是多少了。但是存在几点问题:1、bitmap利用率,bitmap大小为65536个字节,有些程序的边可能会超过(概率很小),但是也存在很多利用率不足的问题。2、可能存在碰撞,因为随机分配的值就有可能相同,其次异或操作之后可能会相同,那么两条不同的边对应的值却相等了。
有一个解决方法就是使用Intel Processor Tracing,Intel研发的一个程序跟踪功能,这个部件可以直接对二进制程序进行跟踪。由于程序执行的时候,它本身的代码在CPU中的地址是固定的,PT可以返回CPU中的数据流操作,通过筛选程序的地址的包信息,就可以获取程序的操作流从而获得程序执行路径。举个例子,hello world这个程序运行的时候,基本块在CPU中的id是45-90,那么运行这个程序的时候使用PT就可以捕获CPU中的执行数据,可能有很多包(包括鼠标、显示器、其他程序、终端等等),筛选id在45-90的PT包,这些数据包就是运行“hello world”产生的包信息,然后对包信息中的基本块id就可以描绘出程序执行的边路径了。因为一个程序载入内存运行后地址是固定的,准确无碰撞,且不依靠源码的插桩,还比AFL自带的QEMU模式快不少,成为一个不错的方法。
我在这就介绍以下在fuzz中使用的一个PTFuzzer、NEUFuzz和Honggfuzz。
PTFuzz
这个工具是在AFL的基础上做出了改进,把AFL的基础上去除了插桩的依赖,把run_target里面的fork子进程跑插桩代码部分改成fork一个子进程利用PT收集包信息、筛选包信息,根据包信息获取当前种子的执行路径。
简单说一下他的创新点:
利用PT包信息
通过PT部件可以获得两个种类的包信息:基本执行信息(时间戳计时器、包流边界等)和控制流信息(时间、程序执行流等)。PT提供了三类调用包:直接调用、间接调用和远转换调用。当捕获了这样的Change of Flow Instructions(COFI)包时,就可以获取基本块的跳转信息,即边信息。
不同于统一大小的bitmap
AFL中的bitmap时固定大小(65536),而PTfuzz会在初始化载入二进制程序的时候,就构建了COFI map。利用python的CLE和capstone库把程序中text部分的调用地址记录下来并且存放在MSR寄存器,那么MSR寄存器就可以用来筛选PT的包信息。(MSR寄存器是PT指定可以实现筛选功能的寄存器)。
在实验部分,分为对有源码的代码进行测试比较和对二进制程序进行测试比较。
在有源码可插桩的代码比较中,PTfuzz比AFL稍慢(有python编写的decoder的脚本收集PT包信息并处理得到运行路径),但是可以测试出更多漏洞,并且在单位时间发现更多的边。
在无源码的二进制程序比较中,PTfuzz优于QEMU模式的AFL,QEMU需要使用虚拟化技术,性能比AFL源码插桩速度慢2到5倍,因此发现的边信息也就比PTFuzz少了。
最后说一下PTFuzz文章中说的不足,需要使用包含PT功能的Intel芯片,内核版本有限制,必须在linux使用,这些局限导致了PTFuzz不能广泛使用。
NeuFuzz
这个fuzzer看名字是深度网络训练,由两部分组成,offline的深度学习模块和正常的PTFuzz部分,在PTFuzz的种子选取部分,通过加入预测模型对种子进行排序,预测模型认为是1(vulnerable seed)的种子会优先执行,更快地发现crash。
训练模型
在模型训练方面,他选了NIST SARD项目(人工合成注入的漏洞)、Gtihub项目和Exploit-DB的项目。认为存在漏洞或者有注入漏洞的为vulnerable 程序,打过补丁或者没有注入漏洞的程序为non-vulnerable程序。一共收集了28475个vulnerable和27436个non-vulnerable。
然后通过使用POC(能触发漏洞的输入)跑上面这些程序,如果触发漏洞,程序执行路径称为vulnerable path,反之,为non-vulnerable path。同时用PT来获取执行路径。
再把获取到的执行路径转换成向量形式。NEUFuzz选择了Word2vec(这个机器学习对向量长度有一定限制,输入一大就不行了)。每条指令的地址(如0x223344)就转换成向量,路径中指令数的上限为n,不足n的用0向量补齐。在Word2vec转换后,使用LSTM(长短期记忆网络)这个深度学习网络进行学习。在后面的结果显示他的模型准确率高达92%。
online fuzz
之前提到过PT利用TNT(jnz,je这样的直接调用)、TIP(call,jmp这样的间接调用)和FUP(exception、interrupt这样的远程调用)获取hit的基本块并记录边信息。NEUFuzz则继续利用PT,在对种子重跑获取执行路径后使用预测模型判断种子是否是vulnerable。
结果
NEUFuzz使用和PTFuzz一样的实验程序——LAVA-M以及一些实际存在程序(libtiff、binutils等)。效果非常好,可能是因为有深度网络的辅助,在PTFuzz基础上更快找到crash。很明显,因为PTFuzz是coverage-oriented,这是改善了覆盖信息,NEUFuzz在此基础上还做了crash-oriented。
个人觉得他这样的实验不是很好,虽然深度学习网络的应用增加了效率,但是他只跟PTFuzz比较,在a的基础上加了优点变成b,只跟a比却不跟基础AFL、AFL的变种进行比较或者跟其他二进制程序fuzz的fuzzer比较是有失公允的。
Honggfuzz
面向安全的Honggfuzz模糊测试器是多线程的,而且经过了优化,可以利用各种系统资源。很多模糊测试工具必须运行多个实例才能达到这种效果,但Honggfuzz自动使用所有可用CPU核心加速模糊测试过程。
Honggfuzz不仅仅适用于Windows,也可以测试在Linux、Mac,甚至Android环境中运行的应用程序。由于其多平台适用的特性,Honggfuzz有一系列例子和测试用例可供开发人员使用,或一字不改直接套用,或根据自身需求加以修改,或者仅做简单参考以便设计自己的模糊测试规则。
可能是由于能在多平台执行模糊测试的能力,Honggfuzz用来展示开发人员捕获漏洞的战果页面相当庞大。开发者介绍,找出引发全球安全补丁的OpenSSL关键漏洞的模糊测试工具仅此一款。
关于honggfuzz的文章大家可以去看这篇https://bbs.pediy.com/thread-247954.htm,讲的非常到位。