介绍一下 fuzz 的流程,从选取目标开始

1. 选取目标

Fuzzing 不是盲目的,你需要选择一个合适的、有价值的目标。好的目标通常具有以下特点:

  • 处理复杂或不受信任的输入:比如文件解析器、网络协议栈、命令行参数处理程序。这些程序是攻击者的首要目标,因为它们直接暴露在外部输入之下
  • 高权限运行:如果一个程序以 rootSYSTEM 权限运行,它将是更具吸引力的攻击目标
  • 处理多种数据格式:例如,一个视频解码器需要处理各种容器格式(MP4, AVI)、编码格式(H.264, VP9)等
  • 有公开源码或已知的开源版本:如果你有源码,可以使用更高效的源码插桩(Source-based Instrumentation)模式,如 AFL++ 或 LibFuzzer。如果没有,则需要使用二进制插桩(Binary Instrumentation)模式,如 QEMU

2. 准备工作

在开始模糊测试之前,需要做好充分的准备,这直接影响到 Fuzzing 的效率和成功率

  • 获取种子文件(Seed Corpus):种子文件是模糊测试的起点。你需要收集一批高质量的、能代表正常输入的样本文件。这些样本应该尽可能地覆盖程序的不同功能。高质量的种子文件能显著提高 Fuzzing 效率
  • 编译目标程序:如果是源码模式,你需要使用 Fuzzer 专用的编译器(例如 afl-clang-fast)来编译目标程序。这会在程序中植入探针,用于收集代码覆盖率信息
  • 创建 Fuzzing 脚本:你需要编写一个脚本,作为 Fuzzer 和目标程序之间的适配器(Harness)。这个脚本负责将 Fuzzer 生成的输入数据传递给目标程序。对于文件输入,适配器通常很简单,可能就是 read()fopen() 函数。对于更复杂的网络协议,适配器需要解析并发送数据包
  • 配置 Fuzzer:根据你的目标和环境,你需要选择并配置一个合适的 Fuzzer(例如 AFL++)。配置参数包括:
    • Fuzzing 模式(源码、QEMU、网络等)
    • Fuzzing 进程数量
    • 字典文件(如果目标程序有特定的关键字)

3. Fuzzing 运行

这个阶段是 Fuzzing 的核心,Fuzzer 将持续不断地生成、变异和测试输入

  • 启动 Fuzzer:运行 Fuzzer 进程,将种子文件作为输入,并指定输出目录
  • 监控 Fuzzing 状态:在 Fuzzing 过程中,需要持续监控其状态。好的 Fuzzer 都会提供一个状态界面,显示:
    • 测试速度(每秒执行次数)
    • 代码覆盖率
    • 发现的崩溃数量和异常(timeout)数量
    • 队列中已有的有价值的输入数量
  • 分析结果:当 Fuzzer 发现一个崩溃或异常时,它会将导致该问题的输入文件保存在一个特定的目录中。你需要定期检查这个目录,并对新发现的崩溃进行分类和分析

4. 漏洞分析与验证

这个阶段是人工分析的过程,目的是将 Fuzzer 发现的“崩溃”转化为可利用的“漏洞”

  • 漏洞重现:首先,你需要用调试器(如 GDB, WinDbg)或逆向工具(如 IDA Pro)来加载导致崩溃的输入文件,并重现崩溃。这能帮助你确定崩溃的类型和位置
  • 漏洞分类:将崩溃分为不同的类型,例如栈溢出、堆溢出、空指针解引用等。这有助于你理解漏洞的性质
  • 可利用性分析:并非所有的崩溃都是可利用的漏洞。你需要分析崩溃的原因和上下文,判断攻击者是否能通过它来劫持程序流或执行任意代码
  • 漏洞报告:一旦确认漏洞是可利用的,你需要编写一份详细的漏洞报告,包括:
    • 漏洞的描述和类型
    • 导致漏洞的输入文件
    • 崩溃发生时的堆栈信息
    • 漏洞的严重性评估

5. 修复与回归测试

这是整个流程的最后一步,也是最重要的

  • 漏洞修复:将漏洞报告交给开发者,由他们来修复代码中的缺陷
  • 回归测试:在修复完成后,你需要将导致漏洞的输入文件添加到你的测试套件中,确保未来的代码修改不会再次引入这个漏洞。这个过程也被称为回归测试
Copyright © 版权信息 all right reserved,powered by Gitbook该文件修订时间: 2025-09-25 03:13:08

results matching ""

    No results matching ""