Detection rules › Sublime MQL

Free email provider sender with mismatched provider reply-to

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

Detects when a sender using a free email provider includes a reply-to address from a different free email provider, which is a common social engineering tactic.

Threat classification

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

CategoryValues
Attack typesBEC/Fraud, Credential Phishing
Tactics and techniquesFree email provider, Social engineering

Event coverage

Rule body MQL

type.inbound
and sender.email.domain.root_domain in $free_email_providers
and length(headers.reply_to) > 0
and any(headers.reply_to,
        .email.domain.root_domain in $free_email_providers
        and .email.domain.root_domain != sender.email.domain.root_domain
        and .email.domain.root_domain not in ("googlegroups.com")
)
// secureserver.net seems to rewrite the sender local part to be the reply-to domain for bounces
// observed in many newsletter sent via secureserver.net
and not (
  strings.istarts_with(sender.email.domain.domain, 'bounces.')
  and sender.email.domain.root_domain == 'secureserver.net'
  and all(headers.reply_to,
          strings.istarts_with(sender.email.local_part, .email.local_part)
          and strings.iends_with(sender.email.local_part, .email.domain.domain)
  )
)
// lists.riseup.net send from the list address and use the reply-to of the sender
// the sender is within the X-Original-From header and contains the full "From" header
and not (
  sender.email.domain.domain == "lists.riseup.net"
  and any(headers.hops,
          any(.fields,
              .name =~ "X-Original-From"
              and any(headers.reply_to,
                      strings.icontains(..value, .email.email)
              )
          )
  )
)

Detection logic

Scope: inbound message.

Detects when a sender using a free email provider includes a reply-to address from a different free email provider, which is a common social engineering tactic.

  1. inbound message
  2. sender.email.domain.root_domain in $free_email_providers
  3. length(headers.reply_to) > 0
  4. any of headers.reply_to where all hold:
    • .email.domain.root_domain in $free_email_providers
    • .email.domain.root_domain is not sender.email.domain.root_domain
    • .email.domain.root_domain not in ('googlegroups.com')
  5. not:
    • all of:
      • sender.email.domain.domain starts with 'bounces.'
      • sender.email.domain.root_domain is 'secureserver.net'
      • all of headers.reply_to where all hold:
        • strings.istarts_with(sender.email.local_part)
        • strings.iends_with(sender.email.local_part)
  6. not:
    • all of:
      • sender.email.domain.domain is 'lists.riseup.net'
      • any of headers.hops where:
        • any of .fields where all hold:
          • .name is 'X-Original-From'
          • any of headers.reply_to where:
            • strings.icontains(.value)

Inspects: headers.hops, headers.hops[].fields, headers.hops[].fields[].name, headers.hops[].fields[].value, headers.reply_to, headers.reply_to[].email.domain.domain, headers.reply_to[].email.domain.root_domain, headers.reply_to[].email.email, headers.reply_to[].email.local_part, sender.email.domain.domain, sender.email.domain.root_domain, sender.email.local_part, type.inbound. Sensors: strings.icontains, strings.iends_with, strings.istarts_with. Reference lists: $free_email_providers.

Indicators matched (5)

FieldMatchValue
headers.reply_to[].email.domain.root_domainmembergooglegroups.com
strings.istarts_withprefixbounces.
sender.email.domain.root_domainequalssecureserver.net
sender.email.domain.domainequalslists.riseup.net
headers.hops[].fields[].nameequalsX-Original-From