请注意,本文编写于 647 天前,最后修改于 647 天前,其中某些信息可能已经过时。
目录
模糊测试技术综述
Fuzz发展历史
模糊测试的流程
预处理
分析技术与获取的信息
模糊测试在预处理阶段的类型分类
实际测试环节
输入构造
输入选择
评估
略
😃
模糊测试技术综述
Fuzz发展历史
- 1988年 诞生了一款软件
Fuzz
以生成随机的字符串对以字符串为输入对象的程序进行测试 主要目的是以非常规数据测试其鲁棒性 [黑盒]
- 2001年
Protos
首次将模糊测试应用到网络协议 模糊测试成为实用性工具的开始 [黑盒]
- 2004年
Peach
由用户定义输入数据的数据模型 是基于语法生成输入思想的早期应用 [黑盒]
- 2007年
Sage
基于符号执行 在执行过程中收集条件语句 通过约束求解器进行求解生成新的输入 [白盒]
- 2008年
jsfunfuzz
根据语言模型生成随机但语法正确的输入 这种基于语法生成输入的思想 成为以后针对高度结构化的测试目标的重要指导思想 [白盒]
- 自此 因为受到符号执行资源开销过大的限制 Fuzz分为两个优化路线
- 继续改进白盒模糊测试
- 2009年
Vganesh
使用污点测试技术替代了符号执行技术 将执行过程中的变量值与输入部分做关联进而知道模糊测试的变异策略 这种思想也被用于灰盒测试中 [白盒]
- 利用少量内部信息进行模糊测试
- 2013年
AFL
以覆盖率为导向的模糊测试软件 通过插桩的方式采集输入数据对应的边覆盖率 作为模糊测试种子选取的衡量标准 [灰盒]
模糊测试的流程
- 预处理: 搜集目标相关信息并且指定模糊测试的策略 为监控目标在测试中的运行状态做准备
- 输入构造: 获取一定量的种子 随后确定种子的能量分配策略 种子的优先级 种子的突变策略 最后根据这些信息获取大量输入数据
- 输入选择: 尝试通过提前筛选不合格输入数据 以节省模糊测试的时间
- 评估: 设计合适的实验 依照评估指标对模糊测试进行评估
- 结果分析: 对结果进行去重 复现 分析 威胁性评估
预处理
- 预处理环节的目标是搜集目标相关的信息 比如目标的输入数据格式 目标的内部结构 并且为监控测试中目标的状态变化做必要的准备
- 主要挑战是: 1. 使用什么程序分析技术 2. 模糊测试究竟需要对目标内部信息有多详细的了解
分析技术与获取的信息
- 插桩: 通过向目标的代码中合适的位置添加预设好的代码 以获取程序的抽象语法树 覆盖率 函数内变量取值等信息
- 静态插桩: 在源码或者中间代码的编译过程中进行插桩 常见的如通过GCC编译器在汇编语言上插桩 或者在LLVM的中间语言LLVM_IR上插桩
- 动态插桩: 运行过程中对运行过的代码进行插桩 如利用QEMU等模拟技术进行动态插桩 可以获得程序运行时的信息
- 符号执行: 将程序行为的推理归结为逻辑领域的推理 通过构建一个表示程序执行的逻辑公式 可以同时推断一个程序在不同输入上的行为 该方法可以使Fuzz获得更高的覆盖率
- 静态符号执行: 通常会因为程序的循环 条件跳转陷入路径爆炸 或者存在约束求解失败的问题 所以基本废弃
- 动态符号执行: 通过对程序的实际执行和符号化执行 维护程序的实际状态和符号状态 通过难以求解的约束替换为实际值 缓解静态符号执行的问题 并且按照深度优先的搜索策略对目标程序进行探索
- 由于程序分支的存在 动态符号执行路径爆炸问题依然存在 解决方法是可以采取一种启发式的方法 选择比较重要的路径进行探索
- 采取了实际值替换的方法 可以解决一部分静态符号执行无法求解的约束 但是会丢失一部分路径
- 受限于约束求解方法的能力
- 污点分析: 观测程序中哪些程序数据受到了预先准备好的污染源(通常为输入)的污染 目的是跟踪污染源和汇聚点之间的程序流
- 静态污点分析: 通过对程序的静态分析获取程序控制流图 抽象语法树等信息 依照数据流和依赖关系进行污点分析
- 缺点: 可能会陷入路径爆炸 而简化之后会存在严重的过度污染情况
- 动态污点分析: 在程序的实际执行过程中 利用程序的动态执行信息进行污点分析
- 优点: 可信度更高
- 缺点: 检测结果是否全面取决于动态污点分析对程序的覆盖情况 消耗更多的资源
模糊测试在预处理阶段的类型分类
- 黑盒模糊测试: 数据驱动的测试 只能获得诸如目标输入格式等内部无关的信息 只能通过检测目标的数据数据对目标的状态进行判断
- 优点: 可以针对不开源的目标 黑盒测试工具设计简单 开发和检测速度快
- 缺点: 由于不了解目标内部信息 会生成大量无效输入 导致测试的覆盖率偏移 且检测深层漏洞能力有限
- 灰盒模糊测试: 只获取部分的内部信息用于模糊测试
- 白盒模糊测试: 可以获得充足的内部信息 通常采用符号执行的方法 近些年通常研究尝试加速符号执行的速度 或者将符号执行和模糊测试分为两个阶段
- 优点: 可以生成高质量输入数据 在覆盖率和深层漏洞监测上有更高的表现
- 缺点: 可能会陷入路径爆炸 对程序的细致全面分析会消耗大量资源 严重影响模糊测试的效率
实际测试环节
输入构造
- 一般来说 输入构造环节是为了构造出大量可以被检测目标执行 用于模糊测试的输入数据
- 挑战在于 如何在满足语法语义检查的情况下快速生成大量输入
针对存在的问题 普遍做法是 首先得到一个数据S 然后S按照一定的策略进行一定次数的变异 获得大量新数据I 最后将I输入到测试对象中进行测试 其中S被称为种子
这样做的好处是可以通过精心构造的种子快速变异出大量高质量的输入数据 其中种子需要经过种子获取
种子筛选
种子突变
三个截断才能获得高质量输入数据
-
种子获取: 可以是准备好的高质量数据集 也可以是通过模型生成得到 或者是按照一定的策略从执行过的数据中进行选择
-
种子筛选: 获得备选种子之后针对种子池中的备用中医进行筛选划分不同权重 以确定每个种子用来生成多少输出
- 种子的能量分配: 一个种子所蕴含的能量代表着该种子可以生成输入的多少 能量越高获得的输入也就越多 不同的能量分配厕所不仅可以提高模糊测试的执行速度 还可以引导模糊测试到指定位置进行检测
- 种子的优先级: 种子的优先级决定了模糊测试到种子池中选择种子的顺序 通常来说种子的长度是影响种子优先级的一个重要因素 在对覆盖率贡献相同的情况下 越短的输入数据优先级就应该越高 因为较短的输入数据占用内存少 会加快模糊测试的速度
-
种子突变: 种子需要在突变策略的引导下快速的生成大量输入数据 变异的策略直接决定了变异生成数据的好坏 按照突变策略的不同分为黑盒突变和导向型突变
- 比特翻转: 按照比特位进行一定步长或连续翻转几个比特位
- 简单算术运算: AFL常用的变异算法 按照8b的步长 依次按照8b 16b 32b的宽度 从头开始做加减操作
- 覆盖: 使用一些预设的值覆盖种子的某些部分
- 插入: 使用一些预设的值插入到种子的某些部分中
- 删除: 删除种子的某一部分
- 拼接: 将差异较大的两个种子进行拼接
- 黑盒突变: 不依赖目标的相关信息 依照随机突变策略对种子进行突变 常作为整体突变策略的一部分出现
- 导向型突变: 通过程序分析技术 得到种子与程序状态的关系 依此制定突变策略 针对感兴趣的程序状态生成响应的测试数据 使突变后的输入尽可能的将程序引导向预期的程序状态 或者获得相应的性能提升 具体来说导向型突变分为程序状态导向性突变和性能导向型突变
- 程序状态导向型突变: 通过程序分析技术 得到种子与程序状态的关系 依此制定突变策略 针对感兴趣的程序状态生成响应的测试数据
- 性能导向突变: 不会试图分析属于与程序内部状态的关系 而是根据输入数据同模糊测试评估指标的关系指定突变的策略
输入选择
主要目的是在输入被实际执行之前尽量将其中的无效数据滤除掉 以节省执行时间 采取机器学习的方式是个不错的选择
评估
主要目的是选取一个合适的评估指标 用于评估模糊测试执行结果 从而帮助模糊测试指定合理的策略并反映模糊测试检测漏洞的真实能力
现阶段主要聚焦在模糊测试的两个指标上的表现: 覆盖率
暴露漏洞平均时间
- 覆盖率: 指的是在测试过程中 对象被覆盖到的数目占总数的比例 通常来说 高覆盖率更可能发现更多的隐藏漏洞
- 基于上下文无关的边覆盖率
- 上下文敏感的分支覆盖率
- 块覆盖率
- 暴露漏洞平均时间: 更接近模糊的本质
略
本文作者:Du4t
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA
许可协议。转载请注明出处!