Detection rules › Sublime MQL
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 |
Event coverage
| Message attribute |
|---|
| body.current_thread |
| headers.auth_summary |
| sender.email |
| type |
Rule body MQL
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 (34)
| 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 |
22 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 |
regex.icount | regex | (?:from|to|sent|date|cc|subject): |
regex.icontains | regex | wrote:[\r\n] |