2023年8月17日

#NoFilter - 特権昇格のためのWindowsフィルタリングプラットフォームの悪用

イントロダクション

このブログは、2023813日(日)にラスベガスで開催されたDEF CON 2023で発表した講演 「#NoFilter: 特権昇格のためのWindowsフィルタリングプラットフォームの悪用」に基づいています。

特権昇格は、Windows OSにおける一般的な攻撃ベクトルです。”NT AUTHORITYSYSTEM "としてコードを実行できる攻撃ツール(MeterpreterCobaltStrikePotatoツール)は複数存在し、いずれも通常、トークンを複製してサービスを操作することで実行します。これにより、 LSASS Shtinkering のような攻撃を行うことができます。

この講演では、Windowsフィルタリングプラットフォーム(WFP)を悪用した、回避的で検出されない特権昇格テクニックを紹介しました。さらに、基本フィルタリングエンジン、TCPIPドライバ、IPSecプロトコルなど、Windowsフィルタリングプラットフォームのさまざまなコンポーネントを分析し、それらを悪用して貴重なデータを引き出す方法に焦点を当てました。このブログでは、講演の詳細を説明します。

アクセストークンの背景

アクセストークンは、プロセスとスレッドのセキュリティ・コンテキストを表すものです。スレッドが特権タスクを実行したり、セキュリティで保護されたオブジェクトとやりとりするとき、アクセストークンは関係するユーザーを識別する役割を果たします。アクセストークンはプロセスの身元を詳細に示すもので、実行したユーザー、所属するグループとログオンセッション、プロセスの特権など、いくつかの要素で構成されます。スレッドがデバイスやミューテックスなどのオブジェクトにアクセスしようとすると、トークンのセキュリティ識別子がチェックされ、アクセスが許可されているかどうかが確認されます。

トークンにはプライマリとインパーソネーションの2種類があります。プライマリー・トークンは、プロセスに関連付けられたユーザー・アカウントのセキュリティー・コンテキストを記述します。インパーソネーショントークンは、スレッドにプロセスの所有者とは異なるセキュリティコンテキストで実行する能力を与えます。これらは、サーバー・アプリケーションに接続するクライアントのセキュリティ・コンテキストを表すために使用されます。

のプロセスのトークンは、DuplicateToken または DuplicateHandle を呼び出すことでアクセスできます。また、スレッドは、"NT AUTHORITYSYSTEM "として実行されているRPCおよびCOMサーバを操作し、ImpersonateNamedPipeClient、CoImpersonateClient、またはRpcImpersonateClientなどのAPIを呼び出すことで、高特権のなりすましトークンを取得できます。

RPC マッパー

Deep Instinctセキュリティ研究チームは、RPCメソッドをマッピングするツールを開発した。このツールの目的は、良性のサービスを操作して、コード・インジェクションやファイル暗号化などの悪意のあるアクションを実行する方法を見つけることです。

システム上のすべてのRPCサーバーがマッピングされ、WinAPIに送信されるパラメータがRPCクライアントによって制御される場合、メソッドがマークされました。WinAPIはRPCメソッドによって直接呼び出されるか、いくつかの内部呼び出しの後に呼び出されます。RPC メソッドは、その名前に特定のキーワードが含まれている場合にもマークされました。例えば、ツールはd3d10warp.dllからのRPCメソッドがReadProcessMemoryにつながることを発見しました:

このツールの結果は、BFE.DLLにつながります。それは194のRPCメソッドを公開し、様々な興味深いWinAPIを呼び出します。次のPowerShellスクリプトは、RPCメソッドをマークするプロセスを示しています:

これはBfeRpcOpenTokenを明らかにしたメソッドで興味深いキーワードを探しています。このDLLはWindows Filtering Platformの一部です。

Windows フィルタリング プラットフォーム

Windowsフィルタリングプラットフォームは、専用のAPIを持つネイティブプラットフォームです。アプリケーション、ユーザー、アドレス、ポートなどのいくつかのフィールドに基づいて、システム内の任意のレイヤーでネットワークトラフィックをブロックまたは許可する機能を提供します。ネットワーク・スタックをフックし、ネットワーク・スタックの相互作用を調整するフィルタリング・エンジンを使用することで、ネットワーク・トラフィックを処理します。これにより、ネットワーク監視ツール、侵入検知システム、ホストファイアウォールなどのセキュリティ製品の開発が可能になります。

プラットフォームはいくつかのコンポーネントで構成されています:

コールアウト・ドライバー:プラットフォームの機能を拡張するためにロードし、統合することができるユーザー定義ドライバー。これらのドライバはネットワークデータを受信し、プロトコルの特定のフィールドに従ったパケットのディープインスペクション、パケットの修正、カスタムロギングの実行など、プラットフォームが提供しないカスタムな方法で処理することができます。

フィルター・エンジン: OSのネットワークスタックから複数のレイヤーを使用してネットワークデータをフィルタリングするように設計されたコンポーネント。レイヤーはユーザーモードとカーネルモードで設定されます。ユーザー・モードのコンポーネントは、RPC と IPSec ネットワーク・データをフィルターします。カーネル・モード・エンジンは、TCP/IPスタックのネットワーク・レイヤーとトランスポート・レイヤーをフィルタリングします。また、コールアウト・ドライバにネットワーク・データを送信します。

ベース・フィルタリング・エンジン(BFE): BFE.DLLに実装されているユーザー・モード・サービスで、ユーザーとの対話のための管理関数もエクスポートします。svchost.exeの下で実行され、WFPコンポーネントを制御します。フィルタを追加または削除するコマンドを受け付け、プラットフォームに関するデータと統計情報を提供し、システム内の他のコンポーネントに構成設定を転送します。

以下のスキーマは、プラットフォームの概要です:

https://learn.microsoft.com/en-us/windows/win32/fwp/windows-filtering-platform-architecture-overview

FWPUCLNT.DLL

FWPUCLNT.DLLは、BFE.DLLへのRPCコールをラップするドキュメント化された関数をエクスポートします。

FwpsOpenToken0は、engineHandleとmodifiedIdをBfeRpcOpenTokenに送信し、desiredAccessパラメータで指定されたパーミッションで現在のプロセスに複製するハンドルを受け取ります。複製されたハンドルはaccessTokenパラメータで呼び出し元に返されます。

FwpsOpenToken0 のパラメータは、BfeRpcOpenToken のリバースエンジニアリングに役立ちます。

BFE.DLL

BfeRpcOpenTokenはBfeDriverTokenQueryを呼び出し、エラーがなければBFEサービスのプロセスIDがトークンのハンドルとともにRPCクライアントに返されます。

BfeDriverTokenQueryは、デバイス"˶.˶WfpAle "にデバイスIOリクエストを送信します。入力バッファはmodifiedId値で、出力バッファはトークンへのハンドルです。

WfpAle

デバイスWfpAleはドライバtcpip.sysによって作成されます。このドライバはWindows OSの主要コンポーネントであり、さまざまな機能を提供する多くのデバイスを登録します: IPSECDOSP、NXTIPSEC、eQoSなどです。

WfpAleへのデバイスIOリクエストによって呼び出されるtcpip.sysの関数を以下の表に示します:

制御コード

Tcpip機能

BFE機能

0x124008

WfpAleQueryTokenById

BfeRpcOpenToken

0x124018

WfpAleProcessEndpointPropertiesQuery

BfeRpcAleEndpointGetById

0x12401E

WfpAleProcessEndpointEnumIoctl

BfeRpcAleEndpointCreateEnumHandle

0x124020

sets tcpip!gMaxInboundSeqRanges global variable

BfeRpcEngineSetOption

0x128000

WfpAleProcessTokenReference

BfeDriverTokenAddRef

0x128004

WfpAleReleaseTokenInformationById

BfeDriverTokenRelease

0x128010

WfpAleProcessExplicitCredentialQuery

BfeRpcAleExplicitCredentialsQuery

Tcpip.sys

BFEサービスが呼び出す関数はWfpAleQueryTokenByIdです。これは、この研究の目的のために TOKEN_ENTRY と名付けられた文書化されていない構造体を使用します。

デバイスIOリクエストで送られたmodifiedId値で、受信したLUIDに基づいてエントリを見つけようとします。見つかった場合、DuplicateTokenが呼び出されます。希望するアクセスはTOKEN_DUPLICATEにハードコードされ、トークン・タイプはTokenPrimaryになります。

デバイスIOリクエストを送信してカーネル内のAPIを呼び出すことは、ユーザーモードのフックをバイパスするのに便利です!

このクエリーの最後のステップは、ハッシュテーブルを繰り返し、正しい値に一致するエントリーを探すことです。

このクエリーの最後のステップは、ハッシュテーブルを繰り返し、正しい値に一致するエントリーを探すことです。

トークン・クエリのまとめ

クエリは、FWPUCLNT.DLL に実装された RPC クライアントから始まり、BFE サービスのメソッドを呼び出します。このサービスは、tcpip.sys ドライバにデバイス IO リクエストを送信し、いくつかの内部関数の後、ハッシュ・テーブルが反復されます。

gAleMasterHashTable

このテーブルはtcpipドライバの30以上の関数で使用されます。プロセス情報、ピア情報、接続コンテキストなどという名前の、 ドキュメントにない様々な構造体を格納します。

トークン・エントリは、関数 WfpAleInsertTokenInformationByUserTokenIdIfNeeded によって追加されます。

OSのブート・プロセスをデバッグすると、この関数が一度も呼び出されないことがわかります。つまり、デフォルトでは、取得できるトークン・エントリが存在しないことになります。

トークンの挿入

挿入関数は WfpAleProcessTokenReference によって呼び出され、制御コード 0x128000 でデバイス IO 要求を送信することで呼び出すことができます。この特定のリクエストを送信するBFEサービスの関数はBfeDriverTokenAddRefですが、RPCによって直接公開されていません。この関数は、簡単には作成できない特定の条件下で呼び出されます。このデバイス IO 要求をトリガすると、トークンがテーブルに挿入されます。

WfpAleProcessTokenReferenceは、プロセスIDとトークンへのハンドルを含む構造体を受け取ります。

この関数の面白いところは、呼び出し元が任意のpidを設定でき、プロセスが別のプロセスのIDを指定できます。そのためこの設計は悪用されやすいのです。

この関数は、現在のスレッドをPIDパラメータで指定されたプロセスのアドレス空間にアタッチし、新しいトークンを複製して、ハッシュ・テーブルに新しいエントリを挿入します。新しいトークンのLUIDは、デバイスIOリクエストの出力バッファに返されます。

WfpAleへのアクセス

トークンをハッシュテーブルに挿入するBFEサービスへのRPCコールはありません。デバイスのIO要求を直接tcpipドライバに送ればこの問題は解決しますが、デバイスWfpAleは、BFEサービス以外のプロセスがそれへのハンドルを得ることをブロックするセキュリティ記述子で作成されます。

デバイスにセキュリティ記述子を追加する関数は WfpAllowBfeGenericAll であり、BFE サービスのトークンは、デバイスにアクセスするために含まれる一意のセキュリティ識別子を示します。

BFEサービスは、デバイスへのオープンハンドルを持ち、このハンドルは、別のプロセス用に複製することができます。これにより、どのプロセスもデバイス WfpAle にアクセスできるようになります。これは、セキュリティ記述子がハンドルの複製をブロックせず、新しいハンドルの作成のみをブロックするためです。

デバイスへのハンドルを複製するには、デバッグ権限と、PROCESS_DUP_HANDLE と PROCESS_QUERY_INFORMATION の権限を持つ BFE サービスへのハンドルが必要です。これらの要件は不審なものではないので、セキュリティ製品を起動させるべきではありません。Process Hacker のようなツールは、プロセスのハンドル・テーブルを表示するためにこれらのタイプのハンドルを開き、FWPUCLNT.DLL に実装された RPC クライアントも BFE サービスから他のプロセスへのハンドルを複製します。

また、デバイスの IO 要求を直接送信することで、DuplicateToken や DuplicateHandle への不審な呼び出しを行わず、検知を回避することができます。これらのAPIが、"NT AUTHORITYSYSTEM "に属するトークンへのハンドルを、より低い権限を持つプロセスに返すと、セキュリティ製品によって検出される可能性があります。

RPCクライアントを使用する場合、DuplicateHandleを呼び出すことで、トークンへのハンドルをBFEサービスから現在のプロセスに複製する必要があります。このトークンが持つパーミッションはTOKEN_DUPLICATEのみで、新しいプロセスを起動するには十分ではないため、十分なパーミッションを持つトークンを取得するにはDuplicateTokenを呼び出す必要があります。

デバイスIOリクエストを直接送信することで、トークンはBFEサービスではなく現在のプロセスに送信され、これらのAPIコールは不要になります。

攻撃1 - WFP経由でのトークンの複製

別のプロセスのハンドルテーブルは、NtQueryInformationProcessを呼び出すことで取得できます。このテーブルには、そのプロセスが保持するトークンが一覧表示されます。これらのトークンのハンドルを複製して、別のプロセスで SYSTEM にエスカレーションすることができます。

このテクニックは、ユーザーモードからDuplicateHandleを呼び出す代わりに、カーネル内で複製を実行するように変更できます。

WfpAleProcessTokenReference を呼び出すために、デバイス IO リクエストが送信されます。これは、サービスのアドレス空間にアタッチし、SYSTEMに属するサービスのトークンを複製し、ハッシュテーブルに格納します。

新しいトークンのLUIDが呼び出し元に返され、そのLUIDでWfpAleQueryTokenByIdが呼び出されます。SYSTEMトークンへのハンドルが呼び出し元に返されます。ハンドルのアクセスはTOKEN_DUPLICATEにハードコードされていますが、TOKEN_ALL_ACCESSパーミッションを得るために複製することができます。

この方法は、概要にある技術と比較されました。LSM、Winmgmt、Scheduleなど、いくつかのサービスのトークンは、この方法を使用することによってのみ複製することができます。

さらに、SYSTEMトークンへのハンドルをサービスからより低いパーミッションで実行されているプロセスに複製する動作は疑わしいため、性能の低いEDRソリューションでも検出される可能性があります。このテクニックは、DuplicateHandleの呼び出しを回避することで、この検出を回避します。

トークン挿入関数への追加の相互参照は、IPSecとの関連を明らかにします。IPSecを使用するとトークンが挿入されるということなのでしょうか?

インターネット・プロトコルのセキュリティ

Iインターネット・プロトコル・セキュリティは、暗号化セキュリティ・サービスを使用することで、ネットワーク上の通信が安全かつプライベートに行われることを保証するプロトコルのセットです。インターネット層に統合することで、ほとんどすべてのTCP/IPプロトコルにセキュリティを提供します。認証と暗号化プロセスにより、ネットワーク・スニッファー、データ変更、IDスプーフィング、サービス拒否などの攻撃から保護されます。

IPSecは、データを交換する前に、2つのマシン間で安全な接続を設定します。これはインターネット鍵交換(IKE)サービスによって行われます。IKEは秘密鍵やその他の保護関連パラメータを交換します。認証は、Kerberos V5、証明書、または事前共有鍵で行うことができます。

IKEの代わりに、AuthIPという別の認証プロトコルを使用することもできます。これは、IKEを拡張して認証オプションを増やした新しいプロトコルです。IPSecポリシーは、Microsoft管理コンソール(MMC)スナップイン、またはWFP APIを使用して構成することができます。APIを使用すると、開発者はより具体的なネットワーク・トラフィック・フィルタリング・モデルを設定できます。

マイクロソフトは、認証に事前共有鍵を使用する IPSec ポリシーをマシン上でプログラム的に設定す を提供しています。ポリシーがインストールされている間、ポリシーにマッチする接続を作成する各プロセスのトークンが、tcpip.sysに格納されているハッシュテーブルに挿入されます。

IPSec ドキュメントによると、これが行われる理由は、IPsec がソケットで作成されるセキュリティコンテキストを偽装するためです。

トークンの LUID は攻撃者にはわかりません。この値は FwpsOpenToken0 の modifiedId パラメータに使用され、後にハッシュテーブルのインデックスとして使用されます。この値は 1 から 0x1000 の間であるため、ブルートフォースされる可能性があります。

攻撃2 - IPSec 接続のトリガー
ポリシーに一致する接続をサービスに強制的に開始させると、テーブルにSYSTEMトークンが挿入されます。この場合、Print Spoolerサービスが悪用されます。このサービスには文書化されたIDLファイルがあり

そのような関数の1つが RpcOpenPrinterであり、これはプリンターのハンドルを名前で取得します。nameを"\127.0.0.1" に設定すると、サービスはlocalhostに接続します。この RPC 呼び出しの後、SYSTEM トークンを返すまでWfpAleQueryTokenById へのデバイス IO 要求を複数回行うことができます。

これは前のものよりもステルス的なテクニックです。IPSecポリシーの設定は、ネットワーク管理者やサーバへの接続を保護するために行われる正当な動きです。また、ポリシーは通信を変更しないので、どのサービスも影響を受けないはずで、ネットワーク・アクティビティを監視するEDRソリューションは、ローカル・ホストへの接続については無視する可能性が高くなります。もう一つの利点は、ドライバが自動的にトークンをハッシュテーブルに追加するので、WfpAleProcessTokenReferenceを呼び出す必要がないことです。

他のトークンを得るために、さらに多くのサービスを操作することは可能でしょうか?

攻撃3 - ユーザーサービスを操作する

マシンにログオンしている他のユーザのトークンを獲得することは、ドメイン内の横移動につながります。トークンをハッシュテーブルに追加することができれば、そのユーザの権限でプロセスを起動することができます。

“NT ATHORITYSYSTEM”ではなく、ログオンしているユーザとして実行されている RPC サーバが検索されました。以下のスクリプトは、ドメイン管理者として実行されているプロセスを探し、それらがRPCインターフェースを公開しているかどうかをチェックします。その結果、SyncController.dllが見つかりました。

マシン上で複数のセッションがアクティブになると、すべてのセッションがユーザーの権限で OneSyncSvc サービスを起動します。このサービスは SyncController.dll をロードし、RPC インターフェース 923c9623-db7f-4b34-9e6d-e86580f8ca2a を登録します。

このインターフェイスには AccountsMgmtRpcDiscoverExchangeServerAuthType というメソッドがあり、次の形式の文字列を受け取ります: user@127.0.0.1.

このサービスを悪用する手順は以下の通りです:

  1. ローカルホストへの接続用に、事前共有鍵で IPSec ポリシーを設定

  2. サービスを列挙し、ターゲット・セッションで実行されているOneSyncSvcのpidを見つける

  3. ALPC ポートのハンドルを見つける。SyncController のインターフェイスは複数のサービスによって公開されているため、RPC 接続はこのインターフェイスに基づいて行うことはできない

  4. 127.0.0.1:443のリスナースレッドを作成。通常、このポートでリッスンしているサービスはないので、このアドレスをリッスンするために別のスレッドが起動

  5. RPCメソッドを呼び出す。これにより、サービスがポート443でローカルホストに接続。接続がアクティブな間、他のセッションのユーザーのトークンがテーブル内に格納

  6. OneSyncSvc がソケットに接続している間に、新しいトークンの LUID をブルートフォース

  7. 新しいトークンでプロセスを起動

OneSyncSvcとSyncController.dllは、攻撃的なツールによって悪用されたことはなく、RPCコールがセキュリティ・ソリューションを引き起こすことはありません。

検出

これらの攻撃は、可能な限りステルスになるように開発されていますが、マシン上で以下のイベントを探すことで検知することができます:

  • 既知のネットワーク・コンフィギュレーションと一致しない新しい IPSec ポリシーを設定
  • IPSec ポリシーがアクティブな状態で Spooler / OneSyncSvc を RPC 呼び出す
  • WfpAleQueryTokenById への複数の呼び出しによる、トークンの LUID のブルートフォース
  • BFE サービス以外のプロセスによるデバイス WfpAle へのデバイス IO 要求

Windows Filtering Platformは、イベントのログを生成します。ほとんどのログは、鍵交換プロセス中のパケット廃棄や失敗に関するものです。送信を許可されたパケットに関するログを生成することも可能です。これは明示的に設定する必要があり、多くのノイズを生成するため、推奨されません。このようなログを生成しても、攻撃を検知するのは難しく、以下のログは、攻撃中に行われた接続に関するものです:

このログは、スプーラ・サービスがlocalhost上のポート135への接続を許可されたことを示しています。この接続を呼び出したIPSecポリシーやRPCメソッドについての記述はありません。このログに関連するフィルターを照会すると、localhostの通信を許可しているだけであることがわかります:

さらなる分析 – tcpip.sys

ドライバtcpip.sysは、いくつかの機能を公開するいくつかのデバイスを作成します。それらにデバイスIOリクエストを送ることで、新たな攻撃経路を発見することができます。いくつかの機能を以下の表に示します:

デバイス

制御コード

Tcpip機能

IPSECDOSP

0x124004

IdpProcessQueryStatsIoctl

0x124002

IdpProcessEnumStateIoctl

NXTIPSEC

0x128028

IPsecSetS2STunnelInterfaceHndlr

0x12801C

IPSecNotifyStatusHndlr

0x128018

IPSecUpdateSaInfoHndlr

WFP

0x12803C

IoctlKfdResetState

0x124050

IoctlKfdSetBfeEngineSd

0x128004

IoctlKfdAddIndex

tcpipドライバのハッシュテーブルを相互参照すると、それが使用される様々な操作と、トークンに加えて管理されるデータについて、多くのことがわかります。例えば、"Process Explicit Credentials" とラベル付けされたデータなどです。

さらなる分析 - 明示的な資格情報(Explicit Credentials)

tcpipドライバは "Process Explicit Credentials "と呼ばれるものを保存しており、トークンと同様にRPCを通して取得することができます。トークンクエリのためのエクスポートされた関数とは対照的に、クレデンシャルクエリのための関数は文書化されていないため、さらにわかりにくくなっています。

BfeRpcAleExplicitCredentialsQuery が呼び出されると、BFE サービスはクライアントのアクセスチェックを行います。管理者権限で動作しているプロセスは ERROR_ACCESS_DENIED を受け取ります。同じ呼び出しがSYSTEMとして実行されているプロセスから送られた場合、BFEサービスはそれを許可し、tcpipドライバにデバイスIO要求を送ります。

これは、デバイスWfpAleへのハンドルを複製することで回避できる、もう1つのセキュリティメカニズムです。デバイスIO要求を直接送ると、BFEサービスのアクセス・チェックがスキップされます。

明示的な資格情報を挿入する関数は WfpAleInsertCredentialInformation ですが、トークンのように、特別な設定なしでは tcpip.sys のハッシュテーブルに挿入されません。この設定はまだ見つかっていません。

“process explicit credentials "とラベル付けされたデータの目的は、現時点では不明ですが、それに関連する関数の相互参照により、何らかのヒントが得られるかもしれません。

テーブルに認証情報を挿入する関数は、WfpAleSetSecurityとWfpAleProcessSocketOptionという関数から呼び出されます。これらの名前からすると、WSASetSocketSecurityは何らかの関連があるものと考えられます。

FwpsAleExplicitCredentialsQuery0 は、関数 IkeGetExplicitCred 内で IKE サービスによって呼び出されます。この関数への相互参照に基づくと、セキュリティサポートプロバイダインタフェース(SSPI)を使用するときに資格情報が挿入される可能性があります。

結論
  • 一のRPCコールをリバース・エンジニアリングし、横方向への移動と権限の昇格を実現
  • Windowsフィルタリングプラットフォームの様々なコンポーネントを分析
  • プラットフォームを保護するセキュリティ・メカニズムをバイパス
  • このプラットフォームをさらに悪用するための手がかりも確認

これらを悪用したいくつかの攻撃手法が開発されており、その特徴は以下の通りです:

  • セキュリティ製品によって監視されているWinAPIを避ける
  • SYSTEMや他のログオンしているユーザーとしてプログラムを実行(ほとんどのツールはSYSTEMにしか昇格しない)
  • これまで以上にステルス性が高い - 証拠やログがほとんど残らない
  • 複数のセキュリティ製品に検出されない

この調査結果は、マイクロソフト・セキュリティ・レスポンス・センターに既に報告済みとなっています。マイクロソフトによると、この動作は設計通りの仕様とのことです。

GitHubリポジトリ: https://github.com/deepinstinct/NoFilter