Terrance DeJesus

Microsoft Entra ID OAuth のフィッシングと検出

In-the-Wild(ItW)Entra ID、OAuthフィッシングおよび検出戦略に関する短期集中コース

40分で読めますセキュリティ調査
Microsoft Entra ID OAuth のフィッシングと検出

前文

Elasticの脅威リサーチ&検出エンジニアリング(TRADE)チームのメンバーは、最近、Microsoft Entra ID(旧Azure AD)のOAuthワークフローを標的とする新たな脅威に注目しました。この調査は、Volexityの最近のブログ「 Phishing for Codes: Russian Threat Actors Target Microsoft 365 OAuth Workflows」に触発されたもので、NGOに対する高度なOAuthフィッシングキャンペーンは、 UTA0352と指定された脅威アクターによるものだとされています。

Volexityの調査は、攻撃者が信頼できるファーストパーティのMicrosoftアプリケーションを悪用して従来の防御を回避した方法の説得力のあるフォレンジック証拠を示しています。攻撃者は、正規のOAuthフローとオープンソースツールの ROADtoolsを使用して、カスタマイズされたMicrosoft認証URLを作成し、セキュリティトークンを収集して、ユーザーになりすましたり、権限を昇格させたり、Outlookの電子メールのダウンロードやSharePointサイトへのアクセスなど、Microsoft Graphを介してデータを盗み出したりしました。

彼らのレポートには攻撃 の内容 が詳細に書かれていますが、Elasticのチームは その方法を理解することに重点を置いています。制御された環境で攻撃チェーンをエミュレートし、トークンの悪用、デバイスの登録、トークンのエンリッチメントの仕組みを直接調査しました。この実践的な実験により、Microsoft の OAuth 実装の内部動作、ROADtools の実用化、推奨される軽減策、そして最も重要なこととして、同様のアクティビティを特定して対応するための効果的な検出戦略について、より深い洞察を得ることができました。

Microsoft Entra ID の OAuth

Microsoft Entra ID は、Outlook、SharePoint、Graph API などの Microsoft 365 サービスへの委任されたアクセスを可能にするために OAuth 2.0 を実装しています。OAuth 仕様は標準化されていますが (RFC6749)、Entra ID では、委任されたアクセスの仕組みと敵対者がそれらを悪用する方法に影響を与える独自の動作とトークンの種類が導入されています。

委任されたアクセスでは、アプリケーションは、サインインしているユーザーに代わって行動する権限があり、アプリが要求し、ユーザーまたは管理者が同意するスコープ (アクセス許可) によって制約されます。このモデルは、アプリが毎回資格情報の入力を求めることなくユーザーのメール、ファイル、またはディレクトリ データを取得するエンタープライズ環境で一般的です。

一般的な委任認証フローには、次のものが含まれます。

認証リクエスト (OAuth 2.0 Authorization Code Grant): アプリは、特定のスコープ (Mail.Read、offline_access など) を持つリソース (Graph など) へのアクセスをリクエストします。これらは、URI にパラメーターとして追加されます。

  • client_id: アプリケーションの ID (VSCode など)
  • Response_type: グラントタイプの OAuth ワークフロー (例:デバイスコード、認証コード)
  • スコープ: ターゲット リソースに対して要求されたアクセス許可 (例:Mail.Read、offline_access)
  • Redirect_uri:認証コードの送付先
  • 状態: CSRF 保護
  • Login_hint:ユーザー名を事前入力します

ユーザー認証(OpenID Connect):Entra IDは、ポリシー(パスワード、MFA、デバイストラスト)を介してユーザーを認証します。

  • 一要素認証(SFA)
  • 多要素認証(MFA)
  • デバイスの信頼 (ハイブリッド参加、Intune コンプライアンス)
  • 条件付きアクセス ポリシー (CAP)
  • シングルサインオン(SSO)

同意: 同意は、アプリが認証コードを受け取ることができるかどうか、および許可されるスコープを制御します。

  • ユーザーの同意が必要なスコープ (例:Mail.Read、offline_access)
  • 管理者の同意が必要なスコープ (例:Directory.ReadWrite) には昇格された承認が必要です。

トークンの発行: アプリは認証コードを受け取り、それを次のものと引き換えます。

  • アクセストークン – GraphなどのAPIを呼び出すために使用される短命のトークン。
  • リフレッシュトークン(RT) - 新しいアクセストークンを静かに取得するための長寿命のトークン。
  • ID トークン - 認証されたユーザーについて説明します。OpenID フローに存在します。
  • (オプション)プライマリ更新トークン: ユーザーがドメインに参加しているデバイスまたは登録済みデバイスを使用している場合、プライマリ更新トークン (PRT) を使用すると、ユーザーの操作なしでサイレント SSO と追加のトークン フローを有効にできます。
  • トークンの主張: 要求は、JWT トークンに埋め込まれたキーと値のペアで、認証のユーザー、アプリ、デバイス、スコープ、コンテキストを記述します。

MSFT OAuth フィッシング URL の定義

Volexityのレポートから得られた主な調査結果についてご紹介する前に、Microsoft OAuthのフィッシングURLを正確に定義するものを分解することが重要です。

前述のように、Microsoft Entra ID はこれらの URL に依存して、どのアプリケーション (クライアント) がどのユーザー プリンシパルに代わって、どのリソースに、どのようなアクセス許可でアクセスを要求しているかを判断します。このコンテキストの多くは、OAuth 認証リクエストのクエリパラメータに直接埋め込まれているため、敵対者と防御者の両方にとって重要なメタデータのソースとなっています。

以下は、Volexityのブログから引用した、認証コード付与フローに沿ったフィッシングURLの例です。

https://login.microsoftonline[.]com/organizations/oauth2/v2.0/authorize?state=https://mae.gov[.]ro/[REMOVED]&client_id=aebc6443-996d-45c2-90f0-388ff96faa56&scope=https://graph.microsoft.com/.default&response_type=code&redirect_uri=https://insiders.vscode.dev/redirect&login_hint=<EMAIL HERE>

主要なコンポーネントのいくつかを分解してみましょう。

  • login.microsoftonline.com – グローバルな Microsoft Entra ID 認証エンドポイント。
  • /oauth2/v2.0/authorize - 認証ワークフローの MSFT Entra ID OAuth v2.0 エンドポイント
  • state - CSRF を防止し、アプリケーションの状態を維持するために使用されるオプションの値。フィッシングのリダイレクトを難読化するために悪用されることもあります。
  • client_id - リクエストを行うアプリケーション ID。これは、Microsoftのファーストパーティアプリ(VSCode、Teamsなど)または敵対者によって登録された悪意のあるサードパーティアプリに属している可能性があります。
  • scope – アプリケーションが要求しているアクセス許可を定義します (Mail.Read、offline_access など)。.default スコープは、クライアントの資格情報フローで事前に同意されたアクセス許可を取得するためによく使用されます。
  • response_type=code – フローが認証コードをリクエストしていることを示します。これは、後でアクセストークンや更新トークンと交換できます。
  • redirect_uri – Entra IDがユーザーの認証後に応答を送信する場所。攻撃者がこの URI を制御している場合、攻撃者はコードを取得するか、有効な MSFT 管理の URI を取得します。
  • login_hint – ターゲット ユーザーを指定します (例: alice @ tenant.onmicrosoft.com)。多くの場合、フィッシング時の摩擦を減らすために事前に充填されています。

注: この例では、一般的な Microsoft Entra ID OAuth フィッシング URL を示していますが、多くのバリエーションがあります。攻撃者は、永続的なアクセスの取得、電子メールの流出、広範な同意付与による特権の昇格など、特定の目的に応じて、クライアント ID、スコープ、グラントタイプ、リダイレクト URI などのパラメータを調整することがあります。

上記の内容が重要である理由

これらのパラメータはカスタマイズ可能であるため、攻撃者は自分の操作に合わせて値を簡単に交換できます。例えば:

  • 彼らは、正当なMicrosoftクライアントIDを使用して、無害なアプリケーションに溶け込む可能性があります。
  • 彼らは.defaultを使うかもしれません特定の同意プロンプトをバイパスするスコープ。
  • 彼らは、認証コードを収集するために、redirect_uriを自分たちの管理下にあるサイトにポイントします。
  • 偵察中に特定した可能性のある特定のユーザー プリンシパルをターゲットにすることができます。
  • 運用上のニーズに基づいて、リソースを対象とするようにアクセス許可を調整できます。

ターゲットが認証されると、目標は単純で、認証コードを取得することです。その後、このコードは (多くの場合、ROADtools などのツールを使用して) 更新トークンやアクセス トークンと交換され、攻撃者は Graph API 呼び出しを行ったり、他のユーザーの操作なしで他の Microsoft 365 サービスにピボットしたりできます。

Volexityの主な調査結果の抽象化

脅威検出のためには、OAuth などのプロトコル、Microsoft Entra ID でのワークフローの実装、この操作に関して敵対者が取った行動や手順に関するコンテキスト メタデータを理解することが重要です。

Volexityの調査と研究から、報告されたOAuthフィッシングのさまざまなバリエーションを把握できます。理解しやすいように、これらを分解することにしました。

VSCode Client On-Behalf-Of Target ユーザー プリンシパルとして Graph API にアクセスするための OAuth フィッシング: これらの URL は、例「MSFT OAuth フィッシング URL を定義するもの」と似ています。最終的な目標は、デフォルトの権限を持つ Graph API へのアクセス トークンです。

  • OAuthフィッシングURLはカスタムで、「承認」エンドポイントを指していました
  • クライアント ID は特に VSCode ("aebc6443-996d-45c2-90f0-388ff96faa56") でした。
  • リソース/スコープはMSFTグラフ(「https://graph.microsoft.com/.default」).defaultを使用権限
  • トークン付与フローは認証コード(response_type=コード)でした
  • リダイレクトURIは正当なMSFTドメイン(インサイダー[.]vscode[.]開発または vscode-redirect[.]azurewebsites[.]ネット)
  • ログイン ヒントは、対象とする特定のユーザー プリンシパルでした (サービス プリンシパルではありません)
  • 敵対者は、ターゲットにURLを開き、認証して認証コードを共有するように要求しました(1.AXg....)

ここから、攻撃者は MSFT の OAuth トークン エンドポイント (https://login.microsoftonline.com/[tenant_id]/oauth2/v2.0/token) にリクエストを送信し、更新トークンをアクセス トークンと交換できます。これは、敵対者がGraph APIにアクセスし、ユーザーが通常利用可能なリソースにアクセスすることを可能にするのに十分です。これらの指標は、このブログの後半で検出と狩猟の戦略を織り込むために重要になります。

MSFT Auth Broker としてのデバイス登録のための OAuth フィッシング: これらの URL は、仮想デバイスの登録、RT の PRT の交換、Graph API と Sharepoint アクセスによる電子メール アクセスを実現するために PRT エンリッチメントを必要とするサブシーケンス ROADtools の使用と連鎖しているため、一意です。

  • OAuth フィッシング URL はカスタムで、authorize (https://login.microsoftonline.com/[tenant_id]/oauth2/v2.0/authorize) を指していました。エンドポイント
  • クライアント ID は、特に MSFT 認証ブローカー ("29d9ed98-a469-4536-ade2-f981bc1d605e") でした
  • リソース/スコープはデバイス登録サービス (DRS) ("01cb2876-7ebd-4aa4-9cc9-d28bd4d359a9") でした
  • トークン付与フローは認証コード(response_type=コード)でした
  • リダイレクト URI には、クラウドベースのドメイン参加エンドポイントが含まれます (通常は Windows セットアップまたは Autopilot 中に使用されます)
  • ログインヒントには、ユーザープリンシパルのメールアドレス(ターゲット)が含まれています
  • リクエストは最終的にADRSトークン用です

ユーザーがフィッシングに遭い、URLを開いた場合、認証により、攻撃者がデバイスを登録し、その後、デバイスの秘密鍵とPEMファイルを含むPRTを取得するために必要なADRSトークンが提供されます。

Volexityのブログには、登録されたデバイスIDを介した侵害IDのアクティビティの追跡や、承認された2FAリクエストが特定された後の侵害後のアクティビティに関する追加情報も含まれており、攻撃者は新しく登録されたデバイスに関連付けられたセッションでターゲットの電子メールをダウンロードすることができます。

このように各フィッシングの試みを理解した上で、次の目標は、これを自社の MSFT テナントでできるだけ正確に再現し、妥当な検出のためのデータを収集することです。

エミュレーションの取り組み

さて、この時点で、OAuthの基本と、Microsoft Entra IDがそれをどのように実装するかについて説明しました。Microsoft OAuthのフィッシングURLの定義を分解し、その重要なパラメータを解読し、Volexityの優れた調査から重要な洞察を引き出して、これらのフィッシングワークフローに沿った指標を特定しました。

しかし、理論とVolexityのノートブックを垣間見るだけでは、私たちはそこまでしか到達できません。

攻撃者の視点、実行の連鎖全体、ツールの癖、微妙な落とし穴、悪用の機会を真に理解するために、ホワイトボックステストを実践的に行うことにしました。OAuthのフィッシングプロセスを自社のテナントで再現し、トークンの収集からリソースアクセスまですべてをエミュレートしました。目標は?静的なインジケーターを超えて、防御者が確実に検出できる行動のパンくずリストを表面化します。

さっそく見ていきましょう。

要件

まず、Azure での脅威の調査と検出環境について、いくつかの詳細を共有することをお勧めします。

  • 確立された Azure テナント: TENANT.onmicrosoft.com
  • Sharepointドメインの設立:DOMAIN.sharepoint.com
  • ネイティブIdP Microsoft Entra ID – IAMの有効化
  • すべてのユーザー向けの Microsoft 365 ライセンス (P2)
  • Azure アクティビティ ログの EventHub へのストリーミング
  • Microsoft Entra ID サインイン ログが EventHub にストリーミングされる
  • Microsoft Entra ID 監査ログの EventHub へのストリーミング
  • Microsoft Graph 監査ログの EventHub へのストリーミング
  • Microsoft 365 監査ログの EventHub へのストリーミング
  • Elastic Azure と M365 の統合が有効になり、EventHub からのログ ダイジェストが取得されました
  • MFA を必要とする CAP で有効化された基本管理者ユーザー
  • 2FAエミュレーション用のモバイル上のMSFT認証アプリ
  • Windows 10 デスクトップとNordVPN(Adversary Box)
  • macOS エンドポイント (Victim box)

1 つのエンドポイントからワークフローをたどることもできますが、多くの場合、開発者の検出に不可能移動のバリエーションに個別のソース アドレスを反映したデータが必要になることに注意してください。

シナリオ 1: VSCode クライアントとしての OAuth フィッシング

エミュレーション

Volexityが文書化したフィッシング手法をエミュレートするために、Microsoft Entra IDを使用してOAuth 2.0認証URLを生成するPythonスクリプトを構築しました。この URL は、ファースト パーティの Visual Studio Code アプリを偽装して、Microsoft Graph API への委任されたアクセスを要求する、認証コード付与フローを開始します。

次のパラメータを使用してURLを構成しました。

{
  "client_id": "aebc6443-996d-45c2-90f0-388ff96faa56",
  "response_type": "code",
  "redirect_uri": "insiders.vscode.dev/redirect",
  "scope": "https://graph.microsoft.com/.default",
  "login_hint": "user @ tenant.onmicrosoft.com",
  "prompt": "select_account",
  "state": "nothingtoseehere"
}

図1:OAuthフィッシングURLのパラメータ

この URL は、ターゲット (この場合は MacOS テスト ユーザー) と共有されます。開くと、ユーザーが認証され、OAuth ワークフローが完了します。ブラウザの開発者ツールを使用して、リダイレクトURIで返された認証コード、つまり攻撃者が被害者に送り返すように求めたものを正確にキャプチャします。

コードを受け取った後、次の宛先にPOSTリクエストを発行します。

{token_url: "https://login.microsoftonline.com/organizations/oauth2/v2.0/token"}

この交換では、authorization_code グラントタイプを使用し、コード、クライアント ID、リダイレクト URI を渡します。Microsoft はアクセス トークンを返しますが、更新トークンは返しません。なぜなのかと疑問に思うかもしれません。

スコープ https://graph.microsoft.com/.defaultユーザーに代わって VSCode アプリに既に付与されているすべての Graph アクセス許可に対してベアラー トークンを発行するように Microsoft に指示します。これは静的スコープであり、アプリの登録から取得され、Mail.Read や offline_access などの動的スコープは含まれません。

Microsoftのドキュメントには次のように書かれています。

""クライアントは、静的 (.default) 同意と動的同意を 1 つの要求に組み合わせることはできません。""

したがって、 offline_access を .default と一緒に含めようとしますエラーになります。攻撃者がリフレッシュトークンを欲しがる場合は、 .default を避ける必要があります代わりに、 offline_access と必要な委任されたスコープ (Mail.Read など) を明示的に要求します – アプリの登録がそれらをサポートしていると仮定します。

アクセス トークンが手元にあったので、Microsoft Graph API と対話するための 2 番目のスクリプトにピボットしました。目標は、攻撃者と同じように、被害者のアカウントから電子メールメッセージを抽出することです。

これを行うために、アクセストークンをBearer JWTとして認証ヘッダーに含め、次のエンドポイントに対してGETリクエストを行いました。

{graph_url: "https://graph.microsoft.com/v1.0/me/messages"}

応答は、電子メール オブジェクトの JSON 配列を返します。ここからは、結果を反復処理し、送信者、件名、受信時間などの有用なメタデータを解析します。

トークンの広範な権限をテストするために、以下を使用してSharePointサイトを列挙することも試みました。

{graph_search_url: "https://graph.microsoft.com/v1.0/sites?search=*"}

リクエストはアクセス拒否エラーで失敗しました - これは、なぜ電子メールアクセスは機能したのにSharePointアクセスは機能しなかったのかという重要な質問につながります。その理由は、ファーストパーティクライアント(VSCode:aebc6443-996d-45c2-90f0-388ff96faa56)には、Microsoftが事前に定義したGraphforSharepointのデフォルトの委任権限がないためです。したがって、敵対者がアクセスできるものに制限があることがわかっています。

これが正確であることを確認するために、アクセス トークンをデコードして、VSCode に関連付けられている SCP を .default で識別しましたGraph へのアクセス許可 – サイトがないことを確認しています *Microsoftの許可を得ています。

これはVolexityが説明したバリエーションの1つですが、攻撃者の舞台裏のプロセス、およびMicrosoft Entra IDのリソース、OAuthなどについて理解を深めるのに役立ちます。

エミュレーションが完了したら、SIEM検出と脅威ハンティングに有効な忠実度の高い信号を特定することに移ります。ここでは、Microsoft Entra ID と Microsoft Graph ログの動作の観測値に焦点を当てています。

検知

シグナル 1 - Visual Studio Code クライアントとしての Microsoft Entra ID OAuth フィッシング

OAuth 2.0 (承認) と OpenID Connect (認証) のフローは、ファーストパーティの Microsoft アプリケーションである Visual Studio Code (VSCode) を使用して成功しました。このサインインは、フィッシングされたユーザー プリンシパルに代わって行われたため、Microsoft Graph へのアクセスが .default で委任されました権限。

event.dataset: "azure.signinlogs" and
event.action: "Sign-in activity" and
event.outcome: "success" and
azure.signinlogs.properties.user_type: "Member" and
azure.signinlogs.properties.authentication_processing_details: *Oauth* and
azure.signinlogs.category: "NonInteractiveUserSignInLogs" and
(
  azure.signinlogs.properties.resource_display_name: "Microsoft Graph" or
  azure.signinlogs.properties.resource_id: "00000003-0000-0000-c000-000000000000"
) and (
  azure.signinlogs.properties.app_id: "aebc6443-996d-45c2-90f0-388ff96faa56" or
  azure.signinlogs.properties.app_display_name: "Visual Studio Code"
)

シグナル 2 - Microsoft Entra セッションの再利用と疑わしいグラフ アクセス

KQL のような従来のクエリ言語は、個々のログ イベントのフィルター処理と視覚化には優れていますが、検出がデータセット、時間、識別子間で複数のレコードを関連付けることに依存している場合は困難です。これがES|QL(Elasticsearch Query Language)が必須になります。これらの種類のマルチイベント相関、時相論理、およびフィールド正規化は、KQL のような静的フィルターベースのクエリ言語では、複数のばらばらのクエリを記述し、事後に手動で関連付けることなしには困難または完全に不可能です。

この検出は、互いに近接して発生するが、異なるデータ ソース (サインイン ログと Microsoft Graph アクティビティ) から発生する複数のイベントの関連付けに依存しています。目標は、複数のIP間で同じセッションIDが再利用されている可能性があり、セッションのハイジャックやトークンの悪用を示している可能性があることを見つけることです。この資料に関するスペースの都合上、[検出ルール] セクションで実際の検出ルールを表示できます。クエリの流れと意味をよりよく説明するために、より高いレベルで示す図を次に示します。

[ FROM logs-azure.* ]
        |
        |  ← Pulls events from all relevant Microsoft Cloud datasets:
        |     - azure.signinlogs (authentication)
        |     - azure.graphactivitylogs (resource access)
        ↓
[ WHERE session_id IS NOT NULL AND IP NOT MICROSOFT ASN ]
        |
        |  ← Filters out Microsoft-owned infrastructure (e.g., internal proxy,
        |     Graph API relays) using ASN checks.
        |  ← Ensures session ID exists so events can be correlated together.
        ↓
[ EVAL session_id, event_type, time_window, etc. ]
        |
        |  ← Normalizes key fields across datasets:
        |     - session_id (from signin or Graph)
        |     - user ID, app ID, event type ("signin" or "graph")
        |  ← Buckets events into 5-minute windows using DATE_TRUNC()
        ↓
[ KEEP selected fields ]
        |
        |  ← Retains only what's needed:
        |     session_id, timestamp, IP, user, client ID, etc.
        ↓
[ STATS BY session_id + time_window ]
        |
        |  ← Groups by session and time window to compute:
        |     - unique IPs used
        |     - apps involved
        |     - first and last timestamps
        |     - whether both signin and graph occurred
        ↓
[ EVAL time_diff + signin_to_graph_delay ]
        |
        |  ← Calculates:
        |     - time_diff: full session duration
        |     - delay: gap between signin and Graph access
        ↓
[ WHERE types_count > 1 AND unique_ips > 1 AND delay <= 5 ]
        |
        |  ← Flags sessions where:
        |     - multiple event types (signin + graph)
        |     - multiple IPs used
        |     - all occurred within 5 minutes
        ↓
[ Output = Suspicious Session Reuse Detected ]

シグナル 3 - 疑わしいプロパティを含む Microsoft Entra ID の同時サインイン

この検出により、ユーザーが MFA を使用せずにデバイス コード フローを使用して認証を行う Microsoft Entra ID での疑わしいサインイン、または VSCode クライアントを使用したサインインが識別されます。同じ ID がいずれかの方法を使用して短い時間枠内に 2 つ以上の異なる IP からサインインすると、トークンのリプレイ、OAuth フィッシング、または中間者 (AitM) アクティビティを示している可能性があります。

[ FROM logs-azure.signinlogs* ]
        |
        |  ← Pulls only Microsoft Entra ID sign-in logs
        ↓
[ WHERE @timestamp > NOW() - 1h AND event.outcome == "success" ]
        |
        |  ← Filters to the last hour and keeps only successful sign-ins
        ↓
[ WHERE source.ip IS NOT NULL AND identity IS NOT NULL ]
        |
        |  ← Ensures the sign-in is tied to a user and IP for correlation
        ↓
[ KEEP fields: identity, app_id, auth_protocol, IP, etc. ]
        |
        |  ← Retains app/client, IP, auth method, and resource info
        ↓
[ EVAL detection flags ]
        |
        |  ← Labels events as:
        |     - device_code: if MFA not required
        |     - visual_studio: if VS Code client used
        |     - other: everything else
        ↓
[ STATS BY identity ]
        |
        |  ← Aggregates all sign-ins per user, calculates:
        |     - IP count
        |     - Device Code or VSCode usage
        |     - App/client/resource details
        ↓
[ WHERE src_ip >= 2 AND (device_code_count > 0 OR vsc > 0) ]
        |
        |  ← Flags users with:
        |     - Sign-ins from multiple IPs
        |     - And either:
        |         - Device Code w/o MFA
        |         - Visual Studio Code app
        ↓
[ Output = Potential OAuth Phishing or Token Misuse ]

このOAuthフィッシングのバリエーションは、リフレッシュトークンやPRTが提供する完全な永続性を欠いていますが、それでも攻撃者は正当なチャネルを通じて、電子メールなどの機密性の高いユーザーデータに1回限り貴重なアクセスを得ることができます。この演習は、静的な .default の制限と機能を理解するのに役立ちますスコープ、アプリの登録の影響、Microsoft Graph が認証後において極めて重要な役割を果たす方法。また、すべてのOAuthフィッシング攻撃が同じように作られているわけではないという、より広範な教訓も強化されます。リフレッシュトークンやデバイス登録を通じて(後述するように)長寿を目指すものもあれば、ファーストパーティクライアントを介した即時のデータ盗難に焦点を当てるものもあります。ニュアンスを理解することは、正確な検出ロジックに不可欠です。

シナリオ 2: デバイス登録のための OAuth フィッシング

先に述べたように、Volexityは、今回は仮想デバイスの登録とPRTの取得を目的として、被害者を標的とした別のフィッシングプレイブックも報告しました。このアプローチでは、敵対者からより多くの手順が必要になりますが、その見返りは、操作を完了するためのはるかに多くのユーティリティを提供するトークン付与トークンです。エミュレーションの取り組みでは、攻撃者が正確性を保つために行ったのと同様に、ツールセットを拡張してROADtoolsに依存する必要がありましたが、最初のフィッシングと侵害後のアクションのために、他のいくつかのPythonスクリプトが作成されました。

エミュレーション

最初のフィッシングから始めて、Pythonスクリプトを調整して、被害者に送信される別のOAuth URLを作成しました。今回は、ファーストパーティのクライアント ID が Microsoft Authentication Broker であることに焦点が当てられ、 offline_access で更新トークンを要求し、エンドポイント URI に参加する Entra ID のクラウド ドメイン デバイスにリダイレクトされました。

{
  "client_id": "29d9ed98-a469-4536-ade2-f981bc1d605e",
  "response_type": "code",
  "response_mode": "query",
  "redirect_uri": "https://login.microsoftonline.com/WebApp/CloudDomainJoin/8",
  "resource": "01cb2876-7ebd-4aa4-9cc9-d28bd4d359a9",
  "state": "nothingtoseehere"
}

成功し、被害者が認証されると、OAuth ワークフローは完了し、ユーザーは指定された URI にリダイレクトされ、クエリ パラメーターに認証コードが追加されます。繰り返しになりますが、このコードは重要な部分であり、トークンと交換するためには敵対者と共有する必要があります。私たちの場合、フィッシングURLが開かれ、ターゲットが認証されると、リダイレクトに埋め込まれた認証コードをキャプチャし、それを使用してMicrosoft Entra IDトークンエンドポイントからトークンをリクエストします。

さて、ここからが面白いところです。トークンリクエストに対して、アクセストークン、リフレッシュトークン、IDトークンの3種類のトークンを受け取ります。あなたは尋ねるかもしれません - なぜ私たちは単なるアクセストークン以上のものを取得するのですか?その答えは、最初にリクエストしたスコープ ( openidoffline_accessprofile) にあります。

  • openid は、OpenID Connect レイヤーの一部である ID トークンを付与し、ユーザーの ID を確認します — これが認証 (authN) アーティファクトです。
  • offline_access 更新トークンを提供し、再認証を必要とせずにセッションを維持し、新しいアクセストークンを要求することができます。これは永続的なアクセスをサポートしますが、ROADtxでの使用には重要です。
  • また、アクセス トークン自体は、Microsoft Graph などの保護された API への要求を承認するために使用され、これは承認 (authZ) を表します。

これら3つのトークンにより、認証、承認、および長期的なセッション継続性というすべてが得られます。これは、単純なOAuthフィッシングの手口から、Microsoft Entra IDに新しいデバイスを登録するような、より永続的な足場に移行するのに十分です。

それでは、点と点をつなぎましょう。PRTには、Entra IDがデバイス証明書と秘密鍵を介して認識する有効なデバイスの登録が必要です。そこで、ROADtxの出番です。最初の OAuth フィッシングは参加したデバイス フローを偽装し、使用されたクライアントは Microsoft Authentication Broker (Device Registration Service と対話するファーストパーティ クライアント) であったため、DRS と対話するための適切なアクセス トークンを既に手元に持っています。返されたオブジェクトでは、スコープが adrs_access であり、これは Azure DRS アクセスを示し、後で検出するために重要です。

ここから、トークン交換から受信したJSONオブジェクトを.roadtool_authにドロップするだけですファイル。このファイルはROADtoolsによってネイティブに消費され、保存されたトークンを使用してデバイス登録を実行し、敵対者の永続化への移行を完了し、有効なPRTを取得するための準備を整えます。

トークンを取得した後、JSONを再フォーマットしてROADtxの準備をします。ROADtx はキャメルケースのキーを想定しており、Microsoft Authentication Broker のクライアント ID も _clientId として含める必要があります。この設定により、 refreshtokento コマンドを実行でき、更新トークンを取得して、DRS をスコープとする新しい JWT (具体的には、サービス プリンシパル urn:ms-drs:enterpriseregistration.windows.net) と交換できます。

それが整ったら、device コマンドを使用して新しいデバイスの登録をシミュレートします。この操作は、Entra ID でエントリを作成するだけのバックエンド登録であるため、実際の仮想マシンや物理ホストは必要ありません。成功すると、有効なデバイス ID、PEM エンコードされた証明書、および秘密キーが発行されますが、これらはすべて、Microsoft エコシステムで有効なハイブリッド参加デバイスをシミュレートするために必要です。

デバイス ID が確立されたら、 prt コマンドを呼び出します。これは、更新トークン、デバイス証明書、および秘密キーを使用して、新しい PRT (Microsoft Entra ID でのユーザーとデバイスの信頼を効果的に結び付ける高い特権を持つ資格情報) を作成します。

そして、まさにそのように - whollah!— PRTがあります。

しかし、なぜこのようなことをするのでしょうか?アクセストークン、IDトークン、リフレッシュトークンがすでにあるのに、なぜデバイスを登録して証明書を生成し、PRTを取得するのですか?

PRT は、ユーザーとデバイスの完全な ID エミュレーションの鍵であるためです。Entra IDの世界では、Kerberosのようなチケット付与トークンと考えてください。しかし、そうではなく、トークン付与トークンです。有効なPRTの場合:

  • 攻撃者は、ユーザーの操作を必要とせずに、Outlook、SharePoint、Teamsなどのファーストパーティアプリに対して新しいアクセストークンとIDトークンをリクエストできます。
  • PRTは、複数のサービス間でシームレスなシングルサインオンSSOを可能にし、通常はユーザーに再度プロンプトを表示するMFAやその他の条件付きアクセスポリシー(CAP)を回避します。CAPとMFAは敵対者にとって大きな障壁となることが多いため、これは永続性にとって非常に重要です。
  • デバイス ID が信頼されている限り、PRT をサイレントに更新してセッション間で活用できるため、有効期間の長い永続化がサポートされています。

そしておそらく最も危険なのは、PRTにより、攻撃者は完全に準拠し、ドメインに参加しているデバイスとユーザーの組み合わせになりすますことができ、従来のほとんどの検出および応答制御を効果的に回避できるため、ハンターやアナリストにとって良性と疑わしいものの境界線が非常に薄くなることです。

これにより、PRT は非常に価値のある資産であり、秘密の横移動、特権昇格、Microsoft 365 サービスへの深いアクセスを可能にする資産になります。もはやただ入るだけでなく、気づかれないようにすることが大切です。

侵害後の活動を忘れないようにしましょう...

ROADtx は、敵対者が頻繁に使用するいくつかの強力なコマンド ( prtenrichbrowserprtauth) を提供します。たとえば、MicrosoftスイートのほとんどのブラウザベースのUIサービスには、認証と承認に必要なメタデータを含むPRTを提供することでアクセスできます。これはもともとフィッシングの被害者(私)に属していましたが、実際には彼らの代わりに行動するMicrosoft認証ブローカーです。

また、Volexityは、デバイスの登録とPRTの取得後、最初の被害者に2FAリクエストが送信され、承認され、SharePoint経由でメールにアクセスするために使用されたことも報告しています。リクエストがどのように行われたかは正確には特定されていませんが、敵対者がPRTを使用してファーストパーティのMicrosoftクライアントを介して認証したと考えるのが妥当であり、実際のデータアクセスはMicrosoft Graphを介して行われていました。Graph は、ほとんどの Microsoft 365 リソースの中央 API ハブとして機能するため、侵害後も人気のあるターゲットです。

まず、ROADtxを活用して、Microsoft Teamsがクライアントで、Microsoft GraphがリソースであるPRTで認証しましょう。PRTでprtauthコマンドを使用すると、新しいアクセストークンとリフレッシュトークンを取得でき、MicrosoftのIDファブリック内でのトークン付与トークンとしてのPRTの有用性を明確に示しています。

アクセストークンを取得したら、それをカスタムPythonスクリプトにプラグインして、SharePointサイト、ドライブ、アイテムの列挙を開始し、関心のあるファイルを特定してその内容をダウンロードできるようにします。

このエミュレーションでは、敵対者が Microsoft Authentication Broker を使用して OAuth フィッシングを連鎖させ、PRT を取得するために ROADtx を活用するために必要な資格情報マテリアルを取得する方法を示しました。このPRTは、機密ファイルへのアクセス、テナントリソースの列挙など、侵害後の重要なユーティリティです。

さて、焦点を変えましょう:この活動を検出するためのもっともらしく正確な信号は何ですか?

検知

シグナル 1 - Microsoft 認証ブローカーとしての Microsoft Entra ID OAuth フィッシング

ユーザー プリンシパルが、Microsoft Authentication Broker (MAB) をクライアントとして、Device Registration Service (DRS) をターゲット リソースとして使用して OAuth 承認コード フローを開始するインスタンスを識別します。この検出は、1つのセッションIDが短時間内に2つ以上の異なるIPアドレスで再利用され、少なくとも1つのリクエストがブラウザから発信された場合(一般的にフィッシングに関連する動作)に焦点を当てています。

[ FROM logs-azure.signinlogs-* ]
        |
        |  ← Pulls all Microsoft Entra ID sign-in logs
        ↓
[ WHERE app_id == MAB AND resource_id == DRS ]
        |
        |  ← Filters to OAuth auth code requests targeting
        |     Microsoft Authentication Broker + Device Reg Service
        ↓
[ EVAL session_id + is_browser ]
        |
        |  ← Extracts session ID and flags browser-based activity
        ↓
[ STATS BY 30-minute window, user, session_id ]
        |
        |  ← Groups logins within same session and time window,
        |     then aggregates:
        |       - user/session/token identifiers
        |       - distinct IPs and geo info
        |       - user agent, browser presence
        |       - app/resource/client info
        ↓
[ WHERE ip_count ≥ 2 AND session_id_count == 1 ]
        |
        |  ← Identifies reuse of a single session ID
        |     across ≥ 2 different IP addresses
        ↓
[ AND has_browser ≥ 1 AND auth_count ≥ 2 ]
        |
        |  ← Requires at least one browser-based request
        |     and at least two total sign-in events
        ↓
[ Output = Suspicious OAuth Flow with Auth Broker for DRS ]

シグナル 2 - Microsoft Auth Broker による疑わしい ADRS トークン要求

ユーザー プリンシパルが Microsoft Authentication Broker (MAB) クライアントに発行された更新トークンを使用して認証し、 adrs_access OAuth スコープを持つデバイス登録サービス (DRS) を対象とする Microsoft Entra ID サインイン イベントを識別します。このパターンは、最初の認証コードフィッシングまたはデバイス登録フローに続くDRSへのトークンベースのアクセスを示している可能性があります。

event.dataset: "azure.signinlogs" and azure.signinlogs.properties.app_id : "29d9ed98-a469-4536-ade2-f981bc1d605e" and azure.signinlogs.properties.resource_id : "01cb2876-7ebd-4aa4-9cc9-d28bd4d359a9" and azure.signinlogs.properties.authentication_processing_details.`Oauth Scope Info`: *adrs_access* and azure.signinlogs.properties.incoming_token_type: "refreshToken" and azure.signinlogs.properties.user_type: "Member"

シグナル 3 - Entra IDでの異常なデバイスの登録

OAuth フィッシングの後によく見られる、更新トークンを使用して、悪意のあるデバイス登録アクティビティの可能性があることを示す一連の Entra ID 監査ログ イベントを検出します。このパターンは、新しく登録された Windows デバイス (ハードコーディングされた OS バージョン 10.0.19041.928) がデバイス登録サービスによって追加され、その後にユーザーと所有者の割り当てが行われる ROADtx などのツールの動作を模倣しています。すべてのイベントは、同じ関連付け ID を共有し、1 分以内に発生する必要があり、正当なユーザー行動ではなく、自動化またはスクリプト駆動型の登録を強く示唆しています。

sequence by azure.correlation_id with maxspan=1m
[any where event.dataset == "azure.auditlogs" and azure.auditlogs.identity == "Device Registration Service" and azure.auditlogs.operation_name == "Add device" and azure.auditlogs.properties.additional_details.value like "Microsoft.OData.Client/*" and (
  azure.auditlogs.properties.target_resources.`0`.modified_properties.`1`.display_name == "CloudAccountEnabled" and 
azure.auditlogs.properties.target_resources.`0`.modified_properties.`1`.new_value: "[true]") and azure.auditlogs.properties.target_resources.`0`.modified_properties.`3`.new_value like "*10.0.19041.928*"]
[any where event.dataset == "azure.auditlogs" and azure.auditlogs.operation_name == "Add registered users to device" and azure.auditlogs.properties.target_resources.`0`.modified_properties.`2`.new_value like "*urn:ms-drs:enterpriseregistration.windows.net*"]
[any where event.dataset == "azure.auditlogs" and azure.auditlogs.operation_name == "Add registered owner to device"]

シグナル 3 - 同じユーザーおよびデバイスからの Entra ID RT から PRT への遷移

この検出は、Microsoft Entra ID ユーザーが最初に Microsoft Authentication Broker (MAB) に発行された更新トークンを使用して認証し、その後すぐに同じデバイスからのプライマリ更新トークン (PRT) を使用したときに識別されます。このシーケンスは、通常のユーザー行動ではまれであり、攻撃者がデバイスを正常に登録し、ROADtx などのツールを使用して永続的なアクセスにエスカレーションしたことを示している可能性があります。2 番目の手順でデバイス登録サービス (DRS) に関連付けられているアクティビティを除外することで、ルールは、他の Microsoft 365 サービスにアクセスするための PRT の登録後の使用に焦点を当てています。

この動作は、トークンベースの侵害と長期的なセッション エミュレーションを強く示唆しています (特に、デバイスの信頼がサイレントに確立されている場合)。このリフレッシュトークンからPRTへの移行をキャッチすることは、OAuthフィッシングの忠実度の高いシグナルと侵害後の永続性を明らかにするために重要です。

sequence by azure.signinlogs.properties.user_id, azure.signinlogs.properties.device_detail.device_id with maxspan=1d
  [authentication where 
    event.dataset == "azure.signinlogs" and
    azure.signinlogs.category == "NonInteractiveUserSignInLogs" and
    azure.signinlogs.properties.app_id == "29d9ed98-a469-4536-ade2-f981bc1d605e" and
    azure.signinlogs.properties.incoming_token_type == "refreshToken" and
    azure.signinlogs.properties.device_detail.trust_type == "Azure AD joined" and
    azure.signinlogs.properties.device_detail.device_id != null and
    azure.signinlogs.properties.token_protection_status_details.sign_in_session_status == "unbound" and
    azure.signinlogs.properties.user_type == "Member" and
    azure.signinlogs.result_signature == "SUCCESS"
  ]
  [authentication where 
    event.dataset == "azure.signinlogs" and
    azure.signinlogs.properties.incoming_token_type == "primaryRefreshToken" and
    azure.signinlogs.properties.resource_display_name != "Device Registration Service" and
    azure.signinlogs.result_signature == "SUCCESS"
  ]

シグナル 4 - 異常な PRT の使用とユーザー プリンシパルの登録デバイス

この検出は、Microsoft Entra ID のユーザーが過去 7 日以内に見たことのない新しいデバイスを登録したときに表面化します (これは、ROADtx ベースのデバイス登録に連鎖する OAuth フィッシング キャンペーンに関連することが多い動作です)。これらの攻撃では、攻撃者はユーザーを騙してDRSを標的とするMicrosoft Authentication Broker(MAB)のアクセスを承認させ、RTを取得した後、ROADtxを使用して偽のWindowsデバイスをサイレントに登録し、PRTを作成します。このルールは、ユーザー プリンシパルが新しく観察されたデバイス ID から認証した場合、特にセッションがバインドされていない場合 (トークンの再生やデバイスのスプーフィングの特徴) にアラートを出します。PRTには登録済みの信頼できるデバイスが必要なため、このシグナルは、敵対者が基本的なトークンの悪用から長期的な侵害に沿った永続的でステルスなアクセスに移行したタイミングを特定する上で重要な役割を果たします。

event.dataset: "azure.signinlogs" and
    event.category: "authentication" and
    azure.signinlogs.properties.user_type: "Member" and
    azure.signinlogs.properties.token_protection_status_details.sign_in_session_status: "unbound" and
    not azure.signinlogs.properties.device_detail.device_id: "" and
    azure.signinlogs.properties.user_principal_name: *

新しい用語 価値観:

  • azure.signinlogs.properties.user_principal_name
  • azure.signinlogs.properties.device_detail.device_id(デバイスID)

このエミュレーションは、同意を求めるフィッシングから、デバイスの信頼の確立、長期的な永続性のためのPRTの作成まで、攻撃者のワークフロー全体を検証するのに役立ちました。OAuthの悪用とデバイス登録を連鎖させることで、攻撃者はCAPを満たし、準拠したエンドポイントになりすまし、クラウド環境内を横方向に移動することができます。多くの場合、従来のセキュリティ制御をトリガーする必要はありません。

これらのニュアンスは重要です。単独で見ると、トークンの発行やデバイスの登録などの個々のイベントは無害に見えるかもしれません。しかし、サインイン ログ、監査データ、トークン メタデータを関連付けると、ID 侵害の明確な痕跡が明らかになります。

検出と不正使用に関する主要なテレメトリの詳細

エミュレーションと検出の取り組みを通じて、特定のテレメトリアーティファクトは、無害なOAuthアクティビティを悪意のある不正使用から分離するために一貫して不可欠であることが証明されました。これらのフィールドが Microsoft Entra ID ログにどのように表示されるか、および攻撃者がどのように操作するかを理解することは、効果的なハンティングと検出エンジニアリングにとって重要です。クライアント ID やグラント タイプから、デバイスのコンプライアンス、トークン タイプ、条件付きアクセスの結果まで、これらのシグナルは ID ベースの攻撃のストーリーを伝えます。以下に、最も重要なもののリストと、それらがどのように私たちを可能にするかをキュレーションしました。

クライアント アプリケーション ID (client_id): OAuth 要求を開始するアプリケーションを識別します。ファーストパーティクライアント(例:VSCode、Auth Broker)は、紛れ込むために悪用される可能性があります。サードパーティのクライアントは、悪意のあるクライアントやレビューされていない可能性があり、多くの場合、同意付与攻撃を表しています。主に、リスクの高いアプリや予期しないアプリの使用を特定するために使用されます。

Target Resource (resource_id / resource_display_name): アクセスされている MSFT サービスを定義します (例:MSFT Graph または Teams)。価値の高いターゲットには、Graph API、SharePoint、Outlook、Teams、ディレクトリサービスが含まれます。リソースのターゲット設定は、多くの場合、攻撃者の目標によってスコープされます。

プリンシパルの種類 (user_type): サインインがメンバー (ユーザー) またはサービス プリンシパルによるものかを示します。フィッシングキャンペーンは、ほとんどの場合、メンバーアカウントを標的にしています。これにより、検出ロジックでのフィルタリングが容易になりますが、ユーザープリンシパルの代わりに通常とは異なるファーストパーティクライアントリクエストをペアリングするのに役立ちます。

OAuth Grant Type (authentication_processing_details): トークンがどのように取得されたかを理解するための鍵 (認証コード、更新トークン、デバイス コード、クライアント資格情報など)。一方、更新トークンとデバイス コードの再利用は、侵害後の忠実度の高いシグナルです。

ジオロケーション:非定型のサインイン(例:珍しい国が見られる)または不可能な旅行(同じユーザーが短時間で遠く離れた場所から)。セッションIDと相関IDと組み合わせることで、トークンのハイジャック、IDの侵害後、またはラテラルムーブメントを明らかにすることができます。

デバイス メタデータ (device_detail、trust_type、compliance_state): デバイス ID、オペレーティング システム、信頼の種類、コンプライアンス、管理状態などが含まれます。デバイスの登録と PRT の発行は、このメタデータに関連付けられています。多くの場合、敵対者はCAPを満たし、永続的な信頼できるアクセスを取得することが目標です。

認証プロトコルと種類 (authentication_protocol / incoming_token_type): セッションが OAuth ベースであったか、MFA が使用されたかを示します。受信するトークン ソースは、この要求に使用されるトークン ソースで、authN または authZ を提供するものです。トークンの再利用、非対話型サインインの検出に役立ちます。

認証マテリアルとセッションコンテキスト:使用されるトークンは、受信トークンタイプ、トークン保護ステータス、およびセッションIDから推測できます。セッションの再利用、長時間のセッション、または複数のIPが1つのセッションに関連付けられている場合は、多くの場合、不正使用を示しています。

条件付きアクセスポリシーのステータス:トークンの発行時に評価されますが、アクセスが許可されたかどうかに大きく影響します。これにより、CAPの回避、予期しない政策結果、またはリスクの要因を特定するのに役立ちます。

スコープと同意動作: 要求されたスコープは、サインイン ログにキャプチャされた SCP または OAuth パラメーターに表示されます。不正使用の指標には、 offline_access.defaultまたは、Mail.ReadWrite のような広範なスコープ。同意テレメトリは、ユーザーが疑わしいアプリケーションを承認したかどうかをピボットまたは関連付けるのに役立ちます。

まとめ

Microsoft Entra ID の OAuth 実装は、強力でシームレスな認証エクスペリエンスを実現するだけでなく、攻撃者が信頼、セッション永続性、デバイス登録攻撃パスを悪用する新たな機会を露呈するという諸刃の剣を提示します。

Volexityが観測したOAuthフィッシング手法を再現することで、私たちのチームは、攻撃者が正規のMicrosoftアプリケーション、トークンフロー、オープンソースツールを悪用して機密データに密かにアクセスしている方法を検証することができました。私たちは、この作業を実践的なエミュレーションを通じて拡張し、OAuthのフィッシングとワークフロー、セキュリティトークンのメタデータと取得の仕組みを深く掘り下げ、防御者が検出できる行動指標を表面化させました。

この調査結果は、OAuthの不正使用がマルウェアやコードの実行に依存しないという重要な点を補強しています。ID、同意、トークンの再利用を武器にすることで、従来のセキュリティ制御が困難になり、ログベースの検出、相関、行動分析が非常に重要である理由を説明します。

ここで共有されているエミュレーションアーティファクト、検出ルール、およびレッスンが、コミュニティ全体の防御者がこの進化するクラウドベースのID脅威をよりよく理解し、検出/追跡するのに役立つことを願っています。

Elasticをご利用の場合は、このブログで説明したすべての検出ルールをオープンソース化していますので、すぐに始めていただけます。また、別のSIEMで狩猟をしている場合は、ロジックを適応させ、それに応じて環境に適応することをお勧めします。

アイデンティティは新たな境界であり、私たちはそれをそのように扱う時が来ました。安全で幸せな狩猟をお楽しみください!

検出ルール

参照:

この記事を共有する