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.
Sublime rule (View on GitHub)
1name: "Callback Phishing via Signable E-Signature Request"
2description: "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."
3type: "rule"
4severity: "high"
5source: |
6 type.inbound
7 and length(attachments) == 0
8 and (
9 not beta.profile.by_reply_to().solicited
10 or (
11 beta.profile.by_reply_to().any_messages_malicious_or_spam
12 and not beta.profile.by_reply_to().any_messages_benign
13 )
14 )
15 // Legitimate Signable sending infratructure
16 and sender.email.domain.root_domain == 'signable.app'
17 and (headers.auth_summary.spf.pass or headers.auth_summary.dmarc.pass)
18 and (
19 // this section is synced with attachment_callback_phish_with_pdf.yml and attachment_callback_phish_with_img.yml
20 regex.icontains(strings.replace_confusables(body.current_thread.text),
21 '(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)'
22 )
23 or any(ml.logo_detect(file.message_screenshot()).brands,
24 .name in (
25 "PayPal",
26 "Norton",
27 "GeekSquad",
28 "Ebay",
29 "McAfee",
30 "AT&T",
31 "Microsoft"
32 )
33 )
34 )
35 and length(body.current_thread.text) < 1750
36 and (
37 (
38 // this seciton is synced with attachment_callback_phish_with_img.yml and attachment_callback_phish_with_pdf.yml
39 // however, the 3 of logic and requiring a phone number is specific to this rule in order to reduce FPs
40 // caused by messages which mention cancelling or otherwise managing a subscription
41 // it is also synced and below for message_screenshot OCR output
42 3 of (
43 strings.icontains(body.current_thread.text, 'purchase'),
44 strings.icontains(body.current_thread.text, 'payment'),
45 strings.icontains(body.current_thread.text, 'transaction'),
46 strings.icontains(body.current_thread.text, 'subscription'),
47 strings.icontains(body.current_thread.text, 'antivirus'),
48 strings.icontains(body.current_thread.text, 'order'),
49 strings.icontains(body.current_thread.text, 'support'),
50 strings.icontains(body.current_thread.text, 'help line'),
51 strings.icontains(body.current_thread.text, 'receipt'),
52 strings.icontains(body.current_thread.text, 'invoice'),
53 strings.icontains(body.current_thread.text, 'call'),
54 strings.icontains(body.current_thread.text, 'cancel'),
55 strings.icontains(body.current_thread.text, 'renew'),
56 strings.icontains(body.current_thread.text, 'refund'),
57 regex.icontains(body.current_thread.text, "(?:reach|contact) us at"),
58 strings.icontains(body.current_thread.text, "+1"),
59 strings.icontains(body.current_thread.text, "amount"),
60 strings.icontains(body.current_thread.text, "charged"),
61 strings.icontains(body.current_thread.text, "crypto"),
62 strings.icontains(body.current_thread.text, "wallet address"),
63 regex.icontains(body.current_thread.text, '\$\d{3}\.\d{2}\b'),
64 )
65 // phone number regex
66 and regex.icontains(body.current_thread.text,
67 '\+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4}',
68 '\+?([ilo0-9]{1,2})?\s?\(?\d{3}\)?[\s\.\-⋅]{0,5}[ilo0-9]{3}[\s\.\-⋅]{0,5}[ilo0-9]{4}'
69 )
70 )
71 or (
72 // this seciton is synced with attachment_callback_phish_with_img.yml and attachment_callback_phish_with_pdf.yml
73 // and above for current_thread.text
74 //
75 // This rule makes use of a beta feature and is subject to change without notice
76 // using the beta feature in custom rules is not suggested until it has been formally released
77 //
78 3 of (
79 strings.icontains(beta.ocr(file.message_screenshot()).text, 'purchase'),
80 strings.icontains(beta.ocr(file.message_screenshot()).text, 'payment'),
81 strings.icontains(beta.ocr(file.message_screenshot()).text, 'transaction'),
82 strings.icontains(beta.ocr(file.message_screenshot()).text,
83 'subscription'
84 ),
85 strings.icontains(beta.ocr(file.message_screenshot()).text, 'antivirus'),
86 strings.icontains(beta.ocr(file.message_screenshot()).text, 'order'),
87 strings.icontains(beta.ocr(file.message_screenshot()).text, 'support'),
88 strings.icontains(beta.ocr(file.message_screenshot()).text, 'help line'),
89 strings.icontains(beta.ocr(file.message_screenshot()).text, 'receipt'),
90 strings.icontains(beta.ocr(file.message_screenshot()).text, 'invoice'),
91 strings.icontains(beta.ocr(file.message_screenshot()).text, 'call'),
92 strings.icontains(beta.ocr(file.message_screenshot()).text, 'helpdesk'),
93 strings.icontains(beta.ocr(file.message_screenshot()).text, 'cancel'),
94 strings.icontains(beta.ocr(file.message_screenshot()).text, 'renew'),
95 strings.icontains(beta.ocr(file.message_screenshot()).text, 'refund'),
96 regex.icontains(beta.ocr(file.message_screenshot()).text,
97 "(?:reach|contact) us at"
98 ),
99 strings.icontains(beta.ocr(file.message_screenshot()).text, '+1'),
100 strings.icontains(beta.ocr(file.message_screenshot()).text, 'amount'),
101 strings.icontains(beta.ocr(file.message_screenshot()).text, 'charged'),
102 strings.icontains(beta.ocr(file.message_screenshot()).text, 'crypto'),
103 strings.icontains(beta.ocr(file.message_screenshot()).text,
104 'wallet address'
105 ),
106 regex.icontains(beta.ocr(file.message_screenshot()).text,
107 '\$\d{3}\.\d{2}\b'
108 ),
109 )
110 // phone number regex
111 and regex.icontains(beta.ocr(file.message_screenshot()).text,
112 '\+?([ilo0-9]{1}.)?\(?[ilo0-9]{3}?\)?.[ilo0-9]{3}.?[ilo0-9]{4}',
113 '\+?([ilo0-9]{1,2})?\s?\(?\d{3}\)?[\s\.\-⋅]{0,5}[ilo0-9]{3}[\s\.\-⋅]{0,5}[ilo0-9]{4}'
114 )
115
116 // negate messages with previous threads. While callback phishing with thread hijacking or with current_thread
117 // padded with whitespace and previous threads in the message has been observed, the intetion of using OCR is for image embedded callbacks
118 and not regex.icount(beta.ocr(file.message_screenshot()).text,
119 '(?:from|to|sent|date|cc|subject):'
120 ) > 3
121 // this notation of previous threads often only occurs once
122 and not regex.icontains(beta.ocr(file.message_screenshot()).text,
123 'wrote:[\r\n]'
124 )
125 )
126 )
127attack_types:
128 - "Callback Phishing"
129tactics_and_techniques:
130 - "Exploit"
131 - "Impersonation: Brand"
132 - "Out of band pivot"
133 - "Social engineering"
134detection_methods:
135 - "Computer Vision"
136 - "Content analysis"
137 - "Header analysis"
138 - "Sender analysis"
139 - "URL analysis"
140id: "4599575d-6dd7-5785-bad9-4902eeff4e1b"