Detection rules › Kusto
Detect Possible Teams BEC Attack by High Teams Recipients
An external sender suddenly increasing the amount of internal users they are sending messages to, can indicate that external user being compromised and used for BEC Attacks. In these kind of attacks compromised accounts are used to send phishing links or attachments to users in business relationships.
MITRE ATT&CK coverage
| Tactic | Techniques |
|---|---|
| Initial Access |
References
Telemetry coverage
| Platform | Record / event type |
|---|---|
| Microsoft Defender for Endpoint | MessageEvents action any: Teams message processed |
Rule body
// Possible BEC detection by high teams recipients
let increase_percentage = 200;
let base = (
MessageEvents
| where TimeGenerated > ago(14d)
// Focus on chat messsages
| where ThreadType == "chat"
// Only return external users sending messages
| join kind=leftanti (
IdentityInfo
| where TimeGenerated > ago(14d)
| distinct AccountObjectId
) on $left.SenderObjectId == $right.AccountObjectId
// Make a set of all the chats they are posting to, for every day
| summarize ChatSet = make_set(ThreadId) by SenderEmailAddress, bin(TimeGenerated, 1d)
// Count the amount of chats they posted to for each day
| extend ChatAmmount = array_length(ChatSet)
);
// Get the average of send chats per external user per day
let averageBySender = (
base
| summarize AverageChatsBySender = avg(ChatAmmount) by SenderEmailAddress
);
// Check if the sender dubbled their chats to internal users compared to their baseline
base
| where TimeGenerated > ago(1d)
| join kind=inner averageBySender on SenderEmailAddress
| where ChatAmmount > AverageChatsBySender * (increase_percentage / 100)
Stages and Predicates
Parameters
let increase_percentage = 200;
let base is inlined into the numbered stages below.
Let binding: averageBySender
let averageBySender = (
base
| summarize AverageChatsBySender = avg(ChatAmmount) by SenderEmailAddress
);
Stage 1: source
let base
Stage 2: source
let averageBySender
Stage 3: source
MessageEvents
Stage 4: where
where TimeGenerated > ago(1209600s)
Stage 5: where
where ThreadType =~ "chat"
Stage 6: join (negated)
join kind=leftanti (IdentityInfo) on SenderObjectId, AccountObjectId
Stage 7: summarize
summarize ChatSet by SenderEmailAddress
Stage 8: extend
extend ChatAmmount
Stage 9: where
where TimeGenerated > ago(86400s)
Stage 10: join
join kind=inner (averageBySender) on SenderEmailAddress
Stage 11: where
where /* macro: (ChatAmmount > (AverageChatsBySender * (200 / 100))) */
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
ThreadType | eq |
| field:"ThreadType" kind:eq value:"chat" |
Output fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
ChatSet | summarize |
SenderEmailAddress | summarize |
ChatAmmount | extend |