Skip to content

Commit 238d655

Browse files
authored
Merge branch 'main' into morriscode-gitgudnoob
2 parents c69b291 + 0465b64 commit 238d655

12 files changed

+187
-41
lines changed
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
name: "Credential Phishing: Image as content, short or no body contents"
2+
description: |
3+
This rule identifies incoming messages with minimal links, all image attachments and either empty, brief
4+
or the body text is only a warning banner/disclaimer. It also checks for truncated PNG images or logos in addition
5+
to high-confidence credit theft intentions.
6+
type: "rule"
7+
severity: "medium"
8+
source: |
9+
type.inbound
10+
and length(body.links) < 2
11+
and 0 < (length(attachments)) < 3
12+
and (
13+
// body text is very short
14+
(
15+
0 <= (length(body.current_thread.text)) < 10 or body.current_thread.text is null
16+
)
17+
or (
18+
length(body.current_thread.text) < 900
19+
// or body is most likely all warning banner (text contains the sender and common warning banner language)
20+
and (
21+
(
22+
strings.contains(body.current_thread.text, sender.email.email)
23+
and strings.contains(body.current_thread.text, 'caution')
24+
)
25+
or regex.icontains(body.current_thread.text,
26+
"intended recipient's use only|external email|sent from outside|you don't often"
27+
)
28+
)
29+
)
30+
)
31+
and (
32+
all(attachments,
33+
(.file_type in $file_types_images)
34+
and (
35+
any(file.explode(.),
36+
any(.scan.exiftool.fields, .value == "Truncated PNG image")
37+
or (
38+
any(ml.logo_detect(..).brands, .name is not null)
39+
and any(ml.nlu_classifier(.scan.ocr.raw).intents,
40+
.name == "cred_theft" and .confidence == "high"
41+
)
42+
)
43+
)
44+
)
45+
)
46+
)
47+
attack_types:
48+
- "Credential Phishing"
49+
tactics_and_techniques:
50+
- "Evasion"
51+
- "Image as content"
52+
detection_methods:
53+
- "Computer Vision"
54+
- "Content analysis"
55+
- "File analysis"
56+
- "Header analysis"
57+
- "Natural Language Understanding"
58+
- "Optical Character Recognition"
59+
id: "01313f38-d0d1-5240-b407-8f9158639277"

detection-rules/attachment_html_smuggling_atob.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,7 @@ severity: "high"
88
source: |
99
type.inbound
1010
and any(attachments,
11-
.size <= 60000
12-
and (
11+
(
1312
.file_extension in~ ("html", "htm", "shtml", "dhtml")
1413
or .file_extension in~ $file_extensions_common_archives
1514
or .file_type == "html"
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
name: "Attachment: HTML smuggling with excessive line break obfuscation"
2+
description: |
3+
Credential Phishing attacks have been observed using excessive line breaks to obfuscate javascript functions within html files.
4+
type: "rule"
5+
severity: "high"
6+
source: |
7+
type.inbound
8+
and any(attachments,
9+
(
10+
.file_extension in~ ("html", "htm", "shtml", "dhtml")
11+
or .file_extension in~ $file_extensions_common_archives
12+
or .file_type == "html"
13+
)
14+
and any(file.explode(.),
15+
any(.scan.strings.strings,
16+
// return new line padded obfuscation
17+
regex.contains(., '(\\r\\n\S{2}){50,}')
18+
and strings.contains(., 'decodeURIComponent')
19+
)
20+
)
21+
)
22+
attack_types:
23+
- "Credential Phishing"
24+
- "Malware/Ransomware"
25+
tactics_and_techniques:
26+
- "Encryption"
27+
- "Evasion"
28+
- "HTML smuggling"
29+
- "Scripting"
30+
detection_methods:
31+
- "Archive analysis"
32+
- "Content analysis"
33+
- "File analysis"
34+
- "HTML analysis"
35+
- "Javascript analysis"
36+
id: "7e901440-5751-5d94-8b2d-47eb3c0e2b9d"

detection-rules/body_extortion.yml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,11 @@ type: "rule"
77
severity: "low"
88
source: |
99
type.inbound
10-
and any([body.html.display_text, body.plain.raw],
11-
any(ml.nlu_classifier(.).intents, .name == "extortion" and .confidence == "high")
12-
and (any(ml.nlu_classifier(.).entities, .name == "financial"))
10+
and (
11+
any(ml.nlu_classifier(body.current_thread.text).intents,
12+
.name == "extortion" and .confidence == "high"
13+
)
14+
and any(ml.nlu_classifier(body.current_thread.text).entities, .name == "financial")
1315
)
1416
and (
1517
(

detection-rules/callback_phishing_nlu_body_or_attachments.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@ source: |
1515
)
1616
)
1717
or any(ml.nlu_classifier(body.current_thread.text).intents,
18-
.name in ("callback_scam") and .confidence == "high"
18+
.name in ("callback_scam")
19+
and .confidence == "high"
20+
and length(body.current_thread.text) < 1500
1921
)
2022
)
2123
and not (

detection-rules/file_sharing_link_suspicious_subject.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ source: |
1616
)
1717
)
1818
and regex.icontains(subject.subject, 'immediately', 'urgent')
19+
and any(ml.nlu_classifier(body.current_thread.text).intents, .name != "benign")
1920
and (
2021
(
2122
sender.email.domain.root_domain in $free_email_providers

detection-rules/headers_freemail_replyto_returnpath_mismatch.yml

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ severity: "medium"
55
source: |
66
type.inbound
77
and any(ml.nlu_classifier(body.current_thread.text).intents,
8-
.name in ("bec") and .confidence in ("medium", "high")
8+
.name in ("bec") and .confidence == "high"
99
)
1010
and (
1111
headers.return_path.domain.root_domain in $free_email_providers
@@ -21,6 +21,24 @@ source: |
2121
)
2222
)
2323
and sender.email.domain.root_domain not in $free_email_providers
24+
25+
// negate gmail autoforwards and null return paths
26+
and (
27+
headers.return_path.email is null
28+
or not any([headers.return_path.email], strings.ilike(headers.return_path.local_part, "*+caf_=*"))
29+
)
30+
31+
// negate listservs
32+
and not (
33+
any(headers.hops, any(.fields, .name == "List-Unsubscribe"))
34+
and strings.contains(sender.display_name, "via")
35+
)
36+
37+
// negate legit replies
38+
and not (
39+
length(headers.references) > 0
40+
or any(headers.hops, any(.fields, strings.ilike(.name, "In-Reply-To")))
41+
)
2442
attack_types:
2543
- "BEC/Fraud"
2644
tactics_and_techniques:

detection-rules/link_credential_phishing_secure_message.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ source: |
2525
sender.email.domain.root_domain not in ("protectedtrust.com")
2626
and any(body.links,
2727
.href_url.domain.root_domain != sender.email.domain.root_domain
28-
and length(.href_url.path) > 20
2928
)
3029
)
3130

detection-rules/link_credential_phishing_voicemail_language.yml

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,16 @@ severity: "medium"
77
source: |
88
type.inbound
99
and length(body.links) > 0
10-
10+
1111
// voicemail related
1212
and (
13-
regex.icontains(coalesce(body.html.inner_text, body.html.display_text),
14-
'voice\s?(mail|message|recording|call)'
15-
)
13+
regex.icontains(body.current_thread.text, 'voice\s?(mail|message|recording|call)')
1614
or (regex.icontains(subject.subject, 'voice\s?(mail|message|recording|call)'))
1715
)
1816
and 2 of (
1917
(
20-
any([body.plain.raw, body.html.inner_text],
21-
any(ml.nlu_classifier(.).intents,
22-
.name in ("cred_theft") and .confidence in ("medium", "high")
23-
)
18+
any(ml.nlu_classifier(body.current_thread.text).intents,
19+
.name in ("cred_theft") and .confidence in ("medium", "high")
2420
)
2521
),
2622
(regex.icontains(sender.display_name, 'voice\s?(mail|message|recording|call)')),
@@ -29,14 +25,15 @@ source: |
2925
all(body.links,
3026
.href_url.domain.root_domain != sender.email.domain.root_domain
3127
and .href_url.domain.root_domain not in $org_domains
28+
and .href_url.domain.root_domain not in ("unitelvoice.com", "googleapis.com", "dialmycalls.com")
3229
)
3330
),
3431
(
3532
// recipient's SLD is in the sender's display name
3633
any(recipients.to, strings.icontains(sender.display_name, .email.domain.sld))
3734
),
3835
)
39-
and sender.email.domain.root_domain not in ("magicjack.com")
36+
and sender.email.domain.root_domain not in ("magicjack.com", "unitelvoice.com")
4037
and (
4138
(
4239
sender.email.domain.root_domain in $free_email_providers

discovery-rules/link_fake_thread_nlu_financial_request.yml renamed to detection-rules/link_fake_thread_nlu_financial_request.yml

Lines changed: 31 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,16 @@ type: "rule"
44
severity: "medium"
55
source: |
66
type.inbound
7-
7+
and length(body.links) < 10
88
// suspicious link
99
and any(body.links,
1010
.href_url.domain.root_domain not in $tranco_1m
1111
and .href_url.domain.domain not in $umbrella_1m
1212
)
13-
13+
1414
// fake thread check
1515
and (strings.istarts_with(subject.subject, "RE:") or strings.istarts_with(subject.subject, "FWD:"))
16-
16+
1717
// Check for the Presence of References or In-Reply-To properties
1818
and (
1919
(length(headers.references) == 0 and headers.in_reply_to is null)
@@ -22,45 +22,53 @@ source: |
2222
and not any(headers.hops, strings.ilike(.signature.headers, "*:reply-to"))
2323
)
2424
)
25-
25+
2626
// sender's domain is not in body, and body has > 0 links
2727
and length(body.links) > 0
2828
and sender.email.domain.root_domain not in $free_email_providers
2929
and not any(body.links, .href_url.domain.root_domain == sender.email.domain.root_domain)
30-
30+
3131
// unusual sender (email address rarely sends to your organization)
3232
and sender.email.email not in $sender_emails
33-
33+
3434
// unusual sender domain (domain rarely sends to your organization)
3535
and sender.email.domain.domain not in $sender_domains
36-
37-
// sender SLD matches no body SLDs
38-
and all(body.links, .href_url.domain.sld != sender.email.domain.sld)
39-
40-
and 2 of (
36+
and 4 of (
4137
// language attempting to engage
42-
any(ml.nlu_classifier(body.html.inner_text).entities, .name == "request"),
43-
44-
// financial request
45-
any(ml.nlu_classifier(body.html.inner_text).entities, .name == "financial"),
46-
38+
(
39+
any(ml.nlu_classifier(body.current_thread.text).entities, .name == "request")
40+
and any(ml.nlu_classifier(body.current_thread.text).entities, .name == "financial")
41+
),
42+
43+
// invoicing language
44+
any(ml.nlu_classifier(body.current_thread.text).tags, .name == "invoice"),
45+
4746
// urgency request
48-
any(ml.nlu_classifier(body.html.inner_text).entities, .name == "urgency"),
49-
47+
any(ml.nlu_classifier(body.current_thread.text).entities, .name == "urgency"),
48+
5049
// cred_theft detection
51-
any(ml.nlu_classifier(body.html.inner_text).intents,
50+
any(ml.nlu_classifier(body.current_thread.text).intents,
5251
.name == "cred_theft" and .confidence in~ ("medium", "high")
5352
),
54-
53+
5554
// commonly abused sender TLD
5655
strings.ilike(sender.email.domain.tld, "*.jp"),
57-
56+
57+
// headers traverse abused TLD
58+
any(headers.domains, strings.ilike(.tld, "*.jp")),
59+
5860
// known suspicious pattern in the URL path
5961
any(body.links, regex.match(.href_url.path, '\/[a-z]{3}\d[a-z]')),
60-
62+
6163
// link display text is in all caps
6264
any(body.links, regex.match(.display_text, '[A-Z ]+')),
63-
65+
66+
// display name contains an email
67+
regex.contains(sender.display_name, '[a-z0-9]+@[a-z]+'),
68+
69+
// Sender domain is empty
70+
sender.email.domain.domain == "",
71+
6472
// sender domain matches no body domains
6573
all(body.links, .href_url.domain.root_domain != sender.email.domain.root_domain),
6674
)

0 commit comments

Comments
 (0)