コンテンツにスキップ

上級

Honggfuzz を使用してインストゥルメントされた C/C++ ターゲット

logo google-logo

Honggfuzz インストゥルメンテーション付きで C/C++ ターゲットをコンパイルする必要がありますか? このレッスンでは、Mayhem で C/C++ honggfuzz ターゲットをコンパイルし、テストする方法を手順を追って説明します。

学習時間の目安: 15 分

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

  1. 不適切な入力検証の欠陥がある C honggfuzz ターゲットをコンパイルし、ファジングする。
  2. 不適切な入力検証の欠陥がある C++ honggfuzz ターゲットをコンパイルし、ファジングする。

レッスンを駆け足で

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

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

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

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

以下が必要です。

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

ワン クリック テスト

次のボタンをクリックし、Create New Run フローの最後で Start Run をクリック して honggfuzz インストゥルメンテーション付き C ターゲットのテストを開始します。Mayhemfile はすでに用意されているため、何も設定する必要はありません。

Mayhem ランが始まると、次のようなラン ページが表示されます。

c-honggfuzz-gcc-run

すばらしい! Mayhem が honggfuzzを使用してインストゥルメントされた C ターゲットをファジングできることを確認したので、次に、たった今 Mayhem ランを実行した honggfuzz ターゲットをコンパイルし、テストする方法を順を追って説明します。

Honggfuzz インストゥルメンテーション付き C ターゲットのコンパイルとテスト

ファイル: c-honggfuzz-gcc.tgz

上記の c-honggfuzz-gcc.tgz をダウンロードして展開し、次の mayhemit.c のソース コードを見てみましょう。

 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
#include <stddef.h>
#include <stdint.h>

int mayhemit(char *buf, unsigned len)
{
  if(len >= 3)
    if(buf[0] == 'b')
      if(buf[1] == 'u')
        if(buf[2] == 'g') {
          abort(); // Defect: SIGABRT.
        }
  return 0;
}

extern int HF_ITER(uint8_t** buf, size_t* len);

int main(void) {
    for (;;) {
        size_t len;
        uint8_t *buf;

        HF_ITER(&buf, &len);

        mayhemit(buf, len);
    }
}

ソース コードは通常の main 関数ではなく、HF_ITER 関数を使用してバイト配列を受け取り、ターゲット関数 mayhemit のファジングに使用していることに気づくでしょう。入力が "bug" の場合、プログラムは不適切な入力検証のエラーでクラッシュします。

Note

honggfuzz を使用する場合、ASAN スタイル (LLVMFuzzerTestOneInput) または HF_ITER スタイルの 2 つのタイプのファザー エントリポイントがあります。詳細については honggfuzz persistent fuzzing に関する公式ドキュメントを参照してください。

Dockerfile を見ると、c-honggfuzz-gcc ターゲットのコンパイル プロセスがわかります。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
FROM fuzzers/honggfuzz:1.9
COPY mayhemit.c .
RUN hfuzz-gcc mayhemit.c -o /mayhemit

FROM debian:buster-slim
COPY --from=0 /mayhemit .
COPY --from=0 /usr/local/bin/honggfuzz /usr/local/bin/honggfuzz
COPY --from=0 /usr/lib/x86_64-linux-gnu/libunwind-ptrace.so.0 /usr/lib/x86_64-linux-gnu/libunwind-ptrace.so.0
COPY --from=0 /usr/lib/x86_64-linux-gnu/libunwind-x86_64.so.8 /usr/lib/x86_64-linux-gnu/libunwind-x86_64.so.8
COPY --from=0 /usr/lib/x86_64-linux-gnu/libbfd-2.31.1-system.so /usr/lib/x86_64-linux-gnu/libbfd-2.31.1-system.so
COPY --from=0 /usr/lib/x86_64-linux-gnu/libopcodes-2.31.1-system.so /usr/lib/x86_64-linux-gnu/libopcodes-2.31.1-system.so
COPY --from=0 /usr/lib/x86_64-linux-gnu/libunwind.so.8 /usr/lib/x86_64-linux-gnu/libunwind.so.8
RUN mkdir /testsuite && echo seed > /testsuite/seed

# Set to fuzz!
ENTRYPOINT ["honggfuzz", "-f", "/testsuite", "--"]
CMD ["/mayhemit"]
  • 行 1: 必要な honggfuzz 依存関係を提供するため、fuzzers/honggfuzz:1.9 ベース イメージがインポートされています。
  • 行 2: Docker コンテナーに mayhemit.c ソース ファイルがコピーされています。
  • 行 3: hfuzz-gcc C コンパイラを使用して honggfuzz インストゥルメンテーション付きで C ターゲットがコンパイルされています。
  • 行 5: debian:buster-slim ベース イメージがインポートされ、直前のビルド ステージからコンパイル済みの mayhemit バイナリが honggfuzz ファザー (および関連する依存関係) とともにコピーされています。
  • 行 17: Docker コンテナーのデフォルト実行ファイルとして /mayhemit 実行ファイルが設定されています。

Note

行 5-13 の処理はマルチステージ ビルドと呼ばれ、構築される Docker イメージを最適化したり、サイズをスリム化したりするために行われます。さらに、honggfuzz ドライバーは honggfuzz コンパイルされたバイナリと同じバージョンでなければなりません。そのため、直前のビルド ステージから honggfuzz 実行ファイルをコピーすることで、バイナリをコンパイルしたものと同じバージョンの honggfuzz が使用されることを保証します。

次に、<DOCKERHUB_USERNAME>/c-honggfuzz-gcc Docker イメージをビルドし、Docker Hub レジストリにプッシュする必要があります。

次に、forallsecure/c-honggfuzz-gcc Docker イメージをビルドし、Mayhem Docker レジストリにプッシュする必要があります。

docker build -f Dockerfile -t <DOCKERHUB_USERNAME>/c-honggfuzz-gcc .
docker push <DOCKERHUB_USERNAME>/c-honggfuzz-gcc
docker build -f Dockerfile -t $MAYHEM_DOCKER_REGISTRY/forallsecure/c-honggfuzz-gcc .
docker push $MAYHEM_DOCKER_REGISTRY/forallsecure/c-honggfuzz-gcc

情報

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

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

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

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

c-honggfuzz-gcc-run

おめでとうございます! Mayhem で C Honggfuzz ターゲットのテストが成功しました。

現実的な演習: Honggfuzz インストゥルメンテーション付き C++ ターゲットのコンパイルとテスト

honggfuzz インストゥルメンテーション付き C ターゲットのコンパイルおよびテスト手順がわかったので、次に、同じことを C++ ターゲットに対して行うことができるか、やってみましょう。

ファイル: cpp-honggfuzz-gcc.tgz

手順

  • Dockerfile および docker build コマンドを使用してDocker イメージをビルドし、結果を <DOCKERHUB_USERNAME>/cpp-honggfuzz-gcc としてタグ付けします。
  • docker tag および docker push コマンドを使用してパブリックな Docker Hub レジストリに <DOCKERHUB_USERNAME>/cpp-honggfuzz-gcc Docker イメージをプッシュします。
  • Mayhem UI または Mayhem CLI を使用して <DOCKERHUB_USERNAME>/cpp-honggfuzz-gcc Docker イメージをファジングします。Mayhemfile が適切に設定されていることを確認します。

  • Dockerfile および docker build コマンドを使用してDocker イメージをビルドし、結果を forallsecure/cpp-honggfuzz-gcc としてタグ付けします。

  • docker tag および docker push コマンドを使用して内部的な Mayhem Docker レジストリに forallsecure/cpp-honggfuzz-gcc Docker イメージをプッシュします。
  • Mayhem UI または Mayhem CLI を使用して forallsecure/cpp-honggfuzz-gcc Docker イメージをテストします。Mayhemfile が適切に設定されていることを確認します。

🔍 確認 Honggfuzz インストゥルメンテーション付き C++ ターゲットのコンパイルとテスト

解答

まず、mayhemit.cpp プログラムのソース コードを見てみましょう。

 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
#include <stddef.h>
#include <stdint.h>

int mayhemit(char *buf, unsigned len)
{
  if(len >= 3)
    if(buf[0] == 'b')
      if(buf[1] == 'u')
        if(buf[2] == 'g') {
          return 1/0;
        }
  return 0;
}

extern "C" int HF_ITER(uint8_t** buf, size_t* len);

int main(void) {
  for (;;) {
    size_t len;
    uint8_t *buf;

    HF_ITER(&buf, &len);

    mayhemit(reinterpret_cast<char *>(buf), len);
  }
}

c-honggfuzz-gcc ターゲットのソース コードと比較したとき、extern "C" キーワードが使用されているという違いがあることに気づいたかもしれません。extern "C" キーワードは、C++ の関数名に C リンケージを持たせ、クライアントの C コードが関数の宣言だけを含む C 互換ヘッダー ファイルを使用して関数にリンク (使用) できるようにします。

次に、対応する Dockerfile を確認します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
FROM fuzzers/honggfuzz:1.9
COPY mayhemit.cpp .
RUN hfuzz-g++ mayhemit.cpp -o /mayhemit

FROM debian:buster-slim
COPY --from=0 /mayhemit .
COPY --from=0 /usr/local/bin/honggfuzz /usr/local/bin/honggfuzz
COPY --from=0 /usr/lib/x86_64-linux-gnu/libunwind-ptrace.so.0 /usr/lib/x86_64-linux-gnu/libunwind-ptrace.so.0
COPY --from=0 /usr/lib/x86_64-linux-gnu/libunwind-x86_64.so.8 /usr/lib/x86_64-linux-gnu/libunwind-x86_64.so.8
COPY --from=0 /usr/lib/x86_64-linux-gnu/libbfd-2.31.1-system.so /usr/lib/x86_64-linux-gnu/libbfd-2.31.1-system.so
COPY --from=0 /usr/lib/x86_64-linux-gnu/libopcodes-2.31.1-system.so /usr/lib/x86_64-linux-gnu/libopcodes-2.31.1-system.so
COPY --from=0 /usr/lib/x86_64-linux-gnu/libunwind.so.8 /usr/lib/x86_64-linux-gnu/libunwind.so.8
RUN mkdir /testsuite && echo seed > /testsuite/seed

# Set to fuzz!
ENTRYPOINT ["honggfuzz", "-f", "/testsuite", "--"]
CMD ["/mayhemit"]

行 1 で、以前と同じように fuzzers/honggfuzz:1.9 ベース イメージをインポートし、行 3 で、今度は hfuzz-g++ コンパイラを使用して Honggfuzz インストゥルメンテーション付き C++ ターゲットをコンパイルしていることがわかります。その後、行 5 に進むと、コンパイルされた mayhemit バイナリおよび honggfuzz ファザーが (その依存関係とともに) debian:buster-slim ベース イメージに基づく次のステージ ビルドにコピーされています。結果として、この Dockerfile はマルチステージ ビルドになり、結果の Docker イメージのディスク領域が最適化されます。

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

次に、Dockerfile と同じディレクトリで docker build コマンドを実行し、結果の Docker イメージに forallsecure/cpp-honggfuzz-gcc とタグ付けします。

docker build -f Dockerfile -t <DOCKERHUB_USERNAME>/cpp-honggfuzz-gcc .
docker build -f Dockerfile -t $MAYHEM_DOCKER_REGISTRY/forallsecure/cpp-honggfuzz-gcc .

次に、<DOCKERHUB_USERNAME>/cpp-honggfuzz-gcc Docker イメージを Docker Hub レジストリにプッシュします。

次に、forallsecure/cpp-honggfuzz-gcc Docker イメージをプライベートな Mayhem Docker レジストリにプッシュします。

docker push <DOCKERHUB_USERNAME>/cpp-honggfuzz-gcc
docker push $MAYHEM_DOCKER_REGISTRY/forallsecure/cpp-honggfuzz-gcc

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

最後に、Mayhem UI または Mayhem CLI を使用して、アップロードされた forallsecure/cpp-honggfuzz-gcc Docker イメージに対して Mayhem ランを実行します。Mayhemfile は次のようになっているはずです。

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

Mayhem ランを開始すると、次のようなラン ページが表示されるはずです。

cpp-honggfuzz-gcc-run

おめでとうございます! Mayhem が不適切な入力検証の欠陥を発見しました。スクラッチから honggfuzz C++ ターゲットをビルドし、Mayhem を使用してバグを検出できました。

✏️ まとめと振り返り

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


学習内容

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

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    int mayhemit(char *buf, unsigned len)
    {
      if(len >= 3)
        if(buf[0] == 'b')
          if(buf[1] == 'u')
            if(buf[2] == 'g') {
              abort(); // Defect: SIGABRT.
            }
      return 0;
    }
    

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

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    FROM fuzzers/honggfuzz:1.9
    COPY mayhemit.c .
    RUN hfuzz-gcc mayhemit.c -o /mayhemit
    
    FROM debian:buster-slim
    COPY --from=0 /mayhemit .
    COPY --from=0 /usr/local/bin/honggfuzz /usr/local/bin/honggfuzz
    COPY --from=0 /usr/lib/x86_64-linux-gnu/libunwind-ptrace.so.0 /usr/lib/x86_64-linux-gnu/libunwind-ptrace.so.0
    COPY --from=0 /usr/lib/x86_64-linux-gnu/libunwind-x86_64.so.8 /usr/lib/x86_64-linux-gnu/libunwind-x86_64.so.8
    COPY --from=0 /usr/lib/x86_64-linux-gnu/libbfd-2.31.1-system.so /usr/lib/x86_64-linux-gnu/libbfd-2.31.1-system.so
    COPY --from=0 /usr/lib/x86_64-linux-gnu/libopcodes-2.31.1-system.so /usr/lib/x86_64-linux-gnu/libopcodes-2.31.1-system.so
    COPY --from=0 /usr/lib/x86_64-linux-gnu/libunwind.so.8 /usr/lib/x86_64-linux-gnu/libunwind.so.8
    RUN mkdir /testsuite && echo seed > /testsuite/seed
    
    # Set to fuzz!
    ENTRYPOINT ["honggfuzz", "-f", "/testsuite", "--"]
    CMD ["/mayhemit"]
    

    1
    2
    3
    4
    5
    6
    7
    image: <DOCKERHUB_USERNAME>/c-honggfuzz-gcc:latest
    duration: 90
    project: mayhem-examples
    target: c-honggfuzz-gcc
    cmds:
      - cmd: /mayhemit
        honggfuzz: true
    
    1
    2
    3
    4
    5
    6
    7
    image: $MAYHEM_DOCKER_REGISTRY/forallsecure/c-honggfuzz-gcc:latest
    duration: 90
    project: mayhem-examples
    target: c-honggfuzz-gcc
    cmds:
      - cmd: /mayhemit
        honggfuzz: true
    
2. 不適切な入力検証の欠陥がある C++ honggfuzz ターゲットをコンパイルし、ファジングする。
  • ソース コードには次の欠陥が含まれているはずです:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    int mayhemit(char *buf, unsigned len)
    {
      if(len >= 3)
        if(buf[0] == 'b')
          if(buf[1] == 'u')
            if(buf[2] == 'g') {
              abort(); // Defect: SIGABRT.
            }
      return 0;
    }
    

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

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    FROM fuzzers/honggfuzz:1.9
    COPY mayhemit.cpp .
    RUN hfuzz-g++ mayhemit.cpp -o /mayhemit
    
    FROM debian:buster-slim
    COPY --from=0 /mayhemit .
    COPY --from=0 /usr/local/bin/honggfuzz /usr/local/bin/honggfuzz
    COPY --from=0 /usr/lib/x86_64-linux-gnu/libunwind-ptrace.so.0 /usr/lib/x86_64-linux-gnu/libunwind-ptrace.so.0
    COPY --from=0 /usr/lib/x86_64-linux-gnu/libunwind-x86_64.so.8 /usr/lib/x86_64-linux-gnu/libunwind-x86_64.so.8
    COPY --from=0 /usr/lib/x86_64-linux-gnu/libbfd-2.31.1-system.so /usr/lib/x86_64-linux-gnu/libbfd-2.31.1-system.so
    COPY --from=0 /usr/lib/x86_64-linux-gnu/libopcodes-2.31.1-system.so /usr/lib/x86_64-linux-gnu/libopcodes-2.31.1-system.so
    COPY --from=0 /usr/lib/x86_64-linux-gnu/libunwind.so.8 /usr/lib/x86_64-linux-gnu/libunwind.so.8
    RUN mkdir /testsuite && echo seed > /testsuite/seed
    
    # Set to fuzz!
    ENTRYPOINT ["honggfuzz", "-f", "/testsuite", "--"]
    CMD ["/mayhemit"]
    

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