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 (
  9    (
 10      (
 11        strings.istarts_with(subject.subject, "RE:")
 12        or strings.istarts_with(subject.subject, "FW:")
 13        or strings.istarts_with(subject.subject, "FWD:")
 14        or regex.imatch(subject.subject,
 15                        '(\[[^\]]+\]\s?){0,3}(re|fwd?|automat.*)\s?:.*'
 16        )
 17      )
 18    )
 19    // fake thread, but no indication in the subject line
 20    // current_thread pulls the recent thread, but the full body contains the fake "original" email
 21    or (
 22      not (
 23        (
 24          strings.istarts_with(subject.subject, "RE:")
 25          or strings.istarts_with(subject.subject, "R:")
 26          or strings.istarts_with(subject.subject, "ODG:")
 27          or strings.istarts_with(subject.subject, "答复:")
 28          or strings.istarts_with(subject.subject, "AW:")
 29          or strings.istarts_with(subject.subject, "TR:")
 30          or strings.istarts_with(subject.subject, "FWD:")
 31        )
 32      )
 33      and any([body.current_thread.text, body.html.display_text, body.plain.raw],
 34              3 of (
 35                strings.icontains(., "from:"),
 36                strings.icontains(., "to:"),
 37                strings.icontains(., "sent:"),
 38                strings.icontains(., "date:"),
 39                strings.icontains(., "cc:"),
 40                strings.icontains(., "subject:")
 41              )
 42      )
 43      and (
 44        length(body.current_thread.text) + 100 < length(body.html.display_text)
 45      )
 46    )
 47  )
 48
 49  // negating bouncebacks
 50  and not any(attachments,
 51              .content_type in ("message/delivery-status", "message/rfc822")
 52  )
 53  // negating Google Calendar invites
 54  and (
 55    (
 56      headers.return_path.domain.domain is not null
 57      and headers.return_path.domain.domain != 'calendar-server.bounces.google.com'
 58    )
 59    or headers.return_path.domain.domain is null
 60  )
 61  
 62  and (
 63    length(headers.references) == 0 
 64    or headers.in_reply_to is null
 65  )
 66  
 67  // and not solicited
 68  and not profile.by_sender().solicited
 69  and 4 of (
 70    // language attempting to engage
 71    (
 72      any(ml.nlu_classifier(body.current_thread.text).entities,
 73          .name == "request"
 74      )
 75      and any(ml.nlu_classifier(body.current_thread.text).entities,
 76              .name == "financial"
 77      )
 78    ),
 79  
 80    // invoicing language
 81    (
 82      any(ml.nlu_classifier(body.current_thread.text).tags, .name == "invoice")
 83      or any(ml.nlu_classifier(body.current_thread.text).entities,
 84             .text == "invoice"
 85      )
 86    ),
 87  
 88    // urgency request
 89    any(ml.nlu_classifier(body.current_thread.text).entities, .name == "urgency"),
 90  
 91    // cred_theft detection
 92    any(ml.nlu_classifier(body.current_thread.text).intents,
 93        .name == "cred_theft" and .confidence in~ ("medium", "high")
 94    ),
 95  
 96    // commonly abused sender TLD
 97    strings.ilike(sender.email.domain.tld, "*.jp"),
 98  
 99    // headers traverse abused TLD
100    any(headers.domains, strings.ilike(.tld, "*.jp")),
101  
102    // known suspicious pattern in the URL path
103    any(body.links, regex.match(.href_url.path, '\/[a-z]{3}\d[a-z]')),
104  
105    // link display text is in all caps
106    any(body.links, regex.match(.display_text, '[A-Z ]+')),
107
108    // link display text contains invisible characters (U+200F)
109    any(body.links, strings.contains(.display_text, "\u{200F}")),
110  
111    // display name contains an email
112    regex.contains(sender.display_name, '[a-z0-9]+@[a-z]+'),
113  
114    // Sender domain is empty
115    sender.email.domain.domain == "",
116  
117    // sender domain matches no body domains
118    all(body.links,
119        .href_url.domain.root_domain != sender.email.domain.root_domain
120    ),
121  
122    // body contains name of VIP
123    (
124      any($org_vips, strings.icontains(body.html.inner_text, .display_name))
125      or any($org_vips, strings.icontains(body.plain.raw, .display_name))
126    ),
127  
128    // new body domain
129    any(body.links, network.whois(.href_url.domain).days_old < 30),
130  
131    // new sender domain
132    network.whois(sender.email.domain).days_old < 30,
133  
134    // new sender
135    profile.by_sender().days_known < 7,
136  
137    // excessive whitespace
138    (
139      regex.icontains(body.html.raw, '((<br\s*/?>\s*){20,}|\n{20,})')
140      or regex.icontains(body.html.raw, '(<p[^>]*>\s*<br\s*/?>\s*</p>\s*){30,}')
141      or regex.icontains(body.html.raw,
142                         '(<p class=".*?"><span style=".*?"><o:p>&nbsp;</o:p></span></p>\s*){30,}'
143      )
144      or regex.icontains(body.html.raw, '(<p>&nbsp;</p>\s*){7,}')
145      or regex.icontains(body.html.raw, '(<p>&nbsp;</p><br>\s*){7,}')
146      or regex.icontains(body.html.raw, '(<p[^>]*>\s*&nbsp;<br>\s*</p>\s*){5,}')
147      or regex.icontains(body.html.raw, '(<p[^>]*>&nbsp;</p>\s*){7,}')
148    ),
149  
150    // body contains recipient SLD
151    any(recipients.to,
152        strings.icontains(body.current_thread.text, .email.domain.sld)
153    )
154  )
155  
156  // negate highly trusted sender domains unless they fail DMARC authentication
157  and (
158    (
159      sender.email.domain.root_domain in $high_trust_sender_root_domains
160      and not headers.auth_summary.dmarc.pass
161    )
162    or sender.email.domain.root_domain not in $high_trust_sender_root_domains
163  )
164  and not profile.by_sender().any_messages_benign  
165
166tags:
167  - "Attack surface reduction"
168attack_types:
169  - "BEC/Fraud"
170  - "Credential Phishing"
171  - "Spam"
172tactics_and_techniques:
173  - "Evasion"
174  - "Social engineering"
175detection_methods:
176  - "Content analysis"
177  - "Header analysis"
178  - "Natural Language Understanding"
179  - "Sender analysis"
180id: "c2e18a57-1f52-544f-bb6d-a578e286cf89"

Related rules

to-top