Skip to content

Business Email Compromise (BEC) & Phishing Triage Playbook

Standard Operating Procedure for handling suspected Microsoft 365 / Exchange Online account takeover and Business Email Compromise (BEC).


⏱️ Phase 1: Immediate Containment (< 15 Minutes)

Section titled “⏱️ Phase 1: Immediate Containment (< 15 Minutes)”

When an account is flagged as compromised, execute immediate containment steps:

1. Revoke Active Refresh Tokens & Reset Password

Section titled “1. Revoke Active Refresh Tokens & Reset Password”
Terminal window
# Connect to Microsoft Graph
Connect-MgGraph -Scopes "User.ReadWrite.All"
$targetUser = "victim.user@company.com"
# 1. Invalidate all active session tokens immediately
Revoke-MgUserSignInSession -UserId $targetUser
# 2. Force password change on next login
Update-MgUser -UserId $targetUser -PasswordProfile @{
ForceChangePasswordNextSignIn = $true
Password = "TemporaryGeneratedStrongPassword123!"
}

2. Check and Block Malicious Sign-In Risk in Entra ID

Section titled “2. Check and Block Malicious Sign-In Risk in Entra ID”

Verify if MFA was modified or if additional FIDO2/phone methods were registered by the attacker:

Terminal window
Get-MgUserAuthenticationMethod -UserId $targetUser | Select-Object Id, @{N='Type';E={$_.'@odata.type'}}

Adversaries establish covert persistence inside mailboxes to intercept invoices, monitor threads, and delete alerts.

1. Audit Inbox Rules & External Forwarders

Section titled “1. Audit Inbox Rules & External Forwarders”
Terminal window
# Connect-ExchangeOnline
$mailbox = "victim.user@company.com"
# Check Transport / Mailbox level forwarding
Get-Mailbox -Identity $mailbox | Select-Object UserPrincipalName, ForwardingAddress, ForwardingSmtpAddress, DeliverToMailboxAndForward
# Audit all custom inbox rules (look for rules moving to RSS, Junk, or external addresses)
Get-InboxRule -Mailbox $mailbox | Select-Object Name, Enabled, Priority, ForwardTo, RedirectTo, MoveToFolder, DeleteMessage | Format-List

2. Audit Mailbox Folder Permissions & Delegates

Section titled “2. Audit Mailbox Folder Permissions & Delegates”

Adversaries often grant SendAs, SendOnBehalf, or FullAccess to another compromised tenant account.

Terminal window
# Check Full Access Delegates
Get-MailboxPermission -Identity $mailbox | Where-Object { $_.User -notmatch 'NT AUTHORITY' } | Format-Table -AutoSize
# Check Send As Rights
Get-RecipientPermission -Identity $mailbox | Where-Object { $_.Trustee -notmatch 'NT AUTHORITY' } | Format-Table -AutoSize

Section titled “📱 Phase 3: Malicious OAuth Enterprise App Consent (Illicit Consent Grants)”

Attackers trick users into granting permissions (e.g. Mail.ReadWrite, Offline_Access) to an external rogue Azure App Registration, allowing API access without needing passwords or MFA.

KQL Query: Hunt for Recent User App Consents

Section titled “KQL Query: Hunt for Recent User App Consents”
AuditLogs
| where TimeGenerated > ago(7d)
| where OperationName in~ ("Consent to application", "Add delegated permission grant", "Add service principal")
| extend ConsentingUser = tostring(InitiatedBy.user.userPrincipalName)
| extend TargetApp = tostring(TargetResources[0].displayName)
| extend PermissionsGranted = tostring(TargetResources[0].modifiedProperties[4].newValue)
| project TimeGenerated, OperationName, ConsentingUser, TargetApp, PermissionsGranted, Result
| sort by TimeGenerated desc
Terminal window
# Remove malicious app consent grant via Microsoft Graph
Remove-MgOauth2PermissionGrant -OAuth2PermissionGrantId "<OAuth2PermissionGrantId>"

📊 Phase 4: Impact Analysis & Data Exposure

Section titled “📊 Phase 4: Impact Analysis & Data Exposure”

Determine what emails the attacker accessed, read, or sent.

1. Identify Emails Sent by Attacker (Search-UnifiedAuditLog)

Section titled “1. Identify Emails Sent by Attacker (Search-UnifiedAuditLog)”
Terminal window
Search-UnifiedAuditLog -RecordType ExchangeItem -Operations Send, SendAs -FreeText $targetUser -StartDate (Get-Date).AddDays(-3) -EndDate (Get-Date)

If your tenant possesses Purview Audit (Premium), query MailItemsAccessed in Log Analytics to identify specific message IDs read or synced via Bind / Sync actions.

CloudAppEvents
| where TimeGenerated > ago(7d)
| where ActionType == "MailItemsAccessed"
| where RawEventData.UserId =~ "victim.user@company.com"
| extend MailAccessType = tostring(RawEventData.OperationProperties[0].Value)
| extend FoldersAccessed = RawEventData.Folders
| project TimeGenerated, AccountDisplayName, IPAddress, MailAccessType, FoldersAccessed

🛡️ Phase 5: Post-Incident Hardening Checklist

Section titled “🛡️ Phase 5: Post-Incident Hardening Checklist”
  • Clear all unauthorized Inbox and Forwarding rules.
  • Remove rogue OAuth permission grants.
  • Audit MFA methods and re-register authenticators.
  • Notify finance/payroll if payroll changes or invoice details were discussed in affected threads.
  • Submit phishing message samples to Defender for Office 365 for tenant-wide blocklisting.