サウンドをミュート:脆弱性を組み合わせて Outlook で RCE を実現:第 1 部
エグゼクティブサマリー
Akamai の研究者である Ben Barnea は、Microsoft Windows の重要な脆弱性を 2 つ発見しました。それが CVE-2023-35384 と CVE-2023-36710です。
インターネット上にいる攻撃者は、これらの脆弱性を組み合わせることで、Outlook クライアントに対する完全なゼロクリックのリモートコード実行(RCE)攻撃を生み出すことができます。
最初の脆弱性は、 MapUrlToZone 関数によるパスの解析にあります。この脆弱性を悪用するためには、細工した電子メールを Outlook クライアントに送信する必要があります。これにより、攻撃者が制御するサーバーから特別な音声ファイルがダウンロードされます。
2 つ目の脆弱性は、Audio Compression Manager(ACM)に存在します。この脆弱性はダウンロードされた音声ファイルが自動再生されるときに悪用され、それが被害者のマシンでのコード実行につながる恐れがあります。この脆弱性については、このブログ記事の 第 2 部 で詳しく説明します。
これらの脆弱性は、「責任ある開示」に従って Microsoft に報告され、 2023 年 8 月 と 2023 年 10 月 の Patch Tuesday で対処されました。
2023 年 10 月のソフトウェアアップデートがインストールされた Windows マシンは、これらの脆弱性から保護されています。さらに、2023 年 3 月のソフトウェア更新プログラムでパッチが適用された Exchange サーバーを使用する Outlook クライアントは、機能の悪用から保護されます。
概要
2023 年 3 月の Patch Tuesday の一環として解決された脆弱性の中には、 Outlook の重大な脆弱性 ( CVE-2023-23397)があります。この脆弱性は、Forest Blizzard によって野放し状態で悪用されていました。Microsoft は Forest Blizzard をロシアから国家支援を受けている攻撃者と見なしています。2023 年 12 月、Microsoft とポーランドのサイバー軍(DKWOC)は、同じ攻撃者が最近この脆弱性の悪用を試みたことを 発表 しました。この脆弱性により、攻撃者は Outlook クライアントに攻撃者のサーバーへの接続を強制することができました。この接続の一環として、クライアントは NTLM 認証情報を攻撃者に送信します。その後、攻撃者は NTLM 認証情報をオフラインで解読したり、リレー攻撃で使用したりできます。この脆弱性は、ユーザーの操作なし(ゼロクリック)で、インターネットを介してリモートで悪用される可能性がありました。
この脆弱性に対するパッチがリリースされた後、Akamai はバイパスを発見し、 以前のブログ記事で説明しました。このバイパスは、2023 年 5 月の Patch Tuesday で修正されました。そのブログ記事で、Akamai は、悪用された機能を削除することを Microsoft に推奨しました。その機能は巨大で複雑なアタックサーフェスとなるからです。しかし、その機能は Outlook に残っているため、Akamai はさらなる調査を行うことにしました。
その結果、Outlook で完全な RCE 脆弱性チェーンを実現できることがわかりました。元の Outlook の脆弱性に対する別のバイパスが見つかりました。このバイパスによって、強制的にクライアントを攻撃者が制御するサーバーに接続して悪性の音声ファイルをダウンロードさせることが再び可能になりました。次に、音声ファイル全般(特に Outlook の通知音)の処理と再生に使用される Windows メディア解析ライブラリーに脆弱性が見つかりました。これらの脆弱性を組み合わせると、攻撃者が脆弱な Outlook クライアントでゼロクリックの RCE を実現することができます。
この 2 部構成のブログシリーズでは、この 2 つの脆弱性を発見するために Akamai が実施した調査について説明します。この第 1 部では、以前のバイパスと新しいバイパスに主眼を置きます。 第 2 部では、発見されたメディア解析の脆弱性について説明します。
元の脆弱性
3 月にパッチが適用された Outlook の脆弱性は、カスタム通知音を伴うリマインダーを含む電子メールを攻撃者が送信するとトリガーされます。このカスタムサウンドが攻撃者によってパスとして指定されます。その際に利用されるのが、拡張された MAPI プロパティ「 PidLidReminderFileParameter」です。攻撃者は、クライアントに SMB サーバーからサウンドファイルを取得させる UNC パスを指定できます。リモート SMB サーバーへの接続の一環として、Net-NTLMv2 ハッシュがネゴシエーションメッセージで送信されます(図 1)。
この問題を解決するために、コードは MapUrlToZone を呼び出し、パスをイントラネット、ローカル、またはインターネットとして分類するようになりました。URL がインターネット上のリソースを指し示す場合は、カスタムのリマインダー音ではなく、デフォルトのリマインダー音が使用されます。
バイパスの発見
緩和策が導入された後、私たちはそれを回避できるかどうかを調べました。
この場合、バイパスとは、ローカル性テストに合格するパスであり、かつ、音声ファイルを遠隔地からダウンロードするために Outlook によって使用されるパスを意味します。つまり、 見つけなければならないのは、 MapUrlToZone にはインターネットではないと見なされるが、 CreateFile にはインターネットドメインとして扱われるパスです。
このようなバイパスを見つけるためには、関数の内部動作と、パス解析の一環として実行される操作を、完全に理解する必要がありました。
Windows のパスと URL
Windows にはさまざまな種類の DOS パス があり、それらに関する調査や NT パスへの変換に関する調査がたくさん行われています。ここでは Windows のさまざまなパスの種類については説明しませんが、 James Forshaw 氏のブログ記事 でこのトピックが詳しく取り上げられています。
それでは、私たちが興味のある関数の話に戻りましょう。 CreateFile は Windows パスを受け取ります。 MapUrlToZone は(その名前からわかるとおり)URL またはパスのいずれかを受け取ることができます。バイパスを見つけるためには、まず各関数(または両方)でサポートされているパスの種類を把握する必要があります。
注: CreateFile と MapUrlToZone 自体はパスを処理しません。パスの処理には他の WinAPI 関数を使用します。簡潔にするために、ここで CreateFile や MapUrlToZone と記載する場合は、根本のパス解析関数を指すこととします。
CreateFile |
MapUrlToZone |
|
---|---|---|
RtlPathTypeUncAbsolute |
✔ |
✔ |
RtlPathTypeDriveAbsolute |
✔ |
✔ |
RtlPathTypeDriveRelative |
✔ |
✔ |
RtlPathTypeRooted |
✔ |
✘ |
RtlPathTypeRelative |
✔ |
✘ |
RtlPathTypeLocalDevice |
✔ |
✔ |
RtlPathTypeRootLocalDevice |
✔ |
✘ |
スキーム(file://、http://) |
✘ |
✔ |
表 1: CreateFile と MapUrlToZone のパス機能の比較表
表 1 のとおり、両方の関数でサポートされているパスの種類は 4 つ( RtlPathTypeUncAbsolute、RtlPathTypeDriveAbsolute、RtlPathTypeDriveRelative、 RtlPathTypeLocalDevice)だけです。
最初の試み
バイパスを見つけるための最初の試みでは、絶対 UNC パス(RtlPathTypeUncAbsolute)を使用しました。図 2 はこのパスの構造を示しています。
Windows はどのようにパスコンポーネントの開始位置を把握するのでしょうか?表 2 に、関連するコード(RtlGetFullPathName_USTR)を示します。
case RtlPathTypeUncAbsolute:
SeperatorsFound = 0;
for ( CurrentIndex = 2; CurrentIndex < InputPathLength; ++CurrentIndex )
{
CurrentChar = InputPathString->Buffer[CurrentIndex];
if ( CurrentChar == '\\' || CurrentChar == '/' )
{
SeperatorsFound++;
if ( SeperatorsFound == 2 )
break;
}
}
表 2: RtlGetFullPathName_USTR コードスニペットは UNC パスを処理する
ご覧のとおり、このコードは絶対 UNC プレフィックス(「\\」)をスキップし、2 番目のパス区切り文字(「\」または「/」)の直後の文字からパスコンポーネントが始まると想定します。
しかし、「\\\\localhost\..\Akamai.com\dir\file.txt」などのパスを指定した場合はどうなるのでしょうか?
パスは次のように処理されます。
「\\\\」は UNC プレフィックス や ルート・パス・コンポーネントとして解釈されます
パスコンポーネントは「localhost\..\Akamai.com\dir\file.txt」です
通常、どれほど「..」があっても、ルートパスより上に行くことはできません。たとえば、「\\localhost\directory\..\file.txt」は「\\localhost\directory\file.txt」になります。ただし、この例では、「..」はルートパスの一部ではないため、パスは「\\\Akamai.com\dir\file.txt」に変換されます。
つまり、パスの一部をドロップすることで、パスを改ざんする方法が見つかりました。
その方法で、 CreateFile はこのパスを処理します。それでは、 MapUrlToZone はこのパスをどのように処理するのでしょうか(表 3 を参照)?初めに余分なバックスラッシュを削除して、次にパスを別の方法で解釈します。その方法は次のとおりです。
「\\localhost」はサーバー名です
「\..\」は無視されます(サーバー名より上には行けないため)
「Akamai.com\dir\file.txt」はパスコンポーネントを構成します
入力パス:\\\\localhost\..\Akamai.com\dir\file.txt |
|
---|---|
CreateFile |
MapUrlToZone |
\\\Akamai.com\dir\file.txt |
\\localhost\Akamai.com\dir\file.txt |
表 3: CreateFile と MapUrlToZone の入力パスおよびその解析結果
MapUrlToZone は、上記の出力パスで 0(ローカル)を返します。
バイパスは見つかりましたが、このパスを使用して UNC 要求をトリガーすることはできないようです。 CreateFile によって処理されるパスの先頭にある余分なスラッシュに注目してください。これは、サーバー名が空であることを示します。複数の UNC プロバイダー(MUP)がさまざまなネットワークプロバイダーに、この(空の)サーバー名を処理できるかどうかを問い合わせると、必ず false が返されます。したがって、要求は行われません。
MapUrlToZone と CreateFile のパス処理方法の違いを悪用するためには、追加のバックスラッシュを省略する方法を見つけたり、MUP コードの解析の不整合を見つけたりするなど、より複雑なソリューションが必要なのかもしれません。これは、さらなる調査の余地があることを示しています。
2 つ目の試み:バイパス #1(CVE-2023-29324)
絶対 UNC パスを使用する方法ではうまくいかなかったため、次は UNC をサポートする別の種類のパスを使用しました。それが、 RtlPathTypeLocalDeviceです。「\\.\UNC\Akamai.com\test.wav」は、ローカル・デバイス・パスの例です。具体的には UNC デバイス名を示しており、MUP ドライバーにリダイレクトされます。
前述のとおり、バイパスを見つけるには、パスの解析の一環として実行されるさまざまな操作を確認する必要があります。表 4 はその違いを示しています。
CreateFile |
MapUrlToZone |
---|---|
RtlPathTypeLocalDevice の場合 → 4 文字進む |
RtlPathTypeLocalDevice の場合 → 4 文字進む |
末尾のスペースをスキップする |
|
「/」を「\」に変換する |
|
連続した「\」を折り畳む |
|
「.」および「..」コンポーネントを削除する |
「.」および「..」コンポーネントを削除する |
表 4:パス解析の一環として実行されるさまざまな操作
結果として、 CreateFile の方が実行する操作が多いことがわかりました(スラッシュからバックスラッシュへの変換や連続したバックスラッシュの折り畳みなど)。
このような違いの 1 つを活用するパスを見てみましょう。その違いとは、余分なパス区切り文字を使用することです。表 5 は、コードが「UNC\」プレフィックスをスキップした後の結果パスを示しています。
入力パス:\\.\UNC\\Akamai.com\test.wav |
|
---|---|
CreateFile |
MapUrlToZone |
Akamai.com\test.wav |
\Akamai.com\test.wav |
表 5:「UNC/」プレフィックスをスキップした後の結果パス
右列のパスに注目してください。パス区切り文字で始まり、パス区切り文字ではない文字が続くパスは、 「ルート化されたパス」と呼ばれます。MapUrlToZone は、 IsRootedPath 関数や IsDrivePath 関数を使用して、ルート・パス・コンポーネントがローカルかどうかを判断します。この場合、パスはルート化されているため、 MapUrlToZone はローカルを返します。
CreateFile は、UNC プレフィックスの後に余分なパス区切り文字がないため、ドメイン名を正しく抽出しなければならないことを認識しており、この例では Akamai.com SMB サーバーにアクセスして test.wav ファイルを取得します。 MapUrlToZone にはローカルと見なされるが、 CreateFile にはローカルと見なされないパスが見つかりました。このバイパスによって、Outlook の脆弱性 CVE-2023-23397を再び悪用できるようになります。
この問題を緩和するために、Microsoft は 2 つのフローをより類似させようとしました。そして、スラッシュからバックスラッシュへの変換の操作と、連続したパス区切り文字の折り畳みの操作が、 MapUrlToZone に追加されました。
検討
前のセクションでは、 MapUrlToZone が、「\\.\UNC\」の後のパスコンポーネントがドライブまたはルート化されたパスであるかを確認することがわかりました。修正後は、このパスコンポーネントをルート化されたパスにすることはできません。なぜなら、連続したパス区切り文字が折り畳まれるからです。しかし、たとえば「\\.\UNC\C:Akamai.com/test.wav」といったドライブパスを指定することはできます。
そうすると、 MapUrlToZone は 0 を返します。残念ながら、コロンを含むパスを処理できるネットワークプロバイダーはないため、この混乱を利用することはできません。最初の(失敗した)試みと同様に、MUP 解析コードに伴う混乱が見つかれば、新たな脆弱性につながる可能性があります。
3 つ目の試み:バイパス #2(CVE-2023-35384)
修正後に 2 つの関数によって実行される操作は、ほぼ同じです(表 6)。
CreateFile |
MapUrlToZone |
---|---|
RtlPathTypeLocalDevice の場合 → 4 文字進む |
RtlPathTypeLocalDevice の場合 → 4 文字進む |
末尾のスペースをスキップする |
|
「/」を「\」に変換する |
「/」を「\」に変換する |
連続した「\」を折り畳む |
連続した「\」を折り畳む |
「.」および「..」コンポーネントを削除する |
「.」および「..」コンポーネントを削除する |
表 6:修正後に CreateFile と MapUrlToZone によって実行される操作
しかし、さらに深く掘り下げるために、次の疑問について考えてみます。それぞれの関数は、パスがローカル・デバイス・パスであるとどのように判断するのでしょうか?表 7 は、パスの種類の判断に関わる各関数のコードスニペットを示しています
CreateFile
if (IS_PATH_SEPARATOR(Path[0]) &&
IS_PATH_SEPARATOR(Path[1]) &&
(Path[2] == '.' || Path[2] == '?') &&
IS_PATH_SEPERATOR(Path[3])
return RtlPathTypeLocalDevice;
MapUrlToZone
!strncmp(path, "\\.\", 4) || !strncmp(path, "\\?\", 4)
表 7:パスの種類を判断するコードスニペット
CreateFileでは、パス区切り文字はスラッシュとバックスラッシュのどちらでも構いません。たとえば、「\\./」はローカル・デバイス・パスと見なされます。 MapUrlToZoneでは、「\\.\」または「\\?\」とぴったり一致するパスのみがローカル・デバイス・パスと見なされます。 これはパスの種類の混乱です。 CreateFile にはコンポーネント「\\./」をローカル・デバイス・パスとして認識させることができますが、 MapUrlToZone は、そのようには認識しません。この混乱は、2 つの関数が異なる方法でパスを処理するため生じます。
これを念頭に置いて、混乱を引き起こすコンポーネントを含むパス「 \\./UNC/Akamai.com/file.wav」を使用してみましょう。
このパスの種類を判断するフローを分析すると、 MapUrlToZoneでは次のようなフローになります。
このパスはローカルドライブまたはルート化されたパスか?いいえ
IsLocalDeviceUNC の判断は?いいえ
PathIsUNCWの判断は?はい
PathIsUNCW は true を返します。そして、この関数はそれを 絶対 UNC パス としてマークし、2 文字進んで UNC プレフィックス「\\」をスキップします。各関数の出力を示したのが表 8 です。
入力パス:\\./UNC/Akamai.com/file.wav |
|
---|---|
CreateFile |
MapUrlToZone |
UNC\Akamai.com\file.wav |
./UNC/Akamai.com/file.wav |
表 8: CreateFile 関数と MapUrlToZone 関数のパス出力
このとき、 CreateFile は、出力は UNC パスであり、Akamai.com はホスト名であると判断します。
一方、 MapUrlToZone は次のように判断します。
スキーム:file://
ホスト:. (ドット)
パス:/UNC/Akamai.com/file.wav
絶対 URI:file://./UNC/Akamai.com/file.wav
絶対 URI が「file://./」で始まる場合(ホストは「.」)、コードは共用名を DOS デバイスの名前空間の一部として解釈します(図 3)。したがって、「file://./UNC/」は UNC 名前空間を指します。
わかりやすく言うと、どちらの関数も入力パスを UNC パスと見なしますが、パスの種類が異なるということです。 CreateFile は Windows ローカル・デバイス・パスとして扱いますが、 MapUrlToZone は URL として認識します。
ここで、2 つの関数の間で混乱を引き起こすことができます。しかし、トリックを使わなければ、 MapUrlToZone は引き続き Akamai.com をホスト名として解釈します。このホスト名はインターネットドメインであるため、この関数は 3 を返します。これはバイパスではありません。この解析プロセスを悪用するためには、別の方法を見つける必要があります。
先に進むと、 MapUrlToZone は内部関数 SetPath を使用して、パスコンポーネントを操作します(表 9)。
CreateFile |
SetPath |
---|---|
RtlPathTypeLocalDevice の場合 → 4 文字進む |
|
末尾のスペースをスキップする |
|
「/」を「\」に変換する |
|
連続した「\」を折り畳む |
|
「.」および「..」コンポーネントを削除する |
「.」および「..」コンポーネントを削除する |
表 9: CreateFile と SetPath によって実行される操作の比較
再び、2 つの関数によって実行される操作の違いを活用することができます。過去の脆弱性から、余分なスラッシュを追加することがバイパスにつながる可能性があることがわかっているため、それを再度試みることは理にかなっています。CreateFileは余分なスラッシュを削除するだけです。
MapUrlToZone では、CreateUri が絶対 URI「file://./UNC//Akamai.com/file.wav」を返します。この URI はGetZoneFromUriInternalに渡され、内部で別のCreateUriの呼び出しにつながります。
なぜそれが問題なのでしょうか?CreateUriは URL を受け取るため、PathCreateFromUrlWを使用してそれを変換し、Windows パスに戻します。返される Windows パスは「\\.\UNC\\Akamai.com\test.wav」です。修正済みのバージョンは、余分なスラッシュを削除しなければならないことを認識しており、Akamai.com がホスト名であることを正しく理解します。
したがって、CreateFileとSetPathの違いを悪用するためには、より複雑な方法が必要です。今回は、次の 2 つの違いを悪用します。
CreateFileは連続したパス区切り文字を折り畳みます。
CreateFileは連続したパス区切り文字を折り畳み、その後「.」および「..」のコンポーネントを削除します。
その両方の違いを悪用するパスが、「 \\./UNC/C://./Akamai.com/file.wav」です。図 4 はその処理を詳細に示したフローチャートです。
図 4:2 つの関数によるパス解析のフローチャート
CreateFileの最終パスが UNC パスとして扱われることは、すでにわかっています。 SetPathの出力では、 MapUrlToZone が絶対 URI「file://./UNC/C:/Akamai.com/file.wav」によって GetZoneFromUriInternal を呼び出します。今回は、 PathCreateFromUrlW がこの URL を Windows パス「\\.\UNC\C:\Akamai.com\file.wav」に変換します。 これはローカルパスであるため、 MapUrlToZone は 0(ローカル)を返します。またしても巧妙なバイパスが見つかりました!
この問題を解決するために、コードは NormalizeDosDevicePrefix を呼び出し、スラッシュをバックスラッシュに変換して、ローカル・デバイス・パスの検知における混乱を防止するようになりました。
検知と緩和
Microsoft は元の Outlook の脆弱性を検知して緩和するための 包括的なガイダンス を公開しました。Akamai の調査によると、指定されたすべてのメソッドは、 PidLidReminderFileParameter プロパティで指定された URL に依存しないため、新しい脆弱性に適用できます。
Akamai は、組織で マイクロセグメンテーション を利用し、リモートパブリック IP アドレスへの発信 SMB 接続をブロックすることを推奨します。さらに、環境内で NTLM を無効にするか、ユーザーを Protected Users グループに追加し、NTLM を認証メカニズムとして使用できないようにすることを推奨します。
発信 SMB 接続をブロックし、NTLM を無効にすれば、認証情報の窃取を防止できます。しかし、SMB 要求が失敗した場合、WebDAV が有効になっていると、Windows は WebDAV に移行します。WebDAV 経由で認証情報を窃取することはできませんが、RCE チェーンの第 2 段階である音声ファイルのダウンロードは可能です。
今すぐ阻止すべき理由
この記事では、2 つのバイパスの探索につながった調査のプロセスについて根本原因分析などを含めて詳しく説明しました。前述のとおり、Windows のパス解析コードは複雑であり、多くの場合、脆弱性につながる可能性があります。パス処理コードに遭遇したセキュリティ研究者は、そのコードによって生じるアタックサーフェスについて検討することが推奨されます。
Outlook における MapUrlToZone のバイパス以外にも、そのような脆弱性が Mark-of-the-Web (MOTW)バイパスにつながる可能性があることを否定できません。
攻撃者は NTLM 認証情報を流出させることができるだけでなく、任意の音声ファイルをダウンロードさせて再生させることができます。このブログシリーズの 第 2 部では、音声解析の脆弱性について詳しく説明します。