Detection rules › Sublime MQL

Display name impersonation using recipient SLD

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

The recipient domain's SLD is used in the sender's display name in order to impersonate the organization.

Threat classification

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

CategoryValues
Attack typesCredential Phishing
Tactics and techniquesSocial engineering

Event coverage

Rule body MQL

type.inbound
and (
  // recipient SLD is being impersonated in the display name
  (
    // these are usually targeted with just 1 recipient,
    // but sometimes they CC themselves or have a blank CC
    length(recipients.to) + length(recipients.cc)
 + length(recipients.bcc) <= 2
    and any(recipients.to,
            length(.email.domain.sld) >= 4
            and 
            // ensure that we're checking the org SLD
            .email.domain.sld in $org_slds
            and strings.icontains(sender.display_name, .email.domain.sld)
    )
  )
  or (
    // accounts for BCC'd messages where the recipients are empty
    // if BCC, sometimes the recipient will be the attacker's email
    length(recipients.to) + length(recipients.cc)
 + length(recipients.bcc) <= 2
    and length(mailbox.email.domain.sld) >= 4
    and strings.icontains(sender.display_name, mailbox.email.domain.sld)
  )
)
and (
  // at least 1 link or non-image attachment
  (
    length(body.links) > 0
    // these attacks all use compromosed senders, so we look for a domain
    // that doesn't match the sender's domain to weed out legit messages
    and any(body.links,
            .href_url.domain.root_domain != sender.email.domain.root_domain
    )
  )
  or length(filter(attachments, .file_type not in $file_types_images)) > 0
)
and not (
  strings.contains(sender.display_name, "on behalf of")
  and sender.email.domain.root_domain == "microsoftonline.com"
)
// negate pageproof updates and visit notifications
and not (sender.email.email in ("team@pageproof.com", "noreply@visitly.io"))
and all(recipients.to,
        .email.email != sender.email.email
        and (
          .email.domain.valid or strings.icontains(.display_name, "undisclosed")
        )
)

// negate org domain senders, which can often be misconfigured and fail
// authentication, causing them to be type.inbound instead of type.internal.
// this is fine because we should catch spoofs in other ways.
// also, we use root_domain here to account for subdomains used by internal tools that aren't connected to the tenant.
// this should also be safe because domains like onmicrosoft[.]com are tracked as FQDNs in $org_domains, so they won't match
and sender.email.domain.root_domain not in $org_domains
// negate tenant_domains
and not (
  sender.email.domain.domain in $tenant_domains
  and headers.auth_summary.dmarc.pass
)

// 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().solicited)
  or (
    profile.by_sender().any_messages_malicious_or_spam
    and not profile.by_sender().any_messages_benign
  )
)
and not profile.by_sender().any_messages_benign

Detection logic

Scope: inbound message.

The recipient domain's SLD is used in the sender's display name in order to impersonate the organization.

  1. inbound message
  2. any of:
    • all of:
      • length(recipients.to) + length(recipients.cc) + length(recipients.bcc) ≤ 2
      • any of recipients.to where all hold:
        • length(.email.domain.sld) ≥ 4
        • .email.domain.sld in $org_slds
        • strings.icontains(sender.display_name)
    • all of:
      • length(recipients.to) + length(recipients.cc) + length(recipients.bcc) ≤ 2
      • length(mailbox.email.domain.sld) ≥ 4
      • strings.icontains(sender.display_name)
  3. any of:
    • all of:
      • length(body.links) > 0
      • any of body.links where:
        • .href_url.domain.root_domain is not sender.email.domain.root_domain
    • length(filter(attachments, .file_type not in $file_types_images)) > 0
  4. not:
    • all of:
      • sender.display_name contains 'on behalf of'
      • sender.email.domain.root_domain is 'microsoftonline.com'
  5. not:
    • sender.email.email in ('team@pageproof.com', 'noreply@visitly.io')
  6. all of recipients.to where all hold:
    • .email.email is not sender.email.email
    • any of:
      • .email.domain.valid
      • .display_name contains 'undisclosed'
  7. sender.email.domain.root_domain not in $org_domains
  8. not:
    • all of:
      • sender.email.domain.domain in $tenant_domains
      • headers.auth_summary.dmarc.pass
  9. 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
  10. any of:
    • not:
      • profile.by_sender().solicited
    • all of:
      • profile.by_sender().any_messages_malicious_or_spam
      • not:
        • profile.by_sender().any_messages_benign
  11. not:
    • profile.by_sender().any_messages_benign

Inspects: attachments[].file_type, body.links, body.links[].href_url.domain.root_domain, headers.auth_summary.dmarc.pass, mailbox.email.domain.sld, recipients.to, recipients.to[].display_name, recipients.to[].email.domain.sld, recipients.to[].email.domain.valid, recipients.to[].email.email, sender.display_name, sender.email.domain.domain, sender.email.domain.root_domain, sender.email.email, type.inbound. Sensors: profile.by_sender, strings.contains, strings.icontains. Reference lists: $file_types_images, $high_trust_sender_root_domains, $org_domains, $org_slds, $tenant_domains.

Indicators matched (5)

FieldMatchValue
strings.containssubstringon behalf of
sender.email.domain.root_domainequalsmicrosoftonline.com
sender.email.emailmemberteam@pageproof.com
sender.email.emailmembernoreply@visitly.io
strings.icontainssubstringundisclosed