
UnicornとLibFuzzerに基づくクローズドソースバイナリ向けファジングツール
uniFuzzerは、UnicornとLibFuzzerをベースにした、クローズドソースバイナリ向けのファジングツールです。現在、ARM/MIPS上の32ビットLSB ELFファイル(IoTデバイスでよく見られる)のファジングをサポートしています。
callbackディレクトリに.cファイルを作成し、以下のコールバックを記述します。void onLibLoad(const char *libName, void *baseAddr, void *ucBaseAddr):Unicorn内で依存ライブラリがロードされるたびに呼び出されます。int uniFuzzerInit(uc_engine *uc):すべてのバイナリがUnicornにロードされた直後に呼び出されます。ここでスタック/ヒープ/レジスタを設定できます。int uniFuzzerBeforeExec(uc_engine *uc, const uint8_t *data, size_t len):各ラウンドのファジング実行前に呼び出されます。int uniFuzzerAfterExec(uc_engine *uc):各ラウンドのファジング実行後に呼び出されます。makeを実行し、ufという名前のファジングツールを生成します。uniFuzzerは以下の環境変数をパラメータとして使用します。
UF_TARGET:ターゲットELFファイルのパスUF_PRELOAD:プリロードライブラリのパス。ライブラリのアーキテクチャがターゲットと一致していることを確認してください。UF_LIBPATH:依存ライブラリが存在するディレクトリのパス。複数のパスは:で区切ります。ファジングは以下のコマンドで開始できます。
UF_TARGET=<target> [UF_PRELOAD=<preload>] UF_LIBPATH=<libPath> ./uf
基本的な使い方のデモがあります。デモには以下のファイルが含まれています。
vuln()という簡単な関数を含みます。printf()と簡略化されたmalloc()/free()を定義しています。vuln()関数をファジングするために必要なコールバックを定義しています。まず、mipsel用のgcc(Debianではgcc-mipsel-linux-gnuパッケージ)をインストールしてデモをビルドします。
# ターゲットバイナリ
# '-Xlinker --hash-style=sysv' はシンボルルックアップに'DT_GNU_HASH'ではなく'DT_HASH'を使用するようgccに指示します。
# 現在uniFuzzerは'DT_GNU_HASH'をサポートしていません。
mipsel-linux-gnu-gcc demo-vuln.c -Xlinker --hash-style=sysv -no-pie -o demo-vuln
# プリロードライブラリ
mipsel-linux-gnu-gcc -shared -fPIC -nostdlib -Xlinker --hash-style=sysv demo-libcpreload.c -o demo-libcpreload.so
あるいは、上記のコマンドでコンパイル済みのdemo-vulnとdemo-libcpreload.soファイルを直接使用することもできます。
次に、makeを実行してuniFuzzerをビルドします。自分でMIPSデモをコンパイルした場合、アドレスがプリビルド版と異なる可能性があるため、demo-callback.cを適宜更新してください。
最後に、MIPSのlibcライブラリが用意されていることを確認します。Debianではlibc6-mipsel-crossパッケージをインストールした後、/usr/mipsel-linux-gnu/lib/にあります。これをUF_LIBPATHに指定します。
UF_TARGET=<path to demo-vuln> UF_PRELOAD=<path to demo-libcpreload.so> UF_LIBPATH=<lib path for MIPS> ./uf
Unicornはこの問題によりQEMUのJITキャッシュをクリアします。これにより、ターゲットバイナリが各ラウンドの実行中にJIT再コンパイルされるため、ファジングの速度が低下します。
パフォーマンス向上のために、その問題で指摘されているtb_flush(env);をコメントアウトすることができます。
GNU_HASHのサポートIFUNCのサポート