Detection rules › Sublime MQL

Sublime MQL rules: lookalike

Lookalike sender domain (untrusted sender)

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

Sender's domain is a lookalike of one of your organization's domains and is untrusted.

Threat Classification

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

CategoryValues
Attack typesBEC/Fraud, Credential Phishing, Malware/Ransomware
Tactics and techniquesLookalike domain, Social engineering

Telemetry Coverage

PlatformRecord / event type
SublimeInbound email message

Message Attributes

  • headers
  • headers.auth_summary
  • sender.email
  • type

Rule Body

type.inbound
and length(sender.email.domain.sld) > 3
and sender.email.domain.domain not in $org_domains
and any($org_domains,
        // this rule can be duplicated in order to tune the threshold
        strings.ilevenshtein(sender.email.domain.domain, .) == 1
)
and (
  (
    profile.by_sender_email().prevalence in ("new", "outlier")
    and not profile.by_sender_email().solicited
  )
  or (
    profile.by_sender_email().any_messages_malicious_or_spam
    and not profile.by_sender_email().any_messages_benign
  )
)

// negate highly trusted sender domains unless they fail DMARC authentication
and (
  (
    sender.email.domain.root_domain in $high_trust_sender_root_domains
    and not headers.auth_summary.dmarc.pass
  )
  or sender.email.domain.root_domain not in $high_trust_sender_root_domains
)
and not profile.by_sender_email().any_messages_benign

Detection Logic

Scope: inbound message.

Sender's domain is a lookalike of one of your organization's domains and is untrusted.

  1. inbound message
  2. length(sender.email.domain.sld) > 3
  3. sender.email.domain.domain not in $org_domains
  4. any($org_domains, // this rule can be duplicated in order to tune the threshold strings.ilevenshtein(sender.email.domain.domain, .) == 1 )
  5. any of:
    • all of:
      • profile.by_sender_email().prevalence in ("new", "outlier")
      • not:
        • profile.by_sender_email().solicited
    • all of:
      • profile.by_sender_email().any_messages_malicious_or_spam
      • not:
        • profile.by_sender_email().any_messages_benign
  6. any of:
    • all of:
      • sender.email.domain.root_domain in $high_trust_sender_root_domains
      • not:
        • headers.auth_summary.dmarc.pass
    • sender.email.domain.root_domain not in $high_trust_sender_root_domains
  7. not:
    • profile.by_sender_email().any_messages_benign

Inspects: headers.auth_summary.dmarc.pass, sender.email.domain.domain, sender.email.domain.root_domain, sender.email.domain.sld, type.inbound. Sensors: profile.by_sender_email, strings.ilevenshtein. Reference lists: $high_trust_sender_root_domains, $org_domains.

Stages and Predicates

Stage 1: mql_rule

and
  or
    and
      not
        headers.auth_summary.dmarc.pass eq "true"
      sender.email.domain.root_domain macro "sender.email.domain.root_domain in high_trust_sender_root_domains"
    sender.email.domain.root_domain macro "sender.email.domain.root_domain not in high_trust_sender_root_domains"
  or
    and
      not
        profile.by_sender_email func_call "profile.by_sender_email().any_messages_benign"
      profile.by_sender_email func_call "profile.by_sender_email().any_messages_malicious_or_spam"
    and
      not
        profile.by_sender_email func_call "profile.by_sender_email().solicited"
      profile.by_sender_email func_call "profile.by_sender_email().prevalence in (\"new\", \"outlier\")"
  not
    profile.by_sender_email func_call "profile.by_sender_email().any_messages_benign"
  sender.email.domain.domain macro "sender.email.domain.domain not in org_domains"
  sender.email.domain.sld length_compare "3"
  type.inbound eq "true"
   macro "any($org_domains,\n        // this rule can be duplicated in order to tune the threshold\n        strings.ilevenshtein(sender.email.domain.domain, .) == 1\n)"

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
type.inboundeq
  • true transforms: boolean corpus 1212 (mql 1212)
field:"type.inbound" kind:eq value:"true"

Suspected lookalike domain with suspicious language

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

This rule identifies messages where links use typosquatting or lookalike domains similar to the sender domain, with at least one domain being either unregistered or recently registered (≤90 days). The messages must also contain indicators of business email compromise (BEC), credential theft, or abusive language patterns like financial terms or polite phrasing such as kindly. This layered approach targets phishing attempts combining domain deception with manipulative content

Threat Classification

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

CategoryValues
Attack typesBEC/Fraud
Tactics and techniquesEvasion, Lookalike domain, Social engineering

Telemetry Coverage

PlatformRecord / event type
SublimeInbound email message

Message Attributes

  • body
  • body.current_thread
  • body.links
  • sender.email
  • type

Rule Body

type.inbound

// levenshtein distance (edit distance) between the SLD of the link and the sender domain is greater than 0 and less than or equal to 2.
// This detects typosquatting or domains that are deceptively similar to the sender.
and any(body.links,
        length(.href_url.domain.sld) > 3
        and 0 < strings.levenshtein(.href_url.domain.sld,
                                    sender.email.domain.sld
        ) <= 2
        // exclude onmicrosoft.com
        and not sender.email.domain.root_domain == "onmicrosoft.com"
        and (
          // domains are not registered or registered within 90d
          // network.whois(.href_url.domain).found == false
          network.whois(.href_url.domain).days_old <= 90
          or network.whois(sender.email.domain).found == false
          or network.whois(sender.email.domain).days_old <= 90
        )
)
// the mesasge is intent is BEC or Cred Theft, or is talking about financial invoicing/banking language, or a request contains "kindly"
and any(ml.nlu_classifier(body.current_thread.text).intents,
        .name in ("bec", "cred_theft")
        or any(ml.nlu_classifier(body.current_thread.text).entities,
               .name == "financial"
               and (
                 .text in ("invoice", "banking information")
                 or .name == "request" and strings.icontains(.text, "kindly")
               )
        )
)

Detection Logic

Scope: inbound message.

This rule identifies messages where links use typosquatting or lookalike domains similar to the sender domain, with at least one domain being either unregistered or recently registered (≤90 days). The messages must also contain indicators of business email compromise (BEC), credential theft, or abusive language patterns like financial terms or polite phrasing such as kindly. This layered approach targets phishing attempts combining domain deception with manipulative content

  1. inbound message
  2. any of body.links where all hold:
    • length(.href_url.domain.sld) > 3
    • all of:
      • (0) < (strings.levenshtein(.href_url.domain.sld, sender.email.domain.sld ))
      • (strings.levenshtein(.href_url.domain.sld, sender.email.domain.sld )) <= (2)
    • not:
      • sender.email.domain.root_domain is 'onmicrosoft.com'
    • any of:
      • network.whois(.href_url.domain).days_old <= 90
      • network.whois(sender.email.domain).found == false
      • network.whois(sender.email.domain).days_old <= 90
  3. any(ml.nlu_classifier(body.current_thread.text).intents, .name in ("bec", "cred_theft") or any(ml.nlu_classifier(body.current_thread.text).entities, .name == "financial" and ( .text in ("invoice", "banking information") or .name == "request" and strings.icontains(.text, "kindly") ) ) )

Inspects: body.current_thread.text, body.links, body.links[].href_url.domain, body.links[].href_url.domain.sld, sender.email.domain, sender.email.domain.root_domain, sender.email.domain.sld, type.inbound. Sensors: ml.nlu_classifier, network.whois, strings.icontains, strings.levenshtein.

Indicators Matched (7)

FieldMatchValue
ml.nlu_classifier(body.current_thread.text).intents[].namememberbec
ml.nlu_classifier(body.current_thread.text).intents[].namemembercred_theft
ml.nlu_classifier(body.current_thread.text).entities[].nameequalsfinancial
ml.nlu_classifier(body.current_thread.text).entities[].textmemberinvoice
ml.nlu_classifier(body.current_thread.text).entities[].textmemberbanking information
ml.nlu_classifier(body.current_thread.text).entities[].nameequalsrequest
strings.icontainssubstringkindly

Stages and Predicates

Stage 1: mql_rule

and
  any(body.links)
    and
      or
        network.whois func_call "network.whois(.href_url.domain).days_old <= 90"
        network.whois func_call "network.whois(sender.email.domain).days_old <= 90"
        network.whois func_call "network.whois(sender.email.domain).found == false"
      not
        sender.email.domain.root_domain eq "onmicrosoft.com"
      body.links.href_url.domain.sld length_compare "3"
      strings.levenshtein func_call "(0) < (strings.levenshtein(.href_url.domain.sld,\n                                    sender.email.domain.sld\n        ))"
      strings.levenshtein func_call "(strings.levenshtein(.href_url.domain.sld,\n                                    sender.email.domain.sld\n        )) <= (2)"
  type.inbound eq "true"
   macro "any(ml.nlu_classifier(body.current_thread.text).intents,\n        .name in (\"bec\", \"cred_theft\")\n        or any(ml.nlu_classifier(body.current_thread.text).entities,\n               .name == \"financial\"\n               and (\n                 .text in (\"invoice\", \"banking information\")\n                 or .name == \"request\" and strings.icontains(.text, \"kindly\")\n               )\n        )\n)"

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
type.inboundeq
  • true transforms: boolean corpus 1212 (mql 1212)
field:"type.inbound" kind:eq value:"true"

Back to all Sublime MQL rules