攻撃者がアクセストークン操作を悪用する方法(ATT&CK T1134)
セキュリティ担当者向けのWindowsアクセストークンに関する前回のブログ記事では、以下の内容を取り上げました。
- ログインセッションとアクセストークンの関係
- Windows環境におけるネットワーク認証の仕組み
Windowsセキュリティの主要な概念をいくつか説明してきたので、今度はその知識を基に、攻撃者が正規のWindows機能を悪用して横方向に移動し、Active Directoryドメインを侵害する方法について見ていきましょう。
このブログでは、可能な限り特定のWindowsネットワーク認証プロトコル(NTLMやKerberosなど)の動作を抽象化するように努めています。そのため、これらのプロトコル特有の動作が、以下に説明する動作と異なる場合があることをご了承ください。また、Kerberos認証プロトコル1に関する基本的な理解があることを前提としています。
さらに、このブログシリーズで取り上げた内容は、Black Hat 2020のプレゼンテーション「アクセストークン操作の検出」で使用されました。プレゼンテーションはこちら、スライドはこちらからご覧いただけます。
アクセストークンの操作 (ATT&CK テクニック: T1134)
前回のブログ記事では、ローカル環境と分散アプリケーションの両方におけるログオンセッションとアクセストークンの基本的な仕組みについて説明しました。本セクションでは、攻撃者がアクセストークンを悪用し、Windowsドメインの基本的な信頼関係を標的にしてネットワーク全体を侵害する方法について説明します。本セクションの目的は、シミュレーションによる侵害状況において、攻撃者が使用するアクセストークン操作の手法を解説することです。
なお、アクセストークン操作に関する優れた研究は既に数多く存在しており(本稿全体を通して多数のリンクを貼る予定です)、本稿では、アクセストークン、ログオンセッション、キャッシュされた認証情報の関係性という観点からアクセストークン操作を考察することで、既存の知識体系をさらに発展させようと試みています。著者の見解では、これらの関係性を考慮せずにトークン操作を説明することは、氷山の一角に過ぎません。したがって、本稿におけるアクセストークン操作の定義は、一般的に理解されているよりもはるかに広範なものとなるでしょう。
最初の侵害
攻撃者がスピアフィッシングによってネットワークに侵入した場合、通常は侵害されたユーザーのセキュリティコンテキストでシェルを実行することになります。これは、新しいプロセスを生成するか、メモリに直接注入することによって実現できます(ペイロードによって異なります)が、最終的な結果は同じです。つまり、攻撃者のコードが、侵害されたユーザーのアクセストークンを持つプロセス内で実行されることになります。
これは、ローカルでのアクセスチェックでは侵害されたユーザーのアクセストークンが使用され、リモートでの認証試行では侵害されたユーザーのキャッシュされた認証情報2が使用されることを意味します。したがって、攻撃者はローカルでもネットワーク全体でも、侵害されたユーザーが実行できるすべてのアクションを実行できます。たとえば、内部WebアプリケーションがWindows SSOを使用している場合、攻撃者はユーザーであるかのようにそれらにアクセスできます。
トークン操作:「可能性の芸術」
通常、攻撃者は侵害されたエンドポイントから別のホストへできるだけ早く移動したいと考えます3。トークン操作の観点から横方向の移動を考えると、攻撃者には実質的に3つの選択肢があり4 、以下に示すように、それぞれがアクセストークン、ログオンセッション、キャッシュされた認証情報の間の基本的な関係によって制約されます。

攻撃者がWindows SSOを介して横方向に移動しようとする場合、これら3つのリンクすべてが確立されている必要があります(例えば、攻撃者は、標的の認証情報によって裏付けられたログオンセッションにリンクされたトークンへのハンドルを持っている必要があります)。それ以外の場合、攻撃者の移動の自由度は、新しいリンク(新しいログオンセッションなど)を作成するか、既存のリンクを変更する(キャッシュされた認証情報やアクセストークンが指すログオンセッションを変更するなど)かのいずれかに依存します。これらの制約については、以下の3つのオプションでさらに詳しく説明します。
1. 既にログインしている特権ユーザーのトークンを盗む(ネットワークログイン以外)
別の特権ユーザーが既に侵害されたホストにログオンしている場合、攻撃者は権限を昇格させて、このユーザーを表すアクセストークンのハンドルを取得できます。攻撃者が盗んだトークンを偽装するか、新しいプロセスを開始するかに関わらず、そのトークンがネットワーク以外のログオンセッションにリンクされている場合、キャッシュされた認証情報を持つため、攻撃者はそのマシンから別のホストに認証できます5。したがって、この手法により、攻撃者は別のユーザーの認証情報を使用してネットワーク経由でリモートホストにアクセスし(Windows SSO経由)、認証情報をダンプする必要なくピボットできます6 。
なお、トークン操作攻撃は一般的に、横方向への移動(このブログで取り上げているもの)とローカル権限の昇格7という 2 つの明確な目的に関連しています。トークンの盗難は後者(例えば、キャッシュされた認証情報をリモート認証に使用するためではなく、ローカルアクセスチェックを回避するためにトークンを盗んだりなりすましたりすること)に関連付けられる傾向があるため、このブログではこれ以上詳しく説明しませんが、以下のリソースは参考になります。
- https://posts.specterops.io/understanding-and-defending-against-access-token-theft-finding-alternatives-to-winlogon-exe-80696c8a73b
- https://foxglovesecurity.com/2016/09/26/rotten-potato-privilege-escalation-from-service-accounts-to-system/
- https://labs.f-secure.com/assets/BlogFiles/mwri-security-implications-of-windows-access-tokens-2008-04-14.pdf
2. 盗んだ認証情報を使用して新しいログオンセッションを作成し、返されたトークンを偽装するか、それを使用して新しいプロセスを起動する
この場合、既にログインしている特権ユーザーは存在しない(したがって、対応する有用なアクセストークン/ログオンセッションも存在しない)ものの、攻撃者は依然としてセキュリティコンテキストを変更する方法を見つける必要があります。
したがって、攻撃者は別の場所で認証情報を入手し、盗んだ認証情報を使用して侵害されたユーザーとして新しいログオンセッションを作成する必要があります。Windowsは特定のログオンタイプの認証情報を自動的にキャッシュするため、攻撃者は盗んだ認証情報によって裏付けられた新しいアクセストークンを取得できます。攻撃者は侵害されたユーザーを表すトークンへのハンドルを取得したら、標準のWindows SSOプロセスを使用して、そのマシンから認証を行うことができます。
通常、攻撃者はKerberoasting攻撃を行うか、ネットワーク共有、SharePoint、社内Wiki、企業GitHub、Zendeskなど、アクセス可能なすべてのリソースで保護されていない平文認証情報を検索することによって、平文認証情報を見つけ出します。8
3. 現在のアクセストークンに関連付けられたキャッシュされた認証情報を盗まれた認証情報に変更する(例えば、APIを介して合法的に、またはlsassメモリを直接変更することによって「不正に」)。
このシナリオでは、攻撃者は新しいログオンセッションを作成するのではなく、現在のアクセストークン (したがってログオンセッション) に関連付けられたキャッシュされた資格情報を変更します。後述するように、多くの Windowsセキュリティサポートプロバイダー(SSP) はこれを行うネイティブの方法を提供し(管理者権限は不要
)ています。あるいは、攻撃者は「直接的な」方法を用いて、lsassに保存されているキャッシュされた認証情報を手動で変更することもできます。これは、OpenProcessを介してlsassへの書き込みハンドル (例: PROCESS_VM_WRITE) を取得するために、管理者権限を必要とします。これは、後述するパス・ザ・ハッシュ攻撃の典型的な例です。
アクセストークン操作攻撃
このブログ記事では、攻撃者がよく使う4つの手法(いずれも上記のオプション3のバリエーションに分類可能)について見ていきます。
- NETONLYフラグ
- パス・ザ・チケット
- パス・ザ・ハッシュ
- オーバーパス・ザ・ハッシュ
1. NETONLYフラグ
Windows API は、指定されたユーザー (またはプリンシパル) の新しいログオンセッションを作成するLogonUser関数を提供します9:
BOOL LogonUserW(
LPCWSTR lpszUsername,
LPCWSTR lpszDomain,
LPCWSTR lpszPassword,
DWORD dwLogonType,
DWORD dwLogonProvider,
PHANDLE phToken
);
ここで注目すべき重要なパラメーターは、実行するログオンの種類を指定するdwLogonTypeです。たとえば、ユーザーがワークステーションに物理的にログインする場合、 LOGON32_LOGON_INTERACTIVEに設定されます。指定されたログオンの種類によって、返されるトークンの種類と権限が決まります。
例えば、対話型ログオンの場合、LogonUserWはプライマリアクセストークンを返し、UACが有効になっている場合は、このトークンはフィルタリングされたトークンになります (つまり、中程度の整合性で昇格されていないトークンになります)。ただし、例外が 1 つあります。ユーザーがローカル管理者アカウント (たとえば、*-500 SID) の場合、Windowsは自動的に昇格されたトークン10を返します。
ネットワークログオン (LOGON32_LOGON_NETWORK) の場合、偽装トークンが返されます (通常、これはサーバーがリモートクライアントに代わって作業を実行するために使用されます)。さらに、ユーザーがローカル管理者グループに属している場合、トークンは昇格され、すべての権限が有効になります11 。
LogonUserのこれらの組み合わせは、以下の表に示されています。
dwLogonType | 返されるトークン | 認証情報をキャッシュしますか? | 返されたトークンは昇格されていますか? (管理者の場合) |
対話型 (LOGON32_LOGON_INTERACTIVE) | プライマリ | はい | いいえ(UACが適用) |
対話型(ローカル管理者アカウント、例:rid-500) | プライマリ | はい | はい |
ネットワーク (LOGON32_LOGON_NETWORK) | なりすまし | 12 | はい(すべての権限が有効) |
ネットワーク(ローカル管理者アカウント、例:rid-500) | なりすまし | いいえ | リモートUAC設定に依存13 |
重要な点は、LogonUserが新しく発行されたトークンへのハンドルを返すことであり、このハンドルはなりすましに使用できます。
返されたトークンがプライマリトークンである場合は、まずDuplicateTokenExを介してTokenTypeをTokenImpersonate 14に渡して偽装トークンに変換する必要があります。
BOOL DuplicateTokenEx(
HANDLE hExistingToken,
DWORD dwDesiredAccess,
LPSECURITY_ATTRIBUTES lpTokenAttributes,
SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,
TOKEN_TYPE TokenType,
PHANDLE phNewToken
);
次に、 SetThreadToken関数を使用して、返された偽装トークンを現在のスレッドに割り当てることができます。
BOOL SetThreadToken(
PHANDLE Thread,
HANDLE Token
);
あるいは、Windows APIにはImpersonateLoggedOnUser関数が用意されており、これを使用すると、呼び出し元のスレッドは渡されたトークンで表されるユーザーのセキュリティコンテキストを偽装できます。
BOOL ImpersonateLoggedOnUser(
HANDLE hToken
);
ImpersonateLoggedOnUser には、渡されたトークンのタイプを自動的にチェックし、プライマリトークンが渡された場合 (このトークンタイプとして) はそれを偽装トークン ( NtDuplicateToken経由) に変換するという利点があります(このトークンタイプはスレッドによるなりすましに使用できないため)15。
防御回避の観点から注意すべき点は、これらのなりすましAPIはどちらも、ドキュメント化されていないシステムコールNtSetInformationThread (例えば、 ThreadInformationClassがThreadImpersonationTokenの場合)の軽量ラッパーであるということです。そのため、攻撃者が、 https://github.com/jthuraisamy/SysWhispersなどの手法を用いて、直接システムコールを使用してユーザーモードフックを回避するのに適した標的となります。
さらに、Windowsにはなりすましに関する厳格なルールがあることを強調しておくことが重要です。以下は、 ImpersonateLoggedOnUserの MSDN ページから抜粋したものです。
ImpersonateLoggedOnUser を含むすべての偽装関数は、次のいずれかが真である場合に要求された偽装を許可します。
- トークンの要求された偽装レベルがSecurityImpersonationより低い場合 (SecurityIdentificationまたはSecurityAnonymousなど)。
- 呼び出し元が SeImpersonatePrivilege権限を持っている場合。
- プロセス (または呼び出し元のログオンセッション内の別のプロセス) が、LogonUserまたはLsaLogonUser関数を介して明示的な資格情報を使用してトークンを作成した場合。
認証された ID が呼び出し元と同じ場合
さらに、なりすましトークンの整合性レベルは、呼び出し元プロセスの整合性レベル以下でなければならず、そうでなければなりすまし呼び出しも失敗します16。したがって、権限のない攻撃者が盗まれた認証情報を使用して管理者ユーザーに対話的にログインし、UACが有効になっている場合、権限のない(フィルタリングされた)トークンが返されるため、返されたユーザーになりすまして横方向に移動することなどに問題はありません。
「奇妙な/NETONLYフラグ」 17
しかし、攻撃者は盗んだ認証情報を使ってユーザーにログインしようとしても失敗する場合があります。これは、認証情報自体は有効でも、そのアカウントに特定のワークステーションにログインする権限がない、認証情報が別のドメインでのみ有効であるなど、さまざまな理由が考えられます。 さらに、 攻撃者は、特権の高いアカウントでのログインを完全に避ける場合もあります。なぜなら、特定の状況下では、これは非常に異常に見える可能性があるからです(例えば、ドメイン管理者が特権の低いビジネスユーザーのホストにログインすることは極めて疑わしい) 。18
このシナリオでは、LOGON32_LOGON_NEW_CREDENTIALSフラグが攻撃者の救世主となります。攻撃者がこのフラグを指定してLogonUserW関数を呼び出し、有効な資格情報セット (たとえば、ファイル共有をスニッフィングして見つけたもの) を渡すと、Windows は呼び出し元が現在のトークンを複製できるようにしますが、そのトークンは新しいログオンセッション (新しい資格情報ログオンセッションと呼ばれます) を指すように変更され、盗まれた資格情報がキャッシュされます。結果として、ユーザーはローカルでは依然として同じセキュリティコンテキスト (たとえば、同じアクセストークンのコピーを保持しており、それが新しいログオンセッションを指しているだけ) を保持しますが、リモートで認証しようとすると、LogonUserW 19の呼び出しで渡された新しい資格情報が提供されます。これは、次の図に示されています。

したがって、 LOGON32_LOGON_NEW_CREDENTIALSフラグは、現在のアクセストークンを別のログオンセッション、ひいては別の認証情報にリンクさせるためのネイティブなメカニズムを提供します20。
なお、LOGON32_LOGON_NEW_CREDENTIALSフラグを指定してLogonUserWを呼び出した場合、呼び出し時に認証情報は検証されません(認証情報が完全に無効なものであっても構いません)。認証情報は、リモート認証要求時にドメインコントローラーによってのみ検証されます。
さらに例として、オープンソースの「MakeToken」タスクのコードを簡単にレビューしてみましょう。.NET C2フレームワークのCovenantも全く同じアプローチを採用しています。ユーザー名とパスワードの組み合わせを受け取り、 LOGON32_LOGON_NEW_CREDENTIALSフラグを渡すことで、それらを使用して新しいログオンセッション/トークンを作成し、返されたトークンを偽装します。
さらに、dwLogonFlagsにLOGON_NETCREDENTIALS_ONLYを渡すことで、 CreateProcessWithLogonWでも全く同じ動作を再現できます。21
BOOL CreateProcessWithLogonW(
LPCWSTR lpUsername,
LPCWSTR lpDomain,
LPCWSTR lpPassword,
DWORD dwLogonFlags,
LPCWSTR lpApplicationName,
LPWSTR lpCommandLine,
DWORD dwCreationFlags,
LPVOID lpEnvironment,
LPCWSTR lpCurrentDirectory,
LPSTARTUPINFOW lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation
);
重要な違いは、これは以前に説明したプロセス内なりすましとは異なり、返されたトークンを使用して新しいプロセスを生成する点です。実際、Windowsに組み込まれているユーティリティであるrunasは、CreateProcessWithLogonWを単純にラップしたものであり、 /NETONLYフラグを使用すると、以下に示すように、ネットワーク専用の異なる認証情報を使用して新しいプロセスを生成するネイティブな方法が提供されます。

前述のとおり、新しいコマンドプロンプトはローカルでは同じユーザーとして実行されているように見えます(つまり、トークンにキャッシュされた属性はローカルアクセスチェックではすべて同じです。そのため、whoamiは「astro\cosmo」を返します)。しかし、リモート認証の試みはすべて、「ASTRO\Administrator」ユーザーの盗まれた認証情報を使用して実行されます。
これらのログオンセッションは、SysInternalsのLogonSessionsツールを使用して表示できます。NewCredentialsフラグを使用して作成されたログオンセッションは、以下に示すように、ログオンタイプフィールドで判別できます。

さらに、異常な NewCredentialsログオンセッション (NETONLY ガジェット経由で生成されたものなど) は、Windows イベントログに痕跡を残します。これらは、イベントID 4642とLogonType 9によって識別できます。例を以下の画像に示します。

元のユーザーはSubjectUserNameフィールドに表示され、指定されたネットワーク専用認証情報(渡された認証情報など)はTargetOutboundUser/DomainNameフィールドに表示されることに注意してください。22
自動昇格
ローカル権限昇格の観点からもう1つ特異な点は、rid-500アカウントの場合、 CreateProcessWithLogonWは対話型ログオンのために返されたトークンを自動的に昇格させることです(つまり、UACを無視します)。したがって、CreateProcessWithLogonWにはローカル/ドメイン管理者アカウントを渡すことで、中程度/非昇格コンテキストから昇格されたプロセスを実行できます。
この動作はrunasコマンドで確認できます。例えば、runasコマンドを使ってローカル管理者アカウントでプロセスを起動した場合(例:runas /user:"Administrator" cmd.exe)、生成されるプロセスは管理者権限が昇格されます(高整合性)。しかし、rid-500権限を持たないアカウント(ただし、ローカル管理者グループに属しているアカウント)を使用した場合、生成されるプロセスは管理者権限が昇格されません(フィルタリングされたトークン/中程度の整合性)。
この動作は、表1のLogonUserWの順列と一致していることに注意してください。したがって、権限昇格されていない攻撃者でも、(rid-500 以外の) 管理者ユーザーとしてネットワークログオンし、すべての権限が有効になった昇格トークンを取得できる可能性があります。
しかし、前述のなりすましルールに従って、攻撃者はこのトークンで実際には何もできないはずです。なぜなら、昇格されたトークンのなりすましを試みても、呼び出し元よりも高い整合性レベルを持っているため失敗するはずだからです。それにもかかわらず、昇格されたトークンを複製し、コピーしたトークンの整合性レベルを中程度に下げ(注: 'isElevated' は依然としてtrueです) 23、昇格されていない/中程度の整合性コンテキストから昇格されたトークンのなりすましを開始することは実際に可能です24。したがって、なりすましトークンの観点からは、特定のアカウントのみを昇格させるというデフォルトのWindowsの動作を回避し、アカウントがrid-500アカウントであるかどうかに関係なく、昇格されたトークンになりすますことができます。
プロセス作成
デフォルトでは、子プロセスを作成すると、現在別のセキュリティコンテキストを偽装している場合でも、プライマリトークンが継承されることに注意してください25 。例えば、SYSTEMトークンを偽装してCreateProcess ()を呼び出した場合、スレッドのSYSTEMセキュリティコンテキストを継承するのではなく、プライマリプロセストークンのコピーを継承します26
。したがって、攻撃者が異なるセキュリティコンテキストで新しいプロセスを起動したい場合は、次のいずれかの方法をとる必要があります。
- (前述のとおり)明示的な認証情報を指定してCreateProcessWithLogonW を使用する
- CreateProcessWithTokenWまたはCreateProcessAsUserWを呼び出し、トークンへのハンドルを渡す(たとえば、LogonUser から返されたトークン、またはより一般的には盗まれたトークン)
これらの関数はいずれも、新しいプロセスのセキュリティコンテキストを表すトークンへのハンドルを渡すことができます。27
BOOL CreateProcessWithTokenW(
HANDLE hToken,
DWORD dwLogonFlags,
LPCWSTR lpApplicationName,
DWORD dwCreationFlags,
LPVOID lpEnvironment,
LPCWSTR lpCurrentDirectory,
LPSTARTUPINFOW lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation
);
BOOL CreateProcessAsUserW(
HANDLE hToken,
LPCWSTR lpApplicationName,
LPWSTR lpCommandLine,
LPSECURITY_ATTRIBUTES lpProcessAttributes,
LPSECURITY_ATTRIBUTES lpThreadAttributes,
BOOL bInheritHandles,
DWORD dwCreationFlags,
LPCWSTR lpCurrentDirectory,
LPSTARTUPINFOW lpStartupInfo,
LPPROCESS_INFORMATION lpProcessInformation
);
例えば、CreateProcessAsUserWは通常、ログオン成功後にユーザーのシェルを起動するためにオペレーティングシステム自体によって使用されます(ユーザーがcreatProcessWithLogonWを呼び出すときにセカンダリログオンサービスによっても使用されます)。この意味で、ユーザーは「選択したログオンセッションにプロセスを挿入する」ことができます28。なお、これらのAPIはどちらもCreateProcessInternalW (KernelBase.dllにあります) のラッパーです。
ここでの重要な違いは、呼び出し元がこれら2つのAPIを呼び出すための特定の権限を持っている必要があることです29。しかし、攻撃者の視点から見ると、ここでの目標は同じです。横方向への移動を目的として、ターゲットユーザーのセキュリティコンテキストでコード実行を取得することです。
興味深い特異点の1つは、PowerShell Empireフレームワークが、このプロセス生成アプローチ(検出の観点からは明らかにノイズが多い)を採用せざるを得なかったことです。これは、PowerShellがなりすましとマルチスレッドを処理する方法の制限によるもので、この点については、 ここに記載されているメモでより詳しく説明されています。
いずれにせよ、プロセス生成トークン操作技術を使用する際のワークフローは変わりません。攻撃者がトークンへのハンドルを取得したら(プライマリトークンの場合はOpenProcess/OpenProcessToken、スレッドを偽装している場合はOpenThread/OpenThreadTokenを介して)、DuplicateTokenExを呼び出してターゲットトークンのローカル(プライマリ)コピーを作成し、そのコピーをCreateProcessWithTokenWまたは CreateProcessAsUserW関数に渡す必要があります。
ここでも、攻撃者はネットワークログインではない特権ログオンセッションのみに関心があることに注意してください。ネットワークログインは認証情報をキャッシュしないため、 他のホストに対して認証を行う。
2. パス・ザ・チケット
Windows は、 Kerberos 30を使用した NETONLY フラグと非常によく似た手法を実行するネイティブな方法を提供します。この手法は、攻撃者が新しいログオンセッションを作成する必要がなく、代わりにログオンセッション(ひいては現在のアクセストークン)に関連付けられたキャッシュされたKerberos認証情報(TGTなど)を任意に変更できるという点で、さらに強力です。以下でその例を示します。

Kerberos SSPとのやり取りを開始し、Kerberosチケットキャッシュを管理するために、プロセスはLsaCallAuthenticationPackage (Sspicl.dll内にあります)を呼び出すことができます。
NTSTATUS LsaCallAuthenticationPackage(
HANDLE LsaHandle,
ULONG AuthenticationPackage,
PVOID ProtocolSubmitBuffer,
ULONG SubmitBufferLength,
PVOID *ProtocolReturnBuffer,
PULONG ReturnBufferLength,
PNTSTATUS ProtocolStatus
);
ユーザーは、LSA サーバーへの接続ハンドルを取得するために事前にLsaConnectUntrustedを呼び出し、Kerberosパッケージ (MICROSOFT_KERBEROS_NAME_A) の IDを見つけるためにLsaLookupAuthenticationPackageを呼び出す必要があることに注意してください。さらに、IDAでこれらの関数を検査すると (これらはSspicl.dllにあります) 、RPCを介して Lsaに接続していることがわかります31 。
LsaCallAuthenticationPackageを使用すると、ユーザーは機密性の高いリクエストを多数実行できますが、ユーザーが実行できるリクエストの種類は、昇格されているかどうかによって異なります。たとえば、昇格されていないユーザーは、基本的なチケット管理アクション32(現在アクティブなチケットの列挙、チケットキャッシュのクリア、現在のログオンセッションへの任意のチケットの適用33など)を実行できます。したがって、これにより、ユーザーは現在のログオンセッションにキャッシュされている認証情報を変更し、任意のネットワーク専用の認証情報を指定できるようになります。
さらに、権限を昇格したコンテキスト34から、攻撃者は他のユーザーに属するチケット(認証情報など)を列挙してダンプできるため、 lsass35へのハンドルを開く必要なくmimikatzと同様の機能を提供できます。
Kerberos認証パッケージに送信できるメッセージの種類の一覧は、こちらで確認できます。特定のログオンセッションに関連付けられている現在のTGTを変更するには、次のメッセージ構造体を使用するKerbSubmitTicketMessageを渡すことができます。
typedef struct _KERB_SUBMIT_TKT_REQUEST {
KERB_PROTOCOL_MESSAGE_TYPE MessageType;
LUID LogonId;
ULONG Flags;
KERB_CRYPTO_KEY32 Key;
ULONG KerbCredSize;
ULONG KerbCredOffset;
} KERB_SUBMIT_TKT_REQUEST, *PKERB_SUBMIT_TKT_REQUEST
したがって、KerbSubmitTicketMessageの場合、ProtocolSubmitBufferパラメーターは、KERB_SUBMIT_TKT_REQUEST構造体とそれに続くASNエンコードされたKerberosチケット (指定されたログオンセッションに適用されるチケット) で構成されるメモリブロックを指すだけです。KerbSubmitTicketMessageリクエストを送信するためのmimikatzの関連コードはこちら、Rubeusの関連コードはこちらで確認できます。
LsaCallAuthenticationPackageの呼び出し後、ユーザーのTGTは盗まれたチケットに更新されました。この時点以降、ユーザーのアクセストークン/対話型ログオンセッションに関連付けられたプロセス/スレッドによるネットワークリソースへのアクセス試行はすべて、盗まれたTGTを使用してKerberos経由で自動的に認証されます(たとえば、ドメイン全体のリソースに対して異なるサービスチケット/TGSを要求することによって)。
なお、ユーザーは現在のログオンセッションに関連付けられるTGTを1 つしか持つことができません。したがって、新しいチケットを適用すると、ユーザーの以前のチケットは消去されます。攻撃者が現在の TGTを保持したい場合はどうでしょうか。この場合も、NETONLYフラグが役立ちます。攻撃者は、任意の/ダミーの認証情報を使用してCreateProcessWithLogonWを介して「犠牲となる」NETONLYプロセスを作成できます。これにより、新しいダミープロセスと、最も重要なことに、盗まれたTGTを適用できる新しいログオンセッション (およびアクセス トークン) が作成されます (これにより、ユーザーの現在のチケットが保持されます) 36 。
防御担当者にとってこの手法から得られる重要な結論の一つは、すべての処理がLsaCallAuthenticationPackage(つまりRPC経由)で行われるため、lsassとの直接的なやり取りは不要であるということです(ここでいう直接的なやり取りとは、OpenProcessを介してlsassへのハンドルを開くことを指します)。さらに、この特定のユースケース(ptt)では、攻撃者がリモートホストへの認証を試みる(これにより新たなログオンが生成される)まで、すべての処理はローカルRPC経由で行われます。
さらに別の例として、RubeusのREADMEには以下の記述があります。
「RubeusにはLSASSを操作するコードは一切含まれておらず(今後もその予定はありません)、そのためその機能はLsaCallAuthenticationPackage() APIを使用してKerberosチケットを抽出することに限定されます。」
したがって、lsassへのハンドルアクセスを前提とする検出ロジック(例えば、特定のプロセスまたはスレッドハンドル操作に対するObjectPreCallbackカーネルルーチン、あるいはOpenProcess/NtOpenProcessのユーザーモードフックなど)では、このアクティビティを見逃す可能性があります。そのため、例えばSysmonのプロセスアクセスイベントを利用して疑わしいプロセスハンドルアクセスを警告する防御側にとっては、潜在的な盲点となります。
3. パス・ザ・ハッシュ(PtH)
このブログで最後に紹介する2つの手法は、攻撃者がlsassメモリを直接変更することで、現在のアクセストークン/ログオンセッションに関連付けられたキャッシュされた認証情報を「不正に」変更する例です。PtHシナリオでは、攻撃者のアクセストークンは変更されず、同じログオンセッションを指していますが、関連付けられたキャッシュされた認証情報は盗まれたハッシュで直接上書きされます。この時点から、以下に示すように、リモート認証の試みはすべて盗まれたハッシュを使用するようになります。

この意味で、PtHとOPtHはどちらも、先に述べたNETONLY技術と機能的に同一であると考えることができる。
PtH攻撃の典型的なワークフローは次のとおりです。
- lsassへの書き込みハンドルを開きます(例えば、 OpenProcess/NtOpenProcessを使用して、必要なアクセス権限PROCESS_VM_WRITEを指定します)。
- ログオンセッションのリンクリストを列挙する
- 対象のログオンセッションを特定し、必要な認証パッケージを識別します(PtH/NTLMの場合は、MSV1_0認証パッケージです)。
- 関連付けられたキャッシュされた認証情報を更新する
これらの手法は、多くの場合、文書化されていないWindows構造の解析と変更に依存していることに注意してください。このブログでは取り上げませんが、その実行方法に関する詳細は、こちらとこちらで確認できます。
したがって、キャッシュされた認証情報がメモリ内で更新されると、通常のWindows SSO設計に従って、そのトークンとして実行されているプロセス/スレッドがリモートリソースにアクセスしようとした際に、自動的にリモート認証に使用されます。
なお、この単純なケースでは、追加のログオンセッションやアクセストークンは作成されていません。しかし、パス・ザ・チケット攻撃と同様に、これらのツールは既存の認証情報を保持したり、盗んだ認証情報を適用したりするために、頻繁に新しい不要なNETONLYプロセスやログオンセッションを作成する必要があります。
なお、lsassへの書き込みハンドルを取得するために、マルウェアは通常、次の2つの方法を用います。
- SeDebugPrivilege 37を取得する
- システムトークンを盗み、なりすます
最初の方法は、このブログシリーズのパート 1 で説明しましたが、後者の方法は、ローカルアクセスチェックを回避する目的でトークンを盗んだり、なりすましたりした典型的な例です (たとえば、特定の権限 (SeTcbPrivilege) が有効になっているSYSTEMトークンを盗むなど)。SYSTEMトークンは通常、winlogonからプライマリトークンを盗むことによって取得されます。
4. オーバーパス・ザ・ハッシュ (OPtH)
オーバーパス・ザ・ハッシュ技術は、パス・ザ・ハッシュと同じ概念を適用しますが、重要な違いが1つあります。それは、ハッシュを完全なTGTチケットに変換することです。
ユーザーが初めてWindowsワークステーションにログオンすると、Kerberos認証プロセスの一環として、ユーザーのパスワードハッシュがタイムスタンプの暗号化に使用され、ドメインコントローラ / キー配布センター (KDC) に対してユーザーの身元を検証し、TGT を取得します。オーバーパス・ザ・ハッシュは、メモリにキャッシュされたこれらのハッシュ38 を変更し、通常のKerberos認証プロトコル (AS-REQ/AS_REP など) を開始して、盗まれたハッシュから完全なTGTを取得します。39
この手法は、mimikatzのpthコマンド(実際には内部でハッシュオーバーパスを実行しているにもかかわらず、pthという紛らわしいラベルが付けられている)を介して実行できます。
mimikatz # sekurlsa::pth /user:Administrator /domain:ASTRO.testlab /ntlm: c0f969f35beb20e8f09ce86ef42ccd51
これは基本的にPtHと同じ手順を実行しますが、Kerberos SSP(したがってkerberos.dll)を対象としています。40

この手法では、ユーザーのログオンセッションに関連付けられた現在のTGTを消去する必要があるため、攻撃者はNETONLYプロセス(関連付けられたダミーのログオンセッション付き)を使用して現在のTGTを保持することができます。これは、mimikatzがデフォルトでオーバーパス・ザ・ハッシュを実行する方法とまったく同じです。
まず、LOGON_NETCREDENTIALS_ONLYフラグを指定してCreateProcessWithLogonWを使用して、サスペンド状態の新しいプロセスを生成します。次に、このサスペンドプロセスのプライマリトークンへのハンドルを取得し、 GetTokenInformationを使用して新しいダミーログオンセッションの認証IDを取得します。この関数は、TOKEN_INFORMATION_CLASS列挙型(この場合はTokenStatistics)を介してトークンにキャッシュされた情報を照会するために使用されます。
認証IDを取得したら、mimikatzはlsass内のログオンセッションのリンクリストを列挙し、新しく作成されたログオンセッションを探すことができます。認証IDを介してターゲットのログオンセッションが見つかると、それに関連付けられたKerberos認証情報を更新できます。認証情報が更新されると、トークン(対応するログオンセッションが盗まれたハッシュにリンクされる)は、DuplicateTokenExを使用して偽装トークンに変換され、SetThreadTokenを使用して偽装することができます。これは前述のとおりです。
この段階では、攻撃者がネットワーク上のリソースにアクセスしようとする場合、認証のためにmimikatzに引数として渡されたドメイン\ユーザー名とパスワードハッシュの組み合わせが使用されます。したがって、すべてのリモート操作は、盗まれた認証情報によるアクセス権限で行われます。
結論
この2部構成のブログシリーズの目的は、Windowsセキュリティの基本的な概念が内部でどのように機能するかを説明し、攻撃者がこれらの機能を悪用してWindowsドメインを侵害する方法を示すことでした。このブログでは、どのようなツールや認証プロバイダーが悪用されるかに関わらず、攻撃者は一連の制約の下で行動し、その結果、アクセストークンの操作において同じ異常なシグナル(例えば、異常なネットワークのみのログイン)が生じることを実証しました。これらの制約は、アクセストークン、ログオンセッション、およびキャッシュされた認証情報の間の基本的な関係によって決定されます。Elastic Securityで包括的なデータ保護を実現する準備はできていますか?今すぐ無料でお試しいただくか、Elastic Cloud上のElasticsearch Serviceで最新バージョンを体験してください。また、クイックスタートトレーニングを活用して、成功への道を切り開きましょう。
参考文献
1. Kerberos認証の仕組みの復習については、Programming Windows Security、Keith Brownを参照してください。 https://posts.specterops.io/kerberosity-killed-the... 。さらに、Kerberosとやり取りするためのツールキットであるRubeusには、非常に有益なreadmeがあり、詳細を知りたい場合は読むことをお勧めします。
2. Windows SSOメカニズムに従い、ユーザーがネットワークリソースにアクセスしようとすると、ログオンセッションにキャッシュされた資格情報を使用してWindowsが自動的に認証を行うことを覚えておいてください。ここでいうキャッシュされた資格情報とは、任意の認証プロバイダー (NTLMハッシュやKerberosチケットなど) を指します。なお、これはユーザーが対話的にログオンしている (ネットワーク接続ではない) ことを前提としています。
3. これは通常
インシデント対応やホストの隔離によって足場を失うことを避けるためです。
4. これは明らかに、侵害されたホスト上での攻撃者の活動にのみ適用され、攻撃者が別のソースからコードを実行する場合(例えば、 impacketを介してリモートで実行する場合)には適用されません。
5. https://clymb3r.wordpress.com/2013/11/03/powershel...
6. この手法の例として、Cobalt Strikeの「steal_token」コマンドを参照してください。https: //www.cobaltstrike.com/help-beacon
7. アーカイブされたPowerSploitフレームワークからのこのコメントは、ローカル権限昇格のためのトークン窃盗と横方向移動の区別について、さらに明確な説明を提供するはずです。
8. あるいは、攻撃者はパスワードスプレー攻撃を行うか、responderなどのツールを介してNTLMスニッフィング/リプレイ攻撃を試みることもできます。
9. LogonUserA/WはどちらもSspiCli.dll内のLogonUserExExWの単純なラッパーであることに注意してください。
10. まったく同じように、CreateProcessWithLogonWにローカル管理者アカウント (rid-500) を渡すことで、中程度/非昇格コンテキストから昇格されたプロセスを実行できます。
11. この動作を変更できるリモートUACレジストリオプションがあります。
12. LOGON32_LOGON_NETWORK_CLEARTEXTという追加のログオンタイプがあり、これは基本的にネットワークログオンですが、資格情報がキャッシュされています。詳細については、Keith Brown氏の「Programming Windows Security」を参照してください。
13. 詳細については
以下を参照してください。
https://blueteamer.blogspot.com/2018/12/disabling-...
https://support.microsoft.com/en-gb/help/951016/de...
https://labs.f-secure.com/blog/enumerating-remote-...
14.なお、 DuplicateToken関数もありますが、これは偽装トークンのみを返します。
15. これは、IDAで関数を調べることで検証できます。または、ReactOSでこちらを確認してください。
16. この要約は、なりすましセキュリティをやや簡略化したものです。より詳細な概要については、James Forshaw氏の「Introduction to Logical Privilege Escalation on Windows」のスライド (p26) を参照してください。 https://conference.hitb.org/hitbsecconf2017ams/mat...
17. このタイトルは、Raphael Mudge氏による優れたブログ記事「Windowsアクセストークンと代替資格情報」から引用したものです。
18. これが
攻撃者がオプション2をあまり使用しない主な理由です。
19. したがって、複製されたトークンのネットワーク認証情報が異なる場合でも、「whoami」を実行しても同じユーザーが表示されます(トークンが同じであるため)。これは、Cobalt Strikeのmake_tokenコマンド(内部では上記と同じ手法を実行)を使用する際によくある混乱の原因です。
20. Windows RPC/COM API を使用すると、ネットワーク専用の資格情報を指定することもできます。たとえば、RPC の場合は、 RpcBindingSetAuthInfoExWを呼び出し、AuthIdentityパラメーターにSEC_WINNT_AUTH_IDENTITY構造体を渡すことで実現できます。詳細については、Keith Brown氏の「Programming Windows Security」およびhttps://docs.microsoft.com/en-us/windows/win32/wmisdk/setting-authentication-using-c-を参照してください。
21. 2つのフラグは名前は異なりますが、意味は同じです。これらの認証情報はネットワーク上でのみ使用できます。
22. 異常なログオンセッションの疑わしいイベントログを作成する方法はまだ存在することに注意してください。
23. これはJames Forshaw氏のトリックです。詳細は以下のブログをご覧ください。 https://www.tiraniddo.dev/2017/05/reading-your-way...また、 TokenViewerはこの種のテクニックを試すのに最適なツールです。
24. この結果として得られた偽装トークンを使用すると、System32などにファイルを書き込むことができます
25. ただし、API呼び出し前になりすましを行う正当な理由が存在する場合もあります。例えば、API呼び出しに必要な権限を、呼び出し前に取得する場合などです(ただし、一部のAPIは権限を自動的に有効化することに注意してください)。
26. これにはいくつかの回避策があります。たとえば、 PROCESS_CREATE_PROCESSアクセス権限を持つOpenProcessを介してSYSTEM プロセスのハンドルを取得することで、SYSTEMプロセスの子としてプロセスを生成することができます。このHANDLE は、NtCreateProcessのParentProcessパラメーターとして渡すことができます。これは、PROC_THREAD_ATTRIBUTE_PARENT_PROCESSパラメーターとCreateProcessを使用しても実現できます。 https://gist.github.com/xpn/a057a26ec81e736518ee50...
27. 奇妙なことに、CreateProcessWithTokenWは、既存のトークンへのハンドルも必要とするにもかかわらず、dwLogonFlags引数を受け取ります。定義上、既存のトークンには既に対応するログオンセッションが存在するはずです。これはユーザープロファイルの読み込みに関係している可能性が高いと思われます。
28. Programming Windows Security, Keith Brown
29.具体的には、CreateProcessWithTokenWの場合はSE_IMPERSONATE_NAME、CreateProcessAsUserWの場合は SE_INCREASE_QUOTA_NAME (&) SE_ASSIGNPRIMARYTOKEN_NAME (トークンが割り当て不可能な場合)
30. Kerberos認証の概要についてはこちらをご覧ください。Kerberos関連の攻撃に関する詳細については、以下を参照してください。 https://www.blackhat.com/docs/us-14/materials/us-1... 、、 https://github.com/GhostPack/Rubeus#readme
31. https://googleprojectzero.blogspot.com/2019/12/cal...
32. 例えば、ネイティブのWindowsツールであるklistは同様の機能を提供しており、明らかにLsaCallAuthenticationPackageのラッパーです。
33. 管理者権限を持たないユーザーは、自分のログオンセッションにのみチケットを適用できることに注意してください。別のログオンセッションにTGTを適用するには、管理者権限が必要です。
34. この記述にはいくつかの注意点や微妙な点があり、RubeusのREADMEでより詳しく説明されています。簡単に言うと、呼び出し元はLsaRegisterLsaProcessを介してLSA接続を登録する必要がありますが、そのためにはSeTcbPrivilege権限が必要です(つまり、呼び出し元は信頼できるコンピューティングベースの一部である必要があります)。
35. 補足として、LsaCallAuthenticationPackage を介して msv1_0 認証パッケージと通信し、以下のメッセージタイプを送信することもできます。 https://docs.microsoft.com/en-us/windows/win32/api... を参照してください。ただし、このインターフェイスを介してNTLM資格情報を取得できるかどうかは調査していません。
36. 詳細については、Rubeusのgithubリポジトリのreadmeを参照してください。そこには、Kerberos関連の多くの機能と運用セキュリティに関する考慮事項について素晴らしい説明があります。
37. 特権を有効にする例についてはこちらを参照してください。
38. これは、IDAで PsOpenProcess/Threadを見てSePrivilegeCheckの呼び出しを探すことで確認できます。
39. なお、SeDebugPrivilegeの取得は、検出ロジックの観点から見ると非常にノイズが多い傾向があることに注意してください。
40. ハッシュ/キーはrc4_hmac(例:NTLM)、aes128_hmac、aes256_hmacなどを使用できます。詳細はここを参照してください。
41. 詳細については以下を参照してください。https://www.blackhat.com/docs/us-14/materials/us-1...
42. なお、Rubeusのasktgt機能は、昇格されていないコンテキストから指定されたハッシュに対して生のAS-REQトラフィックを構築することで、lsassに触れることなく、ハッシュをバイパスする手法の一種を実行します。