エキスパート
バイナリへのパッチによるファジングの改善¶
このレッスンでは、ソース コードが利用できない場合に、ファジング プロセスを改善するためにバイナリ アプリケーションを変更する方法を、手順を追って説明します。
学習時間の目安: 20 分
このレッスンを終了すると、以下のことができるようになります。
- バイナリにパッチを当てるのが有用な理由を説明する。
imagemagick
を使用し、バイナリへのパッチのサンプルを順を追って理解する。
以下が必要です。
- Mayhem の動作するコピー。Mayhem CLI がインストールされていること。
-
あらかじめビルド済みの Docker イメージを実行し、チュートリアル サンプルにアクセスできること。
docker pull forallsecure/tutorial:2.10 docker run -ti --privileged --rm forallsecure/tutorial:2.10
-
リバースエンジニアリングの知識。これは上級チュートリアルであるため、アセンブリ レベルのコードに慣れている必要があります。
- 指令をパッチできる機能を持った逆アセンブラ。サンプルでは Binary Ninja を使用しています。
-
このサンプルは、オンライン アクセス、localhost に Docker がインストールされていること、
debian:stretch
Docker イメージが実行されていることを必要とします。docker pull debian:bullseye docker run -it debian:bullseye
バイナリにパッチを当てる理由¶
バイナリの変更は、ファジングに必須というわけではありませんが、脆弱性を調査する場合にいくつかの理由からバイナリを変更することがあります。
- 1 つのテスト ケースを実行した後にきれいにプログラムを終了できる
- 解析を妨げるチェックサムまたは暗号化に関する要素を除去する
- 認証チェックを除去する
- Mayhem に対象バイナリの特定の関数を直接テストするよう指示する
サンプル 1: チェックサムと imagemagick
¶
次のようにシンプルな入力形式を持つプログラムがあるとします。
data
: 転送するデータcksum
:data
フィールドの 32 ビットのチェックサム
メッセージが有効であるためには、チェックサムが data
に対して正しくなければなりません。つまり、data
と cksum
にデータ依存関係があります。 ファジングはそのようなデータ依存関係を考慮しないため、チェックサムが有効であるかをチェックするコードをパスできず、欠陥を検出できません。
解決策は 2 つあります。
- テスト ドライバーを経由して入力を渡すことができます。そうすることで、テスト対象プログラムに入力を渡す前に、適切なチェックサムを確実に用意することができます。
- バイナリにパッチを当て、チェックサムが無効であっても、すべての入力を受け入れるようにできます。
このチュートリアルでは、imagemagick
スイートの convert
をサンプルとして使用し、2 番目の方法を試します。
convert
¶
まず、現在実行している debian:stretch
Docker コンテナーに次のファイルを移動します。
nsa-insignia-sm.png
- 有効な PNG ファイルです。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
ファイルを受け入れるかどうかを検証します。
チェックサム ルーチンを特定する¶
バイナリ中のチェックサム ルーチンを特定する方法はいくつかあります。
- 修正しようとしているアルゴリズムに関するマジック ナンバーを探し、さかのぼって、そのアルゴリズムの出力と入力を比較して検証している箇所を見つけます。
- エラー メッセージに含まれる文字列を使用して関連するコードを見つけます。
- パッチを当てるべき場所が見つかるまで、バイナリをリバースエンジニアリングします。
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 を使用します。
文字列 “CRC error” を検索します。
最初のエントリは、別の文字列の途中にあるサブ文字列 “CRC error” を示しています。 おそらくこれは探している対象ではありません。
次のエントリは、“CRC error” という文字列だけです。さらに 0x1858a
へのクロスリファレンスがあります。これは可能性がありそうです。
ざっとこの関数を見ると、png_chunk_error
または png_chunk_warn
の呼び出しの直前に "CRC error"
という文字列がロードされていることがわかります。png_chunk_error
および png_chunk_warn
を通るブロックを避けることさえできればうまくいきそうです。0x18571
で必ず分岐することができれば、libpng
がチェックサム エラーで終了するのを避け、より効率的に imagemagick をファジングできるかもしれません。
Binary Ninja にはこのプロセスを簡単にする機能があります。0x18571 の指令を右クリックし、Patch -> Always Branch
を選択します。
変更が完了すると、プログラムはチェックサムの不一致に対してエラーまたは警告を引き起こすコードを実行しないはずです。関数は次のようになります。
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 イメージ内の /mnt
に libpng16.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
が存在するはずです。コマンドを適切に実行するには、convert
の cmd
ブロックを調整する必要があります。
cmd: /usr/bin/convert @@ /dev/null
あとは、mayhem run convert-pkg
を使用して Mayhem にパッケージをアップロードするだけです。
✏️ まとめと振り返り¶
このレッスンでは、ソース コードが利用できない場合に、ファジング プロセスを改善するためにバイナリ アプリケーションを変更する方法を学びました。
学習内容
1.バイナリへのパッチが役に立つ理由を説明する。
- バイナリの変更は、テストに必須というわけではありませんが、脆弱性の調査者はいくつかの理由からバイナリを変更することがあります。
- 1 つのテスト ケースを実行した後にきれいにプログラムを終了できる
- 解析を妨げるチェックサムまたは暗号化に関する要素を除去する
- 認証チェックを除去する
- Mayhem に対象バイナリの特定の関数を直接テストするよう指示する
2.imagemagick
をサンプルとしてバイナリにパッチを当てる手順を行う。
- 次の手順を行う必要がありました。
1.
convert
コマンドをインストールします。- チェックサム ルーチンを特定します。
imagemagick
バイナリを編集します (Binary Ninja を使用)。- 修正済みの
convert
ライブラリをローカルで実行します。 - 修正済みの
convert
ライブラリを Mayhem で実行します。