EXPLORE
← Back to Explore
sublimehighRule

Callback phishing via e-signature service

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.

MITRE ATT&CK

initial-access

Detection Query

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]'
    )
  )
)

Data Sources

Email MessagesEmail HeadersEmail Attachments

Platforms

email
Raw Content
name: "Callback phishing via e-signature service"
description: "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."
type: "rule"
severity: "high"
source: |
  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]'
      )
    )
  )
attack_types:
  - "Callback Phishing"
tactics_and_techniques:
  - "Free email provider"
  - "Impersonation: Brand"
  - "Social engineering"
detection_methods:
  - "Content analysis"
  - "Computer Vision"
  - "Header analysis"
  - "Optical Character Recognition"
id: "ed37b4fd-22bb-5f55-92fa-215e42f5fe5a"