LibFuzzer实战复现
字数 2153 2025-08-29 08:30:19
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漏洞利用链的一部分
复现步骤
-
获取测试套件:
git clone https://github.com/google/fuzzer-test-suite -
项目结构:
build.sh:主编译脚本custom-build.sh:自定义编译选项common.sh:公共函数target.cc:目标测试代码
-
编译执行:
./build.sh编译完成后生成:
- SRC:源码目录
- BUILD:构建目录
- 可执行fuzz程序
-
运行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. 语料库使用技巧
-
提供初始种子:
./fuzz_target corpus/ -
合并优化语料库:
./fuzz_target -merge=1 tmin_corpus corpus -
保存生成语料:
./fuzz_target -artifact_prefix=./crash/ empty_corpus/
11. 字典使用
示例字典文件:
kw1="value1"
kw2="value2"
使用字典:
./fuzz_target -dict=test.dict corpus/
12. 案例:CVE-2014-0160(心脏出血漏洞)
复现步骤
-
获取代码:
git clone https://github.com/Dor1s/libfuzzer-workshop -
编译OpenSSL库:
./config enable-fuzz-afl no-shared no-asm make -
准备证书文件:
- server.key
- server.pem
-
编译target:
clang++ -g -O1 -fsanitize=address,fuzzer target.cc -I./include ./libssl.a ./libcrypto.a -o target -
运行fuzz:
./target
13. VSCode调试配置
- 安装Native Debug扩展
- 创建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"
}
]
}
- 修改target.cc添加main函数:
int main() {
const uint8_t data[] = {0x01, 0x02, 0x03}; // 替换为crash数据
LLVMFuzzerTestOneInput(data, sizeof(data));
return 0;
}
14. 关键技巧总结
- 编译时使用最新
-fsanitize=fuzzer选项 - 提供优质初始语料库可显著提高效率
- 使用字典处理特定关键字匹配
- 合并语料库优化测试用例集
- 合理设置超时和内存限制参数
- 结合ASAN快速定位内存错误
- 使用覆盖率反馈指导测试方向
通过以上方法和技巧,可以高效地使用LibFuzzer进行模糊测试,发现软件中的潜在漏洞。