From 7040e9759b56bbb2cc806b662faad7ad091f10cd Mon Sep 17 00:00:00 2001 From: Brandon Murphy <4827852+zoomequipd@users.noreply.github.com> Date: Mon, 2 Dec 2024 08:54:44 -0600 Subject: [PATCH 1/5] Create link_sharepoint_attached_eml.yml --- .../link_sharepoint_attached_eml.yml | 85 +++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 detection-rules/link_sharepoint_attached_eml.yml diff --git a/detection-rules/link_sharepoint_attached_eml.yml b/detection-rules/link_sharepoint_attached_eml.yml new file mode 100644 index 00000000000..45fb0b0e702 --- /dev/null +++ b/detection-rules/link_sharepoint_attached_eml.yml @@ -0,0 +1,85 @@ +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) + ) + ) + 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 + ) + ) + ) + ) + + +attack_types: + - "Credential Phishing" +tactics_and_techniques: + - "Evasion" + - "Out of band pivot" +detection_methods: + - "File analysis" + - "URL analysis" + - "Header analysis" From 9a85dc28e5032f8d895ac762b4cd6ec5dd3eb16f Mon Sep 17 00:00:00 2001 From: ID Generator Date: Mon, 2 Dec 2024 15:03:09 +0000 Subject: [PATCH 2/5] Auto add rule ID --- detection-rules/link_sharepoint_attached_eml.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/detection-rules/link_sharepoint_attached_eml.yml b/detection-rules/link_sharepoint_attached_eml.yml index 45fb0b0e702..fad58671940 100644 --- a/detection-rules/link_sharepoint_attached_eml.yml +++ b/detection-rules/link_sharepoint_attached_eml.yml @@ -83,3 +83,4 @@ detection_methods: - "File analysis" - "URL analysis" - "Header analysis" +id: "eab46d4b-39c9-568a-bb72-bf93f4cf997e" From be9227af6367c8857828dfd4ffc6bc10856423a6 Mon Sep 17 00:00:00 2001 From: Brandon Murphy <4827852+zoomequipd@users.noreply.github.com> Date: Wed, 11 Dec 2024 00:37:40 -0600 Subject: [PATCH 3/5] Update link_sharepoint_attached_eml.yml --- .../link_sharepoint_attached_eml.yml | 43 ++++++++++++++----- 1 file changed, 32 insertions(+), 11 deletions(-) diff --git a/detection-rules/link_sharepoint_attached_eml.yml b/detection-rules/link_sharepoint_attached_eml.yml index fad58671940..1d0ee810fe8 100644 --- a/detection-rules/link_sharepoint_attached_eml.yml +++ b/detection-rules/link_sharepoint_attached_eml.yml @@ -29,6 +29,18 @@ source: | 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 == "") @@ -43,11 +55,11 @@ source: | // 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 != "")) - ] + [ + 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, @@ -60,11 +72,11 @@ source: | // 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 != "")) - ] + [ + 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 @@ -73,7 +85,16 @@ source: | ) ) - + // 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, .)) attack_types: - "Credential Phishing" tactics_and_techniques: From bade6cfec4ef0354a5c3b15f6b1f7197dcea7ff6 Mon Sep 17 00:00:00 2001 From: Brandon Murphy <4827852+zoomequipd@users.noreply.github.com> Date: Wed, 11 Dec 2024 01:21:13 -0600 Subject: [PATCH 4/5] Update link_sharepoint_attached_eml.yml --- .../link_sharepoint_attached_eml.yml | 51 ++++++++++++++----- 1 file changed, 38 insertions(+), 13 deletions(-) diff --git a/detection-rules/link_sharepoint_attached_eml.yml b/detection-rules/link_sharepoint_attached_eml.yml index 1d0ee810fe8..402d96e81c8 100644 --- a/detection-rules/link_sharepoint_attached_eml.yml +++ b/detection-rules/link_sharepoint_attached_eml.yml @@ -5,10 +5,18 @@ severity: "medium" source: | type.inbound and not any(body.links, .href_url.domain.root_domain == "sharepoint.com") + // ensure there is only a single .eml attachment + and length(filter(attachments, + ( + .content_type == "message/rfc822" + or .file_extension == "eml" + ) + ) + ) == 1 and any( // filter to just eml attachments filter(attachments, - .content_type == "message/rfc822" or .file_extension == "eml" + (.content_type == "message/rfc822" or .file_extension == "eml") ), // any body links go to sharepoint any(file.parse_eml(.).body.links, @@ -54,12 +62,20 @@ source: | // 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 != "")) - ] + 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, @@ -71,12 +87,20 @@ source: | // 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 != "")) - ] + 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 @@ -95,6 +119,7 @@ source: | 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, .)) + attack_types: - "Credential Phishing" tactics_and_techniques: From decc15bf08cf61fe1ae4095b3d241409de6b1e7f Mon Sep 17 00:00:00 2001 From: Brandon Murphy <4827852+zoomequipd@users.noreply.github.com> Date: Wed, 11 Dec 2024 08:43:48 -0600 Subject: [PATCH 5/5] Update link_sharepoint_attached_eml.yml --- detection-rules/link_sharepoint_attached_eml.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/detection-rules/link_sharepoint_attached_eml.yml b/detection-rules/link_sharepoint_attached_eml.yml index 402d96e81c8..c660971e199 100644 --- a/detection-rules/link_sharepoint_attached_eml.yml +++ b/detection-rules/link_sharepoint_attached_eml.yml @@ -105,6 +105,12 @@ source: | and all(recipients.to, .email.email == file.parse_eml(..).sender.email.email ) + ), + + // the attached message contains a very low number of hops, as if it was never sent + ( + length(file.parse_eml(.).headers.hops) <= 2 + or file.parse_eml(.).headers.return_path.email is null ) ) )