From cc22501d466c0833af2de5b0380ac64dbe30a8ce Mon Sep 17 00:00:00 2001 From: Translator Date: Tue, 31 Mar 2026 16:57:35 +0000 Subject: [PATCH] Translated ['', 'src/pentesting-cloud/azure-security/az-basic-informatio --- .../az-tokens-and-public-applications.md | 276 +++++++++++------- 1 file changed, 174 insertions(+), 102 deletions(-) diff --git a/src/pentesting-cloud/azure-security/az-basic-information/az-tokens-and-public-applications.md b/src/pentesting-cloud/azure-security/az-basic-information/az-tokens-and-public-applications.md index f92cb1f56..9797e616d 100644 --- a/src/pentesting-cloud/azure-security/az-basic-information/az-tokens-and-public-applications.md +++ b/src/pentesting-cloud/azure-security/az-basic-information/az-tokens-and-public-applications.md @@ -4,95 +4,168 @@ ## 基本情報 -Entra ID は Microsoft のクラウドベースの identity and access management (IAM) プラットフォームで、Microsoft 365 や Azure Resource Manager のようなサービス向けの基盤的な認証および認可システムとして機能します。Azure AD は OAuth 2.0 authorization framework と OpenID Connect (OIDC) authentication protocol を実装して、リソースへのアクセスを管理します。 +Entra ID は Microsoft のクラウドベースのアイデンティティおよびアクセス管理(IAM)プラットフォームで、Microsoft 365 や Azure Resource Manager のようなサービス向けの認証・認可の基盤を提供します。Azure AD はアクセス管理のために OAuth と OpenID Connect (OIDC) を実装しています。 ### OAuth -**OAuth 2.0 の主要な関係者:** +**OAuth 2.0 の主要な参加者:** -1. **Resource Server (RS):** Resource Owner が所有するリソースを保護します。 -2. **Resource Owner (RO):** 通常は保護されたリソースを所有するエンドユーザーです。 -3. **Client Application (CA):** Resource Owner に代わってリソースへのアクセスを求めるアプリケーションです。 -4. **Authorization Server (AS):** クライアントアプリケーションを認証・認可した後、access tokens を発行します。 +1. **Resource Server (RS):** リソースオーナーが所有するリソースを保護するサーバ。 +2. **Resource Owner (RO):** 通常は保護されたリソースを所有するエンドユーザー。 +3. **Client Application (CA):** リソースオーナーに代わってリソースへアクセスしようとするアプリケーション。 +4. **Authorization Server (AS):** クライアントアプリケーションを認証・認可した後にアクセストークンを発行するサーバ。 -**Scopes と Consent:** +**Scopes と同意(Consent):** -- **Scopes:** リソースサーバー上で定義される粒度の細かい権限で、アクセスレベルを指定します。 -- **Consent:** Resource Owner がクライアントアプリケーションに特定のスコープでリソースへアクセスする許可を与えるプロセスです。 +- **Scopes:** リソースサーバ上で定義された細かな権限で、アクセスレベルを指定するもの。 +- **Consent:** リソースオーナーがクライアントアプリケーションに特定の scopes でリソースへのアクセスを許可するプロセス。 **Microsoft 365 の統合:** -- Microsoft 365 は IAM に Azure AD を利用しており、複数の「first-party」OAuth アプリケーションで構成されています。 -- これらのアプリケーションは深く統合されており、相互に依存するサービス関係を持つことが多いです。 -- ユーザー体験を簡素化し機能性を維持するため、Microsoft はこれらの first-party アプリケーションに対して「暗黙の同意(implied consent)」や「事前同意(pre-consent)」を付与します。 -- **Implied Consent:** 一部のアプリケーションは自動的に**特定のスコープへのアクセスが明示的なユーザーまたは管理者の承認なしに付与され**ます。 -- これらの事前同意されたスコープは通常、ユーザーや管理者の両方から隠されており、標準的な管理インターフェースでは見えにくくなっています。 +- Microsoft 365 は IAM に Azure AD を利用しており、複数の "first-party" OAuth アプリケーションで構成されています。 +- これらのアプリは深く統合され、相互に依存するサービス関係を持つことが多いです。 +- ユーザー体験を簡素化し機能性を保つために、Microsoft はこれらの first-party アプリケーションに対して "implied consent" や "pre-consent" を与えています。 +- **Implied Consent:** 特定のアプリケーションが、ユーザーや管理者の明示的な承認なしに特定の scopes へのアクセスを自動的に許可されることがあります。 +- これらの事前同意された scopes は通常、ユーザーや管理者からは隠されており、標準的な管理インターフェースでは見えにくくなっています。 **Client Application の種類:** 1. **Confidential Clients:** -- 自身のクレデンシャル(パスワードや証明書など)を持ちます。 -- Authorization Server に対して**安全に自身を認証**できます。 +- パスワードや証明書などの独自の資格情報を持つ。 +- Authorization Server に対して **安全に自身を認証できる**。 2. **Public Clients:** -- 固有のクレデンシャルを持ちません。 -- Authorization Server に対して安全に認証することができません。 -- **セキュリティ上の影響:** Authorization Server にアプリケーションの正当性を検証する仕組みがないため、攻撃者はトークンを要求する際に public client アプリケーションを偽装することができます。 +- ユニークな資格情報を持たない。 +- Authorization Server に対して安全に認証できない。 +- **セキュリティ上の影響:** Authorization Server はアプリケーションの正当性を検証する手段がないため、攻撃者はトークン要求時に public client アプリケーションを偽装できる可能性がある。 -## 認証トークン +### ROPC / Password Grant -OIDC で使用されるトークンは**3種類**あります: +OAuth2 の **Resource Owner Password Credentials**(**ROPC**)フローは、`POST` を `https://login.microsoftonline.com//oauth2/v2.0/token` に直接送り、`grant_type=password`、ユーザー名、パスワード、`client_id`、および要求する `scope` を含めます。Entra ID においてこれは主に **public clients** にとって興味深く、攻撃者は Microsoft の first-party client IDs や他の許可された public client を秘密情報なしで再利用できるためです。 +```bash +curl -X POST "https://login.microsoftonline.com//oauth2/v2.0/token" \ +-H "Content-Type: application/x-www-form-urlencoded" \ +--data-urlencode "client_id=f05ff7c9-f75a-4acd-a3b5-f4b6a870245d" \ +--data-urlencode "client_info=1" \ +--data-urlencode "grant_type=password" \ +--data-urlencode "username=user@corp.com" \ +--data-urlencode "password=Password123!" \ +--data-urlencode "scope=https://graph.microsoft.com/.default" +``` +If the credentials are valid and the flow is allowed, Entra can return **access tokens** and sometimes **refresh tokens** that are immediately usable against Microsoft Graph or the target resource. -- [**Access Tokens**](https://learn.microsoft.com/en-us/azure/active-directory/develop/access-tokens)**:** クライアントはこのトークンをリソースサーバーに提示して**リソースへアクセス**します。特定のユーザー、クライアント、およびリソースの組み合わせにのみ使用でき、期限切れになるまで**取り消すことはできません** — デフォルトでは 1 時間です。 -- **ID Tokens**: クライアントは Authorization Server からこの**トークンを受け取ります**。ユーザーに関する基本情報を含んでいます。**特定のユーザーとクライアントの組み合わせに紐づいて**います。 -- **Refresh Tokens**: access token と共にクライアントに提供されます。新しい access と ID トークンを取得するために使用されます。特定のユーザーとクライアントの組み合わせに紐づき、取り消し可能です。デフォルトの失効期間は非アクティブな refresh token が **90 日**、アクティブなトークンには **有効期限なし**(refresh token からさらに新しい refresh token を取得することが可能)です。 -- リフレッシュトークンは `aud`、いくつかの **scopes**、および **テナント** に紐づくべきであり、その aud、scopes(およびそれ以上ではない)とテナントに対してのみ access token を生成できるべきです。しかし、これは **FOCI applications tokens** には当てはまりません。 -- リフレッシュトークンは暗号化されており、復号できるのは Microsoft のみです。 -- 新しいリフレッシュトークンを取得しても前のリフレッシュトークンが取り消されることはありません。 +### Entra ID サインインログ回避クラス + +一部の過去の Entra ID のバグでは、期待される **Entra ID sign-in log** エントリを生成せずに **password validation** や場合によっては **full token issuance** が行われることがありました。これらの問題は修正されていますが、認証パイプラインがどのように失敗し、**downstream token use visible** になる一方で **upstream sign-in telemetry is absent** になるかを理解する上で有用なテクニックです。 + +#### 1. Foreign-tenant endpoint for stealth password validation + +リクエストが別のテナント GUID の token endpoint に送られた場合でも、ユーザーがその外部テナントに存在しないためフローが失敗する前に、Entra は送信されたパスワードが指定されたユーザー名に対して正しいかを検証することがあります。歴史的にはこれにより次のようなことが可能でした: + +- **Password spraying / credential validation** を被害テナントの対応するサインインログなしで実行できる +- パスワードステップが成功したかどうかを明らかにするレスポンス差 +- トークンは発行されないが、通常の失敗ログオンより少ないテレメトリしか残らない + +#### 2. Force a post-password failure + +credential validation の後に使用されるパラメータが無効である場合、例えば無効な `client_id` のように、パスワード自体は既に正しかったとしてもトランザクション全体が失敗することがあります。これにより、歴史的にはパスワード推測が成功していた事実を隠しつつ **failed** なログイン表示が生成されました。 + +覚えておくべきパターンは: + +- **Password check succeeds** +- 後続の検証ステップが失敗する +- ログは最終的なトランザクション状態を表しており、パスワード検証の成功を表さない + +#### 3. Trigger logging failure with oversized-but-valid values + +最も危険なクラスは、リクエストが構文的に有効で認証が成功し、**tokens are returned** する一方で、ある **logged field** が大きすぎてロギングパイプラインを壊す場合です。報告例には次のようなものが含まれます: + +- `openid openid openid ...` のように有効な scope を何千回も繰り返す +- 過度に長いが受け入れられる **User-Agent** ヘッダを送る + +これは一般的に次のような問題クラスを示唆します: + +1. Entra が資格情報とリクエスト構文を検証する +2. トークンが正常に発行される +3. ロギングがユーザー制御の生データフィールドを永続化しようとする +4. 長さやスキーマの想定によりロギング書き込みが失敗する +5. 対応するサインイン記録なしにユーザーが有効なトークンを取得する + +Example of the repeated-scope pattern: +```bash +curl -X POST "https://login.microsoftonline.com/${TENANT_ID}/oauth2/v2.0/token" \ +-H "Content-Type: application/x-www-form-urlencoded" \ +--data-urlencode "client_id=f05ff7c9-f75a-4acd-a3b5-f4b6a870245d" \ +--data-urlencode "client_info=1" \ +--data-urlencode "grant_type=password" \ +--data-urlencode "username=user@corp.com" \ +--data-urlencode "password=Password123!" \ +--data-urlencode "scope=$(for num in {1..10000}; do echo -n 'openid '; done)" +``` +#### ハンティング / 防御ノート + +すべての有効なトークン使用に対応する Entra のサインインイベントが必ず存在するとは限りません。疑わしい Graph のアクティビティを調査する際は、以下を相関させて確認してください: + +- **非対話型サインインログ** +- **Graph Activity Logs** +- **IP アドレス**, **ユーザー/オブジェクト ID**, **セッション/相関識別子**, および **時間ウィンドウ** + +実務的な検証方法の一つは、疑わしい「見えない成功」を通常の失敗ログオン2件の間に挟んで、取り込み遅延後に期待されるシーケンス `Failed -> Successful -> Failed` の中央イベントが欠けているかを確認することです。下流に Graph のアクティビティが存在するがサインインログがない場合は、潜在的な **サインインログの欠落** または **トークンのリプレイ** と見なしてください。 + +## Authentication Tokens + +OIDC で使用されるトークンは **3 種類** あります: + +- [**Access Tokens**](https://learn.microsoft.com/en-us/azure/active-directory/develop/access-tokens)**:** クライアントがリソースサーバーに提示して **リソースへアクセス** するためのトークンです。特定のユーザー、クライアント、リソースの組み合わせでのみ使用可能で、期限切れになるまでは **取り消すことができません**(デフォルトは 1 hour)。 +- **ID Tokens**: クライアントが認可サーバーから受け取るトークンで、ユーザーについての基本情報を含みます。特定のユーザーとクライアントの組み合わせに **バインド** されています。 +- **Refresh Tokens**: access token とともにクライアントに提供され、新しい access token と ID token を取得するために使用されます。特定のユーザーとクライアントの組み合わせにバインドされ、取り消し可能です。デフォルトの有効期限は、非アクティブな refresh token が **90 days**、アクティブなトークンは **有効期限なし**(refresh token から新しい refresh token を取得できる場合がある)です。 +- refresh token は `aud` 、いくつかの **scopes**、および **tenant** に紐づくべきであり、その aud と scopes(それ以上ではない)およびテナントに対する access token のみを生成できるはずです。ただし、**FOCI applications tokens** ではそうなっていない場合があります。 +- refresh token は暗号化されており、復号できるのは Microsoft のみです。 +- 新しい refresh token を取得しても、以前の refresh token は取り消されません。 > [!WARNING] -> conditional access に関する情報は **JWT 内に保存**されます。したがって、もし **許可された IP アドレスからトークンを要求**した場合、その **IP** がトークン内に**保存**され、後でそのトークンを使用して **許可されていない IP からでもリソースにアクセス**できる可能性があります。 +> **conditional access** に関する情報は **JWT** の内部に **保存** されます。したがって、もし許可された IP アドレスからトークンを要求すると、その **IP** がトークン内に **保存** され、許可されていない IP からでもそのトークンを使ってリソースにアクセスできてしまう可能性があります。 ### Access Tokens "aud" -"aud" フィールドに示される値は、ログインを行うために使用される **リソースサーバー**(アプリケーション)です。 +"aud" フィールドに示される値は、ログイン時に使用される **リソースサーバー(アプリケーション)** です。 コマンド `az account get-access-token --resource-type [...]` は以下のタイプをサポートしており、それぞれ結果の access token に特定の "aud" を追加します: > [!CAUTION] -> 次に示すものは `az account get-access-token` がサポートする API の例にすぎず、他にも存在します。 +> 以下は `az account get-access-token` がサポートする API の一部にすぎません。他にも存在します。
-aud examples +aud の例 -- **aad-graph (Azure Active Directory Graph API)**: レガシーの Azure AD Graph API(非推奨)へアクセスするために使用され、アプリケーションが Azure Active Directory (Azure AD) 内のディレクトリデータを読み書きすることを可能にします。 +- **aad-graph (Azure Active Directory Graph API)**: レガシーの Azure AD Graph API(非推奨)へアクセスするために使用され、アプリケーションが Azure Active Directory (Azure AD) のディレクトリデータを読み書きすることを可能にします。 - `https://graph.windows.net/` -* **arm (Azure Resource Manager)**: Azure Resource Manager API を通じて Azure リソースを管理するために使用されます。これには仮想マシン、ストレージアカウントなどのリソースの作成、更新、削除といった操作が含まれます。 +- **arm (Azure Resource Manager)**: Azure Resource Manager API を通じて Azure リソースを管理するために使用されます。仮想マシン、ストレージアカウントなどの作成、更新、削除といった操作を含みます。 - `https://management.core.windows.net/ or https://management.azure.com/` -- **batch (Azure Batch Services)**: 大規模並列処理や高性能コンピューティングアプリケーションをクラウドで効率的に実行するための Azure Batch にアクセスするために使用されます。 +- **batch (Azure Batch Services)**: Azure Batch にアクセスするために使用され、クラウド上で大規模な並列および高性能コンピューティングアプリケーションを効率的に実行するサービスです。 - `https://batch.core.windows.net/` -* **data-lake (Azure Data Lake Storage)**: スケーラブルなデータストレージおよび分析サービスである Azure Data Lake Storage Gen1 と対話するために使用されます。 +- **data-lake (Azure Data Lake Storage)**: Azure Data Lake Storage Gen1 と対話するために使用される、スケーラブルなデータストレージおよび分析サービスです。 - `https://datalake.azure.net/` -- **media (Azure Media Services)**: 動画や音声コンテンツのクラウドベースのメディア処理と配信を提供する Azure Media Services にアクセスするために使用されます。 +- **media (Azure Media Services)**: ビデオや音声コンテンツのクラウドベースのメディア処理および配信サービスである Azure Media Services にアクセスするために使用されます。 - `https://rest.media.azure.net` -* **ms-graph (Microsoft Graph API)**: Microsoft 365 サービスのデータに対する統一エンドポイントである Microsoft Graph API にアクセスするために使用されます。Azure AD、Office 365、Enterprise Mobility、Security services などのサービスからデータやインサイトにアクセスできます。 +- **ms-graph (Microsoft Graph API)**: Microsoft 365 サービスのデータに対する統一エンドポイントである Microsoft Graph API にアクセスするために使用されます。Azure AD、Office 365、Enterprise Mobility、セキュリティサービスなどのデータやインサイトにアクセスできます。 - `https://graph.microsoft.com` -- **oss-rdbms (Azure Open Source Relational Databases)**: MySQL、PostgreSQL、MariaDB といったオープンソースのリレーショナルデータベースエンジン向けの Azure Database サービスへアクセスするために使用されます。 +- **oss-rdbms (Azure Open Source Relational Databases)**: MySQL、PostgreSQL、MariaDB などのオープンソース関係データベース向けの Azure Database サービスにアクセスするために使用されます。 - `https://ossrdbms-aad.database.windows.net`
### Access Tokens Scopes "scp" -access token のスコープは access token JWT の scp キーの中に格納されます。これらのスコープは access token が何にアクセスできるかを定義します。 +access token のスコープは、access token JWT の中の scp キーに格納されます。これらのスコープは、その access token が何にアクセスできるかを定義します。 -もし JWT が特定の API に接触することを許可されていても、要求された操作を実行するためのスコープを**持っていない**場合、その JWT ではその操作を**実行できません**。 +JWT が特定の API に接続することを許可されていても、要求された操作を実行するためのスコープを持っていなければ、その JWT では操作を実行できません。 ### Get refresh & access token example ```python @@ -147,29 +220,28 @@ pprint(new_azure_cli_bearer_tokens_for_graph_api) ### その他の access token フィールド - **appid**: トークンを生成するために使用された Application ID -- **appidacr**: Application Authentication Context Class Reference はクライアントがどのように認証されたかを示す。public client の場合は値が 0、client secret が使用された場合は値が 1 になる -- **acr**: Authentication Context Class Reference claim は、エンドユーザーの認証が ISO/IEC 29115 の要件を満たさなかったときに "0" になる -- **amr**: Authentication method はトークンがどのように認証されたかを示す。値が “pwd” の場合はパスワードが使われたことを示す -- **groups**: principal がメンバーであるグループを示す -- **iss**: トークンを生成した security token service (STS) を識別する。e.g. https://sts.windows.net/fdd066e1-ee37-49bc-b08f-d0e152119b04/ (the uuid is the tenant ID) -- **oid**: principal の object ID +- **appidacr**: The Application Authentication Context Class Reference はクライアントがどのように認証されたかを示します。public client の場合は値が 0、client secret が使われた場合は値が 1 です +- **acr**: Authentication Context Class Reference のクレームは、エンドユーザーの認証が ISO/IEC 29115 の要件を満たさなかった場合に "0" になります。 +- **amr**: 認証方法を示します。値が "pwd" の場合はパスワードが使われたことを示します。 +- **groups**: プリンシパルが所属するグループを示します。 +- **iss**: 発行者はトークンを生成した security token service (STS) を識別します。例: https://sts.windows.net/fdd066e1-ee37-49bc-b08f-d0e152119b04/ (uuid は tenant ID) +- **oid**: プリンシパルのオブジェクト ID - **tid**: Tenant ID -- **iat, nbf, exp**: Issued at (when it was issued), Not before (cannot be used before this time, usually same value as iat), Expiration time. - +- **iat, nbf, exp**: Issued at(発行時刻)、Not before(この時刻以前は使用できない、通常 iat と同じ値)、Expiration time(有効期限) ## FOCI Tokens Privilege Escalation -前述のとおり、refresh tokens は生成時に指定された **scopes**、生成先の **application**、および **tenant** に紐付けられるべきだ。これらの境界のいずれかが破られると、ユーザーがアクセス権を持つ他のリソースや別の tenants に対して、本来意図された以上の scopes を持つ access tokens を生成できるようになり、権限を昇格させることが可能になる。 +前述のように、refresh tokens は生成された **scopes** や **application**、そして生成先の **tenant** に紐づけられるべきだと述べました。これらの境界のいずれかが破られると、ユーザーがアクセスできる別のリソースやテナント向けに、元々意図されたより多くの scope を持つ access token を生成できてしまい、権限を昇格させることが可能になります。 -さらに、[Microsoft identity platform](https://learn.microsoft.com/en-us/entra/identity-platform/)(Microsoft Entra accounts、Microsoft personal accounts、そして social accounts like Facebook and Google)では、[**docs**](https://learn.microsoft.com/en-us/entra/identity-platform/refresh-tokens) にあるとおり、**this is possible with all refresh tokens**: "Refresh tokens are bound to a combination of user and client, but **aren't tied to a resource or tenant**. A client can use a refresh token to acquire access tokens **across any combination of resource and tenant** where it has permission to do so. Refresh tokens are encrypted and only the Microsoft identity platform can read them." +さらに、[Microsoft identity platform](https://learn.microsoft.com/en-us/entra/identity-platform/)(Microsoft Entra accounts、Microsoft personal accounts、Facebook や Google のような social accounts を含む)におけるすべての refresh tokens でこれが可能です。なぜなら [**docs**](https://learn.microsoft.com/en-us/entra/identity-platform/refresh-tokens) にあるように: "Refresh tokens are bound to a combination of user and client, but **aren't tied to a resource or tenant**. A client can use a refresh token to acquire access tokens **across any combination of resource and tenant** where it has permission to do so. Refresh tokens are encrypted and only the Microsoft identity platform can read them." -また、FOCI applications は public applications であるため、サーバーに認証するのに **no secret is needed** である点に注意する。 +また、FOCI applications は public applications であるため、サーバーに対して認証するのに **secret は不要** である点に注意してください。 -既知の FOCI clients は [**original research**](https://github.com/secureworks/family-of-client-ids-research/tree/main) に報告されており、[**found here**](https://github.com/secureworks/family-of-client-ids-research/blob/main/known-foci-clients.csv) で確認できる。 +そのため、[**original research**](https://github.com/secureworks/family-of-client-ids-research/tree/main) で報告された既知の FOCI clients は [**ここ**](https://github.com/secureworks/family-of-client-ids-research/blob/main/known-foci-clients.csv) で確認できます。 ### Get different scope -前のサンプルコードに続いて、このコードでは別の scope のための新しいトークンを要求している: +前のサンプルコードに続き、このコードでは別の scope に対する新しいトークンを要求しています: ```python # Code from https://github.com/secureworks/family-of-client-ids-research azure_cli_bearer_tokens_for_outlook_api = ( @@ -186,7 +258,7 @@ scopes=[ ) pprint(azure_cli_bearer_tokens_for_outlook_api) ``` -### 異なるクライアントとスコープを取得する +### 異なる client と scopes を取得する ```python # Code from https://github.com/secureworks/family-of-client-ids-research microsoft_office_client = msal.PublicClientApplication("d3590ed6-52b3-4102-aeff-aad2292ab01c") @@ -204,61 +276,60 @@ pprint(microsoft_office_bearer_tokens_for_graph_api) ``` ## NAA / BroCI (Nested App Authentication / Broker Client Injection) -A BroCI refresh token は、既存の refresh token を追加の broker パラメータとともに使い、別の信頼された first-party app としてトークンを要求する brokered token exchange のパターンです。 +BroCI refresh tokens は、既存の refresh token を追加の broker parameters と共に使用して、別の信頼された first-party app としてトークンを要求する brokered token exchange パターンです。 -These refresh tokens must be minted in that broker context (a regular refresh token usually cannot be used as a BroCI refresh token). +これらの refresh token はその broker コンテキストで発行されている必要があります(通常の refresh token は通常 BroCI refresh token として使用できません)。 -### Goal and purpose +### 目的と狙い -BroCI の目的は、broker 対応の app チェーンから有効なユーザーセッションを再利用して、別の信頼された app/resource ペア用のトークンを要求することです。これにより、元のトークンからの「特権昇格」を可能にします。 +BroCI の目的は、broker 対応アプリチェーンから有効なユーザーセッションを再利用し、別の信頼された app/resource ペア用のトークンを要求することです。つまり、元のトークンから「権限をエスカレート」できるようにすることです。 -From an offensive perspective, this matters because: +攻撃的観点で重要なのは次の点です: -- It can unlock pre-consented first-party app paths that are not accessible with standard refresh exchanges. -- It can return access tokens for high-value APIs (for example, Microsoft Graph) under app identities with broad delegated permissions. -- It expands post-authentication token pivoting opportunities beyond classic FOCI client switching. +- 標準の refresh 交換ではアクセスできない、事前同意された first-party アプリの経路を開く可能性がある。 +- 広範な delegated permissions を持つアプリ識別で、高価値 API(例えば Microsoft Graph)向けの access token を返す可能性がある。 +- 古典的な FOCI クライアント切り替えを超えて、認証後のトークンピボット機会を拡張する。 -What changes in a NAA/BroCI refresh token is not the visible token format, but the **issuance context** and broker-related metadata that Microsoft validates during brokered refresh operations. +NAA/BroCI refresh token で変わるのは可視のトークン形式ではなく、**発行コンテキスト**と Microsoft が brokered refresh 操作中に検証する broker 関連メタデータです。 -NAA/BroCI token exchanges are **not** the same as a regular OAuth refresh exchange. +NAA/BroCI token exchanges は通常の OAuth refresh 交換とは**異なります**。 -- A regular refresh token (for example obtained via device code flow) is usually valid for standard `grant_type=refresh_token` operations. -- A BroCI request includes additional broker context (`brk_client_id`, broker `redirect_uri`, and `origin`). -- Microsoft validates whether the presented refresh token was minted in a matching brokered context. -- Therefore, many "normal" refresh tokens fail in BroCI requests with errors such as `AADSTS900054` ("Specified Broker Client ID does not match ID in provided grant"). -- You generally cannot "convert" a normal refresh token into a BroCI-valid one in code. -- You need a refresh token already issued by a compatible brokered flow. +- 通常の refresh token(例えば device code flow で取得したもの)は、一般に標準の `grant_type=refresh_token` 操作で有効です。 +- BroCI リクエストには追加の broker コンテキスト(`brk_client_id`、broker の `redirect_uri`、および `origin`)が含まれます。 +- Microsoft は提示された refresh token が一致する brokered コンテキストで発行されたかどうかを検証します。 +- そのため、多くの「通常の」refresh token は BroCI リクエストで `AADSTS900054`("Specified Broker Client ID does not match ID in provided grant")などのエラーで失敗します。 +- 通常、コードで通常の refresh token を BroCI 有効なものに「変換」することはできません。 +- 互換性のある brokered フローによって既に発行されている refresh token が必要です。 -Check the web **** to find BroCI configured apps an the trust relationships they have. +Web **** を確認すると、BroCI 構成されたアプリとそれらの信頼関係を見つけられます。 +### メンタルモデル -### Mental model - -Think of BroCI as: +BroCI を次のように考えてください: `user session -> brokered refresh token issuance -> brokered refresh call (brk_client_id + redirect_uri + origin) -> access token for target trusted app/resource` -If any part of that broker chain does not match, the exchange fails. +チェーンのどの部分でも不一致があれば、交換は失敗します。 ### Where to find a BroCI-valid refresh token -One practical way is browser portal traffic collection: +実用的な方法の一つはブラウザのポータルトラフィック収集です: -1. Sign in to `https://entra.microsoft.com` (or Azure portal). -2. Open DevTools -> Network. -3. Filter for: +1. `https://entra.microsoft.com`(または Azure portal)にサインインする。 +2. DevTools -> Network を開く。 +3. 以下でフィルタする: - `oauth2/v2.0/token` - `management.core.windows.net` -4. Identify the brokered token response and copy `refresh_token`. -5. Use that refresh token with matching BroCI parameters (`brk_client_id`, `redirect_uri`, `origin`) when requesting tokens for target apps (for example ADIbizaUX / Microsoft_Azure_PIMCommon scenarios). +4. brokered token のレスポンスを特定し、`refresh_token` をコピーする。 +5. その refresh token を、対象アプリ(例えば ADIbizaUX / Microsoft_Azure_PIMCommon シナリオ)向けにトークンを要求する際、対応する BroCI パラメータ(`brk_client_id`、`redirect_uri`、`origin`)と共に使用する。 ### Common errors -- `AADSTS900054`: The refresh token context does not match the supplied broker tuple (`brk_client_id` / `redirect_uri` / `origin`) or the token is not from a brokered portal flow. -- `AADSTS7000218`: The selected client flow expects a confidential credential (`client_secret`/assertion), often seen when trying device code with a non-public client. +- `AADSTS900054`: refresh token のコンテキストが提供された broker タプル(`brk_client_id` / `redirect_uri` / `origin`)と一致しない、またはトークンが brokered portal フロー由来ではない。 +- `AADSTS7000218`: 選択したクライアントフローが confidential credential(`client_secret`/assertion)を期待しており、public client で device code を試行したときなどに発生する。
-Python 用 BroCI refresh ヘルパー (broci_auth.py) +Python BroCI refresh ヘルパー (broci_auth.py) ```python #!/usr/bin/env python3 """ @@ -531,32 +602,33 @@ raise SystemExit(main()) ```
-## tokens の見つけ方 +## トークンが見つかる場所 -攻撃者の観点から、被害者のPCが侵害された場合などに access and refresh tokens をどこで見つけられるかを知ることは非常に有用です: +攻撃者の観点から、例えば被害者のPCが侵害された場合にどこで access と refresh tokens を見つけられるかを知ることは非常に重要です: - Inside **`/.Azure`** -- **`azureProfile.json`** は過去にログインしたユーザーの情報を含む -- **`clouds.config`** はサブスクリプションに関する情報を含む -- **`service_principal_entries.json`** はアプリケーションの資格情報 (tenant id, clients and secret) を含む。Linux & macOS のみ -- **`msal_token_cache.json`** は access tokens および refresh tokens を含む。Linux & macOS のみ -- **`service_principal_entries.bin`** と **`msal_token_cache.bin`** は Windows で使用され、DPAPI で暗号化されている -- **`msal_http_cache.bin`** は HTTP リクエストのキャッシュ -- 読み込む: `with open("msal_http_cache.bin", 'rb') as f: pickle.load(f)` -- **`AzureRmContext.json`** は Az PowerShell を使った過去のログインに関する情報を含む(ただし資格情報は含まない) -- `C:\Users\\AppData\Local\Microsoft\IdentityCache\*` 内には複数の `.bin` ファイルがあり、これらは access tokens、ID tokens、アカウント情報をユーザーの DPAPI で暗号化したもの -- `C:\Users\\AppData\Local\Microsoft\TokenBroken\Cache\` 内の `.tbres` ファイルには、DPAPI で暗号化された base64 でエンコードされた access tokens がさらに見つかる可能性がある -- Linux と macOS では、Az PowerShell を使用している場合 `pwsh -Command "Save-AzContext -Path /tmp/az-context.json"` を実行して access tokens、refresh tokens、id tokens を取得できる -- Windows ではこれは id tokens のみを生成する -- Linux と macOS で Az PowerShell が使われたかを確認するには `$HOME/.local/share/.IdentityService/` の存在を確認する(ただし中のファイルは空で役に立たないことが多い) -- ユーザーがブラウザで Azure にログインしている場合、こちらの [**post**](https://www.infosecnoodle.com/p/obtaining-microsoft-entra-refresh?r=357m16&utm_campaign=post&utm_medium=web) によれば、認証フローをローカルホストへの redirect で開始し、ブラウザに自動的にログインを許可させて refresh token を受け取ることが可能です。localhost への redirect を許可する FOCI アプリケーションはごくわずか(az cli や PowerShell モジュールなど)なので、これらのアプリケーションが許可されている必要があります。 -- ブログで説明されているもう一つの方法はツール [**BOF-entra-authcode-flow**](https://github.com/sudonoodle/BOF-entra-authcode-flow) を使うことです。任意のアプリケーションを使える理由は、redirect URI `https://login.microsoftonline.com/common/oauth2/nativeclient` を使って最終的な認証ページのタイトルから OAuth code を取得し、それを使って refresh token を得るからです。 +- **`azureProfile.json`** は過去にログインしたユーザーの情報を含みます +- **`clouds.config contains`** はサブスクリプションの情報を含みます +- **`service_principal_entries.json`** はアプリケーションの資格情報(tenant id、clients、secret)を含みます。Linux & macOS のみ +- **`msal_token_cache.json`** は access tokens と refresh tokens を含みます。Linux & macOS のみ +- **`service_principal_entries.bin`** と msal_token_cache.bin は Windows で使用され、DPAPI で暗号化されています +- **`msal_http_cache.bin`** は HTTP request のキャッシュです +- 読み込み: `with open("msal_http_cache.bin", 'rb') as f: pickle.load(f)` +- **`AzureRmContext.json`** は Az PowerShell を使用した過去のログイン情報を含みます(ただし資格情報は含まれません) +- Inside **`C:\Users\\AppData\Local\Microsoft\IdentityCache\*`** には、ユーザーの DPAPI で暗号化された複数の `.bin` ファイルがあり、そこに **access tokens**、ID tokens、アカウント情報が含まれています +- `.tbres` ファイル(**`C:\Users\\AppData\Local\Microsoft\TokenBroken\Cache\`** 内)にもより多くの **access tokens** が見つかる可能性があり、これらは DPAPI で暗号化された base64 を含みます +- Linux と macOS では、Az PowerShell(使用されていれば)から `pwsh -Command "Save-AzContext -Path /tmp/az-context.json"` を実行して **access tokens, refresh tokens and id tokens** を取得できます +- Windows ではこれにより id tokens のみが生成されます +- Linux と macOS で Az PowerShell が使用されたかどうかは `$HOME/.local/share/.IdentityService/` が存在するかで確認できます(ただし中のファイルは空で役に立たないことが多いです) +- ユーザーが **logged inside Azure with the browser** の場合、こちらの [**post**](https://www.infosecnoodle.com/p/obtaining-microsoft-entra-refresh?r=357m16&utm_campaign=post&utm_medium=web) によれば、認証フローを **redirect to localhost** で開始させ、ブラウザに自動的にログイン承認させて refresh token を取得することが可能です。localhost への redirect を許可する FOCI アプリケーションは限られている(例えば az cli や powershell module など)ため、これらのアプリケーションが許可されている必要があります +- ブログで説明されている別の手法として、任意のアプリケーションを利用できるツール [**BOF-entra-authcode-flow**](https://github.com/sudonoodle/BOF-entra-authcode-flow) を使う方法があります。これは最終認証ページのタイトルから OAuth code を取得し、その後 refresh token を得るために使用されるリダイレクト URI `https://login.microsoftonline.com/common/oauth2/nativeclient` を利用します -## 参考 +## References - [https://github.com/secureworks/family-of-client-ids-research](https://github.com/secureworks/family-of-client-ids-research) - [https://github.com/Huachao/azure-content/blob/master/articles/active-directory/active-directory-token-and-claims.md](https://github.com/Huachao/azure-content/blob/master/articles/active-directory/active-directory-token-and-claims.md) - [https://specterops.io/blog/2025/10/15/naa-or-broci-let-me-explain/](https://specterops.io/blog/2025/10/15/naa-or-broci-let-me-explain/) - [https://specterops.io/blog/2025/08/13/going-for-brokering-offensive-walkthrough-for-nested-app-authentication/](https://specterops.io/blog/2025/08/13/going-for-brokering-offensive-walkthrough-for-nested-app-authentication/) +- [https://trustedsec.com/blog/full-disclosure-a-third-and-fourth-azure-sign-in-log-bypass-found](https://trustedsec.com/blog/full-disclosure-a-third-and-fourth-azure-sign-in-log-bypass-found) {{#include ../../../banners/hacktricks-training.md}}