Detection rules › Sublime MQL

Inbound message from popular service via newly observed distribution list

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

Detects when a message comes through a distribution list by matching on return paths containing Sender Rewrite Scheme (SRS) from a previously unknown domain sender to a single recipient who has never interacted with the organization. This method has been observed being abused by threat actors to deliver callback phishing.

Threat classification

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

CategoryValues
Attack typesCallback Phishing
Tactics and techniquesEvasion, Social engineering

Event coverage

Rule body MQL

type.inbound
and length(recipients.to) == 1
and length(recipients.bcc) == 0
// abuse involves a popular service
and sender.email.domain.root_domain in $tranco_50k

// message is not from a free mail provider, we have only observed sevice providers abused
and sender.email.domain.root_domain not in $free_email_providers
and sender.email.domain.domain not in $free_email_providers
and not any(recipients.to, .email.email =~ sender.email.email)

// uses Sender Rewrite Scheme indicating the message traversed a distribtion list or other automatic relay
and (
  strings.icontains(headers.return_path.local_part, "+SRS=")
  // when the receipient is a group controlled by the final recipient
  // the return_path header can be overwritten
  // check the SPF designator for evidence of SRS 
  or strings.icontains(headers.auth_summary.spf.details.designator, "+SRS=")
  or any(headers.hops,
         strings.icontains(.authentication_results.spf_details.designator,
                           '+SRS='
         )
  )
)
// the sender and recipient is not in $org_domains
and sender.email.domain.domain not in $org_domains
// the recipient has never sent an email to the org
and all(recipients.to,
        .email.domain.domain not in $org_domains
        // ensure the recipient domain has never send/received an email to/from the org
        and (
          (
            // use the domain only if the sender domain is not within free_email_providers
            .email.domain.domain not in $free_email_providers
            and .email.domain.root_domain not in $free_email_providers
            and .email.domain.domain not in $sender_domains
            and .email.domain.root_domain not in $sender_domains
            and .email.domain.domain not in $recipient_domains
            and .email.domain.root_domain not in $recipient_domains
          )
          or (
            // use the email address the sender domain is within free_email_providers
            (
              .email.domain.domain in $free_email_providers
              or .email.domain.root_domain in $free_email_providers
            )
            and .email.email not in $sender_emails
            and .email.email not in $recipient_emails
          )
          or (
            .email.domain.root_domain in ("onmicrosoft.com")
            // negate onmicrosoft domains within org_domains
            and not .email.domain.domain in $org_domains
          )
        )
)
// if there are reply-to addresses, ensure they are also not assoicated with the org
and all(headers.reply_to,
        .email.domain.domain not in $org_domains
        and .display_name not in $org_display_names
)

// check the return path to ensure it's not related to our sender or the mailbox at all
and not strings.iends_with(headers.return_path.local_part,
                           strings.concat('@', sender.email.domain.domain)
)
and not strings.icontains(headers.return_path.local_part,
                          mailbox.email.local_part
)

// not an inbox rule or automatic forward from a Microsoft Account
and not any(headers.hops,
            any(.fields,
                .name in~ (
                  'X-MS-Exchange-ForwardingLoop',
                  'X-MS-Exchange-Inbox-Rules-Loop'
                )
            )
)

Detection logic

Scope: inbound message.

Detects when a message comes through a distribution list by matching on return paths containing Sender Rewrite Scheme (SRS) from a previously unknown domain sender to a single recipient who has never interacted with the organization. This method has been observed being abused by threat actors to deliver callback phishing.

  1. inbound message
  2. length(recipients.to) is 1
  3. length(recipients.bcc) is 0
  4. sender.email.domain.root_domain in $tranco_50k
  5. sender.email.domain.root_domain not in $free_email_providers
  6. sender.email.domain.domain not in $free_email_providers
  7. not:
    • any of recipients.to where:
      • .email.email is sender.email.email
  8. any of:
    • headers.return_path.local_part contains '+SRS='
    • headers.auth_summary.spf.details.designator contains '+SRS='
    • any of headers.hops where:
      • .authentication_results.spf_details.designator contains '+SRS='
  9. sender.email.domain.domain not in $org_domains
  10. all of recipients.to where all hold:
    • .email.domain.domain not in $org_domains
    • any of:
      • all of:
        • .email.domain.domain not in $free_email_providers
        • .email.domain.root_domain not in $free_email_providers
        • .email.domain.domain not in $sender_domains
        • .email.domain.root_domain not in $sender_domains
        • .email.domain.domain not in $recipient_domains
        • .email.domain.root_domain not in $recipient_domains
      • all of:
        • any of:
          • .email.domain.domain in $free_email_providers
          • .email.domain.root_domain in $free_email_providers
        • .email.email not in $sender_emails
        • .email.email not in $recipient_emails
      • all of:
        • .email.domain.root_domain in ('onmicrosoft.com')
        • not:
          • .email.domain.domain in $org_domains
  11. all of headers.reply_to where all hold:
    • .email.domain.domain not in $org_domains
    • .display_name not in $org_display_names
  12. not:
    • strings.iends_with(headers.return_path.local_part)
  13. not:
    • strings.icontains(headers.return_path.local_part)
  14. not:
    • any of headers.hops where:
      • any of .fields where:
        • .name in ('X-MS-Exchange-ForwardingLoop', 'X-MS-Exchange-Inbox-Rules-Loop')

Inspects: headers.auth_summary.spf.details.designator, headers.hops, headers.hops[].authentication_results.spf_details.designator, headers.hops[].fields, headers.hops[].fields[].name, headers.reply_to, headers.reply_to[].display_name, headers.reply_to[].email.domain.domain, headers.return_path.local_part, mailbox.email.local_part, recipients.bcc, recipients.to, recipients.to[].email.domain.domain, recipients.to[].email.domain.root_domain, recipients.to[].email.email, sender.email.domain.domain, sender.email.domain.root_domain, sender.email.email, type.inbound. Sensors: strings.concat, strings.icontains, strings.iends_with. Reference lists: $free_email_providers, $org_display_names, $org_domains, $recipient_domains, $recipient_emails, $sender_domains, $sender_emails, $tranco_50k.

Indicators matched (4)

FieldMatchValue
strings.icontainssubstring+SRS=
recipients.to[].email.domain.root_domainmemberonmicrosoft.com
headers.hops[].fields[].namememberX-MS-Exchange-ForwardingLoop
headers.hops[].fields[].namememberX-MS-Exchange-Inbox-Rules-Loop