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