Detection rules › Sublime MQL

Spoofable internal domain with suspicious signals

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

The sender is a known org domain and doesn't use a known org display name. SPF and DMARC verdicts are "none", which means the domain is spoofable. We then look for a combination of other suspicious signals such as a suspicious link or suspicious language. False Positives may occur with automated sending systems that send rich text emails, in which case we can add additional signals or exclude those.

Threat classification

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

CategoryValues
Attack typesCredential Phishing
Tactics and techniquesFree file host, Free subdomain host, Social engineering, Spoofing

Event coverage

Rule body MQL

type.inbound
and sender.email.domain.domain in $org_domains

// doesn't match an org display name (generic)
// we could make this more generic later
and sender.display_name not in $org_display_names
and any(headers.hops,

        // find the hop Authentication-results for the org domain
        .authentication_results.dmarc_details.from.domain in $org_domains

        // internal domain is spoofable
        and .authentication_results.dmarc == "none"
        and .authentication_results.spf == "none"
        and .authentication_results.compauth.verdict not in ("pass", "softpass")
)
and 3 of (
  (
    // low reputation / suspicious link
    any(body.links,
        .href_url.domain.root_domain not in $org_domains
        and (
          .href_url.domain.root_domain not in $tranco_1m
          or .href_url.domain.domain in $free_file_hosts
          or .href_url.domain.root_domain in $free_file_hosts
          or .href_url.domain.root_domain in $free_subdomain_hosts
          or .href_url.domain.domain in $url_shorteners
          or .href_url.domain.domain in $social_landing_hosts
        )
    )
  ),
  (
    // sender domain matches no body domains
    length(body.links) > 0
    and all(body.links,
            .href_url.domain.root_domain != sender.email.domain.root_domain
    )
  ),
  (
    // suspicious domain in headers
    any(headers.domains,
        // it's not an org domain
        .root_domain not in $org_domains

        // low reputation
        and .root_domain not in $alexa_1m

        // no one has sent an email to it before
        and .root_domain not in $recipient_domains
    )
  ),
  (
    // suspicious language
    any(ml.nlu_classifier(body.current_thread.text).intents,
        .name != "benign" and .confidence == "high"
    )
  ),
  (
    // suspicious language
    any(ml.nlu_classifier(body.current_thread.text).intents,
        .name != "benign" and .confidence == "high"
    )
  ),
)

Detection logic

Scope: inbound message.

The sender is a known org domain and doesn't use a known org display name. SPF and DMARC verdicts are "none", which means the domain is spoofable. We then look for a combination of other suspicious signals such as a suspicious link or suspicious language. False Positives may occur with automated sending systems that send rich text emails, in which case we can add additional signals or exclude those.

  1. inbound message
  2. sender.email.domain.domain in $org_domains
  3. sender.display_name not in $org_display_names
  4. any of headers.hops where all hold:
    • .authentication_results.dmarc_details.from.domain in $org_domains
    • .authentication_results.dmarc is 'none'
    • .authentication_results.spf is 'none'
    • .authentication_results.compauth.verdict not in ('pass', 'softpass')
  5. at least 3 of:
    • any of body.links where all hold:
      • .href_url.domain.root_domain not in $org_domains
      • any of:
        • .href_url.domain.root_domain not in $tranco_1m
        • .href_url.domain.domain in $free_file_hosts
        • .href_url.domain.root_domain in $free_file_hosts
        • .href_url.domain.root_domain in $free_subdomain_hosts
        • .href_url.domain.domain in $url_shorteners
        • .href_url.domain.domain in $social_landing_hosts
    • all of:
      • length(body.links) > 0
      • all of body.links where:
        • .href_url.domain.root_domain is not sender.email.domain.root_domain
    • any of headers.domains where all hold:
      • .root_domain not in $org_domains
      • .root_domain not in $alexa_1m
      • .root_domain not in $recipient_domains
    • any of ml.nlu_classifier(body.current_thread.text).intents where all hold:
      • .name is not 'benign'
      • .confidence is 'high'
    • any of ml.nlu_classifier(body.current_thread.text).intents where all hold:
      • .name is not 'benign'
      • .confidence is 'high'

Inspects: body.current_thread.text, body.links, body.links[].href_url.domain.domain, body.links[].href_url.domain.root_domain, headers.domains, headers.domains[].root_domain, headers.hops, headers.hops[].authentication_results.compauth.verdict, headers.hops[].authentication_results.dmarc, headers.hops[].authentication_results.dmarc_details.from.domain, headers.hops[].authentication_results.spf, sender.display_name, sender.email.domain.domain, sender.email.domain.root_domain, type.inbound. Sensors: ml.nlu_classifier. Reference lists: $alexa_1m, $free_file_hosts, $free_subdomain_hosts, $org_display_names, $org_domains, $recipient_domains, $social_landing_hosts, $tranco_1m, $url_shorteners.

Indicators matched (5)

FieldMatchValue
headers.hops[].authentication_results.dmarcequalsnone
headers.hops[].authentication_results.spfequalsnone
headers.hops[].authentication_results.compauth.verdictmemberpass
headers.hops[].authentication_results.compauth.verdictmembersoftpass
ml.nlu_classifier(body.current_thread.text).intents[].confidenceequalshigh