どこからでもJPEGを作成する

aflの機能の興味深いデモンストレーションです。 私はそれが機能することに本当に驚きました!



$ mkdir in_dir $ echo 'hello' >in_dir/hello $ ./afl-fuzz -i in_dir -o out_dir ./jpeg-9a/djpeg
      
      





本質的に、「hello」という単語だけのテキストファイルを作成し、JPEG画像が入力されることを期待するプログラムにストリームを出力するようにファザーに要求しました( djpegは、一般的なIJG jpegグラフィックライブラリに付属する単純なユーティリティです; libjpeg-turboも動作するはずです) 。 もちろん、私の入力は有効な画像のようなものではないため、ユーティリティはそれらをすぐに拒否します。



 $ ./djpeg '../out_dir/queue/id:000000,orig:hello' Not a JPEG file: starts with 0x68 0x65
      
      





通常、このようなファジングはまったく意味がありません。本質的に、従来の形式に依存しないファザーが単語「hello」を実際のJPEG画像にいつか変えることができるという可能性はありません。 数十のランダム設定が次々と並ぶ可能性は天文学的には小さいです。



幸いなことに、 afl-fuzzは簡単なアセンブリレベルのツールを活用できます。1ミリ秒程度で、最初のバイトを0xffに設定しても外部から観測される出力は変更されませんが、テストアプリケーションでわずかに異なる内部パスを実行できます。 この情報を基に、彼はこのテストケースを将来のファジングラウンドのベースとして使用することにしました。



 $ ./djpeg '../out_dir/queue/id:000001,src:000000,op:int8,pos:0,val:-1,+cov' Not a JPEG file: starts with 0xff 0x65
      
      





第2世代のテストケースを処理した後、ファザーはほとんどすぐに、2番目のバイトを0xd8に設定するとさらに興味深いことが行われることに気付きます。



 $ ./djpeg '../out_dir/queue/id:000004,src:000001,op:havoc,rep:16,+cov' Premature end of JPEG file JPEG datastream contains no image
      
      





ここで、fazzerは有効なファイルヘッダーを合成することができ、その重要性を本当に理解しました。 そのような引き渡しを次のファジングの基礎として使用して、彼はすぐに本質に深く沈み始めます。 数百世代とexecve()への数億呼び出しの後、有効なJPEGファイルに必要な制御構造(SOF、ハフマンテーブル、量子化テーブル、SOSマーカーなど次々と見つかります。



 $ ./djpeg '../out_dir/queue/id:000008,src:000004,op:havoc,rep:2,+cov' Invalid JPEG file structure: two SOI markers ... $ ./djpeg '../out_dir/queue/id:001005,src:000262+000979,op:splice,rep:2' Quantization table 0x0e was not defined ... $ ./djpeg '../out_dir/queue/id:001282,src:001005+001270,op:splice,rep:2,+cov' >.tmp; ls -l .tmp -rw-r--r-- 1 lcamtuf lcamtuf 7069 Nov 7 09:29 .tmp
      
      





8コアシステムで6時間ファジングした後の最初の画像は非常に控えめに見えます。高さ3ピクセル、幅748ピクセルのきれいな灰色の長方形です。 しかし、それが開かれた瞬間から、ファザーはこの画像を基礎として使用し始めます。そして、新しい実行方法ごとに、より多くの興味深い画像をすばやく生成します。







もちろん、どこからでも完全な画像を合成することは例外的なケースであり、実際にはほとんど役に立ちません。 しかし、より平凡な目的のために、ファザーはターゲットプログラムの機能をストレステストするのに適しています。 あまり知られていない機能(たとえば、プログレッシブまたは算術符号化されたJPEG、白黒JPEG)を使用した、スナップインの進化的ファジングを備えたファジングは、ファジングを開始するさまざまなテストケースの巨大な高品質ケースの代替として使用できます。



libjpegの場合の顕著な特徴は、特別な準備なしで機能することです。「hello」行には特別なものはなく、ファザーは画像解析について何も知らず、設計されておらず、このライブラリで特別に機能するように構成されていません。 有効にするコマンドラインスイッチさえありません。 他の多くのタイプのパーサーにafl-fuzzを設定すると、同じ結果が得られます。bashを使用すると、有効なスクリプトが作成されます。 giflibを使用してGIF 生成します。 fileutilsで ELFファイルを生成し、フラグを設定し、BOMでAtari 68xxx、x86、およびUTF-8ブートセクターのバイナリを作成します。 ほとんどすべての場合、生産性へのリギングの影響も最小限です。



もちろん、すべてがそれほどスムーズではありません。 その中心部では、afl-fuzzはブルートフォースプログラムのままです。 これにより、シンプル、高速、信頼性が向上しますが、大規模な検索スペースで特定の種類の霧化されたチェックがファザーにとって乗り越えられない障害になる可能性があることも意味します。 これが良い例です:



 if (strcmp(header.magic_password, "h4ck3d by p1gZ")) goto terminate_now;
      
      





実際には、これはafl-fuzzが PNGファイルまたは重要なHTMLドキュメントをゼロから「発明」できる可能性低いことを意味します-そして、単なる「hello」よりも良い開始点が必要です。 上記の例のようにコード構造を常に使用するには、ユニバーサルファザーが完全に異なるレベルでターゲットバイナリの動作を理解する必要があります。 科学者はこの点である程度の進歩を遂げましたが、多様で複雑なコードベースで迅速、簡単、かつ確実に動作できるフレームワークの出現をさらに数年待つ必要があります。



何人かの人々が、シンボリックなパフォーマンスやafl-fuzzの影響を受けた他のものについて私に尋ねました。 私はこのドキュメントでいくつかのメモを集めました。



All Articles