呼び出しと登録 — WinReg RPC クライアントに対するリレー攻撃
エグゼクティブサマリー
Akamai の研究者である Stiv Kupchik が、Microsoft の Remote Registry クライアントに新しい権限昇格(EOP)の脆弱性 CVE-2024-43532を発見しました。この CVE の CVSS スコアは 8.8 です。
この脆弱性は、WinReg クライアント実装のフォールバックメカニズムを利用します。このメカニズムは、SMB トランスポートが使用できない場合に、古いトランスポートプロトコルを安全でない方法で使用します。
この脆弱性を悪用することで、攻撃者はクライアントの NTLM 認証の詳細を Active Directory 証明書サービス(ADCS)にリレーし、ユーザー証明書を要求してドメイン内でのその後の認証に利用することができます。Akamai は概念実証を GitHub リポジトリで提供しています。
この脆弱性は、2024 年 2 月に Microsoft セキュリティリソースセンターに責任を持って開示され、2024 年 10 月の Patch Tuesday の一部としてパッチが適用されました。
この脆弱性は、パッチが適用されていないすべての Windows バージョンに影響を及ぼします。
Akamai の調査結果は、 No Hat コンピューター・セキュリティ・カンファレンスでも発表されました。
はじめに
MS-RPC は、Microsoft による Remote Procedure Call(RPC)プロトコルおよび標準の実装です。RPC はプロセス間通信メカニズムの一形態であり、他のプロセスが呼び出すことのできる機能をプロセスが公開できるようにします。これは Windows オペレーティングシステムのコアコンポーネントであり、サービスマネージャーから wininit のシャットダウンまで、複数のサービスが利用しています。
Akamai のチームは、MS-RPC について多くの研究を行ってきました。 攻撃 研究によってキャッシング攻撃の形をとった大規模な攻撃ベクトルを発見し、 防御 研究でそのセキュリティメカニズムを分析しました。
そして今回は、別の観点から RPC を調べてみたいと思いました。異なるコンピューター間での通信や操作を可能にするプロトコルはどれも、必ずユーザー認証に関わっています。実際、RPC プロトコルは、 バインディングプロセスの一環として認証情報の受け渡しと認証をサポートします。しかし、認証が行われるところでは、認証リレーが行われる可能性があります。そのため、私たちはリレーの機会を見つけることを試みました。
RPC、認証、その間にあるもの
RPC セッションは バインディングによって処理されます。クライアントアプリケーションはサーバーアプリケーションに接続して、必要な RPC インターフェースにバインドし、特定の機能を実行するように要求します(図 1)。
バインド要求と応答は、接続の際に必要に応じて複数のデータフィールドを伝送できます。通常、認証に関係しない場合、RPC バインディングは単に、後続の呼び出しで関数パラメーターをカプセル化するために使用される 転送構文 を決定するのに使用されます。
このインタラクションに欠けているものは何でしょうか?もちろん認証です!サーバーはどうすれば、クライアントのアイデンティティと、そのクライアントが要求されたアクションを実行できるかどうかを把握できるでしょうか?答えは、「クライアントが明確にバインディングにセキュリティコンテキスト(認証)を追加しない限り、把握できない」です。デフォルトでは、すべての RPC 接続は認証されておらず、すべての RPC サーバーが実際に認証を必要とするわけではありません。
認証(RPC 用語では「セキュリティコンテキストの追加」)を行うためには、クライアントがバインディング要求にデータを追加し、認証プロトコル(NTLM や Kerberos など)をネゴシエートして、認証プロトコルに必要な追加のメタデータ(ユーザー名、ドメインなど)を挿入する必要があります(図 2)。
調査対象を見つける
まずやらなければならないことは、API の視点からどのように認証が行われるかを理解することです。これは、バインディングハンドルを作成した後にクライアントから RpcBindingSetAuthInfo* 関数のいずれかを呼び出すことによって行われます。これらの関数のドキュメントを見てみると、 AuthenticationLevel(認証レベル)というフィールドがあります。これは、認証によってもたらされるセキュリティのレベルを表します。
認証によるセキュリティは、ユーザーが存在し承認されていることを確認するだけでなく、改ざんの防止にも使用できます。認証レベルは、単に接続が成功したことを確認する場合(RPC_C_AUTHN_LEVEL_CONNECT)から、すべてのトラフィックを完全に暗号化して署名し、何も改ざんされないようにする場合(RPC_C_AUTHN_LEVEL_PKT_PRIMARK)まで、さまざまです。もちろん、攻撃者にとって魅力的なのは前者のレベルであり、その場合、トラフィックに対する防御がないため、改ざん可能です。
しかし、話はそれほど単純ではありません。RPC リレー攻撃は新しい概念ではないため、Windows の多くの RPC クライアントとサーバーには、リレー攻撃が成功しないように、最高レベルの認証を使用するためのパッチがすでに適用されています。何らかの理由で未だに安全でない古いコードは貴重なものであり、それを見つけるためには、オペレーティングシステムを徹底的に調べる必要があります(図 3)。
WinReg — 有望な候補
思ったとおり、私たちが発見した潜在的なターゲットのリストには、全 RPC サーバーおよびクライアントの 5% 未満しか含まれておらず、ほとんどはもはや安全でない認証を使用していません。しかし、有望な候補が advapi32.dllに見つかりました。
advapi32.dll は Windows API のコアコンポーネントであり、その名のとおり Windows で多くの「高度な」ロジックを実行しています。イベントログ、暗号化、WMI など、さまざまなフィールドから 800 を超える関数をエクスポートします。
私たちは、この調査のために、内部関数 BaseBindToMachine が RpcBindingSetAuthInfoA を RPC_C_AUTHN_LEVEL_CONNECT の認証レベルで呼び出す場合があることを発見しました。これは、私たちが求めていたものです。 BaseBindToMachine は、エクスポートされた(ドキュメント化されていない)関数 RegConnectRegistryExW がマシン名の UNC パスを受け取った場合に、この関数によって呼び出されます(図 4)。
BaseBindToMachineを見てみると、実際には RpcBindingSetAuthInfoW と RpcBindingSetAuthInfoAの両方の呼び出しが含まれていることがわかります。前者は認証レベル RPC_C_AUTHN_LEVEL_PKT_PRIVACY で安全に使用されます。後者は認証レベル RPC_C_AUTHN_LEVEL_CONNECT を使用しますが、これは接続の信頼性や完全性を検証しないため、リレーすることができます(図 5)。
競合する 2 つの呼び出しがある理由を把握する必要があります。関数ロジックを見てみると、関数ポインター変数と関数の配列があることがわかります(図 6)。これらの関数は、特定の RPC トランスポートを使用するように RPC バインディング情報を設定します。デフォルトでは、SMB と名前付きパイプを使用しようとしますが、失敗した場合は、SPX や TCP/IP などでバインドを試みます。
何らかの理由で、SMB 以外のプロトコルにフォールバックすると、 RpcBindingSetAuthInfoA を使用して認証レベルを Connect に設定します。これは安全ではありません。
TCP/IP へのフォールバックは非常に有望です。なぜなら、クライアントに気付かれることなく、安全でない認証方式を使用し、Machine-in-the-middle 攻撃によってトラフィックをリレーできるからです。他のトランスポートプロトコルでも可能ですが、それらはかなり古いので、現代のネットワークでそれらを見つけるのは非現実的かもしれません(また、使用するとアラームベルがトリガーされる可能性があります)。TCP/IP は RPC トランスポートとしてはるかに一般的であるため、レッドチーム環境でも問題はないはずです。
重要なのは、 BaseBindToMachine と RegConnectRegistryExW のどちらもフォールバック動作を防止する引数としてフラグを受け入れますが、基本関数 RegConnectRegistryW はそのフラグがなくても RegConnectRegistryExW を呼び出すということを知っておくことです。
リレープロセス
NTLM リレーは一般的な技術であるため、リレーは非常に簡単です。必要なロジックの大部分はすでに Impacketの ntlmrelayx に実装されており、私たちはこれを主に使用することとなります。
RPC リレーサーバーの構築
ntlmrelayx には SMB サーバーのみ実装されているため、TCP/IP RPC サーバーがありません。そのため、WinReg の名前付きパイプを拒否して TCP/IP バインディング関数へのフォールバックをトリガーする独自のリレーサーバーを構築する必要があります。
実装する必要がある重要なポイントは次の 3 つです。
RPC エンドポイントマッパー
NTLM を使用する RPC バインド要求
NTLM チャレンジ
RPC エンドポイントマッパーは、RPC インターフェース UUID をそれぞれのエンドポイントに変換します。TCP/IP トランスポートの場合は、ポート番号になります。SMB の場合、エンドポイントは事前に把握できる固有の名前付きパイプですが、SMB とは違って TCP エンドポイントはエフェメラルポートを使用するため、別の変換レイヤーが必要です。
重要なのは、NTLM 関連の問題です。RPC バインディングと NTLM の連携は、バインド要求中に NTLM ネゴシエーションメッセージが送信され、続いてバインド応答とともに NTLM チャレンジが送信されるという方法で行われます。最後に、クライアントはチャレンジ応答とともに AUTH3 という別のメッセージを送信する必要があります(図 7)。
リレーするためには、RPC サーバー内の対応するメッセージを解析しなければなりません。バインドメッセージに NTLM ネゴシエーションメッセージが含まれていたら、ターゲット認証サーバーへの独自の接続をオープンし、NTLM による認証を要求します。次に、サーバーから送信されたチャレンジを取得して、それを標的にリレーし、サーバーに応答をリレーすると、セッションが認証されます。
考えなければならないことは、どのサーバーで認証をリレーするかだけです。
RPC から RPC へのリレー
すぐに思いつくのは、サービスマネージャーやタスクスケジューラーなど、別のマシン上の別の RPC サーバーにリレーして、リモートコード実行を達成することです。しかしこれには、RPC による安全でない認証を使用する人はもはやいないため、重要な RPC サーバーにはリレーできないという問題があります。 (このように RPC による安全でない認証が行われていない理由は、私たちの調査対象が限られている理由と同じです。)
サービスマネージャーとタスクスケジューラーのどちらの RPC サーバーも、RPC_C_AUTHN_LEVEL_PKT_PRIVACY を必要とします。これは、クライアントの NTLMv2 ハッシュを使用してトラフィック全体を暗号化します。このハッシュは、リレーでさえ把握できません。これは諦めて、別の角度から検討する必要があります。
RPC から ADCS へ
幸いにも、SpectterOps 社の皆さんが ADCS(特に ADCS への NTLM リレー)についてたくさんの調査を実施しています。これは Impacket にもデフォルトで実装されているため、認証されたセッションを Impacket の HTTPAttack モジュールに渡して、魔法がかかるのを待つだけで済みます。
ADCS の HTTP Web サーバーはセキュリティを必要とせず、リレー攻撃に対して脆弱です。それを悪用すれば、認証完了後にユーザー証明書を要求して、それを認証に使用できるため、わざわざ認証を再度リレーする必要はありません(図 8)。
私たちはこの証明書を使用して、ドメインコントローラー上の LDAP サービスへの認証を行い、侵害されたドメインに永続的な新しいドメイン管理者を作成しました(図 9)。
潜在的な影響
advapi の関数自体は魅力的でなく、他の何かがそれを使用している場合にのみ影響力があります。 RegConnectRegistryExW または RegConnectRegistryExA のインポートを手早く検索しても、最新のドメインコントローラーには何も表示されません。しかし、 RegConnectRegistryW を検索すると、certutil や certsrv(AD CS)、EFS、DFS など、多くの潜在的な候補が見つかります。
検知
Remote Registry サービスは、すべての Windows マシンでデフォルトでは有効になっていません。次の osquery を使用して、ステータスを検知できます。
SELECT display_name, status, start_type, pid FROM services WHERE name='RemoteRegistry'
しかし、これは CVE-2024-43532から保護するものではありません。なぜなら、それはクライアントの問題だからです。クエリーの結果として、システムを強化する際に考慮する必要があるかもしれない、組織内での Remote Registry の実際のユースケースが浮かび上がるはずです。
脆弱な WinAPI を使用するクライアントを検知するためには、次の YARA ルールを使用します。
import "pe"
rule winreg_client_import {
meta:
description = "Detect binaries that rely on RegConnectRegistry"
author = "Stiv Kupchik with Akamai Technologies"
condition:
pe.is_pe and (
pe.imports(pe.IMPORT_ANY, "advapi32.dll", "RegConnectRegistryA")
or pe.imports(pe.IMPORT_ANY, "advapi32.dll", "RegConnectRegistryW")
or pe.imports(pe.IMPORT_ANY, "advapi32.dll", "RegConnectRegistryExA")
or pe.imports(pe.IMPORT_ANY, "advapi32.dll", "RegConnectRegistryExW")
)
}
Akamai Guardicore Segmentation ユーザーは、RemoteRegistry サービスへのトラフィックに関するポリシールールを作成することもできます(図 10)。
また、Event Tracing for Windows(ETW)を使用して、通信のクライアント側とサーバー側の両方で RPC トラフィックを監視することもできます。このトピックについては、 Black Hat 2023 でのプレゼンテーションとその 付随ブログ記事で詳しく説明しました。ユーザーは Akamai の RPC 可視性オープンソースツール を使用して、RPC 呼び出しを追跡し、フィルタリングによって WinReg RPC インターフェース UUID {338cd001-2244-31f1-aaaa-900038001003}に絞り込むことができます。
結論
RPC プロトコル(および MS-RPC)はセキュリティを考慮して構築されていますが、さまざまな RPC インターフェース実装を分析してみると、時間の経過とともにセキュリティの原理が進化していることが明確にわかります。現在、ほとんどの RPC サーバーとクライアントは安全です。しかし時々、程度の差こそあれ、時代遅れの安全でない実装を見つけることができます。
この調査では、NTLM リレーを実行することができました。これは、過去のものと言ってよい類の攻撃です。このことは、どの時代遅れのインターフェースが未だに公開または実行されているかわからないため、ネットワーク防御を可能な限り徹底する必要があることを示しています。
開示のタイムライン
2024/02/01 — MSRC に脆弱性を開示
2024/04/25 — ドキュメンテーションの問題として報告を終了
2024/06/17 — より適切な PoC と説明によって報告を再開
2024/07/08 — 脆弱性を確認
2024/10/08 — 脆弱性にパッチを適用
2024/10/19 — ブログ記事を公開