
2023年2月、MicrosoftはMicrosoft Wordの深刻な脆弱性CVE-2023-21716(CVSSスコア9.8)にパッチを適用しました。この脆弱性により、攻撃者は認証なしでリモートコードを実行できる可能性があります。 この脆弱性はOutlookのプレビューウィンドウにも影響し、ファイルをプレビューするだけでトリガーされる可能性があります。Microsoftはパッチと回避策をリリースしましたが、問題の詳細は公開しませんでした。 3月6日、このバグを発見した研究者(Joshua J.Drake - @jduck)が概念実証(PoC)をTwitterで公開しました。
CVE-2023-21716は、Microsoft Wordがリッチテキスト形式(RTF)ファイル、特に\fonttbl制御ワードを処理する方法に起因します。 \fonttblは、\f形式を使用してドキュメント内のフォントを定義します。wwlib.dll内の\fonttblは、ヒープ内で一定量のスペースが割り当てられます(これは、ヒープ割り当てが通常、入力によってサイズが変わる可能性のあるフォントテーブルなどの大きな構造を解析するような動的データに使用されるためです)。クラッシュは、フォント数が上限(PoCでは32760であることが証明されています)を超えた場合のバッファオーバーフローによって発生します。割り当てられたヒープスペースを超過すると、リターン命令ポインタ(RIP)が上書きされ、アプリケーションがクラッシュします。
ユーザーは、Microsoftから最新のセキュリティパッチをインストールすることを強くお勧めします。これらのパッチで問題は解決されています。 アップグレードできないユーザーのために、Microsoftはいくつかの回避策も提供しています。詳細はこちら: https://msrc.microsoft.com/update-guide/vulnerability/CVE-2023-21716
WinDbgを使用して、クラッシュの原因を詳しく調べることができます。手順は次のとおりです:
クラッシュが発生すると、WinDbgが自動的にブレークし、さらに分析できるようになります。最初に、'k'と入力してコールスタックを表示します。
0:000> k
# ChildEBP RetAddr
00 012f5134 77a5feb5 ntdll!RtlReportCriticalFailure+0x4b
01 012f5170 77a5dda9 ntdll!RtlpReportHeapFailure+0x2f
02 012f5170 77a66220 ntdll!RtlpHpHeapHandleError+0x89
03 012f5188 77a5dab7 ntdll!RtlpLogHeapFailure+0x43
04 012f51ec 779b400d ntdll!RtlpAnalyzeHeapFailure+0x281
05 012f5348 779f806d ntdll!RtlpFreeHeap+0x24d
06 012f53a4 779b3d66 ntdll!RtlpFreeHeapInternal+0x783
07 012f53c4 6ea4aa24 ntdll!RtlFreeHeap+0x46 //ntdll以下の関数はヒープ破損のエラーハンドリングに関連
08 012f53d8 6ea4a9cb mso20win32client!Ordinal1068+0xab
09 012f53e8 6ea4a995 mso20win32client!Ordinal1068+0x52
0a 012f53f4 6cccda52 mso20win32client!Ordinal1068+0x1c
0b 012f5410 03657fea mso!Ordinal1387+0x24
0c 012f5424 03990115 wwlib!PTLS7::FsUpdateFinitePage+0x7e26f //wwlibはフォントテーブルの処理を担当
0d 012f5670 034ea593 wwlib!PTLS7::LsDestroyContext+0x245f90
0e 012f6f5c 033a68ef wwlib!PTLS7::FsUpdateBottomlessPage+0x17494
0f 012f7484 035054ed wwlib!PTLS7::LsAssert+0x2bd1c
10 012f888c 03503d3b wwlib!PTLS7::FsUpdateBottomlessPage+0x323ee
11 012f8910 0400be52 wwlib!PTLS7::FsUpdateBottomlessPage+0x30c3c
12 012f9e9c 0390013a wwlib!wdGetApplicationObject+0xdf8a0
13 012faf48 03ebf20e wwlib!PTLS7::LsDestroyContext+0x1b5fb5
14 012faf90 0410ab2a wwlib!DllCanUnloadNow+0xcc314
15 012fcfe0 03752fb4 wwlib!wdGetApplicationObject+0x1de578
16 012ff538 03385b93 wwlib!PTLS7::LsDestroyContext+0x8e2f
17 012ff578 75e6173b wwlib!PTLS7::LsAssert+0xafc0
18 012ff5a4 75e57eaa USER32!_InternalCallWinProc+0x2b
19 012ff68c 75e57666 USER32!UserCallWinProcCheckWow+0x33a
1a 012ff6c4 75e55e8b USER32!CallWindowProcAorW+0x7f
1b 012ff6dc 7500ae9d USER32!CallWindowProcW+0x1b
.....
.....
主要な2つのライブラリは、ドキュメントコンテンツ(フォント、テキスト、レイアウトなど)を管理するWordのコアライブラリであるwwlib.dllと、メモリ管理やエラーハンドリングなどの低レベルシステムタスクを処理するntdll.dllです。クラッシュは、WordがRTFファイルから多数のフォントを処理するときに発生します。ntdll.dllが、Wordが無効なメモリにアクセスまたは解放しようとしていることを検出すると(おそらくフォントオーバーフローによって破損した)、ヒープ破損エラーが発生し、クラッシュに至ります。
さらに詳しく調べるために、wwlibライブラリの最後の部分にブレークポイントを設定して、フォントがメモリ内にどのように読み込まれているかを確認し、問題を引き起こした原因を理解できます。
bc * //他のすべてのブレークポイントを削除
bp wwlib!PTLS7::FsUpdateFinitePage+0x7e26f //ブレークポイントを作成
これでアクセス違反が発生します:
(ba4.1a14): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=004f1ce4 ebx=00000001 ecx=000004e4 edx=ffff7ffc esi=13474fe8 edi=00008002
eip=02b300d5 esp=004f1c3c ebp=004f1c48 iopl=0 nv up ei pl nz na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00210206
wwlib!PTLS7::FsUpdateFinitePage+0x7635a:
02b300d5 66894c5604 mov word ptr [esi+edx*2+4],cx ds:002b:13464fe4=???? //ここでブレークが発生
プログラムを早い段階で停止させたため、wwlib.dllが最初に無効なメモリにアクセスまたは変更しようとした時点(FsUpdateFinitePage内)で停止し、最初のアクセス違反(メモリ破損の原因)を確認できます。これにより、ntdll.dllによってヒープ破損エラーが検出される前に、何が問題だったかを調査する機会が得られます。
より正確には、プログラムはwwlib!PTLS7::FsUpdateFinitePage+0x7635a関数内の命令 mov word ptr [esi+edx*2+4],cx でアクセス違反(コードc0000005)により停止しました。
このエラーは、Wordが無効なメモリ位置にアクセスしようとしたことを示しています。具体的には、esi+edx*2+4 のメモリ位置に値(cx)を格納しようとした際に発生しています。
ESIレジスタをさらに詳しく見ると、フォントデータが保持されていることがわかります:
リトルエンディアン形式の各16ビット値(2バイト)は、\fA; 形式のフォントエントリを表しています。
ESI内で最後に表される値は、終端(29-00で示される)に達する前の f8 7f で、これは {\f32760A;} に対応します。

これでフォントテーブルがESIレジスタが指すメモリ位置にロードされましたが、非常に多くのフォントが処理されているため、計算されたメモリ位置(esi + edx*2 + 4)は、フォントテーブルに割り当てられたメモリを超える可能性があります。これにより、範囲外書き込みが発生し、アクセス違反エラーが発生します。 アクセス違反は、メモリ管理とエラー報告を処理するntdll.dllによって検出されます。その結果、ntdll.dllはヒープ破損を検出する関数を呼び出し、最終的にアプリケーションがクラッシュします。