Detection rules › Sublime MQL
Sublime MQL rules: callback
Brand impersonation: GitHub with callback scam indicators
#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).
| Category | Values |
|---|---|
| Attack types | Callback Phishing |
| Tactics and techniques | Impersonation: Brand, Out of band pivot, Social engineering |
Telemetry coverage
| Platform | Record / event type |
|---|---|
| Sublime | Inbound email message |
Message attributes
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.
- inbound message
- sender.email.email is 'noreply@github.com'
- length(attachments) is 0
any of:
any of
ml.nlu_classifier(body.current_thread.text).intentswhere 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)
| Field | Match | Value |
|---|---|---|
sender.email.email | equals | noreply@github.com |
ml.nlu_classifier(body.current_thread.text).intents[].name | equals | callback_scam |
regex.icontains | regex | mcafee|n[o0]rt[o0]n|geek.{0,5}squad|paypal|ebay|symantec|best buy|lifel[o0]ck |
strings.ilike | substring | *purchase* |
strings.ilike | substring | *payment* |
strings.ilike | substring | *transaction* |
strings.ilike | substring | *subscription* |
strings.ilike | substring | *antivirus* |
strings.ilike | substring | *order* |
strings.ilike | substring | *support* |
strings.ilike | substring | *receipt* |
strings.ilike | substring | *invoice* |
7 more
strings.ilike | substring | *call* |
strings.ilike | substring | *cancel* |
strings.ilike | substring | *renew* |
strings.ilike | substring | *refund* |
strings.ilike | substring | *host key* |
regex.icontains | regex | \+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4} |
regex.icontains | regex | \+?([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.
| Field | Kind | Values | Search |
|---|---|---|---|
body.current_thread.text | regex_match |
| field:"body.current_thread.text" kind:regex_match |
body.current_thread.text | wildcard |
| field:"body.current_thread.text" kind:wildcard |
sender.email.email | eq |
| field:"sender.email.email" kind:eq value:"noreply@github.com" |
type.inbound | eq |
| field:"type.inbound" kind:eq value:"true" |
Callback phishing in body or attachment (untrusted sender)
#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).
| Category | Values |
|---|---|
| Attack types | Callback Phishing |
| Tactics and techniques | Out of band pivot, Social engineering |
Telemetry coverage
| Platform | Record / event type |
|---|---|
| Sublime | Inbound email message |
Message attributes
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.
- inbound message
- length(attachments) < 5
any of:
any of
attachmentswhere 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).intentswhere all hold:- .name is 'callback_scam'
- .confidence in ('medium', 'high')
any of
file.explode(.)where all hold:not:
any of
.scan.exiftool.fieldswhere 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).intentswhere 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(.).brandswhere:- .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).intentswhere 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 squadlifelockbest buymcafeenortonebaypaypalvirus
not:
all of:
any of
headers.domainswhere:- .domain is 'smtp-out.gcp.bigcommerce.net'
- body.html.raw contains 'bigcommerce.com'
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
not:
all of:
- sender.email.domain.root_domain in $high_trust_sender_root_domains
- coalesce(headers.auth_summary.dmarc.pass)
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)
| Field | Match | Value |
|---|---|---|
attachments[].file_type | member | pdf |
attachments[].file_type | member | xlsx |
attachments[].file_type | member | docx |
ml.nlu_classifier(beta.ocr(attachments[]).text).intents[].name | equals | callback_scam |
ml.nlu_classifier(beta.ocr(attachments[]).text).intents[].confidence | member | medium |
ml.nlu_classifier(beta.ocr(attachments[]).text).intents[].confidence | member | high |
ml.nlu_classifier(file.explode(attachments[])[].scan.ocr.raw).intents[].name | equals | callback_scam |
ml.nlu_classifier(file.explode(attachments[])[].scan.ocr.raw).intents[].confidence | member | medium |
ml.nlu_classifier(file.explode(attachments[])[].scan.ocr.raw).intents[].confidence | member | high |
sender.email.local_part | member | no_reply |
sender.email.local_part | member | noreply |
ml.logo_detect(attachments[]).brands[].name | member | PayPal |
23 more
ml.logo_detect(attachments[]).brands[].name | member | Norton |
ml.logo_detect(attachments[]).brands[].name | member | GeekSquad |
ml.logo_detect(attachments[]).brands[].name | member | Ebay |
ml.logo_detect(attachments[]).brands[].name | member | McAfee |
ml.nlu_classifier(body.current_thread.text).intents[].name | member | callback_scam |
ml.nlu_classifier(body.current_thread.text).intents[].confidence | member | medium |
ml.nlu_classifier(body.current_thread.text).intents[].confidence | member | high |
strings.ilike | substring | *PayPal* |
strings.ilike | substring | *Norton* |
strings.ilike | substring | *GeekSquad* |
strings.ilike | substring | *Ebay* |
strings.ilike | substring | *McAfee* |
strings.ilike | substring | *=1 |
regex.icontains | regex | \+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4} |
regex.icontains | regex | \+?([ilo0-9]{1,2})?\s?\(?\d{3}\)?[\s\.\-⋅]{0,5}[ilo0-9]{3}[\s\.\-⋅]{0,5}[ilo0-9]{4} |
strings.icontains | substring | geek squad |
strings.icontains | substring | lifelock |
strings.icontains | substring | best buy |
strings.icontains | substring | mcafee |
strings.icontains | substring | norton |
strings.icontains | substring | ebay |
strings.icontains | substring | paypal |
strings.icontains | substring | virus |
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.
| Field | Kind | Excluded values | Search |
|---|---|---|---|
headers.domains | array_any | excludes:headers.domains | |
body.html.raw | contains | bigcommerce.com | excludes:body.html.raw field:"body.html.raw" value:"bigcommerce.com" |
sender.email.email | eq | opsgenie@opsgenie.net | excludes:sender.email.email field:"sender.email.email" value:"opsgenie@opsgenie.net" |
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
beta.ocr(file.message_screenshot()).text | contains |
| field:"beta.ocr(file.message_screenshot()).text" kind:contains |
body.current_thread.text | regex_match |
| field:"body.current_thread.text" kind:regex_match |
body.current_thread.text | wildcard |
| field:"body.current_thread.text" kind:wildcard |
type.inbound | eq |
| field:"type.inbound" kind:eq value:"true" |
Callback phishing via Adobe Sign comment
#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).
| Category | Values |
|---|---|
| Attack types | Callback Phishing |
| Tactics and techniques | Evasion, Impersonation: Brand, Out of band pivot, Social engineering |
Telemetry coverage
| Platform | Record / event type |
|---|---|
| Sublime | Inbound email message |
Message attributes
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.
- inbound message
- length(attachments) is 0
- sender.email.domain.root_domain is 'adobesign.com'
any of:
- headers.auth_summary.spf.pass
- headers.auth_summary.dmarc.pass
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()).brandswhere:- .name in ('PayPal', 'Norton', 'GeekSquad', 'Ebay', 'McAfee', 'AT&T')
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)
| Field | Match | Value |
|---|---|---|
sender.email.domain.root_domain | equals | adobesign.com |
regex.icontains | regex | (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[].name | member | PayPal |
ml.logo_detect(file.message_screenshot()).brands[].name | member | Norton |
ml.logo_detect(file.message_screenshot()).brands[].name | member | GeekSquad |
ml.logo_detect(file.message_screenshot()).brands[].name | member | Ebay |
ml.logo_detect(file.message_screenshot()).brands[].name | member | McAfee |
ml.logo_detect(file.message_screenshot()).brands[].name | member | AT&T |
strings.icontains | substring | purchase |
strings.icontains | substring | payment |
strings.icontains | substring | transaction |
strings.icontains | substring | subscription |
20 more
strings.icontains | substring | antivirus |
strings.icontains | substring | order |
strings.icontains | substring | support |
strings.icontains | substring | help line |
strings.icontains | substring | receipt |
strings.icontains | substring | invoice |
strings.icontains | substring | call |
strings.icontains | substring | cancel |
strings.icontains | substring | renew |
strings.icontains | substring | refund |
regex.icontains | regex | (?:reach|contact) us at |
strings.icontains | substring | +1 |
strings.icontains | substring | amount |
strings.icontains | substring | charged |
strings.icontains | substring | crypto |
strings.icontains | substring | wallet address |
regex.icontains | regex | \$\d{3}\.\d{2}\b |
regex.icontains | regex | \+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4} |
regex.icontains | regex | \+?([ilo0-9]{1,2})?\s?\(?\d{3}\)?[\s\.\-⋅]{0,5}[ilo0-9]{3}[\s\.\-⋅]{0,5}[ilo0-9]{4} |
strings.icontains | substring | helpdesk |
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.
Callback phishing via calendar invite
#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).
| Category | Values |
|---|---|
| Attack types | Callback Phishing |
| Tactics and techniques | Social engineering, Evasion, ICS Phishing |
Telemetry coverage
| Platform | Record / event type |
|---|---|
| Sublime | Inbound email message |
Message attributes
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.
- inbound message
- length(attachments) > 0
all of
attachmentswhere:- .content_type in ('text/calendar', 'application/ics')
any of
attachmentswhere:any of
file.explode(.)where:any of
.scan.ics.calendarswhere:any of
.componentswhere any holds:any of
ml.nlu_classifier(.summary).intentswhere all hold:- .name is 'callback_scam'
- .confidence is 'high'
any of:
any of
ml.nlu_classifier(.description).intentswhere:- .name is 'callback_scam'
any of
ml.nlu_classifier(strings.parse_html(.description).display_text).intentswhere:- .name is 'callback_scam'
all of:
any of
ml.nlu_classifier(.description).topicswhere 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}]'
all of:
not:
- profile.by_sender_email().solicited
not:
- profile.by_sender_email().any_messages_benign
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)
| Field | Match | Value |
|---|---|---|
attachments[].content_type | member | text/calendar |
attachments[].content_type | member | application/ics |
ml.nlu_classifier(file.explode(attachments[])[].scan.ics.calendars[].components[].summary).intents[].name | equals | callback_scam |
ml.nlu_classifier(file.explode(attachments[])[].scan.ics.calendars[].components[].summary).intents[].confidence | equals | high |
ml.nlu_classifier(file.explode(attachments[])[].scan.ics.calendars[].components[].description).intents[].name | equals | callback_scam |
ml.nlu_classifier(strings.parse_html(file.explode(attachments[])[].scan.ics.calendars[].components[].description).display_text).intents[].name | equals | callback_scam |
ml.nlu_classifier(file.explode(attachments[])[].scan.ics.calendars[].components[].description).topics[].name | equals | Request to View Invoice |
ml.nlu_classifier(file.explode(attachments[])[].scan.ics.calendars[].components[].description).topics[].confidence | equals | high |
regex.contains | regex | [\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.
| Field | Kind | Values | Search |
|---|---|---|---|
type.inbound | eq |
| field:"type.inbound" kind:eq value:"true" |
Callback phishing via DocuSign comment
#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).
| Category | Values |
|---|---|
| Attack types | Callback Phishing |
| Tactics and techniques | Evasion, Impersonation: Brand, Out of band pivot, Social engineering |
Telemetry coverage
| Platform | Record / event type |
|---|---|
| Sublime | Inbound email message |
Message attributes
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.
- inbound message
- length(attachments) is 0
- sender.email.domain.root_domain is 'docusign.net'
any of:
- headers.auth_summary.spf.pass
- headers.auth_summary.dmarc.pass
any of
ml.logo_detect(file.message_screenshot()).brandswhere:- .name is 'DocuSign'
- 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**help line**receipt**invoice**call**cancel**renew**refund*
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)
| Field | Match | Value |
|---|---|---|
sender.email.domain.root_domain | equals | docusign.net |
ml.logo_detect(file.message_screenshot()).brands[].name | equals | DocuSign |
regex.icontains | regex | mcafee|n[o0]rt[o0]n|geek.{0,5}squad|paypal|ebay|symantec|best buy|lifel[o0]ck |
strings.ilike | substring | *purchase* |
strings.ilike | substring | *payment* |
strings.ilike | substring | *transaction* |
strings.ilike | substring | *subscription* |
strings.ilike | substring | *antivirus* |
strings.ilike | substring | *order* |
strings.ilike | substring | *support* |
strings.ilike | substring | *help line* |
strings.ilike | substring | *receipt* |
7 more
strings.ilike | substring | *invoice* |
strings.ilike | substring | *call* |
strings.ilike | substring | *cancel* |
strings.ilike | substring | *renew* |
strings.ilike | substring | *refund* |
regex.icontains | regex | \+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4} |
regex.icontains | regex | \+?([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.
| Field | Kind | Values | Search |
|---|---|---|---|
body.current_thread.text | regex_match |
| field:"body.current_thread.text" kind:regex_match |
body.current_thread.text | wildcard |
| field:"body.current_thread.text" kind:wildcard |
headers.auth_summary.dmarc.pass | eq |
| field:"headers.auth_summary.dmarc.pass" kind:eq value:"true" |
headers.auth_summary.spf.pass | eq |
| field:"headers.auth_summary.spf.pass" kind:eq value:"true" |
sender.email.domain.root_domain | eq |
| field:"sender.email.domain.root_domain" kind:eq value:"docusign.net" |
type.inbound | eq |
| field:"type.inbound" kind:eq value:"true" |
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.
Threat classification
Sublime's own taxonomy (not MITRE ATT&CK).
| Category | Values |
|---|---|
| Attack types | Callback Phishing |
| Tactics and techniques | Free email provider, Impersonation: Brand, Social engineering |
Telemetry coverage
| Platform | Record / event type |
|---|---|
| Sublime | Inbound email message |
Message attributes
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.
- inbound message
- length(attachments) is 0
any of
headers.reply_towhere:- .email.domain.root_domain in $free_email_providers
any of
beta.ml_topic(body.current_thread.text).topicswhere:- .name is 'E-Signature'
any of:
- headers.auth_summary.spf.pass
- headers.auth_summary.dmarc.pass
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()).brandswhere:- .name in ('PayPal', 'Norton', 'GeekSquad', 'Ebay', 'McAfee', 'AT&T', 'Microsoft')
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)
| Field | Match | Value |
|---|---|---|
beta.ml_topic(body.current_thread.text).topics[].name | equals | E-Signature |
regex.icontains | regex | (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[].name | member | PayPal |
ml.logo_detect(file.message_screenshot()).brands[].name | member | Norton |
ml.logo_detect(file.message_screenshot()).brands[].name | member | GeekSquad |
ml.logo_detect(file.message_screenshot()).brands[].name | member | Ebay |
ml.logo_detect(file.message_screenshot()).brands[].name | member | McAfee |
ml.logo_detect(file.message_screenshot()).brands[].name | member | AT&T |
ml.logo_detect(file.message_screenshot()).brands[].name | member | Microsoft |
strings.icontains | substring | purchase |
strings.icontains | substring | payment |
strings.icontains | substring | transaction |
21 more
strings.icontains | substring | subscription |
strings.icontains | substring | antivirus |
strings.icontains | substring | order |
strings.icontains | substring | support |
strings.icontains | substring | help line |
strings.icontains | substring | receipt |
strings.icontains | substring | invoice |
strings.icontains | substring | call |
strings.icontains | substring | cancel |
strings.icontains | substring | renew |
strings.icontains | substring | refund |
regex.icontains | regex | (?:reach|contact) us at |
strings.icontains | substring | +1 |
strings.icontains | substring | amount |
strings.icontains | substring | charged |
strings.icontains | substring | crypto |
strings.icontains | substring | wallet address |
regex.icontains | regex | \$\d{3}\.\d{2}\b |
regex.icontains | regex | \+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4} |
regex.icontains | regex | \+?([ilo0-9]{1,2})?\s?\(?\d{3}\)?[\s\.\-⋅]{0,5}[ilo0-9]{3}[\s\.\-⋅]{0,5}[ilo0-9]{4} |
strings.icontains | substring | helpdesk |
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.
| Field | Kind | Values | Search |
|---|---|---|---|
beta.ocr(file.message_screenshot()).text | contains |
| field:"beta.ocr(file.message_screenshot()).text" kind:contains |
beta.ocr(file.message_screenshot()).text | regex_match |
| field:"beta.ocr(file.message_screenshot()).text" kind:regex_match |
body.current_thread.text | contains |
| field:"body.current_thread.text" kind:contains |
body.current_thread.text | regex_match |
| field:"body.current_thread.text" kind:regex_match |
headers.auth_summary.dmarc.pass | eq |
| field:"headers.auth_summary.dmarc.pass" kind:eq value:"true" |
headers.auth_summary.spf.pass | eq |
| field:"headers.auth_summary.spf.pass" kind:eq value:"true" |
strings.replace_confusables(body.current_thread.text) | regex_match |
| 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.inbound | eq |
| field:"type.inbound" kind:eq value:"true" |
Callback phishing via extensionless rfc822 attachment
#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).
| Category | Values |
|---|---|
| Attack types | Callback Phishing |
| Tactics and techniques | Impersonation: Brand, Social engineering |
Telemetry coverage
| Platform | Record / event type |
|---|---|
| Sublime | Inbound email message |
Message attributes
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.
- inbound message
any of
attachmentswhere 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
purchasesubscriptionantivirusordersupportreceiptamountchargedinvoicecallcancelrenewrefund+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).intentswhere all hold:- .name in ('callback_scam')
- .confidence is 'high'
- length(body.current_thread.text) < 1500
all of:
not:
- profile.by_sender().solicited
not:
- profile.by_sender().any_messages_benign
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)
| Field | Match | Value |
|---|---|---|
attachments[].file_type | equals | unknown |
attachments[].content_type | equals | message/rfc822 |
attachments[].file_extension | member | eml |
strings.starts_with | prefix | image |
strings.icontains | substring | purchase |
strings.icontains | substring | subscription |
strings.icontains | substring | antivirus |
strings.icontains | substring | order |
strings.icontains | substring | support |
strings.icontains | substring | receipt |
strings.icontains | substring | amount |
strings.icontains | substring | charged |
16 more
strings.icontains | substring | invoice |
strings.icontains | substring | call |
strings.icontains | substring | cancel |
strings.icontains | substring | renew |
strings.icontains | substring | refund |
strings.icontains | substring | +1 |
strings.ilike | substring | *geek*squad* |
strings.ilike | substring | *lifelock* |
strings.ilike | substring | *best buy* |
strings.ilike | substring | *mcafee* |
strings.ilike | substring | *norton* |
strings.ilike | substring | *ebay* |
strings.ilike | substring | *paypal* |
strings.ilike | substring | *secure anywhere* |
ml.nlu_classifier(file.explode(attachments[])[].scan.ocr.raw).intents[].name | member | callback_scam |
ml.nlu_classifier(file.explode(attachments[])[].scan.ocr.raw).intents[].confidence | equals | high |
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.
| Field | Kind | Values | Search |
|---|---|---|---|
type.inbound | eq |
| field:"type.inbound" kind:eq value:"true" |
Callback phishing via Google Group abuse
#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).
| Category | Values |
|---|---|
| Attack types | Callback Phishing |
| Tactics and techniques | Free email provider, Impersonation: Brand, Social engineering |
Telemetry coverage
| Platform | Record / event type |
|---|---|
| Sublime | Inbound email message |
Message attributes
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.
- inbound message
- length(attachments) < 5
- sender.email.domain.domain is 'googlegroups.com'
any of:
any of
attachmentswhere 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.fieldswhere 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).intentswhere all hold:- .name is 'callback_scam'
- .confidence is 'high'
any of
ml.nlu_classifier(body.current_thread.text).intentswhere all hold:- .name in ('callback_scam')
- .confidence is 'high'
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)
| Field | Match | Value |
|---|---|---|
sender.email.domain.domain | equals | googlegroups.com |
attachments[].file_type | equals | pdf |
ml.nlu_classifier(file.explode(attachments[])[].scan.ocr.raw).intents[].name | equals | callback_scam |
ml.nlu_classifier(file.explode(attachments[])[].scan.ocr.raw).intents[].confidence | equals | high |
ml.nlu_classifier(body.current_thread.text).intents[].name | member | callback_scam |
ml.nlu_classifier(body.current_thread.text).intents[].confidence | equals | high |
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.
| Field | Kind | Values | Search |
|---|---|---|---|
sender.email.domain.domain | eq |
| field:"sender.email.domain.domain" kind:eq value:"googlegroups.com" |
type.inbound | eq |
| field:"type.inbound" kind:eq value:"true" |
Callback phishing via Google Meet
#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).
| Category | Values |
|---|---|
| Attack types | Callback Phishing |
| Tactics and techniques | Out of band pivot |
Telemetry coverage
| Platform | Record / event type |
|---|---|
| Sublime | Inbound email message |
Message attributes
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.
- inbound message
- length(attachments) is 2
all of
attachmentswhere any holds:- .content_type is 'text/calendar'
- .file_extension is 'ics'
- subject.base starts with 'Invitation:'
any of
body.linkswhere all hold:- .display_text is 'Join with Google Meet'
- .href_url.domain.domain is 'meet.google.com'
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)
| Field | Match | Value |
|---|---|---|
attachments[].content_type | equals | text/calendar |
attachments[].file_extension | equals | ics |
strings.starts_with | prefix | Invitation: |
body.links[].display_text | equals | Join with Google Meet |
body.links[].href_url.domain.domain | equals | meet.google.com |
regex.icontains | regex | (?:mcafee|norton|geek.{0,5}squad|paypal|ebay|symantec|best buy|lifelock|apple) |
strings.ilike | substring | *purchase* |
strings.ilike | substring | *payment* |
strings.ilike | substring | *transaction* |
strings.ilike | substring | *subscription* |
strings.ilike | substring | *antivirus* |
strings.ilike | substring | *order* |
9 more
strings.ilike | substring | *support* |
strings.ilike | substring | *help line* |
strings.ilike | substring | *receipt* |
strings.ilike | substring | *invoice* |
strings.ilike | substring | *call* |
strings.ilike | substring | *cancel* |
strings.ilike | substring | *renew* |
strings.ilike | substring | *refund* |
regex.icontains | regex | \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.
| Field | Kind | Values | Search |
|---|---|---|---|
body.current_thread.text | regex_match |
| 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.text | wildcard |
| field:"body.current_thread.text" kind:wildcard |
subject.base | starts_with |
| field:"subject.base" kind:starts_with value:"Invitation:" |
type.inbound | eq |
| field:"type.inbound" kind:eq value:"true" |
Callback phishing via Intuit service abuse
#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).
| Category | Values |
|---|---|
| Attack types | Callback Phishing |
| Tactics and techniques | Evasion, Free email provider, Impersonation: Brand, Social engineering |
Telemetry coverage
| Platform | Record / event type |
|---|---|
| Sublime | Inbound email message |
Message attributes
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.
- inbound message
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
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
attachmentswhere:- .file_extension is 'pdf'
any of
attachmentswhere 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 squadlifelockbest buymcafeenortonebaypaypal
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(.).brandswhere:- .name in ('PayPal', 'Norton', 'GeekSquad', 'Ebay')
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)
| Field | Match | Value |
|---|---|---|
sender.email.domain.root_domain | member | intuit.com |
sender.email.domain.root_domain | member | intuit.co.uk |
regex.icontains | regex | mcafee|norton|geek.{0,5}squad|paypal|ebay|symantec|best buy|lifelock |
strings.ilike | substring | *purchase* |
strings.ilike | substring | *payment* |
strings.ilike | substring | *transaction* |
strings.ilike | substring | *subscription* |
strings.ilike | substring | *antivirus* |
strings.ilike | substring | *order* |
strings.ilike | substring | *support* |
strings.ilike | substring | *help line* |
strings.ilike | substring | *receipt* |
48 more
strings.ilike | substring | *invoice* |
strings.ilike | substring | *call* |
strings.ilike | substring | *cancel* |
strings.ilike | substring | *renew* |
strings.ilike | substring | *refund* |
regex.icontains | regex | \b\+?(\d{1}.)?\(?\d{3}?\)?.\d{3}.?\d{4}\b |
regex.icontains | regex | (?:Sold|Bill)[\s\xa0]To(?:\:\s+|\n)[^\n]+\+?(\d{1}.)?\(?\d{3}?\)?.\d{3}.?\d{4}.*\n |
regex.icontains | regex | (?:Sold|Bill)[\s\xa0]To(?:\:\s+|\n)[^\n]+\+\d{1,3}[ilo0-9]{10}.*\n |
regex.icontains | regex | (?:Sold|Bill)[\s\xa0]To(?:\:\s+|\n)[^\n]+[ilo0-9]{3}\.[ilo0-9]{3}\.[ilo0-9]{4}.*\n |
regex.icontains | regex | (?:Sold|Bill)[\s\xa0]To(?:\:\s+|\n)[^\n]+[ilo0-9]{3}-[ilo0-9]{3}-[ilo0-9]{4}.*\n |
regex.icontains | regex | (?:Sold|Bill)[\s\xa0]To(?:\:\s+|\n)[^\n]+\([ilo0-9]{3}\)[\s-]+[ilo0-9]{3}[\s-]+[ilo0-9]{4}.*\n |
regex.icontains | regex | (?:Sold|Bill)[\s\xa0]To(?:\:\s+|\n)[^\n]+\([ilo0-9]{3}\)-[ilo0-9]{3}-[ilo0-9]{4}.*\n |
regex.icontains | regex | (?:Sold|Bill)[\s\xa0]To(?:\:\s+|\n)[^\n]+1\s?[ilo0-9]{3} [ilo0-9]{3} [ilo0-9]{4}.*\n |
regex.icontains | regex | (?:Sold|Bill)[\s\xa0]To(?:\:\s+|\n)[^\n]+8\d{9}.*\n |
regex.icontains | regex | \+1 |
attachments[].file_extension | equals | pdf |
strings.icontains | substring | purchase |
strings.icontains | substring | payment |
strings.icontains | substring | transaction |
strings.icontains | substring | subscription |
strings.icontains | substring | antivirus |
strings.icontains | substring | order |
strings.icontains | substring | support |
strings.icontains | substring | help line |
strings.icontains | substring | receipt |
strings.icontains | substring | invoice |
strings.icontains | substring | call |
strings.icontains | substring | helpdesk |
strings.icontains | substring | cancel |
strings.icontains | substring | renew |
strings.icontains | substring | refund |
strings.icontains | substring | amount |
strings.icontains | substring | crypto |
strings.icontains | substring | wallet address |
regex.icontains | regex | \$\d{3}\.\d{2}\b |
regex.icontains | regex | (\+\d|1.(\()?\d{3}(\))?\D\d{3}\D\d{4}) |
regex.icontains | regex | \+?(\d{1,2})?\s?\(?\d{3}\)?[\s\.\-⋅]{0,5}\d{3}[\s\.\-⋅]{0,5}\d{4} |
strings.icontains | substring | geek squad |
strings.icontains | substring | lifelock |
strings.icontains | substring | best buy |
strings.icontains | substring | mcafee |
strings.icontains | substring | norton |
strings.icontains | substring | ebay |
strings.icontains | substring | paypal |
ml.logo_detect(attachments[]).brands[].name | member | PayPal |
ml.logo_detect(attachments[]).brands[].name | member | Norton |
ml.logo_detect(attachments[]).brands[].name | member | GeekSquad |
ml.logo_detect(attachments[]).brands[].name | member | Ebay |
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.
| Field | Kind | Values | Search |
|---|---|---|---|
body.current_thread.text | wildcard |
| field:"body.current_thread.text" kind:wildcard |
headers.auth_summary.dmarc.pass | eq |
| field:"headers.auth_summary.dmarc.pass" kind:eq value:"true" |
headers.auth_summary.spf.pass | eq |
| field:"headers.auth_summary.spf.pass" kind:eq value:"true" |
sender.email.domain.root_domain | in |
| field:"sender.email.domain.root_domain" kind:in |
strings.replace_confusables(body.current_thread.text) | regex_match |
| field:"strings.replace_confusables(body.current_thread.text)" kind:regex_match |
strings.replace_confusables(body.html.inner_text) | regex_match |
| field:"strings.replace_confusables(body.html.inner_text)" kind:regex_match |
type.inbound | eq |
| field:"type.inbound" kind:eq value:"true" |
Callback phishing via Microsoft comment
#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).
| Category | Values |
|---|---|
| Attack types | Callback Phishing |
| Tactics and techniques | Impersonation: Brand, Out of band pivot, Social engineering |
Telemetry coverage
| Platform | Record / event type |
|---|---|
| Sublime | Inbound email message |
Message attributes
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.
- inbound message
- length(attachments) is 0
- length(body.current_thread.text) < 1750
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).intentswhere 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)
| Field | Match | Value |
|---|---|---|
sender.email.domain.root_domain | member | microsoftonline.com |
sender.email.email | equals | invites@microsoft.com |
ml.nlu_classifier(body.current_thread.text).intents[].name | member | callback_scam |
ml.nlu_classifier(body.current_thread.text).intents[].name | member | cred_theft |
ml.nlu_classifier(body.current_thread.text).intents[].confidence | member | medium |
ml.nlu_classifier(body.current_thread.text).intents[].confidence | member | high |
strings.ilike | substring | *purchase* |
strings.ilike | substring | *payment* |
strings.ilike | substring | *transaction* |
strings.ilike | substring | *subscription* |
strings.ilike | substring | *antivirus* |
strings.ilike | substring | *order* |
12 more
strings.ilike | substring | *support* |
strings.ilike | substring | *help line* |
strings.ilike | substring | *receipt* |
strings.ilike | substring | *invoice* |
strings.ilike | substring | *call* |
strings.ilike | substring | *cancel* |
strings.ilike | substring | *renew* |
strings.ilike | substring | *refund* |
regex.count | regex | [^\x00-\x7F] |
regex.icontains | regex | \+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4} |
regex.icontains | regex | \+?([ilo0-9]{1,2})?\s?\(?\d{3}\)?[\s\.\-⋅]{0,5}[ilo0-9]{3}[\s\.\-⋅]{0,5}[ilo0-9]{4} |
regex.icontains | regex | \(?[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.
| Field | Kind | Values | Search |
|---|---|---|---|
body.current_thread.text | wildcard |
| field:"body.current_thread.text" kind:wildcard |
sender.email.domain.root_domain | in |
| field:"sender.email.domain.root_domain" kind:in value:"microsoftonline.com" |
sender.email.email | eq |
| field:"sender.email.email" kind:eq value:"invites@microsoft.com" |
type.inbound | eq |
| field:"type.inbound" kind:eq value:"true" |
Callback Phishing via Signable E-Signature Request
#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).
| Category | Values |
|---|---|
| Attack types | Callback Phishing |
| Tactics and techniques | Exploit, Impersonation: Brand, Out of band pivot, Social engineering |
Telemetry coverage
| Platform | Record / event type |
|---|---|
| Sublime | Inbound email message |
Message attributes
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.
- inbound message
- length(attachments) is 0
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
- sender.email.domain.root_domain is 'signable.app'
any of:
- headers.auth_summary.spf.pass
- headers.auth_summary.dmarc.pass
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()).brandswhere:- .name in ('PayPal', 'Norton', 'GeekSquad', 'Ebay', 'McAfee', 'AT&T', 'Microsoft')
- length(body.current_thread.text) < 1750
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)
| Field | Match | Value |
|---|---|---|
sender.email.domain.root_domain | equals | signable.app |
regex.icontains | regex | (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[].name | member | PayPal |
ml.logo_detect(file.message_screenshot()).brands[].name | member | Norton |
ml.logo_detect(file.message_screenshot()).brands[].name | member | GeekSquad |
ml.logo_detect(file.message_screenshot()).brands[].name | member | Ebay |
ml.logo_detect(file.message_screenshot()).brands[].name | member | McAfee |
ml.logo_detect(file.message_screenshot()).brands[].name | member | AT&T |
ml.logo_detect(file.message_screenshot()).brands[].name | member | Microsoft |
strings.icontains | substring | purchase |
strings.icontains | substring | payment |
strings.icontains | substring | transaction |
21 more
strings.icontains | substring | subscription |
strings.icontains | substring | antivirus |
strings.icontains | substring | order |
strings.icontains | substring | support |
strings.icontains | substring | help line |
strings.icontains | substring | receipt |
strings.icontains | substring | invoice |
strings.icontains | substring | call |
strings.icontains | substring | cancel |
strings.icontains | substring | renew |
strings.icontains | substring | refund |
regex.icontains | regex | (?:reach|contact) us at |
strings.icontains | substring | +1 |
strings.icontains | substring | amount |
strings.icontains | substring | charged |
strings.icontains | substring | crypto |
strings.icontains | substring | wallet address |
regex.icontains | regex | \$\d{3}\.\d{2}\b |
regex.icontains | regex | \+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4} |
regex.icontains | regex | \+?([ilo0-9]{1,2})?\s?\(?\d{3}\)?[\s\.\-⋅]{0,5}[ilo0-9]{3}[\s\.\-⋅]{0,5}[ilo0-9]{4} |
strings.icontains | substring | helpdesk |
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.
Callback phishing via SignFree e-signature request
#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).
| Category | Values |
|---|---|
| Attack types | Callback Phishing |
| Tactics and techniques | Exploit, Impersonation: Brand, Out of band pivot, Social engineering |
Telemetry coverage
| Platform | Record / event type |
|---|---|
| Sublime | Inbound email message |
Message attributes
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.
- inbound message
- length(attachments) is 0
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
- sender.email.domain.root_domain is 'signfree.io'
any of:
- headers.auth_summary.spf.pass
- headers.auth_summary.dmarc.pass
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()).brandswhere:- .name in ('PayPal', 'Norton', 'GeekSquad', 'Ebay', 'McAfee', 'AT&T', 'Microsoft')
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)
| Field | Match | Value |
|---|---|---|
sender.email.domain.root_domain | equals | signfree.io |
regex.icontains | regex | (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[].name | member | PayPal |
ml.logo_detect(file.message_screenshot()).brands[].name | member | Norton |
ml.logo_detect(file.message_screenshot()).brands[].name | member | GeekSquad |
ml.logo_detect(file.message_screenshot()).brands[].name | member | Ebay |
ml.logo_detect(file.message_screenshot()).brands[].name | member | McAfee |
ml.logo_detect(file.message_screenshot()).brands[].name | member | AT&T |
ml.logo_detect(file.message_screenshot()).brands[].name | member | Microsoft |
strings.icontains | substring | purchase |
strings.icontains | substring | payment |
strings.icontains | substring | transaction |
21 more
strings.icontains | substring | subscription |
strings.icontains | substring | antivirus |
strings.icontains | substring | order |
strings.icontains | substring | support |
strings.icontains | substring | help line |
strings.icontains | substring | receipt |
strings.icontains | substring | invoice |
strings.icontains | substring | call |
strings.icontains | substring | cancel |
strings.icontains | substring | renew |
strings.icontains | substring | refund |
regex.icontains | regex | (?:reach|contact) us at |
strings.icontains | substring | +1 |
strings.icontains | substring | amount |
strings.icontains | substring | charged |
strings.icontains | substring | crypto |
strings.icontains | substring | wallet address |
regex.icontains | regex | \$\d{3}\.\d{2}\b |
regex.icontains | regex | \+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4} |
regex.icontains | regex | \+?([ilo0-9]{1,2})?\s?\(?\d{3}\)?[\s\.\-⋅]{0,5}[ilo0-9]{3}[\s\.\-⋅]{0,5}[ilo0-9]{4} |
strings.icontains | substring | helpdesk |
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.
Callback phishing via Xodo Sign comment
#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).
| Category | Values |
|---|---|
| Attack types | Callback Phishing |
| Tactics and techniques | Exploit, Impersonation: Brand, Out of band pivot, Social engineering |
Telemetry coverage
| Platform | Record / event type |
|---|---|
| Sublime | Inbound email message |
Message attributes
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.
- inbound message
- length(attachments) is 0
any of:
not:
- profile.by_sender().solicited
all of:
- profile.by_sender().any_messages_malicious_or_spam
not:
- profile.by_sender().any_messages_benign
- sender.email.domain.root_domain is 'eversign.com'
any of:
- headers.auth_summary.spf.pass
- headers.auth_summary.dmarc.pass
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()).brandswhere:- .name in ('PayPal', 'Norton', 'GeekSquad', 'Ebay', 'McAfee', 'AT&T')
- length(body.current_thread.text) < 1750
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)
| Field | Match | Value |
|---|---|---|
sender.email.domain.root_domain | equals | eversign.com |
regex.icontains | regex | (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[].name | member | PayPal |
ml.logo_detect(file.message_screenshot()).brands[].name | member | Norton |
ml.logo_detect(file.message_screenshot()).brands[].name | member | GeekSquad |
ml.logo_detect(file.message_screenshot()).brands[].name | member | Ebay |
ml.logo_detect(file.message_screenshot()).brands[].name | member | McAfee |
ml.logo_detect(file.message_screenshot()).brands[].name | member | AT&T |
strings.icontains | substring | purchase |
strings.icontains | substring | payment |
strings.icontains | substring | transaction |
strings.icontains | substring | subscription |
20 more
strings.icontains | substring | antivirus |
strings.icontains | substring | order |
strings.icontains | substring | support |
strings.icontains | substring | help line |
strings.icontains | substring | receipt |
strings.icontains | substring | invoice |
strings.icontains | substring | call |
strings.icontains | substring | cancel |
strings.icontains | substring | renew |
strings.icontains | substring | refund |
regex.icontains | regex | (?:reach|contact) us at |
strings.icontains | substring | +1 |
strings.icontains | substring | amount |
strings.icontains | substring | charged |
strings.icontains | substring | crypto |
strings.icontains | substring | wallet address |
regex.icontains | regex | \$\d{3}\.\d{2}\b |
regex.icontains | regex | \+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4} |
regex.icontains | regex | \+?([ilo0-9]{1,2})?\s?\(?\d{3}\)?[\s\.\-⋅]{0,5}[ilo0-9]{3}[\s\.\-⋅]{0,5}[ilo0-9]{4} |
strings.icontains | substring | helpdesk |
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.
Callback phishing via Yammer comment
#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).
| Category | Values |
|---|---|
| Attack types | Callback Phishing |
| Tactics and techniques | Impersonation: Brand, Out of band pivot, Social engineering |
Telemetry coverage
| Platform | Record / event type |
|---|---|
| Sublime | Inbound email message |
Message attributes
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.
- inbound message
- sender.email.domain.root_domain is 'yammer.com'
- length(body.current_thread.text) < 2000
any of:
any of
ml.nlu_classifier(body.current_thread.text).intentswhere 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*
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}
not:
any of
ml.nlu_classifier(body.current_thread.text).intentswhere 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)
| Field | Match | Value |
|---|---|---|
sender.email.domain.root_domain | equals | yammer.com |
ml.nlu_classifier(body.current_thread.text).intents[].name | member | callback_scam |
ml.nlu_classifier(body.current_thread.text).intents[].confidence | member | medium |
ml.nlu_classifier(body.current_thread.text).intents[].confidence | member | high |
strings.ilike | substring | *purchase* |
strings.ilike | substring | *payment* |
strings.ilike | substring | *transaction* |
strings.ilike | substring | *subscription* |
strings.ilike | substring | *antivirus* |
strings.ilike | substring | *order* |
strings.ilike | substring | *support* |
strings.ilike | substring | *help line* |
8 more
strings.ilike | substring | *receipt* |
strings.ilike | substring | *invoice* |
strings.ilike | substring | *call* |
strings.ilike | substring | *cancel* |
strings.ilike | substring | *renew* |
strings.ilike | substring | *refund* |
regex.icontains | regex | \+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4} |
regex.icontains | regex | \+?([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.
| Field | Kind | Excluded values | Search |
|---|---|---|---|
ml.nlu_classifier(body.current_thread.text).intents | array_any | excludes:ml.nlu_classifier(body.current_thread.text).intents |
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
body.current_thread.text | wildcard |
| field:"body.current_thread.text" kind:wildcard |
sender.email.domain.root_domain | eq |
| field:"sender.email.domain.root_domain" kind:eq value:"yammer.com" |
type.inbound | eq |
| field:"type.inbound" kind:eq value:"true" |
Callback phishing via Zelle Service Abuse
#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).
| Category | Values |
|---|---|
| Attack types | BEC/Fraud, Callback Phishing |
| Tactics and techniques | Evasion, Social engineering |
Telemetry coverage
| Platform | Record / event type |
|---|---|
| Sublime | Inbound email message |
Message attributes
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.
- inbound message
- length(attachments) is 0
- sender.email.domain.root_domain in ('zellepay.com')
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]'
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).intentswhere:- .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)
| Field | Match | Value |
|---|---|---|
sender.email.domain.root_domain | member | zellepay.com |
strings.ilike | substring | * requested* |
regex.icontains | regex | .*\+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4}.* |
regex.icontains | regex | .*\+[ilo0-9]{1,3}[ilo0-9]{10}.* |
regex.icontains | regex | .*[ilo0-9]{3}\.[ilo0-9]{3}\.[ilo0-9]{4}.* |
regex.icontains | regex | .*[ilo0-9]{3}-[ilo0-9]{3}-[ilo0-9]{4}.* |
regex.icontains | regex | .*\([ilo0-9]{3}\)[\s-]+[ilo0-9]{3}[\s-]+[ilo0-9]{4}.* |
regex.icontains | regex | .*\([ilo0-9]{3}\)-[ilo0-9]{3}-[ilo0-9]{4}.* |
regex.icontains | regex | .*8[ilo0-9]{9}.* |
regex.icontains | regex | \+[1li] |
regex.icontains | regex | \".*\+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4}.*\" |
regex.icontains | regex | \".*\+[ilo0-9]{1,3}[ilo0-9]{10}.*\" |
46 more
regex.icontains | regex | \".*[ilo0-9]{3}\.[ilo0-9]{3}\.[ilo0-9]{4}.*\" |
regex.icontains | regex | \".*[ilo0-9]{3}-[ilo0-9]{3}-[ilo0-9]{4}.*\" |
regex.icontains | regex | \".*\([ilo0-9]{3}\)\s[ilo0-9]{3}-[ilo0-9]{4}.*\" |
regex.icontains | regex | \".*\([ilo0-9]{3}\)-[ilo0-9]{3}-[ilo0-9]{4}.*\" |
regex.icontains | regex | \".*8[ilo0-9]{9}.*\" |
regex.icontains | regex | \".*\+[1li].*\" |
strings.ilike | substring | *"*you did not*"* |
strings.ilike | substring | *"*is not for*"* |
strings.ilike | substring | *"*done by you*"* |
regex.icontains | regex | \".*didn\'t ma[kd]e this.*\" |
strings.ilike | substring | *"*Fruad Alert*"* |
strings.ilike | substring | *"*Fraud Alert*"* |
strings.ilike | substring | *"*fraudulent*"* |
strings.ilike | substring | *"*Zelle*"* |
strings.ilike | substring | *"*subscription*"* |
strings.ilike | substring | *"*antivirus*"* |
strings.ilike | substring | *"*order*"* |
strings.ilike | substring | *"*support*"* |
strings.ilike | substring | *"*sincerely apologize*"* |
strings.ilike | substring | *"*receipt*"* |
strings.ilike | substring | *"*invoice*"* |
strings.ilike | substring | *"*Purchase*"* |
strings.ilike | substring | *"*transaction*"* |
strings.ilike | substring | *"*Market*Value*"* |
strings.ilike | substring | *"*BTC*"* |
strings.ilike | substring | *"*call*"* |
strings.ilike | substring | *"*get in touch with our*"* |
strings.ilike | substring | *"*quickly inform*"* |
strings.ilike | substring | *"*quickly reach*"* |
strings.ilike | substring | *"*detected unusual transactions* |
strings.ilike | substring | *"*without your authorization*"* |
strings.ilike | substring | *"*cancel*"* |
strings.ilike | substring | *"*renew*"* |
strings.ilike | substring | *"*refund*"* |
strings.ilike | substring | *"*+1*"* |
regex.icontains | regex | \"help.{0,3}desk |
strings.ilike | substring | *"* your funds*"* |
strings.ilike | substring | *"* your checking*"* |
strings.ilike | substring | *"* your saving*"* |
strings.ilike | substring | *"*transfer*"* |
strings.ilike | substring | *"*secure your account*"* |
strings.ilike | substring | *"*recover your *"* |
regex.icontains | regex | note from.{0,50}(?:call|reach|contact|paypal) |
ml.nlu_classifier(body.current_thread.text).intents[].name | equals | callback_scam |
regex.icontains | regex | \+𝟭|𝗽𝗮𝘆𝗺𝗲𝗻𝘁|𝗛𝗲𝗹𝗽 𝗗𝗲𝘀𝗸|𝗿𝗲𝗳𝘂𝗻𝗱|𝗮𝗻𝘁𝗶𝘃𝗶𝗿𝘂𝘀|𝗰𝗮𝗹𝗹|𝗰𝗮𝗻𝗰𝗲𝗹 |
strings.ilike | substring | *"*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.
| Field | Kind | Values | Search |
|---|---|---|---|
body.current_thread.text | regex_match |
| field:"body.current_thread.text" kind:regex_match value:"note from.{0,50}(?:call|reach|contact|paypal)" |
body.html.display_text | wildcard |
| field:"body.html.display_text" kind:wildcard value:"* requested*" |
body.html.inner_text | regex_match |
| field:"body.html.inner_text" kind:regex_match |
body.html.inner_text | wildcard |
| field:"body.html.inner_text" kind:wildcard |
sender.email.domain.root_domain | in |
| field:"sender.email.domain.root_domain" kind:in value:"zellepay.com" |
strings.replace_confusables(body.current_thread.text) | regex_match |
| field:"strings.replace_confusables(body.current_thread.text)" kind:regex_match |
strings.replace_confusables(subject.subject) | regex_match |
| field:"strings.replace_confusables(subject.subject)" kind:regex_match |
type.inbound | eq |
| field:"type.inbound" kind:eq value:"true" |
Callback phishing via Zoho service abuse
#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).
| Category | Values |
|---|---|
| Attack types | Callback Phishing |
| Tactics and techniques | Evasion, Free email provider, Impersonation: Brand, Social engineering |
Telemetry coverage
| Platform | Record / event type |
|---|---|
| Sublime | Inbound email message |
Message attributes
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.
- inbound message
all of:
- sender.email.domain.root_domain in ('zohoinvoice.com')
any of:
- headers.auth_summary.spf.pass
- headers.auth_summary.dmarc.pass
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
attachmentswhere:- .file_extension is 'pdf'
any of
attachmentswhere 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 squadlifelockbest buymcafeenortonebaypaypal
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(.).brandswhere:- .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)
| Field | Match | Value |
|---|---|---|
sender.email.domain.root_domain | member | zohoinvoice.com |
regex.icontains | regex | mcafee|norton|geek.{0,5}squad|paypal|ebay|symantec|best buy|lifelock |
strings.ilike | substring | *purchase* |
strings.ilike | substring | *payment* |
strings.ilike | substring | *transaction* |
strings.ilike | substring | *subscription* |
strings.ilike | substring | *antivirus* |
strings.ilike | substring | *order* |
strings.ilike | substring | *support* |
strings.ilike | substring | *help line* |
strings.ilike | substring | *receipt* |
strings.ilike | substring | *invoice* |
38 more
strings.ilike | substring | *call* |
strings.ilike | substring | *cancel* |
strings.ilike | substring | *renew* |
strings.ilike | substring | *refund* |
regex.icontains | regex | \b\+?(\d{1}.)?\(?\d{3}?\)?.\d{3}.?\d{4}\b |
attachments[].file_extension | equals | pdf |
strings.icontains | substring | purchase |
strings.icontains | substring | payment |
strings.icontains | substring | transaction |
strings.icontains | substring | subscription |
strings.icontains | substring | antivirus |
strings.icontains | substring | order |
strings.icontains | substring | support |
strings.icontains | substring | help line |
strings.icontains | substring | receipt |
strings.icontains | substring | invoice |
strings.icontains | substring | call |
strings.icontains | substring | helpdesk |
strings.icontains | substring | cancel |
strings.icontains | substring | renew |
strings.icontains | substring | refund |
strings.icontains | substring | amount |
strings.icontains | substring | crypto |
strings.icontains | substring | wallet address |
regex.icontains | regex | \$\d{3}\.\d{2}\b |
regex.icontains | regex | (\+\d|1.(\()?\d{3}(\))?\D\d{3}\D\d{4}) |
regex.icontains | regex | \+?(\d{1,2})?\s?\(?\d{3}\)?[\s\.\-⋅]{0,5}\d{3}[\s\.\-⋅]{0,5}\d{4} |
strings.icontains | substring | geek squad |
strings.icontains | substring | lifelock |
strings.icontains | substring | best buy |
strings.icontains | substring | mcafee |
strings.icontains | substring | norton |
strings.icontains | substring | ebay |
strings.icontains | substring | paypal |
ml.logo_detect(attachments[]).brands[].name | member | PayPal |
ml.logo_detect(attachments[]).brands[].name | member | Norton |
ml.logo_detect(attachments[]).brands[].name | member | GeekSquad |
ml.logo_detect(attachments[]).brands[].name | member | Ebay |
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.
| Field | Kind | Values | Search |
|---|---|---|---|
body.current_thread.text | regex_match |
| field:"body.current_thread.text" kind:regex_match |
body.current_thread.text | wildcard |
| field:"body.current_thread.text" kind:wildcard |
headers.auth_summary.dmarc.pass | eq |
| field:"headers.auth_summary.dmarc.pass" kind:eq value:"true" |
headers.auth_summary.spf.pass | eq |
| field:"headers.auth_summary.spf.pass" kind:eq value:"true" |
sender.email.domain.root_domain | in |
| field:"sender.email.domain.root_domain" kind:in value:"zohoinvoice.com" |
type.inbound | eq |
| field:"type.inbound" kind:eq value:"true" |
Callback Phishing via Zoom comment
#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).
| Category | Values |
|---|---|
| Attack types | Callback Phishing |
| Tactics and techniques | Out of band pivot, Social engineering, Impersonation: Brand |
Telemetry coverage
| Platform | Record / event type |
|---|---|
| Sublime | Inbound email message |
Message attributes
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.
- inbound message
- length(attachments) is 0
- sender.email.domain.root_domain is 'zoom.us'
any of:
- headers.auth_summary.spf.pass
- headers.auth_summary.dmarc.pass
any of
ml.logo_detect(file.message_screenshot()).brandswhere:- .name is 'Zoom'
- body.current_thread.text matches 'mcafee|n[o0]rt[o0]n|geek.{0,5}squad|paypal|ebay|symantec|best buy|lifel[o0]ck'
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).intentswhere all hold:- .name is 'callback_scam'
- .confidence is not 'low'
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}
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)
| Field | Match | Value |
|---|---|---|
sender.email.domain.root_domain | equals | zoom.us |
ml.logo_detect(file.message_screenshot()).brands[].name | equals | Zoom |
regex.icontains | regex | mcafee|n[o0]rt[o0]n|geek.{0,5}squad|paypal|ebay|symantec|best buy|lifel[o0]ck |
strings.ilike | substring | *purchase* |
strings.ilike | substring | *payment* |
strings.ilike | substring | *transaction* |
strings.ilike | substring | *subscription* |
strings.ilike | substring | *antivirus* |
strings.ilike | substring | *order* |
strings.ilike | substring | *support* |
strings.ilike | substring | *help line* |
strings.ilike | substring | *receipt* |
9 more
strings.ilike | substring | *invoice* |
strings.ilike | substring | *call* |
strings.ilike | substring | *cancel* |
strings.ilike | substring | *renew* |
strings.ilike | substring | *refund* |
strings.ilike | substring | *host key* |
ml.nlu_classifier(body.current_thread.text).intents[].name | equals | callback_scam |
regex.icontains | regex | \+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4} |
regex.icontains | regex | \+?([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.
| Field | Kind | Excluded values | Search |
|---|---|---|---|
body.current_thread.text | contains | Meeting summary | excludes:body.current_thread.text field:"body.current_thread.text" value:"Meeting summary" |
headers.auth_summary.dmarc.pass | eq | true | excludes:headers.auth_summary.dmarc.pass field:"headers.auth_summary.dmarc.pass" value:"true" |
sender.email.email | eq | no-reply@zoom.us | excludes:sender.email.email field:"sender.email.email" value:"no-reply@zoom.us" |
subject.subject | contains | Meeting assets | excludes:subject.subject field:"subject.subject" value:"Meeting assets" |
sender.display_name | eq | Meeting Summary with AI Companion | excludes:sender.display_name field:"sender.display_name" value:"Meeting Summary with AI Companion" |
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
body.current_thread.text | regex_match |
| field:"body.current_thread.text" kind:regex_match |
body.current_thread.text | wildcard |
| field:"body.current_thread.text" kind:wildcard |
headers.auth_summary.dmarc.pass | eq |
| field:"headers.auth_summary.dmarc.pass" kind:eq value:"true" |
headers.auth_summary.spf.pass | eq |
| field:"headers.auth_summary.spf.pass" kind:eq value:"true" |
sender.email.domain.root_domain | eq |
| field:"sender.email.domain.root_domain" kind:eq value:"zoom.us" |
type.inbound | eq |
| field:"type.inbound" kind:eq value:"true" |
Callback phishing: AOL senders with suspicious HTML template or PDF attachment
#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).
| Category | Values |
|---|---|
| Attack types | Callback Phishing |
| Tactics and techniques | Free email provider, Social engineering |
Telemetry coverage
| Platform | Record / event type |
|---|---|
| Sublime | Inbound email message |
Message attributes
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.
- inbound message
- sender.email.domain.root_domain is 'aol.com'
- length(recipients.to) is 1
- length(recipients.cc) is 0
- length(recipients.bcc) is 0
- headers.in_reply_to is missing
- length(headers.references) is 1
- headers.message_id ends with '@mail.yahoo.com>'
- headers.mailer ends with 'AolMailNorrin'
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
attachmentswhere 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)
| Field | Match | Value |
|---|---|---|
sender.email.domain.root_domain | equals | aol.com |
strings.iends_with | suffix | @mail.yahoo.com> |
strings.ends_with | suffix | AolMailNorrin |
strings.icontains | substring | <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.icontains | substring | <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.icontains | substring | <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.icontains | substring | <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_type | equals | pdf |
attachments[].content_id | equals | <@yahoo.com> |
attachments[].content_id | equals | @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.
| Field | Kind | Values | Search |
|---|---|---|---|
body.html.raw | contains |
| field:"body.html.raw" kind:contains |
headers.in_reply_to | is_null | field:"headers.in_reply_to" kind:is_null | |
headers.mailer | ends_with |
| field:"headers.mailer" kind:ends_with value:"AolMailNorrin" |
headers.message_id | ends_with |
| field:"headers.message_id" kind:ends_with value:"@mail.yahoo.com>" |
sender.email.domain.root_domain | eq |
| field:"sender.email.domain.root_domain" kind:eq value:"aol.com" |
type.inbound | eq |
| field:"type.inbound" kind:eq value:"true" |
Callback phishing: Branded invoice from sender/reply-to domain less than 30 days old
#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).
| Category | Values |
|---|---|
| Attack types | Callback Phishing |
| Tactics and techniques | Impersonation: Brand, Out of band pivot, Social engineering |
Telemetry coverage
| Platform | Record / event type |
|---|---|
| Sublime | Inbound email message |
Message attributes
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.
- inbound message
any of:
all of:
- length(headers.reply_to) > 0
all of
headers.reply_towhere 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
any of
ml.nlu_classifier(body.current_thread.text).tagswhere all hold:- .name is 'invoice'
- .confidence is 'high'
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()).brandswhere:- .name in ('PayPal', 'Norton', 'GeekSquad', 'Ebay')
at least 1 of 8: beta.ocr(file.message_screenshot()).text contains any of 8 patterns
geek squadlifelockbest buymcafeenortonebaypaypalvirus
- body.current_thread.text matches '\\+?(\\d{1}.)?\\(?\\d{3}?\\)?.\\d{3}.?\\d{4}'
not:
- profile.by_sender().solicited
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)
| Field | Match | Value |
|---|---|---|
ml.nlu_classifier(body.current_thread.text).tags[].name | equals | invoice |
ml.nlu_classifier(body.current_thread.text).tags[].confidence | equals | high |
strings.ilike | substring | *mcafee* |
strings.ilike | substring | *norton* |
strings.ilike | substring | *geek squad* |
strings.ilike | substring | *paypal* |
strings.ilike | substring | *ebay* |
strings.ilike | substring | *symantec* |
strings.ilike | substring | *best buy* |
strings.ilike | substring | *lifelock* |
strings.ilike | substring | *virus* |
ml.logo_detect(file.message_screenshot()).brands[].name | member | PayPal |
12 more
ml.logo_detect(file.message_screenshot()).brands[].name | member | Norton |
ml.logo_detect(file.message_screenshot()).brands[].name | member | GeekSquad |
ml.logo_detect(file.message_screenshot()).brands[].name | member | Ebay |
strings.icontains | substring | geek squad |
strings.icontains | substring | lifelock |
strings.icontains | substring | best buy |
strings.icontains | substring | mcafee |
strings.icontains | substring | norton |
strings.icontains | substring | ebay |
strings.icontains | substring | paypal |
strings.icontains | substring | virus |
regex.icontains | regex | \+?(\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.
| Field | Kind | Values | Search |
|---|---|---|---|
beta.ocr(file.message_screenshot()).text | contains |
| field:"beta.ocr(file.message_screenshot()).text" kind:contains |
body.current_thread.text | regex_match |
| field:"body.current_thread.text" kind:regex_match value:"+?(\d{1}.)?(?\d{3}?)?.\d{3}.?\d{4}" |
body.current_thread.text | wildcard |
| field:"body.current_thread.text" kind:wildcard |
type.inbound | eq |
| field:"type.inbound" kind:eq value:"true" |
Callback phishing: SumUp infrastructure abuse
#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).
| Category | Values |
|---|---|
| Attack types | BEC/Fraud, Callback Phishing |
| Tactics and techniques | Evasion, Social engineering |
Telemetry coverage
| Platform | Record / event type |
|---|---|
| Sublime | Inbound email message |
Message attributes
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.
- inbound message
- sender.email.domain.root_domain in ('sumup.com')
any of:
- body.html.display_text matches '*delivery note*'
- body.html.display_text matches '*made with sumup*'
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).intentswhere:- .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)
| Field | Match | Value |
|---|---|---|
sender.email.domain.root_domain | member | sumup.com |
strings.ilike | substring | *delivery note* |
strings.ilike | substring | *made with sumup* |
regex.icontains | regex | .*\+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4}.*\n |
regex.icontains | regex | .*\+[ilo0-9]{1,3}[ilo0-9]{10}.*\n |
regex.icontains | regex | .*[ilo0-9]{3}\.[ilo0-9]{3}\.[ilo0-9]{4}.*\n |
regex.icontains | regex | .*[ilo0-9]{3}-[ilo0-9]{3}-[ilo0-9]{4}.*\n |
regex.icontains | regex | .*\([ilo0-9]{3}\)[\s-]+[ilo0-9]{3}[\s-]+[ilo0-9]{4}.*\n |
regex.icontains | regex | .*\([ilo0-9]{3}\)-[ilo0-9]{3}-[ilo0-9]{4}.*\n |
regex.icontains | regex | .*8[ilo0-9]{9}.*\n |
regex.icontains | regex | \+[1l] |
strings.ilike | substring | *you did not* |
44 more
strings.ilike | substring | *is not for* |
strings.ilike | substring | *done by you* |
regex.icontains | regex | didn\'t ma[kd]e this |
strings.ilike | substring | *Fruad Alert* |
strings.ilike | substring | *Fraud Alert* |
strings.ilike | substring | *fraudulent* |
strings.ilike | substring | *using your PayPal* |
strings.ilike | substring | *subscription* |
strings.ilike | substring | *antivirus* |
strings.ilike | substring | *order* |
strings.ilike | substring | *support* |
strings.ilike | substring | *sincerely apologize* |
strings.ilike | substring | *receipt* |
strings.ilike | substring | *invoice* |
strings.ilike | substring | *Purchase* |
strings.ilike | substring | *transaction* |
strings.ilike | substring | *Market*Value* |
strings.ilike | substring | *BTC* |
strings.ilike | substring | *call* |
strings.ilike | substring | *get in touch with our* |
strings.ilike | substring | *quickly inform* |
strings.ilike | substring | *quickly reach * |
strings.ilike | substring | *detected unusual transactions* |
strings.ilike | substring | *without your authorization* |
strings.ilike | substring | *cancel* |
strings.ilike | substring | *renew* |
strings.ilike | substring | *refund* |
strings.ilike | substring | *+1* |
regex.icontains | regex | help.{0,3}desk |
strings.ilike | substring | * your funds* |
strings.ilike | substring | * your checking* |
strings.ilike | substring | * your saving* |
strings.ilike | substring | *transfer* |
strings.ilike | substring | *secure your account* |
strings.ilike | substring | *recover your* |
strings.ilike | substring | *unusual activity* |
strings.ilike | substring | *suspicious transaction* |
strings.ilike | substring | *transaction history* |
strings.ilike | substring | *please ignore this* |
strings.ilike | substring | *report activity* |
regex.icontains | regex | note from.{0,50}(?:call|reach|contact|paypal) |
ml.nlu_classifier(body.current_thread.text).intents[].name | equals | callback_scam |
regex.icontains | regex | \+𝟭|𝗽𝗮𝘆𝗺𝗲𝗻𝘁|𝗛𝗲𝗹𝗽 𝗗𝗲𝘀𝗸|𝗿𝗲𝗳𝘂𝗻𝗱|𝗮𝗻𝘁𝗶𝘃𝗶𝗿𝘂𝘀|𝗰𝗮𝗹𝗹|𝗰𝗮𝗻𝗰𝗲𝗹 |
strings.ilike | substring | *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.
| Field | Kind | Values | Search |
|---|---|---|---|
body.current_thread.text | regex_match |
| field:"body.current_thread.text" kind:regex_match value:"note from.{0,50}(?:call|reach|contact|paypal)" |
body.html.display_text | wildcard |
| field:"body.html.display_text" kind:wildcard |
body.html.inner_text | regex_match |
| field:"body.html.inner_text" kind:regex_match |
body.html.inner_text | wildcard |
| field:"body.html.inner_text" kind:wildcard |
sender.email.domain.root_domain | in |
| field:"sender.email.domain.root_domain" kind:in value:"sumup.com" |
strings.replace_confusables(body.current_thread.text) | regex_match |
| field:"strings.replace_confusables(body.current_thread.text)" kind:regex_match |
type.inbound | eq |
| field:"type.inbound" kind:eq value:"true" |
Callback phishing: Zero-width character obfuscation from freemail sender
#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).
| Category | Values |
|---|---|
| Attack types | Callback Phishing |
| Tactics and techniques | Free email provider, Evasion, Social engineering |
Telemetry coverage
| Platform | Record / event type |
|---|---|
| Sublime | Inbound email message |
Message attributes
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.
- inbound message
- sender.email.domain.root_domain in $free_email_providers
- regex.icount(body.html.raw, '\\x{FEFF}+</[^>]*>[a-z0-9]') ≥ 20
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)
| Field | Match | Value |
|---|---|---|
regex.icount | regex | \x{FEFF}+</[^>]*>[a-z0-9] |
regex.icontains | regex | \+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4} |
regex.icontains | regex | \+?([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.
| Field | Kind | Values | Search |
|---|---|---|---|
body.current_thread.text | regex_match |
| field:"body.current_thread.text" kind:regex_match |
type.inbound | eq |
| field:"type.inbound" kind:eq value:"true" |
Service abuse: Callback phishing via Microsoft Teams invite
#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).
| Category | Values |
|---|---|
| Attack types | Callback Phishing |
| Tactics and techniques | Impersonation: Brand, Out of band pivot, Social engineering |
Telemetry coverage
| Platform | Record / event type |
|---|---|
| Sublime | Inbound email message |
Message attributes
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.
- inbound message
- sender.email.domain.domain is 'teams.mail.microsoft'
any of
body.linkswhere 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'
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)
| Field | Match | Value |
|---|---|---|
sender.email.domain.domain | equals | teams.mail.microsoft |
body.links[].display_text | equals | Open Microsoft Teams |
body.links[].href_url.domain.domain | equals | login.microsoftonline.com |
strings.iends_with | suffix | login.microsoftonline.com |
regex.icontains | regex | mcafee|norton|geek.{0,5}squad|pay.?pal|ebay|symantec|best buy|lifelock|(ms|microsoft|teams).{0,10}premium |
strings.ilike | substring | *purchase* |
strings.ilike | substring | *p?ym?nt* |
strings.ilike | substring | *transaction* |
strings.ilike | substring | *subscription* |
strings.ilike | substring | *antivirus* |
strings.ilike | substring | *order* |
strings.ilike | substring | *support* |
9 more
strings.ilike | substring | *help line* |
strings.ilike | substring | *receipt* |
strings.ilike | substring | *c?ntact* |
strings.ilike | substring | *cancel* |
strings.ilike | substring | *renew* |
strings.ilike | substring | *refund* |
strings.ilike | substring | *billing* |
regex.icontains | regex | [li]nv.[li]ce |
regex.icontains | regex | \+?([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.
| Field | Kind | Values | Search |
|---|---|---|---|
body.current_thread.text | regex_match |
| field:"body.current_thread.text" kind:regex_match value:"[li]nv.[li]ce" |
body.current_thread.text | wildcard |
| field:"body.current_thread.text" kind:wildcard |
sender.email.domain.domain | eq |
| field:"sender.email.domain.domain" kind:eq value:"teams.mail.microsoft" |
strings.replace_confusables(body.current_thread.text) | regex_match |
| field:"strings.replace_confusables(body.current_thread.text)" kind:regex_match |
type.inbound | eq |
| field:"type.inbound" kind:eq value:"true" |