技术深度解析
PromptFuzz 的架构是进化计算与大语言模型推理的联姻。系统围绕四个核心组件构建:种子池(Seed Pool)、变异引擎(Mutation Engine)、驱动生成器(Driver Generator)和反馈循环(Feedback Loop)。
种子池与变异引擎: 整个过程从一小批种子提示词开始,每个提示词描述一个特定的函数签名(例如:“编写一个 C 函数,调用 `strcpy`,并传入一个用户控制的字符串”)。变异引擎应用一组受遗传编程启发的算子:
- 插入(Insertion): 向提示词中添加新的约束或上下文(例如:“……并确保源字符串长度大于目标缓冲区”)。
- 删除(Deletion): 移除安全检查或约束(例如:删除“检查空指针”)。
- 替换(Substitution): 替换函数名或数据类型(例如:将 `strcpy` 替换为 `sprintf`)。
- 交叉(Crossover): 将两个父代提示词组合生成子代(例如:将一个提示词中的缓冲区大小与另一个提示词中的格式字符串混合)。
每次变异都以概率方式应用,通过一个温度参数控制探索与利用的平衡。
驱动生成器: 变异后的提示词被送入 LLM(该项目目前支持 OpenAI 的 GPT-4 和 Anthropic 的 Claude 3.5 Sonnet)。LLM 返回一个完整的模糊测试驱动——一个 C 或 C++ 程序,包含必要的头文件、`main()` 函数以及将模糊测试输入(通常来自 AFL++ 或 libFuzzer)送入目标函数的框架代码。提示词经过精心设计,以指示 LLM 生成可编译、兼容消毒器的代码。
反馈循环: 生成的驱动使用 AddressSanitizer (ASan) 和 UndefinedBehaviorSanitizer (UBSan) 进行编译。然后,它针对来自 AFL++ 的初始种子语料库执行。反馈循环收集三个指标:
1. 覆盖率(Coverage): 新命中的基本块或边的数量。
2. 崩溃计数(Crash Count): 唯一崩溃的数量(按堆栈跟踪去重)。
3. 消毒器违规(Sanitizer Violations): 任何 ASan/UBSan 警告(例如:缓冲区溢出、释放后使用)。
这些指标被合并为一个适应度分数。产生高适应度的提示词会被加入种子池,用于下一代。系统运行可配置的代际数(通常为 50-100 代)。
GitHub 仓库: 该项目托管在 `github.com/promptfuzz/promptfuzz`。截至本文撰写时,已获得超过 2800 颗星标和 350 个分支。仓库包含预构建的 Docker 镜像、针对常见易受攻击函数(例如 `strcpy`、`sprintf`、`memcpy`、`free`)的种子提示词库,以及一个用于可视化进化过程的仪表板。
基准性能:
| 指标 | PromptFuzz (GPT-4) | PromptFuzz (Claude 3.5) | 人类专家(平均) | 传统基于语法的模糊测试器 |
|---|---|---|---|---|
| 首次崩溃时间(分钟) | 12 | 18 | 45 | 无(未发现崩溃) |
| 1 小时后代码覆盖率(边数) | 1,240 | 1,180 | 1,350 | 890 |
| 24 小时内发现的唯一崩溃数 | 7 | 5 | 9 | 0 |
| 误报率(不可利用) | 28% | 32% | 15% | 无 |
数据要点: PromptFuzz 的崩溃发现速度接近人类专家,但误报率更高。覆盖率差距正在缩小,而系统能在基于语法的模糊测试器一无所获的情况下找到崩溃,这是其最有力的卖点。
关键参与者与案例研究
PromptFuzz 项目由剑桥大学和清华大学的研究团队发起,由李伟博士(前 Google Project Zero 实习生)和 Andrew Rice 教授领导。该项目已获得微软和亚马逊云科技安全工程师的贡献。
竞争方法:
| 工具/方法 | 核心方法 | LLM 角色 | 开源? | 关键限制 |
|---|---|---|---|---|
| PromptFuzz | 提示词变异 + 进化循环 | 驱动生成器 | 是 | 高误报率 |
| FuzzGPT (微软研究院) | LLM 为 AFL++ 生成种子输入 | 输入生成器 | 否 | 需要预先存在的驱动 |
| TitanFuzz (Google) | LLM 生成模糊测试配置 | 配置生成器 | 否 | 仅限于 Chrome 特定目标 |
| CodeQL (GitHub) | 静态分析 + 查询语言 | 无 | 是 | 无动态模糊测试;遗漏运行时错误 |
案例研究:libpng
在一项受控实验中,PromptFuzz 被要求查找 libpng(一个广泛使用的 PNG 图像处理 C 库)中的漏洞。系统以一个单一提示词作为种子:“编写一个用于 `png_read_png()` 的模糊测试驱动,从 stdin 读取 PNG 文件。”经过 50 代进化后,PromptFuzz 生成了一个驱动,触发了 `png_handle_tRNS` 函数中的堆缓冲区溢出——该漏洞在代码库中存在超过 5 年,但从未被现有的模糊测试活动捕获。崩溃是由一次提示词变异引起的,该变异移除了“检查有效块长度”的约束,导致 LLM 生成了一个传递超大块的驱动。
数据要点: PromptFuzz 的能力