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      // add fallback when NLU doesn't pick up cred theft to check for suspicious links
 14      or any(body.current_thread.links,
 15             regex.icontains(.display_text, '(?:read|view|open) the message')
 16             and (
 17               .href_url.domain.root_domain not in $tranco_1m
 18               or .href_url.domain.domain in $free_file_hosts
 19               or .href_url.domain.root_domain in $free_file_hosts
 20               or .href_url.domain.root_domain in $free_subdomain_hosts
 21               or .href_url.domain.domain in $url_shorteners
 22               or .href_url.domain.domain in $social_landing_hosts
 23             )
 24      )
 25    )
 26    or any(ml.nlu_classifier(beta.ocr(file.message_screenshot()).text).intents,
 27           .name == "cred_theft" and .confidence in ("medium", "high")
 28    )
 29  )
 30  
 31  // ----- other suspicious signals here -----
 32  and (
 33    (
 34      regex.icontains(body.current_thread.text,
 35                      "secured? (message|directory|document)"
 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)")
 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) access'
 50           )
 51    )
 52    or (
 53      length(filter(ml.nlu_classifier(body.current_thread.text).entities,
 54                    .name == "urgency"
 55             )
 56      ) >= 2
 57      and any(ml.nlu_classifier(body.current_thread.text).topics,
 58              .name == "Secure Message" and .confidence != "low"
 59      )
 60    )
 61  )
 62  // todo: automated display name / human local part
 63  // todo: suspicious link (unfurl click trackers)
 64  
 65  // ----------
 66  
 67  // has at least 1 link
 68  and length(body.links) > 0
 69  
 70  // negate legitimate message senders
 71  and (
 72    sender.email.domain.root_domain not in ("protectedtrust.com")
 73    and any(body.links,
 74            .href_url.domain.root_domain != sender.email.domain.root_domain
 75    )
 76    // negate known secure mailers
 77    and not all(body.links,
 78                .href_url.domain.root_domain in (
 79                  "mimecast.com",
 80                  "cisco.com",
 81                  "csiesafe.com"
 82                )
 83    )
 84    and any(headers.hops,
 85            .index == 0
 86            and not any(.fields,
 87                        strings.contains(.value,
 88                                         'multipart/mixed; boundary="PROOFPOINT_BOUNDARY_1"'
 89                        )
 90            )
 91    )
 92    and not (
 93      length(filter(attachments,
 94                    strings.ilike(.file_name,
 95                                  "logo.*",
 96                                  "lock.gif",
 97                                  "SecureMessageAtt.html"
 98                    )
 99             )
100      ) == 3
101      and any(attachments,
102              .file_type == "html"
103              and any(file.explode(.),
104                      .scan.html.title == "Proofpoint Encryption"
105                      and any(.scan.url.urls,
106                              strings.iends_with(.path,
107                                                 'formpostdir/safeformpost.aspx'
108                              )
109                      )
110              )
111              and strings.count(file.parse_html(.).raw, 'name="msg') > 3
112      )
113    )
114    and not (
115      any(headers.hops,
116          any(.fields,
117              .name in (
118                'X-ZixNet',
119                'X-VPM-MIV',
120                'X-VPM-ActionCode',
121                'X-VPM-SmtpTo'
122              )
123          )
124      )
125      and any(headers.domains,
126              .root_domain in (
127                "zixport.com",
128                "zixcorp.com",
129                "zixmail.net",
130                "zixworks.com"
131              )
132      )
133    )
134    and not (
135      any(headers.hops, any(.fields, .name == 'X-SendInc-Message-Id'))
136      and any(headers.domains, .root_domain in ("sendinc.net"))
137    )
138    // negating Mimecast sends with MS banner and/or sender's email pulled out as a link
139    and not length(filter(body.links,
140                          (
141                            .display_text is null
142                            and .display_url.url == sender.email.domain.root_domain
143                          )
144                          or .href_url.domain.root_domain in (
145                            "aka.ms",
146                            "mimecast.com",
147                            "cisco.com"
148                          )
149                   )
150    ) == length(body.links)
151  )
152  and (
153    (
154      profile.by_sender().prevalence in ("new", "outlier")
155      and not profile.by_sender().solicited
156    )
157    or (
158      profile.by_sender().any_messages_malicious_or_spam
159      and not profile.by_sender().any_messages_benign
160    )
161    // or the sender is all undisclosed or there are no recipients
162    or (
163      length(recipients.to) == 0
164      or all(recipients.to,
165             strings.ilike(.display_name, "undisclosed?recipients")
166      )
167    )
168    // or the sender exhibits a "self sender" pattern
169    or (
170      length(recipients.to) == 1
171      and any(recipients.to, .email.email == sender.email.email)
172    )
173  )
174  and not profile.by_sender().any_messages_benign
175  
176  // negate highly trusted sender domains unless they fail DMARC authentication
177  and (
178    (
179      sender.email.domain.root_domain in $high_trust_sender_root_domains
180      and not headers.auth_summary.dmarc.pass
181    )
182    or sender.email.domain.root_domain not in $high_trust_sender_root_domains
183  )  
184
185attack_types:
186  - "Credential Phishing"
187tactics_and_techniques:
188  - "Social engineering"
189detection_methods:
190  - "Natural Language Understanding"
191  - "Sender analysis"
192id: "bd95a7b1-dc96-53c1-bb7c-3a0f98b04744"
to-top