Credential phishing: Engaging language and other indicators (untrusted sender)
Message contains various suspicious indicators as well as engaging language resembling credential theft from an untrusted sender.
Sublime rule (View on GitHub)
1name: "Credential phishing: Engaging language and other indicators (untrusted sender)"
2description: |
3 Message contains various suspicious indicators as well as engaging language resembling credential theft from an untrusted sender.
4type: "rule"
5severity: "medium"
6source: |
7 type.inbound
8 and (
9 regex.icontains(subject.subject,
10 "termination.*notice",
11 "38417",
12 ":completed",
13 "[il1]{2}mit.*ma[il1]{2} ?bo?x",
14 "[il][il][il]egai[ -]",
15 "[li][li][li]ega[li] attempt",
16 "[ng]-?[io]n .*block",
17 "[ng]-?[io]n .*cancel",
18 "[ng]-?[io]n .*deactiv",
19 "[ng]-?[io]n .*disabl",
20 "action.*required",
21 "abandon.*package",
22 "about.your.account",
23 "acc(ou)?n?t (is )?on ho[li]d",
24 "acc(ou)?n?t.*terminat",
25 "acc(oun)?t.*[il1]{2}mitation",
26 "access.*limitation",
27 "account (will be )?block",
28 "account.*de-?activat",
29 "account.*locked",
30 "account.*re-verification",
31 "account.*security",
32 "account.*suspension",
33 "account.has.expired",
34 "account.will.be.blocked",
35 "account v[il]o[li]at",
36 "activity.*acc(oun)?t",
37 "almost.full",
38 "app[li]e.[il]d",
39 "authenticate.*account",
40 "been.*suspend",
41 "crediential.*notif",
42 "clos.*of.*account.*processed",
43 "confirm.your.account",
44 "courier.*able",
45 "crediential.*notif",
46 "deactivation.*in.*progress",
47 "delivery.*attempt.*failed",
48 "disconnection.*notice",
49 "document.received",
50 "documented.*shared.*with.*you",
51 "dropbox.*document",
52 "e-?ma[il1]+ .{010}suspen",
53 "e-?ma[il1]{1} user",
54 "e-?ma[il1]{2} acc",
55 "e-?ma[il1]{2} preview",
56 "e-?ma[il1]{2}.*up.?grade",
57 "e.?ma[il1]{2}.*server",
58 "e.?ma[il1]{2}.*suspend",
59 "electronic advisory",
60 "email.update",
61 "faxed you",
62 "fraud(ulent)?.*charge",
63 "from.helpdesk",
64 "fu[il1]{2}.*ma[il1]+[ -]?box",
65 "has.been.*suspended",
66 "has.been.limited",
67 "have.locked",
68 "he[li]p ?desk upgrade",
69 "heipdesk",
70 "i[il]iega[il]",
71 "ii[il]ega[il]",
72 "incoming e?mail",
73 "incoming.*fax",
74 "lock.*security",
75 "ma[il1]{1}[ -]?box.*quo",
76 "ma[il1]{2}[ -]?box.*fu[il1]",
77 "ma[il1]{2}box.*[il1]{2}mit",
78 "ma[il1]{2}box stor",
79 "mail on.?hold",
80 "mail.*box.*migration",
81 "mail.*de-?activat",
82 "mail.update.required",
83 "mails.*pending",
84 "messages.*pending",
85 "missed.*shipping.*notification",
86 "missed.shipment.notification",
87 "must.update.your.account",
88 "new [sl][io]g?[nig][ -]?in from",
89 "new voice ?-?mail",
90 "notifications.*pending",
91 "office.*3.*6.*5.*suspend",
92 "office365",
93 "on google docs with you",
94 "online doc",
95 "outstanding inv\\b",
96 "password.*compromised",
97 "(?:payroll|salary|bonus).*Distribution",
98 "periodic maintenance",
99 "potential(ly)? unauthorized",
100 "refund not approved",
101 "report",
102 "\\brfq\\s_",
103 "revised.*policy",
104 "scam",
105 "scanned.?invoice",
106 "secured?.update",
107 "security breach",
108 "securlty",
109 "signed.*delivery",
110 "status of your .{314}? ?delivery",
111 "susp[il1]+c[il1]+ous.*act[il1]+v[il1]+ty",
112 "suspicious.*sign.*[io]n",
113 "suspicious.activit",
114 "temporar(il)?y deactivate",
115 "temporar[il1]{2}y disab[li]ed",
116 "temporarily.*lock",
117 "un-?usua[li].activity",
118 "unable.*deliver",
119 "unauthorized.*activit",
120 "unauthorized.device",
121 "undelivered message",
122 "unread.*doc",
123 "unusual.activity",
124 "(?:unrecognized|Unusual|suspicious|unknown) (?:log|sign).?[io]n attempt",
125 "upgrade.*account",
126 "upgrade.notice",
127 "urgent message",
128 "urgent.verification",
129 "v[il1]o[li1]at[il1]on security",
130 "va[il1]{1}date.*ma[il1]{2}[ -]?box",
131 "verification ?-?require",
132 "verification( )?-?need",
133 "verify.your?.account",
134 "web ?-?ma[il1]{2}",
135 "web[ -]?ma[il1]{2}",
136 "will.be.suspended",
137 "your (customer )?account .as",
138 "your.office.365",
139 "your.online.access",
140 "de.activation",
141 "attn_task",
142 // https://github.com/sublime-security/static-files/blob/main/suspicious_subjects.txt
143 "account has been limited",
144 "action required",
145 "almost full",
146 "apd notifi cation",
147 "are you at your desk",
148 "are you available",
149 "attached file to docusign",
150 "banking is temporarily unavailable",
151 "bankofamerica",
152 "closing statement invoice",
153 "completed: docusign",
154 "de-activation of",
155 "delivery attempt",
156 "delivery stopped for shipment",
157 "detected suspicious",
158 "detected suspicious actvity",
159 "docu sign",
160 "document for you",
161 "document has been sent to you via docusign",
162 "document is ready for signature",
163 "docusign",
164 "encrypted message",
165 "failed delivery",
166 "fedex tracking",
167 "file was shared",
168 "freefax",
169 "fwd: due invoice paid",
170 "has shared",
171 "inbox is full",
172 "invitation to comment",
173 "invitation to edit",
174 "invoice due",
175 "left you a message",
176 "message from",
177 "new message",
178 "new voicemail",
179 "on desk",
180 "out of space",
181 "password reset",
182 "payment status",
183 "pay notification",
184 "quick reply",
185 "re: w-2",
186 "required",
187 "required: completed docusign",
188 "remittance",
189 "ringcentral",
190 "scanned image",
191 "secured files",
192 "secured pdf",
193 "security alert",
194 "new sign-in",
195 "new sign in",
196 "sign-in attempt",
197 "sign in attempt",
198 "staff review",
199 "suspicious activity",
200 "unrecognized login attempt",
201 "unusual signin",
202 "upgrade immediately",
203 "urgent",
204 "wants to share",
205 "w2",
206 "you have notifications pending",
207 "your account",
208 "your amazon order",
209 "your document settlement",
210 "your order with amazon",
211 "your password has been compromised",
212 )
213 or (
214 regex.icontains(subject.subject, 'account.has.been')
215 and not regex.icontains(subject.subject, 'account.has.been.*created')
216 )
217 or (
218 regex.icontains(sender.display_name,
219 "Admin",
220 "Administrator",
221 "Alert",
222 "Assistant",
223 "Authenticat(or|ion)",
224 "Billing",
225 "Benefits",
226 "Bonus",
227 "CEO",
228 "CFO",
229 "CIO",
230 "CTO",
231 "Chairman",
232 "Claim",
233 "Confirm",
234 "Cpanel Mail",
235 "Critical",
236 "Customer Service",
237 "Deal",
238 "Discount",
239 "Director",
240 "Exclusive",
241 "Executive",
242 "Fax",
243 "Free",
244 "Gift",
245 '\bHR\b',
246 "Helpdesk",
247 "Human Resources",
248 "Immediate",
249 "Important",
250 "Info",
251 "Information",
252 "Invoice",
253 '\bIT\b',
254 '\bLegal\b',
255 "Lottery",
256 "Management",
257 "Manager",
258 "Member Services",
259 "Notification",
260 "Offer",
261 "Official Communication",
262 "Operations",
263 "Order",
264 "Partner",
265 "Payment",
266 "Payroll",
267 "Postmaster",
268 "President",
269 "Premium",
270 "Prize",
271 "Receipt",
272 "Refund",
273 "Registrar",
274 "Required",
275 "Reward",
276 "Sales",
277 "Secretary",
278 "Security",
279 "Server",
280 "Service",
281 "Storage",
282 "Support",
283 "Sweepstakes",
284 "System",
285 "Tax",
286 "Tech Support",
287 "Update",
288 "Upgrade",
289 "Urgent",
290 "Validate",
291 "Verify",
292 "VIP",
293 "Webmaster",
294 "Winner",
295 "DocReq\\b"
296 )
297 // add negation for common FPs in the sender display_name
298 and not strings.icontains(sender.display_name, "service bulletin")
299 and not strings.icontains(sender.display_name, "automotive service")
300 )
301 )
302 and (
303 4 of (
304 any(recipients.to,
305 .email.domain.valid
306 and (
307 strings.icontains(body.current_thread.text, .email.email)
308 or strings.icontains(body.current_thread.text, .email.local_part)
309 )
310 ),
311 any(ml.nlu_classifier(body.current_thread.text).intents,
312 .name == "cred_theft" and .confidence in ("medium", "high")
313 ),
314 any(ml.nlu_classifier(body.current_thread.text).entities,
315 .name == "request"
316 ),
317 (
318 any(body.current_thread.links,
319 strings.iends_with(.display_text, ".pdf")
320 and strings.istarts_with(.display_text, "view")
321 )
322 ),
323 // recipient email address base64 encoded in link
324 any(body.links,
325 any(strings.scan_base64(.href_url.url,
326 ignore_padding=true,
327 format="url"
328 ),
329 any(recipients.to, strings.icontains(.., .email.email))
330 )
331 ),
332 (
333 // freemail providers should never be sending this type of email
334 sender.email.domain.domain in $free_email_providers
335
336 // if not freemail, it's suspicious if the sender's root domain
337 // doesn't match any links in the body
338 or all(body.links,
339 .href_url.domain.root_domain != sender.email.domain.root_domain
340 and (
341 .href_url.domain.root_domain not in $org_domains
342 // ignore recipient email addresses in the body in relation to this check
343 or (
344 .href_url.domain.root_domain in $org_domains
345 and any(recipients.to,
346 strings.icount(body.current_thread.text, .email.email) == strings.icount(body.current_thread.text,
347 .email.domain.domain
348 )
349 )
350 )
351 )
352 )
353
354 // bulk mailers should also never be sending this type of email
355 or all(filter(body.links,
356 .href_url.domain.domain not in (
357 "aka.ms",
358 "mimecast.com",
359 "mimecastprotect.com",
360 "cisco.com"
361 )
362 ),
363 .href_url.domain.root_domain in $bulk_mailer_url_root_domains
364 )
365 ),
366 // in case it's embedded in an image attachment
367 // note: don't use message_screenshot() because it's not limited to current_thread
368 // and may FP
369 any(attachments,
370 .file_type in $file_types_images
371 and any(file.explode(.),
372 any(ml.nlu_classifier(.scan.ocr.raw).intents,
373 .name == "cred_theft" and .confidence == "high"
374 )
375 )
376 ),
377 strings.contains(body.current_thread.text,
378 "Your mailbox can no longer send or receive messages."
379 ),
380 strings.contains(body.current_thread.text,
381 "this invoice has been overlooked"
382 ),
383 any(body.links,
384 strings.icontains(.href_url.query_params, 'redirect')
385 or any(.href_url.rewrite.encoders,
386 strings.icontains(., "open_redirect")
387 )
388 ),
389 // multiple entities displaying urgency
390 length(filter(ml.nlu_classifier(body.current_thread.text).entities,
391 .name == "urgency"
392 )
393 ) >= 2
394 // and any body links
395 and any(body.links,
396 // display text contains a request
397 any(ml.nlu_classifier(.display_text).entities, .name == "request")
398 ),
399 (
400 any(body.links,
401 .href_url.domain.root_domain in $self_service_creation_platform_domains
402 )
403 and any(ml.nlu_classifier(body.current_thread.text).tags,
404 .name == "invoice" and .confidence == "high"
405 )
406 ),
407 any(body.links,
408 // display text contains a request
409 (
410 any(ml.nlu_classifier(.display_text).entities, .name == "request")
411 or regex.match(.display_text, '^[^a-z]+$')
412 )
413 and (
414 .href_url.domain.domain in $url_shorteners
415 or .href_url.domain.domain in $social_landing_hosts
416 or .href_url.domain.root_domain in $url_shorteners
417 or .href_url.domain.root_domain in $social_landing_hosts
418 or .href_url.domain.domain in $free_file_hosts
419 or (
420 .href_url.domain.root_domain in (
421 "mimecast.com",
422 "mimecastprotect.com"
423 )
424 and any(.href_url.query_params_decoded['domain'],
425 strings.parse_url(strings.concat("https://", .)).domain.domain in $url_shorteners
426 or strings.parse_url(strings.concat("https://", .)).domain.root_domain in $url_shorteners
427 or strings.parse_url(strings.concat("https://", .)).domain.domain in $free_file_hosts
428 or strings.parse_url(strings.concat("https://", .)).domain.root_domain in $free_subdomain_hosts
429 or strings.parse_url(strings.concat("https://", .)).domain.domain in $social_landing_hosts
430 or strings.parse_url(strings.concat("https://", .)).domain.root_domain in $social_landing_hosts
431 )
432 )
433 )
434 ),
435 // common greetings via email.local_part
436 any(recipients.to,
437 length(.email.local_part) > 2
438 and
439 // use count to ensure the email address is not part of a disclaimer
440 strings.icount(body.current_thread.text, .email.local_part) >
441 // sum allows us to add more logic as needed
442 strings.icount(body.current_thread.text,
443 strings.concat('was sent to ', .email.email)
444 ) + strings.icount(body.current_thread.text,
445 strings.concat('intended for ', .email.email)
446 )
447 )
448 )
449 or (
450 (
451 // recipient's email address is in the body
452 any(recipients.to,
453 // use count to ensure the email address is not part of a disclaimer
454 strings.icount(body.current_thread.text, .email.email) >
455 // sum allows us to add more logic as needed
456 sum([
457 strings.icount(body.current_thread.text,
458 strings.concat('was sent to ', .email.email)
459 ),
460 strings.icount(body.current_thread.text,
461 strings.concat('intended for ', .email.email)
462 )
463 ]
464 )
465 )
466 // suspicious display text
467 or (
468 length(body.links) == 1
469 and all(body.links,
470 strings.ilike(.display_text, "*click here*", "*password*")
471 )
472 )
473 )
474 // link leads to a suspicious TLD or contains an IP address or contains multiple redirects
475 and any(body.links,
476 (
477 ml.link_analysis(., mode="aggressive").effective_url.domain.tld in $suspicious_tlds
478 or length(distinct(map(ml.link_analysis(., mode="aggressive").redirect_history,
479 .domain.root_domain
480 )
481 )
482 ) >= 4
483 or (
484 any(body.ips,
485 any(body.links, strings.icontains(.href_url.url, ..ip))
486 )
487 )
488 )
489 )
490 )
491 )
492 // exclude Google shared calendar messages
493 // Subject: "<sender name> has shared a calendar with you"
494 and headers.return_path.domain.domain != "calendar-server.bounces.google.com"
495 // negate calendar invites
496 and not (
497 0 < length(attachments) < 3
498 and all(attachments, .content_type in ("text/calendar", "application/ics"))
499 )
500 // negate replies
501 and (
502 (
503 (length(headers.references) > 0 or headers.in_reply_to is null)
504 and not (
505 (
506 strings.istarts_with(subject.subject, "RE:")
507 or strings.istarts_with(subject.subject, "R:")
508 or strings.istarts_with(subject.subject, "ODG:")
509 or strings.istarts_with(subject.subject, "答复:")
510 or strings.istarts_with(subject.subject, "AW:")
511 or strings.istarts_with(subject.subject, "TR:")
512 or strings.istarts_with(subject.subject, "FWD:")
513 or regex.icontains(subject.subject,
514 '^(\[[^\]]+\]\s?){0,3}(re|fwd?)\s?:'
515 )
516 )
517 )
518 )
519 or length(headers.references) == 0
520 )
521 // bounce-back and DMARC report negations
522 and not (
523 strings.like(sender.email.local_part,
524 "*postmaster*",
525 "*mailer-daemon*",
526 "*administrator*"
527 )
528 and (
529 any(attachments,
530 .content_type in (
531 "message/rfc822",
532 "message/delivery-status",
533 "text/calendar"
534 )
535 )
536 or (
537 length(attachments) == 1
538 and all(attachments, .content_type in ("application/gzip"))
539 and regex.icontains(subject.subject,
540 '(?:(Report\sDomain).*(Submitter).*(Report-ID))'
541 )
542 )
543 )
544 )
545 and (
546 (
547 profile.by_sender().prevalence != "common"
548 and not profile.by_sender_email().solicited
549 )
550 or (
551 profile.by_sender().any_messages_malicious_or_spam
552 and not profile.by_sender().any_messages_benign
553 )
554 )
555 // negate highly trusted sender domains unless they fail DMARC authentication
556 and (
557 (
558 sender.email.domain.root_domain in $high_trust_sender_root_domains
559 and not headers.auth_summary.dmarc.pass
560 )
561 or sender.email.domain.root_domain not in $high_trust_sender_root_domains
562 )
563 // FP avoidance
564 and not any(ml.nlu_classifier(body.current_thread.text).topics,
565 .name in (
566 "Advertising and Promotions",
567 "Political Mail",
568 "News and Current Events",
569 "Newsletters and Digests"
570 )
571 and .confidence == "high"
572 )
573attack_types:
574 - "Credential Phishing"
575tactics_and_techniques:
576 - "Free email provider"
577 - "Social engineering"
578detection_methods:
579 - "Content analysis"
580 - "Header analysis"
581 - "Natural Language Understanding"
582 - "Sender analysis"
583 - "URL analysis"
584id: "c2bc8ca2-d207-5c7d-96e4-a0d3d33b2af5"