EXPLORE
← Back to Explore
sublimelowRule

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.

MITRE ATT&CK

initial-accessdefense-evasion

Detection Query

type.inbound
and (
  // nlu capture for wide scope of greetings to reduce evasion
  any(filter(ml.nlu_classifier(body.current_thread.text).entities,
             .name == "greeting"
      ),
      any([
            recipients.to[0].email.domain.sld,
            recipients.to[0].email.local_part,
            recipients.to[0].email.domain.domain,
            // "firstlast" naming convention observed
            strings.concat(mailbox.first_name, mailbox.last_name)
          ],
          // recipient entity follows the greeting in the body text
          strings.icontains(body.current_thread.text,
                            strings.concat(..text, " ", .)
          )
      )
  )
  or (
    // nlu capture for wide scope of greetings to reduce evasion
    any(filter(ml.nlu_classifier(body.current_thread.text).entities,
               .name == "greeting"
        ),
        // nlu capture for wide scope of recipient entity to reduce evasion
        any(filter(ml.nlu_classifier(body.current_thread.text).entities,
                   .name == "recipient"
                   and not (
                     strings.icontains(.text, "customer")
                     // accounting for grouped recipients
                     or regex.icontains(.text, '&|\band\b')
                   )
            ),
            // recipient entity follows the greeting in the body text
            strings.icontains(body.current_thread.text,
                              strings.concat(..text, " ", .text)
            )
            // the named recipient doesn't match the actual "to" recipient
            and not any([
                          recipients.to[0].email.domain.sld,
                          recipients.to[0].email.local_part,
                          recipients.to[0].email.domain.domain,
                          mailbox.first_name,
                        ],
                        strings.icontains(..text, .)
            )
        )
    )
  )
  or any([
           recipients.to[0].email.domain.sld,
           recipients.to[0].email.local_part,
           recipients.to[0].email.domain.domain,
           // "firstlast" naming convention observed
           strings.concat(mailbox.first_name, mailbox.last_name)
         ],
         // strings logic for non-greeting body starter
         strings.icontains(body.current_thread.text,
                           strings.concat("attn: ", .)
         )
         // strings logic for recipient as body starter
         or strings.icontains(body.current_thread.text,
                              strings.concat(., " balance statement")
         )
  )
  // count of all recipient elements is 2 or greater
  or length(filter([
                     recipients.to[0].email.domain.sld,
                     recipients.to[0].email.local_part,
                     recipients.to[0].email.domain.domain,
                     // "firstlast" naming convention observed
                     strings.concat(mailbox.first_name, mailbox.last_name)
                   ],
                   strings.icontains(body.current_thread.text, .)
            )
  ) >= 2

  // logic for broken attack
  or any(ml.nlu_classifier(body.current_thread.text).entities,
         .name == "recipient" and regex.icontains(.text, '[{}]')
  )
)

// unicode + keyword generic template
and (
  (
    (
      regex.icontains(body.current_thread.text,
                      '(?:\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)',
                      '(?: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})'
      )
      // negate sharepoint paths with unicode
      and not any(body.links,
                  regex.icontains(.display_url.path,
                                  '(?:\x{2710}|\x{270D}|\x{270E}|\x{270F}|\x{1F4C1}|\x{1F4C4}|\x{1F4D1}|\x{1F4DD})'
                  )
      )
    )
    // start of body is unicode & CTA button is present
    or (
      regex.icontains(body.current_thread.text,
                      '^(?:\x{2710}|\x{270D}|\x{270E}|\x{270F}|\x{1F4C1}|\x{1F4C4}|\x{1F4D1}|\x{1F4DD})'
      )
      and any(body.links,
              regex.icontains(.display_text,
                              '(?:document|completion|remit|review|statement|agreement|shar(?:ed|ing)|receiv|\bmail\b)'
              )
      )
    )
  )
)

// strings negations
and not regex.icontains(body.current_thread.text,
                        'meeting (?:note|recap)|daily brief|brief recap'
)

// nlu intent negation for FP's
and any(ml.nlu_classifier(body.current_thread.text).intents, .name != "benign")

// nlu topic negations
and not any(ml.nlu_classifier(body.current_thread.text).topics,
            .name in ("Software and App Updates", "B2B Cold Outreach")
)

// negate multiple recipients unless undisclosed recipients
and not (
  length(recipients.to) == 1
  and (
    (length(recipients.cc) != 0 or length(recipients.bcc) != 0)
    // notification automation
    and not any(recipients.bcc, .email.local_part == "notifications")
  )
  and not (
    length(recipients.to) == 0
    or all(recipients.to, .email.domain.valid == false)
  )
)

// negate highly trusted sender domains unless they fail DMARC authentication
and (
  (
    sender.email.domain.root_domain in $high_trust_sender_root_domains
    and not coalesce(headers.auth_summary.dmarc.pass, false)
  )
  or sender.email.domain.root_domain not in $high_trust_sender_root_domains
)

// negate legitimate conversations
and not (
  (length(headers.references) > 0 or headers.in_reply_to is not null)
  and (subject.is_forward or subject.is_reply)
  and length(body.previous_threads) >= 1
)

// sender negations
and not (
  sender.email.domain.root_domain in (
    "gc.ai",
    "getguru.com",
    "glean.com",
    "mentorloop.com",
  )
  and coalesce(headers.auth_summary.dmarc.pass, false)
)

Data Sources

Email MessagesEmail HeadersEmail Attachments

Platforms

email

Tags

Attack surface reduction
Raw Content
name: "Credential phishing: Generic document share with unicode and proceedural greeting template"
description: "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."
type: "rule"
severity: "low"
source: |
  type.inbound
  and (
    // nlu capture for wide scope of greetings to reduce evasion
    any(filter(ml.nlu_classifier(body.current_thread.text).entities,
               .name == "greeting"
        ),
        any([
              recipients.to[0].email.domain.sld,
              recipients.to[0].email.local_part,
              recipients.to[0].email.domain.domain,
              // "firstlast" naming convention observed
              strings.concat(mailbox.first_name, mailbox.last_name)
            ],
            // recipient entity follows the greeting in the body text
            strings.icontains(body.current_thread.text,
                              strings.concat(..text, " ", .)
            )
        )
    )
    or (
      // nlu capture for wide scope of greetings to reduce evasion
      any(filter(ml.nlu_classifier(body.current_thread.text).entities,
                 .name == "greeting"
          ),
          // nlu capture for wide scope of recipient entity to reduce evasion
          any(filter(ml.nlu_classifier(body.current_thread.text).entities,
                     .name == "recipient"
                     and not (
                       strings.icontains(.text, "customer")
                       // accounting for grouped recipients
                       or regex.icontains(.text, '&|\band\b')
                     )
              ),
              // recipient entity follows the greeting in the body text
              strings.icontains(body.current_thread.text,
                                strings.concat(..text, " ", .text)
              )
              // the named recipient doesn't match the actual "to" recipient
              and not any([
                            recipients.to[0].email.domain.sld,
                            recipients.to[0].email.local_part,
                            recipients.to[0].email.domain.domain,
                            mailbox.first_name,
                          ],
                          strings.icontains(..text, .)
              )
          )
      )
    )
    or any([
             recipients.to[0].email.domain.sld,
             recipients.to[0].email.local_part,
             recipients.to[0].email.domain.domain,
             // "firstlast" naming convention observed
             strings.concat(mailbox.first_name, mailbox.last_name)
           ],
           // strings logic for non-greeting body starter
           strings.icontains(body.current_thread.text,
                             strings.concat("attn: ", .)
           )
           // strings logic for recipient as body starter
           or strings.icontains(body.current_thread.text,
                                strings.concat(., " balance statement")
           )
    )
    // count of all recipient elements is 2 or greater
    or length(filter([
                       recipients.to[0].email.domain.sld,
                       recipients.to[0].email.local_part,
                       recipients.to[0].email.domain.domain,
                       // "firstlast" naming convention observed
                       strings.concat(mailbox.first_name, mailbox.last_name)
                     ],
                     strings.icontains(body.current_thread.text, .)
              )
    ) >= 2
  
    // logic for broken attack
    or any(ml.nlu_classifier(body.current_thread.text).entities,
           .name == "recipient" and regex.icontains(.text, '[{}]')
    )
  )
  
  // unicode + keyword generic template
  and (
    (
      (
        regex.icontains(body.current_thread.text,
                        '(?:\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)',
                        '(?: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})'
        )
        // negate sharepoint paths with unicode
        and not any(body.links,
                    regex.icontains(.display_url.path,
                                    '(?:\x{2710}|\x{270D}|\x{270E}|\x{270F}|\x{1F4C1}|\x{1F4C4}|\x{1F4D1}|\x{1F4DD})'
                    )
        )
      )
      // start of body is unicode & CTA button is present
      or (
        regex.icontains(body.current_thread.text,
                        '^(?:\x{2710}|\x{270D}|\x{270E}|\x{270F}|\x{1F4C1}|\x{1F4C4}|\x{1F4D1}|\x{1F4DD})'
        )
        and any(body.links,
                regex.icontains(.display_text,
                                '(?:document|completion|remit|review|statement|agreement|shar(?:ed|ing)|receiv|\bmail\b)'
                )
        )
      )
    )
  )
  
  // strings negations
  and not regex.icontains(body.current_thread.text,
                          'meeting (?:note|recap)|daily brief|brief recap'
  )
  
  // nlu intent negation for FP's
  and any(ml.nlu_classifier(body.current_thread.text).intents, .name != "benign")
  
  // nlu topic negations
  and not any(ml.nlu_classifier(body.current_thread.text).topics,
              .name in ("Software and App Updates", "B2B Cold Outreach")
  )
  
  // negate multiple recipients unless undisclosed recipients
  and not (
    length(recipients.to) == 1
    and (
      (length(recipients.cc) != 0 or length(recipients.bcc) != 0)
      // notification automation
      and not any(recipients.bcc, .email.local_part == "notifications")
    )
    and not (
      length(recipients.to) == 0
      or all(recipients.to, .email.domain.valid == false)
    )
  )
  
  // negate highly trusted sender domains unless they fail DMARC authentication
  and (
    (
      sender.email.domain.root_domain in $high_trust_sender_root_domains
      and not coalesce(headers.auth_summary.dmarc.pass, false)
    )
    or sender.email.domain.root_domain not in $high_trust_sender_root_domains
  )
  
  // negate legitimate conversations
  and not (
    (length(headers.references) > 0 or headers.in_reply_to is not null)
    and (subject.is_forward or subject.is_reply)
    and length(body.previous_threads) >= 1
  )
  
  // sender negations
  and not (
    sender.email.domain.root_domain in (
      "gc.ai",
      "getguru.com",
      "glean.com",
      "mentorloop.com",
    )
    and coalesce(headers.auth_summary.dmarc.pass, false)
  )

tags:
  - "Attack surface reduction"
attack_types:
  - "BEC/Fraud"
  - "Credential Phishing"
tactics_and_techniques:
  - "Social engineering"
  - "Evasion"
detection_methods:
  - "Content analysis"
  - "Natural Language Understanding"
id: "f5bee657-53bc-501f-9b7a-ea51da73a716"