怎么给 AFL 做适配去 fuzz 数据库
适配器的核心任务
这个适配器是一个程序,它将从 AFL 获取的文件输入转换成数据库能够理解的网络协议请求,然后发送给数据库
它的主要工作流程是:
- 从标准输入(
stdin
)或文件中读取 AFL 提供的模糊数据 - 将这些数据解析成数据库协议的数据包或 SQL 查询语句
- 通过网络连接发送给数据库
- 监控数据库的响应,寻找崩溃或异常
两种常见的适配方案
这里有两种常用的方案,它们各有优缺点。
方案一:基于文件和本地连接的适配
这是最简单的方案,适用于那些支持从文件加载数据的数据库
实现步骤:
- 编写适配器(
harness.c
):- 适配器会创建一个本地的数据库连接
- 它从 AFL 的输入文件中读取数据,这些数据通常是SQL 语句或数据库协议数据
- 适配器将读取到的内容作为 SQL 查询或协议数据发送给数据库
- AFL 的运行方式:
- 你需要用 AFL 的编译器(
afl-clang-fast
)编译这个适配器 - AFL 启动后,它会变异种子文件中的 SQL 语句或协议数据
- AFL 会不断地运行你的适配器,将变异后的数据通过
stdin
或文件喂给它 - 适配器在每次运行时,都会建立一个新的数据库连接,发送数据,然后退出
- 你需要用 AFL 的编译器(
优点:
- 相对简单:易于实现,特别是当数据库有命令行客户端时
- 高效率:避免了网络延迟,测试速度相对较快
缺点:
- 不完整:只能测试数据库的查询解析部分,无法测试完整的网络协议栈
- 状态问题:难以处理需要管理状态的查询序列。
方案二:基于网络和协议模拟的适配
这是更复杂但更全面的方案,它能够真正地对数据库的网络协议层进行模糊测试
实现步骤:
- 使用 QEMU 模式:
- 直接使用
afl-fuzz -Q
模式来对数据库服务器程序进行模糊测试 - 编写一个自定义的网络协议客户端作为适配器,它会向服务器发送数据,而不是从文件读取
- 直接使用
- 创建“伪文件”:
- 你需要一个外部程序(比如一个 Python 脚本)来生成包含数据库协议请求的“伪文件”
- 这个脚本会根据 AFL 提供的原始模糊数据,将其封装成完整的数据库协议数据包
- AFL 会模糊这个“伪文件”
- 连接和发送:
- 你的适配器会监听一个端口,当 AFL 的 QEMU 模式运行数据库服务器时,你的适配器会与其建立连接,并将模糊数据发送过去
- 关键在于同步:你需要确保 AFL 的输入文件和你的适配器发送的数据包是一致的
优点:
- 全面:能够测试数据库的整个网络协议栈,包括身份验证、连接管理等
- 真实:更接近实际的攻击场景
缺点:
- 性能开销大:QEMU 模式本身就很慢,再加上网络延迟,模糊测试速度会非常低
- 复杂:需要深入理解数据库的协议,并且需要处理网络连接、多进程/多线程等问题