模糊测试一
笔者今天下午进行了一场二进制研究相关面试,但面试后发现笔者在fuzz方面的原理和概念上并不熟练,并且在深度上严重不足,于是总结归纳,希望系统性的学习以下模糊测试,并决定专开一栏,进行相关的系统深入学习。
了解模糊测试
模糊测试概念
通过自动化生成并执行大量测试用例来返现目标的未知漏洞
模糊测试原理模型
生成随机字符串
生成随机字符串是一个比较简陋的方法,可能效果并不好,尤其是协议部分,可能在协议部分就出现问题
基于模板生成
这里我们以HTTP协议为例,以下是一个HTTP协议的例子
1 | http 1.0 |
其中我们知道,类似于http这一类的信息是不变的,而像1.0、GET类似的信息是可变的,而下方Host中的操作是资源字符部分。基于以上我们的分析,我们可以生成一个模板,然后根据模板来进行字符串的生成,只有通过这一模板生成的字符串才是有意义的。
基于覆盖式的生成(覆盖制导)
我们假设有以下的代码
1 | if (data[0] > 0){ |
覆盖引导后就会将代码的流程生成出来程序的流程图,这个流程我们将其称为 代码路径
实现原理
那么这样的功能是怎么实现出来的呢?这里就有一定插桩相关的原理,我们再回到上面的代码来看,我们可以在程序中插入log1,log2,示例如下
1 | log(__main_start) |
此后程序可以对生成的log文件进行跟踪,通过生成的log来分析运行的路径来确定程序的运行流程,从而生成流程图。
为什么要实现覆盖引导
因为每次进行代码路径分析的时候,我们会检测到新的代码路径,而不断的扫描新路径则会不断提高代码的覆盖率,并说明这段代码是有意义的,那么接下来需要将代码放入后续的生成中,基于这个数据上进一步变异生成,然后不断重复这一个过程。
特殊条件的fuzz
图形化FUZZ
很多时候的程序并不像我们我们上述所给出的程序一样,一定存在输入和输出的流,那么此时我们要怎么进行fuzz呢?我们知道,大多数的UI实现都是会对UI和func存在绑定的,那么我们的第一部程序拆解,最终拆解成我们可以进行调用的某一个函数,那么这样后我们就可以和常规的fuzz一致了。
持久化程序fuzz
我们标准的fuzz的理想情况是程序是运行后给出结果立刻结束,第二次测试则进行一个新的运行。但是很多程序并不会这样,譬如webserver,它会一直停留运行,那么我们需要有以下的方法
- idapatch将程序修改程序逻辑为只处理1次
- 修改fuzz逻辑
- 自己实现fuzz
- 持续性fuzz
经典模糊测试工具
- AFL
- libafl (iot常用,rust静态连接低依赖,有点像乐高,可以自己拼接功能)
- winafl(window版)
- syzkaller(同原理,进程fuzz)
- libfuzzer(可以针对程序的某个函数)
- fuzzilli(CS引擎fuzz)