2.2 教程
3 分钟阅读
译文 · 基于 Rust Fuzz Book
教程
在本教程中,我们将对 URL 解析器 rust-url 进行模糊测试。目标是找到模糊器生成的某种输入,在传给 Url::parse 时会导致 panic 或崩溃。
创建模糊测试目标
首先要创建一个模糊测试目标,形式为 Rust 二进制 crate。AFL 会调用生成的二进制文件,向标准输入提供生成的字节,我们再将其传给 Url::parse。
| |
此 crate 需要两个依赖:
url:我们要模糊测试的 crateafl:非必需,但包含一些辅助创建模糊测试目标的实用函数
将它们添加到 Cargo.toml:
| |
我们选择了已知存在 bug 的 url 特定修订版本。你的目标是找到它!
接下来在 src/main.rs 中编写模糊测试目标的源代码:
| |
fuzz! 是 afl crate 提供的实用宏,从标准输入读取字节并传给所提供的闭包。
在闭包体内,我们用 AFL 生成的字节调用 Url::parse。若一切正常,url::Url::parse 会返回包含有效 Url 的 Ok,或返回 Err 表示无法从 String 构造 Url。若 Url::parse 在解析 String 时 panic,AFL 会将其视为崩溃,AFL 界面也会相应显示。
关于 fuzz! 宏的一个重要细节:若闭包体内发生 panic,panic 会被panic::catch_unwind捕获,随后会调用 process::abort。若不调用 process::abort,AFL 不会将展开中的 panic 视为崩溃。
构建模糊测试目标
通常使用 cargo build 编译基于 Cargo 的 Rust 项目。要让 AFL 与 Rust 配合工作,构建过程中需要向 rustc 传递一些额外的编译器标志。为简化此过程,afl crate 提供了 AFL cargo 子命令,会自动为我们传递这些 rustc 标志。用法示例:
| |
我们要构建此 crate,因此运行:
| |
与 cargo fuzz 类似,cargo afl build 会向依赖图中的每个 crate 提供 --cfg fuzzing 参数,从而启用任何标注了 #[cfg(fuzzing)] 的代码路径。
提供起始输入
AFL 严格要求起始输入;若不提供至少包含一个示例输入的输入目录,它将完全无法运行。高质量的输入语料库包含许多不同的有效输入示例,可练习被模糊测试解析过程的不同特性。关于构建有效输入语料库的更多说明见 AFL README,包括对 HTML 等高度冗长数据格式的字典方法的讨论。
本教程不会生成高质量语料库,只提供足以演示基本机制的示例。为此,我们创建一个名为 in 的目录,其中包含几个含有效 URL 的文件:
| |
开始模糊测试
开始模糊测试,运行:
| |
cargo-afl 的 fuzz 子命令是使用 AFL 对 Rust 代码进行模糊测试的主要接口。熟悉 AFL 的用户而言,cargo-afl 的 fuzz 子命令与运行 afl-fuzz 相同。
-i 标志指定 AFL 用作种子的输入文件所在目录。
可使用 -e ext 标志按文件扩展名过滤输入。
-o 标志指定 AFL 写入所有状态与结果的目录。
最后一个参数 target/debug/url-fuzz-target 指定 AFL 将调用的模糊测试目标二进制文件,并向其标准输入提供随机字节。
运行此命令后,应立即看到 AFL 界面启动:

有关此界面及各部分含义的更多信息,请参阅 AFL 网站上的此资源。
AFL 会无限期运行,若要退出,请按 CTRL-C。
复现
从模糊器运行中收集到若干崩溃后,可手动将它们传入测试用例进行复现。通常通过 stdin 完成。例如,对 url-fuzz-target,命令为:
| |
其中 out 是模糊测试命令中的 -o 参数,crash_file 是 crashes 目录中的任意文件。