Fake thread with suspicious indicators

Fake thread contains suspicious indicators, which can lead to BEC, credential phishing, and other undesirable outcomes.

Sublime rule (View on GitHub)

  1name: "Fake thread with suspicious indicators"
  2description: "Fake thread contains suspicious indicators, which can lead to BEC, credential phishing, and other undesirable outcomes."
  3type: "rule"
  4severity: "medium"
  5source: |
  6  type.inbound
  7  // fake thread check
  8  and (length(headers.references) == 0 or headers.in_reply_to is null)
  9  and (
 10    subject.is_reply
 11    or subject.is_forward
 12    // fake thread, but no indication in the subject line
 13    // current_thread pulls the recent thread, but the full body contains the fake "original" email
 14    or (
 15      not (subject.is_reply or subject.is_forward)
 16      and any([body.current_thread.text, body.html.display_text, body.plain.raw],
 17              3 of (
 18                strings.icontains(., "from:"),
 19                strings.icontains(., "to:"),
 20                strings.icontains(., "sent:"),
 21                strings.icontains(., "date:"),
 22                strings.icontains(., "cc:"),
 23                strings.icontains(., "subject:")
 24              )
 25      )
 26      and length(body.current_thread.text) + 100 < length(coalesce(body.html.display_text,
 27                                                                   body.plain.raw
 28                                                          )
 29      )
 30    )
 31  )
 32  
 33  // negating bouncebacks
 34  and not any(attachments,
 35              .content_type in ("message/delivery-status", "message/rfc822")
 36  )
 37  // negating Google Calendar invites
 38  and (
 39    (
 40      headers.return_path.domain.domain is not null
 41      and headers.return_path.domain.domain != 'calendar-server.bounces.google.com'
 42    )
 43    or headers.return_path.domain.domain is null
 44  )
 45  // not mimecast secure message from internal source
 46  and not (
 47    strings.istarts_with(headers.message_id, '<Mimecast.')
 48    and strings.iends_with(headers.message_id, '.mimecast.lan>')
 49    and headers.hops[0].received.server.raw == "relay.mimecast.com"
 50    and strings.icontains(headers.hops[0].received.source.raw, 'mimecast.lan')
 51  )
 52  
 53  // and not solicited
 54  and not profile.by_sender().solicited
 55  and 4 of (
 56    // language attempting to engage
 57    (
 58      any(ml.nlu_classifier(body.current_thread.text).entities,
 59          .name == "request"
 60      )
 61      and any(ml.nlu_classifier(body.current_thread.text).entities,
 62              .name == "financial"
 63      )
 64    ),
 65  
 66    // invoicing language
 67    (
 68      any(ml.nlu_classifier(body.current_thread.text).tags, .name == "invoice")
 69      or any(ml.nlu_classifier(body.current_thread.text).entities,
 70             .text == "invoice"
 71      )
 72    ),
 73  
 74    // urgency request
 75    any(ml.nlu_classifier(body.current_thread.text).entities, .name == "urgency"),
 76  
 77    // cred_theft detection
 78    any(ml.nlu_classifier(body.current_thread.text).intents,
 79        .name == "cred_theft" and .confidence in~ ("medium", "high")
 80    ),
 81
 82    // subject has multiple re: tags and suspicious indicators
 83    (
 84      regex.icontains(subject.subject, '\bre:\s+re:')
 85      and (
 86        regex.icontains(subject.base,
 87                        '(?:action.{0,10}required|invest(?:ment|ing)?|enforcement|opportunit|urgent|verif|confirm|suspend|terminat)'
 88        )
 89      )
 90    ),
 91  
 92    // commonly abused sender TLD
 93    strings.ilike(sender.email.domain.tld, "*.jp"),
 94  
 95    // headers traverse abused TLD
 96    any(headers.domains, strings.ilike(.tld, "*.jp")),
 97  
 98    // known suspicious pattern in the URL path
 99    any(body.links, regex.match(.href_url.path, '\/[a-z]{3}\d[a-z]')),
100  
101    // link display text is in all caps
102    any(body.links, regex.match(.display_text, '[A-Z ]+')),
103  
104    // link display text contains invisible characters (U+200F)
105    any(body.links, strings.contains(.display_text, "\u{200F}")),
106  
107    // Low reputation link with display text ending in a document extension
108    any(body.links,
109        .href_url.domain.root_domain not in $tranco_1m
110        and .href_url.domain.valid
111        and .href_url.domain.root_domain not in $org_domains
112        and .href_url.domain.root_domain not in $high_trust_sender_root_domains
113        and (
114          any($file_extensions_macros, strings.ends_with(..display_text, .))
115          or strings.ends_with(.display_text, 'pdf')
116        )
117    ),
118  
119    // display name contains an email
120    regex.contains(sender.display_name, '[a-z0-9]+@[a-z]+'),
121  
122    // Sender domain is empty
123    sender.email.domain.domain == "",
124  
125    // sender domain matches no body domains
126    all(body.links,
127        .href_url.domain.root_domain != sender.email.domain.root_domain
128    ),
129  
130    // body contains name of VIP
131    (
132      any($org_vips, strings.icontains(body.html.inner_text, .display_name))
133      or any($org_vips, strings.icontains(body.plain.raw, .display_name))
134    ),
135  
136    // new body domain
137    any(body.links, network.whois(.href_url.domain).days_old < 30),
138  
139    // new sender domain
140    network.whois(sender.email.domain).days_old < 30,
141  
142    // new sender
143    profile.by_sender().days_known < 7,
144  
145    // excessive whitespace
146    (
147      regex.icontains(body.html.raw, '((<br\s*/?>\s*){20,}|\n{20,})')
148      or regex.icontains(body.html.raw, '(<p[^>]*>\s*<br\s*/?>\s*</p>\s*){30,}')
149      or regex.icontains(body.html.raw,
150                         '(<p class=".*?"><span style=".*?"><o:p>&nbsp;</o:p></span></p>\s*){30,}'
151      )
152      or regex.icontains(body.html.raw, '(<p>&nbsp;</p>\s*){7,}')
153      or regex.icontains(body.html.raw, '(<p>&nbsp;</p><br>\s*){7,}')
154      or regex.icontains(body.html.raw, '(<p[^>]*>\s*&nbsp;<br>\s*</p>\s*){5,}')
155      or regex.icontains(body.html.raw, '(<p[^>]*>&nbsp;</p>\s*){7,}')
156    ),
157  
158    // body contains recipient SLD
159    any(recipients.to,
160        strings.icontains(body.current_thread.text, .email.domain.sld)
161    ),
162    (
163      // bec
164      any(ml.nlu_classifier(body.current_thread.text).intents,
165          .name == "bec" and .confidence != "low"
166      )
167      // previous thread contains matching domain but mismatch local part in current thread
168      and any(body.previous_threads,
169              .sender.email.domain.root_domain == recipients.to[0].email.domain.root_domain
170              and .sender.email.email != recipients.to[0].email.email
171      )
172    )
173  )
174  
175  // negate highly trusted sender domains unless they fail DMARC authentication
176  and (
177    (
178      sender.email.domain.root_domain in $high_trust_sender_root_domains
179      and not headers.auth_summary.dmarc.pass
180    )
181    or sender.email.domain.root_domain not in $high_trust_sender_root_domains
182  )
183  and not profile.by_sender().any_messages_benign  
184tags:
185  - "Attack surface reduction"
186attack_types:
187  - "BEC/Fraud"
188  - "Credential Phishing"
189  - "Spam"
190tactics_and_techniques:
191  - "Evasion"
192  - "Social engineering"
193detection_methods:
194  - "Content analysis"
195  - "Header analysis"
196  - "Natural Language Understanding"
197  - "Sender analysis"
198id: "c2e18a57-1f52-544f-bb6d-a578e286cf89"

Related rules

to-top