Medium Severity
Callback Phishing solicitation in message body
Description
A fraudulent invoice/receipt found in the body of the message. Callback Phishing is an attempt by an attacker to solicit the victim (recipient) to call a phone number. The resulting interaction could lead to a multitude of attacks ranging from Financial theft, Remote Access Trojan (RAT) Installation or Ransomware Deployment.
References
No references.
Sublime Security
Created Aug 17th, 2023 • Last updated Feb 26th, 2025
Feed Source
Sublime Core Feed
Source
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_false_positives
)
)
and (
sender.email.domain.root_domain in $free_email_providers
or sender.email.domain.tld in $suspicious_tlds
or network.whois(sender.email.domain).found == false
or headers.mailer in~ ("Microsoft CDO for Windows 2000")
or (
length(recipients.to) == 1
and all(recipients.to, .email.domain.domain not in $org_domains)
)
)
and (
// this section is synced with attachment_callback_phish_with_pdf.yml and attachment_callback_phish_with_img.yml
regex.icontains(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(beta.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 (
any(file.explode(beta.message_screenshot()),
// this seciton is synced with attachment_callback_phish_with_img.yml and attachment_callback_phish_with_pdf.yml
// and above for current_thread.text
3 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'),
regex.icontains(.scan.ocr.raw, "(?:reach|contact) us at"),
strings.icontains(.scan.ocr.raw, '+1'),
strings.icontains(.scan.ocr.raw, 'amount'),
strings.icontains(.scan.ocr.raw, 'charged'),
strings.icontains(.scan.ocr.raw, 'crypto'),
strings.icontains(.scan.ocr.raw, 'wallet address'),
regex.icontains(.scan.ocr.raw, '\$\d{3}\.\d{2}\b'),
)
// phone number regex
and regex.icontains(.scan.ocr.raw,
'\+?([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(.scan.ocr.raw, '(?:from|to|sent|date|cc|subject):') > 3
// this notation of previous threads often only occurs once
and not regex.icontains(.scan.ocr.raw, 'wrote:[\r\n]')
)
)
)
// not high trust sender domains
and (
(
sender.email.domain.root_domain in $high_trust_sender_root_domains
and not headers.auth_summary.dmarc.pass
)
or sender.email.domain.root_domain not in $high_trust_sender_root_domains
)
and not strings.ends_with(headers.message_id, "@shopify.com>")
Playground
Test against your own EMLs or sample data.