Credential phishing: Generic document share with unicode and proceedural greeting template
Detects messages that incorporate recipient-specific information (email domain, local part, domain elements or mailbox elements) alongside document-themed Unicode symbols and keywords. The rule identifies various targeting patterns including greeting-based personalization, attention-grabbing prefixes and multiple recipient elements. It also catches broken template attacks where recipient placeholders remain visible.
Sublime rule (View on GitHub)
1name: "Credential phishing: Generic document share with unicode and proceedural greeting template"
2description: "Detects messages that incorporate recipient-specific information (email domain, local part, domain elements or mailbox elements) alongside document-themed Unicode symbols and keywords. The rule identifies various targeting patterns including greeting-based personalization, attention-grabbing prefixes and multiple recipient elements. It also catches broken template attacks where recipient placeholders remain visible."
3type: "rule"
4severity: "low"
5source: |
6 type.inbound
7 and (
8 // nlu capture for wide scope of greetings to reduce evasion
9 any(filter(ml.nlu_classifier(body.current_thread.text).entities,
10 .name == "greeting"
11 ),
12 any([
13 recipients.to[0].email.domain.sld,
14 recipients.to[0].email.local_part,
15 recipients.to[0].email.domain.domain,
16 // "firstlast" naming convention observed
17 strings.concat(mailbox.first_name, mailbox.last_name)
18 ],
19 // recipient entity follows the greeting in the body text
20 strings.icontains(body.current_thread.text,
21 strings.concat(..text, " ", .)
22 )
23 )
24 )
25 or (
26 // nlu capture for wide scope of greetings to reduce evasion
27 any(filter(ml.nlu_classifier(body.current_thread.text).entities,
28 .name == "greeting"
29 ),
30 // nlu capture for wide scope of recipient entity to reduce evasion
31 any(filter(ml.nlu_classifier(body.current_thread.text).entities,
32 .name == "recipient"
33 and not (
34 strings.icontains(.text, "customer")
35 // accounting for grouped recipients
36 or regex.icontains(.text, '&|\band\b')
37 )
38 ),
39 // recipient entity follows the greeting in the body text
40 strings.icontains(body.current_thread.text,
41 strings.concat(..text, " ", .text)
42 )
43 // the named recipient doesn't match the actual "to" recipient
44 and not any([
45 recipients.to[0].email.domain.sld,
46 recipients.to[0].email.local_part,
47 recipients.to[0].email.domain.domain,
48 mailbox.first_name,
49 ],
50 strings.icontains(..text, .)
51 )
52 )
53 )
54 )
55 or any([
56 recipients.to[0].email.domain.sld,
57 recipients.to[0].email.local_part,
58 recipients.to[0].email.domain.domain,
59 // "firstlast" naming convention observed
60 strings.concat(mailbox.first_name, mailbox.last_name)
61 ],
62 // strings logic for non-greeting body starter
63 strings.icontains(body.current_thread.text,
64 strings.concat("attn: ", .)
65 )
66 // strings logic for recipient as body starter
67 or strings.icontains(body.current_thread.text,
68 strings.concat(., " balance statement")
69 )
70 )
71 // count of all recipient elements is 2 or greater
72 or length(filter([
73 recipients.to[0].email.domain.sld,
74 recipients.to[0].email.local_part,
75 recipients.to[0].email.domain.domain,
76 // "firstlast" naming convention observed
77 strings.concat(mailbox.first_name, mailbox.last_name)
78 ],
79 strings.icontains(body.current_thread.text, .)
80 )
81 ) >= 2
82
83 // logic for broken attack
84 or any(ml.nlu_classifier(body.current_thread.text).entities,
85 .name == "recipient" and regex.icontains(.text, '[{}]')
86 )
87 )
88
89 // unicode + keyword generic template
90 and (
91 (
92 (
93 regex.icontains(body.current_thread.text,
94 '(?:\x{2710}|\x{270D}|\x{270E}|\x{270F}|\x{1F4C1}|\x{1F4C4}|\x{1F4D1}|\x{1F4DD})\n?.{0,15}(?:document|completion|remit|review|statement|agreement|shar(?:ed|ing)|receiv|\bmail\b)',
95 '(?:document|completion|remit|review|statement|agreement|shar(?:ed|ing)|receiv|\bmail\b)\n?.{0,15}(?:\x{2710}|\x{270D}|\x{270E}|\x{270F}|\x{1F4C1}|\x{1F4C4}|\x{1F4D1}|\x{1F4DD})'
96 )
97 // negate sharepoint paths with unicode
98 and not any(body.links,
99 regex.icontains(.display_url.path,
100 '(?:\x{2710}|\x{270D}|\x{270E}|\x{270F}|\x{1F4C1}|\x{1F4C4}|\x{1F4D1}|\x{1F4DD})'
101 )
102 )
103 )
104 // start of body is unicode & CTA button is present
105 or (
106 regex.icontains(body.current_thread.text,
107 '^(?:\x{2710}|\x{270D}|\x{270E}|\x{270F}|\x{1F4C1}|\x{1F4C4}|\x{1F4D1}|\x{1F4DD})'
108 )
109 and any(body.links,
110 regex.icontains(.display_text,
111 '(?:document|completion|remit|review|statement|agreement|shar(?:ed|ing)|receiv|\bmail\b)'
112 )
113 )
114 )
115 )
116 )
117
118 // strings negations
119 and not regex.icontains(body.current_thread.text,
120 'meeting (?:note|recap)|daily brief|brief recap'
121 )
122
123 // nlu intent negation for FP's
124 and any(ml.nlu_classifier(body.current_thread.text).intents, .name != "benign")
125
126 // nlu topic negations
127 and not any(ml.nlu_classifier(body.current_thread.text).topics,
128 .name in ("Software and App Updates", "B2B Cold Outreach")
129 )
130
131 // negate multiple recipients unless undisclosed recipients
132 and not (
133 length(recipients.to) == 1
134 and (
135 (length(recipients.cc) != 0 or length(recipients.bcc) != 0)
136 // notification automation
137 and not any(recipients.bcc, .email.local_part == "notifications")
138 )
139 and not (
140 length(recipients.to) == 0
141 or all(recipients.to, .email.domain.valid == false)
142 )
143 )
144
145 // negate highly trusted sender domains unless they fail DMARC authentication
146 and (
147 (
148 sender.email.domain.root_domain in $high_trust_sender_root_domains
149 and not coalesce(headers.auth_summary.dmarc.pass, false)
150 )
151 or sender.email.domain.root_domain not in $high_trust_sender_root_domains
152 )
153
154 // negate legitimate conversations
155 and not (
156 (length(headers.references) > 0 or headers.in_reply_to is not null)
157 and (subject.is_forward or subject.is_reply)
158 and length(body.previous_threads) >= 1
159 )
160
161 // sender negations
162 and not (
163 sender.email.domain.root_domain in (
164 "gc.ai",
165 "getguru.com",
166 "glean.com",
167 "mentorloop.com",
168 )
169 and coalesce(headers.auth_summary.dmarc.pass, false)
170 )
171
172tags:
173 - "Attack surface reduction"
174attack_types:
175 - "BEC/Fraud"
176 - "Credential Phishing"
177tactics_and_techniques:
178 - "Social engineering"
179 - "Evasion"
180detection_methods:
181 - "Content analysis"
182 - "Natural Language Understanding"
183id: "f5bee657-53bc-501f-9b7a-ea51da73a716"