关于 fuzzing-dictionary
fuzzing-dictionary 是一项指导模糊测试的技术技能,介绍如何为解析器、协议处理程序和文件格式处理器准备特定词典。内容涵盖词典格式、生成方法及与多种模糊测试器的用法。
主要功能
- 01关键字与魔数词条
- 02文本及十六进制转义格式
- 03从头文件和二进制提取词条
- 04libFuzzer、AFL++ 和 cargo-fuzz 用法
- 05词典优化与效果排查
适用场景
- 01探索 JSON、XML 和配置解析器
- 02测试 HTTP、DNS 等协议实现
- 03触达 PNG、PDF 等文件格式处理逻辑
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ trailofbits/ skills --skill fuzzing-dictionary安装后在 Claude Code 中输入/fuzzing-dictionary确认已加载。
附带文件agents/openai.yamlassets/trail-of-bits-mark.svg
详细介绍
模糊测试词典
模糊测试词典提供特定领域的词元,引导模糊测试器生成有趣的输入。模糊测试器不再只进行随机变异,而是利用已知关键词、魔数、协议命令和特定格式的字符串,这些内容更有可能让解析器、协议处理程序和文件格式处理器进入更深层的代码路径。
概述
词典是包含带引号字符串的文本文件,这些字符串代表目标程序有意义的词元。它们有助于模糊测试器绕过早期的验证检查,并探索仅靠盲目变异难以触及的代码路径。
核心概念
| 概念 | 描述 |
|---|---|
| 词典条目 | 带引号的字符串(例如 "keyword")或键值对(例如 kw="value") |
| 十六进制转义 | 用于表示不可打印字符的字节序列,例如 "\xF7\xF8" |
| 词元注入 | 模糊测试器将词典条目插入生成的输入中 |
| 跨模糊测试器格式 | 词典文件适用于 libFuzzer、AFL++ 和 cargo-fuzz |
适用场景
适合使用此技术的场景:
- 对解析器进行模糊测试(JSON、XML、配置文件)
- 对协议实现进行模糊测试(HTTP、DNS、自定义协议)
- 对文件格式处理程序进行模糊测试(PNG、PDF、媒体编解码器)
- 覆盖率很早就停滞,无法进入更深层的逻辑
- 目标代码会检查特定关键词或魔数
不适合使用此技术的场景:
- 对没有格式预期的纯算法进行模糊测试
- 目标程序不使用基于关键词的解析
- 语料库已经达到较高覆盖率
快速参考
| 任务 | 命令/模式 |
|---|---|
| 与 libFuzzer 一起使用 | ./fuzz -dict=./dictionary.dict ... |
| 与 AFL++ 一起使用 | afl-fuzz -x ./dictionary.dict ... |
| 与 cargo-fuzz 一起使用 | cargo fuzz run fuzz_target -- -dict=./dictionary.dict |
| 从头文件提取 | grep -o '".*"' header.h > header.dict |
| 从二进制文件生成 | strings ./binary | sed 's/^/"&/; s/$/&"/' > strings.dict |
分步指南
步骤 1:创建词典文件
创建一个文本文件,每行包含一个带引号的字符串。使用注释(#)添加说明。
词典格式示例:
# Lines starting with '#' and empty lines are ignored.
# Adds "blah" (w/o quotes) to the dictionary.
kw1="blah"
# Use \\ for backslash and \" for quotes.
kw2="\"ac\\dc\""
# Use \xAB for hex values
kw3="\xF7\xF8"
# the name of the keyword followed by '=' may be omitted:
"foo\x0Abar"
步骤 2:生成词典内容
根据可用资源选择生成方式:
**使用 LLM:**向 ChatGPT 或 Claude 提示:
A dictionary can be used to guide the fuzzer. Write me a dictionary file for fuzzing a <PNG parser>. Each line should be a quoted string or key-value pair like kw="value". Include magic bytes, chunk types, and common header values. Use hex escapes like "\xF7\xF8" for binary values.
从头文件生成:
grep -o '".*"' header.h > header.dict
从 man 页面生成(适用于 CLI 工具):
man curl | grep -oP '^\s*(--|-)\K\S+' | sed 's/[,.]$//' | sed 's/^/"&/; s/$/&"/' | sort -u > man.dict
从二进制字符串生成:
strings ./binary | sed 's/^/"&/; s/$/&"/' > strings.dict
步骤 3:将词典传递给模糊测试器
使用适用于你的模糊测试器的标志(参见上面的“快速参考”)。
常见模式
模式:协议关键词
**适用场景:**对 HTTP 或自定义协议处理程序进行模糊测试
词典内容:
# HTTP methods
"GET"
"POST"
"PUT"
"DELETE"
"HEAD"
# Headers
"Content-Type"
"Authorization"
"Host"
# Protocol markers
"HTTP/1.1"
"HTTP/2.0"
模式:魔数字节和文件格式头
**适用场景:**对图像解析器、媒体解码器、归档处理程序进行模糊测试
词典内容:
# PNG magic bytes and chunks
png_magic="\x89PNG\r\n\x1a\n"
ihdr="IHDR"
plte="PLTE"
idat="IDAT"
iend="IEND"
# JPEG markers
jpeg_soi="\xFF\xD8"
jpeg_eoi="\xFF\xD9"
模式:配置文件关键词
**适用场景:**对配置文件解析器进行模糊测试(YAML、TOML、INI)
词典内容:
# Common config keywords
"true"
"false"
"null"
"version"
"enabled"
"disabled"
# Section headers
"[general]"
"[network]"
"[security]"
高级用法
技巧与窍门
| 技巧 | 帮助原因 |
|---|---|
| 组合多种生成方法 | 使用 LLM 生成的关键词和从二进制文件提取的字符串,可覆盖更广的范围 |
| 包含边界值 | "0"、"-1"、"2147483647" 可触发边界情况 |
| 添加格式分隔符 | :、=、{、} 有助于模糊测试器构造有效结构 |
| 让词典保持精简、聚焦 | 包含 50-200 个条目的词典比包含数千个条目的词典效果更好 |
| 测试词典的有效性 | 分别在有词典和无词典的情况下运行,并比较覆盖率 |
自动生成词典(AFL++)
使用 afl-clang-lto 编译器时,AFL++ 会自动从二进制文件中的字符串比较中提取词典条目。这是通过 AUTODICTIONARY 功能在编译时完成的。
启用自动词典:
export AFL_LLVM_DICT2FILE=auto.dict
afl-clang-lto++ target.cc -o target
# Dictionary saved to auto.dict
afl-fuzz -x auto.dict -i in -o out -- ./target
合并多个词典
某些模糊测试器支持多个词典文件:
# AFL++ with multiple dictionaries
afl-fuzz -x keywords.dict -x formats.dict -i in -o out -- ./target
反模式
| 反模式 | 问题 | 正确做法 |
|---|---|---|
| 包含完整句子 | Fuzzer 需要的是原子标记,而不是文章 | 拆分为单个关键词 |
| 重复条目 | 浪费变异预算 | 使用 sort -u 去重 |
| 字典过大 | 会拖慢 Fuzzer,并稀释有用标记 | 保持精简:仅保留 50-200 个最相关的条目 |
| 缺少十六进制转义 | 不可打印字节会被破坏 | 对二进制值使用 \xXX |
| 没有注释 | 难以维护和审查 | 使用 # 注释说明各部分 |
特定工具指南
libFuzzer
clang++ -fsanitize=fuzzer,address harness.cc -o fuzz
./fuzz -dict=./dictionary.dict corpus/
集成技巧:
- 字典标记会在变异过程中插入或替换
- 配合
-max_len使用,以控制输入大小 - 使用
-print_final_stats=1查看字典效果指标 - 长于
-max_len的字典条目会被忽略
AFL++
afl-fuzz -x ./dictionary.dict -i input/ -o output/ -- ./target @@
集成技巧:
- AFL++ 支持多个
-x标志,用于指定多个字典 - 使用
afl-clang-lto时,可通过AFL_LLVM_DICT2FILE自动生成字典 - 字典效果会显示在 Fuzzer 统计信息界面中
- 标记会在确定性阶段和 havoc 阶段使用
cargo-fuzz(Rust)
cargo fuzz run fuzz_target -- -dict=./dictionary.dict
集成技巧:
- cargo-fuzz 使用 libFuzzer 后端,因此所有 libFuzzer 字典标志均可用
- 将字典文件放在
fuzz/目录中,与 harness 放在一起 - 从 harness 目录引用:
cargo fuzz run target -- -dict=../dictionary.dict
go-fuzz(Go)
go-fuzz 不支持内置字典,但你可以手动使用字典条目填充语料库:
# Convert dictionary to corpus files
grep -o '".*"' dict.txt | while read line; do
echo -n "$line" | base64 > corpus/$(echo "$line" | md5sum | cut -d' ' -f1)
done
go-fuzz -bin=./target-fuzz.zip -workdir=.
故障排除
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 未加载字典文件 | 路径错误或格式错误 | 检查 Fuzzer 输出中是否有字典解析错误;验证文件格式 |
| 覆盖率没有提升 | 字典标记不相关 | 分析目标代码,找出实际使用的关键词;尝试不同的生成方法 |
| 字典文件中有语法错误 | 引号未转义或转义序列无效 | 反斜杠使用 \\,引号使用 \";通过测试运行进行验证 |
| Fuzzer 忽略较长条目 | 条目超过 -max_len | 将条目控制在最大输入长度以内,或增大 -max_len |
| 条目过多导致 Fuzzer 变慢 | 字典过大 | 精简至 50-200 个最相关的条目 |
相关技能
使用此技术的工具
| 技能 | 应用方式 |
|---|---|
| libfuzzer | 通过 -dict= 标志提供原生字典支持 |
| aflpp | 通过 -x 标志提供原生字典支持;使用 AUTODICTIONARIES 自动生成 |
| cargo-fuzz | 使用 libFuzzer 后端,继承 -dict= 支持 |
相关技术
| 技能 | 关联 |
|---|---|
| fuzzing-corpus | 字典与语料库互为补充:语料库提供结构,字典提供关键词 |
| coverage-analysis | 使用覆盖率数据验证字典效果 |
| harness-writing | harness 结构决定哪些字典标记有用 |
资源
主要外部资源
AFL++ Dictionaries 针对常见格式(HTML、XML、JSON、SQL 等)的预置字典,是进行特定格式模糊测试的良好起点。
libFuzzer Dictionary Documentation libFuzzer 关于字典格式和用法的官方文档,介绍标记插入策略及其对性能的影响。
更多示例
OSS-Fuzz Dictionaries
来自 Google 持续模糊测试服务的真实字典示例。搜索项目目录中的 *.dict 文件,查看生产环境中的示例。