はじめに
Rustでafl (rust-fuzz/afl.rs)を使ったファジングを試してみます。
テスト対象はwoothee-rustを使って説明します。
前提条件
項目 | 説明 |
---|---|
検証日 | 2017.03.10 |
OS | Arch Linux (on Vagrant) |
Rust | rustc 1.11.0-nightly (01411937f 2016-07-01) |
afl | 0.1.5 |
rustcのバージョンはDockerに内包されているバージョンです。
事前準備
まずはdocker pull
でビルド&テスト環境を準備します。
$ docker pull corey/afl.rs
テスト対象のwoothee-rustをクローンしてきます。
$ git clone https://github.com/hhatto/woothee-rust.git
$ cd woothee-rust
テスト用の初期インプットデータを用意します。aflはこのデータを元に自動生成した入力値を使ってテストを行います。
テスト結果を格納するディレクトリも合わせて準備しておきます。
$ mkdir in
$ echo "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0)" > in/basic
$ mkdir out
aflを使えるようにsrc/lib.rs
にプラグイン設定を追加します。
$ git diff src/lib.rs
diff --git a/src/lib.rs b/src/lib.rs
index fcf80c3..01967a4 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,3 +1,5 @@
+#![feature(plugin)]
+#![plugin(afl_plugin)]
#![cfg_attr(feature="clippy", feature(plugin))]
#![cfg_attr(feature="clippy", plugin(clippy))]
以下のようなテスト本体のsrc/main.rs
を準備します。
# ![feature(plugin)]
# ![plugin(afl_plugin)]
extern crate afl;
extern crate woothee;
use woothee::parser::Parser;
fn main() {
afl::handle_string(|s| {
let p = Parser::new();
let _ = p.parse(s.as_str());
})
}
Docker起動とビルド
以降、#
はDockerのセッションです。
$ docker run -v $(pwd):/source -it corey/afl.rs sh
# afl-fuzz --version
afl-fuzz 2.34b by <lcamtuf@google.com>
:
# ls
Cargo.lock Cargo.toml LICENSE README.md benches build.rs in out rustfmt.toml src target templates tests
# rustc --version
rustc 1.11.0-nightly (01411937f 2016-07-01)
# cargo build
Updating registry `https://github.com/rust-lang/crates.io-index`
Downloading regex v0.2.1
Downloading lazy_static v0.2.4
Downloading afl-plugin v0.1.5
Downloading afl v0.1.5
Downloading utf8-ranges v1.0.0
Downloading regex-syntax v0.4.0
Downloading memchr v1.0.1
Downloading aho-corasick v0.6.2
Downloading thread_local v0.3.3
Downloading libc v0.2.21
Downloading unreachable v0.1.1
Downloading void v1.0.2
Downloading gcc v0.3.43
Downloading quale v1.0.0
Downloading afl-sys v0.1.5
Downloading thread-id v3.0.0
Compiling woothee v0.6.0 (file:///source)
afl-llvm-pass by <lszekeres@google.com>
Instrumented 5527 locations (non-hardened mode, ratio 100%).
afl-llvm-pass by <lszekeres@google.com>
Instrumented 429 locations (non-hardened mode, ratio 100%).
# file target/release/woothee
target/release/woothee: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=7823c4b40102920f31d08a2636cab6400e000d62, not stripped
#
テスト実行
afl-fuzz
を使ってテストを実行してみます。
実行イメージ
afl-fuzz 2.34b by <lcamtuf@google.com>
[+] You have 4 CPU cores and 3 runnable tasks (utilization: 75%).
[+] Try parallel jobs - see /usr/local/share/doc/afl/parallel_fuzzing.txt.
[*] Checking CPU core loadout...
[+] Found a free CPU core, binding to #0.
[*] Checking core_pattern...
[*] Setting up output directories...
[+] Output directory exists but deemed OK to reuse.
[*] Deleting old session data...
[+] Output dir cleanup successful.
[*] Scanning 'in'...
[+] No auto-generated dictionary tokens to reuse.
[*] Creating hard links for all input files...
[*] Validating target binary...
[*] Attempting dry run with 'id:000000,orig:basic'...
[*] Spinning up the fork server...
[+] All right - fork server is up.
len = 64, map size = 2078, exec speed = 6858 us
[!] WARNING: Instrumentation output varies across runs.
[+] All test cases processed.
[+] Here are some useful stats:
Test case count : 1 favored, 1 variable, 1 total
Bitmap range : 2078 to 2078 bits (average: 2078.00 bits)
Exec timing : 6858 to 6858 us (average: 6858 us)
[*] No -t option specified, so I'll use exec timeout of 40 ms.
[+] All set and ready to roll!
上記のような出力のあとに、冒頭のような画面になればテスト実行ができたことになります。
はまったところなど
afl-fuzz
が実行できない
# afl-fuzz -i in -o out target/release/woothee
afl-fuzz 2.39b by <lcamtuf@google.com>
[+] You have 2 CPU cores and 2 runnable tasks (utilization: 100%).
[*] Checking CPU core loadout...
[+] Found a free CPU core, binding to #0.
[*] Checking core_pattern...
[-] Hmm, your system is configured to send core dump notifications to an
external utility. This will cause issues: there will be an extended delay
between stumbling upon a crash and having this information relayed to the
fuzzer via the standard waitpid() API.
To avoid having crashes misinterpreted as hangs, please log in as root
and temporarily modify /proc/sys/kernel/core_pattern, like so:
echo core >/proc/sys/kernel/core_pattern
[-] PROGRAM ABORT : Pipe at the beginning of 'core_pattern'
Location : check_crash_handling(), afl-fuzz.c:7194
上記のようなエラーが出た場合はcoreファイル出力の設定が必要なので、以下のどちらかの手順で実行します。
環境変数AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES
を有効にしてafl-fuzz
を実行する
$ AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=true afl-fuzz -i in -o out target/release/woothee
ここに環境変数の一覧があり、色々動作を調整できそうです。
/proc/sys/kernel/core_pattern
を書き換えて適切にcoreファイルを出力できるように設定
$ echo "core" > /proc/sys/kernel/core_pattern
$ afl-fuzz -i in -o out target/release/woothee
テスト実行が遅い
cargo build --release
してリリースビルドでテストすると良さそう
debug情報が必要?
American Fuzzy Lop’ing Rustあたりを見ると
[profile.release]
debug = true
を追加していたりしますね。本当に必要かどうかは不明。。。
参考
- ご注文は American Fuzzy Lop ですか? - Qiita
- cargo-fuzz ... AFLとは別のファザーlibFuzzerを使えるcargo拡張
最後に
以上です。よいファジングライフを!!