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                    '\bid:\s[a-z0-9]{14,16}(?:\s|$)',
143                    // https://github.com/sublime-security/static-files/blob/main/suspicious_subjects.txt
144                    "account has been limited",
145                    "action required",
146                    "almost full",
147                    "apd notifi cation",
148                    "are you at your desk",
149                    "are you available",
150                    "attached file to docusign",
151                    "banking is temporarily unavailable",
152                    "bankofamerica",
153                    "closing statement invoice",
154                    "completed: docusign",
155                    "de-activation of",
156                    "delivery attempt",
157                    "delivery stopped for shipment",
158                    "detected suspicious",
159                    "detected suspicious actvity",
160                    "docu sign",
161                    "document for you",
162                    "document has been sent to you via docusign",
163                    "document is ready for signature",
164                    "docusign",
165                    "encrypted message",
166                    "failed delivery",
167                    "fedex tracking",
168                    "file was shared",
169                    "freefax",
170                    "fwd: due invoice paid",
171                    "has shared",
172                    "inbox is full",
173                    "invitation to comment",
174                    "invitation to edit",
175                    "invoice due",
176                    "left you a message",
177                    "message from",
178                    "new message",
179                    "new voicemail",
180                    "on desk",
181                    "out of space",
182                    "password reset",
183                    "payment status",
184                    "pay notification",
185                    "quick reply",
186                    "re: w-2",
187                    "required",
188                    "required: completed docusign",
189                    "remittance",
190                    "ringcentral",
191                    "scanned image",
192                    "secured files",
193                    "secured pdf",
194                    "security alert",
195                    "new sign-in",
196                    "new sign in",
197                    "sign-in attempt",
198                    "sign in attempt",
199                    "staff review",
200                    "suspicious activity",
201                    "unrecognized login attempt",
202                    "unusual signin",
203                    "upgrade immediately",
204                    "urgent",
205                    "wants to share",
206                    "w2",
207                    "you have notifications pending",
208                    "your account",
209                    "your amazon order",
210                    "your document settlement",
211                    "your order with amazon",
212                    "your password has been compromised"
213    )
214    or (
215      regex.icontains(subject.subject, 'account.has.been')
216      and not regex.icontains(subject.subject, 'account.has.been.*created')
217    )
218    or (
219      regex.imatch(subject.base, '[\x{4e00}-\x{9fff}].*')
220      and any(recipients.to, strings.iends_with(subject.base, .email.email))
221    )
222    or (
223      regex.icontains(sender.display_name,
224                      "Admin",
225                      "Administrator",
226                      "Alert",
227                      "Assistant",
228                      "Authenticat(or|ion)",
229                      "Billing",
230                      "Benefits",
231                      "Bonus",
232                      "CEO",
233                      "CFO",
234                      "CIO",
235                      "CTO",
236                      "Chairman",
237                      "Claim",
238                      "Confirm",
239                      "Cpanel Mail",
240                      "Critical",
241                      "Customer Service",
242                      "Deal",
243                      "Discount",
244                      "Director",
245                      "Exclusive",
246                      "Executive",
247                      "Fax",
248                      "Free",
249                      "Gift",
250                      '\bHR\b',
251                      "Helpdesk",
252                      "Human Resources",
253                      "Immediate",
254                      "Important",
255                      "Info",
256                      "Information",
257                      "Invoice",
258                      '\bIT\b',
259                      '\bLegal\b',
260                      "Lottery",
261                      "Management",
262                      "Manager",
263                      "Member Services",
264                      "Notification",
265                      "Offer",
266                      "Official Communication",
267                      "Operations",
268                      "Order",
269                      "Partner",
270                      "Payment",
271                      "Payroll",
272                      "Postmaster",
273                      "President",
274                      "Premium",
275                      "Prize",
276                      "Receipt",
277                      "Refund",
278                      "Registrar",
279                      "Required",
280                      "Reward",
281                      "Sales",
282                      "Secretary",
283                      "Security",
284                      "Server",
285                      "Service",
286                      "Storage",
287                      "Support",
288                      "Sweepstakes",
289                      "System",
290                      "Tax",
291                      "Tech Support",
292                      "Update",
293                      "Upgrade",
294                      "Urgent",
295                      "Validate",
296                      "Verify",
297                      "VIP",
298                      "Webmaster",
299                      "Winner",
300                      "DocReq\\b"
301      )
302      // add negation for common FPs in the sender display_name
303      and not strings.icontains(sender.display_name, "service bulletin")
304      and not strings.icontains(sender.display_name, "automotive service")
305    )
306  )
307  and (
308    4 of (
309      any(recipients.to,
310          .email.domain.valid
311          and (
312            strings.icontains(body.current_thread.text, .email.email)
313            or strings.icontains(body.current_thread.text, .email.local_part)
314          )
315      ),
316      any(ml.nlu_classifier(body.current_thread.text).intents,
317          .name == "cred_theft" and .confidence in ("medium", "high")
318      ),
319      any(ml.nlu_classifier(body.current_thread.text).entities,
320          .name == "request"
321      ),
322      (
323        any(body.current_thread.links,
324            strings.iends_with(.display_text, ".pdf")
325            and strings.istarts_with(.display_text, "view")
326        )
327      ),
328      // recipient email address base64 encoded in link
329      any(body.links,
330          any(strings.scan_base64(.href_url.url,
331                                  ignore_padding=true,
332                                  format="url"
333              ),
334              any(recipients.to, strings.icontains(.., .email.email))
335          )
336          or strings.decode_hex(.href_url.fragment) == recipients.to[0].email.email
337      ),
338      any(body.links, regex.icontains(.href_url.path, '/~[a-z0-9]+/')),
339      (
340        // freemail providers should never be sending this type of email
341        sender.email.domain.domain in $free_email_providers
342  
343        // if not freemail, it's suspicious if the sender's root domain
344        // doesn't match any links in the body
345        or all(body.links,
346               .href_url.domain.root_domain != sender.email.domain.root_domain
347               and (
348                 .href_url.domain.root_domain not in $org_domains
349                 // ignore recipient email addresses in the body in relation to this check
350                 or (
351                   .href_url.domain.root_domain in $org_domains
352                   and any(recipients.to,
353                           strings.icount(body.current_thread.text, .email.email) == strings.icount(body.current_thread.text,
354                                                                                                    .email.domain.domain
355                           )
356                   )
357                 )
358               )
359        )
360  
361        // bulk mailers should also never be sending this type of email
362        or all(filter(body.links,
363                      .href_url.domain.domain not in (
364                        "aka.ms",
365                        "mimecast.com",
366                        "mimecastprotect.com",
367                        "cisco.com"
368                      )
369               ),
370               .href_url.domain.root_domain in $bulk_mailer_url_root_domains
371        )
372      ),
373      // in case it's embedded in an image attachment
374      // note: don't use message_screenshot() because it's not limited to current_thread
375      // and may FP
376      any(attachments,
377          .file_type in $file_types_images
378          and any(file.explode(.),
379                  any(ml.nlu_classifier(.scan.ocr.raw).intents,
380                      .name == "cred_theft" and .confidence == "high"
381                  )
382          )
383      ),
384      strings.contains(body.current_thread.text,
385                       "Your mailbox can no longer send or receive messages."
386      ),
387      strings.contains(body.current_thread.text,
388                       "this invoice has been overlooked"
389      ),
390      any(body.links,
391          strings.icontains(.href_url.query_params, 'redirect')
392          or any(.href_url.rewrite.encoders,
393                 strings.icontains(., "open_redirect")
394          )
395      ),
396      // multiple entities displaying urgency
397      length(filter(ml.nlu_classifier(body.current_thread.text).entities,
398                    .name == "urgency"
399             )
400      ) >= 2
401      // and any body links
402      and any(body.links,
403              // display text contains a request
404              any(ml.nlu_classifier(.display_text).entities, .name == "request")
405      ),
406      any(body.links,
407          strings.iends_with(.href_url.path, '.html')
408          and strings.parse_email(strings.decode_base64(.href_url.fragment)).domain.valid
409      ),
410      (
411        any(body.links,
412            .href_url.domain.root_domain in $self_service_creation_platform_domains
413        )
414        and any(ml.nlu_classifier(body.current_thread.text).tags,
415                .name == "invoice" and .confidence == "high"
416        )
417      ),
418      any(body.links,
419          // display text contains a request
420          (
421            any(ml.nlu_classifier(.display_text).entities, .name == "request")
422            or regex.match(.display_text, '^[^a-z]+$')
423          )
424          and (
425            .href_url.domain.domain in $url_shorteners
426            or .href_url.domain.domain in $social_landing_hosts
427            or .href_url.domain.root_domain in $url_shorteners
428            or .href_url.domain.root_domain in $social_landing_hosts
429            or .href_url.domain.domain in $free_file_hosts
430            or (
431              .href_url.domain.root_domain in (
432                "mimecast.com",
433                "mimecastprotect.com"
434              )
435              and any(.href_url.query_params_decoded['domain'],
436                      strings.parse_url(strings.concat("https://", .)).domain.domain in $url_shorteners
437                      or strings.parse_url(strings.concat("https://", .)).domain.root_domain in $url_shorteners
438                      or strings.parse_url(strings.concat("https://", .)).domain.domain in $free_file_hosts
439                      or strings.parse_url(strings.concat("https://", .)).domain.root_domain in $free_subdomain_hosts
440                      or strings.parse_url(strings.concat("https://", .)).domain.domain in $social_landing_hosts
441                      or strings.parse_url(strings.concat("https://", .)).domain.root_domain in $social_landing_hosts
442              )
443            )
444          )
445      ),
446      // common greetings via email.local_part
447      any(recipients.to,
448          length(.email.local_part) > 2
449          and 
450          // use count to ensure the email address is not part of a disclaimer
451          strings.icount(body.current_thread.text, .email.local_part) > 
452          // sum allows us to add more logic as needed
453          strings.icount(body.current_thread.text,
454                         strings.concat('was sent to ', .email.email)
455          ) + strings.icount(body.current_thread.text,
456                             strings.concat('intended for ', .email.email)
457          )
458      )
459    )
460    or (
461      (
462        // recipient's email address is in the body
463        any(recipients.to,
464            // use count to ensure the email address is not part of a disclaimer
465            strings.icount(body.current_thread.text, .email.email) > 
466            // sum allows us to add more logic as needed
467            sum([
468                  strings.icount(body.current_thread.text,
469                                 strings.concat('was sent to ', .email.email)
470                  ),
471                  strings.icount(body.current_thread.text,
472                                 strings.concat('intended for ', .email.email)
473                  )
474                ]
475            )
476        )
477        // suspicious display text
478        or (
479          length(body.links) == 1
480          and all(body.links,
481                  strings.ilike(.display_text, "*click here*", "*password*")
482          )
483        )
484      )
485      // link leads to a suspicious TLD or contains an IP address or contains multiple redirects
486      and (
487        any(body.links,
488            any([ml.link_analysis(., mode="aggressive")],
489                .effective_url.domain.tld in $suspicious_tlds
490                or length(distinct(map(.redirect_history, .domain.root_domain))) >= 4
491            )
492        )
493        or any(body.ips, any(body.links, strings.icontains(.href_url.url, ..ip)))
494      )
495    )
496  )
497  // exclude Google shared calendar messages
498  // Subject: "<sender name> has shared a calendar with you"
499  and headers.return_path.domain.domain != "calendar-server.bounces.google.com"
500  // negate calendar invites
501  and not (
502    0 < length(attachments) < 3
503    and all(attachments, .content_type in ("text/calendar", "application/ics"))
504  )
505  // negate replies
506  and (
507    (
508      (length(headers.references) > 0 or headers.in_reply_to is null)
509      and not (
510        (
511          strings.istarts_with(subject.subject, "RE:")
512          or strings.istarts_with(subject.subject, "R:")
513          or strings.istarts_with(subject.subject, "ODG:")
514          or strings.istarts_with(subject.subject, "答复:")
515          or strings.istarts_with(subject.subject, "AW:")
516          or strings.istarts_with(subject.subject, "TR:")
517          or strings.istarts_with(subject.subject, "FWD:")
518          or regex.imatch(subject.subject, '(\[[^\]]+\]\s?){0,3}(re|fwd?)\s?:.*')
519        )
520      )
521    )
522    or length(headers.references) == 0
523  )
524  // bounce-back and DMARC report negations
525  and not (
526    strings.like(sender.email.local_part,
527                 "*postmaster*",
528                 "*mailer-daemon*",
529                 "*administrator*"
530    )
531    and (
532      any(attachments,
533          .content_type in (
534            "message/rfc822",
535            "message/delivery-status",
536            "text/calendar"
537          )
538      )
539      or (
540        length(attachments) == 1
541        and all(attachments, .content_type in ("application/gzip"))
542        and regex.icontains(subject.subject,
543                            '(?:(Report\sDomain).*(Submitter).*(Report-ID))'
544        )
545      )
546    )
547  )
548  and (
549    (
550      profile.by_sender().prevalence != "common"
551      and not profile.by_sender_email().solicited
552    )
553    or (
554      profile.by_sender().any_messages_malicious_or_spam
555      and not profile.by_sender().any_messages_benign
556    )
557  )
558  // negate highly trusted sender domains unless they fail DMARC authentication
559  and not (
560    sender.email.domain.root_domain in $high_trust_sender_root_domains
561    and coalesce(headers.auth_summary.dmarc.pass, false)
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"
to-top