上級
AFL/AFL++ を使用してインストゥルメントされた C/C++ ターゲット¶
Google の AFL インストゥルメンテーションまたはさらに拡張された AFL++ インストゥルメンテーション付きでターゲットをコンパイルする必要がありますか? このレッスンでは、AFL/AFL++ インストゥルメンテーション付きで C/C++ ターゲットをコンパイルし、結果のバイナリを Mayhem でテストする方法を順を追って説明します。
学習時間の目安: 15 分
このレッスンを終了すると、以下のことができるようになります。
- AFL インストゥルメンテーション付き C ターゲットをコンパイルし、ファジングする。
- AFL++ インストゥルメンテーション付き C ターゲットをコンパイルし、ファジングする。
- AFL インストゥルメンテーション付き C++ ターゲットをコンパイルし、ファジングする。
レッスンを駆け足で
始める前に前提条件を確認します。
-
c-afl-gcc.tgz をダウンロードし、
c-afl-gcc
Docker イメージをビルドし、指定された Docker レジストリにプッシュします。docker build -t <DOCKERHUB_USERNAME>/c-afl-gcc . docker push <DOCKERHUB_USERNAME>/c-afl-gcc
docker build -t $MAYHEM_DOCKER_REGISTRY/forallsecure/c-afl-gcc . docker push $MAYHEM_DOCKER_REGISTRY/forallsecure/c-afl-gcc
-
Mayhem UI または Mayhem CLI で次の Mayhemfile を使用して
c-afl-gcc
Docker イメージに対して Mayhem ランを実行します。1 2 3 4 5 6 7
image: <DOCKERHUB_USERNAME>/c-afl-gcc:latest duration: 90 project: mayhem-examples target: c-afl-gcc cmds: - cmd: /mayhemit @@ afl: true
1 2 3 4 5 6 7
image: $MAYHEM_DOCKER_REGISTRY/forallsecure/c-afl-gcc:latest duration: 90 project: mayhem-examples target: c-afl-gcc cmds: - cmd: /mayhemit @@ afl: true
以下が必要です。
- Docker がインストールされていること
- 有効なインターネット接続 (Docker Hub ベース イメージをプルするため)
ワン クリック テスト¶
次のボタンをクリックし、Create New Run フローの最後で Start Run をクリックして AFL インストゥルメンテーション付き C ターゲットのテストを開始します。Mayhemfile
はすでに用意されているため、何も設定する必要はありません。
Mayhem ランが始まると、次のようなラン ページが表示されます。
すばらしい! Mayhem が AFL を使用してインストゥルメントされた C ターゲットをテストできることを確認したので、次に、たった今実行した Mayhem ランの c-afl-gcc
ターゲットをコンパイルし、テストする方法を順を追って説明します。
AFL インストゥルメンテーション付き C ターゲットのコンパイルとテスト¶
ファイル: c-afl-gcc.tgz
上記の c-afl-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 27 28 29 30 31 32 33 34 35 36 |
|
Note
すでに c-uninstrumented
ターゲットをよく知っている場合、ソース コードがまったく同じであることに気づくでしょう。では、C-AFL ターゲットの違いは何でしょうか? 違いは、プログラムのコンパイル方法にあります (少なくとも AFL の場合)。
関連する Dockerfile
を見てみると、次の操作があります。
1 2 3 4 5 6 7 8 |
|
- 行 1: 新規 Docker コンテナーのベース イメージとして
fuzzers/afl:2.52
イメージがインポートされています。 - 行 2: Docker コンテナーに
mayhemit.c
ソース コードがコピーされています。 - 行 3:
afl-gcc
C コンパイラによってmayhemit.c
がコンパイルされ、AFL インストゥルメンテーションが付加されてmayhemit
実行ファイルになります。 - 行 8: Docker コンテナーのデフォルト実行ファイルとして
/mayhemit @@
コマンドが設定されています。
Note
行 7 のエントリポイント コードは、コンテナーが実行されるとき、(デバッグ目的で) AFL が Docker コンテナー内でローカルに mayhemit
実行ファイルをファジングできるようにするためにあります。Docker コンテナーをビルドしたら、docker run -it <container>
コマンドを実行して動作を確認します。 Mayhem でエントリポイント スクリプトを実行する方法の詳細については、「Mayhem での Docker エントリポイントのサポート」を参照してください。
あとは、これまでと同じように、Docker イメージをビルドして Docker レジストリにプッシュするだけです。
docker build -t <DOCKERHUB_USERNAME>/c-afl-gcc .
docker push <DOCKERHUB_USERNAME>/c-afl-gcc
docker build -t $MAYHEM_DOCKER_REGISTRY/forallsecure/c-afl-gcc .
docker push $MAYHEM_DOCKER_REGISTRY/forallsecure/c-afl-gcc
最後に、<DOCKERHUB_USERNAME>/c-afl-gcc
Docker イメージを検索し、Mayhem UI で新規ランの作成フローに従って、Mayhem で 新しい Docker イメージのファジングを実行します。
最後に、forallsecure/c-afl-gcc
Docker イメージを検索し、Mayhem UI で新規ランの作成フローに従って、Mayhem で 新しい Docker イメージのファジングを実行します。
ランの Mayhemfile
が次のようになっていることを確認します。
1 2 3 4 5 6 7 |
|
1 2 3 4 5 6 7 |
|
よくできました! AFL インストゥルメンテーション付き C ターゲットのコンパイルとテストが成功しました。
AFL++ インストゥルメンテーション付き C ターゲットのコンパイルとテスト¶
ファイル: c-aflpp-gcc.tgz
今度は、前に使用した mayhemit.c
ソース コードを AFL++ インストゥルメンテーション付きでコンパイルします。ソース コードは同じであるため、afl-g++-fast
コンパイラを使用するだけです。
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 34 35 36 |
|
c-aflpp-gcc
フォルダーに移動し、c-aflpp-gcc
ターゲットの Dockerfile
を見てみましょう。
c-aflpp-gcc
ターゲットをビルドするプロセスは c-afl-gcc
ターゲットのビルドとほとんど同じであることがわかるでしょう。違いは、行 1 で AFL++ 依存関係を含む fuzzers/aflplusplus:3.12c
ベース イメージをインポートしていることと、行 3 で afl-gcc-fast
コンパイラを使用して mayhemit.c
ソース コードをコンパイルしていることです。
1 2 3 4 5 6 7 8 |
|
次に、mayhemit/c-aflpp-gcc
Docker イメージをビルドし、Mayhem Docker レジストリにプッシュする必要があります。
次に、mayhemit/c-aflpp-gcc
Docker イメージをビルドし、Mayhem Docker レジストリにプッシュする必要があります。
docker build -t <DOCKERHUB_USERNAME>/c-aflpp-gcc .
docker push <DOCKERHUB_USERNAME>/c-aflpp-gcc
docker build -t $DOCKER_REGISTRY/forallsecure/c-aflpp-gcc .
docker push $DOCKER_REGISTRY/forallsecure/c-aflpp-gcc
その後、新規 Mayhem ランのソースとして <DOCKERHUB_USERNAME>/c-aflpp-gcc
Docker イメージを選択し、Mayhemfile
が次のようになっていることを確認します。
その後、新規 Mayhem ランのソースとして forallsecure/c-aflpp-gcc
Docker イメージを選択し、Mayhemfile
が次のようになっていることを確認します。
1 2 3 4 5 6 7 |
|
1 2 3 4 5 6 7 |
|
最後に、Mayhem UI で新規 <DOCKERHUB_USERNAME>/c-aflpp-gcc
Docker イメージをファジングします。
最後に、Mayhem UI で新規 forallsecure/c-aflpp-gcc
Docker イメージをファジングします。
⚡ 現実的な演習: AFL インストゥルメンテーション付き C++ ターゲットのコンパイルとテスト¶
ファイル: cpp-afl-gcc.tgz
AFL および AFL++ インストゥルメンテーション付き C ターゲットのコンパイルおよびテスト手順がわかったので、次に、同じことを C++ ターゲットに対して行うことができるか、やってみましょう。
手順
- 上記の
cpp-afl-gcc.tgz
をダウンロードし、cpp-afl-gcc
フォルダーを展開します。 cpp-afl-gcc
フォルダーに移動し、<DOCKERHUB_USERNAME>/cpp-afl-gcc
ターゲットをビルドして Docker Hub にプッシュします。-
最後に、Mayhem UI から、新しくアップロードした
<DOCKERHUB_USERNAME>/cpp-afl-gc
Docker イメージをファジングします。 -
上記の
cpp-afl-gcc.tgz
をダウンロードし、cpp-afl-gcc
フォルダーを展開します。 cpp-afl-gcc
フォルダーに移動し、forallsecure/cpp-afl-gcc
ターゲットをビルドして Mayhem にプッシュします。- 最後に、Mayhem UI から、新しくアップロードした
forallsecure/cpp-afl-gc
Docker イメージをテストします。
🔍 確認 AFL インストゥルメンテーション付き C++ ターゲットのコンパイルとテスト¶
解答
結果を確認しましょう。まず、cpp-afl-gcc
ターゲットの 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 27 28 29 30 31 32 33 34 35 36 |
|
ソース コードはこれまでの c-afl-gcc
および c-aflpp-gcc
ターゲットとほとんど同じですが、C++ の iostream
ヘッダー ファイルを使用している点が異なります。
対応する Dockerfile
を見ると、AFL インストゥルメンテーション付きで mayhemit.cpp
ソース ファイルをコンパイルするには、afl-g++
コンパイラを使用する必要があることがわかります。
1 2 3 4 5 6 7 8 |
|
次に、Docker イメージをビルドしてパブリックな Docker Hub レジストリにプッシュします。
次に、Docker イメージをビルドして Mayhem Docker レジストリにプッシュします。
docker build -t <DOCKERHUB_USERNAME>/cpp-afl-gcc .
docker push <DOCKERHUB_USERNAME>/cpp-afl-gcc
docker build -t $MAYHEM_DOCKER_REGISTRY/mayhemit/cpp-afl-gcc .
docker push $MAYHEM_DOCKER_REGISTRY/mayhemit/cpp-afl-gcc
Docker Hub にプッシュしたら、Mayhem UI を使用して新規ランを作成し、ソースとして <DOCKERHUB_USERNAME>/cpp-afl-gcc
Docker イメージを指定します。Mayhemfile
は次のようになります。
Mayhem Docker レジストリにプッシュしたら、Mayhem UI を使用して新規ランを作成し、ソースとして forallsecure/cpp-afl-gcc
Docker イメージを指定します。Mayhemfile
は次のようになります。
1 2 3 4 5 6 7 |
|
1 2 3 4 5 6 7 |
|
最後に、Mayhem ランを開始すると、次のようなラン ページが表示されます。よくできました!
✏️ まとめと振り返り¶
このレッスンでは、AFL/AFL++ インストゥルメンテーション付きで C/C++ ターゲットをコンパイルし、Mayhem でファジングする方法を説明しました。
学習内容
1. AFL インストゥルメンテーション付き C ターゲットのコンパイルとテスト。
-
ソース コードには次の欠陥が含まれているはずです:
1 2 3 4 5 6 7 8 9 10 11
int mayhemit(char *buf) { if(strlen(buf) >= 3) if(buf[0] == 'b') if(buf[1] == 'u') if(buf[2] == 'g') { printf("You've got it!"); abort(); // Defect: SIGABRT. } return 0; }
-
C AFL ターゲットをファジングするには、次の
Dockerfile
およびMayhemfile
を使用して C プログラムを含む Docker イメージをビルドし、Mayhem でファジングを実行します。1 2 3 4 5 6 7 8
FROM fuzzers/afl:2.52 COPY mayhemit.c . RUN afl-gcc mayhemit.c -o /mayhemit RUN mkdir /testsuite && echo seed > /testsuite/seed # Set to fuzz! ENTRYPOINT ["afl-fuzz", "-i", "/testsuite", "-o", "/out"] CMD ["/mayhemit", "@@"]
1 2 3 4 5 6 7
image: <DOCKERHUB_USERNAME>/c-afl-gcc:latest duration: 90 project: mayhem-examples target: c-afl-gcc cmds: - cmd: /mayhemit @@ afl: true
1 2 3 4 5 6 7
image: $MAYHEM_DOCKER_REGISTRY/forallsecure/c-afl-gcc:latest duration: 90 project: mayhem-examples target: c-afl-gcc cmds: - cmd: /mayhemit @@ afl: true
2. AFL++ インストゥルメンテーション付き C ターゲットのコンパイルとテスト。
-
ソース コードには次の欠陥が含まれているはずです:
1 2 3 4 5 6 7 8 9 10 11
int mayhemit(char *buf) { if(strlen(buf) >= 3) if(buf[0] == 'b') if(buf[1] == 'u') if(buf[2] == 'g') { printf("You've got it!"); abort(); // Defect: SIGABRT. } return 0; }
-
C AFL++ ターゲットをファジングするには、次の
Dockerfile
およびMayhemfile
を使用して C プログラムを含む Docker イメージをビルドし、Mayhem でファジングを実行します。1 2 3 4 5 6 7 8
FROM fuzzers/aflplusplus:3.12c COPY mayhemit.c . RUN afl-gcc-fast mayhemit.c -o /mayhemit RUN mkdir /testsuite && echo seed > /testsuite/seed # Set to fuzz! ENTRYPOINT ["afl-fuzz", "-i", "/testsuite", "-o", "/out"] CMD ["/mayhemit", "@@"]
1 2 3 4 5 6 7
image: <DOCKERHUB_USERNAME>/c-aflpp-gcc:latest duration: 90 project: mayhem-examples target: c-aflpp-gcc cmds: - cmd: /AFLplusplus/mayhemit @@ afl: true
1 2 3 4 5 6 7
image: $MAYHEM_DOCKER_REGISTRY/forallsecure/c-aflpp-gcc:latest duration: 90 project: mayhem-examples target: c-aflpp-gcc cmds: - cmd: /AFLplusplus/mayhemit @@ afl: true
3. AFL インストゥルメンテーション付き C++ ターゲットのコンパイルとテスト。
-
ソース コードには次の欠陥が含まれているはずです:
1 2 3 4 5 6 7 8 9 10 11
int mayhemit(char *buf) { if(strlen(buf) >= 3) if(buf[0] == 'b') if(buf[1] == 'u') if(buf[2] == 'g') { printf("You've got it!"); abort(); // Defect: SIGABRT. } return 0; }
-
C++ AFL ターゲットをファジングするには、次の
Dockerfile
およびMayhemfile
を使用して C++ プログラムを含む Docker イメージをビルドし、Mayhem でファジングを実行します。1 2 3 4 5 6 7 8
FROM fuzzers/afl:2.52 COPY mayhemit.cpp . RUN afl-g++ mayhemit.cpp -o /mayhemit RUN mkdir /testsuite && echo seed > /testsuite/seed # Set to fuzz! ENTRYPOINT ["afl-fuzz", "-i", "/testsuite", "-o", "/out"] CMD ["/mayhemit", "@@"]
1 2 3 4 5 6 7
image: <DOCKERHUB_USERNAME>/cpp-afl-gcc:latest duration: 90 project: mayhem-examples target: cpp-afl-gcc cmds: - cmd: /mayhemit @@ afl: true
1 2 3 4 5 6 7
image: $MAYHEM_DOCKER_REGISTRY/forallsecure/cpp-afl-gcc:latest duration: 90 project: mayhem-examples target: cpp-afl-gcc cmds: - cmd: /mayhemit @@ afl: true