Detection rules › Sublime MQL

Sublime MQL rules: vendor

Vendor impersonation: Thread hijacking with typosquat domain

#
Severity
high
Type
rule
Source
github.com/sublime-security/sublime-rules

Detects potential thread hijacking where the sender uses a domain similar to known senders, exhibits BEC behavior, and shows signs of compromised thread continuity through domain spoofing or thread manipulation.

Threat classification

Sublime's own taxonomy (not MITRE ATT&CK).

CategoryValues
Attack typesBEC/Fraud
Tactics and techniquesLookalike domain, Social engineering, Spoofing

Telemetry coverage

PlatformRecord / event type
SublimeInbound email message

Message attributes

  • body
  • body.current_thread
  • body.previous_threads
  • sender.email
  • subject
  • type

Rule body

type.inbound
and subject.is_reply
and sender.email.domain.root_domain not in $sender_domains
// current sender has not been seen in the thread before
and any(body.previous_threads, .sender.email.domain.domain not in $org_domains)
and all(body.previous_threads,
        .sender.email.domain.domain != sender.email.domain.domain
        and all(.recipients.to,
                .email.domain.domain != sender.email.domain.domain
        )
        and all(.recipients.cc,
                .email.domain.domain != sender.email.domain.domain
        )
)
and any($sender_domains,
        0 < strings.ilevenshtein(., sender.email.domain.root_domain) < 3
)
and any(ml.nlu_classifier(body.current_thread.text).intents,
        .name == "bec" and .confidence != "low"
)
// risky category
and any(ml.nlu_classifier(body.current_thread.text).topics,
        .name in (
          "Financial Communications",
          "E-Signature",
          "Benefit Enrollment"
        )
        and .confidence == "high"
)
and 1 of (
  not network.whois(sender.email.domain).found,
  any(body.previous_threads, strings.icontains(.preamble, sender.display_name))
)
and (
  profile.by_sender_domain().prevalence == "new"
  or profile.by_sender_domain().days_known < 3
)

Detection logic

Scope: inbound message.

Detects potential thread hijacking where the sender uses a domain similar to known senders, exhibits BEC behavior, and shows signs of compromised thread continuity through domain spoofing or thread manipulation.

  1. inbound message
  2. subject.is_reply
  3. sender.email.domain.root_domain not in $sender_domains
  4. any of body.previous_threads where:
    • .sender.email.domain.domain not in $org_domains
  5. all of body.previous_threads where all hold:
    • .sender.email.domain.domain is not sender.email.domain.domain
    • all of .recipients.to where:
      • .email.domain.domain is not sender.email.domain.domain
    • all of .recipients.cc where:
      • .email.domain.domain is not sender.email.domain.domain
  6. any of $sender_domains where all hold:
    • strings.ilevenshtein(.) > 0
    • strings.ilevenshtein(.) < 3
  7. any of ml.nlu_classifier(body.current_thread.text).intents where all hold:
    • .name is 'bec'
    • .confidence is not 'low'
  8. any of ml.nlu_classifier(body.current_thread.text).topics where all hold:
    • .name in ('Financial Communications', 'E-Signature', 'Benefit Enrollment')
    • .confidence is 'high'
  9. at least 1 of:
    • not:
      • network.whois(sender.email.domain).found
    • any of body.previous_threads where:
      • strings.icontains(.preamble)
  10. any of:
    • profile.by_sender_domain().prevalence is 'new'
    • profile.by_sender_domain().days_known < 3

Inspects: body.current_thread.text, body.previous_threads, body.previous_threads[].preamble, body.previous_threads[].recipients.cc, body.previous_threads[].recipients.cc[].email.domain.domain, body.previous_threads[].recipients.to, body.previous_threads[].recipients.to[].email.domain.domain, body.previous_threads[].sender.email.domain.domain, sender.display_name, sender.email.domain, sender.email.domain.domain, sender.email.domain.root_domain, subject.is_reply, type.inbound. Sensors: ml.nlu_classifier, network.whois, profile.by_sender_domain, strings.icontains, strings.ilevenshtein. Reference lists: $org_domains, $sender_domains.

Indicators matched (5)

FieldMatchValue
ml.nlu_classifier(body.current_thread.text).intents[].nameequalsbec
ml.nlu_classifier(body.current_thread.text).topics[].namememberFinancial Communications
ml.nlu_classifier(body.current_thread.text).topics[].namememberE-Signature
ml.nlu_classifier(body.current_thread.text).topics[].namememberBenefit Enrollment
ml.nlu_classifier(body.current_thread.text).topics[].confidenceequalshigh

Stages and Predicates

Stage 1: mql_rule

and
  any(ml.nlu_classifier(body.current_thread.text).intents)
    and
      ml.nlu_classifier(body.current_thread.text).intents.confidence ne "low"
      ml.nlu_classifier(body.current_thread.text).intents.name eq "bec"
  any(ml.nlu_classifier(body.current_thread.text).topics)
    and
      ml.nlu_classifier(body.current_thread.text).topics.confidence eq "high"
      ml.nlu_classifier(body.current_thread.text).topics.name in ["Benefit Enrollment", "E-Signature", "Financial Communications"]
  or
    not
      network.whois func_call "network.whois(sender.email.domain).found"
    any(body.previous_threads)
      strings.icontains func_call "strings.icontains(body.previous_threads[].preamble)"
  any($sender_domains)
    and
      strings.ilevenshtein func_call "strings.ilevenshtein($sender_domains[]) < 3"
      strings.ilevenshtein func_call "strings.ilevenshtein($sender_domains[]) > 0"
  or
    profile.by_sender_domain func_call "profile.by_sender_domain().days_known < 3"
    profile.by_sender_domain func_call "profile.by_sender_domain().prevalence == new"
  any(body.previous_threads)
     macro "body.previous_threads[].sender.email.domain.domain not in org_domains"
  subject.is_reply eq "true"
  type.inbound eq "true"
   macro "all(body.previous_threads)"
   macro "sender.email.domain.root_domain not in sender_domains"

Indicators

These rows show field, operator, and value matches.