13.10 Detection Engineering
4-6 hours · Module 13
Detection Engineering
Convert the BEC investigation findings into permanent analytics rules. These 6 rules detect the BEC kill chain stages identified in subsection 13.1.
Required role: Microsoft Sentinel Contributor.
Rule 1: Inbox Rule with Financial Keyword Targeting
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| // Scheduled Rule: Inbox rule targeting financial keywords
// Schedule: 5 minutes / Lookback: 10 minutes
// Severity: High
// MITRE: T1114.003 (Email Forwarding Rule)
CloudAppEvents
| where ActionType in ("New-InboxRule", "Set-InboxRule")
| extend RuleData = parse_json(RawEventData)
| extend Creator = tostring(RuleData.UserId)
| extend ClientIP = tostring(RuleData.ClientIP)
| extend Conditions = tostring(RuleData.Parameters)
| where Conditions has_any ("invoice", "payment", "bank", "wire",
"transfer", "remittance", "account details", "sort code",
"routing number", "IBAN", "SWIFT")
| extend ForwardTo = tostring(RuleData.Parameters
| mv-expand RuleData.Parameters
| where tostring(RuleData.Parameters.Name) in ("ForwardTo", "RedirectTo")
| project tostring(RuleData.Parameters.Value))
| extend MoveToFolder = tostring(RuleData.Parameters
| mv-expand RuleData.Parameters
| where tostring(RuleData.Parameters.Name) == "MoveToFolder"
| project tostring(RuleData.Parameters.Value))
| project TimeGenerated, Creator, ClientIP, Conditions, ForwardTo, MoveToFolder
|
Entity mapping: Account → Creator (FullName). IP → ClientIP (Address).
Why this rule matters: Inbox rules targeting financial keywords are the BEC persistence mechanism. This rule catches the attacker’s preparation phase — before the fraudulent email is sent.
Rule 2: Email Thread Reply from Different IP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| // Scheduled Rule: Reply in email thread sent from IP different from previous messages
// Schedule: 15 minutes / Lookback: 20 minutes
// Severity: Medium
// MITRE: T1534 (Internal Spearphishing), T1036 (Masquerading)
let RecentReplies = EmailEvents
| where Subject startswith "Re:"
| where SenderFromDomain == "northgateeng.com" // Internal sender
| project ReplyTime = TimeGenerated, SenderFromAddress, Subject,
ReplyIP = SenderIPv4, NetworkMessageId;
let PreviousMessages = EmailEvents
| where TimeGenerated > ago(30d)
| project OrigTime = TimeGenerated, OrigSender = SenderFromAddress,
Subject, OrigIP = SenderIPv4;
RecentReplies
| join kind=inner PreviousMessages
on SenderFromAddress, Subject
| where ReplyTime > OrigTime
| where ReplyIP != OrigIP and isnotempty(OrigIP)
| project SenderFromAddress, Subject, ReplyTime, ReplyIP, OrigIP,
IPChanged = true
| distinct SenderFromAddress, Subject, ReplyIP, OrigIP
|
Entity mapping: Account → SenderFromAddress (FullName). IP → ReplyIP (Address).
What this detects: Thread hijacking — the attacker replies to an existing thread from a different IP than the legitimate sender used. This is a BEC-specific detection that no standard analytics rule template covers.
Rule 3: Mass Email Read from Non-Corporate IP
Same as M11 Rule 5. Detects the reconnaissance phase — the attacker reading emails to identify vendor payment threads.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| // Scheduled Rule: High-volume email access from external IP
// Schedule: 1 hour / Lookback: 1 hour 15 minutes
// Severity: Medium
// MITRE: T1114.002 (Remote Email Collection)
CloudAppEvents
| where ActionType == "MailItemsAccessed"
| extend ClientIP = tostring(parse_json(RawEventData).ClientIPAddress)
| where not(ipv4_is_private(ClientIP))
| where ClientIP !in (_GetWatchlist('CorporateExternalIPs') | project SearchKey)
| summarize EmailsAccessed = count(),
FirstAccess = min(TimeGenerated),
LastAccess = max(TimeGenerated)
by AccountDisplayName, AccountObjectId, ClientIP
| where EmailsAccessed > 50
|
Rule 4: Vendor Bank Detail Change Email (Keyword Detection)
1
2
3
4
5
6
7
8
9
10
11
12
13
| // Scheduled Rule: Email containing bank detail change language
// Schedule: 15 minutes / Lookback: 20 minutes
// Severity: Medium
// MITRE: T1565.003 (Runtime Data Manipulation)
EmailEvents
| where DeliveryAction == "Delivered"
| where Subject has_any ("bank details", "account details", "payment details",
"new bank", "changed bank", "updated bank", "revised bank",
"new account", "updated account")
| where SenderFromDomain !in ("northgateeng.com") // External sender
| project TimeGenerated, SenderFromAddress, SenderFromDomain,
RecipientEmailAddress, Subject, AuthenticationDetails,
NetworkMessageId
|
Entity mapping: Account → RecipientEmailAddress (FullName).
Operational note: This rule will generate false positives from legitimate bank detail change notifications. Tune by: maintaining a watchlist of verified vendor domains and excluding them, or routing this rule’s alerts to Medium severity for manual review rather than automated response.
Rule 5: Mail Item Deletion from Non-Corporate IP (Evidence Destruction)
1
2
3
4
5
6
7
8
9
10
11
12
| // Scheduled Rule: Bulk email deletion from external IP
// Schedule: 15 minutes / Lookback: 20 minutes
// Severity: High
// MITRE: T1070.008 (Clear Mailbox Data)
CloudAppEvents
| where ActionType in ("HardDelete", "SoftDelete")
| where Application == "Microsoft Exchange Online"
| extend ClientIP = tostring(parse_json(RawEventData).ClientIPAddress)
| where not(ipv4_is_private(ClientIP))
| where ClientIP !in (_GetWatchlist('CorporateExternalIPs') | project SearchKey)
| summarize DeleteCount = count() by AccountDisplayName, ClientIP
| where DeleteCount > 10
|
What this detects: The evidence destruction phase — the attacker deleting sent emails and inbox rules after the fraudulent payment is processed.
Rule 6: BEC Attack Chain Sequence
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| // Scheduled Rule: Complete BEC chain — inbox rule + email read + thread reply within 7 days
// Schedule: 4 hours / Lookback: 7 days
// Severity: Critical
// MITRE: T1114.003, T1114.002, T1534
let FinancialRules = CloudAppEvents
| where ActionType in ("New-InboxRule", "Set-InboxRule")
| extend Conditions = tostring(parse_json(RawEventData).Parameters)
| where Conditions has_any ("invoice", "payment", "bank", "wire", "transfer")
| extend RuleCreator = tostring(parse_json(RawEventData).UserId)
| project RuleTime = TimeGenerated, RuleCreator;
let MassRead = CloudAppEvents
| where ActionType == "MailItemsAccessed"
| extend ClientIP = tostring(parse_json(RawEventData).ClientIPAddress)
| where not(ipv4_is_private(ClientIP))
| summarize EmailsRead = count() by AccountDisplayName, ClientIP
| where EmailsRead > 20
| project ReadUser = AccountDisplayName;
FinancialRules
| join kind=inner MassRead on $left.RuleCreator == $right.ReadUser
| project RuleCreator, RuleTime
|
This rule fires when: A user creates a financial-keyword inbox rule AND has mass email reads from a non-corporate IP. The combination indicates a compromised mailbox being prepared for BEC. Near-zero false positives — legitimate users do not create financial keyword interception rules while reading email from external IPs.
Deployment checklist
For each rule: create in Sentinel Analytics, configure entity mapping, set MITRE technique, configure alert grouping (entity-based), test against 30 days historical data, enable, and monitor for 7 days.
Subsection artifact: 6 deployable BEC detection rules. These form the BEC detection pack — distinct from the AiTM detection pack in M11.13.
Compliance mapping: NIST CSF DE.AE-2 (Anomalous activity is detected). ISO 27001 A.8.16 (Monitoring activities).
Knowledge check
Check your understanding
1. Rule 4 (Vendor Bank Detail Change) generates false positives from legitimate vendor notifications. How do you handle this?
Maintain a watchlist of verified vendor domains. Exclude those domains from the rule. Route the remaining alerts (from unknown or new domains) to Medium severity for manual review. Do not disable the rule — the false positives are the cost of catching the one real BEC attempt. Tune the exclusions over time as you verify more vendor domains.
Disable the rule
Lower the severity to Informational
The rule should have zero false positives
Watchlist exclusion for verified vendors. Manual review for unknown domains. The rule is worth the noise — one real BEC detection justifies many false positive reviews.