LoginSignup
3
3

More than 5 years have passed since last update.

RustでAmerican Fuzzy Lop(afl)

Posted at

はじめに

Rustでafl (rust-fuzz/afl.rs)を使ったファジングを試してみます。
テスト対象はwoothee-rustを使って説明します。

以下はテスト実行時の画面
スクリーンショット 2017-03-11 23.30.16.png

前提条件

項目 説明
検証日 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

を追加していたりしますね。本当に必要かどうかは不明。。。

参考

最後に

以上です。よいファジングライフを!!

3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3