内核漏洞挖掘技术系列(6)——使用AFL进行内核漏洞挖掘(1)
字数 2492 2025-08-05 08:20:12

使用AFL进行内核漏洞挖掘技术详解

1. AFL QEMU模式原理

AFL的QEMU模式是实现内核Fuzzing的基础,其核心机制包括:

1.1 基本执行流程

  • 翻译块(TB)处理
    • QEMU将被模拟架构的基本块(BB)翻译到运行架构
    • 翻译块(TB)存储在翻译块缓存(TBC)中,实现一次翻译多次使用
    • 在基本块中添加prologue和epilogue处理块间跳转和控制恢复

1.2 关键函数

  1. cpu_tb_exec

    • 负责执行TB
    • 可获取PC地址等关键信息
  2. afl_setup

    • 设置子进程中存储跟踪数据的共享内存数组
  3. afl_forkserver

    • 创建fork server并监听fd以启动克隆
  4. afl_maybe_log

    • 首次调用执行setup
    • 每次执行TB时更新共享跟踪内存
  5. tb_find/tb_gen_code

    • 查找和生成翻译块
    • 通过afl_request_tsl通知fork server翻译并保存块

1.3 关键补丁

  • syscall.patch

    • 在fork server发生SIGABRT时传递正确的pid和tgid
  • elfload.patch

    • 记录afl_entry_point、afl_start_code和afl_end_code
    • 用于afl_maybe_log中的边界检查

2. TriforceAFL实现详解

2.1 整体架构

TriforceAFL对AFL和QEMU进行修改,实现内核Fuzzing:

  1. 工作流程

    • 启动操作系统并加载Fuzzing驱动程序
    • 驱动程序控制Fuzzing生命周期:
      • 启动AFL fork server
      • 获取测试用例
      • 启用解析器跟踪
      • 解析测试用例
      • 启用内核跟踪
      • 执行系统调用
      • 通知测试完成
  2. 隔离机制

    • 每个测试用例在虚拟机的fork副本中运行
    • 仅内存状态被隔离,建议使用内存文件系统(如Linux ramdisk)

2.2 关键修改

  1. 新增aflCall指令

    • 在disas_insn函数中添加处理该指令的case
    • 支持操作:
      • startForkserver:启动AFL fork server
      • getWork:从host文件读取输入到guest缓冲区
      • startWork:指定跟踪的虚拟地址范围
      • doneWork:通知测试用例完成并传递退出代码
  2. 命令行参数处理

    • 传入getWork读取的文件名
    • 传入panic函数和log_store函数地址
  3. 代码生成修改

    • 添加gen_aflBBlock函数
    • 遇到panic函数时以exit(32)结束
    • 遇到log_store函数时记录日志
  4. 执行优化

    • 禁用QEMU的block chaining特性
    • 将AFL跟踪特性从cpu_exec移动到cpu_tb_exec
  5. 内存管理

    • patch掉ram_block_add中设置QEMU_MADV_DONTFORK的代码
    • 新增privmem.c模拟IDE磁盘并支持写时拷贝
  6. 多线程处理

    • 改进fork server在多线程环境下的行为
    • 记录CPU状态并在子进程中恢复

2.3 AFL修改

  1. 增加默认内存限制
  2. 延长等待fork server的时间
  3. 将所有非零退出状态视为崩溃
  4. 增强实用程序对fork server特性的支持

3. TriforceLinuxSyscallFuzzer实现

3.1 目录结构

  • crash_reports:发现的crash
  • docs:文档
  • rootTemplate & makeRoot:构建ramdisk镜像
  • aflCall.c:发起hypercall
  • argfd.c:创建系统调用参数使用的文件描述符
  • driver.c:主驱动程序
  • gen.py/gen2.py/gen2-shapes.txt:生成系统调用输入文件
  • getSyms:获取内核符号
  • getvmlinux:从bzImage提取vmlinux
  • heater.c:预热系统调用
  • parse.c:解析函数
  • runCmd:执行命令
  • runFuzz:启动fuzz
  • runTest & testAfl.c:复现crash
  • sysc.c:生成系统调用参数

3.2 驱动程序工作流程

  1. fork子进程执行主要工作
  2. 子进程启动AFL fork server
  3. 调用getWork获取输入数据
  4. 调用startWork跟踪驱动程序解析输入
  5. 再次调用startWork停止跟踪驱动程序并开始跟踪内核
  6. 执行已解析的系统调用
  7. 调用doneWork通知测试完成

4. KAFL架构简介

KAFL采用不同于TriforceAFL的架构:

  1. 三大组件

    • fuzz逻辑:借鉴AFL,在host上运行
    • VM组件:QEMU-PT(用户态)和KVM-QT(内核态)
    • 用户态agent
  2. 通信机制

    • guest通过hypercall与host通信
    • host可读写guest内存
  3. 关键技术

    • 实现Intel PT数据收集和解码
    • 性能优于TriforceAFL

5. 实际应用与总结

5.1 工具对比

  • TriforceAFL

    • 优点:基于成熟AFL框架,修改相对简单
    • 缺点:实际发现的漏洞较少,维护状态不佳
  • KAFL

    • 优点:性能更好,利用Intel PT技术
    • 缺点:实现复杂度高

5.2 当前建议

对于一般内核漏洞挖掘,syzkaller在各方面表现更好,包括:

  • 更活跃的维护
  • 更丰富的系统调用模型
  • 更高的漏洞发现率

6. 参考资料

  1. AFL官方文档:http://lcamtuf.coredump.cx/afl/
  2. TriforceAFL项目:https://github.com/nccgroup/TriforceAFL
  3. TriforceLinuxSyscallFuzzer项目:https://github.com/nccgroup/TriforceLinuxSyscallFuzzer
  4. KAFL项目:https://github.com/RUB-SysSec/KAFL
使用AFL进行内核漏洞挖掘技术详解 1. AFL QEMU模式原理 AFL的QEMU模式是实现内核Fuzzing的基础,其核心机制包括: 1.1 基本执行流程 翻译块(TB)处理 : QEMU将被模拟架构的基本块(BB)翻译到运行架构 翻译块(TB)存储在翻译块缓存(TBC)中,实现一次翻译多次使用 在基本块中添加prologue和epilogue处理块间跳转和控制恢复 1.2 关键函数 cpu_ tb_ exec : 负责执行TB 可获取PC地址等关键信息 afl_ setup : 设置子进程中存储跟踪数据的共享内存数组 afl_ forkserver : 创建fork server并监听fd以启动克隆 afl_ maybe_ log : 首次调用执行setup 每次执行TB时更新共享跟踪内存 tb_ find/tb_ gen_ code : 查找和生成翻译块 通过afl_ request_ tsl通知fork server翻译并保存块 1.3 关键补丁 syscall.patch : 在fork server发生SIGABRT时传递正确的pid和tgid elfload.patch : 记录afl_ entry_ point、afl_ start_ code和afl_ end_ code 用于afl_ maybe_ log中的边界检查 2. TriforceAFL实现详解 2.1 整体架构 TriforceAFL对AFL和QEMU进行修改,实现内核Fuzzing: 工作流程 : 启动操作系统并加载Fuzzing驱动程序 驱动程序控制Fuzzing生命周期: 启动AFL fork server 获取测试用例 启用解析器跟踪 解析测试用例 启用内核跟踪 执行系统调用 通知测试完成 隔离机制 : 每个测试用例在虚拟机的fork副本中运行 仅内存状态被隔离,建议使用内存文件系统(如Linux ramdisk) 2.2 关键修改 新增aflCall指令 : 在disas_ insn函数中添加处理该指令的case 支持操作: startForkserver:启动AFL fork server getWork:从host文件读取输入到guest缓冲区 startWork:指定跟踪的虚拟地址范围 doneWork:通知测试用例完成并传递退出代码 命令行参数处理 : 传入getWork读取的文件名 传入panic函数和log_ store函数地址 代码生成修改 : 添加gen_ aflBBlock函数 遇到panic函数时以exit(32)结束 遇到log_ store函数时记录日志 执行优化 : 禁用QEMU的block chaining特性 将AFL跟踪特性从cpu_ exec移动到cpu_ tb_ exec 内存管理 : patch掉ram_ block_ add中设置QEMU_ MADV_ DONTFORK的代码 新增privmem.c模拟IDE磁盘并支持写时拷贝 多线程处理 : 改进fork server在多线程环境下的行为 记录CPU状态并在子进程中恢复 2.3 AFL修改 增加默认内存限制 延长等待fork server的时间 将所有非零退出状态视为崩溃 增强实用程序对fork server特性的支持 3. TriforceLinuxSyscallFuzzer实现 3.1 目录结构 crash_ reports :发现的crash docs :文档 rootTemplate & makeRoot :构建ramdisk镜像 aflCall.c :发起hypercall argfd.c :创建系统调用参数使用的文件描述符 driver.c :主驱动程序 gen.py/gen2.py/gen2-shapes.txt :生成系统调用输入文件 getSyms :获取内核符号 getvmlinux :从bzImage提取vmlinux heater.c :预热系统调用 parse.c :解析函数 runCmd :执行命令 runFuzz :启动fuzz runTest & testAfl.c :复现crash sysc.c :生成系统调用参数 3.2 驱动程序工作流程 fork子进程执行主要工作 子进程启动AFL fork server 调用getWork获取输入数据 调用startWork跟踪驱动程序解析输入 再次调用startWork停止跟踪驱动程序并开始跟踪内核 执行已解析的系统调用 调用doneWork通知测试完成 4. KAFL架构简介 KAFL采用不同于TriforceAFL的架构: 三大组件 : fuzz逻辑:借鉴AFL,在host上运行 VM组件:QEMU-PT(用户态)和KVM-QT(内核态) 用户态agent 通信机制 : guest通过hypercall与host通信 host可读写guest内存 关键技术 : 实现Intel PT数据收集和解码 性能优于TriforceAFL 5. 实际应用与总结 5.1 工具对比 TriforceAFL : 优点:基于成熟AFL框架,修改相对简单 缺点:实际发现的漏洞较少,维护状态不佳 KAFL : 优点:性能更好,利用Intel PT技术 缺点:实现复杂度高 5.2 当前建议 对于一般内核漏洞挖掘,syzkaller在各方面表现更好,包括: 更活跃的维护 更丰富的系统调用模型 更高的漏洞发现率 6. 参考资料 AFL官方文档:http://lcamtuf.coredump.cx/afl/ TriforceAFL项目:https://github.com/nccgroup/TriforceAFL TriforceLinuxSyscallFuzzer项目:https://github.com/nccgroup/TriforceLinuxSyscallFuzzer KAFL项目:https://github.com/RUB-SysSec/KAFL