Credential phishing: Generic document share with unicode and proceedural greeting template

Detects messages that incorporate recipient-specific information (email domain, local part, domain elements or mailbox elements) alongside document-themed Unicode symbols and keywords. The rule identifies various targeting patterns including greeting-based personalization, attention-grabbing prefixes and multiple recipient elements. It also catches broken template attacks where recipient placeholders remain visible.

Sublime rule (View on GitHub)

  1name: "Credential phishing: Generic document share with unicode and proceedural greeting template"
  2description: "Detects messages that incorporate recipient-specific information (email domain, local part, domain elements or mailbox elements) alongside document-themed Unicode symbols and keywords. The rule identifies various targeting patterns including greeting-based personalization, attention-grabbing prefixes and multiple recipient elements. It also catches broken template attacks where recipient placeholders remain visible."
  3type: "rule"
  4severity: "low"
  5source: |
  6  type.inbound
  7  and (
  8    // nlu capture for wide scope of greetings to reduce evasion
  9    any(filter(ml.nlu_classifier(body.current_thread.text).entities,
 10               .name == "greeting"
 11        ),
 12        any([
 13              recipients.to[0].email.domain.sld,
 14              recipients.to[0].email.local_part,
 15              recipients.to[0].email.domain.domain,
 16              // "firstlast" naming convention observed
 17              strings.concat(mailbox.first_name, mailbox.last_name)
 18            ],
 19            // recipient entity follows the greeting in the body text
 20            strings.icontains(body.current_thread.text,
 21                              strings.concat(..text, " ", .)
 22            )
 23        )
 24    )
 25    or (
 26      // nlu capture for wide scope of greetings to reduce evasion
 27      any(filter(ml.nlu_classifier(body.current_thread.text).entities,
 28                 .name == "greeting"
 29          ),
 30          // nlu capture for wide scope of recipient entity to reduce evasion
 31          any(filter(ml.nlu_classifier(body.current_thread.text).entities,
 32                     .name == "recipient"
 33                     and not (
 34                       strings.icontains(.text, "customer")
 35                       // accounting for grouped recipients
 36                       or regex.icontains(.text, '&|\band\b')
 37                     )
 38              ),
 39              // recipient entity follows the greeting in the body text
 40              strings.icontains(body.current_thread.text,
 41                                strings.concat(..text, " ", .text)
 42              )
 43              // the named recipient doesn't match the actual "to" recipient
 44              and not any([
 45                            recipients.to[0].email.domain.sld,
 46                            recipients.to[0].email.local_part,
 47                            recipients.to[0].email.domain.domain,
 48                            mailbox.first_name,
 49                          ],
 50                          strings.icontains(..text, .)
 51              )
 52          )
 53      )
 54    )
 55    or any([
 56             recipients.to[0].email.domain.sld,
 57             recipients.to[0].email.local_part,
 58             recipients.to[0].email.domain.domain,
 59             // "firstlast" naming convention observed
 60             strings.concat(mailbox.first_name, mailbox.last_name)
 61           ],
 62           // strings logic for non-greeting body starter
 63           strings.icontains(body.current_thread.text,
 64                             strings.concat("attn: ", .)
 65           )
 66           // strings logic for recipient as body starter
 67           or strings.icontains(body.current_thread.text,
 68                                strings.concat(., " balance statement")
 69           )
 70    )
 71    // count of all recipient elements is 2 or greater
 72    or length(filter([
 73                       recipients.to[0].email.domain.sld,
 74                       recipients.to[0].email.local_part,
 75                       recipients.to[0].email.domain.domain,
 76                       // "firstlast" naming convention observed
 77                       strings.concat(mailbox.first_name, mailbox.last_name)
 78                     ],
 79                     strings.icontains(body.current_thread.text, .)
 80              )
 81    ) >= 2
 82  
 83    // logic for broken attack
 84    or any(ml.nlu_classifier(body.current_thread.text).entities,
 85           .name == "recipient" and regex.icontains(.text, '[{}]')
 86    )
 87  )
 88  
 89  // unicode + keyword generic template
 90  and (
 91    (
 92      (
 93        regex.icontains(body.current_thread.text,
 94                        '(?:\x{2710}|\x{270D}|\x{270E}|\x{270F}|\x{1F4C1}|\x{1F4C4}|\x{1F4D1}|\x{1F4DD})\n?.{0,15}(?:document|completion|remit|review|statement|agreement|shar(?:ed|ing)|receiv|\bmail\b)',
 95                        '(?:document|completion|remit|review|statement|agreement|shar(?:ed|ing)|receiv|\bmail\b)\n?.{0,15}(?:\x{2710}|\x{270D}|\x{270E}|\x{270F}|\x{1F4C1}|\x{1F4C4}|\x{1F4D1}|\x{1F4DD})'
 96        )
 97        // negate sharepoint paths with unicode
 98        and not any(body.links,
 99                    regex.icontains(.display_url.path,
100                                    '(?:\x{2710}|\x{270D}|\x{270E}|\x{270F}|\x{1F4C1}|\x{1F4C4}|\x{1F4D1}|\x{1F4DD})'
101                    )
102        )
103      )
104      // start of body is unicode & CTA button is present
105      or (
106        regex.icontains(body.current_thread.text,
107                        '^(?:\x{2710}|\x{270D}|\x{270E}|\x{270F}|\x{1F4C1}|\x{1F4C4}|\x{1F4D1}|\x{1F4DD})'
108        )
109        and any(body.links,
110                regex.icontains(.display_text,
111                                '(?:document|completion|remit|review|statement|agreement|shar(?:ed|ing)|receiv|\bmail\b)'
112                )
113        )
114      )
115    )
116  )
117  
118  // strings negations
119  and not regex.icontains(body.current_thread.text,
120                          'meeting (?:note|recap)|daily brief|brief recap'
121  )
122  
123  // nlu intent negation for FP's
124  and any(ml.nlu_classifier(body.current_thread.text).intents, .name != "benign")
125  
126  // nlu topic negations
127  and not any(ml.nlu_classifier(body.current_thread.text).topics,
128              .name in ("Software and App Updates", "B2B Cold Outreach")
129  )
130  
131  // negate multiple recipients unless undisclosed recipients
132  and not (
133    length(recipients.to) == 1
134    and (
135      (length(recipients.cc) != 0 or length(recipients.bcc) != 0)
136      // notification automation
137      and not any(recipients.bcc, .email.local_part == "notifications")
138    )
139    and not (
140      length(recipients.to) == 0
141      or all(recipients.to, .email.domain.valid == false)
142    )
143  )
144  
145  // negate highly trusted sender domains unless they fail DMARC authentication
146  and (
147    (
148      sender.email.domain.root_domain in $high_trust_sender_root_domains
149      and not coalesce(headers.auth_summary.dmarc.pass, false)
150    )
151    or sender.email.domain.root_domain not in $high_trust_sender_root_domains
152  )
153  
154  // negate legitimate conversations
155  and not (
156    (length(headers.references) > 0 or headers.in_reply_to is not null)
157    and (subject.is_forward or subject.is_reply)
158    and length(body.previous_threads) >= 1
159  )
160  
161  // sender negations
162  and not (
163    sender.email.domain.root_domain in (
164      "gc.ai",
165      "getguru.com",
166      "glean.com",
167      "mentorloop.com",
168    )
169    and coalesce(headers.auth_summary.dmarc.pass, false)
170  )  
171
172tags:
173  - "Attack surface reduction"
174attack_types:
175  - "BEC/Fraud"
176  - "Credential Phishing"
177tactics_and_techniques:
178  - "Social engineering"
179  - "Evasion"
180detection_methods:
181  - "Content analysis"
182  - "Natural Language Understanding"
183id: "f5bee657-53bc-501f-9b7a-ea51da73a716"

Related rules

to-top