Credential phishing: 'Secure message' and engaging language

Body contains language resembling credential theft, and a "secure message" from an untrusted sender.

Sublime rule (View on GitHub)

  1name: "Credential phishing: 'Secure message' and engaging language"
  2description: |
  3    Body contains language resembling credential theft, and a "secure message" from an untrusted sender.
  4type: "rule"
  5severity: "medium"
  6source: |
  7  type.inbound
  8  and (
  9    (
 10      any(ml.nlu_classifier(body.current_thread.text).intents,
 11          .name == "cred_theft" and .confidence == "high"
 12      )
 13      or any(body.current_thread.links,
 14             regex.icontains(.display_text, '(?:read|view|open) the message')
 15             and (
 16               .href_url.domain.root_domain not in $tranco_1m
 17               or .href_url.domain.domain in $free_file_hosts
 18               or .href_url.domain.root_domain in $free_file_hosts
 19               or .href_url.domain.root_domain in $free_subdomain_hosts
 20               or .href_url.domain.domain in $url_shorteners
 21               or .href_url.domain.domain in $social_landing_hosts
 22             )
 23      )
 24    )
 25    or any(ml.nlu_classifier(beta.ocr(file.message_screenshot()).text).intents,
 26           .name == "cred_theft" and .confidence in ("medium", "high")
 27    )
 28  )
 29  and (
 30    (
 31      regex.icontains(body.current_thread.text,
 32                      "secured? (message|directory|document|file)"
 33      )
 34      or regex.icontains(subject.base,
 35                         "secured? (message|directory|document|file)"
 36      )
 37      or strings.icontains(body.current_thread.text, "document portal")
 38      or strings.icontains(body.current_thread.text, "encrypted message")
 39      or strings.icontains(body.current_thread.text, "protected message")
 40    )
 41    or any(body.previous_threads,
 42           regex.icontains(.text, "secured? (message|directory|document|file)")
 43           or strings.icontains(.text, "document portal")
 44           or strings.icontains(.text, "encrypted message")
 45           or strings.icontains(.text, "protected message")
 46    )
 47    or any(body.current_thread.links,
 48           regex.icontains(ml.link_analysis(.).final_dom.display_text,
 49                           'secured? (?:message|directory|document|file) access'
 50           )
 51           or regex.icontains(ml.link_analysis(.).final_dom.inner_text,
 52                              'secured? (?:message|directory|document|file) access'
 53           )
 54    )
 55    or (
 56      (
 57        length(filter(ml.nlu_classifier(body.current_thread.text).entities,
 58                      .name == "urgency"
 59               )
 60        ) >= 2
 61        // two-step instructions
 62        or (
 63          strings.icontains(body.current_thread.text, "view your message")
 64          and strings.icontains(body.current_thread.text, "after that,")
 65        )
 66      )
 67      and any(ml.nlu_classifier(body.current_thread.text).topics,
 68              .name == "Secure Message" and .confidence != "low"
 69      )
 70    )
 71  )
 72  // has at least 1 link
 73  and length(body.links) > 0
 74  
 75  // negate legitimate message senders
 76  and (
 77    sender.email.domain.root_domain not in ("protectedtrust.com")
 78    and any(body.links,
 79            .href_url.domain.root_domain != sender.email.domain.root_domain
 80    )
 81    // negate known secure mailers
 82    and not all(body.links,
 83                .href_url.domain.root_domain in (
 84                  "mimecast.com",
 85                  "cisco.com",
 86                  "csiesafe.com"
 87                )
 88    )
 89    and any(headers.hops,
 90            .index == 0
 91            and not any(.fields,
 92                        strings.contains(.value,
 93                                         'multipart/mixed; boundary="PROOFPOINT_BOUNDARY_1"'
 94                        )
 95            )
 96    )
 97    and not (
 98      length(filter(attachments,
 99                    strings.ilike(.file_name,
100                                  "logo.*",
101                                  "lock.gif",
102                                  "SecureMessageAtt.html"
103                    )
104             )
105      ) == 3
106      and any(attachments,
107              .file_type == "html"
108              and any(file.explode(.),
109                      .scan.html.title == "Proofpoint Encryption"
110                      and any(.scan.url.urls,
111                              strings.iends_with(.path,
112                                                 'formpostdir/safeformpost.aspx'
113                              )
114                      )
115              )
116              and strings.count(file.parse_html(.).raw, 'name="msg') > 3
117      )
118    )
119    and not (
120      any(headers.hops,
121          any(.fields,
122              .name in (
123                'X-ZixNet',
124                'X-VPM-MIV',
125                'X-VPM-ActionCode',
126                'X-VPM-SmtpTo'
127              )
128          )
129      )
130      and any(headers.domains,
131              .root_domain in (
132                "zixport.com",
133                "zixcorp.com",
134                "zixmail.net",
135                "zixworks.com"
136              )
137      )
138    )
139    and not (
140      any(headers.hops, any(.fields, .name == 'X-SendInc-Message-Id'))
141      and any(headers.domains, .root_domain in ("sendinc.net"))
142    )
143    // negating Mimecast sends with MS banner and/or sender's email pulled out as a link
144    and not length(filter(body.links,
145                          (
146                            .display_text is null
147                            and .display_url.url == sender.email.domain.root_domain
148                          )
149                          or .href_url.domain.root_domain in (
150                            "aka.ms",
151                            "mimecast.com",
152                            "cisco.com"
153                          )
154                   )
155    ) == length(body.links)
156  )
157  and (
158    (
159      profile.by_sender().prevalence in ("new", "outlier")
160      and not profile.by_sender().solicited
161    )
162    or (
163      profile.by_sender().any_messages_malicious_or_spam
164      and not profile.by_sender().any_messages_benign
165    )
166    // or the sender is all undisclosed or there are no recipients
167    or (
168      length(recipients.to) == 0
169      or all(recipients.to,
170             strings.ilike(.display_name, "undisclosed?recipients")
171      )
172    )
173    // or the sender exhibits a "self sender" pattern
174    or (
175      length(recipients.to) == 1
176      and any(recipients.to, .email.email == sender.email.email)
177    )
178  )
179  and not profile.by_sender().any_messages_benign
180  and not (
181    sender.email.domain.root_domain in $high_trust_sender_root_domains
182    and coalesce(headers.auth_summary.dmarc.pass, false)
183  )  
184attack_types:
185  - "Credential Phishing"
186tactics_and_techniques:
187  - "Social engineering"
188detection_methods:
189  - "Natural Language Understanding"
190  - "Sender analysis"
191id: "bd95a7b1-dc96-53c1-bb7c-3a0f98b04744"
to-top