コンテンツにスキップ

上級

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

java-logo

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

学習時間の目安: 15 分

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

  1. キャッチされない例外の欠陥があるベース実行ファイル Java ターゲットをコンパイルし、ファジングする。
  2. インデックス境界外の欠陥があるベース実行ファイル Java ターゲットをコンパイルし、ファジングする。

レッスンを駆け足で

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

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

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

    1
    2
    3
    4
    5
    6
    7
    8
    image: <DOCKERHUB_USERNAME>/java-base-executable:latest
    duration: 120
    project: mayhem-examples
    target: java-base-executable
    cmds:
      - cmd: /usr/bin/MayhemIt.jar @@
        env:
          MFUZZ_JAVA: '1'
    
    1
    2
    3
    4
    5
    6
    7
    8
    image: $MAYHEM_DOCKER_REGISTRY/forallsecure/java-base-executable:latest
    duration: 120
    project: mayhem-examples
    target: java-base-executable
    cmds:
      - cmd: /usr/bin/MayhemIt.jar @@
        env:
          MFUZZ_JAVA: '1'
    

以下が必要です。

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

ワン クリック テスト

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

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

base-executable-java-target-run

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

スタンドアロンの Java ターゲットのテスト

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

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

 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
31
32
33
package mayhemit;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.BufferedReader;
import java.io.FileReader;
import java.util.Scanner;

public class MayhemIt {
    public static void main(String[] args) {
        String input = "";

        try {
            File file = new File(args[0]);
            BufferedReader br = new BufferedReader(new FileReader(file));
            Scanner in = new Scanner(br);
            input = in.nextLine();
        } catch (FileNotFoundException e) {
            System.err.println("Could not find file");
            return;
        }

        if (input.length() >= 3) {
            if (input.charAt(0) == 'b') {
                if (input.charAt(1) == 'u') {
                    if (input.charAt(2) == 'g') {
                        throw new RuntimeException("Made it to the bug!");
                    }
                }
            }
        }
    }
}

main 関数のファイル処理をサポートするさまざまな Java ライブラリがインポートされ、入力テスト ケースが "bug" である場合にキャッチされない例外の欠陥でプログラムがクラッシュすることがわかります。

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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
FROM amazoncorretto:8
COPY MayhemIt.java .

# Build MayhemIt.jar
RUN mkdir -p build && \
    javac -d build MayhemIt.java && \
    cd build && \
    jar -cfe MayhemIt.jar mayhemit.MayhemIt * && \
    chmod u+x MayhemIt.jar && \
    mv MayhemIt.jar /usr/bin/MayhemIt.jar && \
    rm -rf build

# Set to fuzz!
ENTRYPOINT []
CMD [ "/usr/bin/MayhemIt.jar", "@@" ]
  1. 行 1: 必要な java 依存関係を収集するため、amazoncorretto:8 ベース イメージがインポートされています。
  2. 行 2: Docker コンテナーに MayhemIt.java ソース ファイルがコピーされています。
  3. 行 5-11: javac コンパイラを使用して MayhemIt.jar ファイルがコンパイルされています。
  4. 行 14: ビルドされた Docker イメージのデフォルト実行ファイルとして /usr/bin/MayhemIt.jar 実行ファイルが設定されています。

Note

コンテナーで MayhemIt.jar を実行するには、java -jar /usr/bin/MayhemIt.jar を実行して JVM で jar ファイルを実行する必要があります。しかし、MayhemIt.jar ファイルの Mayhem ランを実行する場合、MFUZZ_JAVA 環境変数に値 1 を設定して有効化します。これは、ランの実行時に Mayhem の JVM で jar ファイルを実行するよう Mayhem に指示します。そのため、Mayhemfile の CMD 呼び出しでは、java -jar を指定する必要はありません。

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

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

docker build -f Dockerfile -t <DOCKERHUB_USERNAME>/java-base-executable .
docker push <DOCKERHUB_USERNAME>/java-base-executable
docker build -f Dockerfile -t $MAYHEM_DOCKER_REGISTRY/forallsecure/java-base-executable .
docker push $MAYHEM_DOCKER_REGISTRY/forallsecure/java-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>/java-base-executable Docker イメージを検索します。Mayhemfile が次のようになっていることを確認します。

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

1
2
3
4
5
6
7
8
image: <DOCKERHUB_USERNAME>/java-base-executable:latest
duration: 120
project: mayhem-examples
target: java-base-executable
cmds:
  - cmd: /usr/bin/MayhemIt.jar @@
    env:
      MFUZZ_JAVA: '1'
1
2
3
4
5
6
7
8
image: $MAYHEM_DOCKER_REGISTRY/forallsecure/java-base-executable:latest
duration: 120
project: mayhem-examples
target: java-base-executable
cmds:
  - cmd: /usr/bin/MayhemIt.jar @@
    env:
      MFUZZ_JAVA: '1'

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

base-executable-java-target-run

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

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

キャッチされない例外の欠陥がある Java ターゲットのビルドおよびテスト方法がわかったところで、ソース コードを修正してインデックス境界外の欠陥を検出できるかどうかやってみましょう。

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

手順

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

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

解答

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

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

Note

他の境界外の欠陥が起こらないよう、条件として input.length() >= 3 && input.length() < 5 を設定しています。たとえば、単に input.length() < 5 を条件に設定した場合、行 23、 24、25 で追加のインデックス境界外エラーが発生する可能性があります。

 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
31
32
package mayhemit;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.BufferedReader;
import java.io.FileReader;
import java.util.Scanner;

public class MayhemIt {
    public static void main(String[] args) {
        String input = "";

        try {
            File file = new File(args[0]);
            BufferedReader br = new BufferedReader(new FileReader(file));
            Scanner in = new Scanner(br);
            input = in.nextLine();
        } catch (FileNotFoundException e) {
            System.err.println("Could not find file");
            return;
        }

        if (input.length() >= 3 && input.length() < 5) {
            if (input.charAt(0) == 'b') {
                if (input.charAt(1) == 'u') {
                    if (input.charAt(2) == 'g') {
                        char x = input.charAt(10);
                    }
                }
            }
        }
    }
}

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

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

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

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

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

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

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

make build
make push

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

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

1
2
3
4
5
6
7
8
image: <DOCKERHUB_USERNAME>/java-base-executable-mayhemit-out-of-bounds:latest
duration: 120
project: mayhem-examples
target: mayhemit-out-of-bounds
cmds:
  - cmd: /usr/bin/MayhemIt.jar @@
    env:
      MFUZZ_JAVA: '1'
1
2
3
4
5
6
7
8
image: $MAYHEM_DOCKER_REGISTRY/java-base-executable-mayhemit-out-of-bounds:latest
duration: 120
project: mayhem-examples
target: mayhemit-out-of-bounds
cmds:
  - cmd: /usr/bin/MayhemIt.jar @@
    env:
      MFUZZ_JAVA: '1'

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

mayhemit-out-of-bounds-run

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

✏️ まとめと振り返り

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


学習内容

1. キャッチされない例外の欠陥があるベース実行ファイル Java ターゲットをコンパイルし、テストする。
  • ソース コードには次の欠陥が含まれているはずです:

    1
    2
    3
    4
    5
    6
    7
    8
    if (input.length() >= 3) {
        if (input.charAt(0) == 'b') {
            if (input.charAt(1) == 'u') {
                if (input.charAt(2) == 'g') {
                    throw new RuntimeException("Made it to the bug!");
            }
        }
    }
    

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

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    FROM fuzzers/jazzer:0.9.1-openjdk11
    COPY MayhemIt.java .
    
    # Build MayhemIt.jar
    RUN mkdir -p build && \
        javac -d build MayhemIt.java && \
        cd build && \
        jar cvf MayhemIt.jar * && \
        mv MayhemIt.jar /usr/bin/MayhemIt.jar && \
        rm -rf build
    
    # Set to fuzz!
    ENTRYPOINT []
    CMD [ "/usr/bin/jazzer_driver", "--cp=/usr/bin/MayhemIt.jar", "--target_class=mayhemit.MayhemIt" ]
    

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    if (input.length() > 3 && input.length() < 5) {
        if (input.charAt(0) == 'b') {
            if (input.charAt(1) == 'u') {
                if (input.charAt(2) == 'g') {
                    char x = input.charAt(10);
                }
            }
        }
    }
    

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

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    FROM amazoncorretto:8
    COPY MayhemIt.java .
    
    # Build MayhemIt.jar
    RUN mkdir -p build && \
        javac -d build MayhemIt.java && \
        cd build && \
        jar --create --file MayhemIt.jar --main-class mayhemit.MayhemIt * && \
        chmod u+x MayhemIt.jar && \
        mv MayhemIt.jar /usr/bin/MayhemIt.jar && \
        rm -rf build
    
    # Set to fuzz!
    ENTRYPOINT []
    CMD [ "/usr/bin/MayhemIt.jar", "@@" ]
    

    1
    2
    3
    4
    5
    6
    7
    8
    image: <DOCKERHUB_USERNAME>/java-base-executable-mayhemit-out-of-bounds:latest
    duration: 120
    project: mayhem-examples
    target: mayhemit-out-of-bounds
    cmds:
      - cmd: /usr/bin/MayhemIt.jar @@
        env:
          MFUZZ_JAVA: '1'
    
    1
    2
    3
    4
    5
    6
    7
    8
    image: $MAYHEM_DOCKER_REGISTRY/java-base-executable-mayhemit-out-of-bounds:latest
    duration: 120
    project: mayhem-examples
    target: mayhemit-out-of-bounds
    cmds:
      - cmd: /usr/bin/MayhemIt.jar @@
        env:
          MFUZZ_JAVA: '1'