Skip to content

Commit 94a34bd

Browse files
[Test Rules] [PR #4289] added rule: Fake thread with suspicious indicators
1 parent f08bee5 commit 94a34bd

1 file changed

Lines changed: 190 additions & 0 deletions

File tree

Lines changed: 190 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,190 @@
1+
name: "Fake thread with suspicious indicators"
2+
description: "Fake thread contains suspicious indicators, which can lead to BEC, credential phishing, and other undesirable outcomes."
3+
type: "rule"
4+
severity: "medium"
5+
source: |
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+
// commonly abused sender TLD
83+
strings.ilike(sender.email.domain.tld, "*.jp"),
84+
85+
// headers traverse abused TLD
86+
any(headers.domains, strings.ilike(.tld, "*.jp")),
87+
88+
// known suspicious pattern in the URL path
89+
any(body.links, regex.match(.href_url.path, '\/[a-z]{3}\d[a-z]')),
90+
91+
// link display text is in all caps
92+
any(body.links, regex.match(.display_text, '[A-Z ]+')),
93+
94+
// link display text contains invisible characters (U+200F)
95+
any(body.links, strings.contains(.display_text, "\u{200F}")),
96+
97+
// Low reputation link with display text ending in a document extension
98+
any(body.links,
99+
.href_url.domain.root_domain not in $tranco_1m
100+
and .href_url.domain.valid
101+
and .href_url.domain.root_domain not in $org_domains
102+
and .href_url.domain.root_domain not in $high_trust_sender_root_domains
103+
and (
104+
any($file_extensions_macros, strings.ends_with(..display_text, .))
105+
or strings.ends_with(.display_text, 'pdf')
106+
)
107+
),
108+
109+
// display name contains an email
110+
regex.contains(sender.display_name, '[a-z0-9]+@[a-z]+'),
111+
112+
// Sender domain is empty
113+
sender.email.domain.domain == "",
114+
115+
// sender domain matches no body domains
116+
all(body.links,
117+
.href_url.domain.root_domain != sender.email.domain.root_domain
118+
),
119+
120+
// body contains name of VIP
121+
(
122+
any($org_vips, strings.icontains(body.html.inner_text, .display_name))
123+
or any($org_vips, strings.icontains(body.plain.raw, .display_name))
124+
),
125+
126+
// new body domain
127+
any(body.links, network.whois(.href_url.domain).days_old < 30),
128+
129+
// new sender domain
130+
network.whois(sender.email.domain).days_old < 30,
131+
132+
// new sender
133+
profile.by_sender().days_known < 7,
134+
135+
// excessive whitespace
136+
(
137+
regex.icontains(body.html.raw, '((<br\s*/?>\s*){20,}|\n{20,})')
138+
or regex.icontains(body.html.raw, '(<p[^>]*>\s*<br\s*/?>\s*</p>\s*){30,}')
139+
or regex.icontains(body.html.raw,
140+
'(<p class=".*?"><span style=".*?"><o:p>&nbsp;</o:p></span></p>\s*){30,}'
141+
)
142+
or regex.icontains(body.html.raw, '(<p>&nbsp;</p>\s*){7,}')
143+
or regex.icontains(body.html.raw, '(<p>&nbsp;</p><br>\s*){7,}')
144+
or regex.icontains(body.html.raw, '(<p[^>]*>\s*&nbsp;<br>\s*</p>\s*){5,}')
145+
or regex.icontains(body.html.raw, '(<p[^>]*>&nbsp;</p>\s*){7,}')
146+
),
147+
148+
// body contains recipient SLD
149+
any(recipients.to,
150+
strings.icontains(body.current_thread.text, .email.domain.sld)
151+
),
152+
// mailto mismatch from freemailer
153+
(
154+
any(body.links,
155+
strings.istarts_with(.href_url.url, "mailto:")
156+
and .display_text is not null
157+
and strings.icontains(.display_text, "@")
158+
and not strings.icontains(.href_url.url, .display_text)
159+
)
160+
and sender.email.domain.root_domain in $free_email_providers
161+
)
162+
)
163+
164+
// negate highly trusted sender domains unless they fail DMARC authentication
165+
and (
166+
(
167+
sender.email.domain.root_domain in $high_trust_sender_root_domains
168+
and not headers.auth_summary.dmarc.pass
169+
)
170+
or sender.email.domain.root_domain not in $high_trust_sender_root_domains
171+
)
172+
and not profile.by_sender().any_messages_benign
173+
tags:
174+
- "Attack surface reduction"
175+
attack_types:
176+
- "BEC/Fraud"
177+
- "Credential Phishing"
178+
- "Spam"
179+
tactics_and_techniques:
180+
- "Evasion"
181+
- "Social engineering"
182+
detection_methods:
183+
- "Content analysis"
184+
- "Header analysis"
185+
- "Natural Language Understanding"
186+
- "Sender analysis"
187+
id: "c836b065-538b-50f3-83d9-784d34a56e22"
188+
og_id: "c2e18a57-1f52-544f-bb6d-a578e286cf89"
189+
testing_pr: 4289
190+
testing_sha: 521716b0c435abb9157c1e2e785e4db86aa27023

0 commit comments

Comments
 (0)