diff --git a/detection-rules/impersonation_vip_bec_loose.yml b/detection-rules/impersonation_vip_bec_loose.yml index bb9e57f53b2..603681afc42 100644 --- a/detection-rules/impersonation_vip_bec_loose.yml +++ b/detection-rules/impersonation_vip_bec_loose.yml @@ -9,6 +9,18 @@ source: | type.inbound and any($org_vips, 0 <= strings.ilevenshtein(sender.display_name, .display_name) < 4 + or 0 <= strings.ilevenshtein(sender.display_name, + strings.concat(.first_name, + " ", + .last_name + ) + ) < 4 + or 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") diff --git a/detection-rules/impersonation_vip_invoicing_request.yml b/detection-rules/impersonation_vip_invoicing_request.yml index 6e6e2ec76f9..7b1aa71020d 100644 --- a/detection-rules/impersonation_vip_invoicing_request.yml +++ b/detection-rules/impersonation_vip_invoicing_request.yml @@ -4,7 +4,15 @@ type: "rule" severity: "high" source: | type.inbound - and any($org_vips, strings.contains(sender.display_name, .display_name)) + and any($org_vips, + strings.contains(sender.display_name, .display_name) + or strings.contains(sender.display_name, + strings.concat(.first_name, " ", .last_name) + ) + or strings.contains(sender.display_name, + strings.concat(.last_name, ", ", .first_name) + ) + ) and ( ( sender.email.domain.domain in $org_domains @@ -26,7 +34,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 @@ -37,7 +45,6 @@ source: | ) or sender.email.domain.root_domain not in $high_trust_sender_root_domains ) - attack_types: - "BEC/Fraud" tactics_and_techniques: diff --git a/detection-rules/impersonation_vip_urgent_request.yml b/detection-rules/impersonation_vip_urgent_request.yml index 9d876acf77f..114da6cf758 100644 --- a/detection-rules/impersonation_vip_urgent_request.yml +++ b/detection-rules/impersonation_vip_urgent_request.yml @@ -7,7 +7,11 @@ type: "rule" severity: "high" source: | type.inbound - and any($org_vips, .display_name =~ sender.display_name) + and any($org_vips, + .display_name =~ sender.display_name + or strings.concat(.first_name, " ", .last_name) == sender.display_name + or 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") diff --git a/detection-rules/impersonation_vip_w2_request.yml b/detection-rules/impersonation_vip_w2_request.yml index 2c4fc6cc1a1..823845168de 100644 --- a/detection-rules/impersonation_vip_w2_request.yml +++ b/detection-rules/impersonation_vip_w2_request.yml @@ -5,7 +5,15 @@ severity: "high" source: | type.inbound and ( - any($org_vips, strings.contains(sender.display_name, .display_name)) + any($org_vips, + strings.contains(sender.display_name, .display_name) + or strings.contains(sender.display_name, + strings.concat(.first_name, " ", .last_name) + ) + or strings.contains(sender.display_name, + strings.concat(.last_name, ", ", .first_name) + ) + ) or any(regex.extract(sender.display_name, '^(?\S+)\s+(?\S+)$'), any($org_vips, strings.contains(.display_name, ..named_groups["first"]) diff --git a/detection-rules/vip_impersonation.yml b/detection-rules/vip_impersonation.yml index 0dddec63618..feef45d690b 100644 --- a/detection-rules/vip_impersonation.yml +++ b/detection-rules/vip_impersonation.yml @@ -14,13 +14,38 @@ 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 =~ sender.display_name + or strings.concat(.first_name, " ", .last_name) == sender.display_name + or 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) + ( + strings.istarts_with(sender.display_name, .display_name) + and length(sender.display_name) > length(.display_name) + ) + or ( + 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 ( + 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, diff --git a/insights/sender/sender_contains_org_vip.yml b/insights/sender/sender_contains_org_vip.yml index 7845dd5c028..14b2901da52 100644 --- a/insights/sender/sender_contains_org_vip.yml +++ b/insights/sender/sender_contains_org_vip.yml @@ -3,7 +3,11 @@ type: "query" source: | type.inbound and any($org_vips, - strings.icontains(sender.display_name, .display_name) + ( + strings.icontains(sender.display_name, .display_name) + or strings.icontains(sender.display_name, strings.concat(.first_name, " ", .last_name)) + or strings.icontains(sender.display_name, strings.concat(.last_name, ", ", .first_name)) + ) and not sender.email.domain.root_domain in $high_trust_sender_root_domains and not sender.email.domain.root_domain in $org_domains and headers.auth_summary.dmarc.pass