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"
to-top