コンテンツにスキップ

エキスパート

バイナリへのパッチによるファジングの改善

このレッスンでは、ソース コードが利用できない場合に、ファジング プロセスを改善するためにバイナリ アプリケーションを変更する方法を、手順を追って説明します。


学習時間の目安: 20 分

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

  1. バイナリにパッチを当てるのが有用な理由を説明する。
  2. imagemagick を使用し、バイナリへのパッチのサンプルを順を追って理解する。

以下が必要です。

  1. Mayhem の動作するコピー。Mayhem CLI がインストールされていること。
  2. あらかじめビルド済みの Docker イメージを実行し、チュートリアル サンプルにアクセスできること。

    docker pull forallsecure/tutorial:2.10
    docker run -ti --privileged --rm forallsecure/tutorial:2.10
    
  3. リバースエンジニアリングの知識。これは上級チュートリアルであるため、アセンブリ レベルのコードに慣れている必要があります。

  4. 指令をパッチできる機能を持った逆アセンブラ。サンプルでは Binary Ninja を使用しています。
  5. このサンプルは、オンライン アクセス、localhost に Docker がインストールされていること、debian:stretch Docker イメージが実行されていることを必要とします。

    docker pull debian:bullseye
    docker run -it debian:bullseye
    

バイナリにパッチを当てる理由

バイナリの変更は、ファジングに必須というわけではありませんが、脆弱性を調査する場合にいくつかの理由からバイナリを変更することがあります。

  1. 1 つのテスト ケースを実行した後にきれいにプログラムを終了できる
  2. 解析を妨げるチェックサムまたは暗号化に関する要素を除去する
  3. 認証チェックを除去する
  4. Mayhem に対象バイナリの特定の関数を直接テストするよう指示する

サンプル 1: チェックサムと imagemagick

次のようにシンプルな入力形式を持つプログラムがあるとします。

  • data: 転送するデータ
  • cksum: data フィールドの 32 ビットのチェックサム

メッセージが有効であるためには、チェックサムが data に対して正しくなければなりません。つまり、datacksum にデータ依存関係があります。 ファジングはそのようなデータ依存関係を考慮しないため、チェックサムが有効であるかをチェックするコードをパスできず、欠陥を検出できません。

解決策は 2 つあります。

  1. テスト ドライバーを経由して入力を渡すことができます。そうすることで、テスト対象プログラムに入力を渡す前に、適切なチェックサムを確実に用意することができます。
  2. バイナリにパッチを当て、チェックサムが無効であっても、すべての入力を受け入れるようにできます。

このチュートリアルでは、imagemagick スイートの convert をサンプルとして使用し、2 番目の方法を試します。

convert

まず、現在実行している debian:stretch Docker コンテナーに次のファイルを移動します。

  1. nsa-insignia-sm.png - 有効な PNG ファイルです。
  2. nsa-insignia-crc-error.png - 無効な CRC チェックサムを持つ PNG ファイルです。

docker ps コマンドを実行して、debian:stretch イメージのコンテナー ID を特定します。

$ docker ps
CONTAINER ID        IMAGE                  COMMAND                  CREATED             STATUS              PORTS                           NAMES
2261333873ac        forallsecure/tutorial  "bash"                   About a minute ago  Up About a minute                                   dazzling_ptolemy
c146984d637b        debian:stretch         "bash"                   13 minutes ago      Up 13 minutes                                       infallible_shannon

Note

debian:stretch イメージの正確なコンテナー ID は、上記とは異なる可能性があります。

次に、チュートリアル Docker コンテナーの /root/tutorial/binary-patching/testsuite ディレクトリをホスト マシンにコピーしてから、次のコマンドを実行してホスト マシンから debian:stretch Docker コンテナーにファイルをコピーします。

docker cp 2261333873ac:/root/tutorial/binary-patching/testsuite /path/on/host/machine
docker cp /path/on/host/machine c146984d637b:/mnt

debian:stretch コンテナー内の /mnt ディレクトリに移動すると、次のファイルがあります。

root@c146984d637b:/mnt# ls -l
total 272
-rw-r--r-- 1 501 dialout 135939 Feb 13 00:34 nsa-insignia-crc-error.png
-rw-r--r-- 1 501 dialout 135629 Feb 13 00:34 nsa-insignia-sm.png

次に、imagemagick の一部である convert コマンドをインストールする必要があります。

$ # Install imagemagick
$ apt-get update && apt-get install -y imagemagick

$ # Go to the /mnt directory, which should now contain the example files
$ cd /mnt

$ # run convert, and observe it works with a well-formed PNG.
$ convert nsa-insignia-sm.png /tmp/out.png

$ # Run convert, and observe it fails with a failing CRC PNG.
$ convert nsa-insignia-crc-error.png /tmp/out.png
convert-im6.q16: IDAT: CRC error `nsa-insignia-crc-error.png` @ error/png.c/MagickPNGErrorHandler/1628.
...

ファザーはテスト スイート入力のバイト列を変化させます。たとえば、nsa-insignia-sm.png を指定すると、Mayhem などのファザーはバイト列を変化させることで新しいテスト ケースを作成します。しかし、ほとんどの変化は PNG のチェックサムが無効であるために失敗し、時間が無駄になります。Mayhem のシンボリック エグゼキューターは、この問題を克服するのに役立ちます。しかし、パフォーマンスを最適化するには、ファザーととシンボリック エグゼキューターの両方を実行するのが望ましいでしょう。

convert 内のチェックサム ルーチンにパッチを当て、CRC チェックを排除することでファジングをスピードアップしましょう。この手順を完了したら、パッチを当てたバージョンが nsa-insignia-crc-error.png ファイルを受け入れるかどうかを検証します。

チェックサム ルーチンを特定する

バイナリ中のチェックサム ルーチンを特定する方法はいくつかあります。

  1. 修正しようとしているアルゴリズムに関するマジック ナンバーを探し、さかのぼって、そのアルゴリズムの出力と入力を比較して検証している箇所を見つけます。
  2. エラー メッセージに含まれる文字列を使用して関連するコードを見つけます。
  3. パッチを当てるべき場所が見つかるまで、バイナリをリバースエンジニアリングします。

convert では、チェックサムはライブラリの 1 つでチェックされています。ldd を実行すると、プログラムが使用しているライブラリの一覧を取得できます。

$ # Run ldd on convert to see all libraries.
$ ldd /usr/bin/convert
linux-vdso.so.1 (0x00007ffe24f4d000)
libMagickCore-6.Q16.so.3 => /usr/lib/x86_64-linux-gnu/libMagickCore-6.Q16.so.3 (0x00007f7f4bae7000)
libMagickWand-6.Q16.so.3 => /usr/lib/x86_64-linux-gnu/libMagickWand-6.Q16.so.3 (0x00007f7f4b7be000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f7f4b5a1000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f7f4b202000)
...

ここでは、チェックサムを計算しているライブラリには "CRC error" という文字列があることをお教えしますので、grep コマンドを使用してライブラリを発見できるでしょう。

$ grep "CRC error" /usr/lib/x86_64-linux-gnu/*
...
Binary file /usr/lib/x86_64-linux-gnu/libpng16.so.16 matches
Binary file /usr/lib/x86_64-linux-gnu/libpng16.so.16.28.0 matches
...

libpng16.so.16 は単なるシンボリック リンクであるので、libpng16.so.16.28.0 にパッチを当てる必要があります。 Docker とローカル システムの共有ディレクトリである /mnt にファイルをコピーします。

$ cp /usr/lib/x86_64-linux-gnu/libpng16.so.16.28.0 /mnt

バイナリの編集

次に、ホスト OS でターミナルを開いて debian:stretch Docker イメージから libpng16.so.16.28.0 ファイルをコピーしてホスト OS に戻します。すると libpng16.so.16.28.0 ファイルがホスト OS のカレント ディレクトリにコピーされます。

docker cp c146984d637b:/mnt/libpng16.so.16.28.0 .

Note

繰り返しになりますが、debian:stretch イメージの正確なコンテナー ID は、上記とは異なる可能性があります。

任意のバイナリ解析プラットフォームで libpng16.so.16.28.0 ライブラリを開きます。ここでは Binary Ninja を使用します。

imagemagick-binary-ninja-0

文字列 “CRC error” を検索します。

imagemagick-binary-ninja-1

最初のエントリは、別の文字列の途中にあるサブ文字列 “CRC error” を示しています。 おそらくこれは探している対象ではありません。

imagemagick-binary-ninja-2

次のエントリは、“CRC error” という文字列だけです。さらに 0x1858a へのクロスリファレンスがあります。これは可能性がありそうです。

imagemagick-binary-ninja-3

ざっとこの関数を見ると、png_chunk_error または png_chunk_warn の呼び出しの直前に "CRC error" という文字列がロードされていることがわかります。png_chunk_error および png_chunk_warn を通るブロックを避けることさえできればうまくいきそうです。0x18571 で必ず分岐することができれば、libpng がチェックサム エラーで終了するのを避け、より効率的に imagemagick をファジングできるかもしれません。

Binary Ninja にはこのプロセスを簡単にする機能があります。0x18571 の指令を右クリックし、Patch -> Always Branch を選択します。

imagemagick-binary-ninja-4

変更が完了すると、プログラムはチェックサムの不一致に対してエラーまたは警告を引き起こすコードを実行しないはずです。関数は次のようになります。

imagemagick-binary-ninja-5

Binary Ninja で File -> Save Contents As に移動し、新しいファイルを libpng16.so.16.28.0.patched として保存します。

修正済みのライブラリを実行する

最後に、libpng16.so.16.28.0.patched をコピーして debian:stretch Docker イメージに戻します。

docker cp libpng16.so.16.28.0.patched c146984d637b:/mnt

debian:stretch Docker イメージ内の /mntlibpng16.so.16.28.0.patched があるのがわかります。次のどちらかの方法でこのライブラリを使用できます。

  • 次のコマンドを実行してシステム バージョンを上書きします。
$ cp libpng16.so.16.28.0.patched /usr/lib/x86_64-linux-gnu/libpng16.so.16.28.0
  • 修正済みのバージョンを検索するようにライブラリのロード パス LD_LIBRARY_PATH を変更します。Docker イメージの /mnt で以下を実行します。
$ # Change so the current directory is checked first for libraries.
$ export LD_LIBRARY_PATH=`pwd`

$ # Make a symbolic link so the library name is resolved to our
$ # modified version
$ ln -s libpng16.so.16.28.0.patched libpng16.so.16

$ # Verify convert shows we are using the modified version
$ ldd `which convert` | grep libpng
libpng16.so.16 => /mnt/libpng16.so.16 (0x00007fee99e75000)
$ # Verify that convert now accepts the png with an invalid CRC
$ convert nsa-insignia-crc-error.png /tmp/out.png
convert-im6.q16: PNG unsigned integer out of range `nsa-insignia-crc-error.png` @ error/png.c/MagickPNGErrorHandler/1628.
...

Info

編集する前は convert がエラーをレポートしていたことに注意してください。

convert-im6.q16: IDAT: CRC error `nsa-insignia-crc-error.png' @ error/png.c/MagickPNGErrorHandler/1628.

修正済みのライブラリを使用した場合、convert はチェックを回避します。演習として、"integer out of range" エラーも除去してみてください。

Mayhem を実行する

これで、新しいライブラリとともに convert をパッケージ化できるようになりました。Docker コンテナーから次のコマンドを実行します。

$ # install Mayhem CLI
$ apt-get update && apt-get install -y curl
$ curl -o mayhem https://MAYHEM_HOST/images/mayhem && chmod +x mayhem && mv mayhem /usr/local/bin/


$ # package up convert.
$ mayhem package /usr/bin/convert -o /mt/convert-pkg
Packaging target: /usr/bin/convert
Packaging dependency: /usr/bin/convert-im6.q16 -> /mnt/convert-pkg/root/usr/bin/convert-im6.q16
Packaging dependency: /usr/bin/convert -> /mnt/convert-pkg/root/usr/bin/convert
Packaging dependency: /usr/lib/x86_64-linux-gnu/libMagickCore-6.Q16.so.3.0.0 -> /mnt/convert-pkg/root/usr/lib/x86_64-linux-gnu/libMagickCore-6.Q16.so.3.0.0
...

# If you changed LD_LIBRARY_PATH earlier, copy over the modified patched binary. Note the Mayhem CLI does
# not follow LD_LIBRARY_PATH.
$ cp libpng16.so.16.28.0.patched \
   /mnt/convert-pkg/root//usr/lib/x86_64-linux-gnu/libpng16.so.16.28.0

この時点で、ローカル ディスクにディレクトリ convert-pkg が存在するはずです。コマンドを適切に実行するには、convertcmd ブロックを調整する必要があります。

cmd: /usr/bin/convert @@ /dev/null

あとは、mayhem run convert-pkg を使用して Mayhem にパッケージをアップロードするだけです。

✏️ まとめと振り返り

このレッスンでは、ソース コードが利用できない場合に、ファジング プロセスを改善するためにバイナリ アプリケーションを変更する方法を学びました。


学習内容

1.バイナリへのパッチが役に立つ理由を説明する。
  • バイナリの変更は、テストに必須というわけではありませんが、脆弱性の調査者はいくつかの理由からバイナリを変更することがあります。
    1. 1 つのテスト ケースを実行した後にきれいにプログラムを終了できる
    2. 解析を妨げるチェックサムまたは暗号化に関する要素を除去する
    3. 認証チェックを除去する
    4. Mayhem に対象バイナリの特定の関数を直接テストするよう指示する
2.imagemagick をサンプルとしてバイナリにパッチを当てる手順を行う。
  • 次の手順を行う必要がありました。 1.convert コマンドをインストールします。
    1. チェックサム ルーチンを特定します。
    2. imagemagick バイナリを編集します (Binary Ninja を使用)。
    3. 修正済みの convert ライブラリをローカルで実行します。
    4. 修正済みの convert ライブラリを Mayhem で実行します。