Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 24 additions & 1 deletion detection-rules/impersonation_vip_bec_loose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,30 @@ severity: "medium"
source: |
type.inbound
and any($org_vips,
0 <= strings.ilevenshtein(sender.display_name, .display_name) < 4
(
.display_name != ""
and 0 <= strings.ilevenshtein(sender.display_name, .display_name) < 4
)
or (
.first_name != ""
and .last_name != ""
and 0 <= strings.ilevenshtein(sender.display_name,
strings.concat(.first_name,
" ",
.last_name
)
) < 4
)
or (
.first_name != ""
and .last_name != ""
and 0 <= strings.ilevenshtein(sender.display_name,
strings.concat(.last_name,
", ",
.first_name
)
) < 4
)
)
and any(ml.nlu_classifier(body.current_thread.text).intents,
.name == "bec" and .confidence in ("medium", "high")
Expand Down
24 changes: 21 additions & 3 deletions detection-rules/impersonation_vip_invoicing_request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,26 @@ type: "rule"
severity: "high"
source: |
type.inbound
and any($org_vips, strings.contains(sender.display_name, .display_name))
and any($org_vips,
(
.display_name != ""
and strings.contains(sender.display_name, .display_name)
)
or (
.first_name != ""
and .last_name != ""
and strings.contains(sender.display_name,
strings.concat(.first_name, " ", .last_name)
)
)
or (
.first_name != ""
and .last_name != ""
and strings.contains(sender.display_name,
strings.concat(.last_name, ", ", .first_name)
)
)
)
and (
(
sender.email.domain.domain in $org_domains
Expand All @@ -26,7 +45,7 @@ source: |
)
)

// and the reply to email address has never been contacted
// and the reply to email address has never been contacted
and any(headers.reply_to, .email.email not in $recipient_emails)

// negate highly trusted sender domains unless they fail DMARC authentication
Expand All @@ -37,7 +56,6 @@ source: |
)
or sender.email.domain.root_domain not in $high_trust_sender_root_domains
)

attack_types:
- "BEC/Fraud"
tactics_and_techniques:
Expand Down
14 changes: 13 additions & 1 deletion detection-rules/impersonation_vip_urgent_request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,19 @@ type: "rule"
severity: "high"
source: |
type.inbound
and any($org_vips, .display_name =~ sender.display_name)
and any($org_vips,
(.display_name != "" and .display_name =~ sender.display_name)
or (
.first_name != ""
and .last_name != ""
and strings.concat(.first_name, " ", .last_name) =~ sender.display_name
)
or (
.first_name != ""
and .last_name != ""
and strings.concat(.last_name, ", ", .first_name) =~ sender.display_name
)
)
and (
any(ml.nlu_classifier(body.current_thread.text).intents,
.name == "bec" and .confidence in ("medium", "high")
Expand Down
21 changes: 20 additions & 1 deletion detection-rules/impersonation_vip_w2_request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,26 @@ severity: "high"
source: |
type.inbound
and (
any($org_vips, strings.contains(sender.display_name, .display_name))
any($org_vips,
(
.display_name != ""
and strings.contains(sender.display_name, .display_name)
)
or (
.first_name != ""
and .last_name != ""
and strings.contains(sender.display_name,
strings.concat(.first_name, " ", .last_name)
)
)
or (
.first_name != ""
and .last_name != ""
and strings.contains(sender.display_name,
strings.concat(.last_name, ", ", .first_name)
)
)
)
or any(regex.extract(sender.display_name, '^(?<first>\S+)\s+(?<second>\S+)$'),
any($org_vips,
strings.contains(.display_name, ..named_groups["first"])
Expand Down
46 changes: 42 additions & 4 deletions detection-rules/vip_impersonation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,51 @@ source: |
type.inbound
and (
// the display name matches a name on the orgs vip list
any($org_vips, .display_name =~ sender.display_name)
any($org_vips,
(.display_name != "" and .display_name =~ sender.display_name)
or (
.first_name != ""
and .last_name != ""
and strings.concat(.first_name, " ", .last_name) =~ sender.display_name
)
or (
.first_name != ""
and .last_name != ""
and strings.concat(.last_name, ", ", .first_name) =~ sender.display_name
)
)
// or the display name starts with the name on the orgs vip list
or (
any($org_vips,
strings.istarts_with(sender.display_name, .display_name)
// and it is longer than just their name (eg. John Doe CEO)
and length(sender.display_name) > length(.display_name)
(
.display_name != ""
and strings.istarts_with(sender.display_name, .display_name)
and length(sender.display_name) > length(.display_name)
)
or (
.first_name != ""
and .last_name != ""
and strings.istarts_with(sender.display_name,
strings.concat(.first_name, " ", .last_name)
)
and length(sender.display_name) > length(strings.concat(.first_name,
" ",
.last_name
)
)
)
or (
.first_name != ""
and .last_name != ""
and strings.istarts_with(sender.display_name,
strings.concat(.last_name, ", ", .first_name)
)
and length(sender.display_name) > length(strings.concat(.last_name,
", ",
.first_name
)
)
)
)
// and we have confidence it's BEC
and any(ml.nlu_classifier(body.current_thread.text).intents,
Expand Down