上級
Go-Fuzz を使用した LibFuzzer インストゥルメンテーション付き Go ターゲット¶
LibFuzzer インストゥルメンテーション付き Go ターゲットが必要ですか? このレッスンでは、Go-Fuzz を使用して LibFuzzer インストゥルメンテーション付き Go ターゲットをコンパイルする方法を順を追って説明します。
学習時間の目安: 15 分
このレッスンを終了すると、以下のことができるようになります。
- 到達可能なアサーションの欠陥がある go-fuzz を使用した libFuzzer インストゥルメンテーション付き Go ターゲットをコンパイルし、ファジングする。
- インデックス境界外の欠陥がある go-fuzz を使用した libFuzzer インストゥルメンテーション付き Go ターゲットをコンパイルし、ファジングする。
レッスンを駆け足で
始める前に前提条件を確認します。
-
go-go-fuzz.tgz をダウンロードし、
go-go-fuzz
Docker イメージをビルドし、指定された Docker レジストリにプッシュします。docker build -f Dockerfile -t <DOCKERHUB_USERNAME>/go-go-fuzz . docker push <DOCKERHUB_USERNAME>/go-go-fuzz
docker build -f Dockerfile -t $MAYHEM_DOCKER_REGISTRY/forallsecure/go-go-fuzz . docker push $MAYHEM_DOCKER_REGISTRY/forallsecure/go-go-fuzz
-
Mayhem UI または Mayhem CLI で次の Mayhemfile を使用して
go-go-fuzz
Docker イメージに対して Mayhem ランを実行します。1 2 3 4 5
image: <DOCKERHUB_USERNAME>/go-go-fuzz:latest project: mayhem-examples target: go-go-fuzz cmds: - cmd: /go/mayhemit.libfuzzer
1 2 3 4 5
image: $MAYHEM_DOCKER_REGISTRY/forallsecure/go-go-fuzz:latest project: mayhem-examples target: go-go-fuzz cmds: - cmd: /go/mayhemit.libfuzzer
以下が必要です。
- Docker がインストールされていること
- 有効なインターネット接続 (Docker Hub ベース イメージをプルするため)
ワン クリック テスト¶
次のボタンをクリックし、Create New Run フローの最後で Start Run をクリックして、 go-fuzz を使用してインストゥルメントされた Go ターゲットのテストを開始します。Mayhemfile
はすでに用意されているため、何も設定する必要はありません。
Mayhem ランが始まると、次のようなラン ページが表示されます。
すばらしい! Mayhem による libFuzzer を使用してインストゥルメントされた Go ターゲットのテストを確認したので、次に、たった今実行した Mayhem ランの go-go-fuzz
ターゲットをコンパイルし、ファジングする方法を順を追って説明します。
Go-Fuzz を使用した LibFuzzer インストゥルメンテーション付き Go ターゲットのコンパイルとテスト¶
ファイル: go-go-fuzz.tgz
上記の go-go-fuzz.tgz
をダウンロードして展開し、次のバグのある mayhemit.go
プログラムを見てみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
|
注目するべき 2 つの関数 Fuzz
および mayhemit
があるのがわかります。Fuzz
関数は go-fuzz
ファザーへのエントリポイントとして機能し、行 18 で mayhemit
関数を呼び出して入力テスト ケースが "bug" であるかをチェックします。テスト ケースが "bug" である場合、panic()
関数の行 9 で発生する到達可能なアサーション エラーによってプログラムがクラッシュします。
このプログラムがどのようにコンパイルされるかを見てみましょう。
1 2 3 4 5 6 7 8 |
|
- 行 1:
go-fuzz
およびその依存関係へのアクセスを提供する Docker コンテナーのベース環境としてfuzzers/go-fuzz:1.2.0
ベース イメージが設定されています。 - 行 2: Docker コンテナーに
mayhemit.go
ソース コードがコピーされています。 - 行 3:
go-fuzz-build
コンパイラを使用してmayhemit
ソース コードが実行ファイルにコンパイルされています。このケースでは、go-fuzz-build
コンパイラは libFuzzer と共に使用可能な libFuzzer アーカイブを出力します。 - 行 8: ビルドされた Docker イメージのデフォルト実行ファイルとして
/go/mayhemit.libfuzzer
実行ファイルが設定されています。
次に、go-go-fuzz
フォルダーから次の docker
コマンドを実行して <DOCKERHUB_USERNAME>/go-go-fuzz
Docker イメージをビルドし、Docker Hub レジストリにプッシュします。
次に、go-go-fuzz
フォルダーから次の docker
コマンドを実行して forallsecure/go-go-fuzz
Docker イメージをビルドし、Mayhem Docker レジストリにプッシュします。
docker build -f Dockerfile -t <DOCKERHUB_USERNAME>/go-go-fuzz .
docker push <DOCKERHUB_USERNAME>/go-go-fuzz
docker build -f Dockerfile -t $MAYHEM_DOCKER_REGISTRY/forallsecure/go-go-fuzz .
docker push $MAYHEM_DOCKER_REGISTRY/forallsecure/go-go-fuzz
情報
mayhem login
コマンドを使用して内部的な Mayhem Docker レジストリの URL を検索し、次のコマンドを使用して DOCKER_REGISTRY
環境変数を設定できます:
export DOCKER_REGISTRY=tutorial.forallsecure.com:5000
DOCKER_REGISTRY
環境変数に自身の Mayhem Docker レジストリ URL を設定する必要があります。
Docker イメージが正常にプッシュされたら、Mayhem UI に移動し、新規 Mayhem ランのソースとして Docker Hub を選択します。先ほどアップロードした <DOCKERHUB_USERNAME>/go-go-fuzz
Docker イメージを検索し、Mayhemfile
が次のようになっていることを確認します。
Docker イメージが正常にプッシュされたら、Mayhem UI に移動し、新規 Mayhem ランのソースとして Mayhem Docker Registry を選択します。先ほどアップロードした forallsecure/go-go-fuzz
Docker イメージを検索し、Mayhemfile
が次のようになっていることを確認します。
1 2 3 4 5 |
|
1 2 3 4 5 |
|
次に、新規ランの作成フローの最後に到達するまで [Next] をクリックし、[Click Start] ボタンをクリックして Go ターゲットのテストを開始します。次のようなラン ページが表示されます。
おめでとうございます! go-fuzz インストゥルメンテーション付き Go ターゲットのファジングが成功しました。
⚡ 現実的な演習: Go-Fuzz を使用した mayhemit-out-of-bounds
LibFuzzer Go ターゲットのビルドとテスト¶
go-fuzz を使用した libFuzzer インストゥルメンテーション付き Go ターゲットのビルドおよびテスト方法がわかったところで、ソース コードを修正して到達可能なアサーションの欠陥ではなくインデックス境界外の欠陥を検出できるかどうかやってみましょう。
ファイル: mayhemit-out-of-bounds-unsolved.zip
手順
mayhemit.go
ソース コードを変更し、配列境界外欠陥を追加します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
docker build
コマンドを使用して Dockerfile を再ビルドし、結果の Docker イメージを<DOCKERHUB_USERNAME>/go-go-fuzz-mayhemit-out-of-bounds
としてタグ付けします。docker push
コマンドを使用してパブリックな Docker Hub レジストリに<DOCKERHUB_USERNAME>/go-go-fuzz-mayhemit-out-of-bounds
Docker イメージをプッシュします。- Mayhem UI または Mayhem CLI を使用して
<DOCKERHUB_USERNAME>/go-go-fuzz-mayhemit-out-of-bounds
Docker イメージをファジングします。Mayhemfile
が適切に設定されていることを確認します。
docker build
コマンドを使用して Dockerfile を再ビルドし、結果の Docker イメージを$MAYHEM_DOCKER_REGISTRY/go-go-fuzz-mayhemit-out-of-bounds
としてタグ付けします。docker push
コマンドを使用してプライベートな Mayhem Docker レジストリに$MAYHEM_DOCKER_REGISTRY/go-go-fuzz-mayhemit-out-of-bounds
Docker イメージをプッシュします。- Mayhem UI または Mayhem CLI を使用して
$MAYHEM_DOCKER_REGISTRY/go-go-fuzz-mayhemit-out-of-bounds
Docker イメージをテストします。Mayhemfile
が適切に設定されていることを確認します。
🔍 確認Go-Fuzz を使用した mayhemit-out-of-bounds
LibFuzzer Go ターゲットのビルドとテスト¶
解答
模範解答: mayhemit-out-of-bounds-solved.zip
まず、mayhemit
関数をファジングしたとき、入力テスト ケース "bug" がインデックス境界外エラーを発生させるよう、最大長の制約 len(content) < 5
および誤った呼び出し content[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 |
|
次に、Dockerfile
と同じディレクトリで docker build
コマンドを実行し、結果の Docker イメージに <DOCKERHUB_USERNAME>/go-go-fuzz-mayhemit-out-of-bounds
というタグを付けます。
次に、Dockerfile
と同じディレクトリで docker build
コマンドを実行し、結果の Docker イメージに $MAYHEM_DOCKER_REGISTRY/go-go-fuzz-mayhemit-out-of-bounds` というタグを付けます。
docker build -f Dockerfile -t <DOCKERHUB_USERNAME>/go-go-fuzz-mayhemit-out-of-bounds .
docker build -f Dockerfile -t $MAYHEM_DOCKER_REGISTRY/go-go-fuzz-mayhemit-out-of-bounds .
次に、<DOCKERHUB_USERNAME>/go-go-fuzz-mayhemit-out-of-bounds
Docker イメージにタグを付けてパブリックな Docker Hub レジストリにプッシュします。
次に、$MAYHEM_DOCKER_REGISTRY/go-go-fuzz-mayhemit-out-of-bounds
Docker イメージにタグを付けてプライベートな Mayhem Docker レジストリにプッシュします。
docker push <DOCKERHUB_USERNAME>/tutorial/go-go-fuzz-mayhemit-out-of-bounds
docker push $MAYHEM_DOCKER_REGISTRY/go-go-fuzz-mayhemit-out-of-bounds
Note
この例では、go-go-fuzz-mayhemit-out-of-bounds
Docker イメージを tutorial.forallsecure.com
Mayhem デプロイメントのポート 5000
にあるプライベートな Mayhem Docker レジストリにアップロードしています。Docker イメージを正常にアップロードするには、URL を自身の Docker レジストリに変更する必要があります。
別の方法として、付属の Makefil を使用し、
MAYHEM_DOCKER_REGISTRY` 環境変数を設定して次のコマンドを実行することで、簡単に結果の Docker イメージをビルドし、プッシュすることもできます。
make build
make push
最後に、Mayhem UI または Mayhem CLI を使用して、アップロードされた <DOCKERHUB_USERNAME>/go-go-fuzz-mayhemit-out-of-bounds
Docker イメージに対して Mayhem ランを実行します。Mayhemfile
は次のようになっているはずです。
最後に、Mayhem UI または Mayhem CLI を使用して、アップロードされた $MAYHEM_DOCKER_REGISTRY/go-go-fuzz-mayhemit-out-of-bounds
Docker イメージに対して Mayhem ランを実行します。Mayhemfile
は次のようになっているはずです。
1 2 3 4 5 6 7 |
|
1 2 3 4 5 6 7 |
|
最終的なラン ページは次のように表示されるはずです。
おめでとうございます! Mayhem がインデックス境界外の欠陥を発見しました。スクラッチから go-fuzz を使用した libFuzzer インストゥルメンテーション付き Go ターゲットをビルドし、Mayhem を使用してバグを検出できました。
✏️ まとめと振り返り¶
このレッスンでは、Mayhem で go-fuzz を使用した libFuzzer インストゥルメンテーション付き Go ターゲットをコンパイルし、テストする方法を学びました。
学習内容
1. Go-Fuzz を使用した LibFuzzer インストゥルメンテーション付き Go ターゲットをコンパイルおよびテストして到達可能なアサーションの欠陥を検出する。
-
ソース コードには次の欠陥が含まれているはずです:
1 2 3 4 5 6 7 8 9 10 11 12 13
func mayhemit(bytes []byte) int { content := string(bytes) if len(content) >= 3 { if string(content[0]) == "b" { if string(content[1]) == "u" { if string(content[2]) == "g" { panic("found a bug!") } } } } return 0 }
-
libFuzzer Go ターゲットをファジングするには、次の
Dockerfile
およびMayhemfile
を使用して Go 実行ファイルを含む Docker イメージをビルドし、Mayhem でファジングを実行します。1 2 3 4 5 6 7 8
FROM fuzzers/go-fuzz:1.2.0 COPY mayhemit.go . RUN go-fuzz-build -libfuzzer -o mayhemit.a && \ clang -fsanitize=fuzzer mayhemit.a -o mayhemit.libfuzzer # Set to fuzz! ENTRYPOINT [] CMD ["/go/mayhemit.libfuzzer"]
1 2 3 4 5
image: <DOCKERHUB_USERNAME>/go-go-fuzz:latest project: mayhem-examples target: go-go-fuzz cmds: - cmd: /go/mayhemit.libfuzzer
1 2 3 4 5
image: $MAYHEM_DOCKER_REGISTRY/forallsecure/go-go-fuzz:latest project: mayhem-examples target: go-go-fuzz cmds: - cmd: /go/mayhemit.libfuzzer
2. Go-Fuzz を使用した LibFuzzer インストゥルメンテーション付き Go ターゲットをコンパイルおよびファジングしてインデック境界外の欠陥を検出する。
-
ソース コードには次の欠陥が含まれているはずです:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
func mayhemit(bytes []byte) int { content := string(bytes) if len(content) >= 3 && len(content) < 5 { if string(content[0]) == "b" { if string(content[1]) == "u" { if string(content[2]) == "g" { var x = content[10] fmt.Println(x) } } } } return 0 }
-
libFuzzer Go ターゲットをファジングするには、次の
Dockerfile
およびMayhemfile
を使用して Go 実行ファイルを含む Docker イメージをビルドし、Mayhem でファジングを実行します。1 2 3 4 5 6 7 8
FROM fuzzers/go-fuzz:1.2.0 COPY mayhemit.go . RUN go-fuzz-build -libfuzzer -o mayhemit.a && \ clang -fsanitize=fuzzer mayhemit.a -o mayhemit.libfuzzer # Set to fuzz! ENTRYPOINT [] CMD ["/go/mayhemit.libfuzzer"]
1 2 3 4 5 6 7
image: <DOCKERHUB_USERNAME>/go-go-fuzz-mayhemit-out-of-bounds:latest duration: 90 project: mayhem-examples target: go-go-fuzz-mayhemit-out-of-bounds cmds: - cmd: /go/mayhemit.libfuzzer libfuzzer: true
1 2 3 4 5 6 7
image: $MAYHEM_DOCKER_REGISTRY/go-go-fuzz-mayhemit-out-of-bounds:latest duration: 90 project: mayhem-examples target: go-go-fuzz-mayhemit-out-of-bounds cmds: - cmd: /go/mayhemit.libfuzzer libfuzzer: true