Detection rules › Kusto

Detect Possible Teams BEC Attack by High Teams Recipients

Time window
1d
Group by
AccountObjectId, SenderEmailAddress, SenderObjectId
Author
Robbe Van den Daele
Source
github.com/HybridBrothers/Hunting-Queries-Detection-Rules

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

TacticTechniques
Initial Access

References

Telemetry coverage

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 used in Stages 2, 10

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.

Output fields

These fields are emitted when the rule matches.

FieldSource
ChatSetsummarize
SenderEmailAddresssummarize
ChatAmmountextend