Detection rules › Sublime MQL

Sublime MQL rules: unrelated

Sharepoint link likely unrelated to sender

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

Detects when a sender links to a Sharepoint file where the subdomain significantly differs from the sender's domain. The rule checks for OneNote, PDF, or unknown file types and includes various domain validation checks.

Threat classification

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

CategoryValues
Attack typesBEC/Fraud, Credential Phishing
Tactics and techniquesImpersonation: Employee, Lookalike domain, OneNote, PDF, Social engineering

Telemetry coverage

PlatformRecord / event type
SublimeInbound email message

Message attributes

  • body
  • body.html
  • body.links
  • headers
  • headers.auth_summary
  • sender.email
  • type

Rule body

type.inbound
and any(beta.ml_topic(body.html.display_text).topics,
        .name == "File Sharing and Cloud Services" and .confidence == "high"
)
and 0 < length(body.links) < 10
and length(body.html.display_text) < 2000
and any(filter(body.links, .href_url.domain.root_domain == 'sharepoint.com'),
        // Normalize Levenshtein distance by string length (0 = identical, 0.7+ = different)
        // Working with what we have in MQL, considering we dont have max() or any other forms of string distancing
        (
          (
            strings.iends_with(.href_url.domain.subdomain,
                               '-my'
            ) // common Sharepoint subdomain suffix
            and (
              (
                strings.ilevenshtein(.href_url.domain.subdomain,
                                     sender.email.domain.sld
                ) - 3 // subtract aforementioned suffix for more accurate calculation
              ) / (
                (
                  (length(.href_url.domain.subdomain) - 3) + length(sender.email.domain.sld
                  )
 + (
                    (
                      (length(.href_url.domain.subdomain) - 3) - length(sender.email.domain.sld
                      )
                    ) + (
                      length(sender.email.domain.sld) - (
                        length(.href_url.domain.subdomain) - 3
                      )
                    )
                  )
                ) / 2.0 // to ensure we keep the result as a float
              )
            ) > 0.7 // customizable threshold
          )
          or (
            not strings.iends_with(.href_url.domain.subdomain,
                                   '-my'
            ) // no suffix, continue with original calculation
            and (
              strings.ilevenshtein(.href_url.domain.subdomain,
                                   sender.email.domain.sld
              ) / (
                (
                  length(.href_url.domain.subdomain) + length(sender.email.domain.sld
                  )
 + (
                    (
                      length(.href_url.domain.subdomain) - length(sender.email.domain.sld
                      )
                    ) + (
                      length(sender.email.domain.sld) - length(.href_url.domain.subdomain
                      )
                    )
                  )
                ) / 2.0 // to ensure we keep the result as a float
              )
            ) > 0.7 // customizable threshold
          )
        )
        and not strings.icontains(.href_url.path, sender.email.local_part)
        and not any($org_slds,
                    strings.icontains(..href_url.domain.subdomain, .)
        )

        // it is either a OneNote or PDF file, or unknown
        and regex.icontains(.href_url.path, '\/:[obu]:\/(?:p|g\/personal)')
)

// a way to negate long threads
// the full thread must be less than 6 times the length of the current thread
and length(body.html.inner_text) < 6 * length(body.current_thread.text)
and sender.email.domain.root_domain not in (
  "sharepoint.com",
  "sharepointonline.com"
)

// 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
)

Detection logic

Scope: inbound message.

Detects when a sender links to a Sharepoint file where the subdomain significantly differs from the sender's domain. The rule checks for OneNote, PDF, or unknown file types and includes various domain validation checks.

  1. inbound message
  2. any of beta.ml_topic(body.html.display_text).topics where all hold:
    • .name is 'File Sharing and Cloud Services'
    • .confidence is 'high'
  3. all of:
    • length(body.links) > 0
    • length(body.links) < 10
  4. length(body.html.display_text) < 2000
  5. any of filter(body.links) where all hold:
    • any of:
      • all of:
        • .href_url.domain.subdomain ends with '-my'
        • strings.ilevenshtein(.href_url.domain.subdomain) - 3 / length(.href_url.domain.subdomain) - 3 + length(sender.email.domain.sld) + length(.href_url.domain.subdomain) - 3 - length(sender.email.domain.sld) + length(sender.email.domain.sld) - length(.href_url.domain.subdomain) - 3 / 2.0 > 0.7
      • all of:
        • not:
          • .href_url.domain.subdomain ends with '-my'
        • strings.ilevenshtein(.href_url.domain.subdomain) / length(.href_url.domain.subdomain) + length(sender.email.domain.sld) + length(.href_url.domain.subdomain) - length(sender.email.domain.sld) + length(sender.email.domain.sld) - length(.href_url.domain.subdomain) / 2.0 > 0.7
    • not:
      • strings.icontains(.href_url.path)
    • not:
      • any of $org_slds where:
        • strings.icontains(.href_url.domain.subdomain)
    • .href_url.path matches '\\/:[obu]:\\/(?:p|g\\/personal)'
  6. length(body.html.inner_text) < 6 * length(body.current_thread.text)
  7. sender.email.domain.root_domain not in ('sharepoint.com', 'sharepointonline.com')
  8. 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

Inspects: body.html.display_text, body.html.inner_text, body.links, body.links[].href_url.domain.root_domain, headers.auth_summary.dmarc.pass, sender.email.domain.root_domain, sender.email.local_part, type.inbound. Sensors: beta.ml_topic, regex.icontains, strings.icontains, strings.iends_with. Reference lists: $high_trust_sender_root_domains, $org_slds.

Indicators matched (5)

FieldMatchValue
beta.ml_topic(body.html.display_text).topics[].nameequalsFile Sharing and Cloud Services
beta.ml_topic(body.html.display_text).topics[].confidenceequalshigh
body.links[].href_url.domain.root_domainequalssharepoint.com
strings.iends_withsuffix-my
regex.icontainsregex\/:[obu]:\/(?:p|g\/personal)

Stages and Predicates

Stage 1: mql_rule

and
  any(filter(body.links))
    and
      or
        and
          not
            filter(body.links).href_url.domain.subdomain ends_with "-my"
           macro "(strings.ilevenshtein(filter(body.links)[].href_url.domain.subdomain) / (((length(filter(body.links)[].href_url.domain.subdomain) + length(sender.email.domain.sld)) + ((length(filter(body.links)[].href_url.domain.subdomain) - length(sender.email.domain.sld)) + (length(sender.email.domain.sld) - length(filter(body.links)[].href_url.domain.subdomain)))) / 2.0)) > 0.7"
        and
          filter(body.links).href_url.domain.subdomain ends_with "-my"
           macro "((strings.ilevenshtein(filter(body.links)[].href_url.domain.subdomain) - 3) / ((((length(filter(body.links)[].href_url.domain.subdomain) - 3) + length(sender.email.domain.sld)) + (((length(filter(body.links)[].href_url.domain.subdomain) - 3) - length(sender.email.domain.sld)) + (length(sender.email.domain.sld) - (length(filter(body.links)[].href_url.domain.subdomain) - 3)))) / 2.0)) > 0.7"
      not
        any($org_slds)
          strings.icontains func_call "strings.icontains(filter(body.links)[].href_url.domain.subdomain)"
      not
        strings.icontains func_call "strings.icontains(filter(body.links)[].href_url.path)"
      filter(body.links).href_url.path regex_match "\\/:[obu]:\\/(?:p|g\\/personal)"
  or
    and
      not
        headers.auth_summary.dmarc.pass eq "true"
       macro "sender.email.domain.root_domain in high_trust_sender_root_domains"
     macro "sender.email.domain.root_domain not in high_trust_sender_root_domains"
  any(beta.ml_topic(body.html.display_text).topics)
    and
      beta.ml_topic(body.html.display_text).topics.confidence eq "high"
      beta.ml_topic(body.html.display_text).topics.name eq "File Sharing and Cloud Services"
  not
    sender.email.domain.root_domain in ["sharepoint.com", "sharepointonline.com"]
  body.html.display_text length_compare "2000"
  body.links length_compare "0"
  body.links length_compare "10"
  type.inbound eq "true"
   macro "length(body.html.inner_text) < (6 * length(body.current_thread.text))"

Exclusions

The rule actively suppresses these predicates.

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
type.inboundeq
  • true transforms: boolean
field:"type.inbound" kind:eq value:"true"