Detection rules › Sublime MQL

Sublime MQL rules: callback

Brand impersonation: GitHub with callback scam indicators

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

Detects messages using GitHub's noreply address that contain callback scam language, brand impersonation tactics, or fraudulent purchase/payment content with phone numbers for victim contact.

Threat classification

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

CategoryValues
Attack typesCallback Phishing
Tactics and techniquesImpersonation: Brand, Out of band pivot, Social engineering

Telemetry coverage

PlatformRecord / event type
SublimeInbound email message

Message attributes

  • body
  • body.current_thread
  • sender.email
  • subject
  • type

Rule body

type.inbound
and sender.email.email == 'noreply@github.com'
and length(attachments) == 0
and (
  any(ml.nlu_classifier(body.current_thread.text).intents,
      .name == "callback_scam" and .confidence != "low"
  )
  or (
    regex.icontains(body.current_thread.text,
                    (
                      "mcafee|n[o0]rt[o0]n|geek.{0,5}squad|paypal|ebay|symantec|best buy|lifel[o0]ck"
                    )
    )
    and (
      3 of (
        strings.ilike(body.current_thread.text, '*purchase*'),
        strings.ilike(body.current_thread.text, '*payment*'),
        strings.ilike(body.current_thread.text, '*transaction*'),
        strings.ilike(body.current_thread.text, '*subscription*'),
        strings.ilike(body.current_thread.text, '*antivirus*'),
        strings.ilike(body.current_thread.text, '*order*'),
        strings.ilike(body.current_thread.text, '*support*'),
        strings.ilike(body.current_thread.text, '*receipt*'),
        strings.ilike(body.current_thread.text, '*invoice*'),
        strings.ilike(body.current_thread.text, '*call*'),
        strings.ilike(body.current_thread.text, '*cancel*'),
        strings.ilike(body.current_thread.text, '*renew*'),
        strings.ilike(body.current_thread.text, '*refund*'),
        strings.ilike(body.current_thread.text, '*host key*')
      )
    )
    // phone number regex
    and any([body.current_thread.text, subject.subject],
            regex.icontains(.,
                            '\+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4}',
                            '\+?([ilo0-9]{1,2})?\s?\(?\d{3}\)?[\s\.\-⋅]{0,5}[ilo0-9]{3}[\s\.\-⋅]{0,5}[ilo0-9]{4}'
            )
    )
  )
)

Detection logic

Scope: inbound message.

Detects messages using GitHub's noreply address that contain callback scam language, brand impersonation tactics, or fraudulent purchase/payment content with phone numbers for victim contact.

  1. inbound message
  2. sender.email.email is 'noreply@github.com'
  3. length(attachments) is 0
  4. any of:
    • any of ml.nlu_classifier(body.current_thread.text).intents where all hold:
      • .name is 'callback_scam'
      • .confidence is not 'low'
    • all of:
      • body.current_thread.text matches 'mcafee|n[o0]rt[o0]n|geek.{0,5}squad|paypal|ebay|symantec|best buy|lifel[o0]ck'
      • at least 3 of 14: body.current_thread.text matches any of 14 patterns
        • *purchase*
        • *payment*
        • *transaction*
        • *subscription*
        • *antivirus*
        • *order*
        • *support*
        • *receipt*
        • *invoice*
        • *call*
        • *cancel*
        • *renew*
        • *refund*
        • *host key*
      • any of [body.current_thread.text, subject.subject] where:
        • . matches any of 2 patterns
          • \+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4}
          • \+?([ilo0-9]{1,2})?\s?\(?\d{3}\)?[\s\.\-⋅]{0,5}[ilo0-9]{3}[\s\.\-⋅]{0,5}[ilo0-9]{4}

Inspects: body.current_thread.text, sender.email.email, subject.subject, type.inbound. Sensors: ml.nlu_classifier, regex.icontains, strings.ilike.

Indicators matched (19)

FieldMatchValue
sender.email.emailequalsnoreply@github.com
ml.nlu_classifier(body.current_thread.text).intents[].nameequalscallback_scam
regex.icontainsregexmcafee|n[o0]rt[o0]n|geek.{0,5}squad|paypal|ebay|symantec|best buy|lifel[o0]ck
strings.ilikesubstring*purchase*
strings.ilikesubstring*payment*
strings.ilikesubstring*transaction*
strings.ilikesubstring*subscription*
strings.ilikesubstring*antivirus*
strings.ilikesubstring*order*
strings.ilikesubstring*support*
strings.ilikesubstring*receipt*
strings.ilikesubstring*invoice*
7 more
strings.ilikesubstring*call*
strings.ilikesubstring*cancel*
strings.ilikesubstring*renew*
strings.ilikesubstring*refund*
strings.ilikesubstring*host key*
regex.icontainsregex\+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4}
regex.icontainsregex\+?([ilo0-9]{1,2})?\s?\(?\d{3}\)?[\s\.\-⋅]{0,5}[ilo0-9]{3}[\s\.\-⋅]{0,5}[ilo0-9]{4}

Stages and Predicates

Stage 1: mql_rule

and
  or
    and
      any([body.current_thread.text, subject.subject])
        or
          [body.current_thread.text, subject.subject] regex_match "\\+?([ilo0-9]{1,2})?\\s?\\(?\\d{3}\\)?[\\s\\.\\-⋅]{0,5}[ilo0-9]{3}[\\s\\.\\-⋅]{0,5}[ilo0-9]{4}"
          [body.current_thread.text, subject.subject] regex_match "\\+?([ilo0-9]{1}.)?\\(?[ilo0-9]{3}?\\)?.[ilo0-9]{3}.?[ilo0-9]{4}"
      or
        body.current_thread.text match "antivirus"
        body.current_thread.text match "call"
        body.current_thread.text match "cancel"
        body.current_thread.text match "host key"
        body.current_thread.text match "invoice"
        body.current_thread.text match "order"
        body.current_thread.text match "payment"
        body.current_thread.text match "purchase"
        body.current_thread.text match "receipt"
        body.current_thread.text match "refund"
        body.current_thread.text match "renew"
        body.current_thread.text match "subscription"
        body.current_thread.text match "support"
        body.current_thread.text match "transaction"
      body.current_thread.text regex_match "mcafee|n[o0]rt[o0]n|geek.{0,5}squad|paypal|ebay|symantec|best buy|lifel[o0]ck"
    any(ml.nlu_classifier(body.current_thread.text).intents)
      and
        ml.nlu_classifier(body.current_thread.text).intents.confidence ne "low"
        ml.nlu_classifier(body.current_thread.text).intents.name eq "callback_scam"
  attachments length_compare "0"
  sender.email.email eq "noreply@github.com"
  type.inbound eq "true"

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
body.current_thread.textregex_match
    • mcafee
    • n[o0]rt[o0]n
    • geek.{0,5}squad
    • paypal
    • ebay
    • symantec
    • best buy
    • lifel[o0]ck
field:"body.current_thread.text" kind:regex_match
body.current_thread.textwildcard
  • *antivirus*
  • *call*
  • *cancel*
  • *host key*
  • *invoice*
  • *order*
  • *payment*
  • *purchase*
  • *receipt*
  • *refund*
  • *renew*
  • *subscription*
  • *support*
  • *transaction*
field:"body.current_thread.text" kind:wildcard
sender.email.emaileq
  • noreply@github.com
field:"sender.email.email" kind:eq value:"noreply@github.com"
type.inboundeq
  • true transforms: boolean
field:"type.inbound" kind:eq value:"true"

Callback phishing in body or attachment (untrusted sender)

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

Detects callback scams by analyzing text within images of receipts or invoices from untrusted senders.

Threat classification

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

CategoryValues
Attack typesCallback Phishing
Tactics and techniquesOut of band pivot, Social engineering

Telemetry coverage

PlatformRecord / event type
SublimeInbound email message

Message attributes

  • attachments
  • body
  • body.current_thread
  • body.html
  • headers
  • headers.auth_summary
  • headers.domains
  • sender.email
  • type

Rule body

type.inbound
and length(attachments) < 5
and (
  any(attachments,
      (
        .file_type in $file_types_images
        or .file_type in ("pdf", "xlsx", "docx")
      )
      and (
        any(ml.nlu_classifier(beta.ocr(.).text).intents,
            .name == "callback_scam" and .confidence in ("medium", "high")
        )
        or any(file.explode(.),

               // exclude images taken with mobile cameras and screenshots from android
               not any(.scan.exiftool.fields,
                       .key == "Model"
                       or (
                         .key == "Software"
                         and strings.starts_with(.value, "Android")
                       )
                       or (.key == "UserComment" and .value == "Screenshot")
               )
               and any(ml.nlu_classifier(.scan.ocr.raw).intents,
                       .name == "callback_scam"
                       and .confidence in ("medium", "high")
               )
        )
      )
      and (
        // negate noreply unless a logo is found in the attachment
        (
          sender.email.local_part in ("no_reply", "noreply")
          and any(ml.logo_detect(.).brands,
                  .name in ("PayPal", "Norton", "GeekSquad", "Ebay", "McAfee")
          )
        )
        or sender.email.local_part not in ("no_reply", "noreply")
      )
  )
  or (
    any(ml.nlu_classifier(body.current_thread.text).intents,
        .name in ("callback_scam") and .confidence in ("medium", "high")
    )
    and (
      (
        270 < length(body.current_thread.text) < 1750
        or (
          75 < length(body.current_thread.text) < 1750
          and (
            strings.ilike(body.current_thread.text,
                          "*PayPal*",
                          "*Norton*",
                          "*GeekSquad*",
                          "*Ebay*",
                          "*McAfee*",
                          "*=1"
            )
            // phone number regex
            or regex.icontains(body.current_thread.text,
                               '\+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4}',
                               '\+?([ilo0-9]{1,2})?\s?\(?\d{3}\)?[\s\.\-⋅]{0,5}[ilo0-9]{3}[\s\.\-⋅]{0,5}[ilo0-9]{4}'
            )
            or 1 of (
              strings.icontains(beta.ocr(file.message_screenshot()).text,
                                "geek squad"
              ),
              strings.icontains(beta.ocr(file.message_screenshot()).text,
                                "lifelock"
              ),
              strings.icontains(beta.ocr(file.message_screenshot()).text,
                                "best buy"
              ),
              strings.icontains(beta.ocr(file.message_screenshot()).text,
                                "mcafee"
              ),
              strings.icontains(beta.ocr(file.message_screenshot()).text,
                                "norton"
              ),
              strings.icontains(beta.ocr(file.message_screenshot()).text,
                                "ebay"
              ),
              strings.icontains(beta.ocr(file.message_screenshot()).text,
                                "paypal"
              ),
              strings.icontains(beta.ocr(file.message_screenshot()).text,
                                "virus"
              ),
            )
          )
        )
      )
    )
  )
)
and not (
  any(headers.domains, .domain == "smtp-out.gcp.bigcommerce.net")
  and strings.icontains(body.html.raw, "bigcommerce.com")
)
and (
  not profile.by_sender_email().solicited
  or (
    profile.by_sender_email().any_messages_malicious_or_spam
    and not profile.by_sender_email().any_messages_benign
  )
)

// negate highly trusted sender domains unless they fail DMARC authentication
and not (
  sender.email.domain.root_domain in $high_trust_sender_root_domains
  and coalesce(headers.auth_summary.dmarc.pass, false)
)
// negate opsgenie email notifications
and not sender.email.email == 'opsgenie@opsgenie.net'

Detection logic

Scope: inbound message.

Detects callback scams by analyzing text within images of receipts or invoices from untrusted senders.

  1. inbound message
  2. length(attachments) < 5
  3. any of:
    • any of attachments where all hold:
      • any of:
        • .file_type in $file_types_images
        • .file_type in ('pdf', 'xlsx', 'docx')
      • any of:
        • any of ml.nlu_classifier(beta.ocr(.).text).intents where all hold:
          • .name is 'callback_scam'
          • .confidence in ('medium', 'high')
        • any of file.explode(.) where all hold:
          • not:
            • any of .scan.exiftool.fields where any holds:
              • .key is 'Model'
              • all of:
                • .key is 'Software'
                • .value starts with 'Android'
              • all of:
                • .key is 'UserComment'
                • .value is 'Screenshot'
          • any of ml.nlu_classifier(.scan.ocr.raw).intents where all hold:
            • .name is 'callback_scam'
            • .confidence in ('medium', 'high')
      • any of:
        • all of:
          • sender.email.local_part in ('no_reply', 'noreply')
          • any of ml.logo_detect(.).brands where:
            • .name in ('PayPal', 'Norton', 'GeekSquad', 'Ebay', 'McAfee')
        • sender.email.local_part not in ('no_reply', 'noreply')
    • all of:
      • any of ml.nlu_classifier(body.current_thread.text).intents where all hold:
        • .name in ('callback_scam')
        • .confidence in ('medium', 'high')
      • any of:
        • all of:
          • length(body.current_thread.text) > 270
          • length(body.current_thread.text) < 1750
        • all of:
          • all of:
            • length(body.current_thread.text) > 75
            • length(body.current_thread.text) < 1750
          • any of:
            • body.current_thread.text matches any of 6 patterns
              • *PayPal*
              • *Norton*
              • *GeekSquad*
              • *Ebay*
              • *McAfee*
              • *=1
            • body.current_thread.text matches any of 2 patterns
              • \+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4}
              • \+?([ilo0-9]{1,2})?\s?\(?\d{3}\)?[\s\.\-⋅]{0,5}[ilo0-9]{3}[\s\.\-⋅]{0,5}[ilo0-9]{4}
            • at least 1 of 8: beta.ocr(file.message_screenshot()).text contains any of 8 patterns
              • geek squad
              • lifelock
              • best buy
              • mcafee
              • norton
              • ebay
              • paypal
              • virus
  4. not:
    • all of:
      • any of headers.domains where:
        • .domain is 'smtp-out.gcp.bigcommerce.net'
      • body.html.raw contains 'bigcommerce.com'
  5. any of:
    • not:
      • profile.by_sender_email().solicited
    • all of:
      • profile.by_sender_email().any_messages_malicious_or_spam
      • not:
        • profile.by_sender_email().any_messages_benign
  6. not:
    • all of:
      • sender.email.domain.root_domain in $high_trust_sender_root_domains
      • coalesce(headers.auth_summary.dmarc.pass)
  7. not:
    • sender.email.email is 'opsgenie@opsgenie.net'

Inspects: attachments[].file_type, body.current_thread.text, body.html.raw, headers.auth_summary.dmarc.pass, headers.domains, headers.domains[].domain, sender.email.domain.root_domain, sender.email.email, sender.email.local_part, type.inbound. Sensors: beta.ocr, file.explode, file.message_screenshot, ml.logo_detect, ml.nlu_classifier, profile.by_sender_email, regex.icontains, strings.icontains, strings.ilike, strings.starts_with. Reference lists: $file_types_images, $high_trust_sender_root_domains.

Indicators matched (35)

FieldMatchValue
attachments[].file_typememberpdf
attachments[].file_typememberxlsx
attachments[].file_typememberdocx
ml.nlu_classifier(beta.ocr(attachments[]).text).intents[].nameequalscallback_scam
ml.nlu_classifier(beta.ocr(attachments[]).text).intents[].confidencemembermedium
ml.nlu_classifier(beta.ocr(attachments[]).text).intents[].confidencememberhigh
ml.nlu_classifier(file.explode(attachments[])[].scan.ocr.raw).intents[].nameequalscallback_scam
ml.nlu_classifier(file.explode(attachments[])[].scan.ocr.raw).intents[].confidencemembermedium
ml.nlu_classifier(file.explode(attachments[])[].scan.ocr.raw).intents[].confidencememberhigh
sender.email.local_partmemberno_reply
sender.email.local_partmembernoreply
ml.logo_detect(attachments[]).brands[].namememberPayPal
23 more
ml.logo_detect(attachments[]).brands[].namememberNorton
ml.logo_detect(attachments[]).brands[].namememberGeekSquad
ml.logo_detect(attachments[]).brands[].namememberEbay
ml.logo_detect(attachments[]).brands[].namememberMcAfee
ml.nlu_classifier(body.current_thread.text).intents[].namemembercallback_scam
ml.nlu_classifier(body.current_thread.text).intents[].confidencemembermedium
ml.nlu_classifier(body.current_thread.text).intents[].confidencememberhigh
strings.ilikesubstring*PayPal*
strings.ilikesubstring*Norton*
strings.ilikesubstring*GeekSquad*
strings.ilikesubstring*Ebay*
strings.ilikesubstring*McAfee*
strings.ilikesubstring*=1
regex.icontainsregex\+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4}
regex.icontainsregex\+?([ilo0-9]{1,2})?\s?\(?\d{3}\)?[\s\.\-⋅]{0,5}[ilo0-9]{3}[\s\.\-⋅]{0,5}[ilo0-9]{4}
strings.icontainssubstringgeek squad
strings.icontainssubstringlifelock
strings.icontainssubstringbest buy
strings.icontainssubstringmcafee
strings.icontainssubstringnorton
strings.icontainssubstringebay
strings.icontainssubstringpaypal
strings.icontainssubstringvirus

Stages and Predicates

Stage 1: mql_rule

and
  or
    any(attachments)
      and
        or
          any(file.explode(attachments))
            and
              not
                any(file.explode(attachments).scan.exiftool.fields)
                  or
                    and
                      file.explode(attachments[])[].scan.exiftool.fields[].key eq "Software"
                      file.explode(attachments[])[].scan.exiftool.fields[].value starts_with "Android"
                    and
                      file.explode(attachments[])[].scan.exiftool.fields[].key eq "UserComment"
                      file.explode(attachments[])[].scan.exiftool.fields[].value eq "Screenshot"
                    file.explode(attachments[])[].scan.exiftool.fields[].key eq "Model"
              any(ml.nlu_classifier(file.explode(attachments).scan.ocr.raw).intents)
                and
                  ml.nlu_classifier(file.explode(attachments[])[].scan.ocr.raw).intents[].confidence in ["high", "medium"]
                  ml.nlu_classifier(file.explode(attachments[])[].scan.ocr.raw).intents[].name eq "callback_scam"
          any(ml.nlu_classifier(beta.ocr(attachments).text).intents)
            and
              ml.nlu_classifier(beta.ocr(attachments[]).text).intents[].confidence in ["high", "medium"]
              ml.nlu_classifier(beta.ocr(attachments[]).text).intents[].name eq "callback_scam"
        or
          and
            any(ml.logo_detect(attachments).brands)
              ml.logo_detect(attachments).brands.name in ["Ebay", "GeekSquad", "McAfee", "Norton", "PayPal"]
            sender.email.local_part in ["no_reply", "noreply"]
          not
            sender.email.local_part in ["no_reply", "noreply"]
        or
          attachments.file_type in ["docx", "pdf", "xlsx"]
           macro "attachments[].file_type in file_types_images"
    and
      or
        and
          or
            beta.ocr(file.message_screenshot()).text contains "best buy"
            beta.ocr(file.message_screenshot()).text contains "ebay"
            beta.ocr(file.message_screenshot()).text contains "geek squad"
            beta.ocr(file.message_screenshot()).text contains "lifelock"
            beta.ocr(file.message_screenshot()).text contains "mcafee"
            beta.ocr(file.message_screenshot()).text contains "norton"
            beta.ocr(file.message_screenshot()).text contains "paypal"
            beta.ocr(file.message_screenshot()).text contains "virus"
            body.current_thread.text ends_with "=1"
            body.current_thread.text match "Ebay"
            body.current_thread.text match "GeekSquad"
            body.current_thread.text match "McAfee"
            body.current_thread.text match "Norton"
            body.current_thread.text match "PayPal"
            body.current_thread.text regex_match "\\+?([ilo0-9]{1,2})?\\s?\\(?\\d{3}\\)?[\\s\\.\\-⋅]{0,5}[ilo0-9]{3}[\\s\\.\\-⋅]{0,5}[ilo0-9]{4}"
            body.current_thread.text regex_match "\\+?([ilo0-9]{1}.)?\\(?[ilo0-9]{3}?\\)?.[ilo0-9]{3}.?[ilo0-9]{4}"
          body.current_thread.text length_compare "1750"
          body.current_thread.text length_compare "75"
        and
          body.current_thread.text length_compare "1750"
          body.current_thread.text length_compare "270"
      any(ml.nlu_classifier(body.current_thread.text).intents)
        and
          ml.nlu_classifier(body.current_thread.text).intents.confidence in ["high", "medium"]
          ml.nlu_classifier(body.current_thread.text).intents.name eq "callback_scam"
  not
    and
      any(headers.domains)
        headers.domains.domain eq "smtp-out.gcp.bigcommerce.net"
      body.html.raw contains "bigcommerce.com"
  or
    and
      not
        profile.by_sender_email func_call "profile.by_sender_email().any_messages_benign"
      profile.by_sender_email func_call "profile.by_sender_email().any_messages_malicious_or_spam"
    not
      profile.by_sender_email func_call "profile.by_sender_email().solicited"
  not
    and
      coalesce func_call "coalesce(headers.auth_summary.dmarc.pass)"
       macro "sender.email.domain.root_domain in high_trust_sender_root_domains"
  not
    sender.email.email eq "opsgenie@opsgenie.net"
  attachments length_compare "5"
  type.inbound eq "true"

Exclusions

The rule actively suppresses these predicates.

FieldKindExcluded valuesSearch
headers.domainsarray_any(no value, null check)excludes:headers.domains
body.html.rawcontainsbigcommerce.comexcludes:body.html.raw field:"body.html.raw" value:"bigcommerce.com"
sender.email.emaileqopsgenie@opsgenie.netexcludes:sender.email.email field:"sender.email.email" value:"opsgenie@opsgenie.net"

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
beta.ocr(file.message_screenshot()).textcontains
  • best buy
  • ebay
  • geek squad
  • lifelock
  • mcafee
  • norton
  • paypal
  • virus
field:"beta.ocr(file.message_screenshot()).text" kind:contains
body.current_thread.textregex_match
  • +?([ilo0-9]{1,2})?\s?(?\d{3})?[\s.\-⋅]{0,5}[ilo0-9]{3}[\s.\-⋅]{0,5}[ilo0-9]{4}
  • +?([ilo0-9]{1}.)?(?[ilo0-9]{3}?)?.[ilo0-9]{3}.?[ilo0-9]{4}
field:"body.current_thread.text" kind:regex_match
body.current_thread.textwildcard
  • *=1
  • *Ebay*
  • *GeekSquad*
  • *McAfee*
  • *Norton*
  • *PayPal*
field:"body.current_thread.text" kind:wildcard
type.inboundeq
  • true transforms: boolean
field:"type.inbound" kind:eq value:"true"

Callback phishing via Adobe Sign comment

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

This rule inspects messages originating from legitimate Adobe Sign infrastructure, with content matching Callback Phishing criteria, in the body, requiring at least one brand name, as well as 3 matching Callback Phishing terms and a phone number.

Threat classification

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

CategoryValues
Attack typesCallback Phishing
Tactics and techniquesEvasion, Impersonation: Brand, Out of band pivot, Social engineering

Telemetry coverage

PlatformRecord / event type
SublimeInbound email message

Message attributes

  • body
  • body.current_thread
  • headers
  • headers.auth_summary
  • sender.email
  • type

Rule body

type.inbound
and length(attachments) == 0

// Legitimate Docusign sending infratructure
and sender.email.domain.root_domain == 'adobesign.com'
and (headers.auth_summary.spf.pass or headers.auth_summary.dmarc.pass)
and (
  // this section is synced with attachment_callback_phish_with_pdf.yml and attachment_callback_phish_with_img.yml
  regex.icontains(strings.replace_confusables(body.current_thread.text),
                  '(p.{0,3}a.{0,3}y.{0,3}p.{0,3}a.{0,3}l|ma?c.?fee|n[o0]rt[o0]n|geek.{0,5}squad|ebay|symantec|best buy|lifel[o0]c|secure anywhere|starz|utilities premium|pc security|at&t)'
  )
  or any(ml.logo_detect(file.message_screenshot()).brands,
         .name in ("PayPal", "Norton", "GeekSquad", "Ebay", "McAfee", "AT&T")
  )
)
and (
  (
    // this seciton is synced with attachment_callback_phish_with_img.yml and attachment_callback_phish_with_pdf.yml
    // however, the 3 of logic and requiring a phone number is specific to this rule in order to reduce FPs
    // caused by messages which mention cancelling or otherwise managing a subscription
    // it is also synced and below for message_screenshot OCR output
    3 of (
      strings.icontains(body.current_thread.text, 'purchase'),
      strings.icontains(body.current_thread.text, 'payment'),
      strings.icontains(body.current_thread.text, 'transaction'),
      strings.icontains(body.current_thread.text, 'subscription'),
      strings.icontains(body.current_thread.text, 'antivirus'),
      strings.icontains(body.current_thread.text, 'order'),
      strings.icontains(body.current_thread.text, 'support'),
      strings.icontains(body.current_thread.text, 'help line'),
      strings.icontains(body.current_thread.text, 'receipt'),
      strings.icontains(body.current_thread.text, 'invoice'),
      strings.icontains(body.current_thread.text, 'call'),
      strings.icontains(body.current_thread.text, 'cancel'),
      strings.icontains(body.current_thread.text, 'renew'),
      strings.icontains(body.current_thread.text, 'refund'),
      regex.icontains(body.current_thread.text, "(?:reach|contact) us at"),
      strings.icontains(body.current_thread.text, "+1"),
      strings.icontains(body.current_thread.text, "amount"),
      strings.icontains(body.current_thread.text, "charged"),
      strings.icontains(body.current_thread.text, "crypto"),
      strings.icontains(body.current_thread.text, "wallet address"),
      regex.icontains(body.current_thread.text, '\$\d{3}\.\d{2}\b'),
    )
    // phone number regex
    and regex.icontains(body.current_thread.text,
                        '\+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4}',
                        '\+?([ilo0-9]{1,2})?\s?\(?\d{3}\)?[\s\.\-⋅]{0,5}[ilo0-9]{3}[\s\.\-⋅]{0,5}[ilo0-9]{4}'
    )
  )
  or (
    // this seciton is synced with attachment_callback_phish_with_img.yml and attachment_callback_phish_with_pdf.yml
    // and above for current_thread.text
    //
    // This rule makes use of a beta feature and is subject to change without notice
    // using the beta feature in custom rules is not suggested until it has been formally released
    //
    3 of (
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'purchase'),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'payment'),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'transaction'),
      strings.icontains(beta.ocr(file.message_screenshot()).text,
                        'subscription'
      ),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'antivirus'),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'order'),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'support'),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'help line'),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'receipt'),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'invoice'),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'call'),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'helpdesk'),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'cancel'),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'renew'),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'refund'),
      regex.icontains(beta.ocr(file.message_screenshot()).text,
                      "(?:reach|contact) us at"
      ),
      strings.icontains(beta.ocr(file.message_screenshot()).text, '+1'),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'amount'),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'charged'),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'crypto'),
      strings.icontains(beta.ocr(file.message_screenshot()).text,
                        'wallet address'
      ),
      regex.icontains(beta.ocr(file.message_screenshot()).text,
                      '\$\d{3}\.\d{2}\b'
      ),
    )
    // phone number regex
    and regex.icontains(beta.ocr(file.message_screenshot()).text,
                        '\+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4}',
                        '\+?([ilo0-9]{1,2})?\s?\(?\d{3}\)?[\s\.\-⋅]{0,5}[ilo0-9]{3}[\s\.\-⋅]{0,5}[ilo0-9]{4}'
    )

    // negate messages with previous threads.  While callback phishing with thread hijacking or with current_thread 
    // padded with whitespace and previous threads in the message has been observed, the intetion of using OCR is for image embedded callbacks
    and not regex.icount(beta.ocr(file.message_screenshot()).text,
                         '(?:from|to|sent|date|cc|subject):'
    ) > 3
    // this notation of previous threads often only occurs once
    and not regex.icontains(beta.ocr(file.message_screenshot()).text,
                            'wrote:[\r\n]'
    )
  )
)

Detection logic

Scope: inbound message.

This rule inspects messages originating from legitimate Adobe Sign infrastructure, with content matching Callback Phishing criteria, in the body, requiring at least one brand name, as well as 3 matching Callback Phishing terms and a phone number.

  1. inbound message
  2. length(attachments) is 0
  3. sender.email.domain.root_domain is 'adobesign.com'
  4. any of:
    • headers.auth_summary.spf.pass
    • headers.auth_summary.dmarc.pass
  5. any of:
    • strings.replace_confusables(body.current_thread.text) matches '(p.{0,3}a.{0,3}y.{0,3}p.{0,3}a.{0,3}l|ma?c.?fee|n[o0]rt[o0]n|geek.{0,5}squad|ebay|symantec|best buy|lifel[o0]c|secure anywhere|starz|utilities premium|pc security|at&t)'
    • any of ml.logo_detect(file.message_screenshot()).brands where:
      • .name in ('PayPal', 'Norton', 'GeekSquad', 'Ebay', 'McAfee', 'AT&T')
  6. any of:
    • all of:
      • at least 3 of:
        • body.current_thread.text contains 'purchase'
        • body.current_thread.text contains 'payment'
        • body.current_thread.text contains 'transaction'
        • body.current_thread.text contains 'subscription'
        • body.current_thread.text contains 'antivirus'
        • body.current_thread.text contains 'order'
        • body.current_thread.text contains 'support'
        • body.current_thread.text contains 'help line'
        • body.current_thread.text contains 'receipt'
        • body.current_thread.text contains 'invoice'
        • body.current_thread.text contains 'call'
        • body.current_thread.text contains 'cancel'
        • body.current_thread.text contains 'renew'
        • body.current_thread.text contains 'refund'
        • body.current_thread.text matches '(?:reach|contact) us at'
        • body.current_thread.text contains '+1'
        • body.current_thread.text contains 'amount'
        • body.current_thread.text contains 'charged'
        • body.current_thread.text contains 'crypto'
        • body.current_thread.text contains 'wallet address'
        • body.current_thread.text matches '\\$\\d{3}\\.\\d{2}\\b'
      • body.current_thread.text matches any of 2 patterns
        • \+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4}
        • \+?([ilo0-9]{1,2})?\s?\(?\d{3}\)?[\s\.\-⋅]{0,5}[ilo0-9]{3}[\s\.\-⋅]{0,5}[ilo0-9]{4}
    • all of:
      • at least 3 of:
        • beta.ocr(file.message_screenshot()).text contains 'purchase'
        • beta.ocr(file.message_screenshot()).text contains 'payment'
        • beta.ocr(file.message_screenshot()).text contains 'transaction'
        • beta.ocr(file.message_screenshot()).text contains 'subscription'
        • beta.ocr(file.message_screenshot()).text contains 'antivirus'
        • beta.ocr(file.message_screenshot()).text contains 'order'
        • beta.ocr(file.message_screenshot()).text contains 'support'
        • beta.ocr(file.message_screenshot()).text contains 'help line'
        • beta.ocr(file.message_screenshot()).text contains 'receipt'
        • beta.ocr(file.message_screenshot()).text contains 'invoice'
        • beta.ocr(file.message_screenshot()).text contains 'call'
        • beta.ocr(file.message_screenshot()).text contains 'helpdesk'
        • beta.ocr(file.message_screenshot()).text contains 'cancel'
        • beta.ocr(file.message_screenshot()).text contains 'renew'
        • beta.ocr(file.message_screenshot()).text contains 'refund'
        • beta.ocr(file.message_screenshot()).text matches '(?:reach|contact) us at'
        • beta.ocr(file.message_screenshot()).text contains '+1'
        • beta.ocr(file.message_screenshot()).text contains 'amount'
        • beta.ocr(file.message_screenshot()).text contains 'charged'
        • beta.ocr(file.message_screenshot()).text contains 'crypto'
        • beta.ocr(file.message_screenshot()).text contains 'wallet address'
        • beta.ocr(file.message_screenshot()).text matches '\\$\\d{3}\\.\\d{2}\\b'
      • beta.ocr(file.message_screenshot()).text matches any of 2 patterns
        • \+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4}
        • \+?([ilo0-9]{1,2})?\s?\(?\d{3}\)?[\s\.\-⋅]{0,5}[ilo0-9]{3}[\s\.\-⋅]{0,5}[ilo0-9]{4}
      • not:
        • regex.icount(beta.ocr(file.message_screenshot()).text, '(?:from|to|sent|date|cc|subject):') > 3
      • not:
        • beta.ocr(file.message_screenshot()).text matches 'wrote:[\\r\\n]'

Inspects: body.current_thread.text, headers.auth_summary.dmarc.pass, headers.auth_summary.spf.pass, sender.email.domain.root_domain, type.inbound. Sensors: beta.ocr, file.message_screenshot, ml.logo_detect, regex.icontains, regex.icount, strings.icontains, strings.replace_confusables.

Indicators matched (32)

FieldMatchValue
sender.email.domain.root_domainequalsadobesign.com
regex.icontainsregex(p.{0,3}a.{0,3}y.{0,3}p.{0,3}a.{0,3}l|ma?c.?fee|n[o0]rt[o0]n|geek.{0,5}squad|ebay|symantec|best buy|lifel[o0]c|secure anywhere|starz|utilities premium|pc security|at&t)
ml.logo_detect(file.message_screenshot()).brands[].namememberPayPal
ml.logo_detect(file.message_screenshot()).brands[].namememberNorton
ml.logo_detect(file.message_screenshot()).brands[].namememberGeekSquad
ml.logo_detect(file.message_screenshot()).brands[].namememberEbay
ml.logo_detect(file.message_screenshot()).brands[].namememberMcAfee
ml.logo_detect(file.message_screenshot()).brands[].namememberAT&T
strings.icontainssubstringpurchase
strings.icontainssubstringpayment
strings.icontainssubstringtransaction
strings.icontainssubstringsubscription
20 more
strings.icontainssubstringantivirus
strings.icontainssubstringorder
strings.icontainssubstringsupport
strings.icontainssubstringhelp line
strings.icontainssubstringreceipt
strings.icontainssubstringinvoice
strings.icontainssubstringcall
strings.icontainssubstringcancel
strings.icontainssubstringrenew
strings.icontainssubstringrefund
regex.icontainsregex(?:reach|contact) us at
strings.icontainssubstring+1
strings.icontainssubstringamount
strings.icontainssubstringcharged
strings.icontainssubstringcrypto
strings.icontainssubstringwallet address
regex.icontainsregex\$\d{3}\.\d{2}\b
regex.icontainsregex\+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4}
regex.icontainsregex\+?([ilo0-9]{1,2})?\s?\(?\d{3}\)?[\s\.\-⋅]{0,5}[ilo0-9]{3}[\s\.\-⋅]{0,5}[ilo0-9]{4}
strings.icontainssubstringhelpdesk

Stages and Predicates

Stage 1: mql_rule

and
  or
    and
      or
        beta.ocr(file.message_screenshot()).text contains "+1"
        beta.ocr(file.message_screenshot()).text contains "amount"
        beta.ocr(file.message_screenshot()).text contains "antivirus"
        beta.ocr(file.message_screenshot()).text contains "call"
        beta.ocr(file.message_screenshot()).text contains "cancel"
        beta.ocr(file.message_screenshot()).text contains "charged"
        beta.ocr(file.message_screenshot()).text contains "crypto"
        beta.ocr(file.message_screenshot()).text contains "help line"
        beta.ocr(file.message_screenshot()).text contains "helpdesk"
        beta.ocr(file.message_screenshot()).text contains "invoice"
        beta.ocr(file.message_screenshot()).text contains "order"
        beta.ocr(file.message_screenshot()).text contains "payment"
        beta.ocr(file.message_screenshot()).text contains "purchase"
        beta.ocr(file.message_screenshot()).text contains "receipt"
        beta.ocr(file.message_screenshot()).text contains "refund"
        beta.ocr(file.message_screenshot()).text contains "renew"
        beta.ocr(file.message_screenshot()).text contains "subscription"
        beta.ocr(file.message_screenshot()).text contains "support"
        beta.ocr(file.message_screenshot()).text contains "transaction"
        beta.ocr(file.message_screenshot()).text contains "wallet address"
        beta.ocr(file.message_screenshot()).text regex_match "(?:reach|contact) us at"
        beta.ocr(file.message_screenshot()).text regex_match "\\$\\d{3}\\.\\d{2}\\b"
      or
        beta.ocr(file.message_screenshot()).text regex_match "\\+?([ilo0-9]{1,2})?\\s?\\(?\\d{3}\\)?[\\s\\.\\-⋅]{0,5}[ilo0-9]{3}[\\s\\.\\-⋅]{0,5}[ilo0-9]{4}"
        beta.ocr(file.message_screenshot()).text regex_match "\\+?([ilo0-9]{1}.)?\\(?[ilo0-9]{3}?\\)?.[ilo0-9]{3}.?[ilo0-9]{4}"
      not
        beta.ocr(file.message_screenshot()).text regex_match "wrote:[\\r\\n]"
      not
        regex.icount func_call "regex.icount(beta.ocr(file.message_screenshot()).text, \"(?:from|to|sent|date|cc|subject):\") > 3"
    and
      or
        body.current_thread.text contains "+1"
        body.current_thread.text contains "amount"
        body.current_thread.text contains "antivirus"
        body.current_thread.text contains "call"
        body.current_thread.text contains "cancel"
        body.current_thread.text contains "charged"
        body.current_thread.text contains "crypto"
        body.current_thread.text contains "help line"
        body.current_thread.text contains "invoice"
        body.current_thread.text contains "order"
        body.current_thread.text contains "payment"
        body.current_thread.text contains "purchase"
        body.current_thread.text contains "receipt"
        body.current_thread.text contains "refund"
        body.current_thread.text contains "renew"
        body.current_thread.text contains "subscription"
        body.current_thread.text contains "support"
        body.current_thread.text contains "transaction"
        body.current_thread.text contains "wallet address"
        body.current_thread.text regex_match "(?:reach|contact) us at"
        body.current_thread.text regex_match "\\$\\d{3}\\.\\d{2}\\b"
      or
        body.current_thread.text regex_match "\\+?([ilo0-9]{1,2})?\\s?\\(?\\d{3}\\)?[\\s\\.\\-⋅]{0,5}[ilo0-9]{3}[\\s\\.\\-⋅]{0,5}[ilo0-9]{4}"
        body.current_thread.text regex_match "\\+?([ilo0-9]{1}.)?\\(?[ilo0-9]{3}?\\)?.[ilo0-9]{3}.?[ilo0-9]{4}"
  or
    any(ml.logo_detect(file.message_screenshot()).brands)
      ml.logo_detect(file.message_screenshot()).brands.name in ["AT&T", "Ebay", "GeekSquad", "McAfee", "Norton", "PayPal"]
    strings.replace_confusables(body.current_thread.text) regex_match "(p.{0,3}a.{0,3}y.{0,3}p.{0,3}a.{0,3}l|ma?c.?fee|n[o0]rt[o0]n|geek.{0,5}squad|ebay|symantec|best buy|lifel[o0]c|secure anywhere|starz|utilities premium|pc security|at&t)"
  or
    headers.auth_summary.dmarc.pass eq "true"
    headers.auth_summary.spf.pass eq "true"
  attachments length_compare "0"
  sender.email.domain.root_domain eq "adobesign.com"
  type.inbound eq "true"

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
beta.ocr(file.message_screenshot()).textcontains
  • +1
  • amount
  • antivirus
  • call
  • cancel
  • charged
  • crypto
  • help line
  • helpdesk
  • invoice
  • order
  • payment
  • purchase
  • receipt
  • refund
  • renew
  • subscription
  • support
  • transaction
  • wallet address
field:"beta.ocr(file.message_screenshot()).text" kind:contains
beta.ocr(file.message_screenshot()).textregex_match
  • (?:reach|contact) us at
  • $\d{3}.\d{2}\b
  • +?([ilo0-9]{1,2})?\s?(?\d{3})?[\s.\-⋅]{0,5}[ilo0-9]{3}[\s.\-⋅]{0,5}[ilo0-9]{4}
  • +?([ilo0-9]{1}.)?(?[ilo0-9]{3}?)?.[ilo0-9]{3}.?[ilo0-9]{4}
field:"beta.ocr(file.message_screenshot()).text" kind:regex_match
body.current_thread.textcontains
  • +1
  • amount
  • antivirus
  • call
  • cancel
  • charged
  • crypto
  • help line
  • invoice
  • order
  • payment
  • purchase
  • receipt
  • refund
  • renew
  • subscription
  • support
  • transaction
  • wallet address
field:"body.current_thread.text" kind:contains
body.current_thread.textregex_match
  • (?:reach|contact) us at
  • $\d{3}.\d{2}\b
  • +?([ilo0-9]{1,2})?\s?(?\d{3})?[\s.\-⋅]{0,5}[ilo0-9]{3}[\s.\-⋅]{0,5}[ilo0-9]{4}
  • +?([ilo0-9]{1}.)?(?[ilo0-9]{3}?)?.[ilo0-9]{3}.?[ilo0-9]{4}
field:"body.current_thread.text" kind:regex_match
headers.auth_summary.dmarc.passeq
  • true transforms: boolean
field:"headers.auth_summary.dmarc.pass" kind:eq value:"true"
headers.auth_summary.spf.passeq
  • true transforms: boolean
field:"headers.auth_summary.spf.pass" kind:eq value:"true"
sender.email.domain.root_domaineq
  • adobesign.com
field:"sender.email.domain.root_domain" kind:eq value:"adobesign.com"
strings.replace_confusables(body.current_thread.text)regex_match
  • (p.{0,3}a.{0,3}y.{0,3}p.{0,3}a.{0,3}l|ma?c.?fee|n[o0]rt[o0]n|geek.{0,5}squad|ebay|symantec|best buy|lifel[o0]c|secure anywhere|starz|utilities premium|pc security|at&t)
field:"strings.replace_confusables(body.current_thread.text)" kind:regex_match value:"(p.{0,3}a.{0,3}y.{0,3}p.{0,3}a.{0,3}l|ma?c.?fee|n[o0]rt[o0]n|geek.{0,5}squad|ebay|symantec|best buy|lifel[o0]c|secure anywhere|starz|utilities premium|pc security|at&t)"
type.inboundeq
  • true transforms: boolean
field:"type.inbound" kind:eq value:"true"

Callback phishing via calendar invite

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

Detects calendar invites containing callback phishing language in the DESCRIPTION or SUMMARY of the invite.

Threat classification

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

CategoryValues
Attack typesCallback Phishing
Tactics and techniquesSocial engineering, Evasion, ICS Phishing

Telemetry coverage

PlatformRecord / event type
SublimeInbound email message

Message attributes

  • attachments
  • headers
  • headers.auth_summary
  • sender.email
  • type

Rule body

type.inbound
and length(attachments) > 0
and all(attachments, .content_type in ("text/calendar", "application/ics"))
and any(attachments,
        // extract the calendar invite summary or description and use NLU against it
        any(file.explode(.),
            any(.scan.ics.calendars,
                any(.components,
                    any(ml.nlu_classifier(.summary).intents,
                        .name == "callback_scam" and .confidence == "high"
                    )
                    or (
                      any(ml.nlu_classifier(.description).intents,
                          .name == "callback_scam"
                      )
                      or any(ml.nlu_classifier(strings.parse_html(.description).display_text
                             ).intents,
                             .name == "callback_scam"
                      )
                      or (
                        any(ml.nlu_classifier(.description).topics,
                            .name == "Request to View Invoice"
                            and .confidence == "high"
                        )
                        // emoji regex
                        and regex.contains(.description,
                                           '[\x{1F600}-\x{1F64F}\x{1F300}-\x{1F5FF}\x{1F680}-\x{1F6FF}\x{1F900}-\x{1F9FF}\x{2600}-\x{26FF}\x{2700}-\x{27BF}\x{FE00}-\x{FE0F}\x{200D}\x{20E3}\x{E0020}-\x{E007F}]'
                        )
                      )
                    )
                )
            )
        )
)
and (
  not profile.by_sender_email().solicited
  and not profile.by_sender_email().any_messages_benign
)

// negate highly trusted sender domains unless they fail DMARC authentication
and (
  (
    sender.email.domain.root_domain in $high_trust_sender_root_domains
    and not coalesce(headers.auth_summary.dmarc.pass, false)
  )
  or sender.email.domain.root_domain not in $high_trust_sender_root_domains
)

Detection logic

Scope: inbound message.

Detects calendar invites containing callback phishing language in the DESCRIPTION or SUMMARY of the invite.

  1. inbound message
  2. length(attachments) > 0
  3. all of attachments where:
    • .content_type in ('text/calendar', 'application/ics')
  4. any of attachments where:
    • any of file.explode(.) where:
      • any of .scan.ics.calendars where:
        • any of .components where any holds:
          • any of ml.nlu_classifier(.summary).intents where all hold:
            • .name is 'callback_scam'
            • .confidence is 'high'
          • any of:
            • any of ml.nlu_classifier(.description).intents where:
              • .name is 'callback_scam'
            • any of ml.nlu_classifier(strings.parse_html(.description).display_text).intents where:
              • .name is 'callback_scam'
            • all of:
              • any of ml.nlu_classifier(.description).topics where all hold:
                • .name is 'Request to View Invoice'
                • .confidence is 'high'
              • .description matches '[\\x{1F600}-\\x{1F64F}\\x{1F300}-\\x{1F5FF}\\x{1F680}-\\x{1F6FF}\\x{1F900}-\\x{1F9FF}\\x{2600}-\\x{26FF}\\x{2700}-\\x{27BF}\\x{FE00}-\\x{FE0F}\\x{200D}\\x{20E3}\\x{E0020}-\\x{E007F}]'
  5. all of:
    • not:
      • profile.by_sender_email().solicited
    • not:
      • profile.by_sender_email().any_messages_benign
  6. any of:
    • all of:
      • sender.email.domain.root_domain in $high_trust_sender_root_domains
      • not:
        • coalesce(headers.auth_summary.dmarc.pass)
    • sender.email.domain.root_domain not in $high_trust_sender_root_domains

Inspects: attachments[].content_type, headers.auth_summary.dmarc.pass, sender.email.domain.root_domain, type.inbound. Sensors: file.explode, ml.nlu_classifier, profile.by_sender_email, regex.contains, strings.parse_html. Reference lists: $high_trust_sender_root_domains.

Indicators matched (9)

FieldMatchValue
attachments[].content_typemembertext/calendar
attachments[].content_typememberapplication/ics
ml.nlu_classifier(file.explode(attachments[])[].scan.ics.calendars[].components[].summary).intents[].nameequalscallback_scam
ml.nlu_classifier(file.explode(attachments[])[].scan.ics.calendars[].components[].summary).intents[].confidenceequalshigh
ml.nlu_classifier(file.explode(attachments[])[].scan.ics.calendars[].components[].description).intents[].nameequalscallback_scam
ml.nlu_classifier(strings.parse_html(file.explode(attachments[])[].scan.ics.calendars[].components[].description).display_text).intents[].nameequalscallback_scam
ml.nlu_classifier(file.explode(attachments[])[].scan.ics.calendars[].components[].description).topics[].nameequalsRequest to View Invoice
ml.nlu_classifier(file.explode(attachments[])[].scan.ics.calendars[].components[].description).topics[].confidenceequalshigh
regex.containsregex[\x{1F600}-\x{1F64F}\x{1F300}-\x{1F5FF}\x{1F680}-\x{1F6FF}\x{1F900}-\x{1F9FF}\x{2600}-\x{26FF}\x{2700}-\x{27BF}\x{FE00}-\x{FE0F}\x{200D}\x{20E3}\x{E0020}-\x{E007F}]

Stages and Predicates

Stage 1: mql_rule

and
  any(attachments)
    any(file.explode(attachments))
      any(file.explode(attachments).scan.ics.calendars)
        any(file.explode(attachments).scan.ics.calendars.components)
          or
            and
              any(ml.nlu_classifier(file.explode(attachments).scan.ics.calendars.components.description).topics)
                and
                  ml.nlu_classifier(file.explode(attachments[])[].scan.ics.calendars[].components[].description).topics[].confidence eq "high"
                  ml.nlu_classifier(file.explode(attachments[])[].scan.ics.calendars[].components[].description).topics[].name eq "Request to View Invoice"
              file.explode(attachments[])[].scan.ics.calendars[].components[].description regex_match "[\\x{1F600}-\\x{1F64F}\\x{1F300}-\\x{1F5FF}\\x{1F680}-\\x{1F6FF}\\x{1F900}-\\x{1F9FF}\\x{2600}-\\x{26FF}\\x{2700}-\\x{27BF}\\x{FE00}-\\x{FE0F}\\x{200D}\\x{20E3}\\x{E0020}-\\x{E007F}]"
            any(ml.nlu_classifier(file.explode(attachments).scan.ics.calendars.components.summary).intents)
              and
                ml.nlu_classifier(file.explode(attachments[])[].scan.ics.calendars[].components[].summary).intents[].confidence eq "high"
                ml.nlu_classifier(file.explode(attachments[])[].scan.ics.calendars[].components[].summary).intents[].name eq "callback_scam"
            any(ml.nlu_classifier(file.explode(attachments).scan.ics.calendars.components.description).intents)
              ml.nlu_classifier(file.explode(attachments).scan.ics.calendars.components.description).intents.name eq "callback_scam"
            any(ml.nlu_classifier(strings.parse_html(file.explode(attachments).scan.ics.calendars.components.description).display_text).intents)
              ml.nlu_classifier(strings.parse_html(file.explode(attachments).scan.ics.calendars.components.description).display_text).intents.name eq "callback_scam"
  or
    and
      not
        coalesce func_call "coalesce(headers.auth_summary.dmarc.pass)"
       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"
  not
    profile.by_sender_email func_call "profile.by_sender_email().any_messages_benign"
  not
    profile.by_sender_email func_call "profile.by_sender_email().solicited"
  attachments length_compare "0"
  type.inbound eq "true"
   macro "all(attachments)"

Indicators

These rows show field, operator, and value matches.

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

Callback phishing via DocuSign comment

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

This rule inspects messages originating from legitimate DocuSign infrastructure, with a DocuSign logo that match Callback Phishing criteria, in the body, requiring at least one brand name, as well as 3 matching Callback Phishing terms and a phone number.

Threat classification

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

CategoryValues
Attack typesCallback Phishing
Tactics and techniquesEvasion, Impersonation: Brand, Out of band pivot, Social engineering

Telemetry coverage

PlatformRecord / event type
SublimeInbound email message

Message attributes

  • body
  • body.current_thread
  • headers
  • headers.auth_summary
  • sender.email
  • subject
  • type

Rule body

type.inbound
and length(attachments) == 0

// Legitimate Docusign sending infratructure
and sender.email.domain.root_domain == 'docusign.net'
and (headers.auth_summary.spf.pass or headers.auth_summary.dmarc.pass)

// Docusign Logo 
and any(ml.logo_detect(file.message_screenshot()).brands, .name == "DocuSign")

// Callback Phishing
and regex.icontains(body.current_thread.text,
                    (
                      "mcafee|n[o0]rt[o0]n|geek.{0,5}squad|paypal|ebay|symantec|best buy|lifel[o0]ck"
                    )
)
and 3 of (
  strings.ilike(body.current_thread.text, '*purchase*'),
  strings.ilike(body.current_thread.text, '*payment*'),
  strings.ilike(body.current_thread.text, '*transaction*'),
  strings.ilike(body.current_thread.text, '*subscription*'),
  strings.ilike(body.current_thread.text, '*antivirus*'),
  strings.ilike(body.current_thread.text, '*order*'),
  strings.ilike(body.current_thread.text, '*support*'),
  strings.ilike(body.current_thread.text, '*help line*'),
  strings.ilike(body.current_thread.text, '*receipt*'),
  strings.ilike(body.current_thread.text, '*invoice*'),
  strings.ilike(body.current_thread.text, '*call*'),
  strings.ilike(body.current_thread.text, '*cancel*'),
  strings.ilike(body.current_thread.text, '*renew*'),
  strings.ilike(body.current_thread.text, '*refund*')
)
// phone number regex
and any([body.current_thread.text, subject.subject],
        regex.icontains(.,
                        '\+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4}',
                        '\+?([ilo0-9]{1,2})?\s?\(?\d{3}\)?[\s\.\-⋅]{0,5}[ilo0-9]{3}[\s\.\-⋅]{0,5}[ilo0-9]{4}'
        )
)

Detection logic

Scope: inbound message.

This rule inspects messages originating from legitimate DocuSign infrastructure, with a DocuSign logo that match Callback Phishing criteria, in the body, requiring at least one brand name, as well as 3 matching Callback Phishing terms and a phone number.

  1. inbound message
  2. length(attachments) is 0
  3. sender.email.domain.root_domain is 'docusign.net'
  4. any of:
    • headers.auth_summary.spf.pass
    • headers.auth_summary.dmarc.pass
  5. any of ml.logo_detect(file.message_screenshot()).brands where:
    • .name is 'DocuSign'
  6. body.current_thread.text matches 'mcafee|n[o0]rt[o0]n|geek.{0,5}squad|paypal|ebay|symantec|best buy|lifel[o0]ck'
  7. at least 3 of 14: body.current_thread.text matches any of 14 patterns
    • *purchase*
    • *payment*
    • *transaction*
    • *subscription*
    • *antivirus*
    • *order*
    • *support*
    • *help line*
    • *receipt*
    • *invoice*
    • *call*
    • *cancel*
    • *renew*
    • *refund*
  8. any of [body.current_thread.text, subject.subject] where:
    • . matches any of 2 patterns
      • \+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4}
      • \+?([ilo0-9]{1,2})?\s?\(?\d{3}\)?[\s\.\-⋅]{0,5}[ilo0-9]{3}[\s\.\-⋅]{0,5}[ilo0-9]{4}

Inspects: body.current_thread.text, headers.auth_summary.dmarc.pass, headers.auth_summary.spf.pass, sender.email.domain.root_domain, subject.subject, type.inbound. Sensors: file.message_screenshot, ml.logo_detect, regex.icontains, strings.ilike.

Indicators matched (19)

FieldMatchValue
sender.email.domain.root_domainequalsdocusign.net
ml.logo_detect(file.message_screenshot()).brands[].nameequalsDocuSign
regex.icontainsregexmcafee|n[o0]rt[o0]n|geek.{0,5}squad|paypal|ebay|symantec|best buy|lifel[o0]ck
strings.ilikesubstring*purchase*
strings.ilikesubstring*payment*
strings.ilikesubstring*transaction*
strings.ilikesubstring*subscription*
strings.ilikesubstring*antivirus*
strings.ilikesubstring*order*
strings.ilikesubstring*support*
strings.ilikesubstring*help line*
strings.ilikesubstring*receipt*
7 more
strings.ilikesubstring*invoice*
strings.ilikesubstring*call*
strings.ilikesubstring*cancel*
strings.ilikesubstring*renew*
strings.ilikesubstring*refund*
regex.icontainsregex\+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4}
regex.icontainsregex\+?([ilo0-9]{1,2})?\s?\(?\d{3}\)?[\s\.\-⋅]{0,5}[ilo0-9]{3}[\s\.\-⋅]{0,5}[ilo0-9]{4}

Stages and Predicates

Stage 1: mql_rule

and
  any([body.current_thread.text, subject.subject])
    or
      [body.current_thread.text, subject.subject] regex_match "\\+?([ilo0-9]{1,2})?\\s?\\(?\\d{3}\\)?[\\s\\.\\-⋅]{0,5}[ilo0-9]{3}[\\s\\.\\-⋅]{0,5}[ilo0-9]{4}"
      [body.current_thread.text, subject.subject] regex_match "\\+?([ilo0-9]{1}.)?\\(?[ilo0-9]{3}?\\)?.[ilo0-9]{3}.?[ilo0-9]{4}"
  or
    body.current_thread.text match "antivirus"
    body.current_thread.text match "call"
    body.current_thread.text match "cancel"
    body.current_thread.text match "help line"
    body.current_thread.text match "invoice"
    body.current_thread.text match "order"
    body.current_thread.text match "payment"
    body.current_thread.text match "purchase"
    body.current_thread.text match "receipt"
    body.current_thread.text match "refund"
    body.current_thread.text match "renew"
    body.current_thread.text match "subscription"
    body.current_thread.text match "support"
    body.current_thread.text match "transaction"
  or
    headers.auth_summary.dmarc.pass eq "true"
    headers.auth_summary.spf.pass eq "true"
  any(ml.logo_detect(file.message_screenshot()).brands)
    ml.logo_detect(file.message_screenshot()).brands.name eq "DocuSign"
  attachments length_compare "0"
  body.current_thread.text regex_match "mcafee|n[o0]rt[o0]n|geek.{0,5}squad|paypal|ebay|symantec|best buy|lifel[o0]ck"
  sender.email.domain.root_domain eq "docusign.net"
  type.inbound eq "true"

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
body.current_thread.textregex_match
    • mcafee
    • n[o0]rt[o0]n
    • geek.{0,5}squad
    • paypal
    • ebay
    • symantec
    • best buy
    • lifel[o0]ck
field:"body.current_thread.text" kind:regex_match
body.current_thread.textwildcard
  • *antivirus*
  • *call*
  • *cancel*
  • *help line*
  • *invoice*
  • *order*
  • *payment*
  • *purchase*
  • *receipt*
  • *refund*
  • *renew*
  • *subscription*
  • *support*
  • *transaction*
field:"body.current_thread.text" kind:wildcard
headers.auth_summary.dmarc.passeq
  • true transforms: boolean
field:"headers.auth_summary.dmarc.pass" kind:eq value:"true"
headers.auth_summary.spf.passeq
  • true transforms: boolean
field:"headers.auth_summary.spf.pass" kind:eq value:"true"
sender.email.domain.root_domaineq
  • docusign.net
field:"sender.email.domain.root_domain" kind:eq value:"docusign.net"
type.inboundeq
  • true transforms: boolean
field:"type.inbound" kind:eq value:"true"

Callback phishing via e-signature service

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

Detects messages containing e-signature topics combined with tech support keywords and phone numbers. Message includes brand impersonation (PayPal, Norton, McAfee, etc.) and transaction-related language, with no attachments and reply-to addresses from free email providers.

Threat classification

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

CategoryValues
Attack typesCallback Phishing
Tactics and techniquesFree email provider, Impersonation: Brand, Social engineering

Telemetry coverage

PlatformRecord / event type
SublimeInbound email message

Message attributes

  • body
  • body.current_thread
  • headers
  • headers.auth_summary
  • headers.reply_to
  • type

Rule body

type.inbound
and length(attachments) == 0
and any(headers.reply_to, .email.domain.root_domain in $free_email_providers)
and any(beta.ml_topic(body.current_thread.text).topics, .name == "E-Signature")
and (headers.auth_summary.spf.pass or headers.auth_summary.dmarc.pass)
and (
  // this section is synced with attachment_callback_phish_with_pdf.yml and attachment_callback_phish_with_img.yml
  regex.icontains(strings.replace_confusables(body.current_thread.text),
                  '(p.{0,3}a.{0,3}y.{0,3}p.{0,3}a.{0,3}l|ma?c.?fee|n[o0]rt[o0]n|geek.{0,5}squad|ebay|symantec|best buy|lifel[o0]c|secure anywhere|starz|utilities premium|pc security|at&t)'
  )
  or any(ml.logo_detect(file.message_screenshot()).brands,
         .name in (
           "PayPal",
           "Norton",
           "GeekSquad",
           "Ebay",
           "McAfee",
           "AT&T",
           "Microsoft"
         )
  )
)
and (
  (
    // this seciton is synced with attachment_callback_phish_with_img.yml and attachment_callback_phish_with_pdf.yml
    // however, the 3 of logic and requiring a phone number is specific to this rule in order to reduce FPs
    // caused by messages which mention cancelling or otherwise managing a subscription
    // it is also synced and below for message_screenshot OCR output
    3 of (
      strings.icontains(body.current_thread.text, 'purchase'),
      strings.icontains(body.current_thread.text, 'payment'),
      strings.icontains(body.current_thread.text, 'transaction'),
      strings.icontains(body.current_thread.text, 'subscription'),
      strings.icontains(body.current_thread.text, 'antivirus'),
      strings.icontains(body.current_thread.text, 'order'),
      strings.icontains(body.current_thread.text, 'support'),
      strings.icontains(body.current_thread.text, 'help line'),
      strings.icontains(body.current_thread.text, 'receipt'),
      strings.icontains(body.current_thread.text, 'invoice'),
      strings.icontains(body.current_thread.text, 'call'),
      strings.icontains(body.current_thread.text, 'cancel'),
      strings.icontains(body.current_thread.text, 'renew'),
      strings.icontains(body.current_thread.text, 'refund'),
      regex.icontains(body.current_thread.text, "(?:reach|contact) us at"),
      strings.icontains(body.current_thread.text, "+1"),
      strings.icontains(body.current_thread.text, "amount"),
      strings.icontains(body.current_thread.text, "charged"),
      strings.icontains(body.current_thread.text, "crypto"),
      strings.icontains(body.current_thread.text, "wallet address"),
      regex.icontains(body.current_thread.text, '\$\d{3}\.\d{2}\b'),
    )
    // phone number regex
    and regex.icontains(body.current_thread.text,
                        '\+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4}',
                        '\+?([ilo0-9]{1,2})?\s?\(?\d{3}\)?[\s\.\-⋅]{0,5}[ilo0-9]{3}[\s\.\-⋅]{0,5}[ilo0-9]{4}'
    )
  )
  or (
    // this seciton is synced with attachment_callback_phish_with_img.yml and attachment_callback_phish_with_pdf.yml
    // and above for current_thread.text
    //
    // This rule makes use of a beta feature and is subject to change without notice
    // using the beta feature in custom rules is not suggested until it has been formally released
    //
    3 of (
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'purchase'),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'payment'),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'transaction'),
      strings.icontains(beta.ocr(file.message_screenshot()).text,
                        'subscription'
      ),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'antivirus'),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'order'),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'support'),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'help line'),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'receipt'),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'invoice'),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'call'),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'helpdesk'),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'cancel'),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'renew'),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'refund'),
      regex.icontains(beta.ocr(file.message_screenshot()).text,
                      "(?:reach|contact) us at"
      ),
      strings.icontains(beta.ocr(file.message_screenshot()).text, '+1'),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'amount'),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'charged'),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'crypto'),
      strings.icontains(beta.ocr(file.message_screenshot()).text,
                        'wallet address'
      ),
      regex.icontains(beta.ocr(file.message_screenshot()).text,
                      '\$\d{3}\.\d{2}\b'
      ),
    )
    // phone number regex
    and regex.icontains(beta.ocr(file.message_screenshot()).text,
                        '\+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4}',
                        '\+?([ilo0-9]{1,2})?\s?\(?\d{3}\)?[\s\.\-⋅]{0,5}[ilo0-9]{3}[\s\.\-⋅]{0,5}[ilo0-9]{4}'
    )

    // negate messages with previous threads.  While callback phishing with thread hijacking or with current_thread 
    // padded with whitespace and previous threads in the message has been observed, the intetion of using OCR is for image embedded callbacks
    and not regex.icount(beta.ocr(file.message_screenshot()).text,
                         '(?:from|to|sent|date|cc|subject):'
    ) > 3
    // this notation of previous threads often only occurs once
    and not regex.icontains(beta.ocr(file.message_screenshot()).text,
                            'wrote:[\r\n]'
    )
  )
)

Detection logic

Scope: inbound message.

Detects messages containing e-signature topics combined with tech support keywords and phone numbers. Message includes brand impersonation (PayPal, Norton, McAfee, etc.) and transaction-related language, with no attachments and reply-to addresses from free email providers.

  1. inbound message
  2. length(attachments) is 0
  3. any of headers.reply_to where:
    • .email.domain.root_domain in $free_email_providers
  4. any of beta.ml_topic(body.current_thread.text).topics where:
    • .name is 'E-Signature'
  5. any of:
    • headers.auth_summary.spf.pass
    • headers.auth_summary.dmarc.pass
  6. any of:
    • strings.replace_confusables(body.current_thread.text) matches '(p.{0,3}a.{0,3}y.{0,3}p.{0,3}a.{0,3}l|ma?c.?fee|n[o0]rt[o0]n|geek.{0,5}squad|ebay|symantec|best buy|lifel[o0]c|secure anywhere|starz|utilities premium|pc security|at&t)'
    • any of ml.logo_detect(file.message_screenshot()).brands where:
      • .name in ('PayPal', 'Norton', 'GeekSquad', 'Ebay', 'McAfee', 'AT&T', 'Microsoft')
  7. any of:
    • all of:
      • at least 3 of:
        • body.current_thread.text contains 'purchase'
        • body.current_thread.text contains 'payment'
        • body.current_thread.text contains 'transaction'
        • body.current_thread.text contains 'subscription'
        • body.current_thread.text contains 'antivirus'
        • body.current_thread.text contains 'order'
        • body.current_thread.text contains 'support'
        • body.current_thread.text contains 'help line'
        • body.current_thread.text contains 'receipt'
        • body.current_thread.text contains 'invoice'
        • body.current_thread.text contains 'call'
        • body.current_thread.text contains 'cancel'
        • body.current_thread.text contains 'renew'
        • body.current_thread.text contains 'refund'
        • body.current_thread.text matches '(?:reach|contact) us at'
        • body.current_thread.text contains '+1'
        • body.current_thread.text contains 'amount'
        • body.current_thread.text contains 'charged'
        • body.current_thread.text contains 'crypto'
        • body.current_thread.text contains 'wallet address'
        • body.current_thread.text matches '\\$\\d{3}\\.\\d{2}\\b'
      • body.current_thread.text matches any of 2 patterns
        • \+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4}
        • \+?([ilo0-9]{1,2})?\s?\(?\d{3}\)?[\s\.\-⋅]{0,5}[ilo0-9]{3}[\s\.\-⋅]{0,5}[ilo0-9]{4}
    • all of:
      • at least 3 of:
        • beta.ocr(file.message_screenshot()).text contains 'purchase'
        • beta.ocr(file.message_screenshot()).text contains 'payment'
        • beta.ocr(file.message_screenshot()).text contains 'transaction'
        • beta.ocr(file.message_screenshot()).text contains 'subscription'
        • beta.ocr(file.message_screenshot()).text contains 'antivirus'
        • beta.ocr(file.message_screenshot()).text contains 'order'
        • beta.ocr(file.message_screenshot()).text contains 'support'
        • beta.ocr(file.message_screenshot()).text contains 'help line'
        • beta.ocr(file.message_screenshot()).text contains 'receipt'
        • beta.ocr(file.message_screenshot()).text contains 'invoice'
        • beta.ocr(file.message_screenshot()).text contains 'call'
        • beta.ocr(file.message_screenshot()).text contains 'helpdesk'
        • beta.ocr(file.message_screenshot()).text contains 'cancel'
        • beta.ocr(file.message_screenshot()).text contains 'renew'
        • beta.ocr(file.message_screenshot()).text contains 'refund'
        • beta.ocr(file.message_screenshot()).text matches '(?:reach|contact) us at'
        • beta.ocr(file.message_screenshot()).text contains '+1'
        • beta.ocr(file.message_screenshot()).text contains 'amount'
        • beta.ocr(file.message_screenshot()).text contains 'charged'
        • beta.ocr(file.message_screenshot()).text contains 'crypto'
        • beta.ocr(file.message_screenshot()).text contains 'wallet address'
        • beta.ocr(file.message_screenshot()).text matches '\\$\\d{3}\\.\\d{2}\\b'
      • beta.ocr(file.message_screenshot()).text matches any of 2 patterns
        • \+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4}
        • \+?([ilo0-9]{1,2})?\s?\(?\d{3}\)?[\s\.\-⋅]{0,5}[ilo0-9]{3}[\s\.\-⋅]{0,5}[ilo0-9]{4}
      • not:
        • regex.icount(beta.ocr(file.message_screenshot()).text, '(?:from|to|sent|date|cc|subject):') > 3
      • not:
        • beta.ocr(file.message_screenshot()).text matches 'wrote:[\\r\\n]'

Inspects: body.current_thread.text, headers.auth_summary.dmarc.pass, headers.auth_summary.spf.pass, headers.reply_to, headers.reply_to[].email.domain.root_domain, type.inbound. Sensors: beta.ml_topic, beta.ocr, file.message_screenshot, ml.logo_detect, regex.icontains, regex.icount, strings.icontains, strings.replace_confusables. Reference lists: $free_email_providers.

Indicators matched (33)

FieldMatchValue
beta.ml_topic(body.current_thread.text).topics[].nameequalsE-Signature
regex.icontainsregex(p.{0,3}a.{0,3}y.{0,3}p.{0,3}a.{0,3}l|ma?c.?fee|n[o0]rt[o0]n|geek.{0,5}squad|ebay|symantec|best buy|lifel[o0]c|secure anywhere|starz|utilities premium|pc security|at&t)
ml.logo_detect(file.message_screenshot()).brands[].namememberPayPal
ml.logo_detect(file.message_screenshot()).brands[].namememberNorton
ml.logo_detect(file.message_screenshot()).brands[].namememberGeekSquad
ml.logo_detect(file.message_screenshot()).brands[].namememberEbay
ml.logo_detect(file.message_screenshot()).brands[].namememberMcAfee
ml.logo_detect(file.message_screenshot()).brands[].namememberAT&T
ml.logo_detect(file.message_screenshot()).brands[].namememberMicrosoft
strings.icontainssubstringpurchase
strings.icontainssubstringpayment
strings.icontainssubstringtransaction
21 more
strings.icontainssubstringsubscription
strings.icontainssubstringantivirus
strings.icontainssubstringorder
strings.icontainssubstringsupport
strings.icontainssubstringhelp line
strings.icontainssubstringreceipt
strings.icontainssubstringinvoice
strings.icontainssubstringcall
strings.icontainssubstringcancel
strings.icontainssubstringrenew
strings.icontainssubstringrefund
regex.icontainsregex(?:reach|contact) us at
strings.icontainssubstring+1
strings.icontainssubstringamount
strings.icontainssubstringcharged
strings.icontainssubstringcrypto
strings.icontainssubstringwallet address
regex.icontainsregex\$\d{3}\.\d{2}\b
regex.icontainsregex\+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4}
regex.icontainsregex\+?([ilo0-9]{1,2})?\s?\(?\d{3}\)?[\s\.\-⋅]{0,5}[ilo0-9]{3}[\s\.\-⋅]{0,5}[ilo0-9]{4}
strings.icontainssubstringhelpdesk

Stages and Predicates

Stage 1: mql_rule

and
  or
    and
      or
        beta.ocr(file.message_screenshot()).text contains "+1"
        beta.ocr(file.message_screenshot()).text contains "amount"
        beta.ocr(file.message_screenshot()).text contains "antivirus"
        beta.ocr(file.message_screenshot()).text contains "call"
        beta.ocr(file.message_screenshot()).text contains "cancel"
        beta.ocr(file.message_screenshot()).text contains "charged"
        beta.ocr(file.message_screenshot()).text contains "crypto"
        beta.ocr(file.message_screenshot()).text contains "help line"
        beta.ocr(file.message_screenshot()).text contains "helpdesk"
        beta.ocr(file.message_screenshot()).text contains "invoice"
        beta.ocr(file.message_screenshot()).text contains "order"
        beta.ocr(file.message_screenshot()).text contains "payment"
        beta.ocr(file.message_screenshot()).text contains "purchase"
        beta.ocr(file.message_screenshot()).text contains "receipt"
        beta.ocr(file.message_screenshot()).text contains "refund"
        beta.ocr(file.message_screenshot()).text contains "renew"
        beta.ocr(file.message_screenshot()).text contains "subscription"
        beta.ocr(file.message_screenshot()).text contains "support"
        beta.ocr(file.message_screenshot()).text contains "transaction"
        beta.ocr(file.message_screenshot()).text contains "wallet address"
        beta.ocr(file.message_screenshot()).text regex_match "(?:reach|contact) us at"
        beta.ocr(file.message_screenshot()).text regex_match "\\$\\d{3}\\.\\d{2}\\b"
      or
        beta.ocr(file.message_screenshot()).text regex_match "\\+?([ilo0-9]{1,2})?\\s?\\(?\\d{3}\\)?[\\s\\.\\-⋅]{0,5}[ilo0-9]{3}[\\s\\.\\-⋅]{0,5}[ilo0-9]{4}"
        beta.ocr(file.message_screenshot()).text regex_match "\\+?([ilo0-9]{1}.)?\\(?[ilo0-9]{3}?\\)?.[ilo0-9]{3}.?[ilo0-9]{4}"
      not
        beta.ocr(file.message_screenshot()).text regex_match "wrote:[\\r\\n]"
      not
        regex.icount func_call "regex.icount(beta.ocr(file.message_screenshot()).text, \"(?:from|to|sent|date|cc|subject):\") > 3"
    and
      or
        body.current_thread.text contains "+1"
        body.current_thread.text contains "amount"
        body.current_thread.text contains "antivirus"
        body.current_thread.text contains "call"
        body.current_thread.text contains "cancel"
        body.current_thread.text contains "charged"
        body.current_thread.text contains "crypto"
        body.current_thread.text contains "help line"
        body.current_thread.text contains "invoice"
        body.current_thread.text contains "order"
        body.current_thread.text contains "payment"
        body.current_thread.text contains "purchase"
        body.current_thread.text contains "receipt"
        body.current_thread.text contains "refund"
        body.current_thread.text contains "renew"
        body.current_thread.text contains "subscription"
        body.current_thread.text contains "support"
        body.current_thread.text contains "transaction"
        body.current_thread.text contains "wallet address"
        body.current_thread.text regex_match "(?:reach|contact) us at"
        body.current_thread.text regex_match "\\$\\d{3}\\.\\d{2}\\b"
      or
        body.current_thread.text regex_match "\\+?([ilo0-9]{1,2})?\\s?\\(?\\d{3}\\)?[\\s\\.\\-⋅]{0,5}[ilo0-9]{3}[\\s\\.\\-⋅]{0,5}[ilo0-9]{4}"
        body.current_thread.text regex_match "\\+?([ilo0-9]{1}.)?\\(?[ilo0-9]{3}?\\)?.[ilo0-9]{3}.?[ilo0-9]{4}"
  or
    any(ml.logo_detect(file.message_screenshot()).brands)
      ml.logo_detect(file.message_screenshot()).brands.name in ["AT&T", "Ebay", "GeekSquad", "McAfee", "Microsoft", "Norton", "PayPal"]
    strings.replace_confusables(body.current_thread.text) regex_match "(p.{0,3}a.{0,3}y.{0,3}p.{0,3}a.{0,3}l|ma?c.?fee|n[o0]rt[o0]n|geek.{0,5}squad|ebay|symantec|best buy|lifel[o0]c|secure anywhere|starz|utilities premium|pc security|at&t)"
  any(beta.ml_topic(body.current_thread.text).topics)
    beta.ml_topic(body.current_thread.text).topics.name eq "E-Signature"
  or
    headers.auth_summary.dmarc.pass eq "true"
    headers.auth_summary.spf.pass eq "true"
  any(headers.reply_to)
     macro "headers.reply_to[].email.domain.root_domain in free_email_providers"
  attachments length_compare "0"
  type.inbound eq "true"

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
beta.ocr(file.message_screenshot()).textcontains
  • +1
  • amount
  • antivirus
  • call
  • cancel
  • charged
  • crypto
  • help line
  • helpdesk
  • invoice
  • order
  • payment
  • purchase
  • receipt
  • refund
  • renew
  • subscription
  • support
  • transaction
  • wallet address
field:"beta.ocr(file.message_screenshot()).text" kind:contains
beta.ocr(file.message_screenshot()).textregex_match
  • (?:reach|contact) us at
  • $\d{3}.\d{2}\b
  • +?([ilo0-9]{1,2})?\s?(?\d{3})?[\s.\-⋅]{0,5}[ilo0-9]{3}[\s.\-⋅]{0,5}[ilo0-9]{4}
  • +?([ilo0-9]{1}.)?(?[ilo0-9]{3}?)?.[ilo0-9]{3}.?[ilo0-9]{4}
field:"beta.ocr(file.message_screenshot()).text" kind:regex_match
body.current_thread.textcontains
  • +1
  • amount
  • antivirus
  • call
  • cancel
  • charged
  • crypto
  • help line
  • invoice
  • order
  • payment
  • purchase
  • receipt
  • refund
  • renew
  • subscription
  • support
  • transaction
  • wallet address
field:"body.current_thread.text" kind:contains
body.current_thread.textregex_match
  • (?:reach|contact) us at
  • $\d{3}.\d{2}\b
  • +?([ilo0-9]{1,2})?\s?(?\d{3})?[\s.\-⋅]{0,5}[ilo0-9]{3}[\s.\-⋅]{0,5}[ilo0-9]{4}
  • +?([ilo0-9]{1}.)?(?[ilo0-9]{3}?)?.[ilo0-9]{3}.?[ilo0-9]{4}
field:"body.current_thread.text" kind:regex_match
headers.auth_summary.dmarc.passeq
  • true transforms: boolean
field:"headers.auth_summary.dmarc.pass" kind:eq value:"true"
headers.auth_summary.spf.passeq
  • true transforms: boolean
field:"headers.auth_summary.spf.pass" kind:eq value:"true"
strings.replace_confusables(body.current_thread.text)regex_match
  • (p.{0,3}a.{0,3}y.{0,3}p.{0,3}a.{0,3}l|ma?c.?fee|n[o0]rt[o0]n|geek.{0,5}squad|ebay|symantec|best buy|lifel[o0]c|secure anywhere|starz|utilities premium|pc security|at&t)
field:"strings.replace_confusables(body.current_thread.text)" kind:regex_match value:"(p.{0,3}a.{0,3}y.{0,3}p.{0,3}a.{0,3}l|ma?c.?fee|n[o0]rt[o0]n|geek.{0,5}squad|ebay|symantec|best buy|lifel[o0]c|secure anywhere|starz|utilities premium|pc security|at&t)"
type.inboundeq
  • true transforms: boolean
field:"type.inbound" kind:eq value:"true"

Callback phishing via extensionless rfc822 attachment

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

This rule detects messages with an unknown file_type (extensionless) and a content_type of 'message/rfc822' containing an image file with Callback Phishing indicators.

Threat classification

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

CategoryValues
Attack typesCallback Phishing
Tactics and techniquesImpersonation: Brand, Social engineering

Telemetry coverage

PlatformRecord / event type
SublimeInbound email message

Message attributes

  • attachments
  • body
  • body.current_thread
  • headers
  • headers.auth_summary
  • sender.email
  • type

Rule body

type.inbound
and any(attachments,
        .file_type == "unknown"
        and (.content_type == "message/rfc822" or .file_extension in ('eml'))
        and any(file.explode(.),
                strings.starts_with(.flavors.mime, "image")

                // and Image contains callback phishing indicators
                and 4 of (
                  strings.icontains(.scan.ocr.raw, "purchase"),
                  strings.icontains(.scan.ocr.raw, "subscription"),
                  strings.icontains(.scan.ocr.raw, "antivirus"),
                  strings.icontains(.scan.ocr.raw, "order"),
                  strings.icontains(.scan.ocr.raw, "support"),
                  strings.icontains(.scan.ocr.raw, "receipt"),
                  strings.icontains(.scan.ocr.raw, "amount"),
                  strings.icontains(.scan.ocr.raw, "charged"),
                  strings.icontains(.scan.ocr.raw, "invoice"),
                  strings.icontains(.scan.ocr.raw, "call"),
                  strings.icontains(.scan.ocr.raw, "cancel"),
                  strings.icontains(.scan.ocr.raw, "renew"),
                  strings.icontains(.scan.ocr.raw, "refund"),
                  strings.icontains(.scan.ocr.raw, "+1")
                )
        )
        and any(file.explode(.),
                strings.ilike(.scan.ocr.raw,
                              "*geek*squad*",
                              "*lifelock*",
                              "*best buy*",
                              "*mcafee*",
                              "*norton*",
                              "*ebay*",
                              "*paypal*",
                              "*secure anywhere*"
                )
                or any(ml.nlu_classifier(.scan.ocr.raw).intents,
                       .name in ("callback_scam")
                       and .confidence == "high"
                       and length(body.current_thread.text) < 1500
                )
        )
)
and (
  not profile.by_sender().solicited
  and not profile.by_sender().any_messages_benign
)

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

This rule detects messages with an unknown file_type (extensionless) and a content_type of 'message/rfc822' containing an image file with Callback Phishing indicators.

  1. inbound message
  2. any of attachments where all hold:
    • .file_type is 'unknown'
    • any of:
      • .content_type is 'message/rfc822'
      • .file_extension in ('eml')
    • any of file.explode(.) where all hold:
      • .flavors.mime starts with 'image'
      • at least 4 of 14: .scan.ocr.raw contains any of 14 patterns
        • purchase
        • subscription
        • antivirus
        • order
        • support
        • receipt
        • amount
        • charged
        • invoice
        • call
        • cancel
        • renew
        • refund
        • +1
    • any of file.explode(.) where any holds:
      • .scan.ocr.raw matches any of 8 patterns
        • *geek*squad*
        • *lifelock*
        • *best buy*
        • *mcafee*
        • *norton*
        • *ebay*
        • *paypal*
        • *secure anywhere*
      • any of ml.nlu_classifier(.scan.ocr.raw).intents where all hold:
        • .name in ('callback_scam')
        • .confidence is 'high'
        • length(body.current_thread.text) < 1500
  3. all of:
    • not:
      • profile.by_sender().solicited
    • not:
      • profile.by_sender().any_messages_benign
  4. 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: attachments[].content_type, attachments[].file_extension, attachments[].file_type, body.current_thread.text, headers.auth_summary.dmarc.pass, sender.email.domain.root_domain, type.inbound. Sensors: file.explode, ml.nlu_classifier, profile.by_sender, strings.icontains, strings.ilike, strings.starts_with. Reference lists: $high_trust_sender_root_domains.

Indicators matched (28)

FieldMatchValue
attachments[].file_typeequalsunknown
attachments[].content_typeequalsmessage/rfc822
attachments[].file_extensionmembereml
strings.starts_withprefiximage
strings.icontainssubstringpurchase
strings.icontainssubstringsubscription
strings.icontainssubstringantivirus
strings.icontainssubstringorder
strings.icontainssubstringsupport
strings.icontainssubstringreceipt
strings.icontainssubstringamount
strings.icontainssubstringcharged
16 more
strings.icontainssubstringinvoice
strings.icontainssubstringcall
strings.icontainssubstringcancel
strings.icontainssubstringrenew
strings.icontainssubstringrefund
strings.icontainssubstring+1
strings.ilikesubstring*geek*squad*
strings.ilikesubstring*lifelock*
strings.ilikesubstring*best buy*
strings.ilikesubstring*mcafee*
strings.ilikesubstring*norton*
strings.ilikesubstring*ebay*
strings.ilikesubstring*paypal*
strings.ilikesubstring*secure anywhere*
ml.nlu_classifier(file.explode(attachments[])[].scan.ocr.raw).intents[].namemembercallback_scam
ml.nlu_classifier(file.explode(attachments[])[].scan.ocr.raw).intents[].confidenceequalshigh

Stages and Predicates

Stage 1: mql_rule

and
  any(attachments)
    and
      any(file.explode(attachments))
        or
          any(ml.nlu_classifier(file.explode(attachments).scan.ocr.raw).intents)
            and
              body.current_thread.text length_compare "1500"
              ml.nlu_classifier(file.explode(attachments[])[].scan.ocr.raw).intents[].confidence eq "high"
              ml.nlu_classifier(file.explode(attachments[])[].scan.ocr.raw).intents[].name eq "callback_scam"
          file.explode(attachments[])[].scan.ocr.raw match "best buy"
          file.explode(attachments[])[].scan.ocr.raw match "ebay"
          file.explode(attachments[])[].scan.ocr.raw match "lifelock"
          file.explode(attachments[])[].scan.ocr.raw match "mcafee"
          file.explode(attachments[])[].scan.ocr.raw match "norton"
          file.explode(attachments[])[].scan.ocr.raw match "paypal"
          file.explode(attachments[])[].scan.ocr.raw match "secure anywhere"
          file.explode(attachments[])[].scan.ocr.raw wildcard "*geek*squad*"
      any(file.explode(attachments))
        and
          or
            file.explode(attachments[])[].scan.ocr.raw contains "+1"
            file.explode(attachments[])[].scan.ocr.raw contains "amount"
            file.explode(attachments[])[].scan.ocr.raw contains "antivirus"
            file.explode(attachments[])[].scan.ocr.raw contains "call"
            file.explode(attachments[])[].scan.ocr.raw contains "cancel"
            file.explode(attachments[])[].scan.ocr.raw contains "charged"
            file.explode(attachments[])[].scan.ocr.raw contains "invoice"
            file.explode(attachments[])[].scan.ocr.raw contains "order"
            file.explode(attachments[])[].scan.ocr.raw contains "purchase"
            file.explode(attachments[])[].scan.ocr.raw contains "receipt"
            file.explode(attachments[])[].scan.ocr.raw contains "refund"
            file.explode(attachments[])[].scan.ocr.raw contains "renew"
            file.explode(attachments[])[].scan.ocr.raw contains "subscription"
            file.explode(attachments[])[].scan.ocr.raw contains "support"
          file.explode(attachments[])[].flavors.mime starts_with "image"
      or
        attachments.content_type eq "message/rfc822"
        attachments.file_extension eq "eml"
      attachments.file_type eq "unknown"
  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"
  not
    profile.by_sender func_call "profile.by_sender().any_messages_benign"
  not
    profile.by_sender func_call "profile.by_sender().solicited"
  type.inbound eq "true"

Indicators

These rows show field, operator, and value matches.

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

Callback phishing via Google Group abuse

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

A fraudulent invoice/receipt found in the body of the message, delivered via a Google Group mailing list.

Threat classification

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

CategoryValues
Attack typesCallback Phishing
Tactics and techniquesFree email provider, Impersonation: Brand, Social engineering

Telemetry coverage

PlatformRecord / event type
SublimeInbound email message

Message attributes

  • attachments
  • body
  • body.current_thread
  • headers
  • headers.auth_summary
  • sender.email
  • type

Rule body

type.inbound
and length(attachments) < 5
and sender.email.domain.domain == "googlegroups.com"
and (
  any(attachments,
      (.file_type in $file_types_images or .file_type == "pdf")
      and (
        any(file.explode(.),
            // exclude images taken with mobile cameras and screenshots from android
            not any(.scan.exiftool.fields,
                    (
                      .key == "Model"
                      or (
                        .key == "Software"
                        and strings.starts_with(.value, "Android")
                      )
                    )
                    // exclude images taken with mobile cameras and screenshots from Apple
                    and (
                      .key == "DeviceManufacturer"
                      and .value == "Apple Computer Inc."
                    )
            )
            and any(ml.nlu_classifier(.scan.ocr.raw).intents,
                    .name == "callback_scam" and .confidence == "high"
            )
        )
      )
  )
  or any(ml.nlu_classifier(body.current_thread.text).intents,
         .name in ("callback_scam") and .confidence == "high"
  )
)

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

A fraudulent invoice/receipt found in the body of the message, delivered via a Google Group mailing list.

  1. inbound message
  2. length(attachments) < 5
  3. sender.email.domain.domain is 'googlegroups.com'
  4. any of:
    • any of attachments where all hold:
      • any of:
        • .file_type in $file_types_images
        • .file_type is 'pdf'
      • any of file.explode(.) where all hold:
        • not:
          • any of .scan.exiftool.fields where all hold:
            • any of:
              • .key is 'Model'
              • all of:
                • .key is 'Software'
                • .value starts with 'Android'
            • all of:
              • .key is 'DeviceManufacturer'
              • .value is 'Apple Computer Inc.'
        • any of ml.nlu_classifier(.scan.ocr.raw).intents where all hold:
          • .name is 'callback_scam'
          • .confidence is 'high'
    • any of ml.nlu_classifier(body.current_thread.text).intents where all hold:
      • .name in ('callback_scam')
      • .confidence is 'high'
  5. 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: attachments[].file_type, body.current_thread.text, headers.auth_summary.dmarc.pass, sender.email.domain.domain, sender.email.domain.root_domain, type.inbound. Sensors: file.explode, ml.nlu_classifier, strings.starts_with. Reference lists: $file_types_images, $high_trust_sender_root_domains.

Indicators matched (6)

FieldMatchValue
sender.email.domain.domainequalsgooglegroups.com
attachments[].file_typeequalspdf
ml.nlu_classifier(file.explode(attachments[])[].scan.ocr.raw).intents[].nameequalscallback_scam
ml.nlu_classifier(file.explode(attachments[])[].scan.ocr.raw).intents[].confidenceequalshigh
ml.nlu_classifier(body.current_thread.text).intents[].namemembercallback_scam
ml.nlu_classifier(body.current_thread.text).intents[].confidenceequalshigh

Stages and Predicates

Stage 1: mql_rule

and
  or
    any(attachments)
      and
        any(file.explode(attachments))
          and
            not
              any(file.explode(attachments).scan.exiftool.fields)
                and
                  or
                    and
                      file.explode(attachments[])[].scan.exiftool.fields[].key eq "Software"
                      file.explode(attachments[])[].scan.exiftool.fields[].value starts_with "Android"
                    file.explode(attachments[])[].scan.exiftool.fields[].key eq "Model"
                  file.explode(attachments[])[].scan.exiftool.fields[].key eq "DeviceManufacturer"
                  file.explode(attachments[])[].scan.exiftool.fields[].value eq "Apple Computer Inc."
            any(ml.nlu_classifier(file.explode(attachments).scan.ocr.raw).intents)
              and
                ml.nlu_classifier(file.explode(attachments[])[].scan.ocr.raw).intents[].confidence eq "high"
                ml.nlu_classifier(file.explode(attachments[])[].scan.ocr.raw).intents[].name eq "callback_scam"
        or
          attachments.file_type eq "pdf"
           macro "attachments[].file_type in file_types_images"
    any(ml.nlu_classifier(body.current_thread.text).intents)
      and
        ml.nlu_classifier(body.current_thread.text).intents.confidence eq "high"
        ml.nlu_classifier(body.current_thread.text).intents.name eq "callback_scam"
  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"
  attachments length_compare "5"
  sender.email.domain.domain eq "googlegroups.com"
  type.inbound eq "true"

Indicators

These rows show field, operator, and value matches.

Callback phishing via Google Meet

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

Detects Google Meet invitations that include callback phishing content in the body, impersonating brands like McAfee, Norton, PayPal, or Best Buy with purchase-related language and phone numbers to solicit victim contact.

Threat classification

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

CategoryValues
Attack typesCallback Phishing
Tactics and techniquesOut of band pivot

Telemetry coverage

PlatformRecord / event type
SublimeInbound email message

Message attributes

  • attachments
  • body
  • body.current_thread
  • body.links
  • subject
  • type

Rule body

type.inbound
and length(attachments) == 2
and all(attachments,
        .content_type == "text/calendar" or .file_extension == "ics"
)
and strings.starts_with(subject.base, "Invitation:")
// Google Meet indicators
and (
  any(body.links,
      .display_text == "Join with Google Meet"
      and .href_url.domain.domain == "meet.google.com"
  )
)
and (
  (
    regex.icontains(body.current_thread.text,
                    (
                      "(?:mcafee|norton|geek.{0,5}squad|paypal|ebay|symantec|best buy|lifelock|apple)"
                    )
    )
    and 3 of (
      strings.ilike(body.current_thread.text, '*purchase*'),
      strings.ilike(body.current_thread.text, '*payment*'),
      strings.ilike(body.current_thread.text, '*transaction*'),
      strings.ilike(body.current_thread.text, '*subscription*'),
      strings.ilike(body.current_thread.text, '*antivirus*'),
      strings.ilike(body.current_thread.text, '*order*'),
      strings.ilike(body.current_thread.text, '*support*'),
      strings.ilike(body.current_thread.text, '*help line*'),
      strings.ilike(body.current_thread.text, '*receipt*'),
      strings.ilike(body.current_thread.text, '*invoice*'),
      strings.ilike(body.current_thread.text, '*call*'),
      strings.ilike(body.current_thread.text, '*cancel*'),
      strings.ilike(body.current_thread.text, '*renew*'),
      strings.ilike(body.current_thread.text, '*refund*')
    )
    // toll-free phone number regex
    and any([body.current_thread.text, subject.subject],
            regex.icontains(., '\b\+?(\d{1}.)?\(?8\d{2}?\)?.\d{3}.?\d{4}\b')
    )
  )
)

Detection logic

Scope: inbound message.

Detects Google Meet invitations that include callback phishing content in the body, impersonating brands like McAfee, Norton, PayPal, or Best Buy with purchase-related language and phone numbers to solicit victim contact.

  1. inbound message
  2. length(attachments) is 2
  3. all of attachments where any holds:
    • .content_type is 'text/calendar'
    • .file_extension is 'ics'
  4. subject.base starts with 'Invitation:'
  5. any of body.links where all hold:
    • .display_text is 'Join with Google Meet'
    • .href_url.domain.domain is 'meet.google.com'
  6. all of:
    • body.current_thread.text matches '(?:mcafee|norton|geek.{0,5}squad|paypal|ebay|symantec|best buy|lifelock|apple)'
    • at least 3 of 14: body.current_thread.text matches any of 14 patterns
      • *purchase*
      • *payment*
      • *transaction*
      • *subscription*
      • *antivirus*
      • *order*
      • *support*
      • *help line*
      • *receipt*
      • *invoice*
      • *call*
      • *cancel*
      • *renew*
      • *refund*
    • any of [body.current_thread.text, subject.subject] where:
      • . matches '\\b\\+?(\\d{1}.)?\\(?8\\d{2}?\\)?.\\d{3}.?\\d{4}\\b'

Inspects: attachments[].content_type, attachments[].file_extension, body.current_thread.text, body.links, body.links[].display_text, body.links[].href_url.domain.domain, subject.base, subject.subject, type.inbound. Sensors: regex.icontains, strings.ilike, strings.starts_with.

Indicators matched (21)

FieldMatchValue
attachments[].content_typeequalstext/calendar
attachments[].file_extensionequalsics
strings.starts_withprefixInvitation:
body.links[].display_textequalsJoin with Google Meet
body.links[].href_url.domain.domainequalsmeet.google.com
regex.icontainsregex(?:mcafee|norton|geek.{0,5}squad|paypal|ebay|symantec|best buy|lifelock|apple)
strings.ilikesubstring*purchase*
strings.ilikesubstring*payment*
strings.ilikesubstring*transaction*
strings.ilikesubstring*subscription*
strings.ilikesubstring*antivirus*
strings.ilikesubstring*order*
9 more
strings.ilikesubstring*support*
strings.ilikesubstring*help line*
strings.ilikesubstring*receipt*
strings.ilikesubstring*invoice*
strings.ilikesubstring*call*
strings.ilikesubstring*cancel*
strings.ilikesubstring*renew*
strings.ilikesubstring*refund*
regex.icontainsregex\b\+?(\d{1}.)?\(?8\d{2}?\)?.\d{3}.?\d{4}\b

Stages and Predicates

Stage 1: mql_rule

and
  any(body.links)
    and
      body.links.display_text eq "Join with Google Meet"
      body.links.href_url.domain.domain eq "meet.google.com"
  any([body.current_thread.text, subject.subject])
    [body.current_thread.text, subject.subject] regex_match "\\b\\+?(\\d{1}.)?\\(?8\\d{2}?\\)?.\\d{3}.?\\d{4}\\b"
  or
    body.current_thread.text match "antivirus"
    body.current_thread.text match "call"
    body.current_thread.text match "cancel"
    body.current_thread.text match "help line"
    body.current_thread.text match "invoice"
    body.current_thread.text match "order"
    body.current_thread.text match "payment"
    body.current_thread.text match "purchase"
    body.current_thread.text match "receipt"
    body.current_thread.text match "refund"
    body.current_thread.text match "renew"
    body.current_thread.text match "subscription"
    body.current_thread.text match "support"
    body.current_thread.text match "transaction"
  attachments length_compare "2"
  body.current_thread.text regex_match "(?:mcafee|norton|geek.{0,5}squad|paypal|ebay|symantec|best buy|lifelock|apple)"
  subject.base starts_with "Invitation:"
  type.inbound eq "true"
   macro "all(attachments)"

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
body.current_thread.textregex_match
  • (?:mcafee|norton|geek.{0,5}squad|paypal|ebay|symantec|best buy|lifelock|apple)
field:"body.current_thread.text" kind:regex_match value:"(?:mcafee|norton|geek.{0,5}squad|paypal|ebay|symantec|best buy|lifelock|apple)"
body.current_thread.textwildcard
  • *antivirus*
  • *call*
  • *cancel*
  • *help line*
  • *invoice*
  • *order*
  • *payment*
  • *purchase*
  • *receipt*
  • *refund*
  • *renew*
  • *subscription*
  • *support*
  • *transaction*
field:"body.current_thread.text" kind:wildcard
subject.basestarts_with
  • Invitation:
field:"subject.base" kind:starts_with value:"Invitation:"
type.inboundeq
  • true transforms: boolean
field:"type.inbound" kind:eq value:"true"

Callback phishing via Intuit service abuse

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

Callback phishing campaigns have been observed abusing Intuit Quickbooks services to send fraudulent invoices with callback phishing contents.

Threat classification

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

CategoryValues
Attack typesCallback Phishing
Tactics and techniquesEvasion, Free email provider, Impersonation: Brand, Social engineering

Telemetry coverage

PlatformRecord / event type
SublimeInbound email message

Message attributes

  • attachments
  • body
  • body.current_thread
  • body.html
  • headers
  • headers.auth_summary
  • sender.email
  • subject
  • type

Rule body

type.inbound

// Legitimate Intuit sending infratructure
and (
  sender.email.domain.root_domain in ('intuit.com', 'intuit.co.uk')
  // check for SPF or DMARC passed
  and (headers.auth_summary.spf.pass or headers.auth_summary.dmarc.pass)
)
and (
  // Callback Phishing in body (brand names required)
  (
    length(attachments) == 0

    // brand names are required.
    and regex.icontains(strings.replace_confusables(body.current_thread.text),
                        (
                          "mcafee|norton|geek.{0,5}squad|paypal|ebay|symantec|best buy|lifelock"
                        )
    )
    and 3 of (
      strings.ilike(body.current_thread.text, '*purchase*'),
      strings.ilike(body.current_thread.text, '*payment*'),
      strings.ilike(body.current_thread.text, '*transaction*'),
      strings.ilike(body.current_thread.text, '*subscription*'),
      strings.ilike(body.current_thread.text, '*antivirus*'),
      strings.ilike(body.current_thread.text, '*order*'),
      strings.ilike(body.current_thread.text, '*support*'),
      strings.ilike(body.current_thread.text, '*help line*'),
      strings.ilike(body.current_thread.text, '*receipt*'),
      strings.ilike(body.current_thread.text, '*invoice*'),
      strings.ilike(body.current_thread.text, '*call*'),
      strings.ilike(body.current_thread.text, '*cancel*'),
      strings.ilike(body.current_thread.text, '*renew*'),
      strings.ilike(body.current_thread.text, '*refund*')
    )
    // phone number regex
    and any([body.current_thread.text, subject.subject],
            regex.icontains(., '\b\+?(\d{1}.)?\(?\d{3}?\)?.\d{3}.?\d{4}\b')
    )
  )
  // Callback Phishing in the "billtoContent"
  or 
  // icontains a phone number
  (
    regex.icontains(strings.replace_confusables(body.html.inner_text),
                    '(?:Sold|Bill)[\s\xa0]To(?:\:\s+|\n)[^\n]+\+?(\d{1}.)?\(?\d{3}?\)?.\d{3}.?\d{4}.*\n'
    )
    or regex.icontains(strings.replace_confusables(body.html.inner_text),
                       '(?:Sold|Bill)[\s\xa0]To(?:\:\s+|\n)[^\n]+\+\d{1,3}[ilo0-9]{10}.*\n'
    )
    // +12028001238
    or regex.icontains(strings.replace_confusables(body.html.inner_text),
                       '(?:Sold|Bill)[\s\xa0]To(?:\:\s+|\n)[^\n]+[ilo0-9]{3}\.[ilo0-9]{3}\.[ilo0-9]{4}.*\n'
    )
    // 202-800-1238
    or regex.icontains(strings.replace_confusables(body.html.inner_text),
                       '(?:Sold|Bill)[\s\xa0]To(?:\:\s+|\n)[^\n]+[ilo0-9]{3}-[ilo0-9]{3}-[ilo0-9]{4}.*\n'
    )
    // (202) 800-1238
    or regex.icontains(strings.replace_confusables(body.html.inner_text),
                       '(?:Sold|Bill)[\s\xa0]To(?:\:\s+|\n)[^\n]+\([ilo0-9]{3}\)[\s-]+[ilo0-9]{3}[\s-]+[ilo0-9]{4}.*\n'
    )
    // (202)-800-1238
    or regex.icontains(strings.replace_confusables(body.html.inner_text),
                       '(?:Sold|Bill)[\s\xa0]To(?:\:\s+|\n)[^\n]+\([ilo0-9]{3}\)-[ilo0-9]{3}-[ilo0-9]{4}.*\n'
    )
    // 202 800 1238
    or regex.icontains(strings.replace_confusables(body.html.inner_text),
                       '(?:Sold|Bill)[\s\xa0]To(?:\:\s+|\n)[^\n]+1\s?[ilo0-9]{3} [ilo0-9]{3} [ilo0-9]{4}.*\n'
    ) // 8123456789
    or (
      regex.icontains(strings.replace_confusables(body.html.inner_text),
                      '(?:Sold|Bill)[\s\xa0]To(?:\:\s+|\n)[^\n]+8\d{9}.*\n'
      )
      and regex.icontains(strings.replace_confusables(body.html.inner_text),
                          '\+1'
      )
    )
  )
  // all attachments are PDFs with callback phishing indicators Brands Required
  or (
    length(attachments) < 3
    and all(attachments, .file_extension == "pdf")
    // the attachment is a pdf with 1 page, and at least 60 ocr chars
    and any(attachments,
            (
              .file_extension == "pdf"
              and any(file.explode(.), .scan.exiftool.page_count < 3)
              and any(file.explode(.), length(.scan.ocr.raw) > 60)

              // 4 of the following strings are found
              and (
                any(file.explode(.),
                    4 of (
                      strings.icontains(.scan.ocr.raw, "purchase"),
                      strings.icontains(.scan.ocr.raw, "payment"),
                      strings.icontains(.scan.ocr.raw, "transaction"),
                      strings.icontains(.scan.ocr.raw, "subscription"),
                      strings.icontains(.scan.ocr.raw, "antivirus"),
                      strings.icontains(.scan.ocr.raw, "order"),
                      strings.icontains(.scan.ocr.raw, "support"),
                      strings.icontains(.scan.ocr.raw, "help line"),
                      strings.icontains(.scan.ocr.raw, "receipt"),
                      strings.icontains(.scan.ocr.raw, "invoice"),
                      strings.icontains(.scan.ocr.raw, "call"),
                      strings.icontains(.scan.ocr.raw, "helpdesk"),
                      strings.icontains(.scan.ocr.raw, "cancel"),
                      strings.icontains(.scan.ocr.raw, "renew"),
                      strings.icontains(.scan.ocr.raw, "refund"),
                      strings.icontains(.scan.ocr.raw, "amount"),
                      strings.icontains(.scan.ocr.raw, "crypto"),
                      strings.icontains(.scan.ocr.raw, "wallet address"),
                      regex.icontains(.scan.ocr.raw, '\$\d{3}\.\d{2}\b'),
                      regex.icontains(.scan.ocr.raw,
                                      '(\+\d|1.(\()?\d{3}(\))?\D\d{3}\D\d{4})'
                      ),
                      regex.icontains(.scan.ocr.raw,
                                      '\+?(\d{1,2})?\s?\(?\d{3}\)?[\s\.\-⋅]{0,5}\d{3}[\s\.\-⋅]{0,5}\d{4}'
                      )
                    )

                    // 1 of the following strings is found, representing common Callback brands
                    and (
                      1 of (
                        strings.icontains(.scan.ocr.raw, "geek squad"),
                        strings.icontains(.scan.ocr.raw, "lifelock"),
                        strings.icontains(.scan.ocr.raw, "best buy"),
                        strings.icontains(.scan.ocr.raw, "mcafee"),
                        strings.icontains(.scan.ocr.raw, "norton"),
                        strings.icontains(.scan.ocr.raw, "ebay"),
                        strings.icontains(.scan.ocr.raw, "paypal"),
                      )
                      // add additional logic for common language for paypal, which is a valid payment method
                      and not regex.icontains(.scan.ocr.raw,
                                              "paypal[^\n]+accepted"
                      )
                      and not regex.icontains(.scan.ocr.raw,
                                              "pay(ment)?.{0,30}(via|by) paypal"
                      )
                      and not regex.icontains(.scan.ocr.raw,
                                              '\d{2,4} norton'
                      ) // an address, example: 1234 Norton Road
                      and not regex.icontains(.scan.ocr.raw,
                                              'sold on.{0,20}ebay'
                      ) // "cannot be sold on Amazon and EBay", from a legit vendor
                    )
                )
                or any(ml.logo_detect(.).brands,
                       .name in ("PayPal", "Norton", "GeekSquad", "Ebay")
                )
              )
            )
    )
  )
)

//
// This rule makes use of a beta feature and is subject to change without notice
// using the beta feature in custom rules is not suggested until it has been formally released
//
and (
  not beta.profile.by_reply_to().any_messages_benign
  or length(headers.reply_to) == 0
)

Detection logic

Scope: inbound message.

Callback phishing campaigns have been observed abusing Intuit Quickbooks services to send fraudulent invoices with callback phishing contents.

  1. inbound message
  2. all of:
    • sender.email.domain.root_domain in ('intuit.com', 'intuit.co.uk')
    • any of:
      • headers.auth_summary.spf.pass
      • headers.auth_summary.dmarc.pass
  3. any of:
    • all of:
      • length(attachments) is 0
      • strings.replace_confusables(body.current_thread.text) matches 'mcafee|norton|geek.{0,5}squad|paypal|ebay|symantec|best buy|lifelock'
      • at least 3 of 14: body.current_thread.text matches any of 14 patterns
        • *purchase*
        • *payment*
        • *transaction*
        • *subscription*
        • *antivirus*
        • *order*
        • *support*
        • *help line*
        • *receipt*
        • *invoice*
        • *call*
        • *cancel*
        • *renew*
        • *refund*
      • any of [body.current_thread.text, subject.subject] where:
        • . matches '\\b\\+?(\\d{1}.)?\\(?\\d{3}?\\)?.\\d{3}.?\\d{4}\\b'
    • any of:
      • strings.replace_confusables(body.html.inner_text) matches '(?:Sold|Bill)[\\s\\xa0]To(?:\\:\\s+|\\n)[^\\n]+\\+?(\\d{1}.)?\\(?\\d{3}?\\)?.\\d{3}.?\\d{4}.*\\n'
      • strings.replace_confusables(body.html.inner_text) matches '(?:Sold|Bill)[\\s\\xa0]To(?:\\:\\s+|\\n)[^\\n]+\\+\\d{1,3}[ilo0-9]{10}.*\\n'
      • strings.replace_confusables(body.html.inner_text) matches '(?:Sold|Bill)[\\s\\xa0]To(?:\\:\\s+|\\n)[^\\n]+[ilo0-9]{3}\\.[ilo0-9]{3}\\.[ilo0-9]{4}.*\\n'
      • strings.replace_confusables(body.html.inner_text) matches '(?:Sold|Bill)[\\s\\xa0]To(?:\\:\\s+|\\n)[^\\n]+[ilo0-9]{3}-[ilo0-9]{3}-[ilo0-9]{4}.*\\n'
      • strings.replace_confusables(body.html.inner_text) matches '(?:Sold|Bill)[\\s\\xa0]To(?:\\:\\s+|\\n)[^\\n]+\\([ilo0-9]{3}\\)[\\s-]+[ilo0-9]{3}[\\s-]+[ilo0-9]{4}.*\\n'
      • strings.replace_confusables(body.html.inner_text) matches '(?:Sold|Bill)[\\s\\xa0]To(?:\\:\\s+|\\n)[^\\n]+\\([ilo0-9]{3}\\)-[ilo0-9]{3}-[ilo0-9]{4}.*\\n'
      • strings.replace_confusables(body.html.inner_text) matches '(?:Sold|Bill)[\\s\\xa0]To(?:\\:\\s+|\\n)[^\\n]+1\\s?[ilo0-9]{3} [ilo0-9]{3} [ilo0-9]{4}.*\\n'
      • all of:
        • strings.replace_confusables(body.html.inner_text) matches '(?:Sold|Bill)[\\s\\xa0]To(?:\\:\\s+|\\n)[^\\n]+8\\d{9}.*\\n'
        • strings.replace_confusables(body.html.inner_text) matches '\\+1'
    • all of:
      • length(attachments) < 3
      • all of attachments where:
        • .file_extension is 'pdf'
      • any of attachments where all hold:
        • .file_extension is 'pdf'
        • any of file.explode(.) where:
          • .scan.exiftool.page_count < 3
        • any of file.explode(.) where:
          • length(.scan.ocr.raw) > 60
        • any of:
          • any of file.explode(.) where all hold:
            • at least 4 of:
              • .scan.ocr.raw contains 'purchase'
              • .scan.ocr.raw contains 'payment'
              • .scan.ocr.raw contains 'transaction'
              • .scan.ocr.raw contains 'subscription'
              • .scan.ocr.raw contains 'antivirus'
              • .scan.ocr.raw contains 'order'
              • .scan.ocr.raw contains 'support'
              • .scan.ocr.raw contains 'help line'
              • .scan.ocr.raw contains 'receipt'
              • .scan.ocr.raw contains 'invoice'
              • .scan.ocr.raw contains 'call'
              • .scan.ocr.raw contains 'helpdesk'
              • .scan.ocr.raw contains 'cancel'
              • .scan.ocr.raw contains 'renew'
              • .scan.ocr.raw contains 'refund'
              • .scan.ocr.raw contains 'amount'
              • .scan.ocr.raw contains 'crypto'
              • .scan.ocr.raw contains 'wallet address'
              • .scan.ocr.raw matches '\\$\\d{3}\\.\\d{2}\\b'
              • .scan.ocr.raw matches '(\\+\\d|1.(\\()?\\d{3}(\\))?\\D\\d{3}\\D\\d{4})'
              • .scan.ocr.raw matches '\\+?(\\d{1,2})?\\s?\\(?\\d{3}\\)?[\\s\\.\\-⋅]{0,5}\\d{3}[\\s\\.\\-⋅]{0,5}\\d{4}'
            • all of:
              • at least 1 of 7: .scan.ocr.raw contains any of 7 patterns
                • geek squad
                • lifelock
                • best buy
                • mcafee
                • norton
                • ebay
                • paypal
              • not:
                • .scan.ocr.raw matches 'paypal[^\\n]+accepted'
              • not:
                • .scan.ocr.raw matches 'pay(ment)?.{0,30}(via|by) paypal'
              • not:
                • .scan.ocr.raw matches '\\d{2,4} norton'
              • not:
                • .scan.ocr.raw matches 'sold on.{0,20}ebay'
          • any of ml.logo_detect(.).brands where:
            • .name in ('PayPal', 'Norton', 'GeekSquad', 'Ebay')
  4. any of:
    • not:
      • beta.profile.by_reply_to().any_messages_benign
    • length(headers.reply_to) is 0

Inspects: attachments[].file_extension, body.current_thread.text, body.html.inner_text, headers.auth_summary.dmarc.pass, headers.auth_summary.spf.pass, headers.reply_to, sender.email.domain.root_domain, subject.subject, type.inbound. Sensors: beta.profile.by_reply_to, file.explode, ml.logo_detect, regex.icontains, strings.icontains, strings.ilike, strings.replace_confusables.

Indicators matched (60)

FieldMatchValue
sender.email.domain.root_domainmemberintuit.com
sender.email.domain.root_domainmemberintuit.co.uk
regex.icontainsregexmcafee|norton|geek.{0,5}squad|paypal|ebay|symantec|best buy|lifelock
strings.ilikesubstring*purchase*
strings.ilikesubstring*payment*
strings.ilikesubstring*transaction*
strings.ilikesubstring*subscription*
strings.ilikesubstring*antivirus*
strings.ilikesubstring*order*
strings.ilikesubstring*support*
strings.ilikesubstring*help line*
strings.ilikesubstring*receipt*
48 more
strings.ilikesubstring*invoice*
strings.ilikesubstring*call*
strings.ilikesubstring*cancel*
strings.ilikesubstring*renew*
strings.ilikesubstring*refund*
regex.icontainsregex\b\+?(\d{1}.)?\(?\d{3}?\)?.\d{3}.?\d{4}\b
regex.icontainsregex(?:Sold|Bill)[\s\xa0]To(?:\:\s+|\n)[^\n]+\+?(\d{1}.)?\(?\d{3}?\)?.\d{3}.?\d{4}.*\n
regex.icontainsregex(?:Sold|Bill)[\s\xa0]To(?:\:\s+|\n)[^\n]+\+\d{1,3}[ilo0-9]{10}.*\n
regex.icontainsregex(?:Sold|Bill)[\s\xa0]To(?:\:\s+|\n)[^\n]+[ilo0-9]{3}\.[ilo0-9]{3}\.[ilo0-9]{4}.*\n
regex.icontainsregex(?:Sold|Bill)[\s\xa0]To(?:\:\s+|\n)[^\n]+[ilo0-9]{3}-[ilo0-9]{3}-[ilo0-9]{4}.*\n
regex.icontainsregex(?:Sold|Bill)[\s\xa0]To(?:\:\s+|\n)[^\n]+\([ilo0-9]{3}\)[\s-]+[ilo0-9]{3}[\s-]+[ilo0-9]{4}.*\n
regex.icontainsregex(?:Sold|Bill)[\s\xa0]To(?:\:\s+|\n)[^\n]+\([ilo0-9]{3}\)-[ilo0-9]{3}-[ilo0-9]{4}.*\n
regex.icontainsregex(?:Sold|Bill)[\s\xa0]To(?:\:\s+|\n)[^\n]+1\s?[ilo0-9]{3} [ilo0-9]{3} [ilo0-9]{4}.*\n
regex.icontainsregex(?:Sold|Bill)[\s\xa0]To(?:\:\s+|\n)[^\n]+8\d{9}.*\n
regex.icontainsregex\+1
attachments[].file_extensionequalspdf
strings.icontainssubstringpurchase
strings.icontainssubstringpayment
strings.icontainssubstringtransaction
strings.icontainssubstringsubscription
strings.icontainssubstringantivirus
strings.icontainssubstringorder
strings.icontainssubstringsupport
strings.icontainssubstringhelp line
strings.icontainssubstringreceipt
strings.icontainssubstringinvoice
strings.icontainssubstringcall
strings.icontainssubstringhelpdesk
strings.icontainssubstringcancel
strings.icontainssubstringrenew
strings.icontainssubstringrefund
strings.icontainssubstringamount
strings.icontainssubstringcrypto
strings.icontainssubstringwallet address
regex.icontainsregex\$\d{3}\.\d{2}\b
regex.icontainsregex(\+\d|1.(\()?\d{3}(\))?\D\d{3}\D\d{4})
regex.icontainsregex\+?(\d{1,2})?\s?\(?\d{3}\)?[\s\.\-⋅]{0,5}\d{3}[\s\.\-⋅]{0,5}\d{4}
strings.icontainssubstringgeek squad
strings.icontainssubstringlifelock
strings.icontainssubstringbest buy
strings.icontainssubstringmcafee
strings.icontainssubstringnorton
strings.icontainssubstringebay
strings.icontainssubstringpaypal
ml.logo_detect(attachments[]).brands[].namememberPayPal
ml.logo_detect(attachments[]).brands[].namememberNorton
ml.logo_detect(attachments[]).brands[].namememberGeekSquad
ml.logo_detect(attachments[]).brands[].namememberEbay

Stages and Predicates

Stage 1: mql_rule

and
  or
    and
      any(attachments)
        and
          or
            any(file.explode(attachments))
              and
                or
                  file.explode(attachments[])[].scan.ocr.raw contains "amount"
                  file.explode(attachments[])[].scan.ocr.raw contains "antivirus"
                  file.explode(attachments[])[].scan.ocr.raw contains "call"
                  file.explode(attachments[])[].scan.ocr.raw contains "cancel"
                  file.explode(attachments[])[].scan.ocr.raw contains "crypto"
                  file.explode(attachments[])[].scan.ocr.raw contains "help line"
                  file.explode(attachments[])[].scan.ocr.raw contains "helpdesk"
                  file.explode(attachments[])[].scan.ocr.raw contains "invoice"
                  file.explode(attachments[])[].scan.ocr.raw contains "order"
                  file.explode(attachments[])[].scan.ocr.raw contains "payment"
                  file.explode(attachments[])[].scan.ocr.raw contains "purchase"
                  file.explode(attachments[])[].scan.ocr.raw contains "receipt"
                  file.explode(attachments[])[].scan.ocr.raw contains "refund"
                  file.explode(attachments[])[].scan.ocr.raw contains "renew"
                  file.explode(attachments[])[].scan.ocr.raw contains "subscription"
                  file.explode(attachments[])[].scan.ocr.raw contains "support"
                  file.explode(attachments[])[].scan.ocr.raw contains "transaction"
                  file.explode(attachments[])[].scan.ocr.raw contains "wallet address"
                  file.explode(attachments[])[].scan.ocr.raw regex_match "(\\+\\d|1.(\\()?\\d{3}(\\))?\\D\\d{3}\\D\\d{4})"
                  file.explode(attachments[])[].scan.ocr.raw regex_match "\\$\\d{3}\\.\\d{2}\\b"
                  file.explode(attachments[])[].scan.ocr.raw regex_match "\\+?(\\d{1,2})?\\s?\\(?\\d{3}\\)?[\\s\\.\\-⋅]{0,5}\\d{3}[\\s\\.\\-⋅]{0,5}\\d{4}"
                or
                  file.explode(attachments[])[].scan.ocr.raw contains "best buy"
                  file.explode(attachments[])[].scan.ocr.raw contains "ebay"
                  file.explode(attachments[])[].scan.ocr.raw contains "geek squad"
                  file.explode(attachments[])[].scan.ocr.raw contains "lifelock"
                  file.explode(attachments[])[].scan.ocr.raw contains "mcafee"
                  file.explode(attachments[])[].scan.ocr.raw contains "norton"
                  file.explode(attachments[])[].scan.ocr.raw contains "paypal"
                not
                  file.explode(attachments[])[].scan.ocr.raw regex_match "\\d{2,4} norton"
                not
                  file.explode(attachments[])[].scan.ocr.raw regex_match "pay(ment)?.{0,30}(via|by) paypal"
                not
                  file.explode(attachments[])[].scan.ocr.raw regex_match "paypal[^\\n]+accepted"
                not
                  file.explode(attachments[])[].scan.ocr.raw regex_match "sold on.{0,20}ebay"
            any(ml.logo_detect(attachments).brands)
              ml.logo_detect(attachments).brands.name in ["Ebay", "GeekSquad", "Norton", "PayPal"]
          any(file.explode(attachments))
            file.explode(attachments).scan.exiftool.page_count lt "3"
          any(file.explode(attachments))
            file.explode(attachments).scan.ocr.raw length_compare "60"
          attachments.file_extension eq "pdf"
      attachments length_compare "3"
       macro "all(attachments)"
    and
      any([body.current_thread.text, subject.subject])
        [body.current_thread.text, subject.subject] regex_match "\\b\\+?(\\d{1}.)?\\(?\\d{3}?\\)?.\\d{3}.?\\d{4}\\b"
      or
        body.current_thread.text match "antivirus"
        body.current_thread.text match "call"
        body.current_thread.text match "cancel"
        body.current_thread.text match "help line"
        body.current_thread.text match "invoice"
        body.current_thread.text match "order"
        body.current_thread.text match "payment"
        body.current_thread.text match "purchase"
        body.current_thread.text match "receipt"
        body.current_thread.text match "refund"
        body.current_thread.text match "renew"
        body.current_thread.text match "subscription"
        body.current_thread.text match "support"
        body.current_thread.text match "transaction"
      attachments length_compare "0"
      strings.replace_confusables(body.current_thread.text) regex_match "mcafee|norton|geek.{0,5}squad|paypal|ebay|symantec|best buy|lifelock"
    and
      strings.replace_confusables(body.html.inner_text) regex_match "(?:Sold|Bill)[\\s\\xa0]To(?:\\:\\s+|\\n)[^\\n]+8\\d{9}.*\\n"
      strings.replace_confusables(body.html.inner_text) regex_match "\\+1"
    strings.replace_confusables(body.html.inner_text) regex_match "(?:Sold|Bill)[\\s\\xa0]To(?:\\:\\s+|\\n)[^\\n]+1\\s?[ilo0-9]{3} [ilo0-9]{3} [ilo0-9]{4}.*\\n"
    strings.replace_confusables(body.html.inner_text) regex_match "(?:Sold|Bill)[\\s\\xa0]To(?:\\:\\s+|\\n)[^\\n]+[ilo0-9]{3}-[ilo0-9]{3}-[ilo0-9]{4}.*\\n"
    strings.replace_confusables(body.html.inner_text) regex_match "(?:Sold|Bill)[\\s\\xa0]To(?:\\:\\s+|\\n)[^\\n]+[ilo0-9]{3}\\.[ilo0-9]{3}\\.[ilo0-9]{4}.*\\n"
    strings.replace_confusables(body.html.inner_text) regex_match "(?:Sold|Bill)[\\s\\xa0]To(?:\\:\\s+|\\n)[^\\n]+\\([ilo0-9]{3}\\)-[ilo0-9]{3}-[ilo0-9]{4}.*\\n"
    strings.replace_confusables(body.html.inner_text) regex_match "(?:Sold|Bill)[\\s\\xa0]To(?:\\:\\s+|\\n)[^\\n]+\\([ilo0-9]{3}\\)[\\s-]+[ilo0-9]{3}[\\s-]+[ilo0-9]{4}.*\\n"
    strings.replace_confusables(body.html.inner_text) regex_match "(?:Sold|Bill)[\\s\\xa0]To(?:\\:\\s+|\\n)[^\\n]+\\+?(\\d{1}.)?\\(?\\d{3}?\\)?.\\d{3}.?\\d{4}.*\\n"
    strings.replace_confusables(body.html.inner_text) regex_match "(?:Sold|Bill)[\\s\\xa0]To(?:\\:\\s+|\\n)[^\\n]+\\+\\d{1,3}[ilo0-9]{10}.*\\n"
  or
    not
      beta.profile.by_reply_to func_call "beta.profile.by_reply_to().any_messages_benign"
    headers.reply_to length_compare "0"
  or
    headers.auth_summary.dmarc.pass eq "true"
    headers.auth_summary.spf.pass eq "true"
  sender.email.domain.root_domain in ["intuit.co.uk", "intuit.com"]
  type.inbound eq "true"

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
body.current_thread.textwildcard
  • *antivirus*
  • *call*
  • *cancel*
  • *help line*
  • *invoice*
  • *order*
  • *payment*
  • *purchase*
  • *receipt*
  • *refund*
  • *renew*
  • *subscription*
  • *support*
  • *transaction*
field:"body.current_thread.text" kind:wildcard
headers.auth_summary.dmarc.passeq
  • true transforms: boolean
field:"headers.auth_summary.dmarc.pass" kind:eq value:"true"
headers.auth_summary.spf.passeq
  • true transforms: boolean
field:"headers.auth_summary.spf.pass" kind:eq value:"true"
sender.email.domain.root_domainin
  • intuit.co.uk
  • intuit.com
field:"sender.email.domain.root_domain" kind:in
strings.replace_confusables(body.current_thread.text)regex_match
    • mcafee
    • norton
    • geek.{0,5}squad
    • paypal
    • ebay
    • symantec
    • best buy
    • lifelock
field:"strings.replace_confusables(body.current_thread.text)" kind:regex_match
strings.replace_confusables(body.html.inner_text)regex_match
  • (?:Sold|Bill)[\s\xa0]To(?:\:\s+|\n)[^\n]+1\s?[ilo0-9]{3} [ilo0-9]{3} [ilo0-9]{4}.*\n
  • (?:Sold|Bill)[\s\xa0]To(?:\:\s+|\n)[^\n]+8\d{9}.*\n
  • (?:Sold|Bill)[\s\xa0]To(?:\:\s+|\n)[^\n]+[ilo0-9]{3}-[ilo0-9]{3}-[ilo0-9]{4}.*\n
  • (?:Sold|Bill)[\s\xa0]To(?:\:\s+|\n)[^\n]+[ilo0-9]{3}.[ilo0-9]{3}.[ilo0-9]{4}.*\n
  • (?:Sold|Bill)[\s\xa0]To(?:\:\s+|\n)[^\n]+([ilo0-9]{3})-[ilo0-9]{3}-[ilo0-9]{4}.*\n
  • (?:Sold|Bill)[\s\xa0]To(?:\:\s+|\n)[^\n]+([ilo0-9]{3})[\s-]+[ilo0-9]{3}[\s-]+[ilo0-9]{4}.*\n
  • (?:Sold|Bill)[\s\xa0]To(?:\:\s+|\n)[^\n]++?(\d{1}.)?(?\d{3}?)?.\d{3}.?\d{4}.*\n
  • (?:Sold|Bill)[\s\xa0]To(?:\:\s+|\n)[^\n]++\d{1,3}[ilo0-9]{10}.*\n
  • +1
field:"strings.replace_confusables(body.html.inner_text)" kind:regex_match
type.inboundeq
  • true transforms: boolean
field:"type.inbound" kind:eq value:"true"

Callback phishing via Microsoft comment

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

Detects callback scam messages originating from legitimate Microsoft infrastructure but containing fraudulent content designed to trick recipients into calling scammer phone numbers. The message includes typical callback phishing language around purchases, payments, subscriptions, or support services along with embedded phone numbers, while passing Microsoft's authentication checks.

Threat classification

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

CategoryValues
Attack typesCallback Phishing
Tactics and techniquesImpersonation: Brand, Out of band pivot, Social engineering

Telemetry coverage

PlatformRecord / event type
SublimeInbound email message

Message attributes

  • body
  • body.current_thread
  • sender.email
  • subject
  • type

Rule body

type.inbound
and length(attachments) == 0
and length(body.current_thread.text) < 1750

// Legitimate MicrosoftOnline sending infrastructure
// or invites@microsoft.com abuse
and (
  (
    sender.email.domain.root_domain in ('microsoftonline.com')
    or sender.email.email == "invites@microsoft.com"
  )

  // Callback Phishing
  and (
    any(ml.nlu_classifier(body.current_thread.text).intents,
        .name in ("callback_scam", "cred_theft")
        and .confidence in ("medium", "high")
    )
    or 3 of (
      strings.ilike(body.current_thread.text, '*purchase*'),
      strings.ilike(body.current_thread.text, '*payment*'),
      strings.ilike(body.current_thread.text, '*transaction*'),
      strings.ilike(body.current_thread.text, '*subscription*'),
      strings.ilike(body.current_thread.text, '*antivirus*'),
      strings.ilike(body.current_thread.text, '*order*'),
      strings.ilike(body.current_thread.text, '*support*'),
      strings.ilike(body.current_thread.text, '*help line*'),
      strings.ilike(body.current_thread.text, '*receipt*'),
      strings.ilike(body.current_thread.text, '*invoice*'),
      strings.ilike(body.current_thread.text, '*call*'),
      strings.ilike(body.current_thread.text, '*cancel*'),
      strings.ilike(body.current_thread.text, '*renew*'),
      strings.ilike(body.current_thread.text, '*refund*')
    )
    or regex.count(body.current_thread.text, '[^\x00-\x7F]') > 20
  )
  // phone number regex
  and any([body.current_thread.text, subject.subject],
          regex.icontains(.,
                          '\+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4}',
                          '\+?([ilo0-9]{1,2})?\s?\(?\d{3}\)?[\s\.\-⋅]{0,5}[ilo0-9]{3}[\s\.\-⋅]{0,5}[ilo0-9]{4}',
                          '\(?[ilo0-9]{3}\)?[^ilo0-9]{0,3}\(?[ilo0-9]{3}\)?.?[ilo0-9]{4}'
          )
  )
)

Detection logic

Scope: inbound message.

Detects callback scam messages originating from legitimate Microsoft infrastructure but containing fraudulent content designed to trick recipients into calling scammer phone numbers. The message includes typical callback phishing language around purchases, payments, subscriptions, or support services along with embedded phone numbers, while passing Microsoft's authentication checks.

  1. inbound message
  2. length(attachments) is 0
  3. length(body.current_thread.text) < 1750
  4. all of:
    • any of:
      • sender.email.domain.root_domain in ('microsoftonline.com')
      • sender.email.email is 'invites@microsoft.com'
    • any of:
      • any of ml.nlu_classifier(body.current_thread.text).intents where all hold:
        • .name in ('callback_scam', 'cred_theft')
        • .confidence in ('medium', 'high')
      • at least 3 of 14: body.current_thread.text matches any of 14 patterns
        • *purchase*
        • *payment*
        • *transaction*
        • *subscription*
        • *antivirus*
        • *order*
        • *support*
        • *help line*
        • *receipt*
        • *invoice*
        • *call*
        • *cancel*
        • *renew*
        • *refund*
      • regex.count(body.current_thread.text, '[^\\x00-\\x7F]') > 20
    • any of [body.current_thread.text, subject.subject] where:
      • . matches any of 3 patterns
        • \+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4}
        • \+?([ilo0-9]{1,2})?\s?\(?\d{3}\)?[\s\.\-⋅]{0,5}[ilo0-9]{3}[\s\.\-⋅]{0,5}[ilo0-9]{4}
        • \(?[ilo0-9]{3}\)?[^ilo0-9]{0,3}\(?[ilo0-9]{3}\)?.?[ilo0-9]{4}

Inspects: body.current_thread.text, sender.email.domain.root_domain, sender.email.email, subject.subject, type.inbound. Sensors: ml.nlu_classifier, regex.count, regex.icontains, strings.ilike.

Indicators matched (24)

FieldMatchValue
sender.email.domain.root_domainmembermicrosoftonline.com
sender.email.emailequalsinvites@microsoft.com
ml.nlu_classifier(body.current_thread.text).intents[].namemembercallback_scam
ml.nlu_classifier(body.current_thread.text).intents[].namemembercred_theft
ml.nlu_classifier(body.current_thread.text).intents[].confidencemembermedium
ml.nlu_classifier(body.current_thread.text).intents[].confidencememberhigh
strings.ilikesubstring*purchase*
strings.ilikesubstring*payment*
strings.ilikesubstring*transaction*
strings.ilikesubstring*subscription*
strings.ilikesubstring*antivirus*
strings.ilikesubstring*order*
12 more
strings.ilikesubstring*support*
strings.ilikesubstring*help line*
strings.ilikesubstring*receipt*
strings.ilikesubstring*invoice*
strings.ilikesubstring*call*
strings.ilikesubstring*cancel*
strings.ilikesubstring*renew*
strings.ilikesubstring*refund*
regex.countregex[^\x00-\x7F]
regex.icontainsregex\+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4}
regex.icontainsregex\+?([ilo0-9]{1,2})?\s?\(?\d{3}\)?[\s\.\-⋅]{0,5}[ilo0-9]{3}[\s\.\-⋅]{0,5}[ilo0-9]{4}
regex.icontainsregex\(?[ilo0-9]{3}\)?[^ilo0-9]{0,3}\(?[ilo0-9]{3}\)?.?[ilo0-9]{4}

Stages and Predicates

Stage 1: mql_rule

and
  or
    any(ml.nlu_classifier(body.current_thread.text).intents)
      and
        ml.nlu_classifier(body.current_thread.text).intents.confidence in ["high", "medium"]
        ml.nlu_classifier(body.current_thread.text).intents.name in ["callback_scam", "cred_theft"]
    body.current_thread.text match "antivirus"
    body.current_thread.text match "call"
    body.current_thread.text match "cancel"
    body.current_thread.text match "help line"
    body.current_thread.text match "invoice"
    body.current_thread.text match "order"
    body.current_thread.text match "payment"
    body.current_thread.text match "purchase"
    body.current_thread.text match "receipt"
    body.current_thread.text match "refund"
    body.current_thread.text match "renew"
    body.current_thread.text match "subscription"
    body.current_thread.text match "support"
    body.current_thread.text match "transaction"
    regex.count func_call "regex.count(body.current_thread.text, \"[^\\x00-\\x7F]\") > 20"
  any([body.current_thread.text, subject.subject])
    or
      [body.current_thread.text, subject.subject] regex_match "\\(?[ilo0-9]{3}\\)?[^ilo0-9]{0,3}\\(?[ilo0-9]{3}\\)?.?[ilo0-9]{4}"
      [body.current_thread.text, subject.subject] regex_match "\\+?([ilo0-9]{1,2})?\\s?\\(?\\d{3}\\)?[\\s\\.\\-⋅]{0,5}[ilo0-9]{3}[\\s\\.\\-⋅]{0,5}[ilo0-9]{4}"
      [body.current_thread.text, subject.subject] regex_match "\\+?([ilo0-9]{1}.)?\\(?[ilo0-9]{3}?\\)?.[ilo0-9]{3}.?[ilo0-9]{4}"
  or
    sender.email.domain.root_domain eq "microsoftonline.com"
    sender.email.email eq "invites@microsoft.com"
  attachments length_compare "0"
  body.current_thread.text length_compare "1750"
  type.inbound eq "true"

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
body.current_thread.textwildcard
  • *antivirus*
  • *call*
  • *cancel*
  • *help line*
  • *invoice*
  • *order*
  • *payment*
  • *purchase*
  • *receipt*
  • *refund*
  • *renew*
  • *subscription*
  • *support*
  • *transaction*
field:"body.current_thread.text" kind:wildcard
sender.email.domain.root_domainin
  • microsoftonline.com
field:"sender.email.domain.root_domain" kind:in value:"microsoftonline.com"
sender.email.emaileq
  • invites@microsoft.com
field:"sender.email.email" kind:eq value:"invites@microsoft.com"
type.inboundeq
  • true transforms: boolean
field:"type.inbound" kind:eq value:"true"

Callback Phishing via Signable E-Signature Request

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

This rule inspects messages originating from legitimate Signable infrastructure, with content matching Callback Phishing criteria, in the body, requiring at least one brand name, as well as 3 matching Callback Phishing terms and a phone number.

Threat classification

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

CategoryValues
Attack typesCallback Phishing
Tactics and techniquesExploit, Impersonation: Brand, Out of band pivot, Social engineering

Telemetry coverage

PlatformRecord / event type
SublimeInbound email message

Message attributes

  • body
  • body.current_thread
  • headers
  • headers.auth_summary
  • sender.email
  • type

Rule body

type.inbound
and length(attachments) == 0
and (
  not beta.profile.by_reply_to().solicited
  or (
    beta.profile.by_reply_to().any_messages_malicious_or_spam
    and not beta.profile.by_reply_to().any_messages_benign
  )
)
// Legitimate Signable sending infratructure
and sender.email.domain.root_domain == 'signable.app'
and (headers.auth_summary.spf.pass or headers.auth_summary.dmarc.pass)
and (
  // this section is synced with attachment_callback_phish_with_pdf.yml and attachment_callback_phish_with_img.yml
  regex.icontains(strings.replace_confusables(body.current_thread.text),
                  '(p.{0,3}a.{0,3}y.{0,3}p.{0,3}a.{0,3}l|ma?c.?fee|n[o0]rt[o0]n|geek.{0,5}squad|ebay|symantec|best buy|lifel[o0]c|secure anywhere|starz|utilities premium|pc security|at&t)'
  )
  or any(ml.logo_detect(file.message_screenshot()).brands,
         .name in (
           "PayPal",
           "Norton",
           "GeekSquad",
           "Ebay",
           "McAfee",
           "AT&T",
           "Microsoft"
         )
  )
)
and length(body.current_thread.text) < 1750
and (
  (
    // this seciton is synced with attachment_callback_phish_with_img.yml and attachment_callback_phish_with_pdf.yml
    // however, the 3 of logic and requiring a phone number is specific to this rule in order to reduce FPs
    // caused by messages which mention cancelling or otherwise managing a subscription
    // it is also synced and below for message_screenshot OCR output
    3 of (
      strings.icontains(body.current_thread.text, 'purchase'),
      strings.icontains(body.current_thread.text, 'payment'),
      strings.icontains(body.current_thread.text, 'transaction'),
      strings.icontains(body.current_thread.text, 'subscription'),
      strings.icontains(body.current_thread.text, 'antivirus'),
      strings.icontains(body.current_thread.text, 'order'),
      strings.icontains(body.current_thread.text, 'support'),
      strings.icontains(body.current_thread.text, 'help line'),
      strings.icontains(body.current_thread.text, 'receipt'),
      strings.icontains(body.current_thread.text, 'invoice'),
      strings.icontains(body.current_thread.text, 'call'),
      strings.icontains(body.current_thread.text, 'cancel'),
      strings.icontains(body.current_thread.text, 'renew'),
      strings.icontains(body.current_thread.text, 'refund'),
      regex.icontains(body.current_thread.text, "(?:reach|contact) us at"),
      strings.icontains(body.current_thread.text, "+1"),
      strings.icontains(body.current_thread.text, "amount"),
      strings.icontains(body.current_thread.text, "charged"),
      strings.icontains(body.current_thread.text, "crypto"),
      strings.icontains(body.current_thread.text, "wallet address"),
      regex.icontains(body.current_thread.text, '\$\d{3}\.\d{2}\b'),
    )
    // phone number regex
    and regex.icontains(body.current_thread.text,
                        '\+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4}',
                        '\+?([ilo0-9]{1,2})?\s?\(?\d{3}\)?[\s\.\-⋅]{0,5}[ilo0-9]{3}[\s\.\-⋅]{0,5}[ilo0-9]{4}'
    )
  )
  or (
    // this seciton is synced with attachment_callback_phish_with_img.yml and attachment_callback_phish_with_pdf.yml
    // and above for current_thread.text
    //
    // This rule makes use of a beta feature and is subject to change without notice
    // using the beta feature in custom rules is not suggested until it has been formally released
    //
    3 of (
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'purchase'),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'payment'),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'transaction'),
      strings.icontains(beta.ocr(file.message_screenshot()).text,
                        'subscription'
      ),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'antivirus'),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'order'),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'support'),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'help line'),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'receipt'),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'invoice'),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'call'),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'helpdesk'),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'cancel'),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'renew'),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'refund'),
      regex.icontains(beta.ocr(file.message_screenshot()).text,
                      "(?:reach|contact) us at"
      ),
      strings.icontains(beta.ocr(file.message_screenshot()).text, '+1'),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'amount'),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'charged'),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'crypto'),
      strings.icontains(beta.ocr(file.message_screenshot()).text,
                        'wallet address'
      ),
      regex.icontains(beta.ocr(file.message_screenshot()).text,
                      '\$\d{3}\.\d{2}\b'
      ),
    )
    // phone number regex
    and regex.icontains(beta.ocr(file.message_screenshot()).text,
                        '\+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4}',
                        '\+?([ilo0-9]{1,2})?\s?\(?\d{3}\)?[\s\.\-⋅]{0,5}[ilo0-9]{3}[\s\.\-⋅]{0,5}[ilo0-9]{4}'
    )

    // negate messages with previous threads.  While callback phishing with thread hijacking or with current_thread 
    // padded with whitespace and previous threads in the message has been observed, the intetion of using OCR is for image embedded callbacks
    and not regex.icount(beta.ocr(file.message_screenshot()).text,
                         '(?:from|to|sent|date|cc|subject):'
    ) > 3
    // this notation of previous threads often only occurs once
    and not regex.icontains(beta.ocr(file.message_screenshot()).text,
                            'wrote:[\r\n]'
    )
  )
)

Detection logic

Scope: inbound message.

This rule inspects messages originating from legitimate Signable infrastructure, with content matching Callback Phishing criteria, in the body, requiring at least one brand name, as well as 3 matching Callback Phishing terms and a phone number.

  1. inbound message
  2. length(attachments) is 0
  3. any of:
    • not:
      • beta.profile.by_reply_to().solicited
    • all of:
      • beta.profile.by_reply_to().any_messages_malicious_or_spam
      • not:
        • beta.profile.by_reply_to().any_messages_benign
  4. sender.email.domain.root_domain is 'signable.app'
  5. any of:
    • headers.auth_summary.spf.pass
    • headers.auth_summary.dmarc.pass
  6. any of:
    • strings.replace_confusables(body.current_thread.text) matches '(p.{0,3}a.{0,3}y.{0,3}p.{0,3}a.{0,3}l|ma?c.?fee|n[o0]rt[o0]n|geek.{0,5}squad|ebay|symantec|best buy|lifel[o0]c|secure anywhere|starz|utilities premium|pc security|at&t)'
    • any of ml.logo_detect(file.message_screenshot()).brands where:
      • .name in ('PayPal', 'Norton', 'GeekSquad', 'Ebay', 'McAfee', 'AT&T', 'Microsoft')
  7. length(body.current_thread.text) < 1750
  8. any of:
    • all of:
      • at least 3 of:
        • body.current_thread.text contains 'purchase'
        • body.current_thread.text contains 'payment'
        • body.current_thread.text contains 'transaction'
        • body.current_thread.text contains 'subscription'
        • body.current_thread.text contains 'antivirus'
        • body.current_thread.text contains 'order'
        • body.current_thread.text contains 'support'
        • body.current_thread.text contains 'help line'
        • body.current_thread.text contains 'receipt'
        • body.current_thread.text contains 'invoice'
        • body.current_thread.text contains 'call'
        • body.current_thread.text contains 'cancel'
        • body.current_thread.text contains 'renew'
        • body.current_thread.text contains 'refund'
        • body.current_thread.text matches '(?:reach|contact) us at'
        • body.current_thread.text contains '+1'
        • body.current_thread.text contains 'amount'
        • body.current_thread.text contains 'charged'
        • body.current_thread.text contains 'crypto'
        • body.current_thread.text contains 'wallet address'
        • body.current_thread.text matches '\\$\\d{3}\\.\\d{2}\\b'
      • body.current_thread.text matches any of 2 patterns
        • \+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4}
        • \+?([ilo0-9]{1,2})?\s?\(?\d{3}\)?[\s\.\-⋅]{0,5}[ilo0-9]{3}[\s\.\-⋅]{0,5}[ilo0-9]{4}
    • all of:
      • at least 3 of:
        • beta.ocr(file.message_screenshot()).text contains 'purchase'
        • beta.ocr(file.message_screenshot()).text contains 'payment'
        • beta.ocr(file.message_screenshot()).text contains 'transaction'
        • beta.ocr(file.message_screenshot()).text contains 'subscription'
        • beta.ocr(file.message_screenshot()).text contains 'antivirus'
        • beta.ocr(file.message_screenshot()).text contains 'order'
        • beta.ocr(file.message_screenshot()).text contains 'support'
        • beta.ocr(file.message_screenshot()).text contains 'help line'
        • beta.ocr(file.message_screenshot()).text contains 'receipt'
        • beta.ocr(file.message_screenshot()).text contains 'invoice'
        • beta.ocr(file.message_screenshot()).text contains 'call'
        • beta.ocr(file.message_screenshot()).text contains 'helpdesk'
        • beta.ocr(file.message_screenshot()).text contains 'cancel'
        • beta.ocr(file.message_screenshot()).text contains 'renew'
        • beta.ocr(file.message_screenshot()).text contains 'refund'
        • beta.ocr(file.message_screenshot()).text matches '(?:reach|contact) us at'
        • beta.ocr(file.message_screenshot()).text contains '+1'
        • beta.ocr(file.message_screenshot()).text contains 'amount'
        • beta.ocr(file.message_screenshot()).text contains 'charged'
        • beta.ocr(file.message_screenshot()).text contains 'crypto'
        • beta.ocr(file.message_screenshot()).text contains 'wallet address'
        • beta.ocr(file.message_screenshot()).text matches '\\$\\d{3}\\.\\d{2}\\b'
      • beta.ocr(file.message_screenshot()).text matches any of 2 patterns
        • \+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4}
        • \+?([ilo0-9]{1,2})?\s?\(?\d{3}\)?[\s\.\-⋅]{0,5}[ilo0-9]{3}[\s\.\-⋅]{0,5}[ilo0-9]{4}
      • not:
        • regex.icount(beta.ocr(file.message_screenshot()).text, '(?:from|to|sent|date|cc|subject):') > 3
      • not:
        • beta.ocr(file.message_screenshot()).text matches 'wrote:[\\r\\n]'

Inspects: body.current_thread.text, headers.auth_summary.dmarc.pass, headers.auth_summary.spf.pass, sender.email.domain.root_domain, type.inbound. Sensors: beta.ocr, beta.profile.by_reply_to, file.message_screenshot, ml.logo_detect, regex.icontains, regex.icount, strings.icontains, strings.replace_confusables.

Indicators matched (33)

FieldMatchValue
sender.email.domain.root_domainequalssignable.app
regex.icontainsregex(p.{0,3}a.{0,3}y.{0,3}p.{0,3}a.{0,3}l|ma?c.?fee|n[o0]rt[o0]n|geek.{0,5}squad|ebay|symantec|best buy|lifel[o0]c|secure anywhere|starz|utilities premium|pc security|at&t)
ml.logo_detect(file.message_screenshot()).brands[].namememberPayPal
ml.logo_detect(file.message_screenshot()).brands[].namememberNorton
ml.logo_detect(file.message_screenshot()).brands[].namememberGeekSquad
ml.logo_detect(file.message_screenshot()).brands[].namememberEbay
ml.logo_detect(file.message_screenshot()).brands[].namememberMcAfee
ml.logo_detect(file.message_screenshot()).brands[].namememberAT&T
ml.logo_detect(file.message_screenshot()).brands[].namememberMicrosoft
strings.icontainssubstringpurchase
strings.icontainssubstringpayment
strings.icontainssubstringtransaction
21 more
strings.icontainssubstringsubscription
strings.icontainssubstringantivirus
strings.icontainssubstringorder
strings.icontainssubstringsupport
strings.icontainssubstringhelp line
strings.icontainssubstringreceipt
strings.icontainssubstringinvoice
strings.icontainssubstringcall
strings.icontainssubstringcancel
strings.icontainssubstringrenew
strings.icontainssubstringrefund
regex.icontainsregex(?:reach|contact) us at
strings.icontainssubstring+1
strings.icontainssubstringamount
strings.icontainssubstringcharged
strings.icontainssubstringcrypto
strings.icontainssubstringwallet address
regex.icontainsregex\$\d{3}\.\d{2}\b
regex.icontainsregex\+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4}
regex.icontainsregex\+?([ilo0-9]{1,2})?\s?\(?\d{3}\)?[\s\.\-⋅]{0,5}[ilo0-9]{3}[\s\.\-⋅]{0,5}[ilo0-9]{4}
strings.icontainssubstringhelpdesk

Stages and Predicates

Stage 1: mql_rule

and
  or
    and
      or
        beta.ocr(file.message_screenshot()).text contains "+1"
        beta.ocr(file.message_screenshot()).text contains "amount"
        beta.ocr(file.message_screenshot()).text contains "antivirus"
        beta.ocr(file.message_screenshot()).text contains "call"
        beta.ocr(file.message_screenshot()).text contains "cancel"
        beta.ocr(file.message_screenshot()).text contains "charged"
        beta.ocr(file.message_screenshot()).text contains "crypto"
        beta.ocr(file.message_screenshot()).text contains "help line"
        beta.ocr(file.message_screenshot()).text contains "helpdesk"
        beta.ocr(file.message_screenshot()).text contains "invoice"
        beta.ocr(file.message_screenshot()).text contains "order"
        beta.ocr(file.message_screenshot()).text contains "payment"
        beta.ocr(file.message_screenshot()).text contains "purchase"
        beta.ocr(file.message_screenshot()).text contains "receipt"
        beta.ocr(file.message_screenshot()).text contains "refund"
        beta.ocr(file.message_screenshot()).text contains "renew"
        beta.ocr(file.message_screenshot()).text contains "subscription"
        beta.ocr(file.message_screenshot()).text contains "support"
        beta.ocr(file.message_screenshot()).text contains "transaction"
        beta.ocr(file.message_screenshot()).text contains "wallet address"
        beta.ocr(file.message_screenshot()).text regex_match "(?:reach|contact) us at"
        beta.ocr(file.message_screenshot()).text regex_match "\\$\\d{3}\\.\\d{2}\\b"
      or
        beta.ocr(file.message_screenshot()).text regex_match "\\+?([ilo0-9]{1,2})?\\s?\\(?\\d{3}\\)?[\\s\\.\\-⋅]{0,5}[ilo0-9]{3}[\\s\\.\\-⋅]{0,5}[ilo0-9]{4}"
        beta.ocr(file.message_screenshot()).text regex_match "\\+?([ilo0-9]{1}.)?\\(?[ilo0-9]{3}?\\)?.[ilo0-9]{3}.?[ilo0-9]{4}"
      not
        beta.ocr(file.message_screenshot()).text regex_match "wrote:[\\r\\n]"
      not
        regex.icount func_call "regex.icount(beta.ocr(file.message_screenshot()).text, \"(?:from|to|sent|date|cc|subject):\") > 3"
    and
      or
        body.current_thread.text contains "+1"
        body.current_thread.text contains "amount"
        body.current_thread.text contains "antivirus"
        body.current_thread.text contains "call"
        body.current_thread.text contains "cancel"
        body.current_thread.text contains "charged"
        body.current_thread.text contains "crypto"
        body.current_thread.text contains "help line"
        body.current_thread.text contains "invoice"
        body.current_thread.text contains "order"
        body.current_thread.text contains "payment"
        body.current_thread.text contains "purchase"
        body.current_thread.text contains "receipt"
        body.current_thread.text contains "refund"
        body.current_thread.text contains "renew"
        body.current_thread.text contains "subscription"
        body.current_thread.text contains "support"
        body.current_thread.text contains "transaction"
        body.current_thread.text contains "wallet address"
        body.current_thread.text regex_match "(?:reach|contact) us at"
        body.current_thread.text regex_match "\\$\\d{3}\\.\\d{2}\\b"
      or
        body.current_thread.text regex_match "\\+?([ilo0-9]{1,2})?\\s?\\(?\\d{3}\\)?[\\s\\.\\-⋅]{0,5}[ilo0-9]{3}[\\s\\.\\-⋅]{0,5}[ilo0-9]{4}"
        body.current_thread.text regex_match "\\+?([ilo0-9]{1}.)?\\(?[ilo0-9]{3}?\\)?.[ilo0-9]{3}.?[ilo0-9]{4}"
  or
    and
      not
        beta.profile.by_reply_to func_call "beta.profile.by_reply_to().any_messages_benign"
      beta.profile.by_reply_to func_call "beta.profile.by_reply_to().any_messages_malicious_or_spam"
    not
      beta.profile.by_reply_to func_call "beta.profile.by_reply_to().solicited"
  or
    any(ml.logo_detect(file.message_screenshot()).brands)
      ml.logo_detect(file.message_screenshot()).brands.name in ["AT&T", "Ebay", "GeekSquad", "McAfee", "Microsoft", "Norton", "PayPal"]
    strings.replace_confusables(body.current_thread.text) regex_match "(p.{0,3}a.{0,3}y.{0,3}p.{0,3}a.{0,3}l|ma?c.?fee|n[o0]rt[o0]n|geek.{0,5}squad|ebay|symantec|best buy|lifel[o0]c|secure anywhere|starz|utilities premium|pc security|at&t)"
  or
    headers.auth_summary.dmarc.pass eq "true"
    headers.auth_summary.spf.pass eq "true"
  attachments length_compare "0"
  body.current_thread.text length_compare "1750"
  sender.email.domain.root_domain eq "signable.app"
  type.inbound eq "true"

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
beta.ocr(file.message_screenshot()).textcontains
  • +1
  • amount
  • antivirus
  • call
  • cancel
  • charged
  • crypto
  • help line
  • helpdesk
  • invoice
  • order
  • payment
  • purchase
  • receipt
  • refund
  • renew
  • subscription
  • support
  • transaction
  • wallet address
field:"beta.ocr(file.message_screenshot()).text" kind:contains
beta.ocr(file.message_screenshot()).textregex_match
  • (?:reach|contact) us at
  • $\d{3}.\d{2}\b
  • +?([ilo0-9]{1,2})?\s?(?\d{3})?[\s.\-⋅]{0,5}[ilo0-9]{3}[\s.\-⋅]{0,5}[ilo0-9]{4}
  • +?([ilo0-9]{1}.)?(?[ilo0-9]{3}?)?.[ilo0-9]{3}.?[ilo0-9]{4}
field:"beta.ocr(file.message_screenshot()).text" kind:regex_match
body.current_thread.textcontains
  • +1
  • amount
  • antivirus
  • call
  • cancel
  • charged
  • crypto
  • help line
  • invoice
  • order
  • payment
  • purchase
  • receipt
  • refund
  • renew
  • subscription
  • support
  • transaction
  • wallet address
field:"body.current_thread.text" kind:contains
body.current_thread.textregex_match
  • (?:reach|contact) us at
  • $\d{3}.\d{2}\b
  • +?([ilo0-9]{1,2})?\s?(?\d{3})?[\s.\-⋅]{0,5}[ilo0-9]{3}[\s.\-⋅]{0,5}[ilo0-9]{4}
  • +?([ilo0-9]{1}.)?(?[ilo0-9]{3}?)?.[ilo0-9]{3}.?[ilo0-9]{4}
field:"body.current_thread.text" kind:regex_match
headers.auth_summary.dmarc.passeq
  • true transforms: boolean
field:"headers.auth_summary.dmarc.pass" kind:eq value:"true"
headers.auth_summary.spf.passeq
  • true transforms: boolean
field:"headers.auth_summary.spf.pass" kind:eq value:"true"
sender.email.domain.root_domaineq
  • signable.app
field:"sender.email.domain.root_domain" kind:eq value:"signable.app"
strings.replace_confusables(body.current_thread.text)regex_match
  • (p.{0,3}a.{0,3}y.{0,3}p.{0,3}a.{0,3}l|ma?c.?fee|n[o0]rt[o0]n|geek.{0,5}squad|ebay|symantec|best buy|lifel[o0]c|secure anywhere|starz|utilities premium|pc security|at&t)
field:"strings.replace_confusables(body.current_thread.text)" kind:regex_match value:"(p.{0,3}a.{0,3}y.{0,3}p.{0,3}a.{0,3}l|ma?c.?fee|n[o0]rt[o0]n|geek.{0,5}squad|ebay|symantec|best buy|lifel[o0]c|secure anywhere|starz|utilities premium|pc security|at&t)"
type.inboundeq
  • true transforms: boolean
field:"type.inbound" kind:eq value:"true"

Callback phishing via SignFree e-signature request

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

This rule inspects messages originating from legitimate SignFree infrastructure, with content matching Callback Phishing criteria, in the body, requiring at least one brand name, as well as 3 matching Callback Phishing terms and a phone number.

Threat classification

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

CategoryValues
Attack typesCallback Phishing
Tactics and techniquesExploit, Impersonation: Brand, Out of band pivot, Social engineering

Telemetry coverage

PlatformRecord / event type
SublimeInbound email message

Message attributes

  • body
  • body.current_thread
  • headers
  • headers.auth_summary
  • sender.email
  • type

Rule body

type.inbound
and length(attachments) == 0
and (
  not beta.profile.by_reply_to().solicited
  or (
    beta.profile.by_reply_to().any_messages_malicious_or_spam
    and not beta.profile.by_reply_to().any_messages_benign
  )
)
// Legitimate SignFree sending infratructure
and sender.email.domain.root_domain == 'signfree.io'
and (headers.auth_summary.spf.pass or headers.auth_summary.dmarc.pass)
and (
  // this section is synced with attachment_callback_phish_with_pdf.yml and attachment_callback_phish_with_img.yml
  regex.icontains(strings.replace_confusables(body.current_thread.text),
                  '(p.{0,3}a.{0,3}y.{0,3}p.{0,3}a.{0,3}l|ma?c.?fee|n[o0]rt[o0]n|geek.{0,5}squad|ebay|symantec|best buy|lifel[o0]c|secure anywhere|starz|utilities premium|pc security|at&t)'
  )
  or any(ml.logo_detect(file.message_screenshot()).brands,
         .name in (
           "PayPal",
           "Norton",
           "GeekSquad",
           "Ebay",
           "McAfee",
           "AT&T",
           "Microsoft"
         )
  )
)
and (
  (
    // this seciton is synced with attachment_callback_phish_with_img.yml and attachment_callback_phish_with_pdf.yml
    // however, the 3 of logic and requiring a phone number is specific to this rule in order to reduce FPs
    // caused by messages which mention cancelling or otherwise managing a subscription
    // it is also synced and below for message_screenshot OCR output
    3 of (
      strings.icontains(body.current_thread.text, 'purchase'),
      strings.icontains(body.current_thread.text, 'payment'),
      strings.icontains(body.current_thread.text, 'transaction'),
      strings.icontains(body.current_thread.text, 'subscription'),
      strings.icontains(body.current_thread.text, 'antivirus'),
      strings.icontains(body.current_thread.text, 'order'),
      strings.icontains(body.current_thread.text, 'support'),
      strings.icontains(body.current_thread.text, 'help line'),
      strings.icontains(body.current_thread.text, 'receipt'),
      strings.icontains(body.current_thread.text, 'invoice'),
      strings.icontains(body.current_thread.text, 'call'),
      strings.icontains(body.current_thread.text, 'cancel'),
      strings.icontains(body.current_thread.text, 'renew'),
      strings.icontains(body.current_thread.text, 'refund'),
      regex.icontains(body.current_thread.text, "(?:reach|contact) us at"),
      strings.icontains(body.current_thread.text, "+1"),
      strings.icontains(body.current_thread.text, "amount"),
      strings.icontains(body.current_thread.text, "charged"),
      strings.icontains(body.current_thread.text, "crypto"),
      strings.icontains(body.current_thread.text, "wallet address"),
      regex.icontains(body.current_thread.text, '\$\d{3}\.\d{2}\b'),
    )
    // phone number regex
    and regex.icontains(body.current_thread.text,
                        '\+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4}',
                        '\+?([ilo0-9]{1,2})?\s?\(?\d{3}\)?[\s\.\-⋅]{0,5}[ilo0-9]{3}[\s\.\-⋅]{0,5}[ilo0-9]{4}'
    )
  )
  or (
    // this seciton is synced with attachment_callback_phish_with_img.yml and attachment_callback_phish_with_pdf.yml
    // and above for current_thread.text
    //
    // This rule makes use of a beta feature and is subject to change without notice
    // using the beta feature in custom rules is not suggested until it has been formally released
    //
    3 of (
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'purchase'),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'payment'),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'transaction'),
      strings.icontains(beta.ocr(file.message_screenshot()).text,
                        'subscription'
      ),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'antivirus'),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'order'),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'support'),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'help line'),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'receipt'),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'invoice'),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'call'),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'helpdesk'),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'cancel'),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'renew'),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'refund'),
      regex.icontains(beta.ocr(file.message_screenshot()).text,
                      "(?:reach|contact) us at"
      ),
      strings.icontains(beta.ocr(file.message_screenshot()).text, '+1'),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'amount'),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'charged'),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'crypto'),
      strings.icontains(beta.ocr(file.message_screenshot()).text,
                        'wallet address'
      ),
      regex.icontains(beta.ocr(file.message_screenshot()).text,
                      '\$\d{3}\.\d{2}\b'
      ),
    )
    // phone number regex
    and regex.icontains(beta.ocr(file.message_screenshot()).text,
                        '\+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4}',
                        '\+?([ilo0-9]{1,2})?\s?\(?\d{3}\)?[\s\.\-⋅]{0,5}[ilo0-9]{3}[\s\.\-⋅]{0,5}[ilo0-9]{4}'
    )

    // negate messages with previous threads.  While callback phishing with thread hijacking or with current_thread 
    // padded with whitespace and previous threads in the message has been observed, the intetion of using OCR is for image embedded callbacks
    and not regex.icount(beta.ocr(file.message_screenshot()).text,
                         '(?:from|to|sent|date|cc|subject):'
    ) > 3
    // this notation of previous threads often only occurs once
    and not regex.icontains(beta.ocr(file.message_screenshot()).text,
                            'wrote:[\r\n]'
    )
  )
)

Detection logic

Scope: inbound message.

This rule inspects messages originating from legitimate SignFree infrastructure, with content matching Callback Phishing criteria, in the body, requiring at least one brand name, as well as 3 matching Callback Phishing terms and a phone number.

  1. inbound message
  2. length(attachments) is 0
  3. any of:
    • not:
      • beta.profile.by_reply_to().solicited
    • all of:
      • beta.profile.by_reply_to().any_messages_malicious_or_spam
      • not:
        • beta.profile.by_reply_to().any_messages_benign
  4. sender.email.domain.root_domain is 'signfree.io'
  5. any of:
    • headers.auth_summary.spf.pass
    • headers.auth_summary.dmarc.pass
  6. any of:
    • strings.replace_confusables(body.current_thread.text) matches '(p.{0,3}a.{0,3}y.{0,3}p.{0,3}a.{0,3}l|ma?c.?fee|n[o0]rt[o0]n|geek.{0,5}squad|ebay|symantec|best buy|lifel[o0]c|secure anywhere|starz|utilities premium|pc security|at&t)'
    • any of ml.logo_detect(file.message_screenshot()).brands where:
      • .name in ('PayPal', 'Norton', 'GeekSquad', 'Ebay', 'McAfee', 'AT&T', 'Microsoft')
  7. any of:
    • all of:
      • at least 3 of:
        • body.current_thread.text contains 'purchase'
        • body.current_thread.text contains 'payment'
        • body.current_thread.text contains 'transaction'
        • body.current_thread.text contains 'subscription'
        • body.current_thread.text contains 'antivirus'
        • body.current_thread.text contains 'order'
        • body.current_thread.text contains 'support'
        • body.current_thread.text contains 'help line'
        • body.current_thread.text contains 'receipt'
        • body.current_thread.text contains 'invoice'
        • body.current_thread.text contains 'call'
        • body.current_thread.text contains 'cancel'
        • body.current_thread.text contains 'renew'
        • body.current_thread.text contains 'refund'
        • body.current_thread.text matches '(?:reach|contact) us at'
        • body.current_thread.text contains '+1'
        • body.current_thread.text contains 'amount'
        • body.current_thread.text contains 'charged'
        • body.current_thread.text contains 'crypto'
        • body.current_thread.text contains 'wallet address'
        • body.current_thread.text matches '\\$\\d{3}\\.\\d{2}\\b'
      • body.current_thread.text matches any of 2 patterns
        • \+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4}
        • \+?([ilo0-9]{1,2})?\s?\(?\d{3}\)?[\s\.\-⋅]{0,5}[ilo0-9]{3}[\s\.\-⋅]{0,5}[ilo0-9]{4}
    • all of:
      • at least 3 of:
        • beta.ocr(file.message_screenshot()).text contains 'purchase'
        • beta.ocr(file.message_screenshot()).text contains 'payment'
        • beta.ocr(file.message_screenshot()).text contains 'transaction'
        • beta.ocr(file.message_screenshot()).text contains 'subscription'
        • beta.ocr(file.message_screenshot()).text contains 'antivirus'
        • beta.ocr(file.message_screenshot()).text contains 'order'
        • beta.ocr(file.message_screenshot()).text contains 'support'
        • beta.ocr(file.message_screenshot()).text contains 'help line'
        • beta.ocr(file.message_screenshot()).text contains 'receipt'
        • beta.ocr(file.message_screenshot()).text contains 'invoice'
        • beta.ocr(file.message_screenshot()).text contains 'call'
        • beta.ocr(file.message_screenshot()).text contains 'helpdesk'
        • beta.ocr(file.message_screenshot()).text contains 'cancel'
        • beta.ocr(file.message_screenshot()).text contains 'renew'
        • beta.ocr(file.message_screenshot()).text contains 'refund'
        • beta.ocr(file.message_screenshot()).text matches '(?:reach|contact) us at'
        • beta.ocr(file.message_screenshot()).text contains '+1'
        • beta.ocr(file.message_screenshot()).text contains 'amount'
        • beta.ocr(file.message_screenshot()).text contains 'charged'
        • beta.ocr(file.message_screenshot()).text contains 'crypto'
        • beta.ocr(file.message_screenshot()).text contains 'wallet address'
        • beta.ocr(file.message_screenshot()).text matches '\\$\\d{3}\\.\\d{2}\\b'
      • beta.ocr(file.message_screenshot()).text matches any of 2 patterns
        • \+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4}
        • \+?([ilo0-9]{1,2})?\s?\(?\d{3}\)?[\s\.\-⋅]{0,5}[ilo0-9]{3}[\s\.\-⋅]{0,5}[ilo0-9]{4}
      • not:
        • regex.icount(beta.ocr(file.message_screenshot()).text, '(?:from|to|sent|date|cc|subject):') > 3
      • not:
        • beta.ocr(file.message_screenshot()).text matches 'wrote:[\\r\\n]'

Inspects: body.current_thread.text, headers.auth_summary.dmarc.pass, headers.auth_summary.spf.pass, sender.email.domain.root_domain, type.inbound. Sensors: beta.ocr, beta.profile.by_reply_to, file.message_screenshot, ml.logo_detect, regex.icontains, regex.icount, strings.icontains, strings.replace_confusables.

Indicators matched (33)

FieldMatchValue
sender.email.domain.root_domainequalssignfree.io
regex.icontainsregex(p.{0,3}a.{0,3}y.{0,3}p.{0,3}a.{0,3}l|ma?c.?fee|n[o0]rt[o0]n|geek.{0,5}squad|ebay|symantec|best buy|lifel[o0]c|secure anywhere|starz|utilities premium|pc security|at&t)
ml.logo_detect(file.message_screenshot()).brands[].namememberPayPal
ml.logo_detect(file.message_screenshot()).brands[].namememberNorton
ml.logo_detect(file.message_screenshot()).brands[].namememberGeekSquad
ml.logo_detect(file.message_screenshot()).brands[].namememberEbay
ml.logo_detect(file.message_screenshot()).brands[].namememberMcAfee
ml.logo_detect(file.message_screenshot()).brands[].namememberAT&T
ml.logo_detect(file.message_screenshot()).brands[].namememberMicrosoft
strings.icontainssubstringpurchase
strings.icontainssubstringpayment
strings.icontainssubstringtransaction
21 more
strings.icontainssubstringsubscription
strings.icontainssubstringantivirus
strings.icontainssubstringorder
strings.icontainssubstringsupport
strings.icontainssubstringhelp line
strings.icontainssubstringreceipt
strings.icontainssubstringinvoice
strings.icontainssubstringcall
strings.icontainssubstringcancel
strings.icontainssubstringrenew
strings.icontainssubstringrefund
regex.icontainsregex(?:reach|contact) us at
strings.icontainssubstring+1
strings.icontainssubstringamount
strings.icontainssubstringcharged
strings.icontainssubstringcrypto
strings.icontainssubstringwallet address
regex.icontainsregex\$\d{3}\.\d{2}\b
regex.icontainsregex\+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4}
regex.icontainsregex\+?([ilo0-9]{1,2})?\s?\(?\d{3}\)?[\s\.\-⋅]{0,5}[ilo0-9]{3}[\s\.\-⋅]{0,5}[ilo0-9]{4}
strings.icontainssubstringhelpdesk

Stages and Predicates

Stage 1: mql_rule

and
  or
    and
      or
        beta.ocr(file.message_screenshot()).text contains "+1"
        beta.ocr(file.message_screenshot()).text contains "amount"
        beta.ocr(file.message_screenshot()).text contains "antivirus"
        beta.ocr(file.message_screenshot()).text contains "call"
        beta.ocr(file.message_screenshot()).text contains "cancel"
        beta.ocr(file.message_screenshot()).text contains "charged"
        beta.ocr(file.message_screenshot()).text contains "crypto"
        beta.ocr(file.message_screenshot()).text contains "help line"
        beta.ocr(file.message_screenshot()).text contains "helpdesk"
        beta.ocr(file.message_screenshot()).text contains "invoice"
        beta.ocr(file.message_screenshot()).text contains "order"
        beta.ocr(file.message_screenshot()).text contains "payment"
        beta.ocr(file.message_screenshot()).text contains "purchase"
        beta.ocr(file.message_screenshot()).text contains "receipt"
        beta.ocr(file.message_screenshot()).text contains "refund"
        beta.ocr(file.message_screenshot()).text contains "renew"
        beta.ocr(file.message_screenshot()).text contains "subscription"
        beta.ocr(file.message_screenshot()).text contains "support"
        beta.ocr(file.message_screenshot()).text contains "transaction"
        beta.ocr(file.message_screenshot()).text contains "wallet address"
        beta.ocr(file.message_screenshot()).text regex_match "(?:reach|contact) us at"
        beta.ocr(file.message_screenshot()).text regex_match "\\$\\d{3}\\.\\d{2}\\b"
      or
        beta.ocr(file.message_screenshot()).text regex_match "\\+?([ilo0-9]{1,2})?\\s?\\(?\\d{3}\\)?[\\s\\.\\-⋅]{0,5}[ilo0-9]{3}[\\s\\.\\-⋅]{0,5}[ilo0-9]{4}"
        beta.ocr(file.message_screenshot()).text regex_match "\\+?([ilo0-9]{1}.)?\\(?[ilo0-9]{3}?\\)?.[ilo0-9]{3}.?[ilo0-9]{4}"
      not
        beta.ocr(file.message_screenshot()).text regex_match "wrote:[\\r\\n]"
      not
        regex.icount func_call "regex.icount(beta.ocr(file.message_screenshot()).text, \"(?:from|to|sent|date|cc|subject):\") > 3"
    and
      or
        body.current_thread.text contains "+1"
        body.current_thread.text contains "amount"
        body.current_thread.text contains "antivirus"
        body.current_thread.text contains "call"
        body.current_thread.text contains "cancel"
        body.current_thread.text contains "charged"
        body.current_thread.text contains "crypto"
        body.current_thread.text contains "help line"
        body.current_thread.text contains "invoice"
        body.current_thread.text contains "order"
        body.current_thread.text contains "payment"
        body.current_thread.text contains "purchase"
        body.current_thread.text contains "receipt"
        body.current_thread.text contains "refund"
        body.current_thread.text contains "renew"
        body.current_thread.text contains "subscription"
        body.current_thread.text contains "support"
        body.current_thread.text contains "transaction"
        body.current_thread.text contains "wallet address"
        body.current_thread.text regex_match "(?:reach|contact) us at"
        body.current_thread.text regex_match "\\$\\d{3}\\.\\d{2}\\b"
      or
        body.current_thread.text regex_match "\\+?([ilo0-9]{1,2})?\\s?\\(?\\d{3}\\)?[\\s\\.\\-⋅]{0,5}[ilo0-9]{3}[\\s\\.\\-⋅]{0,5}[ilo0-9]{4}"
        body.current_thread.text regex_match "\\+?([ilo0-9]{1}.)?\\(?[ilo0-9]{3}?\\)?.[ilo0-9]{3}.?[ilo0-9]{4}"
  or
    and
      not
        beta.profile.by_reply_to func_call "beta.profile.by_reply_to().any_messages_benign"
      beta.profile.by_reply_to func_call "beta.profile.by_reply_to().any_messages_malicious_or_spam"
    not
      beta.profile.by_reply_to func_call "beta.profile.by_reply_to().solicited"
  or
    any(ml.logo_detect(file.message_screenshot()).brands)
      ml.logo_detect(file.message_screenshot()).brands.name in ["AT&T", "Ebay", "GeekSquad", "McAfee", "Microsoft", "Norton", "PayPal"]
    strings.replace_confusables(body.current_thread.text) regex_match "(p.{0,3}a.{0,3}y.{0,3}p.{0,3}a.{0,3}l|ma?c.?fee|n[o0]rt[o0]n|geek.{0,5}squad|ebay|symantec|best buy|lifel[o0]c|secure anywhere|starz|utilities premium|pc security|at&t)"
  or
    headers.auth_summary.dmarc.pass eq "true"
    headers.auth_summary.spf.pass eq "true"
  attachments length_compare "0"
  sender.email.domain.root_domain eq "signfree.io"
  type.inbound eq "true"

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
beta.ocr(file.message_screenshot()).textcontains
  • +1
  • amount
  • antivirus
  • call
  • cancel
  • charged
  • crypto
  • help line
  • helpdesk
  • invoice
  • order
  • payment
  • purchase
  • receipt
  • refund
  • renew
  • subscription
  • support
  • transaction
  • wallet address
field:"beta.ocr(file.message_screenshot()).text" kind:contains
beta.ocr(file.message_screenshot()).textregex_match
  • (?:reach|contact) us at
  • $\d{3}.\d{2}\b
  • +?([ilo0-9]{1,2})?\s?(?\d{3})?[\s.\-⋅]{0,5}[ilo0-9]{3}[\s.\-⋅]{0,5}[ilo0-9]{4}
  • +?([ilo0-9]{1}.)?(?[ilo0-9]{3}?)?.[ilo0-9]{3}.?[ilo0-9]{4}
field:"beta.ocr(file.message_screenshot()).text" kind:regex_match
body.current_thread.textcontains
  • +1
  • amount
  • antivirus
  • call
  • cancel
  • charged
  • crypto
  • help line
  • invoice
  • order
  • payment
  • purchase
  • receipt
  • refund
  • renew
  • subscription
  • support
  • transaction
  • wallet address
field:"body.current_thread.text" kind:contains
body.current_thread.textregex_match
  • (?:reach|contact) us at
  • $\d{3}.\d{2}\b
  • +?([ilo0-9]{1,2})?\s?(?\d{3})?[\s.\-⋅]{0,5}[ilo0-9]{3}[\s.\-⋅]{0,5}[ilo0-9]{4}
  • +?([ilo0-9]{1}.)?(?[ilo0-9]{3}?)?.[ilo0-9]{3}.?[ilo0-9]{4}
field:"body.current_thread.text" kind:regex_match
headers.auth_summary.dmarc.passeq
  • true transforms: boolean
field:"headers.auth_summary.dmarc.pass" kind:eq value:"true"
headers.auth_summary.spf.passeq
  • true transforms: boolean
field:"headers.auth_summary.spf.pass" kind:eq value:"true"
sender.email.domain.root_domaineq
  • signfree.io
field:"sender.email.domain.root_domain" kind:eq value:"signfree.io"
strings.replace_confusables(body.current_thread.text)regex_match
  • (p.{0,3}a.{0,3}y.{0,3}p.{0,3}a.{0,3}l|ma?c.?fee|n[o0]rt[o0]n|geek.{0,5}squad|ebay|symantec|best buy|lifel[o0]c|secure anywhere|starz|utilities premium|pc security|at&t)
field:"strings.replace_confusables(body.current_thread.text)" kind:regex_match value:"(p.{0,3}a.{0,3}y.{0,3}p.{0,3}a.{0,3}l|ma?c.?fee|n[o0]rt[o0]n|geek.{0,5}squad|ebay|symantec|best buy|lifel[o0]c|secure anywhere|starz|utilities premium|pc security|at&t)"
type.inboundeq
  • true transforms: boolean
field:"type.inbound" kind:eq value:"true"

Callback phishing via Xodo Sign comment

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

This rule inspects messages originating from legitimate Xodo Sign infrastructure, with content matching Callback Phishing criteria, in the body, requiring at least one brand name, as well as 3 matching Callback Phishing terms and a phone number.

Threat classification

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

CategoryValues
Attack typesCallback Phishing
Tactics and techniquesExploit, Impersonation: Brand, Out of band pivot, Social engineering

Telemetry coverage

PlatformRecord / event type
SublimeInbound email message

Message attributes

  • body
  • body.current_thread
  • headers
  • headers.auth_summary
  • sender.email
  • type

Rule body

type.inbound
and length(attachments) == 0
and (
  not profile.by_sender().solicited
  or (
    profile.by_sender().any_messages_malicious_or_spam
    and not profile.by_sender().any_messages_benign
  )
)
// Legitimate Xodo Sign/Eversign sending infratructure
and sender.email.domain.root_domain == 'eversign.com'
and (headers.auth_summary.spf.pass or headers.auth_summary.dmarc.pass)
and (
  // this section is synced with attachment_callback_phish_with_pdf.yml and attachment_callback_phish_with_img.yml
  regex.icontains(strings.replace_confusables(body.current_thread.text),
                  '(p.{0,3}a.{0,3}y.{0,3}p.{0,3}a.{0,3}l|ma?c.?fee|n[o0]rt[o0]n|geek.{0,5}squad|ebay|symantec|best buy|lifel[o0]c|secure anywhere|starz|utilities premium|pc security|at&t)'
  )
  or any(ml.logo_detect(file.message_screenshot()).brands,
         .name in ("PayPal", "Norton", "GeekSquad", "Ebay", "McAfee", "AT&T")
  )
)
and length(body.current_thread.text) < 1750
and (
  (
    // this seciton is synced with attachment_callback_phish_with_img.yml and attachment_callback_phish_with_pdf.yml
    // however, the 3 of logic and requiring a phone number is specific to this rule in order to reduce FPs
    // caused by messages which mention cancelling or otherwise managing a subscription
    // it is also synced and below for message_screenshot OCR output
    3 of (
      strings.icontains(body.current_thread.text, 'purchase'),
      strings.icontains(body.current_thread.text, 'payment'),
      strings.icontains(body.current_thread.text, 'transaction'),
      strings.icontains(body.current_thread.text, 'subscription'),
      strings.icontains(body.current_thread.text, 'antivirus'),
      strings.icontains(body.current_thread.text, 'order'),
      strings.icontains(body.current_thread.text, 'support'),
      strings.icontains(body.current_thread.text, 'help line'),
      strings.icontains(body.current_thread.text, 'receipt'),
      strings.icontains(body.current_thread.text, 'invoice'),
      strings.icontains(body.current_thread.text, 'call'),
      strings.icontains(body.current_thread.text, 'cancel'),
      strings.icontains(body.current_thread.text, 'renew'),
      strings.icontains(body.current_thread.text, 'refund'),
      regex.icontains(body.current_thread.text, "(?:reach|contact) us at"),
      strings.icontains(body.current_thread.text, "+1"),
      strings.icontains(body.current_thread.text, "amount"),
      strings.icontains(body.current_thread.text, "charged"),
      strings.icontains(body.current_thread.text, "crypto"),
      strings.icontains(body.current_thread.text, "wallet address"),
      regex.icontains(body.current_thread.text, '\$\d{3}\.\d{2}\b'),
    )
    // phone number regex
    and regex.icontains(body.current_thread.text,
                        '\+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4}',
                        '\+?([ilo0-9]{1,2})?\s?\(?\d{3}\)?[\s\.\-⋅]{0,5}[ilo0-9]{3}[\s\.\-⋅]{0,5}[ilo0-9]{4}'
    )
  )
  or (
    // this seciton is synced with attachment_callback_phish_with_img.yml and attachment_callback_phish_with_pdf.yml
    // and above for current_thread.text
    //
    // This rule makes use of a beta feature and is subject to change without notice
    // using the beta feature in custom rules is not suggested until it has been formally released
    //
    3 of (
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'purchase'),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'payment'),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'transaction'),
      strings.icontains(beta.ocr(file.message_screenshot()).text,
                        'subscription'
      ),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'antivirus'),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'order'),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'support'),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'help line'),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'receipt'),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'invoice'),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'call'),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'helpdesk'),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'cancel'),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'renew'),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'refund'),
      regex.icontains(beta.ocr(file.message_screenshot()).text,
                      "(?:reach|contact) us at"
      ),
      strings.icontains(beta.ocr(file.message_screenshot()).text, '+1'),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'amount'),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'charged'),
      strings.icontains(beta.ocr(file.message_screenshot()).text, 'crypto'),
      strings.icontains(beta.ocr(file.message_screenshot()).text,
                        'wallet address'
      ),
      regex.icontains(beta.ocr(file.message_screenshot()).text,
                      '\$\d{3}\.\d{2}\b'
      ),
    )
    // phone number regex
    and regex.icontains(beta.ocr(file.message_screenshot()).text,
                        '\+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4}',
                        '\+?([ilo0-9]{1,2})?\s?\(?\d{3}\)?[\s\.\-⋅]{0,5}[ilo0-9]{3}[\s\.\-⋅]{0,5}[ilo0-9]{4}'
    )

    // negate messages with previous threads.  While callback phishing with thread hijacking or with current_thread 
    // padded with whitespace and previous threads in the message has been observed, the intetion of using OCR is for image embedded callbacks
    and not regex.icount(beta.ocr(file.message_screenshot()).text,
                         '(?:from|to|sent|date|cc|subject):'
    ) > 3
    // this notation of previous threads often only occurs once
    and not regex.icontains(beta.ocr(file.message_screenshot()).text,
                            'wrote:[\r\n]'
    )
  )
)

Detection logic

Scope: inbound message.

This rule inspects messages originating from legitimate Xodo Sign infrastructure, with content matching Callback Phishing criteria, in the body, requiring at least one brand name, as well as 3 matching Callback Phishing terms and a phone number.

  1. inbound message
  2. length(attachments) is 0
  3. any of:
    • not:
      • profile.by_sender().solicited
    • all of:
      • profile.by_sender().any_messages_malicious_or_spam
      • not:
        • profile.by_sender().any_messages_benign
  4. sender.email.domain.root_domain is 'eversign.com'
  5. any of:
    • headers.auth_summary.spf.pass
    • headers.auth_summary.dmarc.pass
  6. any of:
    • strings.replace_confusables(body.current_thread.text) matches '(p.{0,3}a.{0,3}y.{0,3}p.{0,3}a.{0,3}l|ma?c.?fee|n[o0]rt[o0]n|geek.{0,5}squad|ebay|symantec|best buy|lifel[o0]c|secure anywhere|starz|utilities premium|pc security|at&t)'
    • any of ml.logo_detect(file.message_screenshot()).brands where:
      • .name in ('PayPal', 'Norton', 'GeekSquad', 'Ebay', 'McAfee', 'AT&T')
  7. length(body.current_thread.text) < 1750
  8. any of:
    • all of:
      • at least 3 of:
        • body.current_thread.text contains 'purchase'
        • body.current_thread.text contains 'payment'
        • body.current_thread.text contains 'transaction'
        • body.current_thread.text contains 'subscription'
        • body.current_thread.text contains 'antivirus'
        • body.current_thread.text contains 'order'
        • body.current_thread.text contains 'support'
        • body.current_thread.text contains 'help line'
        • body.current_thread.text contains 'receipt'
        • body.current_thread.text contains 'invoice'
        • body.current_thread.text contains 'call'
        • body.current_thread.text contains 'cancel'
        • body.current_thread.text contains 'renew'
        • body.current_thread.text contains 'refund'
        • body.current_thread.text matches '(?:reach|contact) us at'
        • body.current_thread.text contains '+1'
        • body.current_thread.text contains 'amount'
        • body.current_thread.text contains 'charged'
        • body.current_thread.text contains 'crypto'
        • body.current_thread.text contains 'wallet address'
        • body.current_thread.text matches '\\$\\d{3}\\.\\d{2}\\b'
      • body.current_thread.text matches any of 2 patterns
        • \+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4}
        • \+?([ilo0-9]{1,2})?\s?\(?\d{3}\)?[\s\.\-⋅]{0,5}[ilo0-9]{3}[\s\.\-⋅]{0,5}[ilo0-9]{4}
    • all of:
      • at least 3 of:
        • beta.ocr(file.message_screenshot()).text contains 'purchase'
        • beta.ocr(file.message_screenshot()).text contains 'payment'
        • beta.ocr(file.message_screenshot()).text contains 'transaction'
        • beta.ocr(file.message_screenshot()).text contains 'subscription'
        • beta.ocr(file.message_screenshot()).text contains 'antivirus'
        • beta.ocr(file.message_screenshot()).text contains 'order'
        • beta.ocr(file.message_screenshot()).text contains 'support'
        • beta.ocr(file.message_screenshot()).text contains 'help line'
        • beta.ocr(file.message_screenshot()).text contains 'receipt'
        • beta.ocr(file.message_screenshot()).text contains 'invoice'
        • beta.ocr(file.message_screenshot()).text contains 'call'
        • beta.ocr(file.message_screenshot()).text contains 'helpdesk'
        • beta.ocr(file.message_screenshot()).text contains 'cancel'
        • beta.ocr(file.message_screenshot()).text contains 'renew'
        • beta.ocr(file.message_screenshot()).text contains 'refund'
        • beta.ocr(file.message_screenshot()).text matches '(?:reach|contact) us at'
        • beta.ocr(file.message_screenshot()).text contains '+1'
        • beta.ocr(file.message_screenshot()).text contains 'amount'
        • beta.ocr(file.message_screenshot()).text contains 'charged'
        • beta.ocr(file.message_screenshot()).text contains 'crypto'
        • beta.ocr(file.message_screenshot()).text contains 'wallet address'
        • beta.ocr(file.message_screenshot()).text matches '\\$\\d{3}\\.\\d{2}\\b'
      • beta.ocr(file.message_screenshot()).text matches any of 2 patterns
        • \+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4}
        • \+?([ilo0-9]{1,2})?\s?\(?\d{3}\)?[\s\.\-⋅]{0,5}[ilo0-9]{3}[\s\.\-⋅]{0,5}[ilo0-9]{4}
      • not:
        • regex.icount(beta.ocr(file.message_screenshot()).text, '(?:from|to|sent|date|cc|subject):') > 3
      • not:
        • beta.ocr(file.message_screenshot()).text matches 'wrote:[\\r\\n]'

Inspects: body.current_thread.text, headers.auth_summary.dmarc.pass, headers.auth_summary.spf.pass, sender.email.domain.root_domain, type.inbound. Sensors: beta.ocr, file.message_screenshot, ml.logo_detect, profile.by_sender, regex.icontains, regex.icount, strings.icontains, strings.replace_confusables.

Indicators matched (32)

FieldMatchValue
sender.email.domain.root_domainequalseversign.com
regex.icontainsregex(p.{0,3}a.{0,3}y.{0,3}p.{0,3}a.{0,3}l|ma?c.?fee|n[o0]rt[o0]n|geek.{0,5}squad|ebay|symantec|best buy|lifel[o0]c|secure anywhere|starz|utilities premium|pc security|at&t)
ml.logo_detect(file.message_screenshot()).brands[].namememberPayPal
ml.logo_detect(file.message_screenshot()).brands[].namememberNorton
ml.logo_detect(file.message_screenshot()).brands[].namememberGeekSquad
ml.logo_detect(file.message_screenshot()).brands[].namememberEbay
ml.logo_detect(file.message_screenshot()).brands[].namememberMcAfee
ml.logo_detect(file.message_screenshot()).brands[].namememberAT&T
strings.icontainssubstringpurchase
strings.icontainssubstringpayment
strings.icontainssubstringtransaction
strings.icontainssubstringsubscription
20 more
strings.icontainssubstringantivirus
strings.icontainssubstringorder
strings.icontainssubstringsupport
strings.icontainssubstringhelp line
strings.icontainssubstringreceipt
strings.icontainssubstringinvoice
strings.icontainssubstringcall
strings.icontainssubstringcancel
strings.icontainssubstringrenew
strings.icontainssubstringrefund
regex.icontainsregex(?:reach|contact) us at
strings.icontainssubstring+1
strings.icontainssubstringamount
strings.icontainssubstringcharged
strings.icontainssubstringcrypto
strings.icontainssubstringwallet address
regex.icontainsregex\$\d{3}\.\d{2}\b
regex.icontainsregex\+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4}
regex.icontainsregex\+?([ilo0-9]{1,2})?\s?\(?\d{3}\)?[\s\.\-⋅]{0,5}[ilo0-9]{3}[\s\.\-⋅]{0,5}[ilo0-9]{4}
strings.icontainssubstringhelpdesk

Stages and Predicates

Stage 1: mql_rule

and
  or
    and
      or
        beta.ocr(file.message_screenshot()).text contains "+1"
        beta.ocr(file.message_screenshot()).text contains "amount"
        beta.ocr(file.message_screenshot()).text contains "antivirus"
        beta.ocr(file.message_screenshot()).text contains "call"
        beta.ocr(file.message_screenshot()).text contains "cancel"
        beta.ocr(file.message_screenshot()).text contains "charged"
        beta.ocr(file.message_screenshot()).text contains "crypto"
        beta.ocr(file.message_screenshot()).text contains "help line"
        beta.ocr(file.message_screenshot()).text contains "helpdesk"
        beta.ocr(file.message_screenshot()).text contains "invoice"
        beta.ocr(file.message_screenshot()).text contains "order"
        beta.ocr(file.message_screenshot()).text contains "payment"
        beta.ocr(file.message_screenshot()).text contains "purchase"
        beta.ocr(file.message_screenshot()).text contains "receipt"
        beta.ocr(file.message_screenshot()).text contains "refund"
        beta.ocr(file.message_screenshot()).text contains "renew"
        beta.ocr(file.message_screenshot()).text contains "subscription"
        beta.ocr(file.message_screenshot()).text contains "support"
        beta.ocr(file.message_screenshot()).text contains "transaction"
        beta.ocr(file.message_screenshot()).text contains "wallet address"
        beta.ocr(file.message_screenshot()).text regex_match "(?:reach|contact) us at"
        beta.ocr(file.message_screenshot()).text regex_match "\\$\\d{3}\\.\\d{2}\\b"
      or
        beta.ocr(file.message_screenshot()).text regex_match "\\+?([ilo0-9]{1,2})?\\s?\\(?\\d{3}\\)?[\\s\\.\\-⋅]{0,5}[ilo0-9]{3}[\\s\\.\\-⋅]{0,5}[ilo0-9]{4}"
        beta.ocr(file.message_screenshot()).text regex_match "\\+?([ilo0-9]{1}.)?\\(?[ilo0-9]{3}?\\)?.[ilo0-9]{3}.?[ilo0-9]{4}"
      not
        beta.ocr(file.message_screenshot()).text regex_match "wrote:[\\r\\n]"
      not
        regex.icount func_call "regex.icount(beta.ocr(file.message_screenshot()).text, \"(?:from|to|sent|date|cc|subject):\") > 3"
    and
      or
        body.current_thread.text contains "+1"
        body.current_thread.text contains "amount"
        body.current_thread.text contains "antivirus"
        body.current_thread.text contains "call"
        body.current_thread.text contains "cancel"
        body.current_thread.text contains "charged"
        body.current_thread.text contains "crypto"
        body.current_thread.text contains "help line"
        body.current_thread.text contains "invoice"
        body.current_thread.text contains "order"
        body.current_thread.text contains "payment"
        body.current_thread.text contains "purchase"
        body.current_thread.text contains "receipt"
        body.current_thread.text contains "refund"
        body.current_thread.text contains "renew"
        body.current_thread.text contains "subscription"
        body.current_thread.text contains "support"
        body.current_thread.text contains "transaction"
        body.current_thread.text contains "wallet address"
        body.current_thread.text regex_match "(?:reach|contact) us at"
        body.current_thread.text regex_match "\\$\\d{3}\\.\\d{2}\\b"
      or
        body.current_thread.text regex_match "\\+?([ilo0-9]{1,2})?\\s?\\(?\\d{3}\\)?[\\s\\.\\-⋅]{0,5}[ilo0-9]{3}[\\s\\.\\-⋅]{0,5}[ilo0-9]{4}"
        body.current_thread.text regex_match "\\+?([ilo0-9]{1}.)?\\(?[ilo0-9]{3}?\\)?.[ilo0-9]{3}.?[ilo0-9]{4}"
  or
    and
      not
        profile.by_sender func_call "profile.by_sender().any_messages_benign"
      profile.by_sender func_call "profile.by_sender().any_messages_malicious_or_spam"
    not
      profile.by_sender func_call "profile.by_sender().solicited"
  or
    any(ml.logo_detect(file.message_screenshot()).brands)
      ml.logo_detect(file.message_screenshot()).brands.name in ["AT&T", "Ebay", "GeekSquad", "McAfee", "Norton", "PayPal"]
    strings.replace_confusables(body.current_thread.text) regex_match "(p.{0,3}a.{0,3}y.{0,3}p.{0,3}a.{0,3}l|ma?c.?fee|n[o0]rt[o0]n|geek.{0,5}squad|ebay|symantec|best buy|lifel[o0]c|secure anywhere|starz|utilities premium|pc security|at&t)"
  or
    headers.auth_summary.dmarc.pass eq "true"
    headers.auth_summary.spf.pass eq "true"
  attachments length_compare "0"
  body.current_thread.text length_compare "1750"
  sender.email.domain.root_domain eq "eversign.com"
  type.inbound eq "true"

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
beta.ocr(file.message_screenshot()).textcontains
  • +1
  • amount
  • antivirus
  • call
  • cancel
  • charged
  • crypto
  • help line
  • helpdesk
  • invoice
  • order
  • payment
  • purchase
  • receipt
  • refund
  • renew
  • subscription
  • support
  • transaction
  • wallet address
field:"beta.ocr(file.message_screenshot()).text" kind:contains
beta.ocr(file.message_screenshot()).textregex_match
  • (?:reach|contact) us at
  • $\d{3}.\d{2}\b
  • +?([ilo0-9]{1,2})?\s?(?\d{3})?[\s.\-⋅]{0,5}[ilo0-9]{3}[\s.\-⋅]{0,5}[ilo0-9]{4}
  • +?([ilo0-9]{1}.)?(?[ilo0-9]{3}?)?.[ilo0-9]{3}.?[ilo0-9]{4}
field:"beta.ocr(file.message_screenshot()).text" kind:regex_match
body.current_thread.textcontains
  • +1
  • amount
  • antivirus
  • call
  • cancel
  • charged
  • crypto
  • help line
  • invoice
  • order
  • payment
  • purchase
  • receipt
  • refund
  • renew
  • subscription
  • support
  • transaction
  • wallet address
field:"body.current_thread.text" kind:contains
body.current_thread.textregex_match
  • (?:reach|contact) us at
  • $\d{3}.\d{2}\b
  • +?([ilo0-9]{1,2})?\s?(?\d{3})?[\s.\-⋅]{0,5}[ilo0-9]{3}[\s.\-⋅]{0,5}[ilo0-9]{4}
  • +?([ilo0-9]{1}.)?(?[ilo0-9]{3}?)?.[ilo0-9]{3}.?[ilo0-9]{4}
field:"body.current_thread.text" kind:regex_match
headers.auth_summary.dmarc.passeq
  • true transforms: boolean
field:"headers.auth_summary.dmarc.pass" kind:eq value:"true"
headers.auth_summary.spf.passeq
  • true transforms: boolean
field:"headers.auth_summary.spf.pass" kind:eq value:"true"
sender.email.domain.root_domaineq
  • eversign.com
field:"sender.email.domain.root_domain" kind:eq value:"eversign.com"
strings.replace_confusables(body.current_thread.text)regex_match
  • (p.{0,3}a.{0,3}y.{0,3}p.{0,3}a.{0,3}l|ma?c.?fee|n[o0]rt[o0]n|geek.{0,5}squad|ebay|symantec|best buy|lifel[o0]c|secure anywhere|starz|utilities premium|pc security|at&t)
field:"strings.replace_confusables(body.current_thread.text)" kind:regex_match value:"(p.{0,3}a.{0,3}y.{0,3}p.{0,3}a.{0,3}l|ma?c.?fee|n[o0]rt[o0]n|geek.{0,5}squad|ebay|symantec|best buy|lifel[o0]c|secure anywhere|starz|utilities premium|pc security|at&t)"
type.inboundeq
  • true transforms: boolean
field:"type.inbound" kind:eq value:"true"

Callback phishing via Yammer comment

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

Detects callback scams sent through Yammer infrastructure containing suspicious payment-related keywords and phone numbers. The rule identifies messages with callback scam language patterns or multiple financial transaction terms combined with phone number patterns in the message body or subject line.

Threat classification

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

CategoryValues
Attack typesCallback Phishing
Tactics and techniquesImpersonation: Brand, Out of band pivot, Social engineering

Telemetry coverage

PlatformRecord / event type
SublimeInbound email message

Message attributes

  • body
  • body.current_thread
  • sender.email
  • subject
  • type

Rule body

type.inbound
// message from Yammer sending infratructure
and sender.email.domain.root_domain == 'yammer.com'
and length(body.current_thread.text) < 2000

// Callback Phishing
and (
  any(ml.nlu_classifier(body.current_thread.text).intents,
      .name in ("callback_scam") and .confidence in ("medium", "high")
  )
  or 3 of (
    strings.ilike(body.current_thread.text, '*purchase*'),
    strings.ilike(body.current_thread.text, '*payment*'),
    strings.ilike(body.current_thread.text, '*transaction*'),
    strings.ilike(body.current_thread.text, '*subscription*'),
    strings.ilike(body.current_thread.text, '*antivirus*'),
    strings.ilike(body.current_thread.text, '*order*'),
    strings.ilike(body.current_thread.text, '*support*'),
    strings.ilike(body.current_thread.text, '*help line*'),
    strings.ilike(body.current_thread.text, '*receipt*'),
    strings.ilike(body.current_thread.text, '*invoice*'),
    strings.ilike(body.current_thread.text, '*call*'),
    strings.ilike(body.current_thread.text, '*cancel*'),
    strings.ilike(body.current_thread.text, '*renew*'),
    strings.ilike(body.current_thread.text, '*refund*')
  )
)
// phone number regex
and any([body.current_thread.text, subject.subject],
        regex.icontains(.,
                        '\+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4}',
                        '\+?([ilo0-9]{1,2})?\s?\(?\d{3}\)?[\s\.\-⋅]{0,5}[ilo0-9]{3}[\s\.\-⋅]{0,5}[ilo0-9]{4}'
        )
)
// negate benign threads
and not any(ml.nlu_classifier(body.current_thread.text).intents,
            .name == "benign" and .confidence == "high"
)

Detection logic

Scope: inbound message.

Detects callback scams sent through Yammer infrastructure containing suspicious payment-related keywords and phone numbers. The rule identifies messages with callback scam language patterns or multiple financial transaction terms combined with phone number patterns in the message body or subject line.

  1. inbound message
  2. sender.email.domain.root_domain is 'yammer.com'
  3. length(body.current_thread.text) < 2000
  4. any of:
    • any of ml.nlu_classifier(body.current_thread.text).intents where all hold:
      • .name in ('callback_scam')
      • .confidence in ('medium', 'high')
    • at least 3 of 14: body.current_thread.text matches any of 14 patterns
      • *purchase*
      • *payment*
      • *transaction*
      • *subscription*
      • *antivirus*
      • *order*
      • *support*
      • *help line*
      • *receipt*
      • *invoice*
      • *call*
      • *cancel*
      • *renew*
      • *refund*
  5. any of [body.current_thread.text, subject.subject] where:
    • . matches any of 2 patterns
      • \+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4}
      • \+?([ilo0-9]{1,2})?\s?\(?\d{3}\)?[\s\.\-⋅]{0,5}[ilo0-9]{3}[\s\.\-⋅]{0,5}[ilo0-9]{4}
  6. not:
    • any of ml.nlu_classifier(body.current_thread.text).intents where all hold:
      • .name is 'benign'
      • .confidence is 'high'

Inspects: body.current_thread.text, sender.email.domain.root_domain, subject.subject, type.inbound. Sensors: ml.nlu_classifier, regex.icontains, strings.ilike.

Indicators matched (20)

FieldMatchValue
sender.email.domain.root_domainequalsyammer.com
ml.nlu_classifier(body.current_thread.text).intents[].namemembercallback_scam
ml.nlu_classifier(body.current_thread.text).intents[].confidencemembermedium
ml.nlu_classifier(body.current_thread.text).intents[].confidencememberhigh
strings.ilikesubstring*purchase*
strings.ilikesubstring*payment*
strings.ilikesubstring*transaction*
strings.ilikesubstring*subscription*
strings.ilikesubstring*antivirus*
strings.ilikesubstring*order*
strings.ilikesubstring*support*
strings.ilikesubstring*help line*
8 more
strings.ilikesubstring*receipt*
strings.ilikesubstring*invoice*
strings.ilikesubstring*call*
strings.ilikesubstring*cancel*
strings.ilikesubstring*renew*
strings.ilikesubstring*refund*
regex.icontainsregex\+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4}
regex.icontainsregex\+?([ilo0-9]{1,2})?\s?\(?\d{3}\)?[\s\.\-⋅]{0,5}[ilo0-9]{3}[\s\.\-⋅]{0,5}[ilo0-9]{4}

Stages and Predicates

Stage 1: mql_rule

and
  not
    any(ml.nlu_classifier(body.current_thread.text).intents)
      and
        ml.nlu_classifier(body.current_thread.text).intents.confidence eq "high"
        ml.nlu_classifier(body.current_thread.text).intents.name eq "benign"
  or
    any(ml.nlu_classifier(body.current_thread.text).intents)
      and
        ml.nlu_classifier(body.current_thread.text).intents.confidence in ["high", "medium"]
        ml.nlu_classifier(body.current_thread.text).intents.name eq "callback_scam"
    body.current_thread.text match "antivirus"
    body.current_thread.text match "call"
    body.current_thread.text match "cancel"
    body.current_thread.text match "help line"
    body.current_thread.text match "invoice"
    body.current_thread.text match "order"
    body.current_thread.text match "payment"
    body.current_thread.text match "purchase"
    body.current_thread.text match "receipt"
    body.current_thread.text match "refund"
    body.current_thread.text match "renew"
    body.current_thread.text match "subscription"
    body.current_thread.text match "support"
    body.current_thread.text match "transaction"
  any([body.current_thread.text, subject.subject])
    or
      [body.current_thread.text, subject.subject] regex_match "\\+?([ilo0-9]{1,2})?\\s?\\(?\\d{3}\\)?[\\s\\.\\-⋅]{0,5}[ilo0-9]{3}[\\s\\.\\-⋅]{0,5}[ilo0-9]{4}"
      [body.current_thread.text, subject.subject] regex_match "\\+?([ilo0-9]{1}.)?\\(?[ilo0-9]{3}?\\)?.[ilo0-9]{3}.?[ilo0-9]{4}"
  body.current_thread.text length_compare "2000"
  sender.email.domain.root_domain eq "yammer.com"
  type.inbound eq "true"

Exclusions

The rule actively suppresses these predicates.

FieldKindExcluded valuesSearch
ml.nlu_classifier(body.current_thread.text).intentsarray_any(no value, null check)excludes:ml.nlu_classifier(body.current_thread.text).intents

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
body.current_thread.textwildcard
  • *antivirus*
  • *call*
  • *cancel*
  • *help line*
  • *invoice*
  • *order*
  • *payment*
  • *purchase*
  • *receipt*
  • *refund*
  • *renew*
  • *subscription*
  • *support*
  • *transaction*
field:"body.current_thread.text" kind:wildcard
sender.email.domain.root_domaineq
  • yammer.com
field:"sender.email.domain.root_domain" kind:eq value:"yammer.com"
type.inboundeq
  • true transforms: boolean
field:"type.inbound" kind:eq value:"true"

Callback phishing via Zelle Service Abuse

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

Callback phishing campaigns have been observed abusing Zelle services to send fraudulent payment requests with callback phishing contents.

Threat classification

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

CategoryValues
Attack typesBEC/Fraud, Callback Phishing
Tactics and techniquesEvasion, Social engineering

Telemetry coverage

PlatformRecord / event type
SublimeInbound email message

Message attributes

  • body
  • body.current_thread
  • body.html
  • sender.email
  • subject
  • type

Rule body

type.inbound
and length(attachments) == 0
and sender.email.domain.root_domain in ("zellepay.com")
and (
  // only seeing payment requests abused
  strings.ilike(body.html.display_text, "* requested*")
  // phone number in subject
  // the subject contains the seller's "name", attacks have been seen with the entire callback text in the seller's name
  or (
    regex.icontains(strings.replace_confusables(subject.subject),
                    '.*\+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4}.*'
    )
    or regex.icontains(strings.replace_confusables(subject.subject),
                       '.*\+[ilo0-9]{1,3}[ilo0-9]{10}.*'
    )
    // +12028001238
    or regex.icontains(strings.replace_confusables(subject.subject),
                       '.*[ilo0-9]{3}\.[ilo0-9]{3}\.[ilo0-9]{4}.*'
    )
    // 202-800-1238
    or regex.icontains(strings.replace_confusables(subject.subject),
                       '.*[ilo0-9]{3}-[ilo0-9]{3}-[ilo0-9]{4}.*'
    )
    // (202) 800-1238
    or regex.icontains(strings.replace_confusables(subject.subject),
                       '.*\([ilo0-9]{3}\)[\s-]+[ilo0-9]{3}[\s-]+[ilo0-9]{4}.*'
    )
    // (202)-800-1238
    or regex.icontains(strings.replace_confusables(subject.subject),
                       '.*\([ilo0-9]{3}\)-[ilo0-9]{3}-[ilo0-9]{4}.*'
    )
    or ( // 8123456789
      regex.icontains(strings.replace_confusables(subject.subject),
                      '.*8[ilo0-9]{9}.*'
      )
      and regex.icontains(strings.replace_confusables(subject.subject),
                          '\+[1li]'
      )
    )
  )
)
and (
  (
    // icontains a phone number within the memo section (wrapped in quotes)
    (
      regex.icontains(strings.replace_confusables(body.current_thread.text),
                      '\".*\+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4}.*\"'
      )
      or regex.icontains(strings.replace_confusables(body.current_thread.text),
                         '\".*\+[ilo0-9]{1,3}[ilo0-9]{10}.*\"'
      )
      // +12028001238
      or regex.icontains(strings.replace_confusables(body.current_thread.text),
                         '\".*[ilo0-9]{3}\.[ilo0-9]{3}\.[ilo0-9]{4}.*\"'
      )
      // 202-800-1238
      or regex.icontains(strings.replace_confusables(body.current_thread.text),
                         '\".*[ilo0-9]{3}-[ilo0-9]{3}-[ilo0-9]{4}.*\"'
      )
      // (202) 800-1238
      or regex.icontains(strings.replace_confusables(body.current_thread.text),
                         '\".*\([ilo0-9]{3}\)\s[ilo0-9]{3}-[ilo0-9]{4}.*\"'
      )
      // (202)-800-1238
      or regex.icontains(strings.replace_confusables(body.current_thread.text),
                         '\".*\([ilo0-9]{3}\)-[ilo0-9]{3}-[ilo0-9]{4}.*\"'
      )
      or ( // 8123456789
        regex.icontains(strings.replace_confusables(body.current_thread.text),
                        '\".*8[ilo0-9]{9}.*\"'
        )
        and regex.icontains(strings.replace_confusables(body.current_thread.text
                            ),
                            '\".*\+[1li].*\"'
        )
      )
    )
    and (
      (
        4 of (
          strings.ilike(body.html.inner_text, '*"*you did not*"*'),
          strings.ilike(body.html.inner_text, '*"*is not for*"*'),
          strings.ilike(body.html.inner_text, '*"*done by you*"*'),
          regex.icontains(body.html.inner_text, "\".*didn\'t ma[kd]e this.*\""),
          strings.ilike(body.html.inner_text, '*"*Fruad Alert*"*'),
          strings.ilike(body.html.inner_text, '*"*Fraud Alert*"*'),
          strings.ilike(body.html.inner_text, '*"*fraudulent*"*'),
          strings.ilike(body.html.inner_text, '*"*Zelle*"*'),
          strings.ilike(body.html.inner_text, '*"*subscription*"*'),
          strings.ilike(body.html.inner_text, '*"*antivirus*"*'),
          strings.ilike(body.html.inner_text, '*"*order*"*'),
          strings.ilike(body.html.inner_text, '*"*support*"*'),
          strings.ilike(body.html.inner_text, '*"*sincerely apologize*"*'),
          strings.ilike(body.html.inner_text, '*"*receipt*"*'),
          strings.ilike(body.html.inner_text, '*"*invoice*"*'),
          strings.ilike(body.html.inner_text, '*"*Purchase*"*'),
          strings.ilike(body.html.inner_text, '*"*transaction*"*'),
          strings.ilike(body.html.inner_text, '*"*Market*Value*"*'),
          strings.ilike(body.html.inner_text, '*"*BTC*"*'),
          strings.ilike(body.html.inner_text, '*"*call*"*'),
          strings.ilike(body.html.inner_text, '*"*get in touch with our*"*'),
          strings.ilike(body.html.inner_text, '*"*quickly inform*"*'),
          strings.ilike(body.html.inner_text, '*"*quickly reach*"*'),
          strings.ilike(body.html.inner_text,
                        '*"*detected unusual transactions*'
          ),
          strings.ilike(body.html.inner_text,
                        '*"*without your authorization*"*'
          ),
          strings.ilike(body.html.inner_text, '*"*cancel*"*'),
          strings.ilike(body.html.inner_text, '*"*renew*"*'),
          strings.ilike(body.html.inner_text, '*"*refund*"*'),
          strings.ilike(body.html.inner_text, '*"*+1*"*'),
          regex.icontains(body.html.inner_text, '\"help.{0,3}desk'),
          strings.ilike(body.html.inner_text, '*"* your funds*"*'),
          strings.ilike(body.html.inner_text, '*"* your checking*"*'),
          strings.ilike(body.html.inner_text, '*"* your saving*"*'),
          strings.ilike(body.html.inner_text, '*"*transfer*"*'),
          strings.ilike(body.html.inner_text, '*"*secure your account*"*'),
          strings.ilike(body.html.inner_text, '*"*recover your *"*'),
        )
      )
      or regex.icontains(body.current_thread.text,
                         'note from.{0,50}(?:call|reach|contact|paypal)'
      )
      or any(ml.nlu_classifier(body.current_thread.text).intents,
             .name == "callback_scam"
      )
      or (
        // Unicode confusables words obfuscated in note
        regex.icontains(body.html.inner_text,
                        '\+𝟭|𝗽𝗮𝘆𝗺𝗲𝗻𝘁|𝗛𝗲𝗹𝗽 𝗗𝗲𝘀𝗸|𝗿𝗲𝗳𝘂𝗻𝗱|𝗮𝗻𝘁𝗶𝘃𝗶𝗿𝘂𝘀|𝗰𝗮𝗹𝗹|𝗰𝗮𝗻𝗰𝗲𝗹'
        )
      )
      or strings.ilike(body.html.inner_text, '*"*kindly*"*')
    )
  )
)

Detection logic

Scope: inbound message.

Callback phishing campaigns have been observed abusing Zelle services to send fraudulent payment requests with callback phishing contents.

  1. inbound message
  2. length(attachments) is 0
  3. sender.email.domain.root_domain in ('zellepay.com')
  4. any of:
    • body.html.display_text matches '* requested*'
    • any of:
      • strings.replace_confusables(subject.subject) matches '.*\\+?([ilo0-9]{1}.)?\\(?[ilo0-9]{3}?\\)?.[ilo0-9]{3}.?[ilo0-9]{4}.*'
      • strings.replace_confusables(subject.subject) matches '.*\\+[ilo0-9]{1,3}[ilo0-9]{10}.*'
      • strings.replace_confusables(subject.subject) matches '.*[ilo0-9]{3}\\.[ilo0-9]{3}\\.[ilo0-9]{4}.*'
      • strings.replace_confusables(subject.subject) matches '.*[ilo0-9]{3}-[ilo0-9]{3}-[ilo0-9]{4}.*'
      • strings.replace_confusables(subject.subject) matches '.*\\([ilo0-9]{3}\\)[\\s-]+[ilo0-9]{3}[\\s-]+[ilo0-9]{4}.*'
      • strings.replace_confusables(subject.subject) matches '.*\\([ilo0-9]{3}\\)-[ilo0-9]{3}-[ilo0-9]{4}.*'
      • all of:
        • strings.replace_confusables(subject.subject) matches '.*8[ilo0-9]{9}.*'
        • strings.replace_confusables(subject.subject) matches '\\+[1li]'
  5. all of:
    • any of:
      • strings.replace_confusables(body.current_thread.text) matches '\\".*\\+?([ilo0-9]{1}.)?\\(?[ilo0-9]{3}?\\)?.[ilo0-9]{3}.?[ilo0-9]{4}.*\\"'
      • strings.replace_confusables(body.current_thread.text) matches '\\".*\\+[ilo0-9]{1,3}[ilo0-9]{10}.*\\"'
      • strings.replace_confusables(body.current_thread.text) matches '\\".*[ilo0-9]{3}\\.[ilo0-9]{3}\\.[ilo0-9]{4}.*\\"'
      • strings.replace_confusables(body.current_thread.text) matches '\\".*[ilo0-9]{3}-[ilo0-9]{3}-[ilo0-9]{4}.*\\"'
      • strings.replace_confusables(body.current_thread.text) matches '\\".*\\([ilo0-9]{3}\\)\\s[ilo0-9]{3}-[ilo0-9]{4}.*\\"'
      • strings.replace_confusables(body.current_thread.text) matches '\\".*\\([ilo0-9]{3}\\)-[ilo0-9]{3}-[ilo0-9]{4}.*\\"'
      • all of:
        • strings.replace_confusables(body.current_thread.text) matches '\\".*8[ilo0-9]{9}.*\\"'
        • strings.replace_confusables(body.current_thread.text) matches '\\".*\\+[1li].*\\"'
    • any of:
      • at least 4 of 36: body.html.inner_text matches any of 36 patterns
        • *"*you did not*"*
        • *"*is not for*"*
        • *"*done by you*"*
        • \".*didn\'t ma[kd]e this.*\"
        • *"*Fruad Alert*"*
        • *"*Fraud Alert*"*
        • *"*fraudulent*"*
        • *"*Zelle*"*
        • *"*subscription*"*
        • *"*antivirus*"*
        • *"*order*"*
        • *"*support*"*
        • *"*sincerely apologize*"*
        • *"*receipt*"*
        • *"*invoice*"*
        • *"*Purchase*"*
        • *"*transaction*"*
        • *"*Market*Value*"*
        • *"*BTC*"*
        • *"*call*"*
        • *"*get in touch with our*"*
        • *"*quickly inform*"*
        • *"*quickly reach*"*
        • *"*detected unusual transactions*
        • *"*without your authorization*"*
        • *"*cancel*"*
        • *"*renew*"*
        • *"*refund*"*
        • *"*+1*"*
        • \"help.{0,3}desk
        • *"* your funds*"*
        • *"* your checking*"*
        • *"* your saving*"*
        • *"*transfer*"*
        • *"*secure your account*"*
        • *"*recover your *"*
      • body.current_thread.text matches 'note from.{0,50}(?:call|reach|contact|paypal)'
      • any of ml.nlu_classifier(body.current_thread.text).intents where:
        • .name is 'callback_scam'
      • body.html.inner_text matches '\\+𝟭|𝗽𝗮𝘆𝗺𝗲𝗻𝘁|𝗛𝗲𝗹𝗽 𝗗𝗲𝘀𝗸|𝗿𝗲𝗳𝘂𝗻𝗱|𝗮𝗻𝘁𝗶𝘃𝗶𝗿𝘂𝘀|𝗰𝗮𝗹𝗹|𝗰𝗮𝗻𝗰𝗲𝗹'
      • body.html.inner_text matches '*"*kindly*"*'

Inspects: body.current_thread.text, body.html.display_text, body.html.inner_text, sender.email.domain.root_domain, subject.subject, type.inbound. Sensors: ml.nlu_classifier, regex.icontains, strings.ilike, strings.replace_confusables.

Indicators matched (58)

FieldMatchValue
sender.email.domain.root_domainmemberzellepay.com
strings.ilikesubstring* requested*
regex.icontainsregex.*\+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4}.*
regex.icontainsregex.*\+[ilo0-9]{1,3}[ilo0-9]{10}.*
regex.icontainsregex.*[ilo0-9]{3}\.[ilo0-9]{3}\.[ilo0-9]{4}.*
regex.icontainsregex.*[ilo0-9]{3}-[ilo0-9]{3}-[ilo0-9]{4}.*
regex.icontainsregex.*\([ilo0-9]{3}\)[\s-]+[ilo0-9]{3}[\s-]+[ilo0-9]{4}.*
regex.icontainsregex.*\([ilo0-9]{3}\)-[ilo0-9]{3}-[ilo0-9]{4}.*
regex.icontainsregex.*8[ilo0-9]{9}.*
regex.icontainsregex\+[1li]
regex.icontainsregex\".*\+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4}.*\"
regex.icontainsregex\".*\+[ilo0-9]{1,3}[ilo0-9]{10}.*\"
46 more
regex.icontainsregex\".*[ilo0-9]{3}\.[ilo0-9]{3}\.[ilo0-9]{4}.*\"
regex.icontainsregex\".*[ilo0-9]{3}-[ilo0-9]{3}-[ilo0-9]{4}.*\"
regex.icontainsregex\".*\([ilo0-9]{3}\)\s[ilo0-9]{3}-[ilo0-9]{4}.*\"
regex.icontainsregex\".*\([ilo0-9]{3}\)-[ilo0-9]{3}-[ilo0-9]{4}.*\"
regex.icontainsregex\".*8[ilo0-9]{9}.*\"
regex.icontainsregex\".*\+[1li].*\"
strings.ilikesubstring*"*you did not*"*
strings.ilikesubstring*"*is not for*"*
strings.ilikesubstring*"*done by you*"*
regex.icontainsregex\".*didn\'t ma[kd]e this.*\"
strings.ilikesubstring*"*Fruad Alert*"*
strings.ilikesubstring*"*Fraud Alert*"*
strings.ilikesubstring*"*fraudulent*"*
strings.ilikesubstring*"*Zelle*"*
strings.ilikesubstring*"*subscription*"*
strings.ilikesubstring*"*antivirus*"*
strings.ilikesubstring*"*order*"*
strings.ilikesubstring*"*support*"*
strings.ilikesubstring*"*sincerely apologize*"*
strings.ilikesubstring*"*receipt*"*
strings.ilikesubstring*"*invoice*"*
strings.ilikesubstring*"*Purchase*"*
strings.ilikesubstring*"*transaction*"*
strings.ilikesubstring*"*Market*Value*"*
strings.ilikesubstring*"*BTC*"*
strings.ilikesubstring*"*call*"*
strings.ilikesubstring*"*get in touch with our*"*
strings.ilikesubstring*"*quickly inform*"*
strings.ilikesubstring*"*quickly reach*"*
strings.ilikesubstring*"*detected unusual transactions*
strings.ilikesubstring*"*without your authorization*"*
strings.ilikesubstring*"*cancel*"*
strings.ilikesubstring*"*renew*"*
strings.ilikesubstring*"*refund*"*
strings.ilikesubstring*"*+1*"*
regex.icontainsregex\"help.{0,3}desk
strings.ilikesubstring*"* your funds*"*
strings.ilikesubstring*"* your checking*"*
strings.ilikesubstring*"* your saving*"*
strings.ilikesubstring*"*transfer*"*
strings.ilikesubstring*"*secure your account*"*
strings.ilikesubstring*"*recover your *"*
regex.icontainsregexnote from.{0,50}(?:call|reach|contact|paypal)
ml.nlu_classifier(body.current_thread.text).intents[].nameequalscallback_scam
regex.icontainsregex\+𝟭|𝗽𝗮𝘆𝗺𝗲𝗻𝘁|𝗛𝗲𝗹𝗽 𝗗𝗲𝘀𝗸|𝗿𝗲𝗳𝘂𝗻𝗱|𝗮𝗻𝘁𝗶𝘃𝗶𝗿𝘂𝘀|𝗰𝗮𝗹𝗹|𝗰𝗮𝗻𝗰𝗲𝗹
strings.ilikesubstring*"*kindly*"*

Stages and Predicates

Stage 1: mql_rule

and
  or
    any(ml.nlu_classifier(body.current_thread.text).intents)
      ml.nlu_classifier(body.current_thread.text).intents.name eq "callback_scam"
    body.current_thread.text regex_match "note from.{0,50}(?:call|reach|contact|paypal)"
    body.html.inner_text regex_match "\\+𝟭|𝗽𝗮𝘆𝗺𝗲𝗻𝘁|𝗛𝗲𝗹𝗽 𝗗𝗲𝘀𝗸|𝗿𝗲𝗳𝘂𝗻𝗱|𝗮𝗻𝘁𝗶𝘃𝗶𝗿𝘂𝘀|𝗰𝗮𝗹𝗹|𝗰𝗮𝗻𝗰𝗲𝗹"
    body.html.inner_text regex_match "\\\".*didn\\'t ma[kd]e this.*\\\""
    body.html.inner_text regex_match "\\\"help.{0,3}desk"
    body.html.inner_text wildcard "*\"* your checking*\"*"
    body.html.inner_text wildcard "*\"* your funds*\"*"
    body.html.inner_text wildcard "*\"* your saving*\"*"
    body.html.inner_text wildcard "*\"*+1*\"*"
    body.html.inner_text wildcard "*\"*BTC*\"*"
    body.html.inner_text wildcard "*\"*Fraud Alert*\"*"
    body.html.inner_text wildcard "*\"*Fruad Alert*\"*"
    body.html.inner_text wildcard "*\"*Market*Value*\"*"
    body.html.inner_text wildcard "*\"*Purchase*\"*"
    body.html.inner_text wildcard "*\"*Zelle*\"*"
    body.html.inner_text wildcard "*\"*antivirus*\"*"
    body.html.inner_text wildcard "*\"*call*\"*"
    body.html.inner_text wildcard "*\"*cancel*\"*"
    body.html.inner_text wildcard "*\"*detected unusual transactions*"
    body.html.inner_text wildcard "*\"*done by you*\"*"
    body.html.inner_text wildcard "*\"*fraudulent*\"*"
    body.html.inner_text wildcard "*\"*get in touch with our*\"*"
    body.html.inner_text wildcard "*\"*invoice*\"*"
    body.html.inner_text wildcard "*\"*is not for*\"*"
    body.html.inner_text wildcard "*\"*kindly*\"*"
    body.html.inner_text wildcard "*\"*order*\"*"
    body.html.inner_text wildcard "*\"*quickly inform*\"*"
    body.html.inner_text wildcard "*\"*quickly reach*\"*"
    body.html.inner_text wildcard "*\"*receipt*\"*"
    body.html.inner_text wildcard "*\"*recover your *\"*"
    body.html.inner_text wildcard "*\"*refund*\"*"
    body.html.inner_text wildcard "*\"*renew*\"*"
    body.html.inner_text wildcard "*\"*secure your account*\"*"
    body.html.inner_text wildcard "*\"*sincerely apologize*\"*"
    body.html.inner_text wildcard "*\"*subscription*\"*"
    body.html.inner_text wildcard "*\"*support*\"*"
    body.html.inner_text wildcard "*\"*transaction*\"*"
    body.html.inner_text wildcard "*\"*transfer*\"*"
    body.html.inner_text wildcard "*\"*without your authorization*\"*"
    body.html.inner_text wildcard "*\"*you did not*\"*"
  or
    and
      strings.replace_confusables(body.current_thread.text) regex_match "\\\".*8[ilo0-9]{9}.*\\\""
      strings.replace_confusables(body.current_thread.text) regex_match "\\\".*\\+[1li].*\\\""
    strings.replace_confusables(body.current_thread.text) regex_match "\\\".*[ilo0-9]{3}-[ilo0-9]{3}-[ilo0-9]{4}.*\\\""
    strings.replace_confusables(body.current_thread.text) regex_match "\\\".*[ilo0-9]{3}\\.[ilo0-9]{3}\\.[ilo0-9]{4}.*\\\""
    strings.replace_confusables(body.current_thread.text) regex_match "\\\".*\\([ilo0-9]{3}\\)-[ilo0-9]{3}-[ilo0-9]{4}.*\\\""
    strings.replace_confusables(body.current_thread.text) regex_match "\\\".*\\([ilo0-9]{3}\\)\\s[ilo0-9]{3}-[ilo0-9]{4}.*\\\""
    strings.replace_confusables(body.current_thread.text) regex_match "\\\".*\\+?([ilo0-9]{1}.)?\\(?[ilo0-9]{3}?\\)?.[ilo0-9]{3}.?[ilo0-9]{4}.*\\\""
    strings.replace_confusables(body.current_thread.text) regex_match "\\\".*\\+[ilo0-9]{1,3}[ilo0-9]{10}.*\\\""
  or
    and
      strings.replace_confusables(subject.subject) regex_match ".*8[ilo0-9]{9}.*"
      strings.replace_confusables(subject.subject) regex_match "\\+[1li]"
    body.html.display_text match " requested"
    strings.replace_confusables(subject.subject) regex_match ".*[ilo0-9]{3}-[ilo0-9]{3}-[ilo0-9]{4}.*"
    strings.replace_confusables(subject.subject) regex_match ".*[ilo0-9]{3}\\.[ilo0-9]{3}\\.[ilo0-9]{4}.*"
    strings.replace_confusables(subject.subject) regex_match ".*\\([ilo0-9]{3}\\)-[ilo0-9]{3}-[ilo0-9]{4}.*"
    strings.replace_confusables(subject.subject) regex_match ".*\\([ilo0-9]{3}\\)[\\s-]+[ilo0-9]{3}[\\s-]+[ilo0-9]{4}.*"
    strings.replace_confusables(subject.subject) regex_match ".*\\+?([ilo0-9]{1}.)?\\(?[ilo0-9]{3}?\\)?.[ilo0-9]{3}.?[ilo0-9]{4}.*"
    strings.replace_confusables(subject.subject) regex_match ".*\\+[ilo0-9]{1,3}[ilo0-9]{10}.*"
  attachments length_compare "0"
  sender.email.domain.root_domain eq "zellepay.com"
  type.inbound eq "true"

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
body.current_thread.textregex_match
  • note from.{0,50}(?:call|reach|contact|paypal)
field:"body.current_thread.text" kind:regex_match value:"note from.{0,50}(?:call|reach|contact|paypal)"
body.html.display_textwildcard
  • * requested*
field:"body.html.display_text" kind:wildcard value:"* requested*"
body.html.inner_textregex_match
  • \".*didn\'t ma[kd]e this.*\"
  • \"help.{0,3}desk
    • +𝟭
    • 𝗽𝗮𝘆𝗺𝗲𝗻𝘁
    • 𝗛𝗲𝗹𝗽 𝗗𝗲𝘀𝗸
    • 𝗿𝗲𝗳𝘂𝗻𝗱
    • 𝗮𝗻𝘁𝗶𝘃𝗶𝗿𝘂𝘀
    • 𝗰𝗮𝗹𝗹
    • 𝗰𝗮𝗻𝗰𝗲𝗹
field:"body.html.inner_text" kind:regex_match
body.html.inner_textwildcard
  • *"* your checking*"*
  • *"* your funds*"*
  • *"* your saving*"*
  • *"*+1*"*
  • *"*BTC*"*
  • *"*Fraud Alert*"*
  • *"*Fruad Alert*"*
  • *"*Market*Value*"*
  • *"*Purchase*"*
  • *"*Zelle*"*
  • *"*antivirus*"*
  • *"*call*"*
  • *"*cancel*"*
  • *"*detected unusual transactions*
  • *"*done by you*"*
  • *"*fraudulent*"*
  • *"*get in touch with our*"*
  • *"*invoice*"*
  • *"*is not for*"*
  • *"*kindly*"*
  • *"*order*"*
  • *"*quickly inform*"*
  • *"*quickly reach*"*
  • *"*receipt*"*
  • *"*recover your *"*
  • *"*refund*"*
  • *"*renew*"*
  • *"*secure your account*"*
  • *"*sincerely apologize*"*
  • *"*subscription*"*
  • *"*support*"*
  • *"*transaction*"*
  • *"*transfer*"*
  • *"*without your authorization*"*
  • *"*you did not*"*
field:"body.html.inner_text" kind:wildcard
sender.email.domain.root_domainin
  • zellepay.com
field:"sender.email.domain.root_domain" kind:in value:"zellepay.com"
strings.replace_confusables(body.current_thread.text)regex_match
  • \".*8[ilo0-9]{9}.*\"
  • \".*[ilo0-9]{3}-[ilo0-9]{3}-[ilo0-9]{4}.*\"
  • \".*[ilo0-9]{3}.[ilo0-9]{3}.[ilo0-9]{4}.*\"
  • \".*([ilo0-9]{3})-[ilo0-9]{3}-[ilo0-9]{4}.*\"
  • \".*([ilo0-9]{3})\s[ilo0-9]{3}-[ilo0-9]{4}.*\"
  • \".*+?([ilo0-9]{1}.)?(?[ilo0-9]{3}?)?.[ilo0-9]{3}.?[ilo0-9]{4}.*\"
  • \".*+[1li].*\"
  • \".*+[ilo0-9]{1,3}[ilo0-9]{10}.*\"
field:"strings.replace_confusables(body.current_thread.text)" kind:regex_match
strings.replace_confusables(subject.subject)regex_match
  • .*8[ilo0-9]{9}.*
  • .*[ilo0-9]{3}-[ilo0-9]{3}-[ilo0-9]{4}.*
  • .*[ilo0-9]{3}.[ilo0-9]{3}.[ilo0-9]{4}.*
  • .*([ilo0-9]{3})-[ilo0-9]{3}-[ilo0-9]{4}.*
  • .*([ilo0-9]{3})[\s-]+[ilo0-9]{3}[\s-]+[ilo0-9]{4}.*
  • .*+?([ilo0-9]{1}.)?(?[ilo0-9]{3}?)?.[ilo0-9]{3}.?[ilo0-9]{4}.*
  • .*+[ilo0-9]{1,3}[ilo0-9]{10}.*
  • +[1li]
field:"strings.replace_confusables(subject.subject)" kind:regex_match
type.inboundeq
  • true transforms: boolean
field:"type.inbound" kind:eq value:"true"

Callback phishing via Zoho service abuse

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

Callback phishing campaigns have been observed abusing Zoho Invoice services to send fraudulent invoices with callback phishing contents.

Threat classification

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

CategoryValues
Attack typesCallback Phishing
Tactics and techniquesEvasion, Free email provider, Impersonation: Brand, Social engineering

Telemetry coverage

PlatformRecord / event type
SublimeInbound email message

Message attributes

  • attachments
  • body
  • body.current_thread
  • headers
  • headers.auth_summary
  • sender.email
  • subject
  • type

Rule body

type.inbound

// Legitimate Zoho sending infratructure
and (
  sender.email.domain.root_domain in ('zohoinvoice.com')
  // check for SPF or DMARC passed
  and (headers.auth_summary.spf.pass or headers.auth_summary.dmarc.pass)
)
and (
  // Callback Phishing in body (brand names required)
  (
    length(attachments) == 0

    // brand names are required.
    and regex.icontains(body.current_thread.text,
                        (
                          "mcafee|norton|geek.{0,5}squad|paypal|ebay|symantec|best buy|lifelock"
                        )
    )
    and 3 of (
      strings.ilike(body.current_thread.text, '*purchase*'),
      strings.ilike(body.current_thread.text, '*payment*'),
      strings.ilike(body.current_thread.text, '*transaction*'),
      strings.ilike(body.current_thread.text, '*subscription*'),
      strings.ilike(body.current_thread.text, '*antivirus*'),
      strings.ilike(body.current_thread.text, '*order*'),
      strings.ilike(body.current_thread.text, '*support*'),
      strings.ilike(body.current_thread.text, '*help line*'),
      strings.ilike(body.current_thread.text, '*receipt*'),
      strings.ilike(body.current_thread.text, '*invoice*'),
      strings.ilike(body.current_thread.text, '*call*'),
      strings.ilike(body.current_thread.text, '*cancel*'),
      strings.ilike(body.current_thread.text, '*renew*'),
      strings.ilike(body.current_thread.text, '*refund*')
    )
    // phone number regex
    and any([body.current_thread.text, subject.subject],
            regex.icontains(., '\b\+?(\d{1}.)?\(?\d{3}?\)?.\d{3}.?\d{4}\b')
    )
  )
  // all attachments are PDFs with callback phishing indicators Brands Required
  or (
    length(attachments) < 3
    and all(attachments, .file_extension == "pdf")
    // the attachment is a pdf with 1 page, and at least 60 ocr chars
    and any(attachments,
            (
              .file_extension == "pdf"
              and any(file.explode(.), .scan.exiftool.page_count < 3)
              and any(file.explode(.), length(.scan.ocr.raw) > 60)

              // 4 of the following strings are found        
              and (
                any(file.explode(.),
                    4 of (
                      strings.icontains(.scan.ocr.raw, "purchase"),
                      strings.icontains(.scan.ocr.raw, "payment"),
                      strings.icontains(.scan.ocr.raw, "transaction"),
                      strings.icontains(.scan.ocr.raw, "subscription"),
                      strings.icontains(.scan.ocr.raw, "antivirus"),
                      strings.icontains(.scan.ocr.raw, "order"),
                      strings.icontains(.scan.ocr.raw, "support"),
                      strings.icontains(.scan.ocr.raw, "help line"),
                      strings.icontains(.scan.ocr.raw, "receipt"),
                      strings.icontains(.scan.ocr.raw, "invoice"),
                      strings.icontains(.scan.ocr.raw, "call"),
                      strings.icontains(.scan.ocr.raw, "helpdesk"),
                      strings.icontains(.scan.ocr.raw, "cancel"),
                      strings.icontains(.scan.ocr.raw, "renew"),
                      strings.icontains(.scan.ocr.raw, "refund"),
                      strings.icontains(.scan.ocr.raw, "amount"),
                      strings.icontains(.scan.ocr.raw, "crypto"),
                      strings.icontains(.scan.ocr.raw, "wallet address"),
                      regex.icontains(.scan.ocr.raw, '\$\d{3}\.\d{2}\b'),
                      regex.icontains(.scan.ocr.raw,
                                      '(\+\d|1.(\()?\d{3}(\))?\D\d{3}\D\d{4})'
                      ),
                      regex.icontains(.scan.ocr.raw,
                                      '\+?(\d{1,2})?\s?\(?\d{3}\)?[\s\.\-⋅]{0,5}\d{3}[\s\.\-⋅]{0,5}\d{4}'
                      )
                    )

                    // 1 of the following strings is found, representing common Callback brands          
                    and (
                      1 of (
                        strings.icontains(.scan.ocr.raw, "geek squad"),
                        strings.icontains(.scan.ocr.raw, "lifelock"),
                        strings.icontains(.scan.ocr.raw, "best buy"),
                        strings.icontains(.scan.ocr.raw, "mcafee"),
                        strings.icontains(.scan.ocr.raw, "norton"),
                        strings.icontains(.scan.ocr.raw, "ebay"),
                        strings.icontains(.scan.ocr.raw, "paypal"),
                      )
                      // add additional logic for common language for paypal, which is a valid payment method
                      and not regex.icontains(.scan.ocr.raw,
                                              "paypal[^\n]+accepted"
                      )
                      and not regex.icontains(.scan.ocr.raw,
                                              "payment.{0,30}(via|by) paypal"
                      )
                      and not regex.icontains(.scan.ocr.raw,
                                              '\d{2,4} norton'
                      ) // an address, example: 1234 Norton Road
                    )
                )
                or any(ml.logo_detect(.).brands,
                       .name in ("PayPal", "Norton", "GeekSquad", "Ebay")
                )
              )
            )
    )
  )
)

Detection logic

Scope: inbound message.

Callback phishing campaigns have been observed abusing Zoho Invoice services to send fraudulent invoices with callback phishing contents.

  1. inbound message
  2. all of:
    • sender.email.domain.root_domain in ('zohoinvoice.com')
    • any of:
      • headers.auth_summary.spf.pass
      • headers.auth_summary.dmarc.pass
  3. any of:
    • all of:
      • length(attachments) is 0
      • body.current_thread.text matches 'mcafee|norton|geek.{0,5}squad|paypal|ebay|symantec|best buy|lifelock'
      • at least 3 of 14: body.current_thread.text matches any of 14 patterns
        • *purchase*
        • *payment*
        • *transaction*
        • *subscription*
        • *antivirus*
        • *order*
        • *support*
        • *help line*
        • *receipt*
        • *invoice*
        • *call*
        • *cancel*
        • *renew*
        • *refund*
      • any of [body.current_thread.text, subject.subject] where:
        • . matches '\\b\\+?(\\d{1}.)?\\(?\\d{3}?\\)?.\\d{3}.?\\d{4}\\b'
    • all of:
      • length(attachments) < 3
      • all of attachments where:
        • .file_extension is 'pdf'
      • any of attachments where all hold:
        • .file_extension is 'pdf'
        • any of file.explode(.) where:
          • .scan.exiftool.page_count < 3
        • any of file.explode(.) where:
          • length(.scan.ocr.raw) > 60
        • any of:
          • any of file.explode(.) where all hold:
            • at least 4 of:
              • .scan.ocr.raw contains 'purchase'
              • .scan.ocr.raw contains 'payment'
              • .scan.ocr.raw contains 'transaction'
              • .scan.ocr.raw contains 'subscription'
              • .scan.ocr.raw contains 'antivirus'
              • .scan.ocr.raw contains 'order'
              • .scan.ocr.raw contains 'support'
              • .scan.ocr.raw contains 'help line'
              • .scan.ocr.raw contains 'receipt'
              • .scan.ocr.raw contains 'invoice'
              • .scan.ocr.raw contains 'call'
              • .scan.ocr.raw contains 'helpdesk'
              • .scan.ocr.raw contains 'cancel'
              • .scan.ocr.raw contains 'renew'
              • .scan.ocr.raw contains 'refund'
              • .scan.ocr.raw contains 'amount'
              • .scan.ocr.raw contains 'crypto'
              • .scan.ocr.raw contains 'wallet address'
              • .scan.ocr.raw matches '\\$\\d{3}\\.\\d{2}\\b'
              • .scan.ocr.raw matches '(\\+\\d|1.(\\()?\\d{3}(\\))?\\D\\d{3}\\D\\d{4})'
              • .scan.ocr.raw matches '\\+?(\\d{1,2})?\\s?\\(?\\d{3}\\)?[\\s\\.\\-⋅]{0,5}\\d{3}[\\s\\.\\-⋅]{0,5}\\d{4}'
            • all of:
              • at least 1 of 7: .scan.ocr.raw contains any of 7 patterns
                • geek squad
                • lifelock
                • best buy
                • mcafee
                • norton
                • ebay
                • paypal
              • not:
                • .scan.ocr.raw matches 'paypal[^\\n]+accepted'
              • not:
                • .scan.ocr.raw matches 'payment.{0,30}(via|by) paypal'
              • not:
                • .scan.ocr.raw matches '\\d{2,4} norton'
          • any of ml.logo_detect(.).brands where:
            • .name in ('PayPal', 'Norton', 'GeekSquad', 'Ebay')

Inspects: attachments[].file_extension, body.current_thread.text, headers.auth_summary.dmarc.pass, headers.auth_summary.spf.pass, sender.email.domain.root_domain, subject.subject, type.inbound. Sensors: file.explode, ml.logo_detect, regex.icontains, strings.icontains, strings.ilike.

Indicators matched (50)

FieldMatchValue
sender.email.domain.root_domainmemberzohoinvoice.com
regex.icontainsregexmcafee|norton|geek.{0,5}squad|paypal|ebay|symantec|best buy|lifelock
strings.ilikesubstring*purchase*
strings.ilikesubstring*payment*
strings.ilikesubstring*transaction*
strings.ilikesubstring*subscription*
strings.ilikesubstring*antivirus*
strings.ilikesubstring*order*
strings.ilikesubstring*support*
strings.ilikesubstring*help line*
strings.ilikesubstring*receipt*
strings.ilikesubstring*invoice*
38 more
strings.ilikesubstring*call*
strings.ilikesubstring*cancel*
strings.ilikesubstring*renew*
strings.ilikesubstring*refund*
regex.icontainsregex\b\+?(\d{1}.)?\(?\d{3}?\)?.\d{3}.?\d{4}\b
attachments[].file_extensionequalspdf
strings.icontainssubstringpurchase
strings.icontainssubstringpayment
strings.icontainssubstringtransaction
strings.icontainssubstringsubscription
strings.icontainssubstringantivirus
strings.icontainssubstringorder
strings.icontainssubstringsupport
strings.icontainssubstringhelp line
strings.icontainssubstringreceipt
strings.icontainssubstringinvoice
strings.icontainssubstringcall
strings.icontainssubstringhelpdesk
strings.icontainssubstringcancel
strings.icontainssubstringrenew
strings.icontainssubstringrefund
strings.icontainssubstringamount
strings.icontainssubstringcrypto
strings.icontainssubstringwallet address
regex.icontainsregex\$\d{3}\.\d{2}\b
regex.icontainsregex(\+\d|1.(\()?\d{3}(\))?\D\d{3}\D\d{4})
regex.icontainsregex\+?(\d{1,2})?\s?\(?\d{3}\)?[\s\.\-⋅]{0,5}\d{3}[\s\.\-⋅]{0,5}\d{4}
strings.icontainssubstringgeek squad
strings.icontainssubstringlifelock
strings.icontainssubstringbest buy
strings.icontainssubstringmcafee
strings.icontainssubstringnorton
strings.icontainssubstringebay
strings.icontainssubstringpaypal
ml.logo_detect(attachments[]).brands[].namememberPayPal
ml.logo_detect(attachments[]).brands[].namememberNorton
ml.logo_detect(attachments[]).brands[].namememberGeekSquad
ml.logo_detect(attachments[]).brands[].namememberEbay

Stages and Predicates

Stage 1: mql_rule

and
  or
    and
      any(attachments)
        and
          or
            any(file.explode(attachments))
              and
                or
                  file.explode(attachments[])[].scan.ocr.raw contains "amount"
                  file.explode(attachments[])[].scan.ocr.raw contains "antivirus"
                  file.explode(attachments[])[].scan.ocr.raw contains "call"
                  file.explode(attachments[])[].scan.ocr.raw contains "cancel"
                  file.explode(attachments[])[].scan.ocr.raw contains "crypto"
                  file.explode(attachments[])[].scan.ocr.raw contains "help line"
                  file.explode(attachments[])[].scan.ocr.raw contains "helpdesk"
                  file.explode(attachments[])[].scan.ocr.raw contains "invoice"
                  file.explode(attachments[])[].scan.ocr.raw contains "order"
                  file.explode(attachments[])[].scan.ocr.raw contains "payment"
                  file.explode(attachments[])[].scan.ocr.raw contains "purchase"
                  file.explode(attachments[])[].scan.ocr.raw contains "receipt"
                  file.explode(attachments[])[].scan.ocr.raw contains "refund"
                  file.explode(attachments[])[].scan.ocr.raw contains "renew"
                  file.explode(attachments[])[].scan.ocr.raw contains "subscription"
                  file.explode(attachments[])[].scan.ocr.raw contains "support"
                  file.explode(attachments[])[].scan.ocr.raw contains "transaction"
                  file.explode(attachments[])[].scan.ocr.raw contains "wallet address"
                  file.explode(attachments[])[].scan.ocr.raw regex_match "(\\+\\d|1.(\\()?\\d{3}(\\))?\\D\\d{3}\\D\\d{4})"
                  file.explode(attachments[])[].scan.ocr.raw regex_match "\\$\\d{3}\\.\\d{2}\\b"
                  file.explode(attachments[])[].scan.ocr.raw regex_match "\\+?(\\d{1,2})?\\s?\\(?\\d{3}\\)?[\\s\\.\\-⋅]{0,5}\\d{3}[\\s\\.\\-⋅]{0,5}\\d{4}"
                or
                  file.explode(attachments[])[].scan.ocr.raw contains "best buy"
                  file.explode(attachments[])[].scan.ocr.raw contains "ebay"
                  file.explode(attachments[])[].scan.ocr.raw contains "geek squad"
                  file.explode(attachments[])[].scan.ocr.raw contains "lifelock"
                  file.explode(attachments[])[].scan.ocr.raw contains "mcafee"
                  file.explode(attachments[])[].scan.ocr.raw contains "norton"
                  file.explode(attachments[])[].scan.ocr.raw contains "paypal"
                not
                  file.explode(attachments[])[].scan.ocr.raw regex_match "\\d{2,4} norton"
                not
                  file.explode(attachments[])[].scan.ocr.raw regex_match "payment.{0,30}(via|by) paypal"
                not
                  file.explode(attachments[])[].scan.ocr.raw regex_match "paypal[^\\n]+accepted"
            any(ml.logo_detect(attachments).brands)
              ml.logo_detect(attachments).brands.name in ["Ebay", "GeekSquad", "Norton", "PayPal"]
          any(file.explode(attachments))
            file.explode(attachments).scan.exiftool.page_count lt "3"
          any(file.explode(attachments))
            file.explode(attachments).scan.ocr.raw length_compare "60"
          attachments.file_extension eq "pdf"
      attachments length_compare "3"
       macro "all(attachments)"
    and
      any([body.current_thread.text, subject.subject])
        [body.current_thread.text, subject.subject] regex_match "\\b\\+?(\\d{1}.)?\\(?\\d{3}?\\)?.\\d{3}.?\\d{4}\\b"
      or
        body.current_thread.text match "antivirus"
        body.current_thread.text match "call"
        body.current_thread.text match "cancel"
        body.current_thread.text match "help line"
        body.current_thread.text match "invoice"
        body.current_thread.text match "order"
        body.current_thread.text match "payment"
        body.current_thread.text match "purchase"
        body.current_thread.text match "receipt"
        body.current_thread.text match "refund"
        body.current_thread.text match "renew"
        body.current_thread.text match "subscription"
        body.current_thread.text match "support"
        body.current_thread.text match "transaction"
      attachments length_compare "0"
      body.current_thread.text regex_match "mcafee|norton|geek.{0,5}squad|paypal|ebay|symantec|best buy|lifelock"
  or
    headers.auth_summary.dmarc.pass eq "true"
    headers.auth_summary.spf.pass eq "true"
  sender.email.domain.root_domain eq "zohoinvoice.com"
  type.inbound eq "true"

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
body.current_thread.textregex_match
    • mcafee
    • norton
    • geek.{0,5}squad
    • paypal
    • ebay
    • symantec
    • best buy
    • lifelock
field:"body.current_thread.text" kind:regex_match
body.current_thread.textwildcard
  • *antivirus*
  • *call*
  • *cancel*
  • *help line*
  • *invoice*
  • *order*
  • *payment*
  • *purchase*
  • *receipt*
  • *refund*
  • *renew*
  • *subscription*
  • *support*
  • *transaction*
field:"body.current_thread.text" kind:wildcard
headers.auth_summary.dmarc.passeq
  • true transforms: boolean
field:"headers.auth_summary.dmarc.pass" kind:eq value:"true"
headers.auth_summary.spf.passeq
  • true transforms: boolean
field:"headers.auth_summary.spf.pass" kind:eq value:"true"
sender.email.domain.root_domainin
  • zohoinvoice.com
field:"sender.email.domain.root_domain" kind:in value:"zohoinvoice.com"
type.inboundeq
  • true transforms: boolean
field:"type.inbound" kind:eq value:"true"

Callback Phishing via Zoom comment

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

Detects callback scams sent through legitimate Zoom infrastructure that impersonate well-known brands like McAfee, Norton, or PayPal. These messages contain purchase or support-related language along with phone numbers, attempting to trick recipients into calling fraudulent support lines.

Threat classification

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

CategoryValues
Attack typesCallback Phishing
Tactics and techniquesOut of band pivot, Social engineering, Impersonation: Brand

Telemetry coverage

PlatformRecord / event type
SublimeInbound email message

Message attributes

  • body
  • body.current_thread
  • headers
  • headers.auth_summary
  • sender.email
  • subject
  • type

Rule body

type.inbound
and length(attachments) == 0

// Legitimate Zoom sending infratructure
and sender.email.domain.root_domain == 'zoom.us'
and (headers.auth_summary.spf.pass or headers.auth_summary.dmarc.pass)

// Zoom Logo
and any(ml.logo_detect(file.message_screenshot()).brands, .name == "Zoom")

// Callback Phishing
and regex.icontains(body.current_thread.text,
                    (
                      "mcafee|n[o0]rt[o0]n|geek.{0,5}squad|paypal|ebay|symantec|best buy|lifel[o0]ck"
                    )
)
and (
  3 of (
    strings.ilike(body.current_thread.text, '*purchase*'),
    strings.ilike(body.current_thread.text, '*payment*'),
    strings.ilike(body.current_thread.text, '*transaction*'),
    strings.ilike(body.current_thread.text, '*subscription*'),
    strings.ilike(body.current_thread.text, '*antivirus*'),
    strings.ilike(body.current_thread.text, '*order*'),
    strings.ilike(body.current_thread.text, '*support*'),
    strings.ilike(body.current_thread.text, '*help line*'),
    strings.ilike(body.current_thread.text, '*receipt*'),
    strings.ilike(body.current_thread.text, '*invoice*'),
    strings.ilike(body.current_thread.text, '*call*'),
    strings.ilike(body.current_thread.text, '*cancel*'),
    strings.ilike(body.current_thread.text, '*renew*'),
    strings.ilike(body.current_thread.text, '*refund*'),
    strings.ilike(body.current_thread.text, '*host key*')
  )
  or any(ml.nlu_classifier(body.current_thread.text).intents,
         .name == "callback_scam" and .confidence != "low"
  )
)
// phone number regex
and any([body.current_thread.text, subject.subject],
        regex.icontains(.,
                        '\+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4}',
                        '\+?([ilo0-9]{1,2})?\s?\(?\d{3}\)?[\s\.\-⋅]{0,5}[ilo0-9]{3}[\s\.\-⋅]{0,5}[ilo0-9]{4}'
        )
)
// negation for legitimate AI generated meeting summaries from Zoom
and not (
  (
    sender.display_name == "Meeting Summary with AI Companion"
    and sender.email.email == "no-reply@zoom.us"
    and headers.auth_summary.dmarc.pass
  )
  or (
    strings.icontains(subject.subject, "Meeting assets")
    and strings.icontains(body.current_thread.text, "Meeting summary")
    and sender.email.email == "no-reply@zoom.us"
    and headers.auth_summary.dmarc.pass
  )
)

Detection logic

Scope: inbound message.

Detects callback scams sent through legitimate Zoom infrastructure that impersonate well-known brands like McAfee, Norton, or PayPal. These messages contain purchase or support-related language along with phone numbers, attempting to trick recipients into calling fraudulent support lines.

  1. inbound message
  2. length(attachments) is 0
  3. sender.email.domain.root_domain is 'zoom.us'
  4. any of:
    • headers.auth_summary.spf.pass
    • headers.auth_summary.dmarc.pass
  5. any of ml.logo_detect(file.message_screenshot()).brands where:
    • .name is 'Zoom'
  6. body.current_thread.text matches 'mcafee|n[o0]rt[o0]n|geek.{0,5}squad|paypal|ebay|symantec|best buy|lifel[o0]ck'
  7. any of:
    • at least 3 of 15: body.current_thread.text matches any of 15 patterns
      • *purchase*
      • *payment*
      • *transaction*
      • *subscription*
      • *antivirus*
      • *order*
      • *support*
      • *help line*
      • *receipt*
      • *invoice*
      • *call*
      • *cancel*
      • *renew*
      • *refund*
      • *host key*
    • any of ml.nlu_classifier(body.current_thread.text).intents where all hold:
      • .name is 'callback_scam'
      • .confidence is not 'low'
  8. any of [body.current_thread.text, subject.subject] where:
    • . matches any of 2 patterns
      • \+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4}
      • \+?([ilo0-9]{1,2})?\s?\(?\d{3}\)?[\s\.\-⋅]{0,5}[ilo0-9]{3}[\s\.\-⋅]{0,5}[ilo0-9]{4}
  9. none of:
    • all of:
      • sender.display_name is 'Meeting Summary with AI Companion'
      • sender.email.email is 'no-reply@zoom.us'
      • headers.auth_summary.dmarc.pass
    • all of:
      • subject.subject contains 'Meeting assets'
      • body.current_thread.text contains 'Meeting summary'
      • sender.email.email is 'no-reply@zoom.us'
      • headers.auth_summary.dmarc.pass

Inspects: body.current_thread.text, headers.auth_summary.dmarc.pass, headers.auth_summary.spf.pass, sender.display_name, sender.email.domain.root_domain, sender.email.email, subject.subject, type.inbound. Sensors: file.message_screenshot, ml.logo_detect, ml.nlu_classifier, regex.icontains, strings.icontains, strings.ilike.

Indicators matched (21)

FieldMatchValue
sender.email.domain.root_domainequalszoom.us
ml.logo_detect(file.message_screenshot()).brands[].nameequalsZoom
regex.icontainsregexmcafee|n[o0]rt[o0]n|geek.{0,5}squad|paypal|ebay|symantec|best buy|lifel[o0]ck
strings.ilikesubstring*purchase*
strings.ilikesubstring*payment*
strings.ilikesubstring*transaction*
strings.ilikesubstring*subscription*
strings.ilikesubstring*antivirus*
strings.ilikesubstring*order*
strings.ilikesubstring*support*
strings.ilikesubstring*help line*
strings.ilikesubstring*receipt*
9 more
strings.ilikesubstring*invoice*
strings.ilikesubstring*call*
strings.ilikesubstring*cancel*
strings.ilikesubstring*renew*
strings.ilikesubstring*refund*
strings.ilikesubstring*host key*
ml.nlu_classifier(body.current_thread.text).intents[].nameequalscallback_scam
regex.icontainsregex\+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4}
regex.icontainsregex\+?([ilo0-9]{1,2})?\s?\(?\d{3}\)?[\s\.\-⋅]{0,5}[ilo0-9]{3}[\s\.\-⋅]{0,5}[ilo0-9]{4}

Stages and Predicates

Stage 1: mql_rule

and
  not
    or
      and
        body.current_thread.text contains "Meeting summary"
        headers.auth_summary.dmarc.pass eq "true"
        sender.email.email eq "no-reply@zoom.us"
        subject.subject contains "Meeting assets"
      and
        headers.auth_summary.dmarc.pass eq "true"
        sender.display_name eq "Meeting Summary with AI Companion"
        sender.email.email eq "no-reply@zoom.us"
  or
    any(ml.nlu_classifier(body.current_thread.text).intents)
      and
        ml.nlu_classifier(body.current_thread.text).intents.confidence ne "low"
        ml.nlu_classifier(body.current_thread.text).intents.name eq "callback_scam"
    body.current_thread.text match "antivirus"
    body.current_thread.text match "call"
    body.current_thread.text match "cancel"
    body.current_thread.text match "help line"
    body.current_thread.text match "host key"
    body.current_thread.text match "invoice"
    body.current_thread.text match "order"
    body.current_thread.text match "payment"
    body.current_thread.text match "purchase"
    body.current_thread.text match "receipt"
    body.current_thread.text match "refund"
    body.current_thread.text match "renew"
    body.current_thread.text match "subscription"
    body.current_thread.text match "support"
    body.current_thread.text match "transaction"
  any([body.current_thread.text, subject.subject])
    or
      [body.current_thread.text, subject.subject] regex_match "\\+?([ilo0-9]{1,2})?\\s?\\(?\\d{3}\\)?[\\s\\.\\-⋅]{0,5}[ilo0-9]{3}[\\s\\.\\-⋅]{0,5}[ilo0-9]{4}"
      [body.current_thread.text, subject.subject] regex_match "\\+?([ilo0-9]{1}.)?\\(?[ilo0-9]{3}?\\)?.[ilo0-9]{3}.?[ilo0-9]{4}"
  or
    headers.auth_summary.dmarc.pass eq "true"
    headers.auth_summary.spf.pass eq "true"
  any(ml.logo_detect(file.message_screenshot()).brands)
    ml.logo_detect(file.message_screenshot()).brands.name eq "Zoom"
  attachments length_compare "0"
  body.current_thread.text regex_match "mcafee|n[o0]rt[o0]n|geek.{0,5}squad|paypal|ebay|symantec|best buy|lifel[o0]ck"
  sender.email.domain.root_domain eq "zoom.us"
  type.inbound eq "true"

Exclusions

The rule actively suppresses these predicates.

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
body.current_thread.textregex_match
    • mcafee
    • n[o0]rt[o0]n
    • geek.{0,5}squad
    • paypal
    • ebay
    • symantec
    • best buy
    • lifel[o0]ck
field:"body.current_thread.text" kind:regex_match
body.current_thread.textwildcard
  • *antivirus*
  • *call*
  • *cancel*
  • *help line*
  • *host key*
  • *invoice*
  • *order*
  • *payment*
  • *purchase*
  • *receipt*
  • *refund*
  • *renew*
  • *subscription*
  • *support*
  • *transaction*
field:"body.current_thread.text" kind:wildcard
headers.auth_summary.dmarc.passeq
  • true transforms: boolean
field:"headers.auth_summary.dmarc.pass" kind:eq value:"true"
headers.auth_summary.spf.passeq
  • true transforms: boolean
field:"headers.auth_summary.spf.pass" kind:eq value:"true"
sender.email.domain.root_domaineq
  • zoom.us
field:"sender.email.domain.root_domain" kind:eq value:"zoom.us"
type.inboundeq
  • true transforms: boolean
field:"type.inbound" kind:eq value:"true"

Callback phishing: AOL senders with suspicious HTML template or PDF attachment

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

Detects a specific behavioral pattern from AOL senders using consistent HTML templates and PDF attachment characteristics. The pattern includes particular Yahoo-style formatting with specific font families, and standardized PDF metadata when attachments are present.

Threat classification

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

CategoryValues
Attack typesCallback Phishing
Tactics and techniquesFree email provider, Social engineering

Telemetry coverage

PlatformRecord / event type
SublimeInbound email message

Message attributes

  • attachments
  • body
  • body.html
  • headers
  • recipients
  • sender.email
  • type

Rule body

type.inbound
// sender is aol
and sender.email.domain.root_domain == "aol.com"

// there is a single recipient
and length(recipients.to) == 1
and length(recipients.cc) == 0
and length(recipients.bcc) == 0

// is not a reply
and headers.in_reply_to is null

// this is another way to limit replies but need to account for 
// a behavior where Yahoo/Aol seems to include it's own message ID as a reference
and length(headers.references) == 1

// all message-id values end in mail.yahoo.com, some benign messages use @aol.com
and strings.iends_with(headers.message_id, '@mail.yahoo.com>')

// All are using the legit Yahoo X-Mailer
// this removes AOL sent from iphones and other non AOL client
and strings.ends_with(headers.mailer, 'AolMailNorrin')

// exclude common recipients which interact with aol addresses that are commonly (but not always) benign 
// recipeint exclusions are suggested for other recipients
and (
  // no attachment
  (
    length(attachments) == 0
    // if there are no attachments focus on the HTML template being observed
    and (

      // yahoo div followed by <br>
      // // verdana, helvetica, sans-serif;
      strings.icontains(body.html.raw,
                        "<div class=\"yahoo-style-wrap\" style=\"font-family:verdana, helvetica, sans-serif;font-size:18px;\">\r\n<div dir=\"ltr\" data-setdir=\"false\"><br>\r\n"
      )
      // // Helvetica Neue, Helvetica, Arial, sans-serif;
      or strings.icontains(body.html.raw,
                           "<div class=\"yahoo-style-wrap\" style=\"font-family:Helvetica Neue, Helvetica, Arial, sans-serif;font-size:18px;\">\r\n<div dir=\"ltr\" data-setdir=\"false\"><br>\r\n"
      )
      // yahoo div followed by doctype 
      // // verdana, helvetica, sans-serif;
      or strings.icontains(body.html.raw,
                           "<div class=\"yahoo-style-wrap\" style=\"font-family:verdana, helvetica, sans-serif;font-size:18px;\">\r\n<div dir=\"ltr\" data-setdir=\"false\"><!DOCTYPE html>"
      )
      // // Helvetica Neue, Helvetica, Arial, sans-serif;
      or strings.icontains(body.html.raw,
                           "<div class=\"yahoo-style-wrap\" style=\"font-family:Helvetica Neue, Helvetica, Arial, sans-serif;font-size:18px;\">\r\n<div dir=\"ltr\" data-setdir=\"false\"><!DOCTYPE html>"
      )
    )
  )
  or (
    // if there is an attachment, there can be only one
    length(attachments) == 1
    and all(attachments,
            // it's a PDF, 
            .file_type == "pdf"
            and (
              // static content_id value for the attachments
              (
                .content_id == '<@yahoo.com>' or .content_id == '@yahoo.com'
              )
              // created by observed static PDF details
              or (

                // 
                // This rule makes use of a beta feature and is subject to change without notice
                // using the beta feature in custom rules is not suggested until it has been formally released
                // 
                beta.parse_exif(.).creator == "wkhtmltopdf 0.12.6"
                and beta.parse_exif(.).title is null
                and beta.parse_exif(.).producer == 'Qt 4.8.7'
              )
            )
    )
  )
)

Detection logic

Scope: inbound message.

Detects a specific behavioral pattern from AOL senders using consistent HTML templates and PDF attachment characteristics. The pattern includes particular Yahoo-style formatting with specific font families, and standardized PDF metadata when attachments are present.

  1. inbound message
  2. sender.email.domain.root_domain is 'aol.com'
  3. length(recipients.to) is 1
  4. length(recipients.cc) is 0
  5. length(recipients.bcc) is 0
  6. headers.in_reply_to is missing
  7. length(headers.references) is 1
  8. headers.message_id ends with '@mail.yahoo.com>'
  9. headers.mailer ends with 'AolMailNorrin'
  10. any of:
    • all of:
      • length(attachments) is 0
      • body.html.raw contains any of 4 patterns
        • <div class=\"yahoo-style-wrap\" style=\"font-family:verdana, helvetica, sans-serif;font-size:18px;\">\r\n<div dir=\"ltr\" data-setdir=\"false\"><br>\r\n
        • <div class=\"yahoo-style-wrap\" style=\"font-family:Helvetica Neue, Helvetica, Arial, sans-serif;font-size:18px;\">\r\n<div dir=\"ltr\" data-setdir=\"false\"><br>\r\n
        • <div class=\"yahoo-style-wrap\" style=\"font-family:verdana, helvetica, sans-serif;font-size:18px;\">\r\n<div dir=\"ltr\" data-setdir=\"false\"><!DOCTYPE html>
        • <div class=\"yahoo-style-wrap\" style=\"font-family:Helvetica Neue, Helvetica, Arial, sans-serif;font-size:18px;\">\r\n<div dir=\"ltr\" data-setdir=\"false\"><!DOCTYPE html>
    • all of:
      • length(attachments) is 1
      • all of attachments where all hold:
        • .file_type is 'pdf'
        • any of:
          • any of:
            • .content_id is '<@yahoo.com>'
            • .content_id is '@yahoo.com'
          • all of:
            • beta.parse_exif(.).creator is 'wkhtmltopdf 0.12.6'
            • beta.parse_exif(.).title is missing
            • beta.parse_exif(.).producer is 'Qt 4.8.7'

Inspects: attachments[].content_id, attachments[].file_type, body.html.raw, headers.in_reply_to, headers.mailer, headers.message_id, headers.references, recipients.bcc, recipients.cc, recipients.to, sender.email.domain.root_domain, type.inbound. Sensors: beta.parse_exif, strings.ends_with, strings.icontains, strings.iends_with.

Indicators matched (10)

FieldMatchValue
sender.email.domain.root_domainequalsaol.com
strings.iends_withsuffix@mail.yahoo.com>
strings.ends_withsuffixAolMailNorrin
strings.icontainssubstring<div class=\"yahoo-style-wrap\" style=\"font-family:verdana, helvetica, sans-serif;font-size:18px;\">\r\n<div dir=\"ltr\" data-setdir=\"false\"><br>\r\n
strings.icontainssubstring<div class=\"yahoo-style-wrap\" style=\"font-family:Helvetica Neue, Helvetica, Arial, sans-serif;font-size:18px;\">\r\n<div dir=\"ltr\" data-setdir=\"false\"><br>\r\n
strings.icontainssubstring<div class=\"yahoo-style-wrap\" style=\"font-family:verdana, helvetica, sans-serif;font-size:18px;\">\r\n<div dir=\"ltr\" data-setdir=\"false\"><!DOCTYPE html>
strings.icontainssubstring<div class=\"yahoo-style-wrap\" style=\"font-family:Helvetica Neue, Helvetica, Arial, sans-serif;font-size:18px;\">\r\n<div dir=\"ltr\" data-setdir=\"false\"><!DOCTYPE html>
attachments[].file_typeequalspdf
attachments[].content_idequals<@yahoo.com>
attachments[].content_idequals@yahoo.com

Stages and Predicates

Stage 1: mql_rule

and
  or
    and
      or
        body.html.raw contains "<div class=\\\"yahoo-style-wrap\\\" style=\\\"font-family:Helvetica Neue, Helvetica, Arial, sans-serif;font-size:18px;\\\">\\r\\n<div dir=\\\"ltr\\\" data-setdir=\\\"false\\\"><!DOCTYPE html>"
        body.html.raw contains "<div class=\\\"yahoo-style-wrap\\\" style=\\\"font-family:Helvetica Neue, Helvetica, Arial, sans-serif;font-size:18px;\\\">\\r\\n<div dir=\\\"ltr\\\" data-setdir=\\\"false\\\"><br>\\r\\n"
        body.html.raw contains "<div class=\\\"yahoo-style-wrap\\\" style=\\\"font-family:verdana, helvetica, sans-serif;font-size:18px;\\\">\\r\\n<div dir=\\\"ltr\\\" data-setdir=\\\"false\\\"><!DOCTYPE html>"
        body.html.raw contains "<div class=\\\"yahoo-style-wrap\\\" style=\\\"font-family:verdana, helvetica, sans-serif;font-size:18px;\\\">\\r\\n<div dir=\\\"ltr\\\" data-setdir=\\\"false\\\"><br>\\r\\n"
      attachments length_compare "0"
    and
      attachments length_compare "1"
       macro "all(attachments)"
  headers.in_reply_to is_null
  headers.mailer ends_with "AolMailNorrin"
  headers.message_id ends_with "@mail.yahoo.com>"
  headers.references length_compare "1"
  recipients.bcc length_compare "0"
  recipients.cc length_compare "0"
  recipients.to length_compare "1"
  sender.email.domain.root_domain eq "aol.com"
  type.inbound eq "true"

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
body.html.rawcontains
  • <div class=\"yahoo-style-wrap\" style=\"font-family:Helvetica Neue, Helvetica, Arial, sans-serif;font-size:18px;\">\r\n<div dir=\"ltr\" data-setdir=\"false\"><!DOCTYPE html>
  • <div class=\"yahoo-style-wrap\" style=\"font-family:Helvetica Neue, Helvetica, Arial, sans-serif;font-size:18px;\">\r\n<div dir=\"ltr\" data-setdir=\"false\"><br>\r\n
  • <div class=\"yahoo-style-wrap\" style=\"font-family:verdana, helvetica, sans-serif;font-size:18px;\">\r\n<div dir=\"ltr\" data-setdir=\"false\"><!DOCTYPE html>
  • <div class=\"yahoo-style-wrap\" style=\"font-family:verdana, helvetica, sans-serif;font-size:18px;\">\r\n<div dir=\"ltr\" data-setdir=\"false\"><br>\r\n
field:"body.html.raw" kind:contains
headers.in_reply_tois_null
  • (no value, null check)
field:"headers.in_reply_to" kind:is_null
headers.mailerends_with
  • AolMailNorrin
field:"headers.mailer" kind:ends_with value:"AolMailNorrin"
headers.message_idends_with
  • @mail.yahoo.com>
field:"headers.message_id" kind:ends_with value:"@mail.yahoo.com>"
sender.email.domain.root_domaineq
  • aol.com
field:"sender.email.domain.root_domain" kind:eq value:"aol.com"
type.inboundeq
  • true transforms: boolean
field:"type.inbound" kind:eq value:"true"

Callback phishing: Branded invoice from sender/reply-to domain less than 30 days old

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

This rule checks for invoicing content from a sender, reply-to domain or return-path domain less than 30d old. It also checks the body or the OCR'd screenshot for key words commonly abused in fraudulent invoicing attacks.

Threat classification

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

CategoryValues
Attack typesCallback Phishing
Tactics and techniquesImpersonation: Brand, Out of band pivot, Social engineering

Telemetry coverage

PlatformRecord / event type
SublimeInbound email message

Message attributes

  • body
  • body.current_thread
  • headers
  • headers.reply_to
  • headers.return_path
  • sender.email
  • type

Rule body

type.inbound
// reply to domain that's less than 30d old and doesn't match the sender
and (
  (
    length(headers.reply_to) > 0
    and all(headers.reply_to,
            network.whois(.email.domain).days_old <= 30
            and .email.email != sender.email.email
    )
  )

  // or the return path or sender domain is less than 30d old 
  or network.whois(headers.return_path.domain).days_old <= 30
  or network.whois(sender.email.domain).days_old <= 30
)

// invoicing with high confidence
and any(ml.nlu_classifier(body.current_thread.text).tags,
        .name == "invoice" and .confidence == "high"
)

// commonly abused brands in body
and (
  strings.ilike(body.current_thread.text,
                "*mcafee*",
                "*norton*",
                "*geek squad*",
                "*paypal*",
                "*ebay*",
                "*symantec*",
                "*best buy*",
                "*lifelock*",
                "*virus*"
  )

  // commonly abused brand logo
  or any(ml.logo_detect(file.message_screenshot()).brands,
         .name in ("PayPal", "Norton", "GeekSquad", "Ebay")
  )

  // check message screenshot ocr for commonly abused brands
  //
  // This rule makes use of a beta feature and is subject to change without notice
  // using the beta feature in custom rules is not suggested until it has been formally released
  //    
  or 1 of (
    strings.icontains(beta.ocr(file.message_screenshot()).text, "geek squad"),
    strings.icontains(beta.ocr(file.message_screenshot()).text, "lifelock"),
    strings.icontains(beta.ocr(file.message_screenshot()).text, "best buy"),
    strings.icontains(beta.ocr(file.message_screenshot()).text, "mcafee"),
    strings.icontains(beta.ocr(file.message_screenshot()).text, "norton"),
    strings.icontains(beta.ocr(file.message_screenshot()).text, "ebay"),
    strings.icontains(beta.ocr(file.message_screenshot()).text, "paypal"),
    strings.icontains(beta.ocr(file.message_screenshot()).text, "virus"),
  )
)

// phone number regex
and regex.icontains(body.current_thread.text,
                    '\+?(\d{1}.)?\(?\d{3}?\)?.\d{3}.?\d{4}'
)
and not profile.by_sender().solicited
and not profile.by_sender().any_messages_benign

Detection logic

Scope: inbound message.

This rule checks for invoicing content from a sender, reply-to domain or return-path domain less than 30d old. It also checks the body or the OCR'd screenshot for key words commonly abused in fraudulent invoicing attacks.

  1. inbound message
  2. any of:
    • all of:
      • length(headers.reply_to) > 0
      • all of headers.reply_to where all hold:
        • network.whois(.email.domain).days_old ≤ 30
        • .email.email is not sender.email.email
    • network.whois(headers.return_path.domain).days_old ≤ 30
    • network.whois(sender.email.domain).days_old ≤ 30
  3. any of ml.nlu_classifier(body.current_thread.text).tags where all hold:
    • .name is 'invoice'
    • .confidence is 'high'
  4. any of:
    • body.current_thread.text matches any of 9 patterns
      • *mcafee*
      • *norton*
      • *geek squad*
      • *paypal*
      • *ebay*
      • *symantec*
      • *best buy*
      • *lifelock*
      • *virus*
    • any of ml.logo_detect(file.message_screenshot()).brands where:
      • .name in ('PayPal', 'Norton', 'GeekSquad', 'Ebay')
    • at least 1 of 8: beta.ocr(file.message_screenshot()).text contains any of 8 patterns
      • geek squad
      • lifelock
      • best buy
      • mcafee
      • norton
      • ebay
      • paypal
      • virus
  5. body.current_thread.text matches '\\+?(\\d{1}.)?\\(?\\d{3}?\\)?.\\d{3}.?\\d{4}'
  6. not:
    • profile.by_sender().solicited
  7. not:
    • profile.by_sender().any_messages_benign

Inspects: body.current_thread.text, headers.reply_to, headers.reply_to[].email.domain, headers.reply_to[].email.email, headers.return_path.domain, sender.email.domain, sender.email.email, type.inbound. Sensors: beta.ocr, file.message_screenshot, ml.logo_detect, ml.nlu_classifier, network.whois, profile.by_sender, regex.icontains, strings.icontains, strings.ilike.

Indicators matched (24)

FieldMatchValue
ml.nlu_classifier(body.current_thread.text).tags[].nameequalsinvoice
ml.nlu_classifier(body.current_thread.text).tags[].confidenceequalshigh
strings.ilikesubstring*mcafee*
strings.ilikesubstring*norton*
strings.ilikesubstring*geek squad*
strings.ilikesubstring*paypal*
strings.ilikesubstring*ebay*
strings.ilikesubstring*symantec*
strings.ilikesubstring*best buy*
strings.ilikesubstring*lifelock*
strings.ilikesubstring*virus*
ml.logo_detect(file.message_screenshot()).brands[].namememberPayPal
12 more
ml.logo_detect(file.message_screenshot()).brands[].namememberNorton
ml.logo_detect(file.message_screenshot()).brands[].namememberGeekSquad
ml.logo_detect(file.message_screenshot()).brands[].namememberEbay
strings.icontainssubstringgeek squad
strings.icontainssubstringlifelock
strings.icontainssubstringbest buy
strings.icontainssubstringmcafee
strings.icontainssubstringnorton
strings.icontainssubstringebay
strings.icontainssubstringpaypal
strings.icontainssubstringvirus
regex.icontainsregex\+?(\d{1}.)?\(?\d{3}?\)?.\d{3}.?\d{4}

Stages and Predicates

Stage 1: mql_rule

and
  or
    and
      headers.reply_to length_compare "0"
       macro "all(headers.reply_to)"
    network.whois func_call "network.whois(headers.return_path.domain).days_old <= 30"
    network.whois func_call "network.whois(sender.email.domain).days_old <= 30"
  or
    any(ml.logo_detect(file.message_screenshot()).brands)
      ml.logo_detect(file.message_screenshot()).brands.name in ["Ebay", "GeekSquad", "Norton", "PayPal"]
    beta.ocr(file.message_screenshot()).text contains "best buy"
    beta.ocr(file.message_screenshot()).text contains "ebay"
    beta.ocr(file.message_screenshot()).text contains "geek squad"
    beta.ocr(file.message_screenshot()).text contains "lifelock"
    beta.ocr(file.message_screenshot()).text contains "mcafee"
    beta.ocr(file.message_screenshot()).text contains "norton"
    beta.ocr(file.message_screenshot()).text contains "paypal"
    beta.ocr(file.message_screenshot()).text contains "virus"
    body.current_thread.text match "best buy"
    body.current_thread.text match "ebay"
    body.current_thread.text match "geek squad"
    body.current_thread.text match "lifelock"
    body.current_thread.text match "mcafee"
    body.current_thread.text match "norton"
    body.current_thread.text match "paypal"
    body.current_thread.text match "symantec"
    body.current_thread.text match "virus"
  any(ml.nlu_classifier(body.current_thread.text).tags)
    and
      ml.nlu_classifier(body.current_thread.text).tags.confidence eq "high"
      ml.nlu_classifier(body.current_thread.text).tags.name eq "invoice"
  not
    profile.by_sender func_call "profile.by_sender().any_messages_benign"
  not
    profile.by_sender func_call "profile.by_sender().solicited"
  body.current_thread.text regex_match "\\+?(\\d{1}.)?\\(?\\d{3}?\\)?.\\d{3}.?\\d{4}"
  type.inbound eq "true"

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
beta.ocr(file.message_screenshot()).textcontains
  • best buy
  • ebay
  • geek squad
  • lifelock
  • mcafee
  • norton
  • paypal
  • virus
field:"beta.ocr(file.message_screenshot()).text" kind:contains
body.current_thread.textregex_match
  • +?(\d{1}.)?(?\d{3}?)?.\d{3}.?\d{4}
field:"body.current_thread.text" kind:regex_match value:"+?(\d{1}.)?(?\d{3}?)?.\d{3}.?\d{4}"
body.current_thread.textwildcard
  • *best buy*
  • *ebay*
  • *geek squad*
  • *lifelock*
  • *mcafee*
  • *norton*
  • *paypal*
  • *symantec*
  • *virus*
field:"body.current_thread.text" kind:wildcard
type.inboundeq
  • true transforms: boolean
field:"type.inbound" kind:eq value:"true"

Callback phishing: Social Security Administration fraud

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

Detects phishing attempts that impersonate the Social Security Administration, using a single PDF attachment containing specific fraud-related language and a callback number.

Threat classification

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

CategoryValues
Attack typesCallback Phishing
Tactics and techniquesEvasion, Free email provider, Out of band pivot, PDF, Social engineering

Telemetry coverage

PlatformRecord / event type
SublimeInbound email message

Message attributes

  • attachments
  • sender.email
  • type

Rule body

type.inbound
and (
  not profile.by_sender().solicited
  or (
    profile.by_sender().any_messages_malicious_or_spam
    and not profile.by_sender().any_messages_benign
  )
)

// single attachment
and length(attachments) == 1

// sender is freemail
and sender.email.domain.root_domain in $free_email_providers

// the attachment is a pdf with 1 page, and at least 60 ocr chars
and any(attachments,
        .file_extension == "pdf"
        and any(file.explode(.), .scan.exiftool.page_count == 1)
        and any(file.explode(.), length(.scan.ocr.raw) > 60)

        // 4 of the following strings are found        
        and (
          any(file.explode(.),
              4 of (
                strings.icontains(.scan.ocr.raw, "fraudulent activity"),
                strings.icontains(.scan.ocr.raw, "Social Security Number"),
                strings.icontains(.scan.ocr.raw, "SSN"),
                strings.icontains(.scan.ocr.raw, "stolen"),
                strings.icontains(.scan.ocr.raw, "illicit activities"),
                strings.icontains(.scan.ocr.raw,
                                  "Social Security Administration"
                ),
                strings.icontains(.scan.ocr.raw, "if you are innocent"),
                strings.icontains(.scan.ocr.raw, "help line"),
                strings.icontains(.scan.ocr.raw, "Department of Justice"),
                strings.icontains(.scan.ocr.raw, "innocent"),
                regex.icontains(.scan.ocr.raw, '\$\d{3}\.\d{2}\b')
                and (
                  regex.contains(.scan.ocr.raw,
                                 '(\+\d|1.(\()?\d{3}(\))?\D\d{3}\D\d{4})'
                  )
                  or regex.contains(.scan.ocr.raw,
                                    '\+?(\d{1,2})?\s?\(?\d{3}\)?[\s\.\-⋅]{0,5}\d{3}[\s\.\-⋅]{0,5}\d{4}'
                  )
                )
              )
          )
        )
)

Detection logic

Scope: inbound message.

Detects phishing attempts that impersonate the Social Security Administration, using a single PDF attachment containing specific fraud-related language and a callback number.

  1. inbound message
  2. any of:
    • not:
      • profile.by_sender().solicited
    • all of:
      • profile.by_sender().any_messages_malicious_or_spam
      • not:
        • profile.by_sender().any_messages_benign
  3. length(attachments) is 1
  4. sender.email.domain.root_domain in $free_email_providers
  5. any of attachments where all hold:
    • .file_extension is 'pdf'
    • any of file.explode(.) where:
      • .scan.exiftool.page_count is 1
    • any of file.explode(.) where:
      • length(.scan.ocr.raw) > 60
    • any of file.explode(.) where:
      • at least 4 of:
        • .scan.ocr.raw contains 'fraudulent activity'
        • .scan.ocr.raw contains 'Social Security Number'
        • .scan.ocr.raw contains 'SSN'
        • .scan.ocr.raw contains 'stolen'
        • .scan.ocr.raw contains 'illicit activities'
        • .scan.ocr.raw contains 'Social Security Administration'
        • .scan.ocr.raw contains 'if you are innocent'
        • .scan.ocr.raw contains 'help line'
        • .scan.ocr.raw contains 'Department of Justice'
        • .scan.ocr.raw contains 'innocent'
        • all of:
          • .scan.ocr.raw matches '\\$\\d{3}\\.\\d{2}\\b'
          • any of:
            • .scan.ocr.raw matches '(\\+\\d|1.(\\()?\\d{3}(\\))?\\D\\d{3}\\D\\d{4})'
            • .scan.ocr.raw matches '\\+?(\\d{1,2})?\\s?\\(?\\d{3}\\)?[\\s\\.\\-⋅]{0,5}\\d{3}[\\s\\.\\-⋅]{0,5}\\d{4}'

Inspects: attachments[].file_extension, sender.email.domain.root_domain, type.inbound. Sensors: file.explode, profile.by_sender, regex.contains, regex.icontains, strings.icontains. Reference lists: $free_email_providers.

Indicators matched (14)

FieldMatchValue
attachments[].file_extensionequalspdf
strings.icontainssubstringfraudulent activity
strings.icontainssubstringSocial Security Number
strings.icontainssubstringSSN
strings.icontainssubstringstolen
strings.icontainssubstringillicit activities
strings.icontainssubstringSocial Security Administration
strings.icontainssubstringif you are innocent
strings.icontainssubstringhelp line
strings.icontainssubstringDepartment of Justice
strings.icontainssubstringinnocent
regex.icontainsregex\$\d{3}\.\d{2}\b
2 more
regex.containsregex(\+\d|1.(\()?\d{3}(\))?\D\d{3}\D\d{4})
regex.containsregex\+?(\d{1,2})?\s?\(?\d{3}\)?[\s\.\-⋅]{0,5}\d{3}[\s\.\-⋅]{0,5}\d{4}

Stages and Predicates

Stage 1: mql_rule

and
  any(attachments)
    and
      any(file.explode(attachments))
        or
          and
            or
              file.explode(attachments[])[].scan.ocr.raw regex_match "(\\+\\d|1.(\\()?\\d{3}(\\))?\\D\\d{3}\\D\\d{4})"
              file.explode(attachments[])[].scan.ocr.raw regex_match "\\+?(\\d{1,2})?\\s?\\(?\\d{3}\\)?[\\s\\.\\-⋅]{0,5}\\d{3}[\\s\\.\\-⋅]{0,5}\\d{4}"
            file.explode(attachments[])[].scan.ocr.raw regex_match "\\$\\d{3}\\.\\d{2}\\b"
          file.explode(attachments[])[].scan.ocr.raw contains "Department of Justice"
          file.explode(attachments[])[].scan.ocr.raw contains "SSN"
          file.explode(attachments[])[].scan.ocr.raw contains "Social Security Administration"
          file.explode(attachments[])[].scan.ocr.raw contains "Social Security Number"
          file.explode(attachments[])[].scan.ocr.raw contains "fraudulent activity"
          file.explode(attachments[])[].scan.ocr.raw contains "help line"
          file.explode(attachments[])[].scan.ocr.raw contains "if you are innocent"
          file.explode(attachments[])[].scan.ocr.raw contains "illicit activities"
          file.explode(attachments[])[].scan.ocr.raw contains "innocent"
          file.explode(attachments[])[].scan.ocr.raw contains "stolen"
      any(file.explode(attachments))
        file.explode(attachments).scan.exiftool.page_count eq "1"
      any(file.explode(attachments))
        file.explode(attachments).scan.ocr.raw length_compare "60"
      attachments.file_extension eq "pdf"
  or
    and
      not
        profile.by_sender func_call "profile.by_sender().any_messages_benign"
      profile.by_sender func_call "profile.by_sender().any_messages_malicious_or_spam"
    not
      profile.by_sender func_call "profile.by_sender().solicited"
  attachments length_compare "1"
  type.inbound eq "true"
   macro "sender.email.domain.root_domain in free_email_providers"

Indicators

These rows show field, operator, and value matches.

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

Callback phishing: SumUp infrastructure abuse

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

A fraudulent invoice/receipt found in the body of the message sent by exploiting SumUp's receipt email service.

Threat classification

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

CategoryValues
Attack typesBEC/Fraud, Callback Phishing
Tactics and techniquesEvasion, Social engineering

Telemetry coverage

PlatformRecord / event type
SublimeInbound email message

Message attributes

  • body
  • body.current_thread
  • body.html
  • sender.email
  • type

Rule body

type.inbound
and sender.email.domain.root_domain in ("sumup.com")
and (
  strings.ilike(body.html.display_text, "*delivery note*")
  or strings.ilike(body.html.display_text, "*made with sumup*")
)
// keep in sync with https://github.com/sublime-security/sublime-rules/blob/main/detection-rules/paypal_invoice_abuse.yml
and (
  (
    // icontains a phone number
    (
      regex.icontains(strings.replace_confusables(body.current_thread.text),
                      '.*\+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4}.*\n'
      )
      or regex.icontains(strings.replace_confusables(body.current_thread.text),
                         '.*\+[ilo0-9]{1,3}[ilo0-9]{10}.*\n'
      )
      // +12028001238
      or regex.icontains(strings.replace_confusables(body.current_thread.text),
                         '.*[ilo0-9]{3}\.[ilo0-9]{3}\.[ilo0-9]{4}.*\n'
      )
      // 202-800-1238
      or regex.icontains(strings.replace_confusables(body.current_thread.text),
                         '.*[ilo0-9]{3}-[ilo0-9]{3}-[ilo0-9]{4}.*\n'
      )
      // (202) 800-1238
      or regex.icontains(strings.replace_confusables(body.current_thread.text),
                         '.*\([ilo0-9]{3}\)[\s-]+[ilo0-9]{3}[\s-]+[ilo0-9]{4}.*\n'
      )
      // (202)-800-1238
      or regex.icontains(strings.replace_confusables(body.current_thread.text),
                         '.*\([ilo0-9]{3}\)-[ilo0-9]{3}-[ilo0-9]{4}.*\n'
      )
      or ( // 8123456789
        regex.icontains(strings.replace_confusables(body.current_thread.text),
                        '.*8[ilo0-9]{9}.*\n'
        )
        and regex.icontains(strings.replace_confusables(body.current_thread.text
                            ),
                            '\+[1l]'
        )
      )
    )
    and (
      (
        4 of (
          strings.ilike(body.html.inner_text, '*you did not*'),
          strings.ilike(body.html.inner_text, '*is not for*'),
          strings.ilike(body.html.inner_text, '*done by you*'),
          regex.icontains(body.html.inner_text, "didn\'t ma[kd]e this"),
          strings.ilike(body.html.inner_text, '*Fruad Alert*'),
          strings.ilike(body.html.inner_text, '*Fraud Alert*'),
          strings.ilike(body.html.inner_text, '*fraudulent*'),
          strings.ilike(body.html.inner_text, '*using your PayPal*'),
          strings.ilike(body.html.inner_text, '*subscription*'),
          strings.ilike(body.html.inner_text, '*antivirus*'),
          strings.ilike(body.html.inner_text, '*order*'),
          strings.ilike(body.html.inner_text, '*support*'),
          strings.ilike(body.html.inner_text, '*sincerely apologize*'),
          strings.ilike(body.html.inner_text, '*receipt*'),
          strings.ilike(body.html.inner_text, '*invoice*'),
          strings.ilike(body.html.inner_text, '*Purchase*'),
          strings.ilike(body.html.inner_text, '*transaction*'),
          strings.ilike(body.html.inner_text, '*Market*Value*'),
          strings.ilike(body.html.inner_text, '*BTC*'),
          strings.ilike(body.html.inner_text, '*call*'),
          strings.ilike(body.html.inner_text, '*get in touch with our*'),
          strings.ilike(body.html.inner_text, '*quickly inform*'),
          strings.ilike(body.html.inner_text, '*quickly reach *'),
          strings.ilike(body.html.inner_text, '*detected unusual transactions*'),
          strings.ilike(body.html.inner_text, '*without your authorization*'),
          strings.ilike(body.html.inner_text, '*cancel*'),
          strings.ilike(body.html.inner_text, '*renew*'),
          strings.ilike(body.html.inner_text, '*refund*'),
          strings.ilike(body.html.inner_text, '*+1*'),
          regex.icontains(body.html.inner_text, 'help.{0,3}desk'),
          strings.ilike(body.html.inner_text, '* your funds*'),
          strings.ilike(body.html.inner_text, '* your checking*'),
          strings.ilike(body.html.inner_text, '* your saving*'),
          strings.ilike(body.html.inner_text, '*transfer*'),
          strings.ilike(body.html.inner_text, '*secure your account*'),
          strings.ilike(body.html.inner_text, '*recover your*'),
          strings.ilike(body.html.inner_text, '*unusual activity*'),
          strings.ilike(body.html.inner_text, '*suspicious transaction*'),
          strings.ilike(body.html.inner_text, '*transaction history*'),
          strings.ilike(body.html.inner_text, '*please ignore this*'),
          strings.ilike(body.html.inner_text, '*report activity*'),
        )
      )
      or regex.icontains(body.current_thread.text,
                         'note from.{0,50}(?:call|reach|contact|paypal)'
      )
      or any(ml.nlu_classifier(body.current_thread.text).intents,
             .name == "callback_scam"
      )
      or (
        // Unicode confusables words obfuscated in note
        regex.icontains(body.html.inner_text,
                        '\+𝟭|𝗽𝗮𝘆𝗺𝗲𝗻𝘁|𝗛𝗲𝗹𝗽 𝗗𝗲𝘀𝗸|𝗿𝗲𝗳𝘂𝗻𝗱|𝗮𝗻𝘁𝗶𝘃𝗶𝗿𝘂𝘀|𝗰𝗮𝗹𝗹|𝗰𝗮𝗻𝗰𝗲𝗹'
        )
      )
      or strings.ilike(body.html.inner_text, '*kindly*')
    )
  )
)

Detection logic

Scope: inbound message.

A fraudulent invoice/receipt found in the body of the message sent by exploiting SumUp's receipt email service.

  1. inbound message
  2. sender.email.domain.root_domain in ('sumup.com')
  3. any of:
    • body.html.display_text matches '*delivery note*'
    • body.html.display_text matches '*made with sumup*'
  4. all of:
    • any of:
      • strings.replace_confusables(body.current_thread.text) matches '.*\\+?([ilo0-9]{1}.)?\\(?[ilo0-9]{3}?\\)?.[ilo0-9]{3}.?[ilo0-9]{4}.*\\n'
      • strings.replace_confusables(body.current_thread.text) matches '.*\\+[ilo0-9]{1,3}[ilo0-9]{10}.*\\n'
      • strings.replace_confusables(body.current_thread.text) matches '.*[ilo0-9]{3}\\.[ilo0-9]{3}\\.[ilo0-9]{4}.*\\n'
      • strings.replace_confusables(body.current_thread.text) matches '.*[ilo0-9]{3}-[ilo0-9]{3}-[ilo0-9]{4}.*\\n'
      • strings.replace_confusables(body.current_thread.text) matches '.*\\([ilo0-9]{3}\\)[\\s-]+[ilo0-9]{3}[\\s-]+[ilo0-9]{4}.*\\n'
      • strings.replace_confusables(body.current_thread.text) matches '.*\\([ilo0-9]{3}\\)-[ilo0-9]{3}-[ilo0-9]{4}.*\\n'
      • all of:
        • strings.replace_confusables(body.current_thread.text) matches '.*8[ilo0-9]{9}.*\\n'
        • strings.replace_confusables(body.current_thread.text) matches '\\+[1l]'
    • any of:
      • at least 4 of 41: body.html.inner_text matches any of 41 patterns
        • *you did not*
        • *is not for*
        • *done by you*
        • didn\'t ma[kd]e this
        • *Fruad Alert*
        • *Fraud Alert*
        • *fraudulent*
        • *using your PayPal*
        • *subscription*
        • *antivirus*
        • *order*
        • *support*
        • *sincerely apologize*
        • *receipt*
        • *invoice*
        • *Purchase*
        • *transaction*
        • *Market*Value*
        • *BTC*
        • *call*
        • *get in touch with our*
        • *quickly inform*
        • *quickly reach *
        • *detected unusual transactions*
        • *without your authorization*
        • *cancel*
        • *renew*
        • *refund*
        • *+1*
        • help.{0,3}desk
        • * your funds*
        • * your checking*
        • * your saving*
        • *transfer*
        • *secure your account*
        • *recover your*
        • *unusual activity*
        • *suspicious transaction*
        • *transaction history*
        • *please ignore this*
        • *report activity*
      • body.current_thread.text matches 'note from.{0,50}(?:call|reach|contact|paypal)'
      • any of ml.nlu_classifier(body.current_thread.text).intents where:
        • .name is 'callback_scam'
      • body.html.inner_text matches '\\+𝟭|𝗽𝗮𝘆𝗺𝗲𝗻𝘁|𝗛𝗲𝗹𝗽 𝗗𝗲𝘀𝗸|𝗿𝗲𝗳𝘂𝗻𝗱|𝗮𝗻𝘁𝗶𝘃𝗶𝗿𝘂𝘀|𝗰𝗮𝗹𝗹|𝗰𝗮𝗻𝗰𝗲𝗹'
      • body.html.inner_text matches '*kindly*'

Inspects: body.current_thread.text, body.html.display_text, body.html.inner_text, sender.email.domain.root_domain, type.inbound. Sensors: ml.nlu_classifier, regex.icontains, strings.ilike, strings.replace_confusables.

Indicators matched (56)

FieldMatchValue
sender.email.domain.root_domainmembersumup.com
strings.ilikesubstring*delivery note*
strings.ilikesubstring*made with sumup*
regex.icontainsregex.*\+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4}.*\n
regex.icontainsregex.*\+[ilo0-9]{1,3}[ilo0-9]{10}.*\n
regex.icontainsregex.*[ilo0-9]{3}\.[ilo0-9]{3}\.[ilo0-9]{4}.*\n
regex.icontainsregex.*[ilo0-9]{3}-[ilo0-9]{3}-[ilo0-9]{4}.*\n
regex.icontainsregex.*\([ilo0-9]{3}\)[\s-]+[ilo0-9]{3}[\s-]+[ilo0-9]{4}.*\n
regex.icontainsregex.*\([ilo0-9]{3}\)-[ilo0-9]{3}-[ilo0-9]{4}.*\n
regex.icontainsregex.*8[ilo0-9]{9}.*\n
regex.icontainsregex\+[1l]
strings.ilikesubstring*you did not*
44 more
strings.ilikesubstring*is not for*
strings.ilikesubstring*done by you*
regex.icontainsregexdidn\'t ma[kd]e this
strings.ilikesubstring*Fruad Alert*
strings.ilikesubstring*Fraud Alert*
strings.ilikesubstring*fraudulent*
strings.ilikesubstring*using your PayPal*
strings.ilikesubstring*subscription*
strings.ilikesubstring*antivirus*
strings.ilikesubstring*order*
strings.ilikesubstring*support*
strings.ilikesubstring*sincerely apologize*
strings.ilikesubstring*receipt*
strings.ilikesubstring*invoice*
strings.ilikesubstring*Purchase*
strings.ilikesubstring*transaction*
strings.ilikesubstring*Market*Value*
strings.ilikesubstring*BTC*
strings.ilikesubstring*call*
strings.ilikesubstring*get in touch with our*
strings.ilikesubstring*quickly inform*
strings.ilikesubstring*quickly reach *
strings.ilikesubstring*detected unusual transactions*
strings.ilikesubstring*without your authorization*
strings.ilikesubstring*cancel*
strings.ilikesubstring*renew*
strings.ilikesubstring*refund*
strings.ilikesubstring*+1*
regex.icontainsregexhelp.{0,3}desk
strings.ilikesubstring* your funds*
strings.ilikesubstring* your checking*
strings.ilikesubstring* your saving*
strings.ilikesubstring*transfer*
strings.ilikesubstring*secure your account*
strings.ilikesubstring*recover your*
strings.ilikesubstring*unusual activity*
strings.ilikesubstring*suspicious transaction*
strings.ilikesubstring*transaction history*
strings.ilikesubstring*please ignore this*
strings.ilikesubstring*report activity*
regex.icontainsregexnote from.{0,50}(?:call|reach|contact|paypal)
ml.nlu_classifier(body.current_thread.text).intents[].nameequalscallback_scam
regex.icontainsregex\+𝟭|𝗽𝗮𝘆𝗺𝗲𝗻𝘁|𝗛𝗲𝗹𝗽 𝗗𝗲𝘀𝗸|𝗿𝗲𝗳𝘂𝗻𝗱|𝗮𝗻𝘁𝗶𝘃𝗶𝗿𝘂𝘀|𝗰𝗮𝗹𝗹|𝗰𝗮𝗻𝗰𝗲𝗹
strings.ilikesubstring*kindly*

Stages and Predicates

Stage 1: mql_rule

and
  or
    any(ml.nlu_classifier(body.current_thread.text).intents)
      ml.nlu_classifier(body.current_thread.text).intents.name eq "callback_scam"
    body.current_thread.text regex_match "note from.{0,50}(?:call|reach|contact|paypal)"
    body.html.inner_text match " your checking"
    body.html.inner_text match " your funds"
    body.html.inner_text match " your saving"
    body.html.inner_text match "+1"
    body.html.inner_text match "BTC"
    body.html.inner_text match "Fraud Alert"
    body.html.inner_text match "Fruad Alert"
    body.html.inner_text match "Purchase"
    body.html.inner_text match "antivirus"
    body.html.inner_text match "call"
    body.html.inner_text match "cancel"
    body.html.inner_text match "detected unusual transactions"
    body.html.inner_text match "done by you"
    body.html.inner_text match "fraudulent"
    body.html.inner_text match "get in touch with our"
    body.html.inner_text match "invoice"
    body.html.inner_text match "is not for"
    body.html.inner_text match "kindly"
    body.html.inner_text match "order"
    body.html.inner_text match "please ignore this"
    body.html.inner_text match "quickly inform"
    body.html.inner_text match "quickly reach "
    body.html.inner_text match "receipt"
    body.html.inner_text match "recover your"
    body.html.inner_text match "refund"
    body.html.inner_text match "renew"
    body.html.inner_text match "report activity"
    body.html.inner_text match "secure your account"
    body.html.inner_text match "sincerely apologize"
    body.html.inner_text match "subscription"
    body.html.inner_text match "support"
    body.html.inner_text match "suspicious transaction"
    body.html.inner_text match "transaction history"
    body.html.inner_text match "transaction"
    body.html.inner_text match "transfer"
    body.html.inner_text match "unusual activity"
    body.html.inner_text match "using your PayPal"
    body.html.inner_text match "without your authorization"
    body.html.inner_text match "you did not"
    body.html.inner_text regex_match "\\+𝟭|𝗽𝗮𝘆𝗺𝗲𝗻𝘁|𝗛𝗲𝗹𝗽 𝗗𝗲𝘀𝗸|𝗿𝗲𝗳𝘂𝗻𝗱|𝗮𝗻𝘁𝗶𝘃𝗶𝗿𝘂𝘀|𝗰𝗮𝗹𝗹|𝗰𝗮𝗻𝗰𝗲𝗹"
    body.html.inner_text regex_match "didn\\'t ma[kd]e this"
    body.html.inner_text regex_match "help.{0,3}desk"
    body.html.inner_text wildcard "*Market*Value*"
  or
    and
      strings.replace_confusables(body.current_thread.text) regex_match ".*8[ilo0-9]{9}.*\\n"
      strings.replace_confusables(body.current_thread.text) regex_match "\\+[1l]"
    strings.replace_confusables(body.current_thread.text) regex_match ".*[ilo0-9]{3}-[ilo0-9]{3}-[ilo0-9]{4}.*\\n"
    strings.replace_confusables(body.current_thread.text) regex_match ".*[ilo0-9]{3}\\.[ilo0-9]{3}\\.[ilo0-9]{4}.*\\n"
    strings.replace_confusables(body.current_thread.text) regex_match ".*\\([ilo0-9]{3}\\)-[ilo0-9]{3}-[ilo0-9]{4}.*\\n"
    strings.replace_confusables(body.current_thread.text) regex_match ".*\\([ilo0-9]{3}\\)[\\s-]+[ilo0-9]{3}[\\s-]+[ilo0-9]{4}.*\\n"
    strings.replace_confusables(body.current_thread.text) regex_match ".*\\+?([ilo0-9]{1}.)?\\(?[ilo0-9]{3}?\\)?.[ilo0-9]{3}.?[ilo0-9]{4}.*\\n"
    strings.replace_confusables(body.current_thread.text) regex_match ".*\\+[ilo0-9]{1,3}[ilo0-9]{10}.*\\n"
  or
    body.html.display_text match "delivery note"
    body.html.display_text match "made with sumup"
  sender.email.domain.root_domain eq "sumup.com"
  type.inbound eq "true"

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
body.current_thread.textregex_match
  • note from.{0,50}(?:call|reach|contact|paypal)
field:"body.current_thread.text" kind:regex_match value:"note from.{0,50}(?:call|reach|contact|paypal)"
body.html.display_textwildcard
  • *delivery note*
  • *made with sumup*
field:"body.html.display_text" kind:wildcard
body.html.inner_textregex_match
    • +𝟭
    • 𝗽𝗮𝘆𝗺𝗲𝗻𝘁
    • 𝗛𝗲𝗹𝗽 𝗗𝗲𝘀𝗸
    • 𝗿𝗲𝗳𝘂𝗻𝗱
    • 𝗮𝗻𝘁𝗶𝘃𝗶𝗿𝘂𝘀
    • 𝗰𝗮𝗹𝗹
    • 𝗰𝗮𝗻𝗰𝗲𝗹
  • didn\'t ma[kd]e this
  • help.{0,3}desk
field:"body.html.inner_text" kind:regex_match
body.html.inner_textwildcard
  • * your checking*
  • * your funds*
  • * your saving*
  • *+1*
  • *BTC*
  • *Fraud Alert*
  • *Fruad Alert*
  • *Market*Value*
  • *Purchase*
  • *antivirus*
  • *call*
  • *cancel*
  • *detected unusual transactions*
  • *done by you*
  • *fraudulent*
  • *get in touch with our*
  • *invoice*
  • *is not for*
  • *kindly*
  • *order*
  • *please ignore this*
  • *quickly inform*
  • *quickly reach *
  • *receipt*
  • *recover your*
  • *refund*
  • *renew*
  • *report activity*
  • *secure your account*
  • *sincerely apologize*
  • *subscription*
  • *support*
  • *suspicious transaction*
  • *transaction history*
  • *transaction*
  • *transfer*
  • *unusual activity*
  • *using your PayPal*
  • *without your authorization*
  • *you did not*
field:"body.html.inner_text" kind:wildcard
sender.email.domain.root_domainin
  • sumup.com
field:"sender.email.domain.root_domain" kind:in value:"sumup.com"
strings.replace_confusables(body.current_thread.text)regex_match
  • .*8[ilo0-9]{9}.*\n
  • .*[ilo0-9]{3}-[ilo0-9]{3}-[ilo0-9]{4}.*\n
  • .*[ilo0-9]{3}.[ilo0-9]{3}.[ilo0-9]{4}.*\n
  • .*([ilo0-9]{3})-[ilo0-9]{3}-[ilo0-9]{4}.*\n
  • .*([ilo0-9]{3})[\s-]+[ilo0-9]{3}[\s-]+[ilo0-9]{4}.*\n
  • .*+?([ilo0-9]{1}.)?(?[ilo0-9]{3}?)?.[ilo0-9]{3}.?[ilo0-9]{4}.*\n
  • .*+[ilo0-9]{1,3}[ilo0-9]{10}.*\n
  • +[1l]
field:"strings.replace_confusables(body.current_thread.text)" kind:regex_match
type.inboundeq
  • true transforms: boolean
field:"type.inbound" kind:eq value:"true"

Callback phishing: Zero-width character obfuscation from freemail sender

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

Detects inbound messages sent from free email providers that contain a high volume of zero-width no-break space characters inserted before closing HTML tags, a technique used to break up and obfuscate text from content scanners. The rule also requires the presence of a phone number pattern in the message thread, consistent with callback phishing lures that rely on victims dialing a number rather than clicking a link.

Threat classification

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

CategoryValues
Attack typesCallback Phishing
Tactics and techniquesFree email provider, Evasion, Social engineering

Telemetry coverage

PlatformRecord / event type
SublimeInbound email message

Message attributes

  • body
  • body.current_thread
  • body.html
  • sender.email
  • type

Rule body

type.inbound
and sender.email.domain.root_domain in $free_email_providers
and regex.icount(body.html.raw, '\x{FEFF}+</[^>]*>[a-z0-9]') >= 20
and regex.icontains(body.current_thread.text,
                    '\+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4}',
                    '\+?([ilo0-9]{1,2})?\s?\(?\d{3}\)?[\s\.\-⋅]{0,5}[ilo0-9]{3}[\s\.\-⋅]{0,5}[ilo0-9]{4}'
)

Detection logic

Scope: inbound message.

Detects inbound messages sent from free email providers that contain a high volume of zero-width no-break space characters inserted before closing HTML tags, a technique used to break up and obfuscate text from content scanners. The rule also requires the presence of a phone number pattern in the message thread, consistent with callback phishing lures that rely on victims dialing a number rather than clicking a link.

  1. inbound message
  2. sender.email.domain.root_domain in $free_email_providers
  3. regex.icount(body.html.raw, '\\x{FEFF}+</[^>]*>[a-z0-9]') ≥ 20
  4. body.current_thread.text matches any of 2 patterns
    • \+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4}
    • \+?([ilo0-9]{1,2})?\s?\(?\d{3}\)?[\s\.\-⋅]{0,5}[ilo0-9]{3}[\s\.\-⋅]{0,5}[ilo0-9]{4}

Inspects: body.current_thread.text, body.html.raw, sender.email.domain.root_domain, type.inbound. Sensors: regex.icontains, regex.icount. Reference lists: $free_email_providers.

Indicators matched (3)

FieldMatchValue
regex.icountregex\x{FEFF}+</[^>]*>[a-z0-9]
regex.icontainsregex\+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4}
regex.icontainsregex\+?([ilo0-9]{1,2})?\s?\(?\d{3}\)?[\s\.\-⋅]{0,5}[ilo0-9]{3}[\s\.\-⋅]{0,5}[ilo0-9]{4}

Stages and Predicates

Stage 1: mql_rule

and
  or
    body.current_thread.text regex_match "\\+?([ilo0-9]{1,2})?\\s?\\(?\\d{3}\\)?[\\s\\.\\-⋅]{0,5}[ilo0-9]{3}[\\s\\.\\-⋅]{0,5}[ilo0-9]{4}"
    body.current_thread.text regex_match "\\+?([ilo0-9]{1}.)?\\(?[ilo0-9]{3}?\\)?.[ilo0-9]{3}.?[ilo0-9]{4}"
  regex.icount func_call "regex.icount(body.html.raw, \"\\x{FEFF}+</[^>]*>[a-z0-9]\") >= 20"
  type.inbound eq "true"
   macro "sender.email.domain.root_domain in free_email_providers"

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
body.current_thread.textregex_match
  • +?([ilo0-9]{1,2})?\s?(?\d{3})?[\s.\-⋅]{0,5}[ilo0-9]{3}[\s.\-⋅]{0,5}[ilo0-9]{4}
  • +?([ilo0-9]{1}.)?(?[ilo0-9]{3}?)?.[ilo0-9]{3}.?[ilo0-9]{4}
field:"body.current_thread.text" kind:regex_match
type.inboundeq
  • true transforms: boolean
field:"type.inbound" kind:eq value:"true"

Service abuse: Callback phishing via Microsoft Teams invite

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

Detects abuse of legitimate Microsoft Teams invites containing callback scam content, including brand references and financial transaction language with phone numbers.

Threat classification

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

CategoryValues
Attack typesCallback Phishing
Tactics and techniquesImpersonation: Brand, Out of band pivot, Social engineering

Telemetry coverage

PlatformRecord / event type
SublimeInbound email message

Message attributes

  • body
  • body.current_thread
  • body.links
  • sender.email
  • subject
  • type

Rule body

type.inbound
and sender.email.domain.domain == "teams.mail.microsoft"
// MS Teams invite indicators
and (
  any(body.links,
      .display_text == "Open Microsoft Teams"
      and (
        .href_url.domain.domain == "login.microsoftonline.com"
        or strings.iends_with(.href_url.query_params,
                              "login.microsoftonline.com"
        )
      )
  )
)
and (
  (
    regex.icontains(strings.replace_confusables(body.current_thread.text),
                    (
                      "mcafee|norton|geek.{0,5}squad|pay.?pal|ebay|symantec|best buy|lifelock|(ms|microsoft|teams).{0,10}premium"
                    )
    )
    or 3 of (
      strings.ilike(body.current_thread.text, '*purchase*'),
      strings.ilike(body.current_thread.text, '*p?ym?nt*'),
      strings.ilike(body.current_thread.text, '*transaction*'),
      strings.ilike(body.current_thread.text, '*subscription*'),
      strings.ilike(body.current_thread.text, '*antivirus*'),
      strings.ilike(body.current_thread.text, '*order*'),
      strings.ilike(body.current_thread.text, '*support*'),
      strings.ilike(body.current_thread.text, '*help line*'),
      strings.ilike(body.current_thread.text, '*receipt*'),
      strings.ilike(body.current_thread.text, '*c?ntact*'),
      strings.ilike(body.current_thread.text, '*cancel*'),
      strings.ilike(body.current_thread.text, '*renew*'),
      strings.ilike(body.current_thread.text, '*refund*'),
      strings.ilike(body.current_thread.text, '*billing*'),
      regex.icontains(body.current_thread.text, '[li]nv.[li]ce')
    )
  )
  // phone number regex
  and any([body.current_thread.text, subject.subject],
          regex.icontains(.,
                          '\+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4}'
          )
  )
)

Detection logic

Scope: inbound message.

Detects abuse of legitimate Microsoft Teams invites containing callback scam content, including brand references and financial transaction language with phone numbers.

  1. inbound message
  2. sender.email.domain.domain is 'teams.mail.microsoft'
  3. any of body.links where all hold:
    • .display_text is 'Open Microsoft Teams'
    • any of:
      • .href_url.domain.domain is 'login.microsoftonline.com'
      • .href_url.query_params ends with 'login.microsoftonline.com'
  4. all of:
    • any of:
      • strings.replace_confusables(body.current_thread.text) matches 'mcafee|norton|geek.{0,5}squad|pay.?pal|ebay|symantec|best buy|lifelock|(ms|microsoft|teams).{0,10}premium'
      • at least 3 of 15: body.current_thread.text matches any of 15 patterns
        • *purchase*
        • *p?ym?nt*
        • *transaction*
        • *subscription*
        • *antivirus*
        • *order*
        • *support*
        • *help line*
        • *receipt*
        • *c?ntact*
        • *cancel*
        • *renew*
        • *refund*
        • *billing*
        • [li]nv.[li]ce
    • any of [body.current_thread.text, subject.subject] where:
      • . matches '\\+?([ilo0-9]{1}.)?\\(?[ilo0-9]{3}?\\)?.[ilo0-9]{3}.?[ilo0-9]{4}'

Inspects: body.current_thread.text, body.links, body.links[].display_text, body.links[].href_url.domain.domain, body.links[].href_url.query_params, sender.email.domain.domain, subject.subject, type.inbound. Sensors: regex.icontains, strings.iends_with, strings.ilike, strings.replace_confusables.

Indicators matched (21)

FieldMatchValue
sender.email.domain.domainequalsteams.mail.microsoft
body.links[].display_textequalsOpen Microsoft Teams
body.links[].href_url.domain.domainequalslogin.microsoftonline.com
strings.iends_withsuffixlogin.microsoftonline.com
regex.icontainsregexmcafee|norton|geek.{0,5}squad|pay.?pal|ebay|symantec|best buy|lifelock|(ms|microsoft|teams).{0,10}premium
strings.ilikesubstring*purchase*
strings.ilikesubstring*p?ym?nt*
strings.ilikesubstring*transaction*
strings.ilikesubstring*subscription*
strings.ilikesubstring*antivirus*
strings.ilikesubstring*order*
strings.ilikesubstring*support*
9 more
strings.ilikesubstring*help line*
strings.ilikesubstring*receipt*
strings.ilikesubstring*c?ntact*
strings.ilikesubstring*cancel*
strings.ilikesubstring*renew*
strings.ilikesubstring*refund*
strings.ilikesubstring*billing*
regex.icontainsregex[li]nv.[li]ce
regex.icontainsregex\+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4}

Stages and Predicates

Stage 1: mql_rule

and
  any(body.links)
    and
      or
        body.links.href_url.domain.domain eq "login.microsoftonline.com"
        body.links.href_url.query_params ends_with "login.microsoftonline.com"
      body.links.display_text eq "Open Microsoft Teams"
  any([body.current_thread.text, subject.subject])
    [body.current_thread.text, subject.subject] regex_match "\\+?([ilo0-9]{1}.)?\\(?[ilo0-9]{3}?\\)?.[ilo0-9]{3}.?[ilo0-9]{4}"
  or
    body.current_thread.text match "antivirus"
    body.current_thread.text match "billing"
    body.current_thread.text match "c?ntact"
    body.current_thread.text match "cancel"
    body.current_thread.text match "help line"
    body.current_thread.text match "order"
    body.current_thread.text match "p?ym?nt"
    body.current_thread.text match "purchase"
    body.current_thread.text match "receipt"
    body.current_thread.text match "refund"
    body.current_thread.text match "renew"
    body.current_thread.text match "subscription"
    body.current_thread.text match "support"
    body.current_thread.text match "transaction"
    body.current_thread.text regex_match "[li]nv.[li]ce"
    strings.replace_confusables(body.current_thread.text) regex_match "mcafee|norton|geek.{0,5}squad|pay.?pal|ebay|symantec|best buy|lifelock|(ms|microsoft|teams).{0,10}premium"
  sender.email.domain.domain eq "teams.mail.microsoft"
  type.inbound eq "true"

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
body.current_thread.textregex_match
  • [li]nv.[li]ce
field:"body.current_thread.text" kind:regex_match value:"[li]nv.[li]ce"
body.current_thread.textwildcard
  • *antivirus*
  • *billing*
  • *c?ntact*
  • *cancel*
  • *help line*
  • *order*
  • *p?ym?nt*
  • *purchase*
  • *receipt*
  • *refund*
  • *renew*
  • *subscription*
  • *support*
  • *transaction*
field:"body.current_thread.text" kind:wildcard
sender.email.domain.domaineq
  • teams.mail.microsoft
field:"sender.email.domain.domain" kind:eq value:"teams.mail.microsoft"
strings.replace_confusables(body.current_thread.text)regex_match
    • mcafee
    • norton
    • geek.{0,5}squad
    • pay.?pal
    • ebay
    • symantec
    • best buy
    • lifelock
    • (ms|microsoft|teams).{0,10}premium
field:"strings.replace_confusables(body.current_thread.text)" kind:regex_match
type.inboundeq
  • true transforms: boolean
field:"type.inbound" kind:eq value:"true"