Walk through a complete BEC incident investigation using Threat Explorer, analyse email flows and compromised mailbox rules, identify impacted recipients, contain the threat, deploy email authentication (SPF/DKIM/DMARC), implement Conditional Access, and build a reusable BEC response playbook.
Business Email Compromise (BEC) is a sophisticated attack where an adversary compromises or impersonates a legitimate business email account to conduct fraudulent wire transfers, redirect payments, or steal sensitive data. This lab simulates a real-world BEC scenario: an executive’s account is compromised via credential phishing, the attacker creates inbox forwarding rules, and sends fraudulent wire transfer requests to the finance team.
You will use Threat Explorer, message trace, sign-in logs, and unified audit log to reconstruct the full attack timeline from initial phishing email to account compromise to fraudulent activity. The lab covers the complete incident lifecycle: detection, investigation, containment, eradication, recovery, and post-incident improvements.
Contoso’s SOC receives a high-severity alert: “Suspicious inbox forwarding rule detected” on the CFO’s mailbox. All emails are being forwarded to an external Gmail address. Initial investigation reveals three fraudulent wire transfer request emails sent from the CFO’s account to the Accounts Payable team in the past 48 hours. One wire transfer of $185,000 was executed by AP before the alert fired.
The bank must be notified within 24 hours for potential recovery. The security team must simultaneously contain the compromise, investigate the full scope, notify affected parties, preserve evidence, and implement controls to prevent recurrence.
FBI IC3 reported $2.9 billion in BEC losses. more than ransomware, data breaches, and all other categories combined. Wire transfer recovery success drops from 75% to below 20% after 48 hours. rapid investigation and containment directly saves money.
BEC investigation requires cross-domain skills spanning email security, identity, and financial fraud. few SOC analysts have all three. Compromised executive email may expose PII, financial data, or privileged communications, triggering breach notification requirements under GDPR, CCPA, and industry regulations.
A high-severity alert fires: “Suspicious email forwarding rule detected”. Immediately assess the scope and urgency:
# WHAT: Immediately check a compromised mailbox for attacker-created forwarding rules and redirects
# WHY: BEC attackers create inbox rules to forward all incoming mail to an external address (e.g., Gmail)
# so they can monitor responses to their fraudulent requests. They also set mailbox-level forwarding
# and may delete the rule after setup to avoid detection. This is the FIRST check during BEC triage.
# OUTPUT: Three sections:
# 1. Inbox Rules: Any rule that forwards, redirects, or auto-deletes mail (attacker hiding evidence)
# 2. Mailbox Forwarding: SMTP-level forwarding set on the mailbox object itself
# 3. OAuth Permissions: Third-party apps granted mail access (consent phishing / illicit consent grant)
# CRITICAL: If ANY forwarding is found, remove it IMMEDIATELY before proceeding with investigation.
Connect-ExchangeOnline
$compromisedUser = "cfo@contoso.com"
# Check inbox rules - look for ForwardTo, RedirectTo, or DeleteMessage (used to hide attacker traces)
Write-Host "=== Inbox Rules ===" -ForegroundColor Red
Get-InboxRule -Mailbox $compromisedUser | Where-Object {
$_.ForwardTo -or $_.ForwardAsAttachmentTo -or $_.RedirectTo -or $_.DeleteMessage
} | Select-Object Name, Description, ForwardTo, RedirectTo,
DeleteMessage, Enabled | Format-List
# Check mailbox-level forwarding (set via Set-Mailbox, not visible as an inbox rule)
# ForwardingSmtpAddress is commonly used by attackers because it doesn't require mail contacts
Write-Host "=== Mailbox Forwarding ===" -ForegroundColor Red
Get-Mailbox -Identity $compromisedUser |
Select-Object ForwardingAddress, ForwardingSmtpAddress,
DeliverToMailboxAndForward | Format-List
# Check for OAuth apps with delegated mail permissions (consent phishing attack vector)
Write-Host "=== OAuth App Consents ===" -ForegroundColor Red
Get-MailboxPermission -Identity $compromisedUser |
Where-Object { $_.User -ne "NT AUTHORITY\SELF" } | Format-Table -AutoSizePerform containment actions in rapid sequence. Do NOT just change the password. you must also revoke existing tokens:
# WHAT: Execute immediate containment actions for a compromised BEC account (6-step rapid response)
# WHY: Every minute the attacker has access, they can send more fraudulent emails, read confidential
# data, and modify mail rules. This script removes forwarding, resets credentials, revokes all
# active tokens (OAuth + refresh), and temporarily blocks sign-in to stop the attacker cold.
# ORDER OF OPERATIONS:
# 1. Remove forwarding rules FIRST (stops data exfiltration immediately)
# 2. Remove mailbox-level forwarding
# 3. Reset password with random complex value (invalidates stolen credentials)
# 4. Revoke ALL active sessions and tokens (forces attacker re-authentication which will fail)
# 5. Verify/enforce MFA (prevents re-compromise using the same stolen password)
# 6. Temporarily disable account (belt-and-suspenders while investigation proceeds)
# OUTPUT: Green confirmation for each step. Account is fully locked down after script completes.
# WARNING: Disabling an executive account may impact business operations - coordinate with their EA.
$compromisedUser = "cfo@contoso.com"
# 1. Remove all malicious forwarding rules (stops exfiltration of new incoming mail)
Write-Host "1. Removing forwarding rules..." -ForegroundColor Yellow
Get-InboxRule -Mailbox $compromisedUser | Where-Object {
$_.ForwardTo -or $_.ForwardAsAttachmentTo -or $_.RedirectTo
} | Remove-InboxRule -Confirm:$false
Write-Host " Forwarding rules removed" -ForegroundColor Green
# 2. Remove mailbox-level forwarding (ForwardingSmtpAddress is the most common BEC vector)
Set-Mailbox -Identity $compromisedUser `
-ForwardingAddress $null `
-ForwardingSmtpAddress $null `
-DeliverToMailboxAndForward $false
Write-Host "2. Mailbox forwarding disabled" -ForegroundColor Green
# 3. Reset password - use a cryptographically random 16-char password with 4 special characters
# ForceChangePasswordNextSignIn ensures the legitimate user sets a new password when re-enabled
Connect-MgGraph -Scopes "User.ReadWrite.All"
Update-MgUser -UserId $compromisedUser -PasswordProfile @{
ForceChangePasswordNextSignIn = $true
Password = [System.Web.Security.Membership]::GeneratePassword(16, 4)
}
Write-Host "3. Password reset" -ForegroundColor Green
# 4. Revoke ALL active sessions - invalidates refresh tokens, OAuth tokens, and browser sessions
# Without this step, the attacker’s existing session remains valid even after password change
Revoke-MgUserSignInSession -UserId $compromisedUser
Write-Host "4. All sessions revoked" -ForegroundColor Green
# 5. Verify MFA is enabled (if not, the attacker can re-compromise with a new phish)
Write-Host "5. Verify MFA status in Entra admin center" -ForegroundColor Yellow
# 6. Temporarily disable the account to prevent any access during investigation
Update-MgUser -UserId $compromisedUser -AccountEnabled:$false
Write-Host "6. Account temporarily disabled for investigation" -ForegroundColor Green
Write-Host "`nCONTAINMENT COMPLETE. Account secured" -ForegroundColor CyanUse Threat Explorer, sign-in logs, and the unified audit log to build a complete attack timeline:
# Search for the initial phishing email delivered to the CFO
Connect-ExchangeOnline
$compromisedUser = "cfo@contoso.com"
$lookbackDays = 14
# Search message trace for inbound emails to CFO
$messages = Get-MessageTrace -RecipientAddress $compromisedUser `
-StartDate (Get-Date).AddDays(-$lookbackDays) -EndDate (Get-Date) |
Where-Object { $_.Status -eq "Delivered" }
Write-Host "Messages delivered to $compromisedUser (last $lookbackDays days): $($messages.Count)"
$messages | Select-Object Received, SenderAddress, Subject, Status |
Sort-Object Received | Format-Table -AutoSize
# Search unified audit log for inbox rule creation
$auditLogs = Search-UnifiedAuditLog -StartDate (Get-Date).AddDays(-30) `
-EndDate (Get-Date) -UserIds $compromisedUser `
-Operations "New-InboxRule","Set-InboxRule","Set-Mailbox" `
-ResultSize 100
Write-Host "`n=== Inbox Rule Operations ===" -ForegroundColor Yellow
$auditLogs | ForEach-Object {
$data = $_.AuditData | ConvertFrom-Json
Write-Host "$($data.CreationTime) | $($data.Operation) | IP: $($data.ClientIP)"
}
# Search for fraudulent sent emails
$sentMessages = Get-MessageTrace -SenderAddress $compromisedUser `
-StartDate (Get-Date).AddDays(-7) -EndDate (Get-Date)
Write-Host "`n=== Emails Sent from Compromised Account ===" -ForegroundColor Yellow
$sentMessages | Select-Object Received, RecipientAddress, Subject |
Sort-Object Received | Format-Table -AutoSizeReview Microsoft Entra sign-in logs to identify the attacker’s access patterns:
# Analyse sign-in logs for the compromised account
Connect-MgGraph -Scopes "AuditLog.Read.All"
$compromisedUser = "cfo@contoso.com"
$signIns = Get-MgAuditLogSignIn -Filter "userPrincipalName eq '$compromisedUser'" `
-Top 100 | Sort-Object CreatedDateTime
Write-Host "=== Sign-In Analysis for $compromisedUser ===" -ForegroundColor Cyan
$signIns | Select-Object CreatedDateTime,
@{N='IP';E={$_.IPAddress}},
@{N='Location';E={"$($_.Location.City), $($_.Location.CountryOrRegion)"}},
@{N='App';E={$_.AppDisplayName}},
@{N='Status';E={$_.Status.ErrorCode}},
@{N='Risk';E={$_.RiskLevelDuringSignIn}} |
Format-Table -AutoSize
# Identify suspicious sign-ins (unusual locations/IPs)
$suspiciousSignIns = $signIns | Where-Object {
$_.RiskLevelDuringSignIn -in @("medium","high") -or
$_.Location.CountryOrRegion -notin @("US","United States")
}
if ($suspiciousSignIns) {
Write-Host "`nSUSPICIOUS SIGN-INS DETECTED:" -ForegroundColor Red
$suspiciousSignIns | Select-Object CreatedDateTime, IPAddress,
@{N='Location';E={"$($_.Location.City), $($_.Location.CountryOrRegion)"}},
@{N='Risk';E={$_.RiskLevelDuringSignIn}} | Format-Table -AutoSize
}Identify all recipients of fraudulent emails. For each recipient, determine: did they see the message, did they take action, and was any money transferred?
# Identify all recipients of emails sent during the compromise window
$compromisedUser = "cfo@contoso.com"
$compromiseStart = (Get-Date).AddDays(-7) # Adjust based on investigation
$fraudulentEmails = Get-MessageTrace -SenderAddress $compromisedUser `
-StartDate $compromiseStart -EndDate (Get-Date) |
Where-Object { $_.RecipientAddress -ne $compromisedUser }
Write-Host "=== IMPACTED RECIPIENTS ===" -ForegroundColor Red
Write-Host "Emails sent from compromised account during breach window:"
$fraudulentEmails | Group-Object RecipientAddress |
Select-Object @{N='Recipient';E={$_.Name}}, Count |
Sort-Object Count -Descending | Format-Table -AutoSize
Write-Host "`nSubjects of sent emails:" -ForegroundColor Yellow
$fraudulentEmails | Select-Object Received, RecipientAddress, Subject |
Sort-Object Received | Format-Table -AutoSizeFor the initial phishing email that compromised the CFO’s credentials, analyse the email headers to extract indicators of compromise:
Submit all IOCs to your threat intelligence platform and to Microsoft via Admin Submissions:
# Use the Message Header Analyzer or parse headers manually
# Extract key IOCs from the phishing email
$iocs = @{
"Sending IP" = "203.0.113.42"
"Sender Domain" = "contoso-secure.com"
"Phishing URL" = "https://contoso-secure.com/login"
"Reply-To" = "attacker@gmail.com"
"User-Agent" = "Mozilla/5.0 (attacker browser string)"
"Attacker Sign-In" = "198.51.100.15"
}
Write-Host "=== INDICATORS OF COMPROMISE ===" -ForegroundColor Red
$iocs.GetEnumerator() | Format-Table -AutoSize
# Block the phishing URL and sender domain
Write-Host "`nBlocking IOCs in Tenant Allow/Block List..." -ForegroundColor Yellow
New-TenantAllowBlockListItems -ListType Url `
-Entries "contoso-secure.com/*" -Block -NoExpiration
New-TenantAllowBlockListItems -ListType Sender `
-Entries "contoso-secure.com" -Block -NoExpiration
Write-Host "IOCs blocked successfully" -ForegroundColor GreenSearch for signs that other accounts were targeted by the same campaign:
# WHAT: Hunt across ALL mailboxes for suspicious auto-forwarding rules targeting external domains
# WHY: If one executive was compromised, the attacker may have targeted others in the same campaign.
# This script checks EVERY mailbox for rules forwarding to external providers (Gmail, Yahoo, etc.)
# which are almost never legitimate for corporate email.
# OUTPUT: Table of suspicious rules found, with mailbox, rule name, forward destination, and status.
# If Count > 0, each result should be investigated as a potential additional BEC compromise.
# Also checks if the same phishing domain targeted other users via message trace.
Write-Host "=== HUNTING: Suspicious Forwarding Rules ===" -ForegroundColor Cyan
$allMailboxes = Get-Mailbox -RecipientTypeDetails UserMailbox -ResultSize Unlimited
$suspiciousRules = @()
foreach ($mbx in $allMailboxes) {
# Check each mailbox for rules forwarding to common external email providers
# Pattern: smtp: prefix indicates external SMTP forwarding; gmail/yahoo/outlook = attacker drop accounts
$rules = Get-InboxRule -Mailbox $mbx.PrimarySmtpAddress -ErrorAction SilentlyContinue |
Where-Object {
($_.ForwardTo -and $_.ForwardTo -match "smtp:|gmail|yahoo|outlook") -or
($_.RedirectTo -and $_.RedirectTo -match "smtp:|gmail|yahoo|outlook") -or
($_.ForwardAsAttachmentTo -and $_.ForwardAsAttachmentTo -match "smtp:|gmail|yahoo|outlook")
}
if ($rules) {
foreach ($rule in $rules) {
$suspiciousRules += [PSCustomObject]@{
Mailbox = $mbx.PrimarySmtpAddress
RuleName = $rule.Name
ForwardTo = $rule.ForwardTo
RedirectTo = $rule.RedirectTo
Enabled = $rule.Enabled
}
}
}
}
if ($suspiciousRules.Count -gt 0) {
Write-Host "ALERT: $($suspiciousRules.Count) suspicious rule(s) found!" -ForegroundColor Red
$suspiciousRules | Format-Table -AutoSize
} else {
Write-Host "No additional suspicious forwarding rules found" -ForegroundColor Green
}
# Check if the same phishing domain was used to target other users in the organization
$phishDomain = "contoso-secure.com"
$otherTargets = Get-MessageTrace -SenderAddress "*@$phishDomain" `
-StartDate (Get-Date).AddDays(-14) -EndDate (Get-Date)
Write-Host "`nOther users targeted by $phishDomain :" -ForegroundColor Yellow
$otherTargets | Select-Object RecipientAddress, Subject, Status |
Format-Table -AutoSizeCreate a forensic evidence package for potential law enforcement referral and legal proceedings:
# WHAT: Export a complete forensic evidence package for the BEC incident
# WHY: BEC investigations often lead to law enforcement referral (FBI IC3), insurance claims,
# and legal proceedings. Evidence must be preserved in its original form with timestamps.
# This script exports audit logs, sent messages, and received messages as CSV files.
# OUTPUT: Three CSV files saved to a dated evidence folder:
# - AuditLog.csv: All actions taken on/by the compromised account (rule creation, logons, mail reads)
# - SentMessages.csv: All emails sent FROM the compromised account during the breach window
# - ReceivedMessages.csv: All emails received BY the compromised account (includes phishing email)
# RETENTION: Preserve these files for at least 1 year. Store in a read-only, access-controlled location.
$compromisedUser = "cfo@contoso.com"
$evidencePath = "C:\BEC-Evidence\$(Get-Date -Format 'yyyyMMdd')"
New-Item -ItemType Directory -Path $evidencePath -Force | Out-Null
# Export unified audit log - captures ALL user and admin activity for the account
# Operations include: New-InboxRule, Set-Mailbox, MailItemsAccessed, Send, etc.
$auditLog = Search-UnifiedAuditLog -StartDate (Get-Date).AddDays(-30) `
-EndDate (Get-Date) -UserIds $compromisedUser -ResultSize 5000
$auditLog | Export-Csv "$evidencePath\AuditLog.csv" -NoTypeInformation
Write-Host "Audit log exported: $($auditLog.Count) records" -ForegroundColor Green
# Export messages SENT from the compromised account (includes fraudulent wire transfer requests)
$messages = Get-MessageTrace -SenderAddress $compromisedUser `
-StartDate (Get-Date).AddDays(-14) -EndDate (Get-Date)
$messages | Export-Csv "$evidencePath\SentMessages.csv" -NoTypeInformation
Write-Host "Sent messages exported: $($messages.Count) records" -ForegroundColor Green
# Export messages RECEIVED by the compromised account (includes the initial phishing email)
$inbound = Get-MessageTrace -RecipientAddress $compromisedUser `
-StartDate (Get-Date).AddDays(-14) -EndDate (Get-Date)
$inbound | Export-Csv "$evidencePath\ReceivedMessages.csv" -NoTypeInformation
Write-Host "Received messages exported: $($inbound.Count) records" -ForegroundColor Green
Write-Host "`nEvidence package saved to: $evidencePath" -ForegroundColor CyanStrengthen domain authentication to prevent future spoofing attacks. Implement all three email authentication standards:
-all (hard fail) for maximum protectionp=none and rua reporting to identify all legitimate senders, then progress to p=quarantine and finally p=reject# SPF Record (add to DNS as TXT record for contoso.com)
v=spf1 include:spf.protection.outlook.com -all
# DKIM CNAME Records (add to DNS)
# selector1._domainkey.contoso.com CNAME selector1-contoso-com._domainkey.contoso.onmicrosoft.com
# selector2._domainkey.contoso.com CNAME selector2-contoso-com._domainkey.contoso.onmicrosoft.com
# DMARC Record. Phase 1: Monitor only
_dmarc.contoso.com TXT "v=DMARC1; p=none; rua=mailto:dmarc-reports@contoso.com; ruf=mailto:dmarc-forensics@contoso.com"
# DMARC Record. Phase 2: Quarantine (after 30 days of monitoring)
# _dmarc.contoso.com TXT "v=DMARC1; p=quarantine; pct=100; rua=mailto:dmarc-reports@contoso.com"
# DMARC Record. Phase 3: Reject (after confirming all legitimate senders)
# _dmarc.contoso.com TXT "v=DMARC1; p=reject; pct=100; rua=mailto:dmarc-reports@contoso.com"# WHAT: Enable DKIM (DomainKeys Identified Mail) signing in Exchange Online and verify DNS records
# WHY: DKIM cryptographically signs outbound email so receiving mail servers can verify the message
# was actually sent by your domain and wasn't modified in transit. Combined with SPF and DMARC,
# this prevents attackers from spoofing your domain in BEC attacks against your partners/clients.
# OUTPUT:
# - DKIM signing config status (Enabled/Disabled)
# - CNAME record values needed for DNS configuration
# - SPF and DMARC record verification from DNS
# PREREQUISITE: CNAME records must be published in DNS BEFORE enabling DKIM signing.
# selector1._domainkey.contoso.com -> selector1-contoso-com._domainkey.contoso.onmicrosoft.com
# selector2._domainkey.contoso.com -> selector2-contoso-com._domainkey.contoso.onmicrosoft.com
Connect-ExchangeOnline
# Enable DKIM signing for your domain (requires CNAME records already in DNS)
New-DkimSigningConfig -DomainName "contoso.com" -Enabled $true
# Verify DKIM configuration - Status should be "Valid" and Enabled should be "True"
Get-DkimSigningConfig -Identity "contoso.com" |
Select-Object Domain, Enabled, Status, Selector1CNAME, Selector2CNAME |
Format-List
# Verify SPF and DMARC records are properly published in DNS
# SPF should contain "include:spf.protection.outlook.com" and end with "-all" (hard fail)
# DMARC should have a policy (p=none for monitoring, p=quarantine or p=reject for enforcement)
Resolve-DnsName -Name "contoso.com" -Type TXT | Where-Object { $_.Strings -match "spf|dmarc" }
Resolve-DnsName -Name "_dmarc.contoso.com" -Type TXTDeploy Conditional Access policies to prevent similar compromises. Create targeted policies for high-value accounts:
Configure these in the Microsoft Entra admin center → Protection → Conditional Access. Test with a pilot group before applying to all executives.
Create proactive detection rules to catch BEC attempts early:
# WHAT: Create a transport rule to block all automatic email forwarding to external domains
# WHY: External auto-forwarding is the #1 BEC persistence mechanism. Attackers create inbox rules
# or set mailbox-level forwarding to exfiltrate all incoming mail. This transport rule blocks
# ALL auto-forwarding from internal to external recipients organization-wide.
# OUTPUT: Transport rule created. Any auto-forward to external recipients will be rejected with
# a bounce message explaining the security policy. Exceptions can be added for legitimate
# business needs (e.g., secops mailbox for security analysis).
# NOTE: MessageTypeMatches AutoForward catches both inbox rule forwards and mailbox-level SMTP forwards.
# This does NOT block manual forwarding by users - only automated/rule-based forwarding.
New-TransportRule -Name "Block External Auto-Forward" `
-FromScope InOrganization `
-SentToScope NotInOrganization `
-MessageTypeMatches AutoForward `
-RejectMessageReasonText "External auto-forwarding is blocked per security policy. Contact IT Security if you need an exception." `
-ExceptIfFrom "secops@contoso.com"
Write-Host "Transport rule created: Block External Auto-Forward" -ForegroundColor Green
# WHAT: Alert policies to configure in the Defender portal for proactive BEC monitoring
# WHY: These alerts catch BEC indicators before financial damage occurs.
# Configure at: Policies > Alert policy > Create new alert
Write-Host "`nConfigure these alert policies in the Defender portal:" -ForegroundColor Yellow
Write-Host " 1. New-InboxRule with ForwardTo on Priority Accounts" # Catches attacker rule creation
Write-Host " 2. Set-Mailbox with ForwardingSmtpAddress changes" # Catches mailbox-level forwarding
Write-Host " 3. Unusual volume of sent emails from Priority Accounts" # Catches mass fraudulent emailsDocument the entire investigation as a reusable BEC response playbook. This ensures consistent, rapid response to future incidents:
Decision trees for escalation:
p=none to p=reject over 60-90 days| Resource | Description |
|---|---|
| Detect and remediate illicit consent grants | Investigate OAuth-based BEC attacks |
| Threat Explorer and Real-time detections | Investigate email threats and compromised mailboxes |
| Message trace in the Defender portal | Track email flow and identify suspicious messages |
| Automated investigation and response (AIR) | Automatic investigation and remediation of email threats |
| Microsoft Entra ID Protection | Detect and remediate identity-based risks |
| Email authentication in Microsoft 365 | SPF, DKIM, and DMARC configuration |
| Conditional Access overview | Deploy identity-based access controls |
| Admin submissions | Report false positives/negatives to Microsoft |