コンテンツにスキップ

上級

ベース実行ファイル Rust ターゲット

rust-logo

テスト対象はインストゥルメンテーションされていない、またはベース実行ファイルの Rust ターゲットでしょうか? このレッスンでは、Mayhem を使用してベース実行ファイル Rust ターゲットをテストする方法を順を追って説明します。

学習時間の目安: 15 分

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

  1. 不適切な入力検証の欠陥があるベース実行ファイル Rust ターゲットをコンパイルし、ファジングする。
  2. インデックス境界外の欠陥があるベース実行ファイル Rust ターゲットをコンパイルし、ファジングする。

レッスンを駆け足で

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

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

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

    1
    2
    3
    4
    5
    6
    image: <DOCKERHUB_USERNAME>/rust-base-executable:latest
    duration: 90
    project: mayhem-examples
    target: rust-base-executable
    cmds:
      - cmd: /mayhemit @@
    
    1
    2
    3
    4
    5
    6
    image: $MAYHEM_DOCKER_REGISTRY/forallsecure/rust-base-executable:latest
    duration: 90
    project: mayhem-examples
    target: rust-base-executable
    cmds:
      - cmd: /mayhemit @@
    

以下が必要です。

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

ワン クリック テスト

下のボタンをクリックしてベース実行ファイル Rust ターゲットのテストを開始します。最終確認ページに到達するまで [Next] をクリックし、[Start Run] をクリックします。

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

rust-base-executable-run

Mayhem によるベース実行ファイル Rust ターゲットのテストを確認したので、次に、どのように Rust ターゲットがビルドされたのかを順を追って説明します。

ベース実行ファイル Rust ターゲットのテスト

ファイル: rust-base-executable.tgz

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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
use std::env;
use std::fs::File;
use std::io;
use std::io::prelude::*;
use std::process;

fn main() -> io::Result<()> {
    let args: Vec<String> = env::args().collect();
    let filename = &args[1];

    let mut f = File::open(filename)?;
    let mut buffer = [0; 10];

    // read up to 10 bytes
    f.read(&mut buffer)?;
    mayhemit(&buffer);
    Ok(())
}

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

ソース コードの先頭でさまざまな標準 Rust モジュールがインポートされ、main および mayhemit の 2 つの主要な関数があることがわかります。

main 関数はファイル入力を処理し、コンテンツの最初の 10 バイトまでを読み取り、mayhemit 関数で解析を行って、プログラムに入力テスト ケース "bug" が挿入されたかどうかを判定します。テスト ケース "bug" が存在する場合、abort() 関数によって不適切な入力検証の欠陥が設定されます。

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

1
2
3
4
5
6
7
FROM rust:1.44-buster as rust-target
COPY mayhemit.rs .
RUN rustc -o /mayhemit mayhemit.rs

# Set to fuzz!
ENTRYPOINT []
CMD ["/mayhemit", "@@"]
  • 行 1: 必要な Rust 依存関係を収集するため、rust:1.44-buster ベース イメージがインポートされています。
  • 行 2: Docker コンテナーに mayhemit.rs ソース ファイルがコピーされています。
  • 行 3: rustc コンパイラを使用して mayhemit.rs ソース コードが mayhemit Rust 実行ファイルにコンパイルされています。
  • 行 7: ビルドされた Docker イメージのデフォルト実行ファイルとして /mayhemit @@ 実行ファイルが定義されています。

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

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

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

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-base-executable Docker イメージを検索します。Mayhemfile が次のようになっていることを確認します。

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

1
2
3
4
5
6
image: <DOCKERHUB_USERNAME>/rust-base-executable:latest
duration: 90
project: mayhem-examples
target: rust-base-executable
cmds:
  - cmd: /mayhemit @@
1
2
3
4
5
6
image: $MAYHEM_DOCKER_REGISTRY/forallsecure/rust-base-executable:latest
duration: 90
project: mayhem-examples
target: rust-base-executable
cmds:
  - cmd: /mayhemit @@

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

rust-base-executable-run

おめでとうございます! Mayhem によるベース実行ファイル Rust ターゲットのテストが成功しました。

現実的な演習: mayhemit-out-of-bounds ベース実行ファイル Rust ターゲットのコンパイルとテスト

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

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

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

🔍 確認mayhemit-out-of-bounds ベース実行ファイル Rust ターゲットのコンパイルとテスト

解答

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

まず、mayhemit 関数を使用してファズ入力を解析したとき、入力テスト ケース "bug" がインデックス境界外エラーを発生させるよう、最大長の制約 [0; 3] および誤った呼び出し `data[10] を追加します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
use std::env;
use std::fs::File;
use std::io;
use std::println;
use std::io::prelude::*;


fn main() -> io::Result<()> {
    let args: Vec<String> = env::args().collect();
    let filename = &args[1];

    let mut f = File::open(filename)?;
    let mut buffer = [0; 3];

    f.read(&mut buffer)?;
    mayhemit(&buffer);
    Ok(())
}

fn mayhemit(data: &[u8]) {
    if data[0] == 'b' as u8 {
        if data[1] == 'u' as u8 {
            if data[2] == 'g' as u8 {
                println!("made it!");
                let x;
                x = data[10];
            }
        }
    }
}

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

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

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

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

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

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

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

make build
make push

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

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

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

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

mayhemit-out-of-bounds-run

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

✏️ まとめと振り返り

このレッスンでは、Mayhem でベース実行ファイル Rust ターゲットをファジングする方法を学びました。


学習内容

1.不適切な入力検証の欠陥があるベース実行ファイル Rust ターゲットをビルドし、テストする。
  • ソース コードには次の欠陥が含まれているはずです:

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

  • ベース実行ファイル Rust ターゲットをファジングするには、次の Dockerfile を使用して Rust プログラムを含む Docker イメージをビルドします。

    1
    2
    3
    4
    5
    6
    7
    FROM rust:1.44-buster as rust-target
    COPY mayhemit.rs .
    RUN rustc -o /mayhemit mayhemit.rs
    
    # Set to fuzz!
    ENTRYPOINT []
    CMD ["/mayhemit", "@@"]
    

    1
    2
    3
    4
    5
    6
    image: <DOCKERHUB_USERNAME>/rust-base-executable:latest
    duration: 90
    project: mayhem-examples
    target: rust-base-executable
    cmds:
      - cmd: /mayhemit @@
    
    1
    2
    3
    4
    5
    6
    image: $MAYHEM_DOCKER_REGISTRY/forallsecure/rust-base-executable:latest
    duration: 90
    project: mayhem-examples
    target: rust-base-executable
    cmds:
      - cmd: /mayhemit @@
    
2.インデックス境界外の欠陥の欠陥があるベース実行ファイル Rust ターゲットをビルドし、ファジングする。
  • ソース コードには次の欠陥が含まれているはずです:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    fn mayhemit(data: &[u8]) {
        if data[0] == 'b' as u8 {
            if data[1] == 'u' as u8 {
                if data[2] == 'g' as u8 {
                    println!("made it!");
                    let x;
                    x = data[10];
                }
            }
        }
    }
    

  • ベース実行ファイル Rust ターゲットをファジングするには、次の Dockerfile を使用して Rust プログラムを含む Docker イメージをビルドします。

    1
    2
    3
    4
    5
    6
    7
    FROM rust:1.44-buster as rust-target
    COPY mayhemit.rs .
    RUN rustc -o /mayhemit mayhemit.rs
    
    # Set to fuzz!
    ENTRYPOINT []
    CMD ["/mayhemit", "@@"]
    

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