Windows HEIF コーデックの画像解析の脆弱性に関する議論を続けると、新しいクラッシュの分析、関数シンボルの再構築、および脆弱性の根本原因の分析、CVE-2022-24457 について検討します。この脆弱性は、Windows 10 および 11 の既定のインストールに存在し、悪意のある画像ファイルを含むフォルダーを参照するだけで脆弱性がトリガーされます。この脆弱性は、Windows が画像のサムネイルを自動的に生成しようとするときに引き起こされます。すべての脆弱性は、Mandiant による開示に続いて Microsoft によって修正されました。
クラッシュ – CVE-2022-24457
図 1 のクラッシュは、AVX2 命令内の範囲外のメモリ書き込みです。クラッシュ関数はかなり大きく、顕著な一連の AVX2 命令が含まれていることに注意してください。逆コンパイル、操作、およびmemcpy
関数への内部呼び出しを簡単に調べた後、これがmemcpy
の AVX2 最適化バージョンであると推測できます。 memcpy
関数内の境界外書き込みは、詳細な分析に適したクラッシュです。
その他の機能の特定
memcpy
として識別されたクラッシュ関数を使用して、次にバイナリ内の他の関数を識別しようとします。このために、コール スタックを 1 フレーム上に移動し、図 2 の逆コンパイルを確認します。この逆コンパイルには、 sub_18017dd88
への呼び出しが含まれていることがわかります。これは、2 番目のパラメーターとして関数名を持つログ関数のように見えます。
一部のソフトウェアには、本番環境でクラッシュやパフォーマンスの問題を分析するのに役立つロギング機能が付属しています。この場合、ロギング呼び出しは、複数の関数名を再構築し、これらの関数の実装された機能を理解するのに役立ちます。これにより、脆弱性の根本原因を簡単に特定することができます。相互参照を見ると、このロギング関数への呼び出しが 5000 回を超えていることがわかります (図 3 を参照)。
多数のロギング呼び出しを考慮して、2 番目の引数から関数名を復元し、呼び出し元関数の名前を変更するスクリプトを作成します。
IDA スクリプト
このプロセスを自動化するために、IDAPython スクリプトが作成されました。以下のアルゴリズムに従って動作します。
- ロギング機能への相互参照 (xref) のリストを取得する
- 外部参照のリストから一意の呼び出し元関数を取得する
- 各呼び出し元を逆コンパイルします
- ロギング関数呼び出しを見つけて、2 番目の引数を関数名として取得します
- 取得した関数名で呼び出し元関数の名前を変更します
他のプロジェクトで再利用できる汎用スクリプトを作成することにしました。そのために、IDA の逆コンパイラ API を使用して、プロセッサと呼び出し規約固有のコードを回避しました。このスクリプトは、逆コンパイラ ラッパー FIDLも使用します。スクリプトを表 1 に示します。
IDC インポートから * # f_name: ロギング関数名 呼び出し元 = セット () f = get_func(ref.frm) f_ea = f.start_ea 呼び出し元の caller_ea の場合: 名前の変更 (‘sub_18017DD88’, 1) |
IDA で名前が変更された何千もの関数により、完全な根本原因分析を行うことがかなり容易になります。静的分析には IDA を使用していますが、ほとんどの動的分析には WinDBG + Time Travel Debugging (TTD) が定期的に使用されています。 IDA プラグインFakePDBを使用して、名前を変更したシンボルを WinDBG に移植します。 FakePDB は、IDA データベースから PDB を作成します。これを WinDBG にロードして、デバッグ/トレース機能を強化できます。例を図 4 に示します。
バグの根本原因分析
関数msheif_store!CHEIFStreamReader::ReadItemData
の関連コードを表 2 に示します。
/* QWORD currentOffset = 0; |
賢明な読者は、可能性のある整数オーバーフロー シナリオのif
条件をすぐに指摘するでしょう。ただし、この場合、 CHEIFItemInfoEntry::GetDataSize
で長さを計算する際に、そのようなシナリオは軽減されます。この脆弱性は、 MFCreateMemoryBuffer
関数とそのパラメーターを詳しく調べた場合にのみ明らかになります。図 5 は、MSDN からの関数のドキュメントを示しています。
MFCreateMemoryBuffer
関数は、長さパラメーターとして 32 ビットの DWORD を受け入れ、割り当てられたバッファーを返します。しかし、表 2 を見ると、関数に渡される長さパラメーターが 64 ビットの QWORD であることがわかります。このような場合、コンパイラは QWORD を DWORD に切り詰めることを決定します。この場合、長さ0x1000003f0
ははるかに小さい0x3f0
に切り捨てられます。これにより、より小さなバッファーが割り当てられ、より大きなデータがバッファーにコピーされ、境界外書き込みが発生します。
関数名CHEIFStreamReader::ReadItemData
から、 item
ボックスを解析しようとしているときに脆弱性が発生したと推測されます。呼び出しをさらに遡ると、関数CItemLocationAtom::ParseAtom
から長さが読み取られていることがわかります。これは、図 6 に示すiloc
ボックスを指しています。
ボックスの内容を見ると、ボックスで指定された 3 つの長さの値 (0x309、0xEE7、および 0xFFFFF200) がすべて表示されます。ここで、 iloc
仕様を調べて、これらの長さの正確な詳細を把握できます。 HEIF はISO Base Media File Format (ISOBMFF) に基づいていますが、ボックス解析アルゴリズムを使用して適切な仕様を取得することは、複雑であったり、有料であったりする傾向があります。
私たちが試すことができる別のアプローチは、 libheif やnokiatech-heif などの HEIF 画像パーサーのオープンソース実装を調べることです。 PoC ファイルをデコード ルーチンで実行すると、 iloc
ボックスから正確な長さの詳細が得られます (図 7 参照)。
PoC ファイルに表示される 3 つの長さはエクステント長と呼ばれます。 Microsoft の HEIF 実装は、エクステントの長さをすべて読み取り、それらを合計してから、結果の長さが API 関数MFCreateMemoryBuffer
によるメモリの割り当てに使用されます。この API は長さを DWORD に切り捨て、より小さいバッファーを割り当てるため、境界外書き込みが発生します。
パッチ
Microsoft は2022 年 3 月にこの脆弱性にパッチを適用し、全長が 0xC8000000 (~3GiB) を超える場合にエラーを出して救済しました。
結論
このブログ シリーズのパート 4 では、Microsoft の HEIF デコーダーの脆弱性を紹介し、シンボルを再構築して脆弱性の完全な根本原因分析を行う方法を示します。 HEIF コーデックで報告された最新の脆弱性のリストは、次の付録に記載されており、 Mandiant Vulnerability Disclosuresで参照されています。
付録
CVE ID |
提出日 |
確定日 |
脆弱性の種類 |
CVE-2022-22007 |
2021 年 4 月 22 日 |
2022 年 3 月 8 日 |
ヒープオーバーフロー |
CVE-2022-21926 |
2021 年 9 月 13 日 |
2022 年 2 月 8 日 |
ヒープオーバーフロー |
CVE-2022-21917 |
2021 年 9 月 17 日 |
2022 年 1 月 11 日 |
ヒープオーバーフロー |
CVE-2022-21927 |
2021 年 9 月 17 日 |
2022 年 2 月 8 日 |
ヒープオーバーフロー |
CVE-2022-22006 |
2021 年 9 月 17 日 |
2022 年 3 月 8 日 |
ヒープオーバーフロー |
CVE-2022-21844 |
2021 年 9 月 23 日 |
2022 年 2 月 8 日 |
ヒープオーバーフロー |
CVE-2022-24453 |
2021 年 10 月 19 日 |
2022 年 3 月 8 日 |
ヒープオーバーフロー |
CVE-2022-24457 |
2021 年 10 月 19 日 |
2022 年 3 月 8 日 |
ヒープオーバーフロー |
CVE-2022-24456 |
2021 年 11 月 14 日 |
2022 年 3 月 8 日 |
ヒープオーバーフロー |
CVE-2022-24532 |
2021 年 12 月 4 日 |
2022 年 4 月 12 日 |
ヒープオーバーフロー |
参照: https://www.mandiant.com/resources/blog/fuzzing-image-parsing-windows-part-four
Comments