コンテンツにスキップ

上級

Mayhem で libFuzzer、AFL、honggfuzz OSS ファザーを使用する

llvm-logo google-logo

このレッスンでは、最も広く利用されている 3 つのオープン ソース ソフトウェアのファジング フレームワークである libFuzzerAFL および honggfuzz を Mayhem とともに使用する方法を順を追って学びます。


学習時間の目安: 15 分

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

  1. AFL、libFuzzer、および honggfuzz ファジング フレームワークについて説明する。
  2. testme ターゲットで各ファジング フレームワークを使用するための Mayhemfile を構成する。
  3. 各ファジング フレームワークを使用して testme ターゲットに対して Mayhem ランを実行する。

レッスンを駆け足で

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

  1. mayhem package コマンドを使用して、libFuzzer インストゥルメンテーション付きの testme バイナリをパッケージ化します。

    mayhem package ./testme -o /tmp/libfuzzer-pkg
    
  2. mayhem run コマンドに次の Mayhemfile を指定して、libFuzzer インストゥルメンテーション付きの testme バイナリに対して Mayhem ランを実行します。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    project: libfuzzer
    target: testme
    duration: 90
    advanced_triage: false
    
    cmds:
      - cmd: /root/tutorial/oss-fuzzers/libfuzzer/testme
        libfuzzer: true
        sanitizer: true
    
  3. mayhem package コマンドを使用して、afl インストゥルメンテーション付きの testme バイナリをパッケージ化します。

    mayhem package ./testme -o /tmp/afl-pkg
    
  4. mayhem run コマンドに次の Mayhemfile を指定して、afl インストゥルメンテーション付きの testme バイナリに対して Mayhem ランを実行します。

    1
    2
    3
    4
    5
    6
    7
    8
    project: afl
    target: testme
    duration: 90
    advanced_triage: false
    
    cmds:
      - cmd: /root/tutorial/oss-fuzzers/afl/testme @@
        afl: true
    
  5. mayhem package コマンドを使用して、honggfuzz インストゥルメンテーション付きの (hfuzz-clang を使用してコンパイルされた) testme バイナリをパッケージ化します。

    mayhem package ./testme -o /tmp/hfuzz-libfuzzer-pkg
    
  6. mayhem run コマンドに次の Mayhemfile を指定して、honggfuzz インストゥルメンテーション付きの (hfuzz-clang を使用してコンパイルされた) testme バイナリに対して Mayhem ランを実行します。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    project: honggfuzz-libfuzzer
    target: testme
    duration: 90
    advanced_triage: false
    
    cmds:
        - cmd: /root/tutorial/oss-fuzzers/honggfuzz-libfuzzer/testme
          honggfuzz: true
          sanitizer: true
    
  7. mayhem package コマンドを使用して、honggfuzz インストゥルメンテーション付きの (hfuzz-gcc を使用してコンパイルされた) testme バイナリをパッケージ化します。

    mayhem package ./testme -o /tmp/honggfuzz-pkg
    
  8. mayhem run コマンドに次の Mayhemfile を指定して、honggfuzz インストゥルメンテーション付きの (hfuzz-gcc を使用してコンパイルされた) testme バイナリに対して Mayhem ランを実行します。

    1
    2
    3
    4
    5
    6
    7
    8
    project: honggfuzz
    target: testme
    duration: 90
    advanced_triage: false
    
    cmds:
        - cmd: /root/tutorial/oss-fuzzers/honggfuzz/testme
          honggfuzz: true
    

以下が必要です。

  • Mayhem CLI がインストールされ、Mayhem サーバーで認証済みであること。
  • あらかじめビルドされた Docker イメージを実行し、チュートリアル サンプルにアクセスできること。

    docker pull forallsecure/tutorial:2.10
    docker run -ti --privileged --rm forallsecure/tutorial:2.10
    

LibFuzzer を使用したファジング

LibFuzzer は、LLVM プロジェクトによって開発されたインプロセスのファザーです。インプロセスのファザーは、呼び出しのたびに fork() を使用してプログラムを再実行するのではなく、同じインメモリ プロセス内で新しい入力を使用して反復的にターゲットを呼び出します。

このサンプルをビルドし、実行するには、oss-fuzzers/libfuzzer ディレクトリに移動 (cd) します。次に示す、新しいバージョンの testme.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 testme(char *buf, unsigned len)
{
  unsigned ok;
  char *ptr = (char *) buf[0]; // Added for clang

  if(!ok) // Defect: uninitialized use of ok.
    ok = len;

  if (len < 3) return 1;

  if(buf[0] == 'b')
    if(buf[1] == 'a')
      if(buf[2] == 'd') {
        return (*ptr == 0x0);      // Defect: OOB reference.
      }
  return 0;
}

int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size)
{
  testme((char *) Data, Size);
  return 0;
}

変更点は次のとおりです。

  • 行 17: 以前の testme.cabort() 関数を使用して不適切な入力検証の欠陥を作成していました。この abort() 関数が、無効なメモリアクセスに置き換えられました。

  • 行 22-26: LibFuzzer では、テスト ドライバーを作成する必要があります。テスト ドライバーについては、後ほどより詳しく説明します。今のところは、 テスト対象の関数を指定し、Data および Size という 2 つの引数を渡す必要があるという点が重要です。2 つの引数には、ファザーによって値が入力されます。

Mayhem で LibFuzzer を使用するには、実行対象コマンド (cmd) に libfuzzer: true を指定する必要があります。さらに、sanitizer: true を使用し、ターゲットがサニタイザーを使用してビルドされることを指定します。

Note

どのサニタイザーの場合でも (UndefinedBehaviorSanitizer、AddressSanitizer、MemorySanitizer など) sanitizer: true を使用します。

Mayhemfile 全体は次のようになります。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
# A user-meaningful name to group like targets
project: libfuzzer

# A user-meaningful name of the target
target: testme-libfuzzer

# Time to spend fuzzing.
duration: 90

# Perform advanced triage and diagnosis of each test case.
advanced_triage: false

# List of executable programs to analyze.  For most use, you only
# need one.
cmds:

    # The full path to the executable program to test.
    #
    # libfuzzer targets do not accept a filename.
    - cmd: /root/tutorial/oss-fuzzers/libfuzzer/testme
      libfuzzer: true   # this is a libfuzzer target
      sanitizer: true        # A sanitizer was used (the average case)

Mayhem を実行するには、次のコマンドを実行します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
#!/bin/sh

# Package testme.
mayhem package ./testme -o /tmp/libfuzzer-pkg

# Copy over our Mayhemfile
cp Mayhemfile /tmp/libfuzzer-pkg

# Copy over our tests
cp testsuite/* /tmp/libfuzzer-pkg/testsuite/

# Run mayhem. The run ID is saved to $id
id=$(mayhem run /tmp/libfuzzer-pkg)

# Wait for the run to finish
mayhem wait $id

# Sync the test suite to the "testsuite" directory.
mayhem sync /tmp/libfuzzer-pkg

Mayhem UI に移動すると、Mayhem がターゲットをファジングしているのがわかります。

AFL を使用したファジング

AFL は、よく知られたプロセスベースのファザーです。AFL を使用するには、AFL ツールチェーンを使用してアプリケーションを再ビルドする必要があります。ツールチェーンは AFL インストゥルメンテーションを実行ファイルにインライン化し、それがファザーのガイドとして使用されます。

このサンプルをビルドし、実行するには、oss-fuzzers/afl ディレクトリに移動 (cd) します。ディレクトリには以下のファイルがあります。

  • testme.c - これまでのレッスンで使用したものと同じ、脆弱性のあるアプリケーションです。
  • Makefile - AFL インストゥルメンテーション付きでターゲットをビルドするための UNIX Makefile ファイルです。afl-gcc コマンド - これまでのサンプルど同様に gcc を使用します。ターゲットをビルドするには、make clean && make を実行します。

  • Mayhemfile - 内容は下記のとおりです。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# A user-meaningful name to group like targets
project: afl

# A user-meaningful name of the target
target: testme-afl

# Time to spend fuzzing.
duration: 90

# Perform advanced triage and diagnosis of each test case.
advanced_triage: false

# List of executable programs to analyze.  For most use, you only
# need one.
cmds:

    # The full path to the executable program to test.
    #   - "@@" is the  to test.
    #     For programs that take input from a file, use '@@' to mark
    #     the location in the target's command line where the input
    #     file name should be placed. Mayhem will substitute this
    #     for you.
    - cmd: /root/tutorial/oss-fuzzers/afl/testme @@
      afl: true

Mayhemfileafl: true が追加されていることに注目してください。これは、ターゲットが AFL を使用してコンパイルされていることを Mayhem に通知します。

Mayhem を実行するには、次のコマンドを実行します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
#!/bin/sh

# Package testme-v1 library dependencies.
mayhem package ./testme -o /tmp/afl-pkg

# Copy over our Mayhemfile
cp Mayhemfile /tmp/afl-pkg

# Run mayhem. The run ID is saved to $id
id=$(mayhem run /tmp/afl-pkg)

# Wait for the run to finish
mayhem wait $id

# Sync the test suite to the "testsuite" directory.
mayhem sync /tmp/afl-pkg

Mayhem UI に移動すると、Mayhem がターゲットをファジングしているのがわかります。

honggfuzz を使用したファジング

Honggfuzz は、いくつかの解析オプションを備え、先進的で使いやすいセキュリティ志向のフィードバック駆動型ファザーです。Honggfuzz は、clang および GCC に対応するコンパイラ ラッパーである hfuzz-clang および hfuzz-gcc を提供します。これらのラッパーを使用すると、さまざまなコンパイル時カバレッジ インストゥルメンテーションの形式でコンパイルできます。

hfuzz-clang または hfuzz-gcc のどちらも同じように使用できます。

Info

Honggfuzz にはいくつかのモードがありますが、このレッスンではLLVMFuzzerTestOneInput または HF_ITER スタイルのテスト ドライバーを使用して honggfuzz persistent モードのバイナリをコンパイルする方法を説明します。詳細については honggfuzz の persistent mode を参照してください。

hfuzz-clang を使用した Honggfuzz (推奨)

Mayhem は、hfuzz-clang を使用してコンパイルされた honggfuzz persistent モード バイナリのファジングをサポートします。このセクションでは、libFuzzer スタイルのテスト ドライバー (LLVMFuzzerTestOneInput など) を使用してコンパイルする方法を説明します。

このサンプルをビルドし、実行するには、oss-fuzzers/honggfuzz-libfuzzer ディレクトリに移動 (cd) します。以下のファイルがあります。

  • testme.c - 上記の libFuzzer サンプルで使用したものと同じ、脆弱性のあるアプリケーションです。
  • Makefile - ターゲットをビルドするための UNIX Makefile ファイルです。Makefilehfuzz-clang を使用します。
  • Mayhemfile - 内容は下記のとおりです。
 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
# A user-meaningful name to group like targets
project: honggfuzz-libfuzzer

# A user-meaningful name of the target
target: testme-honggfuzz-libfuzzer

# Time to spend fuzzing.
duration: 90

# Perform advanced triage and diagnosis of each test case.
advanced_triage: false

# List of executable programs to analyze.  For most use, you only
# need one.
cmds:

    # The full path to the executable program to test.
    # You do not need "@@" for libfuzzer, including under honggfuzz
    # when clang/libfuzzer is used to create.
    #
    # However, you *do* need to include the sanitizer flag with honggfuzz
    # libfuzzer targets.
    - cmd: /root/tutorial/oss-fuzzers/honggfuzz-libfuzzer/testme
      honggfuzz: true
      sanitizer: true

Note

honggfuzz: true および sanitizer: true を指定する必要があります。honggfuzz: true は、honggfuzz ファザーの使用を指示します。sanitizer: true は、ターゲット バイナリがサニタイザー付きでコンパイルされていることを Mayhem に通知します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
#!/bin/sh

# Package testme.
mayhem package ./testme -o /tmp/hfuzz-libfuzzer-pkg

# Copy over our Mayhemfile
cp Mayhemfile /tmp/hfuzz-libfuzzer-pkg

# Copy over our tests
cp testsuite/* /tmp/hfuzz-libfuzzer-pkg/testsuite/

# Run mayhem. The run ID is saved to $id
id=$(mayhem run /tmp/hfuzz-libfuzzer-pkg)

# Wait for the run to finish
mayhem wait $id

# Sync the test suite to the "testsuite" directory.
mayhem sync /tmp/hfuzz-libfuzzer-pkg

Mayhem UI に移動すると、Mayhem がターゲットをファジングしているのがわかります。

Warning

サニタイザー付きのターゲットで sanitizer: true が指定されていない場合、Mayhem は発見されたバグを適切にレポートしません。

hfuzz-gcc を使用した Honggfuzz

Mayhem は、hfuzz-gcc を使用してコンパイルされた honggfuzz persistent モード バイナリのファジングもサポートします。このセクションでは、HF_ITER スタイルのテスト ドライバーを使用してバイナリをコンパイルする方法を説明します。

Info

Mayhem は Honggfuzz インストゥルメンテーション付きでコンパイルされた non-persistent モードのバイナリの実行もサポートしています。ただし、non-persistent モードのバイナリは非インストゥルメンテーションバイナリと同様に扱われるため、推奨されていません。

基本的なサンプルを見てみましょう。oss-fuzzers/honggfuzz ディレクトリに移動 (cd) します。次のファイルがあります。

  • testme.c - 前のレッスンで使用した testme アプリケーションの修正版です。
  • Makefile - ターゲットをビルドするための UNIX Makefile ファイルです。Makefilehfuzz-gcc を使用します。これによって特殊な honggfuzz インストゥルメンテーションが追加されます。
  • Mayhemfile - Mayhem ランの構成ファイルです。
 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 testme(char *buf, unsigned len)
{
  if(len >= 3)
    if(buf[0] == 'b')
      if(buf[1] == 'u')
        if(buf[2] == 'g') {
          return 1/0;      // Defect: divide-by-zero.
        }
  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);

        testme(buf, len);
    }
}

修正された testme.cHF_ITER 関数を使用していることに注目してください。これは、persistent モードのバイナリであることを示しています。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
# A user-meaningful name to group like targets
project: honggfuzz

# A user-meaningful name of the target
target: testme-honggfuzz

# Time to spend fuzzing.
duration: 90

# Perform advanced triage and diagnosis of each test case.
advanced_triage: false

# List of executable programs to analyze.  For most use, you only
# need one.
cmds:

    # The full path to the executable program to test.
    # "@@" should be removed for persistent mode binaries.
    - cmd: /root/tutorial/oss-fuzzers/honggfuzz/testme
      honggfuzz: true

persistent モードの testme バイナリでは、cmd パラメーターから @@ を削除する必要があります。

Mayhem を実行するには、次のコマンドを実行します。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
#!/bin/sh

# Package testme-v1 library dependencies.
mayhem package ./testme -o /tmp/honggfuzz-pkg

# Copy over our Mayhemfile
cp Mayhemfile /tmp/honggfuzz-pkg

# Run mayhem. The run ID is saved to $id
id=$(mayhem run /tmp/honggfuzz-pkg)

# Wait for the run to finish
mayhem wait $id

# Sync the test suite to the "testsuite" directory.
mayhem sync /tmp/honggfuzz-pkg

Mayhem UI に移動すると、Mayhem がターゲットをファジングしているのがわかります。

✏️ まとめと振り返り

このレッスンでは、 AFL、libFuzzer および honggfuzz ファジング フレームワークを使用してターゲットをファジングする方法を学びました。


学習内容

1.AFL、libFuzzer および honggfuzz ファジング フレームワークについて説明します。
  • AFL は、よく知られたプロセスベースのファザーです。AFL を使用するには、AFL ツールチェーンを使用してアプリケーションを再ビルドする必要があります。ツールチェーンは AFL インストゥルメンテーションを実行ファイルにインライン化し、それがファザーのガイドとして使用されます。
  • LibFuzzer は、LLVM プロジェクトによって開発されたインプロセスのファザーです。インプロセスのファザーは、呼び出しのたびに fork() を使用してプログラムを再実行するのではなく、同じインメモリ プロセス内で新しい入力を使用して反復的にターゲットを呼び出します。
  • Honggfuzz は、魅力的な解析オプションを備え、先進的で使いやすいセキュリティ志向のフィードバック駆動型ファザーです。Honggfuzz は、Honggfuzz 独自の hfuzz-gcc や libFuzzer など、異なるインストゥルメンテーション タイプでコンパイルする機能を備えています。
2. testme ターゲットに対してそれぞれのファジング フレームワークを使用するよう Mayhemfile を構成します。
  • AFL Mayhemfile:

    1
    2
    3
    4
    5
    6
    7
    project: afl
    target: testme
    duration: 90
    advanced_triage: false
    cmds:
      - cmd: /root/tutorial/oss-fuzzers/afl/testme @@
        afl: true
    
  • LibFuzzer Mayhemfile:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    project: libfuzzer
    target: testme
    duration: 90
    advanced_triage: false
    
    cmds:
      - cmd: /root/tutorial/oss-fuzzers/libfuzzer/testme
        libfuzzer: true   # this is a libfuzzer target
        sanitizer: true        # A sanitizer was used (the average case)
    
  • Honggfuzz Mayhemfile:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    project: honggfuzz-libfuzzer
    target: testme
    duration: 90
    advanced_triage: false
    
    cmds:
      - cmd: /root/tutorial/oss-fuzzers/honggfuzz-libfuzzer/testme
        honggfuzz: true
        sanitizer: true
    
3.testme ターゲットに対してそれぞれのファジング フレームワークを使用して Mayhem ランを実行します。
  • AFL、libFuzzer および honggfuzz のそれぞれに対して mayhem run コマンドを実行します。