コンテンツにスキップ

上級

AFL インストゥルメンテーション付き Rust ターゲット

rust-logo google-logo

テスト対象は Google の AFL を使用してインストゥルメントされた Rust ターゲットですか? このレッスンでは、AFL インストゥルメンテーション付きで Rust ターゲットをビルドし、結果のバイナリを Mayhem でテストする方法を順を追って説明します。

学習時間の目安: 15 分

このレッスンを終了すると、以下のことができるようになります。

  1. 不適切な入力検証の欠陥がある AFL インストゥルメンテーション付き Rust ターゲットをコンパイルし、ファジングする。
  2. インデックス境界外の欠陥がある AFL インストゥルメンテーション付き Rust ターゲットをコンパイルし、ファジングする。

レッスンを駆け足で

始める前に前提条件を確認します。

  1. rust-afl.tgz をダウンロードし、rust-afl Docker イメージをビルドし、指定された Docker レジストリにプッシュします。

    docker build -t <DOCKERHUB_USERNAME>/rust-afl .
    docker push <DOCKERHUB_USERNAME>/rust-afl
    
    docker build -t $MAYHEM_DOCKER_REGISTRY/forallsecure/rust-afl .
    docker push $MAYHEM_DOCKER_REGISTRY/forallsecure/rust-afl
    
  2. Mayhem UI または Mayhem CLI で次の Mayhemfile を使用して forallsecure/rust-afl Docker イメージに対して Mayhem ランを実行します。

    1
    2
    3
    4
    5
    6
    7
    image: <DOCKERHUB_USERNAME>/rust-afl:latest
    duration: 90
    project: mayhem-examples
    target: rust-afl
    cmds:
      - cmd: /mayhemit/target/debug/mayhemit
        afl: true
    
    1
    2
    3
    4
    5
    6
    7
    image: $MAYHEM_DOCKER_REGISTRY/forallsecure/rust-afl:latest
    duration: 90
    project: mayhem-examples
    target: rust-afl
    cmds:
      - cmd: /mayhemit/target/debug/mayhemit
        afl: true
    

以下が必要です。

  • Docker がインストールされていること
  • 有効なインターネット接続 (Docker Hub ベース イメージをプルするため)

ワン クリック テスト

下のボタンをクリックして AFL インストゥルメンテーション付き Rust ターゲットのテストを開始します。最終確認ページに到達するまで [Next] をクリックし、[Start Run] をクリックします。

次のようなラン ページが表示されます。

rust-afl-run

Mayhem による AFL インストゥルメンテーション付き Rust ターゲットのテストを確認したので、次に、どのように Rust ターゲットがビルドされたかを順を追って説明します。

AFL インストゥルメンテーション付き Rust ターゲットのテスト

ファイル: rust-afl.tgz

上記の rust-afl.tgz をダウンロードして展開し、次のバグのある mayhemit.rs プログラムを見てみましょう。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
#[macro_use]
extern crate afl;

use std::process;

fn main() {
    fuzz!(|data: &[u8]| {
        if data[0] == 'b' as u8 {
            if data[1] == 'u' as u8 {
                if data[2] == 'g' as u8 {
                    process::abort();
                }
            }
        }
    });
}

ソース ファイルの先頭でプログラムに外部クレート afl ライブラリがインポートされ、3 つの主要な関数 main および fuzz! があることがわかります。

main 関数はプログラムへのエントリポイントして機能し、afl クレートによって提供される fuzz! 関数が含まれています。この関数は、標準入力からバイト列を読み取ってロジックにバイト列を渡します。特に、バイト列が "bug" である場合、abort() 関数が初期化され、不適切な入力検証の欠陥を発生させます。

次に rust-afl がどのようにビルドされるかを見てみましょう。関連する Dockerfile を見ると、以下の処理があるのがわかります。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
FROM rust:1.44-buster as rust-target
RUN cargo install afl --version 0.7.0
COPY mayhemit.rs .
RUN export USER=root && \
    cargo new mayhemit && \
    cd mayhemit && \
    mv /mayhemit.rs src/main.rs && \
    echo afl = '"0.4"' >> Cargo.toml && \
    cargo afl build
RUN mkdir /testsuite && echo seed > /testsuite/seed

# Set to fuzz!
ENTRYPOINT ["cargo", "afl", "fuzz", "-i", "/tmp", "-o", "/out"]
CMD ["/mayhemit/target/debug/mayhemit"]
  • 行 1: 必要な Rust 依存関係を収集するため、rust:1.44-buster ベース イメージがインポートされています。
  • 行 2: afl クレート ライブラリがインストールされています。
  • 行 3: Docker コンテナーに mayhemit.rs ソース ファイルがコピーされています。
  • 行 4-9: (afl クレートによって提供される) AFL cargo サブコマンドが使用され、mayhemit.rs ソース コードが mayhemit Rust 実行ファイルにコンパイルされています。
  • 行 14: ビルドされた Docker イメージのデフォルト実行ファイルとして /mayhemit/target/debug/mayhemit 実行ファイルが定義されています。

次に、docker build および docker push コマンドを使用して、Docker イメージをビルドして Docker Hub にプッシュする必要があります。

次に、docker build および docker push コマンドを使用して、Docker イメージをビルドして Mayhem サーバーにプッシュする必要があります。$DOCKER_REGISTRY は、内部的な Mayhem Docker レジストリの URL を表します。

docker build -t <DOCKERHUB_USERNAME>/rust-afl .
docker push <DOCKERHUB_USERNAME>/rust-afl
docker build -t $MAYHEM_DOCKER_REGISTRY/forallsecure/rust-afl .
docker push $MAYHEM_DOCKER_REGISTRY/forallsecure/rust-afl

Info

mayhem login コマンドを使用して内部的な Mayhem Docker レジストリの URL を検索し、次のコマンドを使用して DOCKER_REGISTRY 環境変数を設定できます:

export DOCKER_REGISTRY=tutorial.forallsecure.com:5000
ここでは、サンプルの Docker レジストリ URL を設定していますが、DOCKER_REGISTRY 環境変数に自身の Mayhem Docker レジストリ URL を設定する必要があります。

新しく作成した Docker イメージをパブリックな Docker Hub レジストリに正常にプッシュしたら、Mayhem UI から新規ランを作成し、<DOCKERHUB_USERNAME>/rust-afl Docker イメージを検索します。Mayhemfile が次のようになっていることを確認します。

新しく作成した Docker イメージをプライベートな Mayhem Docker レジストリに正常にプッシュしたら、Mayhem UI から新規ランを作成し、forallsecure/rust-afl Docker イメージを検索します。Mayhemfile が次のようになっていることを確認します。

1
2
3
4
5
6
7
image: <DOCKERHUB_USERNAME>/rust-afl:latest
duration: 90
project: mayhem-examples
target: rust-afl
cmds:
  - cmd: /mayhemit/target/debug/mayhemit
    afl: true
1
2
3
4
5
6
7
image: $MAYHEM_DOCKER_REGISTRY/forallsecure/rust-afl:latest
duration: 90
project: mayhem-examples
target: rust-afl
cmds:
  - cmd: /mayhemit/target/debug/mayhemit
    afl: true

Note

ファイル入力を使用してターゲットをファジングするよう Mayhem に指示する @@ などのパラメーターなしで /mayhemit/target/debug/mayhemitcmd に設定されていることを確認します。これは、Rust の afl クレートが標準入力だけを使用してファジングを行うからです。詳細については Rust Fuzz Book を参照してください。

新規ラン作成フローの最終確認ページに到達するまで [Next] をクリックし、[Start Run] をクリックして Mayhem ランを実行します。次のようなラン ページが表示されます。

rust-afl-run

おめでとうございます! Mayhem での AFL インストゥルメンテーション付き Rust ターゲットのテストが成功しました。

現実的な演習: mayhemit-out-of-bounds AFL インストゥルメンテーション付き Rust ターゲットのコンパイルとテスト

不適切な入力検証の欠陥がある Rust ターゲットのビルドおよびテスト方法がわかったところで、ソース コードを修正してインデックス境界外の欠陥を検出できるかどうかやってみましょう。

ファイル: mayhemit-out-of-bounds-unsolved.zip

手順

  • mayhemit.rs ソース コードを変更して最大長の制約を追加し、次のようにインデックス境界外欠陥を追加します。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
fuzz!(|data: &[u8]| {
    if data.len() >= 3 && data.len() < 5 {
        if data[0] == 'b' as u8 {
            if data[1] == 'u' as u8 {
                if data[2] == 'g' as u8 {
                    let x;
                    x = data[10];
                }
            }
        }
    }
});
  • docker build コマンドを使用して Dockerfile を再ビルドし、結果の Docker イメージを <DOCKERHUB_USERNAME>/rust-afl-mayhemit-out-of-bounds としてタグ付けします。
  • docker push コマンドを使用してパブリックな Docker Hub レジストリに <DOCKERHUB_USERNAME>/rust-afl-mayhemit-out-of-bounds Docker イメージをプッシュします。
  • Mayhem UI または Mayhem CLI を使用して <DOCKERHUB_USERNAME>/rust-afl-mayhemit-out-of-bounds Docker イメージをファジングします。Mayhemfile が適切に設定されていることを確認します。
  • docker build コマンドを使用して Dockerfile を再ビルドし、結果の Docker イメージを $MAYHEM_DOCKER_REGISTRY/rust-afl-mayhemit-out-of-bounds としてタグ付けします。
  • docker push コマンドを使用してプライベートな Mayhem Docker レジストリに $MAYHEM_DOCKER_REGISTRY/rust-afl-mayhemit-out-of-bounds Docker イメージをプッシュします。
  • Mayhem UI または Mayhem CLI を使用して $MAYHEM_DOCKER_REGISTRY/rust-afl-mayhemit-out-of-bounds Docker イメージをテストします。Mayhemfile が適切に設定されていることを確認します。

🔍 確認mayhemit-out-of-bounds AFL インストゥルメンテーション付き Rsut ターゲットのコンパイルとテスト

解答

模範解答: mayhemit-out-of-bounds-solved.zip

まず、fuzz! 関数をファジングしたとき、入力テスト ケース "bug" がインデックス境界外エラーを発生させるよう、最大長の制約 data.len() < 5 および誤った呼び出し data[10] を追加します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
#[macro_use]
extern crate afl;

fn main() {
    fuzz!(|data: &[u8]| {
        if data.len() >= 3 && data.len() < 5 {
            if data[0] == 'b' as u8 {
                if data[1] == 'u' as u8 {
                    if data[2] == 'g' as u8 {
                        let x;
                        x = data[10];
                    }
                }
            }
        }
    });
}

次に、Dockerfile と同じディレクトリで docker build コマンドを実行し、結果の Docker イメージに <DOCKERHUB_USERNAME>/rust-afl-mayhemit-out-of-bounds というタグを付けます。

次に、Dockerfile と同じディレクトリで docker build コマンドを実行し、結果の Docker イメージに $MAYHEM_DOCKER_REGISTRY/rust-afl-mayhemit-out-of-bounds というタグを付けます。

docker build -f Dockerfile -t <DOCKERHUB_USERNAME>/rust-afl-mayhemit-out-of-bounds .
docker build -f Dockerfile -t $MAYHEM_DOCKER_REGISTRY/rust-afl-mayhemit-out-of-bounds .

次に、$MAYHEM_DOCKER_REGISTRY/rust-afl-mayhemit-out-of-bounds Docker イメージにタグを付けてパブリックな Docker Hub レジストリにプッシュします。

次に、$MAYHEM_DOCKER_REGISTRY/rust-afl-mayhemit-out-of-bounds Docker イメージにタグを付けてプライベートな Mayhem Docker レジストリにプッシュします。

docker push <DOCKERHUB_USERNAME>/rust-afl-mayhemit-out-of-bounds
docker push $MAYHEM_DOCKER_REGISTRY/rust-afl-mayhemit-out-of-bounds

別の方法として、付属の Makefil を使用し、MAYHEM_DOCKER_REGISTRY` 環境変数を設定して次のコマンドを実行することで、簡単に結果の Docker イメージをビルドし、プッシュすることもできます。

make build
make push

最後に、Mayhem UI または Mayhem CLI を使用して、アップロードされた <DOCKERHUB_USERNAME>/rust-afl-mayhemit-out-of-bounds Docker イメージに対して Mayhem ランを実行します。Mayhemfile は次のようになっているはずです。

最後に、Mayhem UI または Mayhem CLI を使用して、アップロードされた $MAYHEM_DOCKER_REGISTRY/rust-afl-mayhemit-out-of-bounds Docker イメージに対して Mayhem ランを実行します。Mayhemfile は次のようになっているはずです。

1
2
3
4
5
6
7
image: <DOCKERHUB_USERNAME>/rust-afl-mayhemit-out-of-bounds:latest
duration: 90
project: mayhem-examples
target: mayhemit-out-of-bounds
cmds:
  - cmd: /mayhemit/target/debug/mayhemit
    afl: true
1
2
3
4
5
6
7
image: $MAYHEM_DOCKER_REGISTRY/rust-afl-mayhemit-out-of-bounds:latest
duration: 90
project: mayhem-examples
target: mayhemit-out-of-bounds
cmds:
  - cmd: /mayhemit/target/debug/mayhemit
    afl: true

最終的なラン ページは次のように表示されるはずです。

mayhemit-out-of-bounds-run

おめでとうございます! Mayhem がインデックス境界外の欠陥を発見しました。スクラッチからベース実行ファイル AFL インストゥルメンテーション付き Rust ターゲットをビルドし、Mayhem を使用してバグを検出できました。

✏️ まとめと振り返り

このレッスンでは、AFL インストゥルメンテーション付き Rust ターゲットを Mayhem でファジングする方法を学びました。


学習内容

1.不適切な入力検証の欠陥がある AFL インストゥルメンテーション付き Rust ターゲットをビルドし、テストする。
  • ソース コードには次の欠陥が含まれているはずです:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    fn main() {
        fuzz!(|data: &[u8]| {
            if data[0] == 'b' as u8 {
                if data[1] == 'u' as u8 {
                    if data[2] == 'g' as u8 {
                        process::abort();
                    }
                }
            }
        });
    }
    

  • AFL インストゥルメンテーション付き Rust ターゲットをファジングするには、次の Dockerfile および Mayhemfile を使用して Rust プログラムを含む Docker イメージをビルドし、Mayhem でファジングを実行します。

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    FROM rust:1.44-buster as rust-target
    RUN cargo install afl --version 0.7.0
    COPY mayhemit.rs .
    RUN export USER=root && \
        cargo new mayhemit && \
        cd mayhemit && \
        mv /mayhemit.rs src/main.rs && \
        echo afl = '"0.4"' >> Cargo.toml && \
        cargo afl build
    RUN mkdir /testsuite && echo seed > /testsuite/seed
    
    # Set to fuzz!
    ENTRYPOINT ["cargo", "afl", "fuzz", "-i", "/tmp", "-o", "/out"]
    CMD ["/mayhemit/target/debug/mayhemit"]
    

    1
    2
    3
    4
    5
    6
    7
    image: <DOCKERHUB_USERNAME>/rust-afl:latest
    duration: 90
    project: mayhem-examples
    target: rust-afl
    cmds:
      - cmd: /mayhemit/target/debug/mayhemit
        afl: true
    
    1
    2
    3
    4
    5
    6
    7
    image: $MAYHEM_DOCKER_REGISTRY/forallsecure/rust-afl:latest
    duration: 90
    project: mayhem-examples
    target: rust-afl
    cmds:
      - cmd: /mayhemit/target/debug/mayhemit
        afl: true
    
2.インデックス境界外の欠陥がある AFL インストゥルメンテーション付き Rust ターゲットをビルドし、テストする。
  • ソース コードには次の欠陥が含まれているはずです:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    fn main() {
        fuzz!(|data: &[u8]| {
            if data.len() >= 3 && data.len() < 5 {
                if data[0] == 'b' as u8 {
                    if data[1] == 'u' as u8 {
                        if data[2] == 'g' as u8 {
                            let x;
                            x = data[10];
                        }
                    }
                }
            }
        });
    }
    

  • AFL インストゥルメンテーション付き Rust ターゲットをファジングするには、次の Dockerfile および Mayhemfile を使用して Rust プログラムを含む Docker イメージをビルドし、Mayhem でファジングを実行します。

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    FROM rust:1.44-buster as rust-target
    RUN cargo install afl --version 0.7.0
    COPY mayhemit.rs .
    RUN export USER=root && \
        cargo new mayhemit && \
        cd mayhemit && \
        mv /mayhemit.rs src/main.rs && \
        echo afl = '"0.4"' >> Cargo.toml && \
        cargo afl build
    RUN mkdir /testsuite && echo seed > /testsuite/seed
    
    # Set to fuzz!
    ENTRYPOINT ["cargo", "afl", "fuzz", "-i", "/tmp", "-o", "/out"]
    CMD ["/mayhemit/target/debug/mayhemit"]
    

    1
    2
    3
    4
    5
    6
    7
    image: <DOCKERHUB_USERNAME>/rust-afl-mayhemit-out-of-bounds:latest
    duration: 90
    project: mayhem-examples
    target: mayhemit-out-of-bounds
    cmds:
      - cmd: /mayhemit/target/debug/mayhemit
        afl: true
    
    1
    2
    3
    4
    5
    6
    7
    image: $MAYHEM_DOCKER_REGISTRY/rust-afl-mayhemit-out-of-bounds:latest
    duration: 90
    project: mayhem-examples
    target: mayhemit-out-of-bounds
    cmds:
      - cmd: /mayhemit/target/debug/mayhemit
        afl: true