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.imatch(subject.base, '[\x{4e00}-\x{9fff}].*')
219      and any(recipients.to, strings.iends_with(subject.base, .email.email))
220    )
221    or (
222      regex.icontains(sender.display_name,
223                      "Admin",
224                      "Administrator",
225                      "Alert",
226                      "Assistant",
227                      "Authenticat(or|ion)",
228                      "Billing",
229                      "Benefits",
230                      "Bonus",
231                      "CEO",
232                      "CFO",
233                      "CIO",
234                      "CTO",
235                      "Chairman",
236                      "Claim",
237                      "Confirm",
238                      "Cpanel Mail",
239                      "Critical",
240                      "Customer Service",
241                      "Deal",
242                      "Discount",
243                      "Director",
244                      "Exclusive",
245                      "Executive",
246                      "Fax",
247                      "Free",
248                      "Gift",
249                      '\bHR\b',
250                      "Helpdesk",
251                      "Human Resources",
252                      "Immediate",
253                      "Important",
254                      "Info",
255                      "Information",
256                      "Invoice",
257                      '\bIT\b',
258                      '\bLegal\b',
259                      "Lottery",
260                      "Management",
261                      "Manager",
262                      "Member Services",
263                      "Notification",
264                      "Offer",
265                      "Official Communication",
266                      "Operations",
267                      "Order",
268                      "Partner",
269                      "Payment",
270                      "Payroll",
271                      "Postmaster",
272                      "President",
273                      "Premium",
274                      "Prize",
275                      "Receipt",
276                      "Refund",
277                      "Registrar",
278                      "Required",
279                      "Reward",
280                      "Sales",
281                      "Secretary",
282                      "Security",
283                      "Server",
284                      "Service",
285                      "Storage",
286                      "Support",
287                      "Sweepstakes",
288                      "System",
289                      "Tax",
290                      "Tech Support",
291                      "Update",
292                      "Upgrade",
293                      "Urgent",
294                      "Validate",
295                      "Verify",
296                      "VIP",
297                      "Webmaster",
298                      "Winner",
299                      "DocReq\\b"
300      )
301      // add negation for common FPs in the sender display_name
302      and not strings.icontains(sender.display_name, "service bulletin")
303      and not strings.icontains(sender.display_name, "automotive service")
304    )
305  )
306  and (
307    4 of (
308      any(recipients.to,
309          .email.domain.valid
310          and (
311            strings.icontains(body.current_thread.text, .email.email)
312            or strings.icontains(body.current_thread.text, .email.local_part)
313          )
314      ),
315      any(ml.nlu_classifier(body.current_thread.text).intents,
316          .name == "cred_theft" and .confidence in ("medium", "high")
317      ),
318      any(ml.nlu_classifier(body.current_thread.text).entities,
319          .name == "request"
320      ),
321      (
322        any(body.current_thread.links,
323            strings.iends_with(.display_text, ".pdf")
324            and strings.istarts_with(.display_text, "view")
325        )
326      ),
327      // recipient email address base64 encoded in link
328      any(body.links,
329          any(strings.scan_base64(.href_url.url,
330                                  ignore_padding=true,
331                                  format="url"
332              ),
333              any(recipients.to, strings.icontains(.., .email.email))
334          )
335          or strings.decode_hex(.href_url.fragment) == recipients.to[0].email.email
336      ),
337      (
338        // freemail providers should never be sending this type of email
339        sender.email.domain.domain in $free_email_providers
340  
341        // if not freemail, it's suspicious if the sender's root domain
342        // doesn't match any links in the body
343        or all(body.links,
344               .href_url.domain.root_domain != sender.email.domain.root_domain
345               and (
346                 .href_url.domain.root_domain not in $org_domains
347                 // ignore recipient email addresses in the body in relation to this check
348                 or (
349                   .href_url.domain.root_domain in $org_domains
350                   and any(recipients.to,
351                           strings.icount(body.current_thread.text, .email.email) == strings.icount(body.current_thread.text,
352                                                                                                    .email.domain.domain
353                           )
354                   )
355                 )
356               )
357        )
358  
359        // bulk mailers should also never be sending this type of email
360        or all(filter(body.links,
361                      .href_url.domain.domain not in (
362                        "aka.ms",
363                        "mimecast.com",
364                        "mimecastprotect.com",
365                        "cisco.com"
366                      )
367               ),
368               .href_url.domain.root_domain in $bulk_mailer_url_root_domains
369        )
370      ),
371      // in case it's embedded in an image attachment
372      // note: don't use message_screenshot() because it's not limited to current_thread
373      // and may FP
374      any(attachments,
375          .file_type in $file_types_images
376          and any(file.explode(.),
377                  any(ml.nlu_classifier(.scan.ocr.raw).intents,
378                      .name == "cred_theft" and .confidence == "high"
379                  )
380          )
381      ),
382      strings.contains(body.current_thread.text,
383                       "Your mailbox can no longer send or receive messages."
384      ),
385      strings.contains(body.current_thread.text,
386                       "this invoice has been overlooked"
387      ),
388      any(body.links,
389          strings.icontains(.href_url.query_params, 'redirect')
390          or any(.href_url.rewrite.encoders,
391                 strings.icontains(., "open_redirect")
392          )
393      ),
394      // multiple entities displaying urgency
395      length(filter(ml.nlu_classifier(body.current_thread.text).entities,
396                    .name == "urgency"
397             )
398      ) >= 2
399      // and any body links
400      and any(body.links,
401              // display text contains a request
402              any(ml.nlu_classifier(.display_text).entities, .name == "request")
403      ),
404      any(body.links,
405          strings.iends_with(.href_url.path, '.html')
406          and strings.parse_email(strings.decode_base64(.href_url.fragment)).domain.valid
407      ),
408      (
409        any(body.links,
410            .href_url.domain.root_domain in $self_service_creation_platform_domains
411        )
412        and any(ml.nlu_classifier(body.current_thread.text).tags,
413                .name == "invoice" and .confidence == "high"
414        )
415      ),
416      any(body.links,
417          // display text contains a request
418          (
419            any(ml.nlu_classifier(.display_text).entities, .name == "request")
420            or regex.match(.display_text, '^[^a-z]+$')
421          )
422          and (
423            .href_url.domain.domain in $url_shorteners
424            or .href_url.domain.domain in $social_landing_hosts
425            or .href_url.domain.root_domain in $url_shorteners
426            or .href_url.domain.root_domain in $social_landing_hosts
427            or .href_url.domain.domain in $free_file_hosts
428            or (
429              .href_url.domain.root_domain in (
430                "mimecast.com",
431                "mimecastprotect.com"
432              )
433              and any(.href_url.query_params_decoded['domain'],
434                      strings.parse_url(strings.concat("https://", .)).domain.domain in $url_shorteners
435                      or strings.parse_url(strings.concat("https://", .)).domain.root_domain in $url_shorteners
436                      or strings.parse_url(strings.concat("https://", .)).domain.domain in $free_file_hosts
437                      or strings.parse_url(strings.concat("https://", .)).domain.root_domain in $free_subdomain_hosts
438                      or strings.parse_url(strings.concat("https://", .)).domain.domain in $social_landing_hosts
439                      or strings.parse_url(strings.concat("https://", .)).domain.root_domain in $social_landing_hosts
440              )
441            )
442          )
443      ),
444      // common greetings via email.local_part
445      any(recipients.to,
446          length(.email.local_part) > 2
447          and 
448          // use count to ensure the email address is not part of a disclaimer
449          strings.icount(body.current_thread.text, .email.local_part) > 
450          // sum allows us to add more logic as needed
451          strings.icount(body.current_thread.text,
452                         strings.concat('was sent to ', .email.email)
453          ) + strings.icount(body.current_thread.text,
454                             strings.concat('intended for ', .email.email)
455          )
456      )
457    )
458    or (
459      (
460        // recipient's email address is in the body
461        any(recipients.to,
462            // use count to ensure the email address is not part of a disclaimer
463            strings.icount(body.current_thread.text, .email.email) > 
464            // sum allows us to add more logic as needed
465            sum([
466                  strings.icount(body.current_thread.text,
467                                 strings.concat('was sent to ', .email.email)
468                  ),
469                  strings.icount(body.current_thread.text,
470                                 strings.concat('intended for ', .email.email)
471                  )
472                ]
473            )
474        )
475        // suspicious display text
476        or (
477          length(body.links) == 1
478          and all(body.links,
479                  strings.ilike(.display_text, "*click here*", "*password*")
480          )
481        )
482      )
483      // link leads to a suspicious TLD or contains an IP address or contains multiple redirects
484      and (
485        any(body.links,
486            any([ml.link_analysis(., mode="aggressive")],
487                .effective_url.domain.tld in $suspicious_tlds
488                or length(distinct(map(.redirect_history, .domain.root_domain))) >= 4
489            )
490        )
491        or any(body.ips, any(body.links, strings.icontains(.href_url.url, ..ip)))
492      )
493    )
494  )
495  // exclude Google shared calendar messages
496  // Subject: "<sender name> has shared a calendar with you"
497  and headers.return_path.domain.domain != "calendar-server.bounces.google.com"
498  // negate calendar invites
499  and not (
500    0 < length(attachments) < 3
501    and all(attachments, .content_type in ("text/calendar", "application/ics"))
502  )
503  // negate replies
504  and (
505    (
506      (length(headers.references) > 0 or headers.in_reply_to is null)
507      and not (
508        (
509          strings.istarts_with(subject.subject, "RE:")
510          or strings.istarts_with(subject.subject, "R:")
511          or strings.istarts_with(subject.subject, "ODG:")
512          or strings.istarts_with(subject.subject, "答复:")
513          or strings.istarts_with(subject.subject, "AW:")
514          or strings.istarts_with(subject.subject, "TR:")
515          or strings.istarts_with(subject.subject, "FWD:")
516          or regex.imatch(subject.subject, '(\[[^\]]+\]\s?){0,3}(re|fwd?)\s?:.*')
517        )
518      )
519    )
520    or length(headers.references) == 0
521  )
522  // bounce-back and DMARC report negations
523  and not (
524    strings.like(sender.email.local_part,
525                 "*postmaster*",
526                 "*mailer-daemon*",
527                 "*administrator*"
528    )
529    and (
530      any(attachments,
531          .content_type in (
532            "message/rfc822",
533            "message/delivery-status",
534            "text/calendar"
535          )
536      )
537      or (
538        length(attachments) == 1
539        and all(attachments, .content_type in ("application/gzip"))
540        and regex.icontains(subject.subject,
541                            '(?:(Report\sDomain).*(Submitter).*(Report-ID))'
542        )
543      )
544    )
545  )
546  and (
547    (
548      profile.by_sender().prevalence != "common"
549      and not profile.by_sender_email().solicited
550    )
551    or (
552      profile.by_sender().any_messages_malicious_or_spam
553      and not profile.by_sender().any_messages_benign
554    )
555  )
556  // negate highly trusted sender domains unless they fail DMARC authentication
557  and not (
558    sender.email.domain.root_domain in $high_trust_sender_root_domains
559    and coalesce(headers.auth_summary.dmarc.pass, false)
560  )
561  // FP avoidance
562  and not any(ml.nlu_classifier(body.current_thread.text).topics,
563              .name in (
564                "Advertising and Promotions",
565                "Political Mail",
566                "News and Current Events",
567                "Newsletters and Digests"
568              )
569              and .confidence == "high"
570  )  
571attack_types:
572  - "Credential Phishing"
573tactics_and_techniques:
574  - "Free email provider"
575  - "Social engineering"
576detection_methods:
577  - "Content analysis"
578  - "Header analysis"
579  - "Natural Language Understanding"
580  - "Sender analysis"
581  - "URL analysis"
582id: "c2bc8ca2-d207-5c7d-96e4-a0d3d33b2af5"
to-top