Skip to content

Commit

Permalink
Sync from PR#2177
Browse files Browse the repository at this point in the history
Create link_sharepoint_attached_eml.yml by @zoomequipd
#2177
Source SHA decc15b
Triggered by @zoomequipd
  • Loading branch information
Sublime Rule Testing Bot committed Dec 11, 2024
1 parent a3bc442 commit 5720a6b
Showing 1 changed file with 2 additions and 94 deletions.
96 changes: 2 additions & 94 deletions detection-rules/link_sharepoint_attached_eml.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,99 +2,7 @@ name: "Link: SharePoint Nested Message Forgery"
description: "This detection rule identifies messages with an EML attachment containing SharePoint links, where the inner and outer messages share multiple matching characteristics, suggesting message content manipulation."
type: "rule"
severity: "medium"
source: |
type.inbound
and not any(body.links, .href_url.domain.root_domain == "sharepoint.com")
and any(
// filter to just eml attachments
filter(attachments,
.content_type == "message/rfc822" or .file_extension == "eml"
),
// any body links go to sharepoint
any(file.parse_eml(.).body.links,
.href_url.domain.root_domain == "sharepoint.com"
and regex.icontains(.href_url.path, '/:[a-z]:/')
)
and 2 of (
// the recipients of the outer and inner messages are the same
// or there is no outer recipients
(
(
all(map(file.parse_eml(.).recipients.to, .email.email),
. in map(recipients.to, .email.email)
)
and all(map(file.parse_eml(.).recipients.bcc, .email.email),
. in map(recipients.bcc, .email.email)
)
and all(map(file.parse_eml(.).recipients.cc, .email.email),
. in map(recipients.cc, .email.email)
)
// make sure the are the same length
and sum([
length(recipients.to),
length(recipients.bcc),
length(recipients.cc)
]
) == sum([
length(file.parse_eml(.).recipients.to),
length(file.parse_eml(.).recipients.bcc),
length(file.parse_eml(.).recipients.cc)
]
)
)
or length(recipients.to) == 0
or all(recipients.to, .email.email == "")
),
// the sender of the outer and inner messages are the same
file.parse_eml(.).sender.email.email == sender.email.email,
// the subject of the outer and inner messages are the same
strings.icontains(subject.subject, file.parse_eml(.).subject.subject),
// the inner message has the recipient and sender as the same address
// without any other recipients and matches the outer message sender
(
sum(
[
length(filter(file.parse_eml(.).recipients.to, .email.email != "")),
length(filter(file.parse_eml(.).recipients.bcc, .email.email != "")),
length(filter(file.parse_eml(.).recipients.cc, .email.email != ""))
]
) == 1
and (
all(file.parse_eml(.).recipients.to,
.email.email == file.parse_eml(..).sender.email.email
)
)
and file.parse_eml(.).sender.email.email == sender.email.email
),
// the outer recipieint is the sender of the inner message
(
sum(
[
length(filter(file.parse_eml(.).recipients.to, .email.email != "")),
length(filter(file.parse_eml(.).recipients.bcc, .email.email != "")),
length(filter(file.parse_eml(.).recipients.cc, .email.email != ""))
]
) == 1
and all(recipients.to,
.email.email == file.parse_eml(..).sender.email.email
)
)
)
)
// exclude bounce backs & read receipts
and not strings.like(sender.email.local_part,
"*postmaster*",
"*mailer-daemon*",
"*administrator*"
)
and not regex.icontains(subject.subject, "^(undeliverable|read:)")
and not any(attachments, .content_type == "message/delivery-status")
// if the "References" is in the body of the message, it's probably a bounce
and not any(headers.references, strings.contains(body.html.display_text, .))
source: "type.inbound\nand not any(body.links, .href_url.domain.root_domain == \"sharepoint.com\")\n// ensure there is only a single .eml attachment\nand length(filter(attachments,\n (\n .content_type == \"message/rfc822\"\n or .file_extension == \"eml\"\n )\n )\n) == 1\nand any(\n // filter to just eml attachments\n filter(attachments,\n (.content_type == \"message/rfc822\" or .file_extension == \"eml\")\n ),\n // any body links go to sharepoint\n any(file.parse_eml(.).body.links,\n .href_url.domain.root_domain == \"sharepoint.com\"\n and regex.icontains(.href_url.path, '/:[a-z]:/')\n )\n and 2 of (\n // the recipients of the outer and inner messages are the same\n // or there is no outer recipients\n (\n (\n all(map(file.parse_eml(.).recipients.to, .email.email),\n . in map(recipients.to, .email.email)\n )\n and all(map(file.parse_eml(.).recipients.bcc, .email.email),\n . in map(recipients.bcc, .email.email)\n )\n and all(map(file.parse_eml(.).recipients.cc, .email.email),\n . in map(recipients.cc, .email.email)\n )\n // make sure the are the same length\n and sum([\n length(recipients.to),\n length(recipients.bcc),\n length(recipients.cc)\n ]\n ) == sum([\n length(file.parse_eml(.).recipients.to),\n length(file.parse_eml(.).recipients.bcc),\n length(file.parse_eml(.).recipients.cc)\n ]\n )\n )\n or length(recipients.to) == 0\n or all(recipients.to, .email.email == \"\")\n ),\n // the sender of the outer and inner messages are the same\n file.parse_eml(.).sender.email.email == sender.email.email,\n\n // the subject of the outer and inner messages are the same\n strings.icontains(subject.subject, file.parse_eml(.).subject.subject),\n\n // the inner message has the recipient and sender as the same address\n // without any other recipients and matches the outer message sender\n (\n sum([\n length(filter(file.parse_eml(.).recipients.to,\n .email.email != \"\"\n )\n ),\n length(filter(file.parse_eml(.).recipients.bcc,\n .email.email != \"\"\n )\n ),\n length(filter(file.parse_eml(.).recipients.cc,\n .email.email != \"\"\n )\n )\n ]\n ) == 1\n and (\n all(file.parse_eml(.).recipients.to,\n .email.email == file.parse_eml(..).sender.email.email\n )\n )\n and file.parse_eml(.).sender.email.email == sender.email.email\n ),\n\n // the outer recipieint is the sender of the inner message\n (\n sum([\n length(filter(file.parse_eml(.).recipients.to,\n .email.email != \"\"\n )\n ),\n length(filter(file.parse_eml(.).recipients.bcc,\n .email.email != \"\"\n )\n ),\n length(filter(file.parse_eml(.).recipients.cc,\n .email.email != \"\"\n )\n )\n ]\n ) == 1\n and all(recipients.to,\n .email.email == file.parse_eml(..).sender.email.email\n )\n ),\n \n // the attached message contains a very low number of hops, as if it was never sent\n (\n length(file.parse_eml(.).headers.hops) <= 2\n or file.parse_eml(.).headers.return_path.email is null\n )\n )\n)\n\n// exclude bounce backs & read receipts\nand not strings.like(sender.email.local_part,\n \"*postmaster*\",\n \"*mailer-daemon*\",\n \"*administrator*\"\n)\nand not regex.icontains(subject.subject, \"^(undeliverable|read:)\")\nand not any(attachments, .content_type == \"message/delivery-status\")\n// if the \"References\" is in the body of the message, it's probably a bounce\nand not any(headers.references, strings.contains(body.html.display_text, .))\n"
attack_types:
- "Credential Phishing"
tactics_and_techniques:
Expand All @@ -106,4 +14,4 @@ detection_methods:
- "Header analysis"
id: "eab46d4b-39c9-568a-bb72-bf93f4cf997e"
testing_pr: 2177
testing_sha: 9fa98f4cecb92d6d44346987526a8da42700b143
testing_sha: decc15bf08cf61fe1ae4095b3d241409de6b1e7f

0 comments on commit 5720a6b

Please sign in to comment.