Fake voicemail notification (untrusted sender)
This rule detects a common credential phishing vector enticing the user to engage with links under the premise that they have a voicemail to retrieve. The rule looks for voicemail verbiage in the display name, body, subject or a combination of those elements with emojis or a medium to high credential theft NLU Intent from first-time + unsolicited sender.
Sublime rule (View on GitHub)
1name: "Fake voicemail notification (untrusted sender)"
2description: |
3 This rule detects a common credential phishing vector enticing the user to engage with links under the premise that they have a voicemail to retrieve.
4 The rule looks for voicemail verbiage in the display name, body, subject or a combination of those elements with emojis or a medium to high credential theft NLU Intent from first-time + unsolicited sender.
5type: "rule"
6severity: "medium"
7source: |
8 type.inbound
9 // contains links or attachments
10 and (
11 0 < length(body.links) <= 25 or 0 < length(distinct(attachments, .md5)) <= 3
12 )
13
14 // the subject or display_name need some keywords which are voicemail related
15 and (
16 any([subject.subject, sender.display_name],
17 regex.icontains(.,
18 // split phrases that occur within 3 words between or only punctuation between them
19 '(?:v[nm](\b|[[:punct:]])?|\bvoice(?:mail|message)?|audi[o0]|incoming|missed(?:\sa\s)?|left( a)?|wireless)(?:\w+(\s\w+)?|[[:punct:]]+|\s+){0,3}(?:mail|message|msg|recording|received|notif|support|ca[li1][li1]\d*\b|ca[il1][il1](?:er)?|log|transcript(?:ion)?\b)',
20 // regex specific to v-mail, v_msg, v,mail, etc
21 // list of "secondary" words synced with regex above this one
22 'v[[:punct:]](?:mail|message|msg|recording|received|notif|support|ca[li1][li1]\d*\b|ca[il1][il1](?:er)?|log|transcript(?:ion)?\b)',
23 // split phrases that start with "caller" that occur within 3 words between or only punctation
24 'ca[li1][li1](?:er)?(?:\w+(\s\w+)?|[[:punct:]]+|\s+){0,3}(?:v[nm](\b|[[:punct:]])?|\bvoice(?:mail|message)?|audi[o0]|missed(?:\sa\s)?|left( a)?)',
25 // strong phrases
26 '(?:open mp3|audi[o0] note|\.wav|left a vm|[^\s]+voip[^\s]*|unanswered.*ca[li1][li1]|incoming.vm|left msg|wireless ca[li1][li1]er|VM Service|voice message|missed.ca[li1][li1](?:e[rd])?|\bca[li1][li1].(?:support|service)(?: for| log)?|missed.{0,10} VM|new voicemail from|new.v.m.from.\+?\d+|new voicemail?(?:\w+(\s\w+)?|[[:punct:]]+|\s+){0,3}transcript(s|ion)?|message received|incoming transmission)',
27 // starts in the format of `(4)` and contains some voicemail keywords
28 '^\(\d\)\s(?:\w+(\s\w+)?|[[:punct:]]+|\s+){0,3}(?:message|voip|voice|unread|call)',
29 'ca[li1][li1](?:er)?(?:\w+(\s\w+)?|[[:punct:]]+|\s+){0,3}(?:playback|transcript)',
30
31 // obfuscated phone number with at least one digit in the area code and at least one obfuscated number in the last group
32 // 555-555-555X, 555-555-XXXX, 555-5XX-XXXX
33 '\b1?\(?(\d{3}|\d{2}[\*X]|\d[\*X]{2})\)?[^a-z0-9]{0,2}(\d{2,3}|\d{2}[\*X]|\d[\*X]{2}|[\*X]{2,3})[^a-z0-9]{0,4}(\d{3}[\*X]|\d{2}[\*X]{2}|\d[\*X]{3}|[\*X]{3,4})[^0-9]',
34 // obfuscated phone number with at least one digit in the prefix
35 // XXX-555-5555, XXX-5XX-XXXX
36 '\b1?\(?(\d{2}[\*X]|\d[\*X]{2}|[\*X]{2,3})\)?[^a-z0-9]{0,2}(\d{2,3}|\d{2}[\*X]|\d[\*X]{2})[^a-z0-9]{0,4}(\d{4}|\d{3}[\*X]|\d{2}[\*X]{2}|\d[\*X]{3}|[\*X]{3,4})\b',
37 )
38 )
39 // body.current_thread.text inspection should be very specific to avoid FP
40 or regex.icontains(strings.replace_confusables(body.current_thread.text),
41 // body.current_thread.text,
42 'sent (?:from|by) (?:your )?voice (?:mail )?system',
43 'new (?:voice(?:mail)?|audi[o0]) (?:message|notification|record)',
44 'voicemail (is )?attached',
45 'an? (?:new )?encrypted voicemail',
46 'a (?:new )?pending message',
47 'Your? have (?: an?)?incoming voiceRec',
48 "you(?:\'ve| have) a (?:new )?missed ca[li1][li1]",
49 'New Voicemail Received',
50 'New missed ca[li1][li1] record',
51 'voicemail transcript(?:ion)?',
52 'Listen to VoiceMail',
53 'New voicemail from'
54 )
55 // pull out two regexes that could benefit from negations
56 or (
57 regex.icontains(body.current_thread.text,
58 // body.current_thread.text,
59 'you (?:have |received )*(?:\w+(\s\w+)?|[[:punct:]]+|\s+){0,3}\bvoice\s?(?:mail|audi[o0]|message)',
60 'left you a (?:\w+(\s\w+)?|[[:punct:]]+|\s+){0,3}(?:voice(?:mail)?|audi[o0])(?: message)?',
61 )
62 and not regex.icontains(body.current_thread.text,
63 '(?:I(?:\sjust)?|just(?: called you at (?:\d+[[:punct:]])+) and)? left you a (?:\w+(\s\w+)?|[[:punct:]]+|\s+){0,3}(?:voice(?:mail)?|audio)(?: message)?'
64 )
65 and not regex.icontains(body.current_thread.text,
66 'you (?:have |received )my voice\s?(?:mail|audio|message)'
67 )
68 )
69 // Reuse the body.current_thread.text logic against the OCR output of the message screenshot
70 or (
71 all(attachments, .file_type in $file_types_images)
72 and any((filter(file.explode(beta.message_screenshot()), .depth == 0)),
73 regex.icontains(.scan.ocr.raw,
74 // body.current_thread.text,
75 'sent (?:from|by) (?:your )?voice (?:mail )?system',
76 'new (?:voice(?:mail)?|audio) (?:message|notification|record)',
77 'voicemail (is )?attached',
78 'an? (?:new )?encrypted voicemail',
79 'a (?:new )?pending message',
80 'Your? have (?: an?)?incoming voiceRec',
81 "you(?:\'ve| have) a (?:new )?missed ca[li1][li1]",
82 'New Voicemail Received',
83 'New missed ca[li1][li1] record',
84 'voicemail transcript(?:ion)?',
85 'Listen to VoiceMail',
86 'New voicemail from'
87 )
88 or (
89 regex.icontains(.scan.ocr.raw,
90 // body.current_thread.text,
91 'you (?:have |received )*(?:\w+(\s\w+)?|[[:punct:]]+|\s+){0,3}\bvoice\s?(?:mail|audi[o0]|message)',
92 'left you a (?:\w+(\s\w+)?|[[:punct:]]+|\s+){0,3}(?:voice(?:mail)?|audi[o0])(?: message)?',
93 )
94 and not regex.icontains(body.current_thread.text,
95 '(?:I(?:\sjust)?|just) left you a (?:\w+(\s\w+)?|[[:punct:]]+|\s+){0,3}(?:voice(?:mail)?|audio)(?: message)?'
96 )
97 and not regex.icontains(body.current_thread.text,
98 'you (?:have |received )my voice\s?(?:mail|audio|message)'
99 )
100 )
101 )
102 )
103 // phishing template observed https://platform.sublime.security/messages/341eed2be003036cdd3eeee575202df8a7472b6567d0dfa0f99c3b3fb42a8e7f
104 or strings.icontains(body.html.raw, '<title>Voicemail Notification</title>')
105 or strings.icontains(body.html.raw, '<!-- Voicemail phone logo')
106 )
107 and 2 of (
108 (
109 // the sender is a freemail
110 sender.email.domain.root_domain in $free_email_providers
111 ),
112 (
113 any(ml.nlu_classifier(body.current_thread.text).intents,
114 .name in ("cred_theft") and .confidence in ("medium", "high")
115 )
116 or
117 // use the OCR from the message screenshot
118 any(filter(file.explode(beta.message_screenshot()), .depth == 0),
119 any(ml.nlu_classifier(.scan.ocr.raw).intents,
120 .name in ("cred_theft") and .confidence in ("medium", "high")
121 )
122 )
123 ),
124 (
125 any(attachments,
126 .content_type in ("html", "text", "text/html")
127 and any(ml.logo_detect(file.html_screenshot(.)).brands,
128 .name in ("Microsoft") and .confidence in ("medium", "high")
129 )
130 )
131 ),
132 (
133 regex.icontains(sender.display_name,
134 '(voice|audi[o0]|call|missed|caii)(\s?|-)(mail|message|recording|call|caii)|(transcription|Caller.?ID)'
135 )
136 ),
137 // attachment names are often HTML and voice mail related
138 (
139 any(attachments,
140 // this logic is reused below for eml attachments
141 // ensure updates occur both places
142 (
143 .content_type in ("html", "text", "text/html")
144 or .file_type in ("html", "unknown")
145 or .file_type == "pdf"
146 )
147 and (
148 regex.icontains(.file_name,
149 '(?:voice|aud[i1l][o0]|call|missed|caii|mail|message|recording|call|caii|transcr[il1]ption|v[nm]|audi[o0]|play|listen|unheard|msg)',
150 // contains a time
151 // 01min , 60secs
152 '0?[1-9]\s*min(?:(?:ute)?s)?',
153 '\d{1,2}\s*s(?:ec(?:ond)?s)?',
154 // (00:50s)
155 // 3:26 seconds
156 '[\(\[]?(?:\d{1,2}[\:\s-])\d{1,2}[\)\]]?\s*(?:s(?:(?:ecs?)onds)?)[\)\]]?',
157 // 03min25secs
158 '0?[1-9]\s*min(?:(?:ute)?s)?\d{1,2}\s*s(?:ec(?:ond)?s)?',
159 // [0:39]
160 // (0:39)
161 '[\(\[](?:\d{1,2}[\:\s-])\d{1,2}[\)\]]\s',
162 // contains an emoji
163 '[\x{1F300}-\x{1F5FF}\x{1F600}-\x{1F64F}\x{1F680}-\x{1F6FF}\x{1F700}-\x{1F77F}\x{1F780}-\x{1F7FF}\x{1F900}-\x{1F9FF}\x{2600}-\x{26FF}\x{2700}-\x{27BF}\x{2300}-\x{23FF}]'
164 )
165 // somtimes there is no name, it's just the extension which is also strange
166 or .file_name in~ (".htm", ".html")
167 // or sometimes it has no name....
168 or .file_name is null
169 )
170 )
171 ),
172 // html attachment is small and contains javascript
173 (
174 any(attachments,
175 (
176 .content_type in ("html", "text", "text/html")
177 or .file_type in ("html", "unknown")
178 )
179 and (
180 .size < 1500 and any(file.explode(.), length(.scan.html.scripts) > 0)
181 )
182 )
183 ),
184 (
185 any(attachments,
186 (
187 .content_type in ("html", "text", "text/html")
188 or .file_type in ("html", "unknown")
189 )
190 and any(recipients.to,
191 // the html attachment contains a receipient email address
192 strings.contains(file.parse_html(..).raw, .email.email)
193 // the sld of the domain is in the attachment name
194 or strings.contains(..file_name, .email.domain.sld)
195 )
196 )
197 ),
198 // eml attachments
199 (
200 any(filter(attachments, .content_type == "message/rfc822"),
201 // which contain attachments
202 // this is the same logic as above
203 any(file.parse_eml(.).attachments,
204 (
205 .content_type in ("html", "text", "text/html")
206 or .file_type in ("html", "unknown")
207 or .file_type == "pdf"
208 )
209 and (
210 regex.icontains(.file_name,
211 '(?:voice|aud[il1][o0]|call|missed|caii|mail|message|recording|call|caii|transcr[il1]ption|v[nm]|audi[o0]|play|listen|unheard|msg)',
212 // contains a time
213 // 01min , 60secs
214 '0?[1-9]\s*min(?:(?:ute)?s)?',
215 '\d{1,2}\s*s(?:ec(?:ond)?s)?',
216 // (00:50s)
217 // 3:26 seconds
218 '[\(\[]?(?:\d{1,2}[\:\s-])\d{1,2}[\)\]]?\s*(?:s(?:(?:ecs?)onds)?)[\)\]]?',
219 // 03min25secs
220 '0?[1-9]\s*min(?:(?:ute)?s)?\d{1,2}\s*s(?:ec(?:ond)?s)?',
221 // [0:39]
222 // (0:39)
223 '[\(\[](?:\d{1,2}[\:\s-])\d{1,2}[\)\]]\s',
224 // contains an emoji
225 '[\x{1F300}-\x{1F5FF}\x{1F600}-\x{1F64F}\x{1F680}-\x{1F6FF}\x{1F700}-\x{1F77F}\x{1F780}-\x{1F7FF}\x{1F900}-\x{1F9FF}\x{2600}-\x{26FF}\x{2700}-\x{27BF}\x{2300}-\x{23FF}]'
226 )
227 // somtimes there is no name, it's just the extension which is also strange
228 or .file_name in~ (".htm", ".html")
229 // or sometimes it has no name....
230 or .file_name is null
231 )
232 )
233 )
234 ),
235 // attached eml sender/recipeient/subject are all the same as the outer
236 // and have an attachment or body links
237 (
238 any(filter(attachments, .content_type == "message/rfc822"),
239 // which contain attachments
240 // this is the same logic as above
241 file.parse_eml(.).subject.subject == subject.subject
242 and file.parse_eml(.).sender.email.email == sender.email.email
243 and (
244 length(file.parse_eml(.).recipients.to) == length(recipients.to)
245 and all(recipients.to,
246 .email.email in map(file.parse_eml(..).recipients.to,
247 .email.email
248 )
249 )
250 )
251 and (
252 // there are attachments
253 length(file.parse_eml(.).attachments) > 0
254 // or body links
255 or length(filter(file.parse_eml(.).body.links,
256 .href_url.domain.domain not in $org_domains
257 and .href_url.domain.root_domain not in $org_domains
258 )
259 ) > 0
260 )
261 )
262 ),
263 // the body links contain the recipients email
264 (
265 length(filter(recipients.to, .email.email != "" or .email.domain.valid)) > 0
266 and any(body.links,
267 any(recipients.to,
268 strings.icontains(..href_url.url, .email.email)
269 or strings.icontains(..href_url.url, .email.local_part)
270 )
271 )
272 ),
273 (
274 length(body.current_thread.text) < 700
275 and regex.icontains(body.current_thread.text,
276 'Méssãge|Méssage|Recéived|Addréss'
277 )
278 ),
279 (
280 // sender domain matches no body domains
281 // only inspect "links" that have a display_text and display_url is null to remove "plain text" email address from being caught
282 length(filter(body.links,
283 .display_text is not null
284 and .display_url.url is null
285 and .href_url.domain.valid
286 )
287 ) > 0
288 and all(filter(body.links,
289 .display_text is not null
290 and .display_url.url is null
291 and .href_url.domain.valid
292 ),
293 .href_url.domain.root_domain != sender.email.domain.root_domain
294 and .href_url.domain.root_domain not in $org_domains
295 and .href_url.domain.root_domain not in ("aka.ms")
296 and .href_url.domain.root_domain not in (
297 "unitelvoice.com",
298 "googleapis.com",
299 "dialmycalls.com",
300 "ringcentral.biz"
301 )
302 )
303 ),
304 // the body links contain vm related phrases
305 (
306 any(body.links,
307 regex.contains(.display_text, '[^a-z]*[A-Z][^a-z]*')
308 and regex.icontains(.display_text,
309 '(v[nm]|voice|audi[o0]|call|missed|caii)(\s?|-)(mail|message|recording|call|caii)|transcription|open mp3|audi[o0] note|listen|playback|\(?(?:\*\*\*|[0-9]{3})?.(?:\*\*\*|[0-9]{3})[^a-z]{0,2}(?:\*{4}|\d+\*+)|play'
310 )
311 // negate FP terms in link display texts
312 and not strings.icontains(.display_text, 'voice call center')
313 )
314 ),
315 (
316 any(body.links,
317 .href_url.path == "/ctt"
318 and regex.icontains(.display_text,
319 '(v[nm]|voice|audi[o0]|call|missed|caii)(\s?|-)(mail|message|recording|call|caii)|transcription|open mp3|audi[o0] note|listen|playback|\(?(?:\*\*\*|[0-9]{3})?.(?:\*\*\*|[0-9]{3})[^a-z]{0,2}(?:\*{4}|\d+\*+)|play'
320 )
321 // negate FP terms in link display texts
322 and not strings.icontains(.display_text, 'voice call center')
323 )
324 ),
325 // new domains
326 (
327 any(body.links,
328 network.whois(.href_url.domain).days_old < 10
329 and not strings.icontains(.href_url.path, "unsubscribe")
330 )
331 ),
332 // sld use in sender/subject selements
333 (
334 any(recipients.to,
335 // recipient's SLD is in the sender's display name
336 strings.icontains(sender.display_name, .email.domain.sld)
337 // recipient's SLD is in the sender's display name
338 or strings.icontains(subject.subject, .email.domain.sld)
339 // recipient's SLD is in the senders local_part
340 or strings.icontains(sender.email.local_part, .email.domain.sld)
341 )
342 ),
343 // often times the subject or sender display name will contain time references
344 (
345 any([sender.display_name, subject.subject, body.current_thread.text],
346 regex.icontains(.,
347 // 01min , 60secs
348 '0?[1-9]\s*min(?:(?:ute)?s)?\b',
349 '\d{1,2}\s*s(?:ec(?:ond)?s)?\b',
350 // (00:50s)
351 // 3:26 seconds
352 '[\(\[]?(?:\d{1,2}[\:\s-])\d{1,2}[\)\]]?\s*(?:s(?:(?:ecs?)onds)?)[\)\]]?',
353 // 03min25secs
354 '0?[1-9]\s*min(?:(?:ute)?s)?\d{1,2}\s*s(?:ec(?:ond)?s)?',
355 // [0:39]
356 // (0:39)
357 '[\(\[](?:\d{1,2}[\:\s-])\d{1,2}[\)\]]\s'
358 )
359 )
360 // resuse the same logic against ORC output of message_screenshot
361 or any(filter(file.explode(beta.message_screenshot()), .depth == 0),
362 regex.icontains(.scan.ocr.raw,
363 // 01min , 60secs
364 '0?[1-9]\s*min(?:(?:ute)?s)?\b',
365 '\d{1,2}\s*s(?:ec(?:ond)?s)?\b',
366 // (00:50s)
367 // 3:26 seconds
368 '[\(\[]?(?:\d{1,2}[\:\s-])\d{1,2}[\)\]]?\s*(?:s(?:(?:ecs?)onds)?)[\)\]]?',
369 // 03min25secs
370 '0?[1-9]\s*min(?:(?:ute)?s)?\d{1,2}\s*s(?:ec(?:ond)?s)?',
371 // [0:39]
372 // (0:39)
373 '[\(\[](?:\d{1,2}[\:\s-])\d{1,2}[\)\]]\s'
374 )
375 )
376 ),
377 // often times the subject or sender display name will contain dates
378 (
379 any([sender.display_name, subject.subject],
380 // days of week
381 any([
382 'monday',
383 'tuesday',
384 'wednesday',
385 'thursday',
386 'friday',
387 'saturday',
388 'sunday'
389 ],
390 strings.icontains(.., .)
391 )
392 // months
393 // may is problematic for words like "Mayor", "Maybe", "MayFlower", etc
394 or any([
395 "January",
396 "February",
397 "March",
398 "April",
399 "June",
400 "July",
401 "August",
402 "September",
403 "October",
404 "November",
405 "December"
406 ],
407 strings.icontains(.., .)
408 )
409 // use a regex for May
410 or regex.icontains(., '\bmay\b')
411 // common date formats
412 or regex.contains(.,
413 // YYYY-MM-DD or YY-MM-DD (ISO 8601 format)
414 '\d{2}(\d{2})?-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])',
415 // MM/DD/YYYY or MM/DD/YY (US format)
416 '(0[1-9]|1[0-2])/(0[1-9]|[12]\d|3[01])/\d{2}(\d{2})?',
417 // DD/MM/YYYY or DD/MM/YY (European format)
418 '(0[1-9]|[12]\d|3[01])/(0[1-9]|1[0-2])/\d{2}(\d{2})?',
419 // Month DD, YYYY or Month DD, YY (e.g., March 15, 2024 or March 15, 24)
420 '(January|February|March|April|May|June|July|August|September|October|November|December) (0[1-9]|[12]\d|3[01]), \d{2}(\d{2})?'
421 )
422 // common time formats
423 or regex.contains(.,
424 // Example: 23:45, 08:30
425 '([01]\d|2[0-3]):([0-5]\d)',
426 // Example: 23:45:59, 08:30:12
427 '([01]\d|2[0-3]):([0-5]\d):([0-5]\d)',
428 // Example: 08:30 AM, 12:45 pm
429 '(0[1-9]|1[0-2]):([0-5]\d)\s?([AaPp][Mm])',
430 // Example: 08:30 AM, 12:45 pm
431 '(0[1-9]|1[0-2]):([0-5]\d):([0-5]\d) ?([AaPp][Mm])'
432 )
433 )
434 // or use the OCR results from beta.message_screenshot
435 or any(filter(file.explode(beta.message_screenshot()), .depth == 0),
436 // days of week
437 any([
438 'monday',
439 'tuesday',
440 'wednesday',
441 'thursday',
442 'friday',
443 'saturday',
444 'sunday'
445 ],
446 strings.icontains(..scan.ocr.raw, .)
447 )
448 // months
449 // may is problematic for words like "Mayor", "Maybe", "MayFlower", etc
450 or any([
451 "January",
452 "February",
453 "March",
454 "April",
455 "June",
456 "July",
457 "August",
458 "September",
459 "October",
460 "November",
461 "December"
462 ],
463 strings.icontains(..scan.ocr.raw, .)
464 )
465 // use a regex for May
466 or regex.icontains(.scan.ocr.raw, '\bmay\b')
467 // common date formats
468 or regex.contains(.scan.ocr.raw,
469 // YYYY-MM-DD or YY-MM-DD (ISO 8601 format)
470 '\d{2}(\d{2})?-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])',
471 // MM/DD/YYYY or MM/DD/YY (US format)
472 '(0[1-9]|1[0-2])/(0[1-9]|[12]\d|3[01])/\d{2}(\d{2})?',
473 // DD/MM/YYYY or DD/MM/YY (European format)
474 '(0[1-9]|[12]\d|3[01])/(0[1-9]|1[0-2])/\d{2}(\d{2})?',
475 // Month DD, YYYY or Month DD, YY (e.g., March 15, 2024 or March 15, 24)
476 '(January|February|March|April|May|June|July|August|September|October|November|December) (0[1-9]|[12]\d|3[01]), \d{2}(\d{2})?'
477 )
478 // common time formats
479 or regex.contains(.scan.ocr.raw,
480 // Example: 23:45, 08:30
481 '([01]\d|2[0-3]):([0-5]\d)',
482 // Example: 23:45:59, 08:30:12
483 '([01]\d|2[0-3]):([0-5]\d):([0-5]\d)',
484 // Example: 08:30 AM, 12:45 pm
485 '(0[1-9]|1[0-2]):([0-5]\d)\s?([AaPp][Mm])',
486 // Example: 08:30 AM, 12:45 pm
487 '(0[1-9]|1[0-2]):([0-5]\d):([0-5]\d) ?([AaPp][Mm])'
488 )
489 )
490 ),
491 // there are often emoji in the sender display name
492 (
493 any([sender.display_name, subject.subject],
494 // contains an emoji
495 regex.contains(.,
496 '[\x{1F300}-\x{1F5FF}\x{1F600}-\x{1F64F}\x{1F680}-\x{1F6FF}\x{1F700}-\x{1F77F}\x{1F780}-\x{1F7FF}\x{1F900}-\x{1F9FF}\x{2600}-\x{26FF}\x{2700}-\x{27BF}\x{2300}-\x{23FF}]'
497 )
498 // negate where the emoji occur in tags
499 and not regex.contains(.,
500 '^(?:\[[^\]]*\]\s*)*\[[^\]]*[\x{1F300}-\x{1F5FF}\x{1F600}-\x{1F64F}\x{1F680}-\x{1F6FF}\x{1F700}-\x{1F77F}\x{1F780}-\x{1F7FF}\x{1F900}-\x{1F9FF}\x{2600}-\x{26FF}\x{2700}-\x{27BF}\x{2300}-\x{23FF}][^\]]*\]'
501 )
502 )
503 ),
504 // an attachment is a pdf, image, or document that contains a url
505 (
506 1 <= length(attachments) <= 2
507 and any(attachments,
508 (
509 .file_type in $file_types_images
510 or .file_type == "pdf"
511 or .file_extension in $file_extensions_macros
512 )
513 and any(file.explode(.),
514 .scan.qr.type == "url"
515 or strings.icontains(.scan.qr.data, 'http')
516 or any(recipients.to,
517 strings.icontains(..scan.qr.data, .email.local_part)
518 or strings.icontains(..scan.qr.data, .email.email)
519 )
520 )
521 )
522 )
523 )
524
525 // negating legit replies and legitimate audio file attachments and known voicemail senders
526 and not (
527 sender.email.domain.valid
528 and sender.email.domain.root_domain in (
529 "magicjack.com",
530 "unitelvoice.com",
531 "voipinterface.net",
532 "ringcentral.biz",
533 "verizonwireless.com",
534 "t-mobile.com",
535 "justcall.io"
536 )
537 )
538 and not any(attachments, strings.starts_with(.content_type, "audio"))
539 and not (
540 (
541 strings.istarts_with(subject.subject, "RE:")
542 // out of office auto-reply
543 // the NLU model will handle these better natively soon
544 or strings.istarts_with(subject.subject, "Automatic reply:")
545 )
546 and (
547 length(headers.references) > 0
548 or any(headers.hops, any(.fields, strings.ilike(.name, "In-Reply-To")))
549 )
550 )
551 // negate highly trusted sender domains unless they fail DMARC authentication
552 and (
553 (
554 sender.email.domain.root_domain in $high_trust_sender_root_domains
555 and not headers.auth_summary.dmarc.pass
556 )
557 or sender.email.domain.root_domain not in $high_trust_sender_root_domains
558 )
559 // bounce-back negations
560 and not any(attachments,
561 any(file.parse_eml(.).attachments,
562 .content_type == "message/delivery-status"
563 )
564 )
565 // bounce-back negations
566 and not (
567 any(attachments,
568 .content_type in ("message/delivery-status", "text/calendar")
569 )
570 )
571 // negate bouncebacks from proofpoint
572 and not (
573 sender.display_name == "Mail Delivery Subsystem"
574 and strings.ends_with(headers.message_id, "pphosted.com>")
575 and any(headers.hops,
576 .index == 0 and strings.contains(.received.server.raw, "pphosted.com")
577 )
578 and any(attachments, .content_type == "message/rfc822")
579 )
580 // an impersonated high trust domain
581 and (
582 (
583 sender.email.domain.root_domain in $high_trust_sender_root_domains
584 and not headers.auth_summary.dmarc.pass
585 )
586
587 // sender profile
588 or (
589 (
590 not sender.email.domain.root_domain in $org_domains
591 and (profile.by_sender().prevalence not in ("common"))
592 and not profile.by_sender().solicited
593 )
594 or (
595 profile.by_sender().any_messages_malicious_or_spam
596 and not profile.by_sender().any_false_positives
597 )
598 )
599 )
600attack_types:
601 - "Credential Phishing"
602tactics_and_techniques:
603 - "Social engineering"
604detection_methods:
605 - "Content analysis"
606 - "Natural Language Understanding"
607 - "Sender analysis"
608 - "URL analysis"
609id: "74ba7787-e543-5ce8-b6eb-e1ecdb8f1d67"