Detection rules › Sublime MQL

Link: Display text matches subject line

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

Message with short body text contains a single link where the display text matches the subject line. The link is deceptive and the recipient patterns are unusual, such as the recipient's address appearing in the body or undisclosed recipients being used.

Threat classification

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

CategoryValues
Attack typesBEC/Fraud, Credential Phishing
Tactics and techniquesSocial engineering, Evasion

Event coverage

Rule body MQL

type.inbound

// short body
and length(body.current_thread.text) < 1500

// suspicious recipient patterns
and (
  // recipient email is contained within the body
  (
    length(recipients.to) == 1
    and all(recipients.to,
            strings.icontains(body.current_thread.text, .email.email)
    )
  )
  // the sender is the recipient
  or sender.email.email in map(recipients.to, .email.email)
  // none of the recipients are valid (generally undisclosed recipients)
  or not all(recipients.to, .email.domain.valid)
)
// few overall links
and length(body.links) < 10
// none of the links are unsubscribe links
and not any(body.links,
            strings.icontains(.display_text, 'unsub')
            or strings.icontains(.href_url.url, 'unsub')
            or strings.icontains(.display_text, 'optout')
            or strings.icontains(.href_url.url, 'optout')
            or strings.icontains(.display_text, 'subscription')
            // google confidential email use the subject as a link
            or .href_url.domain.domain == "confidential-mail.google.com"
)

// even fewer links which are
and 0 < length(filter(body.links,
                      // not related to the sender domain
                      .href_url.domain.root_domain != sender.email.domain.root_domain
                      // not related to the recipient domain
                      and not any(recipients.to,
                                  .email.domain.root_domain == ..href_url.domain.root_domain
                      )
                      // filter out links common in signatures
                      and not .href_url.domain.root_domain in (
                        "facebook.com",
                        "instagram.com",
                        'twitter.com',
                        'x.com'
                      )
                      // do not contain a display_text (TP samples have the display_text of the subject)
                      // // this removes domains found in signatures
                      and .display_text is not null
                      // not the aka.ms in warning banners
                      and not .href_url.domain.domain == "aka.ms"
               )
) <= 3

// exactly one link with display text that matches the subject
and length(filter(body.links, subject.subject =~ .display_text)) == 1
and (
  // the link with the display_text of the subject
  any(filter(body.links, subject.subject =~ .display_text),
      // when visited is phishing
      ml.link_analysis(.).credphish.disposition == "phishing"
      or ml.link_analysis(.).final_dom.display_text == "Verify you are human"
      or .href_url.domain.root_domain in $self_service_creation_platform_domains
      or .href_url.domain.domain in $self_service_creation_platform_domains
      or .href_url.domain.domain in $url_shorteners
  )
  // or the body is cred_theft
  or any(ml.nlu_classifier(body.current_thread.text).intents,
         .name == "cred_theft"
  )
)

// the display text of a link is the subject
and subject.subject in map(body.links, .display_text)

// exclude common in signup links/password resets which are observed in links all the time
and not (
  strings.icontains(subject.subject, 'confirm')
  or strings.icontains(subject.subject, 'activate')
  or strings.icontains(subject.subject, 'reset')
  or strings.icontains(subject.subject, 'unlock')
  or strings.icontains(subject.subject, 'login')
  or strings.icontains(subject.subject, 'log in')
)

Detection logic

Scope: inbound message.

Message with short body text contains a single link where the display text matches the subject line. The link is deceptive and the recipient patterns are unusual, such as the recipient's address appearing in the body or undisclosed recipients being used.

  1. inbound message
  2. length(body.current_thread.text) < 1500
  3. any of:
    • all of:
      • length(recipients.to) is 1
      • all of recipients.to where:
        • strings.icontains(body.current_thread.text)
    • sender.email.email in map(recipients.to, .email.email)
    • not:
      • all of recipients.to where:
        • .email.domain.valid
  4. length(body.links) < 10
  5. not:
    • any of body.links where any holds:
      • .display_text contains 'unsub'
      • .href_url.url contains 'unsub'
      • .display_text contains 'optout'
      • .href_url.url contains 'optout'
      • .display_text contains 'subscription'
      • .href_url.domain.domain is 'confidential-mail.google.com'
  6. all of:
    • length(filter(body.links, .href_url.domain.root_domain != sender.email.domain.root_domain and not any(recipients.to, .email.domain.root_domain == ..href_url.domain.root_domain) and not .href_url.domain.root_domain in ('facebook.com', 'instagram.com', 'twitter.com', 'x.com') and .display_text is not null and not .href_url.domain.domain == 'aka.ms')) > 0
    • length(filter(body.links, .href_url.domain.root_domain != sender.email.domain.root_domain and not any(recipients.to, .email.domain.root_domain == ..href_url.domain.root_domain) and not .href_url.domain.root_domain in ('facebook.com', 'instagram.com', 'twitter.com', 'x.com') and .display_text is not null and not .href_url.domain.domain == 'aka.ms')) ≤ 3
  7. length(filter(body.links, subject.subject =~ .display_text)) is 1
  8. any of:
    • any of filter(body.links) where any holds:
      • ml.link_analysis(.).credphish.disposition is 'phishing'
      • ml.link_analysis(.).final_dom.display_text is 'Verify you are human'
      • .href_url.domain.root_domain in $self_service_creation_platform_domains
      • .href_url.domain.domain in $self_service_creation_platform_domains
      • .href_url.domain.domain in $url_shorteners
    • any of ml.nlu_classifier(body.current_thread.text).intents where:
      • .name is 'cred_theft'
  9. subject.subject in map(body.links, .display_text)
  10. none of:
    • subject.subject contains 'confirm'
    • subject.subject contains 'activate'
    • subject.subject contains 'reset'
    • subject.subject contains 'unlock'
    • subject.subject contains 'login'
    • subject.subject contains 'log in'

Inspects: body.current_thread.text, body.links, body.links[].display_text, body.links[].href_url.domain.domain, body.links[].href_url.domain.root_domain, body.links[].href_url.url, recipients.to, recipients.to[].email.domain.root_domain, recipients.to[].email.domain.valid, recipients.to[].email.email, sender.email.domain.root_domain, sender.email.email, subject.subject, type.inbound. Sensors: ml.link_analysis, ml.nlu_classifier, strings.icontains. Reference lists: $self_service_creation_platform_domains, $url_shorteners.

Indicators matched (16)

FieldMatchValue
strings.icontainssubstringunsub
strings.icontainssubstringoptout
strings.icontainssubstringsubscription
body.links[].href_url.domain.domainequalsconfidential-mail.google.com
body.links[].href_url.domain.root_domainmemberfacebook.com
body.links[].href_url.domain.root_domainmemberinstagram.com
body.links[].href_url.domain.root_domainmembertwitter.com
body.links[].href_url.domain.root_domainmemberx.com
body.links[].href_url.domain.domainequalsaka.ms
ml.nlu_classifier(body.current_thread.text).intents[].nameequalscred_theft
strings.icontainssubstringconfirm
strings.icontainssubstringactivate
4 more
strings.icontainssubstringreset
strings.icontainssubstringunlock
strings.icontainssubstringlogin
strings.icontainssubstringlog in