LibFuzzer实战复现
字数 2153 2025-08-29 08:30:19

LibFuzzer实战教学文档

1. LibFuzzer概述

LibFuzzer是LLVM项目的一部分,是一个功能强大的模糊测试引擎,具有以下核心特性:

  1. 进程内(In-process):所有测试在同一个进程内存空间中进行,不启动新进程
  2. 覆盖率引导(Coverage-guided):基于代码覆盖率反馈优化测试用例
  3. 进化式(Evolutionary):结合变异和生成两种方式产生测试用例

工作原理:LibFuzzer与待测库链接,向目标函数发送测试数据,跟踪代码覆盖率,通过变异输入数据最大化覆盖率。

2. 环境配置

安装要求

  • 已集成在Clang中,安装Clang即可
  • 检查安装:clang --version

3. 实战案例:CVE-2016-5180复现

漏洞背景

Heap overflow in c-ares,是ChromeOS漏洞利用链的一部分

复现步骤

  1. 获取测试套件:

    git clone https://github.com/google/fuzzer-test-suite
    
  2. 项目结构:

    • build.sh:主编译脚本
    • custom-build.sh:自定义编译选项
    • common.sh:公共函数
    • target.cc:目标测试代码
  3. 编译执行:

    ./build.sh
    

    编译完成后生成:

    • SRC:源码目录
    • BUILD:构建目录
    • 可执行fuzz程序
  4. 运行fuzz:

    ./fuzz_target
    

4. LibFuzzer输出解析

字段 含义 示例分析
cov 代码覆盖率(基本块数) 初始14,增至29
ft 独特特征数(路径/分支等) 15增至45
corp 语料库状态(用例数/总字节) 9个用例,21字节
exec/s 每秒执行次数 0表示初期或受限
rss 内存占用 稳定31MB
L 输入长度(实际/最大) 多数4字节内
MS 变异策略组合 ChangeBit-CrossOver等

5. ASAN错误分析

典型错误类型:

  • heap-buffer-overflow:堆缓冲区溢出
  • 报错示例:0x603000032a25

6. 编译脚本详解

build.sh

主编译脚本,调用:

  • custom-build.sh:设置编译选项
  • common.sh:公共函数

重要编译选项

  • -fsanitize=fuzzer:替代旧的-fsanitize-coverage=trace-pc-guard
  • -fsanitize=address:检测堆栈溢出、UAF
  • -fsanitize=undefined:检测未定义行为
  • -fsanitize=memory:检测未初始化内存访问

7. 目标函数编写

必须实现的函数模板:

extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
  // 调用待测库函数
  return 0;
}

8. 编译选项详解

选项 作用
-g 保留调试符号
-O0/-O1/-O2/-O3 优化等级
-o file_name 指定输出文件名
-I path 添加头文件路径
-fsanitize=fuzzer 链接LibFuzzer库
-fsanitize=address 检测内存错误
-fsanitize-coverage 覆盖率统计

9. Fuzz执行参数

参数 默认值 作用
verbosity 1 输出详细日志
seed 0 随机种子
runs -1 测试次数(-1无限)
max_len 0 输入最大长度
shuffle 1 打乱初始语料库
prefer_small 1 优先小输入
timeout 1200 单次运行超时(秒)
max_total_time 0 最大运行时长
jobs 0 并行任务数
workers 0 工作线程数
detect_leaks 1 检测内存泄漏
print_coverage 0 退出打印覆盖率

10. 语料库使用技巧

  1. 提供初始种子:

    ./fuzz_target corpus/
    
  2. 合并优化语料库:

    ./fuzz_target -merge=1 tmin_corpus corpus
    
  3. 保存生成语料:

    ./fuzz_target -artifact_prefix=./crash/ empty_corpus/
    

11. 字典使用

示例字典文件:

kw1="value1"
kw2="value2"

使用字典:

./fuzz_target -dict=test.dict corpus/

12. 案例:CVE-2014-0160(心脏出血漏洞)

复现步骤

  1. 获取代码:

    git clone https://github.com/Dor1s/libfuzzer-workshop
    
  2. 编译OpenSSL库:

    ./config enable-fuzz-afl no-shared no-asm
    make
    
  3. 准备证书文件:

    • server.key
    • server.pem
  4. 编译target:

    clang++ -g -O1 -fsanitize=address,fuzzer target.cc -I./include ./libssl.a ./libcrypto.a -o target
    
  5. 运行fuzz:

    ./target
    

13. VSCode调试配置

  1. 安装Native Debug扩展
  2. 创建launch.json:
{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "(gdb) Launch",
            "type": "cppdbg",
            "request": "launch",
            "program": "${workspaceFolder}/target",
            "args": [],
            "stopAtEntry": false,
            "cwd": "${workspaceFolder}",
            "environment": [],
            "externalConsole": false,
            "MIMode": "gdb"
        }
    ]
}
  1. 修改target.cc添加main函数:
int main() {
    const uint8_t data[] = {0x01, 0x02, 0x03}; // 替换为crash数据
    LLVMFuzzerTestOneInput(data, sizeof(data));
    return 0;
}

14. 关键技巧总结

  1. 编译时使用最新-fsanitize=fuzzer选项
  2. 提供优质初始语料库可显著提高效率
  3. 使用字典处理特定关键字匹配
  4. 合并语料库优化测试用例集
  5. 合理设置超时和内存限制参数
  6. 结合ASAN快速定位内存错误
  7. 使用覆盖率反馈指导测试方向

通过以上方法和技巧,可以高效地使用LibFuzzer进行模糊测试,发现软件中的潜在漏洞。

LibFuzzer实战教学文档 1. LibFuzzer概述 LibFuzzer是LLVM项目的一部分,是一个功能强大的模糊测试引擎,具有以下核心特性: 进程内(In-process) :所有测试在同一个进程内存空间中进行,不启动新进程 覆盖率引导(Coverage-guided) :基于代码覆盖率反馈优化测试用例 进化式(Evolutionary) :结合变异和生成两种方式产生测试用例 工作原理:LibFuzzer与待测库链接,向目标函数发送测试数据,跟踪代码覆盖率,通过变异输入数据最大化覆盖率。 2. 环境配置 安装要求 已集成在Clang中,安装Clang即可 检查安装: clang --version 3. 实战案例:CVE-2016-5180复现 漏洞背景 Heap overflow in c-ares,是ChromeOS漏洞利用链的一部分 复现步骤 获取测试套件: 项目结构: build.sh :主编译脚本 custom-build.sh :自定义编译选项 common.sh :公共函数 target.cc :目标测试代码 编译执行: 编译完成后生成: SRC:源码目录 BUILD:构建目录 可执行fuzz程序 运行fuzz: 4. LibFuzzer输出解析 | 字段 | 含义 | 示例分析 | |------|------|----------| | cov | 代码覆盖率(基本块数) | 初始14,增至29 | | ft | 独特特征数(路径/分支等) | 15增至45 | | corp | 语料库状态(用例数/总字节) | 9个用例,21字节 | | exec/s | 每秒执行次数 | 0表示初期或受限 | | rss | 内存占用 | 稳定31MB | | L | 输入长度(实际/最大) | 多数4字节内 | | MS | 变异策略组合 | ChangeBit-CrossOver等 | 5. ASAN错误分析 典型错误类型: heap-buffer-overflow :堆缓冲区溢出 报错示例: 0x603000032a25 6. 编译脚本详解 build.sh 主编译脚本,调用: custom-build.sh :设置编译选项 common.sh :公共函数 重要编译选项 -fsanitize=fuzzer :替代旧的 -fsanitize-coverage=trace-pc-guard -fsanitize=address :检测堆栈溢出、UAF -fsanitize=undefined :检测未定义行为 -fsanitize=memory :检测未初始化内存访问 7. 目标函数编写 必须实现的函数模板: 8. 编译选项详解 | 选项 | 作用 | |------|------| | -g | 保留调试符号 | | -O0/-O1/-O2/-O3 | 优化等级 | | -o file_ name | 指定输出文件名 | | -I path | 添加头文件路径 | | -fsanitize=fuzzer | 链接LibFuzzer库 | | -fsanitize=address | 检测内存错误 | | -fsanitize-coverage | 覆盖率统计 | 9. Fuzz执行参数 | 参数 | 默认值 | 作用 | |------|--------|------| | verbosity | 1 | 输出详细日志 | | seed | 0 | 随机种子 | | runs | -1 | 测试次数(-1无限) | | max_ len | 0 | 输入最大长度 | | shuffle | 1 | 打乱初始语料库 | | prefer_ small | 1 | 优先小输入 | | timeout | 1200 | 单次运行超时(秒) | | max_ total_ time | 0 | 最大运行时长 | | jobs | 0 | 并行任务数 | | workers | 0 | 工作线程数 | | detect_ leaks | 1 | 检测内存泄漏 | | print_ coverage | 0 | 退出打印覆盖率 | 10. 语料库使用技巧 提供初始种子: 合并优化语料库: 保存生成语料: 11. 字典使用 示例字典文件: 使用字典: 12. 案例:CVE-2014-0160(心脏出血漏洞) 复现步骤 获取代码: 编译OpenSSL库: 准备证书文件: server.key server.pem 编译target: 运行fuzz: 13. VSCode调试配置 安装Native Debug扩展 创建launch.json: 修改target.cc添加main函数: 14. 关键技巧总结 编译时使用最新 -fsanitize=fuzzer 选项 提供优质初始语料库可显著提高效率 使用字典处理特定关键字匹配 合并语料库优化测试用例集 合理设置超时和内存限制参数 结合ASAN快速定位内存错误 使用覆盖率反馈指导测试方向 通过以上方法和技巧,可以高效地使用LibFuzzer进行模糊测试,发现软件中的潜在漏洞。