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

Related rules

to-top