From 2184142c8ffe3b855863020f692fd5c94a0a7a99 Mon Sep 17 00:00:00 2001 From: Aiden Mitchell Date: Mon, 2 Dec 2024 15:05:50 -0800 Subject: [PATCH 01/67] Update impersonation_sharepoint_fake_file_share.yml (#2180) --- .../impersonation_sharepoint_body_credential_theft.yml | 1 + detection-rules/impersonation_sharepoint_fake_file_share.yml | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/detection-rules/impersonation_sharepoint_body_credential_theft.yml b/detection-rules/impersonation_sharepoint_body_credential_theft.yml index 047d931f5dd..fb646a8498d 100644 --- a/detection-rules/impersonation_sharepoint_body_credential_theft.yml +++ b/detection-rules/impersonation_sharepoint_body_credential_theft.yml @@ -15,6 +15,7 @@ source: | .name == "Microsoft SharePoint" ) or strings.istarts_with(strings.replace_confusables(body.current_thread.text), "Sharepoint") + or regex.icontains(body.html.raw, ']+style="[^"]*background-color:\s*#[0-9A-F]{2}[5-9A-F]{2}[0-9A-F]{2}[^"]*"[^>]*>[^<]*(?:open)[^<]*' // blue button containing the word "open" + ) or ( any(recipients.to, strings.icontains(body.current_thread.text, From 9624f75c0df8d9f2c697e4ddeeb87c461cb781ed Mon Sep 17 00:00:00 2001 From: Aiden Mitchell Date: Mon, 2 Dec 2024 15:19:58 -0800 Subject: [PATCH 02/67] Update attachment_adobe_image_lure_qr_code.yml (#2152) --- detection-rules/attachment_adobe_image_lure_qr_code.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/detection-rules/attachment_adobe_image_lure_qr_code.yml b/detection-rules/attachment_adobe_image_lure_qr_code.yml index b4b001acd3f..2f78d728835 100644 --- a/detection-rules/attachment_adobe_image_lure_qr_code.yml +++ b/detection-rules/attachment_adobe_image_lure_qr_code.yml @@ -16,7 +16,13 @@ source: | .name == "Adobe" ) or any(file.explode(.), - any(.scan.strings.strings, regex.icontains(., "adobe (acrobat|sign)")) + any(.scan.strings.strings, + regex.icontains(., "adobe (acrobat|sign)") + // negate PDF data, like "xmp:CreatorTool>Adobe Acrobat Pro (64-bit) 24.4.20272" + and not regex.icontains(., + "(creatortool|producer|creator).{1,5}adobe acrobat" + ) + ) ) ) ) From 88bfcde3ae518cd8814ea7327bf4f37808b733ca Mon Sep 17 00:00:00 2001 From: Aiden Mitchell Date: Mon, 2 Dec 2024 15:20:21 -0800 Subject: [PATCH 03/67] Create attachment_html_emoji_map.yml (#2135) Co-authored-by: ID Generator --- detection-rules/attachment_html_emoji_map.yml | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 detection-rules/attachment_html_emoji_map.yml diff --git a/detection-rules/attachment_html_emoji_map.yml b/detection-rules/attachment_html_emoji_map.yml new file mode 100644 index 00000000000..d929afeb223 --- /dev/null +++ b/detection-rules/attachment_html_emoji_map.yml @@ -0,0 +1,48 @@ +name: "Attachment: HTML With Emoji-to-Character Map" +description: "Detects inbound messages containing HTML attachments with an unusually high number of emojis in a list, sent from untrusted or suspicious senders who lack an established sending history or have previous malicious behavior." +type: "rule" +severity: "high" +source: | + type.inbound + and any(attachments, + ( + .file_extension in~ ("html", "htm", "shtml", "dhtml") + or .file_type == "html" + or .content_type in ("application/octet-stream", "text/html") + ) + and regex.icount(file.parse_html(.).raw, + '[\x{1F300}-\x{1F5FF}\x{1F600}-\x{1F64F}\x{1F680}-\x{1F6FF}\x{1F700}-\x{1F77F}\x{1F780}-\x{1F7FF}\x{1F900}-\x{1F9FF}\x{2600}-\x{26FF}\x{2700}-\x{27BF}\x{2300}-\x{23FF}].{0,10},' + ) > 10 + ) + and ( + ( + profile.by_sender().prevalence in ("new", "outlier") + and not profile.by_sender().solicited + ) + or profile.by_sender().any_messages_malicious_or_spam + ) + and not profile.by_sender().any_false_positives + + // negate highly trusted sender domains unless they fail DMARC authentication + and ( + ( + sender.email.domain.root_domain in $high_trust_sender_root_domains + and not headers.auth_summary.dmarc.pass + ) + or sender.email.domain.root_domain not in $high_trust_sender_root_domains + ) + +attack_types: + - "Credential Phishing" +tactics_and_techniques: + - "Evasion" + - "HTML smuggling" + - "Impersonation: Brand" + - "Scripting" + - "Social engineering" +detection_methods: + - "File analysis" + - "HTML analysis" + - "Javascript analysis" + - "Sender analysis" +id: "3119d086-13b9-549c-85b9-8117beaded4a" From 4eca6c8a7ae2f8237d3ffbe68783b39f6e69edd4 Mon Sep 17 00:00:00 2001 From: Brandon Murphy <4827852+zoomequipd@users.noreply.github.com> Date: Tue, 3 Dec 2024 15:41:21 -0600 Subject: [PATCH 04/67] Update link_adobe_share_suspicious.yml (#2181) --- detection-rules/link_adobe_share_suspicious.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/detection-rules/link_adobe_share_suspicious.yml b/detection-rules/link_adobe_share_suspicious.yml index 7d0138d1cb3..e1fb98f9529 100644 --- a/detection-rules/link_adobe_share_suspicious.yml +++ b/detection-rules/link_adobe_share_suspicious.yml @@ -42,6 +42,15 @@ source: | // the NLU detected "sender" is included within the body wrapped with new lines indicating it's a "signature" or any(filter(ml.nlu_classifier(body.current_thread.text).entities, .name == "sender" and .text not in ('Customer Support', 'SHARED ON') + // in some cases the filename is detected as the sender + // we can filter out this case when the detected "sender" + // text is the file shared + and not strings.icontains(body.current_thread.text, + strings.concat("invited you to edit\n", + .text, + "\nOpen" + ) + ) ), strings.icontains(body.current_thread.text, strings.concat("\n", .text, "\n") From 484f001d5a00aace8f1dd210b1888b7b990704a2 Mon Sep 17 00:00:00 2001 From: Brandon Murphy <4827852+zoomequipd@users.noreply.github.com> Date: Tue, 3 Dec 2024 15:41:34 -0600 Subject: [PATCH 05/67] Update link_multistage_google_drive.yml (#2182) --- detection-rules/link_multistage_google_drive.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/detection-rules/link_multistage_google_drive.yml b/detection-rules/link_multistage_google_drive.yml index 2bd989205eb..2acdcc93eda 100644 --- a/detection-rules/link_multistage_google_drive.yml +++ b/detection-rules/link_multistage_google_drive.yml @@ -32,29 +32,29 @@ source: | and ( // check the shared filed name for suspicious indicators // alerting keywords - regex.icontains(subject.subject, + regex.icontains(strings.replace_confusables(subject.subject), ': \".*(?:Immediate|Urgent|Critical|Alert|Warning|Urgent|Important|Critical Alert|Security Notice)[!:\-]?[^\"]*\"' ) // account issues - or regex.icontains(subject.subject, + or regex.icontains(strings.replace_confusables(subject.subject), ': \".*(?:Online|Bank(?:ing)?|User|Account|Access|[[:punct:]\s]?(?:ID)|Transactions)\b.*\b(?:Security|Recover|Blocked|Suspen(?:ded|sion)|Restricted|Locked|Disabled|Frozen|Closed)[^\"]*\"' ) // keywords themed as Suspicious - or regex.icontains(subject.subject, + or regex.icontains(strings.replace_confusables(subject.subject), ': \".*(Suspicious|Unauthorized|Unrecognized|Fraudulent|Scam)\b.*\b(Activity|Transaction|Log[- ]?In|Access|Entry|Sign[- ]?In|Detected)[^\"]*\"' ) // account/identify verification keywords - or regex.icontains(subject.subject, + or regex.icontains(strings.replace_confusables(subject.subject), ': \".*(?:(?:Verify|Confirm|Update|Review|Complete)\b.*\b(Your (Identity|Account|Online[- ]?ID|Billing Information))|(?:(?:Action|Attention|Verification|Review)[[:punct:]\s](?:Needed|Required)))[^\"]*\"' ) or ( // filenames that in References/ID keywords - regex.icontains(subject.subject, + regex.icontains(strings.replace_confusables(subject.subject), ': \".*[[:punct:]\s]+\w+[[:punct:]\s]*[a-zA-Z]*[0-9][a-zA-Z0-9]*\"$' ) // the above regex is a bit "open", so close it by checking it with a more specific "ending" pattern. - and regex.icontains(subject.subject, '[[:punct:]]\s*[a-z0-9]{5,}\"$') + and regex.icontains(strings.replace_confusables(subject.subject), '[[:punct:]]\s*[a-z0-9]{5,}\"$') ) // finally get ready to do link analysis From 8dc784d4072c9958367c17e3363ecf943b20ce50 Mon Sep 17 00:00:00 2001 From: Brandon Murphy <4827852+zoomequipd@users.noreply.github.com> Date: Tue, 3 Dec 2024 15:41:49 -0600 Subject: [PATCH 06/67] Create abuse_hellosign_sus_names.yml (#2085) Co-authored-by: ID Generator Co-authored-by: Sam Scholten --- detection-rules/abuse_hellosign_sus_names.yml | 178 ++++++++++++++++++ 1 file changed, 178 insertions(+) create mode 100644 detection-rules/abuse_hellosign_sus_names.yml diff --git a/detection-rules/abuse_hellosign_sus_names.yml b/detection-rules/abuse_hellosign_sus_names.yml new file mode 100644 index 00000000000..59ae8f75d35 --- /dev/null +++ b/detection-rules/abuse_hellosign_sus_names.yml @@ -0,0 +1,178 @@ +name: "Service Abuse: HelloSign Share with Suspicious Sender or Document Name" +description: "The detection rule is designed to identify messages sent from HelloSign that notify recipients about a shared file and contain suspicious content either in the document or the sender's display name." +type: "rule" +severity: "medium" +source: | + type.inbound + + // Legitimate Dropbox sending infrastructure + and sender.email.email == "noreply@mail.hellosign.com" + and headers.auth_summary.spf.pass + and headers.auth_summary.dmarc.pass + and strings.ends_with(headers.auth_summary.spf.details.designator, + '.hellosign.com' + ) + and strings.icontains(subject.subject, ' - Signature Requested') + and not strings.icontains(subject.subject, 'You just signed') + and not strings.contains(body.current_thread.text, '@cdpesign.com') // negate CDP Esign which reuses hellosign + // negate messages where the "on_behalf_of_email" is within the org_domains + and not any(headers.hops, + any(.fields, + .name == "X-Mailgun-Variables" + and any($org_domains, + // we're not able to do an exact match because the sender email + // is dynamic in nature + // but the "on_behalf_of_email" is always before "on_behalf_of_guid" + strings.icontains(..value, + strings.concat("@", ., "\", \"on_behalf_of_guid") + ) + ) + ) + ) + and ( + // contains the word dropbox + // the subject is in the format of " - Signature Requested by " + strings.icontains(subject.subject, 'dropbox') + or strings.icontains(subject.subject, 'sharefile') + or strings.icontains(subject.subject, 'helloshare') + + // sender names part of the subject + or ( + // Billing Accounting + regex.icontains(subject.subject, + ' - Signature Requested by .*Accounts? (?:Payable|Receivable)', + ' - Signature Requested by .*Billing Support' + ) + + // HR/Payroll/Legal/etc + or regex.icontains(subject.subject, + ' - Signature Requested by .*Compliance HR' + ) + or regex.icontains(subject.subject, + ' - Signature Requested by .*(?:Compliance|Executive|Finance|\bHR\b|Human Resources|\bIT\b|Legal|Payroll|Purchasing|Operations|Security|Training|Support).*(?:Department|Team)?' + ) + or regex.icontains(subject.subject, + ' - Signature Requested by .*Corporate Communications' + ) + or regex.icontains(subject.subject, + ' - Signature Requested by .*Employee Relations' + ) + or regex.icontains(subject.subject, + ' - Signature Requested by .*Office Manager' + ) + or regex.icontains(subject.subject, + ' - Signature Requested by .*Risk Management' + ) + or regex.icontains(subject.subject, + ' - Signature Requested by .*Payroll Admin(?:istrator)' + ) + + // IT related + or regex.icontains(subject.subject, + ' - Signature Requested by .*IT Support', + ' - Signature Requested by .*Information Technology', + ' - Signature Requested by .*(?:Network|System)? Admin(?:istrator)', + ' - Signature Requested by .*Help Desk', + ' - Signature Requested by .*Tech(?:nical) Support' + ) + + ) + // filename analysis + // the filename is also contianed in the subject line + or ( + // scanner themed + regex.icontains(subject.subject, 'scanne[rd].* - Signature Requested by') + // image theme + or regex.icontains(subject.subject, '_IMG_.* - Signature Requested by') + or regex.icontains(subject.subject, + 'IMG[_-](?:\d|\W)+.* - Signature Requested by' + ) + + + // Invoice Themes + or regex.icontains(subject.subject, 'Invoice.* - Signature Requested by') + or regex.icontains(subject.subject, 'INV\b.* - Signature Requested by') + or regex.icontains(subject.subject, 'Payment.* - Signature Requested by') + or regex.icontains(subject.subject, 'ACH.* - Signature Requested by') + or regex.icontains(subject.subject, + 'Wire Confirmation.* - Signature Requested by' + ) + or regex.icontains(subject.subject, + 'P[O0]\W+?\d+\".* - Signature Requested by' + ) + or regex.icontains(subject.subject, + 'P[O0](?:\W+?|\d+).* - Signature Requested by' + ) + or regex.icontains(subject.subject, 'receipt.* - Signature Requested by') + or regex.icontains(subject.subject, 'Billing.* - Signature Requested by') + or regex.icontains(subject.subject, 'statement.* - Signature Requested by') + or regex.icontains(subject.subject, 'Past Due.* - Signature Requested by') + or regex.icontains(subject.subject, + 'Remit(?:tance)?.* - Signature Requested by' + ) + or regex.icontains(subject.subject, + 'Purchase Order.* - Signature Requested by' + ) + or regex.icontains(subject.subject, 'Settlement.* - Signature Requested by') + + // contract language + or regex.icontains(subject.subject, + 'Pr[0o]p[0o]sal.* - Signature Requested by' + ) + + or regex.icontains(subject.subject, 'Claim Doc.* - Signature Requested by') + + // Payroll/HR + or regex.icontains(subject.subject, 'Payroll.* - Signature Requested by') + or regex.icontains(subject.subject, + 'Employee Pay\b.* - Signature Requested by' + ) + or regex.icontains(subject.subject, 'Salary.* - Signature Requested by') + or regex.icontains(subject.subject, + 'Benefit Enrollment.* - Signature Requested by' + ) + or regex.icontains(subject.subject, 'Employee Handbook.* - Signature Requested by' + ) + or regex.icontains(subject.subject, 'Reimbursement Approved.* - Signature Requested by' + ) + + // shared files/extenstion/urgency/CTA + or regex.icontains(subject.subject, 'Urgent.* - Signature Requested by') + or regex.icontains(subject.subject, 'Important.* - Signature Requested by') + or regex.icontains(subject.subject, 'Secure.* - Signature Requested by') + or regex.icontains(subject.subject, 'Encrypt.* - Signature Requested by') + or regex.icontains(subject.subject, 'shared.* - Signature Requested by') + or regex.icontains(subject.subject, 'protected.* - Signature Requested by') + or regex.icontains(subject.subject, 'Validate.* - Signature Requested by') + or regex.icontains(subject.subject, 'Action Required.* - Signature Requested by') + or regex.icontains(subject.subject, 'Final Notice.* - Signature Requested by') + or regex.icontains(subject.subject, 'Review(?: and| & |\s+)?Sign.* - Signature Requested by') + or regex.icontains(subject.subject, 'Download PDF.* - Signature Requested by' + ) + + // all caps filename allowing for numbers, punct and spaces, and an optional file extenstion + or regex.contains(subject.subject, + '[A-Z0-9[:punct:]\s]+(?:\.[a-zA-Z]{3,5}).* - Signature Requested by' + ) + or regex.icontains(subject.subject, + '.*(?:shared|sent).* - Signature Requested by' + ) + + // MFA theme + or regex.icontains(subject.subject, + 'Verification Code.* - Signature Requested by' + ) + or regex.icontains(subject.subject, '\bMFA\b.* - Signature Requested by') + ) + ) +attack_types: + - "Callback Phishing" + - "BEC/Fraud" +tactics_and_techniques: + - "Evasion" + - "Social engineering" +detection_methods: + - "Sender analysis" + - "Header analysis" + - "Content analysis" +id: "464d98f3-38b4-5a72-b0d5-e3a148f88025" From 5f3632e47b5fb5f857ded52d010eb096f5c2638f Mon Sep 17 00:00:00 2001 From: Brandon Murphy <4827852+zoomequipd@users.noreply.github.com> Date: Tue, 3 Dec 2024 16:40:17 -0600 Subject: [PATCH 07/67] Update impersonation_microsoft_teams.yml (#2183) --- detection-rules/impersonation_microsoft_teams.yml | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/detection-rules/impersonation_microsoft_teams.yml b/detection-rules/impersonation_microsoft_teams.yml index 33b8af0fe80..2dfaee5e5c5 100644 --- a/detection-rules/impersonation_microsoft_teams.yml +++ b/detection-rules/impersonation_microsoft_teams.yml @@ -5,13 +5,23 @@ type: "rule" severity: "high" source: | type.inbound + and length(filter(attachments, + .file_type in $file_types_images or .file_type == "pdf" + ) + ) < 10 and any(attachments, (.file_type in $file_types_images or .file_type == "pdf") and any(file.explode(.), - regex.icontains(.scan.ocr.raw, "trying to reach you.*microsoft teams") + regex.icontains(.scan.ocr.raw, + "trying to reach you.*microsoft teams" + ) ) ) - and sender.email.domain.root_domain not in ("microsoft.com", "microsoftsupport.com", "office.com") + and sender.email.domain.root_domain not in ( + "microsoft.com", + "microsoftsupport.com", + "office.com" + ) attack_types: - "Credential Phishing" tactics_and_techniques: From 635f9db2d12cd7c0a986559e0f3d024d27a93540 Mon Sep 17 00:00:00 2001 From: Aiden Mitchell Date: Wed, 4 Dec 2024 15:27:00 -0800 Subject: [PATCH 08/67] Update link_credential_phishing_voicemail_language.yml (#2189) --- .../link_credential_phishing_voicemail_language.yml | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/detection-rules/link_credential_phishing_voicemail_language.yml b/detection-rules/link_credential_phishing_voicemail_language.yml index c04fa1889fc..22bc6e38250 100644 --- a/detection-rules/link_credential_phishing_voicemail_language.yml +++ b/detection-rules/link_credential_phishing_voicemail_language.yml @@ -46,7 +46,8 @@ source: | 'left you a (?:\w+(\s\w+)?|[[:punct:]]+|\s+){0,3}(?:voice(?:mail)?|audio)(?: message)?', 'New missed ca[li1][li1] record', 'voicemail transcript(?:ion)?', - 'Listen to VoiceMail' + 'Listen to VoiceMail', + 'New voicemail from' ) // phishing template observed https://platform.sublime.security/messages/341eed2be003036cdd3eeee575202df8a7472b6567d0dfa0f99c3b3fb42a8e7f or strings.icontains(body.html.raw, 'Voicemail Notification') @@ -296,11 +297,15 @@ source: | ) ) ), - // an attachment is a pdf or image that contains a url + // an attachment is a pdf, image, or document that contains a url ( 1 <= length(attachments) <= 2 and any(attachments, - (.file_type in $file_types_images or .file_type == "pdf") + ( + .file_type in $file_types_images + or .file_type == "pdf" + or .file_extension in $file_extensions_macros + ) and any(file.explode(.), .scan.qr.type == "url" or strings.icontains(.scan.qr.data, 'http') From aed89dd5c88dceff2841effa8d3ff5fa7253c955 Mon Sep 17 00:00:00 2001 From: Aiden Mitchell Date: Wed, 4 Dec 2024 15:30:19 -0800 Subject: [PATCH 09/67] Update spam_attendee_list_solicitation.yml (#2190) --- detection-rules/spam_attendee_list_solicitation.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/detection-rules/spam_attendee_list_solicitation.yml b/detection-rules/spam_attendee_list_solicitation.yml index 46457bb0538..a4e3a7bfb55 100644 --- a/detection-rules/spam_attendee_list_solicitation.yml +++ b/detection-rules/spam_attendee_list_solicitation.yml @@ -44,7 +44,9 @@ source: | ), regex.icontains(body.current_thread.text, 'follow(?:ing)? up'), regex.icontains(body.current_thread.text, '(?:contact|attendee)s? list'), + regex.icontains(body.current_thread.text, '(any|get an) update.{0,50}\?'), strings.icontains(body.current_thread.text, 'heard back'), + strings.icontains(body.current_thread.text, 'swift response'), ) and any([body.html.display_text, body.plain.raw], ( From 3abc869637438d6388c22328361ccf716d52cc45 Mon Sep 17 00:00:00 2001 From: Aiden Mitchell Date: Thu, 5 Dec 2024 08:26:31 -0800 Subject: [PATCH 10/67] Update impersonation_paypal.yml (#2188) --- detection-rules/impersonation_paypal.yml | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/detection-rules/impersonation_paypal.yml b/detection-rules/impersonation_paypal.yml index 5c96e32cd43..eb9a0edaa07 100644 --- a/detection-rules/impersonation_paypal.yml +++ b/detection-rules/impersonation_paypal.yml @@ -15,7 +15,7 @@ source: | (.file_type in $file_types_images or .file_type == "pdf") and any(ml.logo_detect(.).brands, .name == "PayPal") and any(file.explode(.), - // exclude images taken with mobile cameras and screenshots from android + // exclude images taken with mobile cameras and screenshots from android not any(.scan.exiftool.fields, .key == "Model" or ( @@ -34,9 +34,21 @@ source: | "*transaction*", "*bitcoin*", "*dear customer*", + "*suspicious activity*" ) ) ) + or ( + any(ml.logo_detect(beta.message_screenshot()).brands, .name == "PayPal") + and strings.ilike(body.current_thread.text, "*PayPal*") + and strings.ilike(body.current_thread.text, + "*invoice*", + "*transaction*", + "*bitcoin*", + "*dear customer*", + "*suspicious activity*" + ) + ) ) and sender.email.domain.root_domain not in ( 'paypal.com', From 48efb56a1d89bfe6845285bda7a7b8af10b54fc4 Mon Sep 17 00:00:00 2001 From: Aiden Mitchell Date: Thu, 5 Dec 2024 08:26:54 -0800 Subject: [PATCH 11/67] Update impersonation_wells_fargo.yml (#2187) --- detection-rules/impersonation_wells_fargo.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/detection-rules/impersonation_wells_fargo.yml b/detection-rules/impersonation_wells_fargo.yml index d611b1bfc94..d28bad07a4b 100644 --- a/detection-rules/impersonation_wells_fargo.yml +++ b/detection-rules/impersonation_wells_fargo.yml @@ -10,8 +10,8 @@ source: | type.inbound and ( sender.display_name =~ 'wellsfargo' - or strings.ilevenshtein(sender.display_name, 'wellsfargo') <= 1 - or regex.icontains(sender.display_name, "wells?fargo") + or strings.ilevenshtein(strings.replace_confusables(sender.display_name), 'wellsfargo') <= 1 + or regex.icontains(strings.replace_confusables(sender.display_name), 'we(ll|ii)s?\s?farg(o|oอ™)') or strings.ilike(sender.email.domain.domain, '*wellsfargo*') or strings.ilike(subject.subject, '*wells fargo security*') or strings.ilike(body.plain.raw, '*wells fargo security team*') @@ -38,6 +38,7 @@ source: | and not headers.auth_summary.dmarc.pass ) or sender.email.domain.root_domain not in $high_trust_sender_root_domains + or sender.email.email in ("drive-shares-noreply@google.com", "drive-shares-dm-noreply@google.com") // Google Drive abuse has been observed ) attack_types: From 5038d75b69decee31901d3425b56f527176788e2 Mon Sep 17 00:00:00 2001 From: Aiden Mitchell Date: Thu, 5 Dec 2024 08:27:25 -0800 Subject: [PATCH 12/67] Update impersonation_employee_payroll_fraud.yml (#2191) --- detection-rules/impersonation_employee_payroll_fraud.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/detection-rules/impersonation_employee_payroll_fraud.yml b/detection-rules/impersonation_employee_payroll_fraud.yml index 675e326c2cd..a2bbff19da2 100644 --- a/detection-rules/impersonation_employee_payroll_fraud.yml +++ b/detection-rules/impersonation_employee_payroll_fraud.yml @@ -19,10 +19,10 @@ source: | ) and 1 of ( regex.icontains(body.current_thread.text, - '(pay\s?(roll|check|date|day)|direct deposit|\bACH\b|\bdd\b|gehalt|salario|salary)' + '(pay\s?(roll|check|date|day)|direct deposit|(acct|account) rephrase|paid.{0,50}problems|\bACH\b|\bdd\b|gehalt|salario|salary)' ), regex.icontains(subject.subject, - '(pay\s?(roll|check|date|day)|direct deposit|\bACH\b|\bdd\b|gehalt|salario|salary)' + '(pay\s?(roll|check|date|day)|direct deposit|(acct|account) rephrase|paid.{0,50}problems|\bACH\b|\bdd\b|gehalt|salario|salary)' ) ) and ( From 4f77539fe8063510f4a6aeafede001f0682346b1 Mon Sep 17 00:00:00 2001 From: Brandon Murphy <4827852+zoomequipd@users.noreply.github.com> Date: Thu, 5 Dec 2024 14:40:51 -0600 Subject: [PATCH 13/67] Update body_job_scam_unsolicited.yml (#2193) --- detection-rules/body_job_scam_unsolicited.yml | 47 ++++++++++--------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/detection-rules/body_job_scam_unsolicited.yml b/detection-rules/body_job_scam_unsolicited.yml index 6bb91e0b5f2..c6cf20a2391 100644 --- a/detection-rules/body_job_scam_unsolicited.yml +++ b/detection-rules/body_job_scam_unsolicited.yml @@ -5,30 +5,31 @@ type: "rule" severity: "low" source: | type.inbound - and any(ml.nlu_classifier(body.current_thread.text).intents, - .name in ("job_scam") - and .confidence == "high" - and ( - any(ml.nlu_classifier(body.current_thread.text).entities, - .name == "financial" - ) - or strings.icontains(body.current_thread.text, "kindly") - or ( - any(ml.nlu_classifier(body.current_thread.text).entities, - .name in ("greeting", "salutation") - ) - and ( - ( - length(recipients.to) == 0 - or length(recipients.bcc) > 0 - or ( - all(recipients.to, .email.domain.valid == false) - and all(recipients.cc, .email.domain.valid == false) - ) - ) - ) - ) + and ( + any(ml.nlu_classifier(body.current_thread.text).intents, + .name in ("job_scam") and .confidence == "high" + ) + ) + and ( + any(ml.nlu_classifier(body.current_thread.text).entities, + .name == "financial" + ) + or strings.icontains(body.current_thread.text, "kindly") + or ( + any(ml.nlu_classifier(body.current_thread.text).entities, + .name in ("greeting", "salutation") + ) + and ( + ( + length(recipients.to) == 0 + or length(recipients.bcc) > 0 + or ( + all(recipients.to, .email.domain.valid == false) + and all(recipients.cc, .email.domain.valid == false) ) + ) + ) + ) ) and ( not profile.by_sender().solicited From a5b4f98edad5a1f1706553c43e71ec29d64002e0 Mon Sep 17 00:00:00 2001 From: Brandon Murphy <4827852+zoomequipd@users.noreply.github.com> Date: Thu, 5 Dec 2024 14:41:04 -0600 Subject: [PATCH 14/67] lower severity of abuse_docusign_unsolicited_reply-to.yml (#2175) --- detection-rules/abuse_docusign_unsolicited_reply-to.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/detection-rules/abuse_docusign_unsolicited_reply-to.yml b/detection-rules/abuse_docusign_unsolicited_reply-to.yml index 8ff372cfbc5..07fe308cdf3 100644 --- a/detection-rules/abuse_docusign_unsolicited_reply-to.yml +++ b/detection-rules/abuse_docusign_unsolicited_reply-to.yml @@ -1,7 +1,7 @@ name: "Service Abuse: DocuSign Share From an Unsolicited Reply-To Address" description: "DocuSign shares which contain a reply-to address or domain that has not been previously observed by the recipient organization." type: "rule" -severity: "high" +severity: "medium" source: | type.inbound From 47b474c9867c0fe9c49c77741d583f4eee4de35c Mon Sep 17 00:00:00 2001 From: Sam Scholten Date: Fri, 6 Dec 2024 17:24:00 -0500 Subject: [PATCH 15/67] Update paypal_invoice_abuse.yml (#2184) --- detection-rules/paypal_invoice_abuse.yml | 40 +++++++++++++++--------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/detection-rules/paypal_invoice_abuse.yml b/detection-rules/paypal_invoice_abuse.yml index 05435537a8c..87e2d188b3c 100644 --- a/detection-rules/paypal_invoice_abuse.yml +++ b/detection-rules/paypal_invoice_abuse.yml @@ -10,7 +10,13 @@ severity: "medium" source: | type.inbound and length(attachments) == 0 - and sender.email.domain.root_domain in ("paypal.com", "paypal.com.mx", "paypal.com.br", "paypal.com.ar", "paypal.co.uk") + and sender.email.domain.root_domain in ( + "paypal.com", + "paypal.com.mx", + "paypal.com.br", + "paypal.com.ar", + "paypal.co.uk" + ) and ( strings.ilike(body.html.display_text, "*seller note*") or strings.ilike(body.html.display_text, "*Note from *") @@ -26,19 +32,19 @@ source: | '.*\+[lo0-9]{1,3}[lo0-9]{10}.*\n' ) or // +12028001238 - regex.icontains(strings.replace_confusables(body.current_thread.text), + regex.icontains(strings.replace_confusables(body.current_thread.text), '.*[lo0-9]{3}\.[lo0-9]{3}\.[lo0-9]{4}.*\n' ) or // 202-800-1238 - regex.icontains(strings.replace_confusables(body.current_thread.text), + regex.icontains(strings.replace_confusables(body.current_thread.text), '.*[lo0-9]{3}-[lo0-9]{3}-[lo0-9]{4}.*\n' ) or // (202) 800-1238 - regex.icontains(strings.replace_confusables(body.current_thread.text), + regex.icontains(strings.replace_confusables(body.current_thread.text), '.*\([lo0-9]{3}\)\s[lo0-9]{3}-[lo0-9]{4}.*\n' ) or // (202)-800-1238 - regex.icontains(strings.replace_confusables(body.current_thread.text), + regex.icontains(strings.replace_confusables(body.current_thread.text), '.*\([lo0-9]{3}\)-[lo0-9]{3}-[lo0-9]{4}.*\n' ) or ( // 8123456789 @@ -58,13 +64,15 @@ source: | strings.ilike(body.html.inner_text, '*is not for*'), strings.ilike(body.html.inner_text, '*done by you*'), regex.icontains(body.html.inner_text, "didn\'t ma[kd]e this"), - strings.ilike(body.html.inner_text, "*Fruad Alert*"), - strings.ilike(body.html.inner_text, "*Fraud Alert*"), + strings.ilike(body.html.inner_text, '*Fruad Alert*'), + strings.ilike(body.html.inner_text, '*Fraud Alert*'), + strings.ilike(body.html.inner_text, '*fraudulent*'), strings.ilike(body.html.inner_text, '*using your PayPal*'), strings.ilike(body.html.inner_text, '*subscription*'), strings.ilike(body.html.inner_text, '*antivirus*'), strings.ilike(body.html.inner_text, '*order*'), strings.ilike(body.html.inner_text, '*support*'), + strings.ilike(body.html.inner_text, '*sincerely apologize*'), strings.ilike(body.html.inner_text, '*receipt*'), strings.ilike(body.html.inner_text, '*invoice*'), strings.ilike(body.html.inner_text, '*Purchase*'), @@ -76,6 +84,7 @@ source: | strings.ilike(body.html.inner_text, '*quickly inform*'), strings.ilike(body.html.inner_text, '*quickly reach *'), strings.ilike(body.html.inner_text, '*detected unusual transactions*'), + strings.ilike(body.html.inner_text, '*without your authorization*'), strings.ilike(body.html.inner_text, '*cancel*'), strings.ilike(body.html.inner_text, '*renew*'), strings.ilike(body.html.inner_text, '*refund*'), @@ -86,15 +95,18 @@ source: | or regex.icontains(body.current_thread.text, 'note from.{0,50}(?:call|reach|contact|paypal)' ) + or any(ml.nlu_classifier(body.current_thread.text).intents, + .name == "callback_scam" + ) + or ( + // Unicode confusables words obfuscated in note + regex.icontains(body.html.inner_text, + '\+๐Ÿญ|๐—ฝ๐—ฎ๐˜†๐—บ๐—ฒ๐—ป๐˜|๐—›๐—ฒ๐—น๐—ฝ ๐——๐—ฒ๐˜€๐—ธ|๐—ฟ๐—ฒ๐—ณ๐˜‚๐—ป๐—ฑ|๐—ฎ๐—ป๐˜๐—ถ๐˜ƒ๐—ถ๐—ฟ๐˜‚๐˜€|๐—ฐ๐—ฎ๐—น๐—น|๐—ฐ๐—ฎ๐—ป๐—ฐ๐—ฒ๐—น' + ) + ) + or strings.ilike(body.html.inner_text, '*kindly*') ) ) - or ( - // Unicode confusables words obfuscated in note - regex.icontains(body.html.inner_text, - '\+๐Ÿญ|๐—ฝ๐—ฎ๐˜†๐—บ๐—ฒ๐—ป๐˜|๐—›๐—ฒ๐—น๐—ฝ ๐——๐—ฒ๐˜€๐—ธ|๐—ฟ๐—ฒ๐—ณ๐˜‚๐—ป๐—ฑ|๐—ฎ๐—ป๐˜๐—ถ๐˜ƒ๐—ถ๐—ฟ๐˜‚๐˜€|๐—ฐ๐—ฎ๐—น๐—น|๐—ฐ๐—ฎ๐—ป๐—ฐ๐—ฒ๐—น' - ) - ) - or strings.ilike(body.html.inner_text, '*kindly*') ) attack_types: - "BEC/Fraud" From 1298a8b9b0e88852a26d5bd98cf29098cf8b1705 Mon Sep 17 00:00:00 2001 From: Brandon Murphy <4827852+zoomequipd@users.noreply.github.com> Date: Tue, 10 Dec 2024 09:36:26 -0600 Subject: [PATCH 16/67] =?UTF-8?q?Update=20credential=5Fphishing=5Fcorporat?= =?UTF-8?q?e=5Fservices=5Fimpersonation=5Fwith=5Fsusp=E2=80=A6=20(#2202)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...ces_impersonation_with_suspicious_link.yml | 96 +++++++++++-------- 1 file changed, 54 insertions(+), 42 deletions(-) diff --git a/detection-rules/credential_phishing_corporate_services_impersonation_with_suspicious_link.yml b/detection-rules/credential_phishing_corporate_services_impersonation_with_suspicious_link.yml index 5d23ee0f394..de15264ef5e 100644 --- a/detection-rules/credential_phishing_corporate_services_impersonation_with_suspicious_link.yml +++ b/detection-rules/credential_phishing_corporate_services_impersonation_with_suspicious_link.yml @@ -4,60 +4,71 @@ type: "rule" severity: "high" source: | type.inbound - and 0 < length(body.links) < 8 - + // use distinct "urls" (without query params) to determine number of links + and 0 < length(distinct(body.links, + // strip out query params to determine + // the unique number of links + strings.concat(.href_url.scheme, + .href_url.domain.domain, + .href_url.path + ) + ) + ) <= 8 + // HR language found in subject and ( ( length(subject.subject) > 20 and regex.icontains(subject.subject, - '(time.{0,4}sheet)|(employ).{0,30}(benefit|handbook|comp\b|compensation|salary|pay(roll)?|policy|conduct|acknowl|PTO|vacation)' + '(time.{0,4}sheet)|(employ|update(?:d| to)).{0,30}(benefit|handbook|comp\b|compensation|salary|pay(roll)?|policy|conduct|acknowl|PTO|vacation)' ) ) - + // or HR language found in sender or ( regex.icontains(sender.display_name, - '(Employ|Time.{0,3}sheet|\bHR\b|Human R|Handbook|\bIT[- ]|Help.{0,3}Desk)' + '(Employ|Time.{0,3}sheet|\bHR\b|Human R|Handbook|\bIT[- ]|Help.{0,3}Desk)|Internal.?Comm' ) and not regex.icontains(sender.display_name, "forum|employee voice|briefs|newsletter|screening" ) - and not regex.icontains(sender.display_name, "HR (new|vue|view|tech admin|global)") + and not regex.icontains(sender.display_name, + "HR (new|vue|view|tech admin|global)" + ) ) ) - + // suspicious display_text and ( - any(body.links, - regex.icontains(.display_text, - '((verify|view|click|download|goto|keep|Vฮนew|release).{0,10}(request|here|attachment|current|download|fax|file|document|message|same)s?)' - ) - and not strings.ilike(.display_text, "*unsub*") - and not strings.ilike(.href_url.url, "*privacy-policy*") - and not strings.ilike(.display_text, "*REGISTER*") + any(body.links, + regex.icontains(.display_text, + '((verify|view|click|download|goto|keep|Vฮนew|release).{0,10}(request|here|attachment|current|download|fax|file|document|message|same)s?)' + ) + and not strings.ilike(.display_text, "*unsub*") + and not strings.ilike(.href_url.url, "*privacy-policy*") + and not strings.ilike(.display_text, "*REGISTER*") - // from a low reputation link - and ( - not .href_url.domain.root_domain in $org_domains + // from a low reputation link and ( - .href_url.domain.root_domain not in $tranco_1m - or .href_url.domain.domain in $free_file_hosts - or .href_url.domain.root_domain in $free_file_hosts - or .href_url.domain.root_domain in $free_subdomain_hosts - or .href_url.domain.domain in $url_shorteners + not .href_url.domain.root_domain in $org_domains + and ( + .href_url.domain.root_domain not in $tranco_1m + or .href_url.domain.domain in $free_file_hosts + or .href_url.domain.root_domain in $free_file_hosts + or .href_url.domain.root_domain in $free_subdomain_hosts + or .href_url.domain.domain in $url_shorteners + ) + or + // or mass mailer link, masks the actual URL + .href_url.domain.root_domain in ( + "hubspotlinks.com", + "mandrillapp.com", + "sendgrid.net", + "rs6.net", + "mailanyone.net", + ) ) - or - // or mass mailer link, masks the actual URL - .href_url.domain.root_domain in ( - "hubspotlinks.com", - "mandrillapp.com", - "sendgrid.net", - "rs6.net", - "mailanyone.net", - ) - ) - ) + ) // or credential theft confidence high or ( length(body.links) > 0 @@ -75,14 +86,14 @@ source: | // negate messages where "click here" was found and was a link actually an unsub link // this method allows for matching on other 'click here' links if they are present and not ( - length(filter(body.links, strings.icontains(.display_text, 'click here'))) > 0 - and ( - length(filter(body.links, strings.icontains(.display_text, 'click here'))) - == - strings.icount(body.current_thread.text, 'click here to unsubscribe') + length(filter(body.links, strings.icontains(.display_text, 'click here'))) > 0 + and ( + length(filter(body.links, strings.icontains(.display_text, 'click here'))) == strings.icount(body.current_thread.text, + 'click here to unsubscribe' ) + ) ) - + // negate highly trusted sender domains unless they fail DMARC authentication and ( ( @@ -99,8 +110,9 @@ source: | ) // not from sharepointonline actual and not ( - sender.email.domain.root_domain == "sharepointonline.com" and - strings.ends_with(headers.message_id, '@odspnotify>') and strings.starts_with(headers.message_id, "') + and strings.starts_with(headers.message_id, " Date: Wed, 11 Dec 2024 10:23:21 -0800 Subject: [PATCH 17/67] Increase page size & debug test rule removal (#2211) --- .github/workflows/clear-old-test-rules.yml | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/.github/workflows/clear-old-test-rules.yml b/.github/workflows/clear-old-test-rules.yml index f0cefca1ccb..a5a06aef464 100644 --- a/.github/workflows/clear-old-test-rules.yml +++ b/.github/workflows/clear-old-test-rules.yml @@ -26,12 +26,15 @@ jobs: uses: actions/github-script@v4 with: script: | - github.pulls.list({ - owner: context.repo.owner, - repo: context.repo.repo, - state: 'open' - }).then((result) => { - const openPRs = result.data.map(pr => pr.number); + github.paginate( + github.pulls.list, + { + owner: context.repo.owner, + repo: context.repo.repo, + state: 'open', + }, + (response) => response.data.map((pr) => pr.number) + ).then((openPRs) => { console.log(`::set-output name=open_prs::${openPRs.join(',')}`); }); @@ -43,6 +46,8 @@ jobs: echo "This is a forked repository. Skipping the job." exit 0 fi + + echo "Open PRs: [$OPEN_PRS]" echo "Scheduled cleanup" > message.txt echo "" >> message.txt @@ -61,6 +66,7 @@ jobs: fi done + echo "$file is in open PR: $in_open_pr. File PR num: $file_pr_num" if [[ "$in_open_pr" = "false" ]]; then rm $file echo "Removed $file_pr_num" >> ../message.txt From 450267aec485137c288e41e66d684a6518ff650d Mon Sep 17 00:00:00 2001 From: Aiden Mitchell Date: Thu, 12 Dec 2024 11:22:44 -0800 Subject: [PATCH 18/67] Update body_extortion.yml (#2207) --- detection-rules/body_extortion.yml | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/detection-rules/body_extortion.yml b/detection-rules/body_extortion.yml index a37e4abde09..ebeb51ed28f 100644 --- a/detection-rules/body_extortion.yml +++ b/detection-rules/body_extortion.yml @@ -9,34 +9,34 @@ source: | type.inbound and ( ( - any(ml.nlu_classifier(body.current_thread.text).intents, + any(ml.nlu_classifier(strings.replace_confusables(body.current_thread.text)).intents, .name == "extortion" and .confidence == "high" ) - and any(ml.nlu_classifier(body.current_thread.text).entities, + and any(ml.nlu_classifier(strings.replace_confusables(body.current_thread.text)).entities, .name == "financial" ) ) // manual indicators failsafe or 3 of ( // malware terms - regex.icontains(body.current_thread.text, "((spy|mal)ware|trojan|remote control)"), + regex.icontains(strings.replace_confusables(body.current_thread.text), "((spy|mal)ware|trojan|remote control)"), // actions recorded - regex.icontains(body.current_thread.text, + regex.icontains(strings.replace_confusables(body.current_thread.text), "porn|adult (web)?site|webcam|masturbating|jerking off|pleasuring yourself|getting off" ), - regex.icontains(body.current_thread.text, "pervert|perversion|masturbat"), + regex.icontains(strings.replace_confusables(body.current_thread.text), "pervert|perversion|masturbat"), // a timeframe to pay - regex.icontains(body.current_thread.text, '\d\d hours', '(?:one|two|three|\d) days?'), + regex.icontains(strings.replace_confusables(body.current_thread.text), '\d\d hours', '(?:one|two|three|\d) days?'), // a promise from the actor - regex.icontains(body.current_thread.text, + regex.icontains(strings.replace_confusables(body.current_thread.text), 'permanently delete|(remove|destroy) (?:\w+\s*){0,4} (?:data|evidence|videos?)' ), // a threat from the actor - regex.icontains(body.current_thread.text, + regex.icontains(strings.replace_confusables(body.current_thread.text), 'sen[dt]\s*(?:\w+\s*){0,2}\s*to\s*(?:\w+\s*){0,3}\s*your contacts'), // bitcoin language (excluding newsletters) ( - regex.icontains(body.current_thread.text, 'bitcoin|\bbtc\b|blockchain') + regex.icontains(strings.replace_confusables(body.current_thread.text), 'bitcoin|\bbtc\b|blockchain') // negate cryptocurrency newsletters and not ( any(body.links, @@ -56,14 +56,14 @@ source: | ), // bitcoin wallet address + threat ( - strings.icontains(body.current_thread.text, + strings.icontains(strings.replace_confusables(body.current_thread.text), "contact the police" ) - and regex.icontains(body.current_thread.text, + and regex.icontains(strings.replace_confusables(body.current_thread.text), '(\b[13][a-km-zA-HJ-NP-Z0-9]{24,33}\b)|\bX[1-9A-HJ-NP-Za-km-z]{33}\b|\b(0x[a-fA-F0-9]{40})\b|\b[LM3][a-km-zA-HJ-NP-Z1-9]{26,33}\b|\b[48][0-9AB][1-9A-HJ-NP-Za-km-z]{93}\b' ) ), - regex.icontains(body.current_thread.text, 'bc1q.{0,50}\b') + regex.icontains(strings.replace_confusables(body.current_thread.text), 'bc1q.{0,50}\b') ) ) and ( From 921ae3ccb47c71cf285ba0d11b70ed7a65486f76 Mon Sep 17 00:00:00 2001 From: Aiden Mitchell Date: Thu, 12 Dec 2024 11:23:24 -0800 Subject: [PATCH 19/67] Update attachment_free_subdomain_suspicious_link_language.yml (#2212) --- ...ree_subdomain_suspicious_link_language.yml | 26 ++++++++++++++++--- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/detection-rules/attachment_free_subdomain_suspicious_link_language.yml b/detection-rules/attachment_free_subdomain_suspicious_link_language.yml index 80600bb8977..b3436acbefc 100644 --- a/detection-rules/attachment_free_subdomain_suspicious_link_language.yml +++ b/detection-rules/attachment_free_subdomain_suspicious_link_language.yml @@ -10,12 +10,30 @@ source: | and .href_url.domain.subdomain is not null and .href_url.domain.subdomain != "www" ) - and (length(recipients.to) == 0 or all(recipients.to, .display_name == "Undisclosed recipients")) - and length(recipients.cc) == 0 - and length(recipients.bcc) == 0 + and ( + ( + ( + length(recipients.to) == 0 + or all(recipients.to, .display_name == "Undisclosed recipients") + ) + and length(recipients.cc) == 0 + and length(recipients.bcc) == 0 + ) + or ( + length(recipients.to) == 1 + and any(recipients.to, .email.email == sender.email.email) + ) + or ( + length(recipients.to) == 0 + and length(recipients.cc) == 0 + and length(recipients.bcc) > 0 + ) + ) and any(body.links, any(file.explode(ml.link_analysis(.).screenshot), - any(ml.nlu_classifier(.scan.ocr.raw).intents, .name == "cred_theft" and .confidence != "low") + any(ml.nlu_classifier(.scan.ocr.raw).intents, + .name == "cred_theft" and .confidence != "low" + ) ) ) tags: From 18af1961656ccedf3d1b834173838a0114d57c53 Mon Sep 17 00:00:00 2001 From: Peter Djordjevic <116412909+peterdj45@users.noreply.github.com> Date: Thu, 12 Dec 2024 12:11:06 -0800 Subject: [PATCH 20/67] Update impersonation_vip_urgent_request.yml (#2087) Co-authored-by: Sam Scholten --- detection-rules/impersonation_vip_urgent_request.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/detection-rules/impersonation_vip_urgent_request.yml b/detection-rules/impersonation_vip_urgent_request.yml index bad63d6041b..e955fde6c2b 100644 --- a/detection-rules/impersonation_vip_urgent_request.yml +++ b/detection-rules/impersonation_vip_urgent_request.yml @@ -31,7 +31,12 @@ source: | and not profile.by_sender().any_false_positives ) ) - + // negate sharepoint notifications originating from within the org + and not ( + sender.email.email in ('no-reply@sharepointonline.com') + and length(headers.reply_to) > 0 + and all(headers.reply_to, .email.domain.root_domain in $org_domains) + ) // negate highly trusted sender domains unless they fail DMARC authentication and ( ( From 4e8a5ebdca831989460984f834af0ea292466c19 Mon Sep 17 00:00:00 2001 From: Peter Djordjevic <116412909+peterdj45@users.noreply.github.com> Date: Fri, 13 Dec 2024 08:21:14 -0800 Subject: [PATCH 21/67] Update suspicious_request_for_quote_or_purchase.yml (#2217) --- detection-rules/suspicious_request_for_quote_or_purchase.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/detection-rules/suspicious_request_for_quote_or_purchase.yml b/detection-rules/suspicious_request_for_quote_or_purchase.yml index cb5738d04f6..4253793cd24 100644 --- a/detection-rules/suspicious_request_for_quote_or_purchase.yml +++ b/detection-rules/suspicious_request_for_quote_or_purchase.yml @@ -39,7 +39,7 @@ source: | '(sign(ed?)|view).{0,10}(purchase order)|Request for a Quot(e|ation)' ) ), - (regex.icontains(body.current_thread.text, '(please|kindly).{0,30}quote')), + (regex.icontains(body.current_thread.text, '(please|kindly).{0,30}quot(e|ation)')), ( regex.icontains(subject.subject, '(request for (purchase|quot(e|ation))|\bRFQ\b|\bRFP\b)' From eaff6101908b2dc169cc6729f01c0a3e1aae3d5b Mon Sep 17 00:00:00 2001 From: Aiden Mitchell Date: Fri, 13 Dec 2024 08:43:51 -0800 Subject: [PATCH 22/67] Update impersonation_sharepoint_fake_file_share.yml (#2213) --- detection-rules/impersonation_sharepoint_fake_file_share.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/detection-rules/impersonation_sharepoint_fake_file_share.yml b/detection-rules/impersonation_sharepoint_fake_file_share.yml index b24422a89ef..25d3ad383fc 100644 --- a/detection-rules/impersonation_sharepoint_fake_file_share.yml +++ b/detection-rules/impersonation_sharepoint_fake_file_share.yml @@ -264,7 +264,7 @@ source: | or sender.email.domain.root_domain not in $high_trust_sender_root_domains ) and ( - (not profile.by_sender().solicited) + not profile.by_sender_email().solicited or ( profile.by_sender().any_messages_malicious_or_spam and not profile.by_sender().any_false_positives From 5f67fa175dfd1548b359591240899e7469305b99 Mon Sep 17 00:00:00 2001 From: Brandon Murphy <4827852+zoomequipd@users.noreply.github.com> Date: Mon, 16 Dec 2024 07:49:44 -0600 Subject: [PATCH 23/67] Update impersonation_sharepoint_fake_file_share.yml (#2219) Co-authored-by: Sam Scholten --- ...personation_sharepoint_fake_file_share.yml | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/detection-rules/impersonation_sharepoint_fake_file_share.yml b/detection-rules/impersonation_sharepoint_fake_file_share.yml index 25d3ad383fc..024f1f19389 100644 --- a/detection-rules/impersonation_sharepoint_fake_file_share.yml +++ b/detection-rules/impersonation_sharepoint_fake_file_share.yml @@ -15,7 +15,9 @@ source: | "*shared a file with you*", "*shared with you*", "*invited you to access a file*", - "*you've received a document*" + "*received a document*", + "*shared a document*", + "*shared this document*" ) ) or any(file.explode(beta.message_screenshot()), @@ -23,7 +25,9 @@ source: | "*shared a file with you*", "*shared with you*", "*invited you to access a file*", - "*you've received a document*" + "*received a document*", + "*shared a document*", + "*shared this document*" ) ) ) @@ -40,8 +44,14 @@ source: | "*PowerPoint*", "*OneNote*" ) + or any(body.links, strings.icontains(.display_text, "OPEN DOCUMENT")) or subject.subject is null or subject.subject == "" + // the org as determined by NLU is in the subject + or any(ml.nlu_classifier(body.current_thread.text).entities, + .name == "org" and strings.icontains(subject.subject, .text) + ) + ) ) or any([ @@ -210,7 +220,7 @@ source: | regex.icontains(body.html.raw, 'rgb\((25[0-5]),\s?(20[0-2]),\s?([0-7])\)') ) or regex.icontains(body.html.raw, - ']+style="[^"]*background-color:\s*#[0-9A-F]{2}[5-9A-F]{2}[0-9A-F]{2}[^"]*"[^>]*>[^<]*(?:open)[^<]*' // blue button containing the word "open" + ']+style="[^"]*background-color:\s*#[0-9A-F]{2}[5-9A-F]{2}[0-9A-F]{2}[^"]*"[^>]*>[^<]*(?:open)[^<]*' // blue button containing the word "open" ) or ( any(recipients.to, @@ -264,7 +274,8 @@ source: | or sender.email.domain.root_domain not in $high_trust_sender_root_domains ) and ( - not profile.by_sender_email().solicited + profile.by_sender().solicited == false + or profile.by_sender_email().prevalence == "new" or ( profile.by_sender().any_messages_malicious_or_spam and not profile.by_sender().any_false_positives From c4dd4865e34fe5a6950c506c862629d66cc2a1d4 Mon Sep 17 00:00:00 2001 From: Brandon Murphy <4827852+zoomequipd@users.noreply.github.com> Date: Mon, 16 Dec 2024 07:49:56 -0600 Subject: [PATCH 24/67] Update impersonation_employee_payroll_fraud.yml (#2220) --- detection-rules/impersonation_employee_payroll_fraud.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/detection-rules/impersonation_employee_payroll_fraud.yml b/detection-rules/impersonation_employee_payroll_fraud.yml index a2bbff19da2..b7c8409840e 100644 --- a/detection-rules/impersonation_employee_payroll_fraud.yml +++ b/detection-rules/impersonation_employee_payroll_fraud.yml @@ -26,7 +26,7 @@ source: | ) ) and ( - not profile.by_sender().solicited + not profile.by_sender_email().solicited or ( profile.by_sender().any_messages_malicious_or_spam and not profile.by_sender().any_false_positives From 9cbe2f678aa615697d1ed15b80e72bc7e551dcd5 Mon Sep 17 00:00:00 2001 From: Brandon Murphy <4827852+zoomequipd@users.noreply.github.com> Date: Mon, 16 Dec 2024 09:08:16 -0600 Subject: [PATCH 25/67] Update impersonation_x_with_credphish_nlu.yml (#2221) --- detection-rules/impersonation_x_with_credphish_nlu.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/detection-rules/impersonation_x_with_credphish_nlu.yml b/detection-rules/impersonation_x_with_credphish_nlu.yml index 3ebc1eda1d1..37523123103 100644 --- a/detection-rules/impersonation_x_with_credphish_nlu.yml +++ b/detection-rules/impersonation_x_with_credphish_nlu.yml @@ -30,6 +30,7 @@ source: | profile.by_sender().any_messages_malicious_or_spam and not profile.by_sender().any_false_positives ) + or sender.email.email in ("noreply@salesforce.com", "support@salesforce.com") ) // negate highly trusted sender domains unless they fail DMARC authentication @@ -39,6 +40,9 @@ source: | and not headers.auth_summary.dmarc.pass ) or sender.email.domain.root_domain not in $high_trust_sender_root_domains + + // salesforce has been abused for x/twitter phishing campaigns repeatedly + or sender.email.domain.root_domain == "salesforce.com" ) attack_types: - "Credential Phishing" From ddbc3da7e6b3e30017038dae1f38ce6ded8d79e8 Mon Sep 17 00:00:00 2001 From: Brandon Murphy <4827852+zoomequipd@users.noreply.github.com> Date: Mon, 16 Dec 2024 09:08:32 -0600 Subject: [PATCH 26/67] Create abuse_quickbooks_impersonation_intuit.yml (#2054) Co-authored-by: ID Generator Co-authored-by: Aiden Mitchell --- .../abuse_quickbooks_impersonation_intuit.yml | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 detection-rules/abuse_quickbooks_impersonation_intuit.yml diff --git a/detection-rules/abuse_quickbooks_impersonation_intuit.yml b/detection-rules/abuse_quickbooks_impersonation_intuit.yml new file mode 100644 index 00000000000..f2cbfede2ed --- /dev/null +++ b/detection-rules/abuse_quickbooks_impersonation_intuit.yml @@ -0,0 +1,43 @@ +name: "Brand Impersonation: QuickBooks Notification From Intuit Themed Company Name" +description: "This detection rule matches on QuickBooks notifications that feature company names impersonating Intuit and QuickBooks." +type: "rule" +severity: "medium" +source: | + type.inbound + + // Legitimate Intuit sending infratructure + and sender.email.email == "quickbooks@notification.intuit.com" + and headers.auth_summary.spf.pass + and headers.auth_summary.dmarc.pass + and strings.ends_with(headers.auth_summary.spf.details.designator, + '.intuit.com' + ) + and ( + // subject also contains the company name + strings.icontains(subject.subject, "Quickbooks") + or strings.icontains(subject.subject, "Intuit") + // the reply-to contains Inuit Themes + or any(headers.reply_to, + ( + strings.icontains(.email.email, 'intuit') + or strings.icontains(.email.domain.domain, 'quickbooks') + ) + and not (.email.domain.root_domain in ('intuit.com', 'quickbooks.com')) + ) + // the "company" part of the message + or regex.icontains(body.html.raw, + '

.*(?:Intuit|Quickbooks).*

' + ) + ) +attack_types: + - "Callback Phishing" + - "Credential Phishing" + - "BEC/Fraud" +tactics_and_techniques: + - "Evasion" + - "Social engineering" +detection_methods: + - "Content analysis" + - "Sender analysis" + - "Header analysis" +id: "42058fc4-d700-5bc3-9ee9-91641d9343c2" From ab0c1f38bd00972523f8bbad42423e7ab2a1d967 Mon Sep 17 00:00:00 2001 From: Brandon Murphy <4827852+zoomequipd@users.noreply.github.com> Date: Mon, 16 Dec 2024 09:09:42 -0600 Subject: [PATCH 27/67] Update abuse_docusign_unsolicited_reply-to.yml (#2204) --- detection-rules/abuse_docusign_unsolicited_reply-to.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/detection-rules/abuse_docusign_unsolicited_reply-to.yml b/detection-rules/abuse_docusign_unsolicited_reply-to.yml index 07fe308cdf3..4fa5b80c72a 100644 --- a/detection-rules/abuse_docusign_unsolicited_reply-to.yml +++ b/detection-rules/abuse_docusign_unsolicited_reply-to.yml @@ -44,7 +44,7 @@ source: | or .email.domain.domain not in $free_email_providers ) ), - .email.domain.root_domain in $sender_domains + .email.domain.domain in $sender_domains ) ) tags: From bb05c14ec13032ff4d247f79b52cc1ae8ba65420 Mon Sep 17 00:00:00 2001 From: Brandon Murphy <4827852+zoomequipd@users.noreply.github.com> Date: Mon, 16 Dec 2024 09:10:02 -0600 Subject: [PATCH 28/67] Update impersonation_usps.yml (#2206) --- detection-rules/impersonation_usps.yml | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/detection-rules/impersonation_usps.yml b/detection-rules/impersonation_usps.yml index 2f6b310cc6e..d730a013bdd 100644 --- a/detection-rules/impersonation_usps.yml +++ b/detection-rules/impersonation_usps.yml @@ -26,11 +26,16 @@ source: | // no links go to usps.com all(body.links, .href_url.domain.root_domain != "usps.com") ) - and ( - sender.email.domain.root_domain not in ("usps.com") + sender.email.domain.root_domain not in ( + "usps.com", + "opinions-inmoment.com" // https://faq.usps.com/s/article/USPS-Customer-Experience-Surveys + ) or ( - sender.email.domain.root_domain in ("usps.com") + sender.email.domain.root_domain in ( + "usps.com", + "opinions-inmoment.com" // https://faq.usps.com/s/article/USPS-Customer-Experience-Surveys + ) and not headers.auth_summary.dmarc.pass ) ) From 214b2a603dd3e8384e30b2a80d5477293d3a364c Mon Sep 17 00:00:00 2001 From: Brandon Murphy <4827852+zoomequipd@users.noreply.github.com> Date: Mon, 16 Dec 2024 09:10:26 -0600 Subject: [PATCH 29/67] Update impersonation_paypal.yml (#2208) --- detection-rules/impersonation_paypal.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/detection-rules/impersonation_paypal.yml b/detection-rules/impersonation_paypal.yml index eb9a0edaa07..3f02037438b 100644 --- a/detection-rules/impersonation_paypal.yml +++ b/detection-rules/impersonation_paypal.yml @@ -8,9 +8,9 @@ severity: "medium" source: | type.inbound and ( - sender.display_name =~ "paypal" - or strings.ilevenshtein(sender.display_name, 'paypal') <= 1 - or strings.ilike(sender.email.domain.domain, '*paypal*') + strings.replace_confusables(sender.display_name) =~ "paypal" + or strings.ilevenshtein(strings.replace_confusables(sender.display_name), 'paypal') <= 1 + or strings.ilike(strings.replace_confusables(sender.display_name), '*paypal*') or any(attachments, (.file_type in $file_types_images or .file_type == "pdf") and any(ml.logo_detect(.).brands, .name == "PayPal") From e9eb47533f7f963b82d1cb155e34989c26343923 Mon Sep 17 00:00:00 2001 From: Brandon Murphy <4827852+zoomequipd@users.noreply.github.com> Date: Mon, 16 Dec 2024 09:10:40 -0600 Subject: [PATCH 30/67] Update link_multistage_adobe_express.yml (#2209) --- .../link_multistage_adobe_express.yml | 25 ++++++++++++++----- 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/detection-rules/link_multistage_adobe_express.yml b/detection-rules/link_multistage_adobe_express.yml index 696391ccaf7..3578e588fdc 100644 --- a/detection-rules/link_multistage_adobe_express.yml +++ b/detection-rules/link_multistage_adobe_express.yml @@ -4,12 +4,25 @@ type: "rule" severity: "high" source: | type.inbound - and any(body.links, - // it is a new.express.adobe.com page - .href_url.domain.domain == "new.express.adobe.com" - and strings.starts_with(.href_url.path, "/webpage/") - - // filter down the links on express.adobe.com page to those that are external to adobe + and any(filter(body.links, + // the link is a new.express.adobe.com page + .href_url.domain.domain == "new.express.adobe.com" + and strings.starts_with(.href_url.path, "/webpage/") + ), + // filter down the links on express.adobe.com page to those that are external to adobe + // check that the length of external links is reasonable + length(distinct(filter(ml.link_analysis(., mode="aggressive").final_dom.links, + // filter any links on the adobe express page which are + // on express.adobe.com + .href_url.domain.domain != 'new.express.adobe.com' + // or www.adobe.com (privacy page/report abuse/etc) + and .href_url.domain.domain != 'www.adobe.com' + // relative links (no domains) + and .href_url.domain.domain is not null + ), + .href_url.domain.domain + ) + ) <= 10 and any(filter(ml.link_analysis(., mode="aggressive").final_dom.links, // filter any links on the adobe express page which are // on express.adobe.com From 7c75163ea0fdd1af57639b25db2e730646c3687a Mon Sep 17 00:00:00 2001 From: Brandon Murphy <4827852+zoomequipd@users.noreply.github.com> Date: Mon, 16 Dec 2024 09:11:05 -0600 Subject: [PATCH 31/67] Update link_microsoft_low_reputation.yml (#2214) --- detection-rules/link_microsoft_low_reputation.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/detection-rules/link_microsoft_low_reputation.yml b/detection-rules/link_microsoft_low_reputation.yml index af2dc0dd9ca..83c4e1b605d 100644 --- a/detection-rules/link_microsoft_low_reputation.yml +++ b/detection-rules/link_microsoft_low_reputation.yml @@ -70,7 +70,8 @@ source: | .file_type in $file_types_images and any(ml.logo_detect(.).brands, strings.starts_with(.name, "Microsoft")) ) - or strings.istarts_with(body.current_thread.text, "Microsoft ") + or strings.istarts_with(strings.replace_confusables(body.current_thread.text), "Microsoft ") + or regex.icontains(strings.replace_confusables(body.current_thread.text), '(?:^|\n)[o0O]ff[il1]ce\b') or any(ml.logo_detect(beta.message_screenshot()).brands, strings.starts_with(.name, "Microsoft") ) @@ -331,7 +332,7 @@ source: | "sharepointonline.com", "yammer.com", ) - + // negate legitimate Office 365 bouncebacks and not ( length(attachments) > 0 @@ -340,7 +341,7 @@ source: | ) and (sender.email.local_part in ('postmaster', 'mailer-daemon')) ) - + // negate Microsoft "welcome to the X group" notifications and not ( headers.auth_summary.dmarc.pass From a0f0c1a4a2d753183f200e83e00bcef66b6f86b8 Mon Sep 17 00:00:00 2001 From: Brandon Murphy <4827852+zoomequipd@users.noreply.github.com> Date: Mon, 16 Dec 2024 09:11:28 -0600 Subject: [PATCH 32/67] Update abuse_dropbox_sus_names.yml (#2218) --- detection-rules/abuse_dropbox_sus_names.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/detection-rules/abuse_dropbox_sus_names.yml b/detection-rules/abuse_dropbox_sus_names.yml index 982458a9a1c..51a683658fd 100644 --- a/detection-rules/abuse_dropbox_sus_names.yml +++ b/detection-rules/abuse_dropbox_sus_names.yml @@ -58,8 +58,10 @@ source: | // the filename is also contianed in the subject line or ( + // untitled.paper + regex.icontains(subject.subject, 'shared.*\"Untitled.paper') // scanner themed - regex.icontains(subject.subject, 'shared.*\".*scanne[rd]') + or regex.icontains(subject.subject, 'shared.*\".*scanne[rd]') // image theme or regex.icontains(subject.subject, 'shared.*\".*_IMG_') or regex.icontains(subject.subject, 'shared.*\".*IMG[_-](?:\d|\W)+\"') From 110ef6d2d23b6020535bf31b2f466658c4aada19 Mon Sep 17 00:00:00 2001 From: Brandon Murphy <4827852+zoomequipd@users.noreply.github.com> Date: Mon, 16 Dec 2024 09:12:27 -0600 Subject: [PATCH 33/67] Update attachment_extortion.yml (#2201) --- detection-rules/attachment_extortion.yml | 192 ++++++++++++++++------- 1 file changed, 137 insertions(+), 55 deletions(-) diff --git a/detection-rules/attachment_extortion.yml b/detection-rules/attachment_extortion.yml index 144ac7ef31b..c6efe4cdae9 100644 --- a/detection-rules/attachment_extortion.yml +++ b/detection-rules/attachment_extortion.yml @@ -15,68 +15,150 @@ source: | ) ) and any(attachments, - (.file_type in $file_types_images or .file_type == "pdf") - and any(filter(file.explode(.), .scan.ocr.raw is not null), - ( - any(ml.nlu_classifier(.scan.ocr.raw).intents, - .name == "extortion" and .confidence == "high" - ) - and any(ml.nlu_classifier(.scan.ocr.raw).entities, - .name == "financial" + // use ocr output from file.explode on pdfs/images + ( + (.file_type in $file_types_images or .file_type == "pdf") + and any(filter(file.explode(.), .scan.ocr.raw is not null), + ( + any(ml.nlu_classifier(.scan.ocr.raw).intents, + .name == "extortion" and .confidence == "high" + ) + and any(ml.nlu_classifier(.scan.ocr.raw).entities, + .name == "financial" + ) ) - ) - or 3 of ( - // malware terms - regex.icontains(.scan.ocr.raw, "((spy|mal)ware|trojan|remote control)"), - // actions recorded - regex.icontains(.scan.ocr.raw, - "porn|adult (web)?site|webcam|masturbating|jerking off|pleasuring yourself|getting off" - ), - regex.icontains(.scan.ocr.raw, - "pervert|perversion|masturbat" - ), - // a timeframe to pay - regex.icontains(.scan.ocr.raw, '\d\d hours', '(?:one|two|three) days?'), - // a promise from the actor - regex.icontains(.scan.ocr.raw, + or 3 of ( + // malware terms + regex.icontains(.scan.ocr.raw, + "((spy|mal)ware|trojan|remote control)" + ), + // actions recorded + regex.icontains(.scan.ocr.raw, + "porn|adult (web)?site|webcam|masturbating|jerking off|pleasuring yourself|getting off" + ), + regex.icontains(.scan.ocr.raw, + "pervert|perversion|masturbat" + ), + // a timeframe to pay + regex.icontains(.scan.ocr.raw, + '\d\d hours', + '(?:one|two|three) days?' + ), + // a promise from the actor + regex.icontains(.scan.ocr.raw, 'permanently delete|destroy (?:\w+\s*){0,4} (?:data|evidence|videos?)' - ), - // a threat from the actor - regex.icontains(.scan.ocr.raw, - 'sen[dt]\s*(?:\w+\s*){0,2}\s*to\s*(?:\w+\s*){0,3}\s*your contacts'), - // bitcoin - ( + ), + // a threat from the actor regex.icontains(.scan.ocr.raw, - 'bitcoin|\bbtc\b|blockchain' - ) - // negate cryptocurrency newsletters - and not ( - any(body.links, - strings.icontains(.display_text, "unsubscribe") - and ( - strings.icontains(.href_url.path, "unsubscribe") - // handle mimecast URL rewrites - or ( - .href_url.domain.root_domain == 'mimecastprotect.com' - and strings.icontains(.href_url.query_params, - sender.email.domain.root_domain + 'sen[dt]\s*(?:\w+\s*){0,2}\s*to\s*(?:\w+\s*){0,3}\s*your contacts' + ), + // bitcoin + ( + regex.icontains(.scan.ocr.raw, + 'bitcoin|\bbtc\b|blockchain' + ) + // negate cryptocurrency newsletters + and not ( + any(body.links, + strings.icontains(.display_text, "unsubscribe") + and ( + strings.icontains(.href_url.path, "unsubscribe") + // handle mimecast URL rewrites + or ( + .href_url.domain.root_domain == 'mimecastprotect.com' + and strings.icontains(.href_url.query_params, + sender.email.domain.root_domain + ) ) ) - ) + ) ) - ) - ), - // bitcoin wallet address + threat - ( - strings.icontains(.scan.ocr.raw, - "contact the police" - ) - and regex.icontains(.scan.ocr.raw, - '(\b[13][a-km-zA-HJ-NP-Z0-9]{24,33}\b)|\bX[1-9A-HJ-NP-Za-km-z]{33}\b|\b(0x[a-fA-F0-9]{40})\b|\b[LM3][a-km-zA-HJ-NP-Z1-9]{26,33}\b|\b[48][0-9AB][1-9A-HJ-NP-Za-km-z]{93}\b' - ) - ), - regex.icontains(.scan.ocr.raw, 'bc1q.{0,50}\b') + ), + // bitcoin wallet address + threat + ( + strings.icontains(.scan.ocr.raw, "contact the police") + and regex.icontains(.scan.ocr.raw, + '(\b[13][a-km-zA-HJ-NP-Z0-9]{24,33}\b)|\bX[1-9A-HJ-NP-Za-km-z]{33}\b|\b(0x[a-fA-F0-9]{40})\b|\b[LM3][a-km-zA-HJ-NP-Z1-9]{26,33}\b|\b[48][0-9AB][1-9A-HJ-NP-Za-km-z]{93}\b' + ) + ), + regex.icontains(.scan.ocr.raw, 'bc1q.{0,50}\b') + ) + ) + ) + or + // use beta.parse_text on plain text files + ( + ( + .file_extension in ("txt") + and ( + ( + any(ml.nlu_classifier(beta.parse_text(.).text).intents, + .name == "extortion" and .confidence == "high" ) + and any(ml.nlu_classifier(beta.parse_text(.).text).entities, + .name == "financial" + ) + ) + or 3 of ( + // malware terms + regex.icontains(beta.parse_text(.).text, + "((spy|mal)ware|trojan|remote control)" + ), + // actions recorded + regex.icontains(beta.parse_text(.).text, + "porn|adult (web)?site|webcam|masturbating|jerking off|pleasuring yourself|getting off" + ), + regex.icontains(beta.parse_text(.).text, + "pervert|perversion|masturbat" + ), + // a timeframe to pay + regex.icontains(beta.parse_text(.).text, + '\d\d hours', + '(?:one|two|three) days?' + ), + // a promise from the actor + regex.icontains(beta.parse_text(.).text, + 'permanently delete|destroy (?:\w+\s*){0,4} (?:data|evidence|videos?)' + ), + // a threat from the actor + regex.icontains(beta.parse_text(.).text, + 'sen[dt]\s*(?:\w+\s*){0,2}\s*to\s*(?:\w+\s*){0,3}\s*your contacts' + ), + // bitcoin + ( + regex.icontains(beta.parse_text(.).text, + 'bitcoin|\bbtc\b|blockchain' + ) + // negate cryptocurrency newsletters + and not ( + any(body.links, + strings.icontains(.display_text, "unsubscribe") + and ( + strings.icontains(.href_url.path, "unsubscribe") + // handle mimecast URL rewrites + or ( + .href_url.domain.root_domain == 'mimecastprotect.com' + and strings.icontains(.href_url.query_params, + sender.email.domain.root_domain + ) + ) + ) + ) + ) + ), + // bitcoin wallet address + threat + ( + strings.icontains(beta.parse_text(.).text, + "contact the police" + ) + and regex.icontains(beta.parse_text(.).text, + '(\b[13][a-km-zA-HJ-NP-Z0-9]{24,33}\b)|\bX[1-9A-HJ-NP-Za-km-z]{33}\b|\b(0x[a-fA-F0-9]{40})\b|\b[LM3][a-km-zA-HJ-NP-Z1-9]{26,33}\b|\b[48][0-9AB][1-9A-HJ-NP-Za-km-z]{93}\b' + ) + ), + regex.icontains(beta.parse_text(.).text, 'bc1q.{0,50}\b') + ) + ) + ) ) ) and ( From fc6e8997501ba43334eaae55a42ac73013936116 Mon Sep 17 00:00:00 2001 From: Brandon Murphy <4827852+zoomequipd@users.noreply.github.com> Date: Mon, 16 Dec 2024 09:13:00 -0600 Subject: [PATCH 34/67] Update abuse_docusign_sus_names.yml (#2205) --- detection-rules/abuse_docusign_sus_names.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/detection-rules/abuse_docusign_sus_names.yml b/detection-rules/abuse_docusign_sus_names.yml index 1e0aee78607..96b8507f448 100644 --- a/detection-rules/abuse_docusign_sus_names.yml +++ b/detection-rules/abuse_docusign_sus_names.yml @@ -42,7 +42,7 @@ source: | or .email.domain.domain not in $free_email_providers ) ), - .email.domain.root_domain in $sender_domains + .email.domain.domain in $sender_domains ) ) From 7cf05c226f7f864390e6f1935a274f828dff6b5d Mon Sep 17 00:00:00 2001 From: Brandon Murphy <4827852+zoomequipd@users.noreply.github.com> Date: Mon, 16 Dec 2024 09:16:01 -0600 Subject: [PATCH 35/67] Create abuse_google_drive_unsolicited_reply-to.yml (#2185) Co-authored-by: ID Generator --- ...buse_google_drive_unsolicited_reply-to.yml | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 detection-rules/abuse_google_drive_unsolicited_reply-to.yml diff --git a/detection-rules/abuse_google_drive_unsolicited_reply-to.yml b/detection-rules/abuse_google_drive_unsolicited_reply-to.yml new file mode 100644 index 00000000000..c0e47f3c1e1 --- /dev/null +++ b/detection-rules/abuse_google_drive_unsolicited_reply-to.yml @@ -0,0 +1,57 @@ +name: "Service Abuse: Google Drive Share From an Unsolicited Reply-To Address" +description: "Identifies messages appearing to come from Google Drive sharing notifications that contain a reply-to address not previously seen in organizational communications. This tactic exploits trust in legitimate Google services while attempting to establish unauthorized communication channels." +type: "rule" +severity: "medium" +source: | + type.inbound + and sender.email.email in ( + 'drive-shares-dm-noreaply@google.com', + 'drive-shares-noreply@google.com', + ) + and not any(headers.reply_to, .email.domain.domain in $org_domains) + + // the message needs to have a reply-to address + and length(headers.reply_to) > 0 + + // reply-to email address has never been sent an email by the org + and not ( + any(headers.reply_to, .email.email in $recipient_emails) + // if the reply-to email address is NOT in free_email_providers, check the domain in recipient_domains + or any(filter(headers.reply_to, + // filter the list to only emails that are not in free_email_providers + ( + .email.domain.domain not in $free_email_providers + or .email.domain.root_domain not in $free_email_providers + ) + ), + .email.domain.domain in $recipient_domains + ) + ) + // reply-to address has never sent an email to the org + and not ( + any(headers.reply_to, .email.email in $sender_emails) + // if the reply-to address is NOT in free_email_providers, check the domain in sender_domains + or any(filter(headers.reply_to, + // filter the list to only emails that are not in free_email_providers + ( + .email.domain.domain not in $free_email_providers + or .email.domain.domain not in $free_email_providers + ) + ), + .email.domain.root_domain in $sender_domains + ) + ) +tags: + - "Attack surface reduction" +attack_types: + - "BEC/Fraud" + - "Callback Phishing" + - "Credential Phishing" +tactics_and_techniques: + - "Free email provider" + - "Social engineering" + - "Free file host" +detection_methods: + - "Header analysis" + - "Sender analysis" +id: "4581ec0c-aed2-50ed-8e16-2c9ca1d350ff" From 621394d719a9cc779ba51daeb33e6c594b7bee15 Mon Sep 17 00:00:00 2001 From: Brandon Murphy <4827852+zoomequipd@users.noreply.github.com> Date: Mon, 16 Dec 2024 09:19:00 -0600 Subject: [PATCH 36/67] Update link_fake_password_expiration.yml (#2215) --- .../link_fake_password_expiration.yml | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/detection-rules/link_fake_password_expiration.yml b/detection-rules/link_fake_password_expiration.yml index b9d1bc57bc2..fa96f7828c7 100644 --- a/detection-rules/link_fake_password_expiration.yml +++ b/detection-rules/link_fake_password_expiration.yml @@ -5,8 +5,8 @@ severity: "medium" source: | type.inbound - // few links - and 0 < length(body.links) < 10 + // few links which are not in $org_domains + and 0 < length(filter(body.links, .href_url.domain.domain not in $org_domains)) <= 10 // no attachments or suspicious attachment and ( @@ -17,6 +17,18 @@ source: | .scan.entropy.entropy > 7 and length(.scan.ocr.raw) < 20 ) ) + // or there are duplicate pdfs in name + or ( + length(filter(attachments, .file_type == "pdf")) > length(distinct(filter(attachments, + .file_type == "pdf" + ), + .file_name + ) + ) + or + // all PDFs are the same MD5 + length(distinct(filter(attachments, .file_type == "pdf"), .md5)) == 1 + ) ) // body contains expire, expiration, loose, lose @@ -93,11 +105,13 @@ source: | ) or regex.icontains(body.html.raw, '(?:

\s* \s*

\s*){7,}') or regex.icontains(body.html.raw, '(?:

\s* \s*

\s*
\s*){7,}') - or regex.icontains(body.html.raw, '(?:]*>\s* \s*
\s*

\s*){5,}') + or regex.icontains(body.html.raw, + '(?:]*>\s* \s*
\s*

\s*){5,}' + ) or regex.icontains(body.html.raw, '(?:]*> 

\s*){7,}') ) ) - + // a body link does not match the sender domain and any(body.links, .href_url.domain.root_domain != sender.email.domain.root_domain From be50bd0652ef108c00015a6cd0dada1e4b19c149 Mon Sep 17 00:00:00 2001 From: Brandon Murphy <4827852+zoomequipd@users.noreply.github.com> Date: Mon, 16 Dec 2024 09:19:55 -0600 Subject: [PATCH 37/67] Create abuse_quickbooks_new_domain.yml (#2052) Co-authored-by: ID Generator --- .../abuse_quickbooks_new_domain.yml | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 detection-rules/abuse_quickbooks_new_domain.yml diff --git a/detection-rules/abuse_quickbooks_new_domain.yml b/detection-rules/abuse_quickbooks_new_domain.yml new file mode 100644 index 00000000000..c05a552f12e --- /dev/null +++ b/detection-rules/abuse_quickbooks_new_domain.yml @@ -0,0 +1,45 @@ +name: "Service Abuse: QuickBooks Notification From New Domain" +description: "This Attack Surface Reduction (ASR) rule matches on QuickBooks notifications with recently registered reply-to domains." +type: "rule" +severity: "medium" +source: | + type.inbound + + // Legitimate Intuit sending infratructure + and sender.email.email == "quickbooks@notification.intuit.com" + and headers.auth_summary.spf.pass + and headers.auth_summary.dmarc.pass + and strings.ends_with(headers.auth_summary.spf.details.designator, + '.intuit.com' + ) + + // remove payment confirmation messages + and not strings.starts_with(subject.subject, 'Payment confirmation:') + + // the message needs to have a reply-to address + and length(headers.reply_to) > 0 + + // reply-to email address has never received an email from your org + and not any(headers.reply_to, .email.email in $recipient_emails) + + // new reply-to + and any(filter(headers.reply_to, + // negate .com.au which doesn't provide created date for domains + .email.domain.tld not in ('com.au') + ), + network.whois(.email.domain).days_old < 30 + ) +tags: + - "Attack surface reduction" +attack_types: + - "Callback Phishing" + - "Credential Phishing" + - "BEC/Fraud" +tactics_and_techniques: + - "Evasion" + - "Social engineering" +detection_methods: + - "Content analysis" + - "Sender analysis" + - "Header analysis" +id: "c4f46473-0f5a-56d6-bb7e-489460bdb20f" From b337c7f1dbe94aa9de9374791ae7faf4dfc802bd Mon Sep 17 00:00:00 2001 From: Brandon Murphy <4827852+zoomequipd@users.noreply.github.com> Date: Mon, 16 Dec 2024 09:20:09 -0600 Subject: [PATCH 38/67] Create abuse_quickbooks_suspicious_comments.yml (#2053) Co-authored-by: ID Generator --- .../abuse_quickbooks_suspicious_comments.yml | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 detection-rules/abuse_quickbooks_suspicious_comments.yml diff --git a/detection-rules/abuse_quickbooks_suspicious_comments.yml b/detection-rules/abuse_quickbooks_suspicious_comments.yml new file mode 100644 index 00000000000..ec436e55852 --- /dev/null +++ b/detection-rules/abuse_quickbooks_suspicious_comments.yml @@ -0,0 +1,39 @@ +name: "Service Abuse: QuickBooks Notification with Suspicious Comments" +description: "This detection rule matches QuickBooks notifications that contain suspicious keywords within the comments section of the notification" +type: "rule" +severity: "medium" +source: | + type.inbound + + // Legitimate Intuit sending infratructure + and sender.email.email == "quickbooks@notification.intuit.com" + and headers.auth_summary.spf.pass + and headers.auth_summary.dmarc.pass + and strings.ends_with(headers.auth_summary.spf.details.designator, + '.intuit.com' + ) + + // remove payment confirmation messages + and not strings.starts_with(subject.subject, 'Payment confirmation:') + + and body.html.raw is not null + // Comments contains suspicious phrases + and ( + // three different templates where commonly observed, on regex for each template + // this could optionally be converted into a "2 of" logic against current_thread if FN are discovered + regex.icontains(body.html.raw, '
\s*.*\b(?:your subscription renewal|couldn.?t be processed|trouble renewing subscription|update your details|just update your|continue your subscription|prefer to use EFT|change payment method|verify your account|suspended due to issue|payment declined notice|account needs verification|confirm your billing|immediate action required|failed payment notification|billing information update|service interruption warning|unable to process payment|subscription payment failed|action needed now|update banking information|subscription expiration notice|payment method change)\b.*
') + or regex.icontains(body.html.raw, '
.*\b(?:your subscription renewal|couldn.?t be processed|trouble renewing subscription|update your details|just update your|continue your subscription|prefer to use EFT|change payment method|verify your account|suspended due to issue|payment declined notice|account needs verification|confirm your billing|immediate action required|failed payment notification|billing information update|service interruption warning|unable to process payment|subscription payment failed|action needed now|update banking information|subscription expiration notice|payment method change)\b.*
') + or regex.icontains(body.html.raw, '(?:\s*)?\s*\s*') + ) +attack_types: + - "Callback Phishing" + - "Credential Phishing" + - "BEC/Fraud" +tactics_and_techniques: + - "Evasion" + - "Social engineering" +detection_methods: + - "Content analysis" + - "Sender analysis" + - "Header analysis" +id: "a23d0950-9117-5199-bc74-7192217b80ff" From b23155072f27fb6f3da9f782792fce13bf1ad95c Mon Sep 17 00:00:00 2001 From: Sam Scholten Date: Mon, 16 Dec 2024 10:21:09 -0500 Subject: [PATCH 39/67] Update link_microsoft_low_reputation.yml (#2216) --- detection-rules/link_microsoft_low_reputation.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/detection-rules/link_microsoft_low_reputation.yml b/detection-rules/link_microsoft_low_reputation.yml index 83c4e1b605d..95c91a63b02 100644 --- a/detection-rules/link_microsoft_low_reputation.yml +++ b/detection-rules/link_microsoft_low_reputation.yml @@ -4,7 +4,7 @@ type: "rule" severity: "medium" source: | type.inbound - and 0 < length(body.links) < 100 + and 0 < length(body.links) < 50 // suspicious link and any(body.links, ( From ee16b91043b54e457170feabe8ee314152708b20 Mon Sep 17 00:00:00 2001 From: Brandon Murphy <4827852+zoomequipd@users.noreply.github.com> Date: Tue, 17 Dec 2024 17:15:52 -0600 Subject: [PATCH 40/67] fix typo in drive-shares-dm-noreaply (#2231) --- detection-rules/abuse_google_drive_unsolicited_reply-to.yml | 2 +- detection-rules/link_google_presentation_open_redirect.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/detection-rules/abuse_google_drive_unsolicited_reply-to.yml b/detection-rules/abuse_google_drive_unsolicited_reply-to.yml index c0e47f3c1e1..b01aa73250b 100644 --- a/detection-rules/abuse_google_drive_unsolicited_reply-to.yml +++ b/detection-rules/abuse_google_drive_unsolicited_reply-to.yml @@ -5,7 +5,7 @@ severity: "medium" source: | type.inbound and sender.email.email in ( - 'drive-shares-dm-noreaply@google.com', + 'drive-shares-dm-noreply@google.com', 'drive-shares-noreply@google.com', ) and not any(headers.reply_to, .email.domain.domain in $org_domains) diff --git a/detection-rules/link_google_presentation_open_redirect.yml b/detection-rules/link_google_presentation_open_redirect.yml index f06fe291a15..65e5d89c90c 100644 --- a/detection-rules/link_google_presentation_open_redirect.yml +++ b/detection-rules/link_google_presentation_open_redirect.yml @@ -85,7 +85,7 @@ source: | or ( sender.email.email in ( 'comments-noreply@docs.google.com', - 'drive-shares-dm-noreaply@google.com', + 'drive-shares-dm-noreply@google.com', 'drive-shares-noreply@google.com', 'calendar-notification@google.com' ) From 34ce2e70a1eb15c67fe8dd1df47f29c0bfa9614f Mon Sep 17 00:00:00 2001 From: Sam Scholten Date: Tue, 17 Dec 2024 19:53:44 -0500 Subject: [PATCH 41/67] Update impersonation_microsoft_credential_theft.yml (#2200) --- detection-rules/impersonation_microsoft_credential_theft.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/detection-rules/impersonation_microsoft_credential_theft.yml b/detection-rules/impersonation_microsoft_credential_theft.yml index 36f64134c9e..fc4d734c2be 100644 --- a/detection-rules/impersonation_microsoft_credential_theft.yml +++ b/detection-rules/impersonation_microsoft_credential_theft.yml @@ -52,6 +52,11 @@ source: | and not profile.by_sender().any_false_positives ) ) + and not ( + sender.email.domain.domain == "planner.office365.com" + and headers.return_path.email == "noreply@planner.office365.com" + and headers.auth_summary.dmarc.details.from.domain == "planner.office365.com" + ) // negate highly trusted sender domains unless they fail DMARC authentication and ( From 52332b7816cb7a5c7864709c90fb4ce570fde1c3 Mon Sep 17 00:00:00 2001 From: Brandon Murphy <4827852+zoomequipd@users.noreply.github.com> Date: Tue, 17 Dec 2024 22:45:16 -0600 Subject: [PATCH 42/67] Update attachment_extortion.yml (#2227) --- detection-rules/attachment_extortion.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/detection-rules/attachment_extortion.yml b/detection-rules/attachment_extortion.yml index c6efe4cdae9..02878275278 100644 --- a/detection-rules/attachment_extortion.yml +++ b/detection-rules/attachment_extortion.yml @@ -92,10 +92,10 @@ source: | .file_extension in ("txt") and ( ( - any(ml.nlu_classifier(beta.parse_text(.).text).intents, + any(ml.nlu_classifier(file.parse_text(.).text).intents, .name == "extortion" and .confidence == "high" ) - and any(ml.nlu_classifier(beta.parse_text(.).text).entities, + and any(ml.nlu_classifier(file.parse_text(.).text).entities, .name == "financial" ) ) From facda96e0946097bf2bbefb9e35f746d6dc273a0 Mon Sep 17 00:00:00 2001 From: Brandon Murphy <4827852+zoomequipd@users.noreply.github.com> Date: Tue, 17 Dec 2024 22:46:08 -0600 Subject: [PATCH 43/67] Update impersonation_facebook.yml (#2226) --- detection-rules/impersonation_facebook.yml | 24 ++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/detection-rules/impersonation_facebook.yml b/detection-rules/impersonation_facebook.yml index f1db3377bf2..a74ad1b8b1e 100644 --- a/detection-rules/impersonation_facebook.yml +++ b/detection-rules/impersonation_facebook.yml @@ -8,6 +8,8 @@ severity: "low" source: | type.inbound and ( + // sender display name is a strong enough indicator + // that it can be used without any other impersonation logic ( strings.ilike(sender.display_name, '*facebook ads*', @@ -21,10 +23,16 @@ source: | or ( strings.ilevenshtein(sender.display_name, 'meta support') <= 2 // negation for Zeta Support - and not (sender.display_name == "Zeta Support" and sender.email.domain.root_domain == 'zetaglobal.net') + and not ( + sender.display_name == "Zeta Support" + and sender.email.domain.root_domain == 'zetaglobal.net' + ) ) or strings.ilike(sender.email.domain.domain, '*facebook*') ) + // the use of these keywords (facebook, meta, meta.*support) + // or the levenshtien distance to facebook + // are less strong and thus need to be combined with logo detection or nlu or ( ( ( @@ -51,6 +59,17 @@ source: | ) ) ) + // salesforce sender combined with logo detection and nlu is enough + or ( + sender.email.domain.root_domain == "salesforce.com" + and any(ml.logo_detect(beta.message_screenshot()).brands, + .name in ("Facebook", "Meta") + ) + and any(ml.nlu_classifier(body.current_thread.text).intents, + .name in ("cred_theft", "callback_scam", "steal_pii") + and .confidence in ("high") + ) + ) or // or the body contains a facebook/meta footer with the address citing "community support" ( @@ -92,7 +111,8 @@ source: | profile.by_sender().any_messages_malicious_or_spam and not profile.by_sender().any_false_positives ) - or sender.email.email == "noreply@salesforce.com" + // if saleforce is being abused, sender profiles aren't very useful + or sender.email.email in ("noreply@salesforce.com", "support@salesforce.com") // sent via Google group or any(headers.hops, any(.fields, .name == "X-Google-Group-Id")) ) From c64a7b6034c4b21e0611138a105cd014c7a8e9e7 Mon Sep 17 00:00:00 2001 From: Aiden Mitchell Date: Tue, 17 Dec 2024 21:04:08 -0800 Subject: [PATCH 44/67] Update attachment_office_file_relationship_cred_theft.yml (#2229) --- .../attachment_file_scheme_link_to_executable_filetype.yml | 1 + .../attachment_office_file_relationship_cred_theft.yml | 1 + 2 files changed, 2 insertions(+) diff --git a/detection-rules/attachment_file_scheme_link_to_executable_filetype.yml b/detection-rules/attachment_file_scheme_link_to_executable_filetype.yml index d50ce32802b..32c32f8b4cb 100644 --- a/detection-rules/attachment_file_scheme_link_to_executable_filetype.yml +++ b/detection-rules/attachment_file_scheme_link_to_executable_filetype.yml @@ -15,6 +15,7 @@ source: | and .size < 100000000 ) ) + and length(file.oletools(.).relationships) < 500 and any(file.oletools(.).relationships, .target_url.scheme == "file" and regex.icontains(.target_url.path, diff --git a/detection-rules/attachment_office_file_relationship_cred_theft.yml b/detection-rules/attachment_office_file_relationship_cred_theft.yml index 8945b4622bc..9d0dc17d383 100644 --- a/detection-rules/attachment_office_file_relationship_cred_theft.yml +++ b/detection-rules/attachment_office_file_relationship_cred_theft.yml @@ -15,6 +15,7 @@ source: | and .size < 100000000 ) ) + and length(file.oletools(.).relationships) < 500 and any(file.oletools(.).relationships, ( any(ml.nlu_classifier(ml.link_analysis(.target_url).final_dom.display_text From fdcf1fdfdca2a92295e7248c5bf286972fab7e77 Mon Sep 17 00:00:00 2001 From: Aiden Mitchell Date: Tue, 17 Dec 2024 21:04:25 -0800 Subject: [PATCH 45/67] Update attachment_docusign_suspicious_links.yml (#2222) --- .../attachment_docusign_suspicious_links.yml | 100 +++++++++--------- 1 file changed, 51 insertions(+), 49 deletions(-) diff --git a/detection-rules/attachment_docusign_suspicious_links.yml b/detection-rules/attachment_docusign_suspicious_links.yml index 58ec4ac0d39..0b532459c9a 100644 --- a/detection-rules/attachment_docusign_suspicious_links.yml +++ b/detection-rules/attachment_docusign_suspicious_links.yml @@ -65,56 +65,58 @@ source: | ) ) ) - + // accomidate truncated pngs and GIF files which can cause logodetect/OCR failures - or any(attachments, - ( - .file_type =~ "gif" - or any(file.explode(.), - any(.scan.exiftool.fields, - .key == "Warning" and .value == "Truncated PNG image" - ) - ) - ) - and ( - any(ml.logo_detect(beta.message_screenshot()).brands, - ( - .name == "DocuSign" - or any(file.explode(beta.message_screenshot()), - strings.ilike(.scan.ocr.raw, "*DocuSign*") - ) - ) - ) - and ( - any(file.explode(beta.message_screenshot()), - ( - any(ml.nlu_classifier(.scan.ocr.raw).intents, - .name == "cred_theft" and .confidence != "low" - ) - or regex.icontains(.scan.ocr.raw, - "((re)?view|access|complete(d)?) document(s)?", - "[^d][^o][^c][^u]sign", - "important edocs", - // German (Document (check|check|sign|sent)) - "Dokument (รผberprรผfen|prรผfen|unterschreiben|geschickt)", - // German (important|urgent|immediate) - "(wichtig|dringend|sofort)" - ) + or ( + any(attachments, + ( + .file_type =~ "gif" + or any(file.explode(.), + any(.scan.exiftool.fields, + .key == "Warning" and .value == "Truncated PNG image" ) - ) - ) - and not any(file.explode(beta.message_screenshot()), - ( - strings.ilike(.scan.ocr.raw, "*DocuSigned By*") - and not strings.ilike(.scan.ocr.raw, - "*DocuSign Envelope ID*" - ) - and not strings.ilike(.scan.ocr.raw, - "*Certificate Of Completion*" - ) - ) - ) - ) + ) + ) + ) + and ( + any(ml.logo_detect(beta.message_screenshot()).brands, + ( + .name == "DocuSign" + or any(file.explode(beta.message_screenshot()), + strings.ilike(.scan.ocr.raw, "*DocuSign*") + ) + ) + ) + and ( + any(file.explode(beta.message_screenshot()), + ( + any(ml.nlu_classifier(.scan.ocr.raw).intents, + .name == "cred_theft" and .confidence != "low" + ) + or regex.icontains(.scan.ocr.raw, + "((re)?view|access|complete(d)?) document(s)?", + "[^d][^o][^c][^u]sign", + "important edocs", + // German (Document (check|check|sign|sent)) + "Dokument (รผberprรผfen|prรผfen|unterschreiben|geschickt)", + // German (important|urgent|immediate) + "(wichtig|dringend|sofort)" + ) + ) + ) + ) + and not any(file.explode(beta.message_screenshot()), + ( + strings.ilike(.scan.ocr.raw, "*DocuSigned By*") + and not strings.ilike(.scan.ocr.raw, + "*DocuSign Envelope ID*" + ) + and not strings.ilike(.scan.ocr.raw, + "*Certificate Of Completion*" + ) + ) + ) + ) ) ) and ( @@ -125,7 +127,7 @@ source: | ) ) and not profile.by_sender().any_false_positives - + // negate docusign 'via' messages and not ( any(headers.hops, From 099d32735eb35a1410cabec91f115962e13e7ef8 Mon Sep 17 00:00:00 2001 From: Brandon Murphy <4827852+zoomequipd@users.noreply.github.com> Date: Wed, 18 Dec 2024 09:34:10 -0600 Subject: [PATCH 46/67] Update link_microsoft_low_reputation.yml (#2232) --- detection-rules/link_microsoft_low_reputation.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/detection-rules/link_microsoft_low_reputation.yml b/detection-rules/link_microsoft_low_reputation.yml index 95c91a63b02..67b83e08151 100644 --- a/detection-rules/link_microsoft_low_reputation.yml +++ b/detection-rules/link_microsoft_low_reputation.yml @@ -71,7 +71,7 @@ source: | and any(ml.logo_detect(.).brands, strings.starts_with(.name, "Microsoft")) ) or strings.istarts_with(strings.replace_confusables(body.current_thread.text), "Microsoft ") - or regex.icontains(strings.replace_confusables(body.current_thread.text), '(?:^|\n)[o0O]ff[il1]ce\b') + or regex.imatch(strings.replace_confusables(body.current_thread.text), '[\n\s]*[o0O]ff[il1]ce\b.*') or any(ml.logo_detect(beta.message_screenshot()).brands, strings.starts_with(.name, "Microsoft") ) From 6eda67a2869a8c6de9dbcc504ecc3c2178e888af Mon Sep 17 00:00:00 2001 From: Brandon Murphy <4827852+zoomequipd@users.noreply.github.com> Date: Wed, 18 Dec 2024 09:48:31 -0600 Subject: [PATCH 47/67] Create abuse_docsend_new_domain.yml (#2164) Co-authored-by: ID Generator Co-authored-by: Aiden Mitchell --- detection-rules/abuse_docsend_new_domain.yml | 37 ++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 detection-rules/abuse_docsend_new_domain.yml diff --git a/detection-rules/abuse_docsend_new_domain.yml b/detection-rules/abuse_docsend_new_domain.yml new file mode 100644 index 00000000000..48d295da824 --- /dev/null +++ b/detection-rules/abuse_docsend_new_domain.yml @@ -0,0 +1,37 @@ +name: "Service Abuse: DocSend Share From Newly Registered Domain" +description: "This Attack Surface Reduction (ASR) rule matches on DocSend notifications with recently registered reply-to domains." +type: "rule" +severity: "high" +source: | + type.inbound + + // Legitimate DocSend sending infratructure + and sender.email.email == "no-reply@docsend.com" + and headers.auth_summary.spf.pass + and headers.auth_summary.dmarc.pass + + // the message needs to have a reply-to address + and length(headers.reply_to) > 0 + + // reply-to email address has never received an email from your org + and not any(headers.reply_to, .email.email in $recipient_emails) + + // new reply-to + and any(headers.reply_to, + network.whois(.email.domain).days_old < 30 + ) +tags: + - "Attack surface reduction" +attack_types: + - "BEC/Fraud" + - "Credential Phishing" +tactics_and_techniques: + - "Evasion" + - "Free file host" + - "Impersonation: Brand" + - "Social engineering" +detection_methods: + - "Content analysis" + - "Header analysis" + - "Sender analysis" +id: "3bc152f2-6722-57be-b924-055c35fa1e60" From 23c41ebe5da78a86cc23b2ef52387a58cc78fe5c Mon Sep 17 00:00:00 2001 From: Brandon Murphy <4827852+zoomequipd@users.noreply.github.com> Date: Wed, 18 Dec 2024 09:51:57 -0600 Subject: [PATCH 48/67] Create header_onmicrosoft_traversal.yml (#2060) Co-authored-by: ID Generator Co-authored-by: Aiden Mitchell --- .../header_onmicrosoft_traversal.yml | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 detection-rules/header_onmicrosoft_traversal.yml diff --git a/detection-rules/header_onmicrosoft_traversal.yml b/detection-rules/header_onmicrosoft_traversal.yml new file mode 100644 index 00000000000..c6ba1546391 --- /dev/null +++ b/detection-rules/header_onmicrosoft_traversal.yml @@ -0,0 +1,37 @@ +name: "Message Traversed Multiple onmicrosoft.com Tenants" +description: "This detection rule identifies messages that have traversed multiple distinct onmicrosoft.com tenants. This technique has been observed as an evasion tactic to distribute a single message across a list of targeted recipients." +type: "rule" +severity: "medium" +source: | + type.inbound + and length(recipients.to) == 1 + and all(recipients.to, + .email.domain.root_domain == "onmicrosoft.com" + and not .email.domain.domain in $org_domains + ) + // the message has traversed two or more different "onmicrosoft.com" subdomains + and length(distinct(map(filter(headers.hops, + strings.icontains(.authentication_results.spf_details.designator, + '.onmicrosoft.com' + ) + and not strings.contains(.authentication_results.spf_details.designator, + "@" + ) + ), + .authentication_results.spf_details.designator + ), + . + ) + ) > 1 + + and all(recipients.to, .email.domain.domain != headers.return_path.domain.domain) +attack_types: + - "Callback Phishing" +tactics_and_techniques: + - "Evasion" + - "Free email provider" + - "Free subdomain host" +detection_methods: + - "Sender analysis" + - "Header analysis" +id: "9cf01c0d-95d5-5ea6-8150-cf5879834e06" From 5eb78b361fd87be5dca81fa7788f9c1d19f7b7af Mon Sep 17 00:00:00 2001 From: Brandon Murphy <4827852+zoomequipd@users.noreply.github.com> Date: Wed, 18 Dec 2024 09:54:38 -0600 Subject: [PATCH 49/67] Update suspicious_sharepoint_file_shared.yml (#2178) --- detection-rules/suspicious_sharepoint_file_shared.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/detection-rules/suspicious_sharepoint_file_shared.yml b/detection-rules/suspicious_sharepoint_file_shared.yml index 2b0e481a4ff..3a21411caaa 100644 --- a/detection-rules/suspicious_sharepoint_file_shared.yml +++ b/detection-rules/suspicious_sharepoint_file_shared.yml @@ -1,5 +1,5 @@ name: "Suspicious SharePoint File Sharing" -description: "This rule detect potential credential phishing leveraging SharePoint file sharing to deliver a PDF or OneNote file using indicators such as suspicious sender analysis and link characteristics." +description: "This rule detect potential credential phishing leveraging SharePoint file sharing to deliver a PDF, OneNote, or Unknown file type file using indicators such as suspicious sender analysis and link characteristics." type: "rule" severity: "medium" source: | @@ -61,6 +61,7 @@ source: | and ( strings.icontains(.href_url.path, '/:o:/') or strings.icontains(.href_url.path, '/:b:/') + or strings.icontains(.href_url.path, '/:u:/') ) ) From bf237eea34de573758a61535bafe6bcef76dec26 Mon Sep 17 00:00:00 2001 From: Brandon Murphy <4827852+zoomequipd@users.noreply.github.com> Date: Wed, 18 Dec 2024 09:56:12 -0600 Subject: [PATCH 50/67] Update unsolicited_reply-to rules (#2233) --- detection-rules/abuse_docusign_unsolicited_reply-to.yml | 2 +- detection-rules/abuse_google_drive_unsolicited_reply-to.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/detection-rules/abuse_docusign_unsolicited_reply-to.yml b/detection-rules/abuse_docusign_unsolicited_reply-to.yml index 4fa5b80c72a..a796593ddc4 100644 --- a/detection-rules/abuse_docusign_unsolicited_reply-to.yml +++ b/detection-rules/abuse_docusign_unsolicited_reply-to.yml @@ -41,7 +41,7 @@ source: | // filter the list to only emails that are not in free_email_providers ( .email.domain.domain not in $free_email_providers - or .email.domain.domain not in $free_email_providers + or .email.domain.root_domain not in $free_email_providers ) ), .email.domain.domain in $sender_domains diff --git a/detection-rules/abuse_google_drive_unsolicited_reply-to.yml b/detection-rules/abuse_google_drive_unsolicited_reply-to.yml index b01aa73250b..fc1dfe73eab 100644 --- a/detection-rules/abuse_google_drive_unsolicited_reply-to.yml +++ b/detection-rules/abuse_google_drive_unsolicited_reply-to.yml @@ -35,7 +35,7 @@ source: | // filter the list to only emails that are not in free_email_providers ( .email.domain.domain not in $free_email_providers - or .email.domain.domain not in $free_email_providers + or .email.domain.root_domain not in $free_email_providers ) ), .email.domain.root_domain in $sender_domains From e9078db87236bbfe6ccdd9a6656305569207da45 Mon Sep 17 00:00:00 2001 From: Brandon Murphy <4827852+zoomequipd@users.noreply.github.com> Date: Wed, 18 Dec 2024 10:00:24 -0600 Subject: [PATCH 51/67] Create abuse_docsend_unsolicited_reply-to.yml (#2165) Co-authored-by: ID Generator Co-authored-by: Aiden Mitchell --- .../abuse_docsend_unsolicited_reply-to.yml | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 detection-rules/abuse_docsend_unsolicited_reply-to.yml diff --git a/detection-rules/abuse_docsend_unsolicited_reply-to.yml b/detection-rules/abuse_docsend_unsolicited_reply-to.yml new file mode 100644 index 00000000000..f4e6bc0ab78 --- /dev/null +++ b/detection-rules/abuse_docsend_unsolicited_reply-to.yml @@ -0,0 +1,56 @@ +name: "Service Abuse: DocSend Share From an Unsolicited Reply-To Address" +description: "DocSend shares which contain a reply-to address or domain that has not been previously observed by the recipient organization." +type: "rule" +severity: "high" +source: | + type.inbound + + // Legitimate DocSend sending infratructure + and sender.email.email == "no-reply@docsend.com" + and headers.auth_summary.spf.pass + and headers.auth_summary.dmarc.pass + + // the message needs to have a reply-to address + and length(headers.reply_to) > 0 + + // reply-to email address has never been sent an email by the org + and not ( + any(headers.reply_to, .email.email in $recipient_emails) + // if the reply-to email address is NOT in free_email_providers, check the domain in recipient_domains + or any(filter(headers.reply_to, + // filter the list to only emails that are not in free_email_providers + ( + .email.domain.domain not in $free_email_providers + or .email.domain.root_domain not in $free_email_providers + ) + ), + .email.domain.domain in $recipient_domains + ) + ) + // reply-to address has never sent an email to the org + and not ( + any(headers.reply_to, .email.email in $sender_emails) + // if the reply-to address is NOT in free_email_providers, check the domain in sender_domains + or any(filter(headers.reply_to, + // filter the list to only emails that are not in free_email_providers + ( + .email.domain.domain not in $free_email_providers + or .email.domain.root_domain not in $free_email_providers + ) + ), + .email.domain.domain in $sender_domains + ) + ) +tags: + - "Attack surface reduction" +attack_types: + - "Credential Phishing" +tactics_and_techniques: + - "Evasion" + - "Free file host" + - "Social engineering" +detection_methods: + - "Content analysis" + - "Header analysis" + - "Sender analysis" +id: "b377e64c-21bd-5040-86ec-534e545a42db" From 50dc51459a691f194a5980232e72a3649bbf7697 Mon Sep 17 00:00:00 2001 From: Brandon Murphy <4827852+zoomequipd@users.noreply.github.com> Date: Wed, 18 Dec 2024 10:01:35 -0600 Subject: [PATCH 52/67] Create abuse_dropbox_unsolicited_reply-to.yml (#2078) Co-authored-by: ID Generator Co-authored-by: Aiden Mitchell --- .../abuse_dropbox_unsolicited_reply-to.yml | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 detection-rules/abuse_dropbox_unsolicited_reply-to.yml diff --git a/detection-rules/abuse_dropbox_unsolicited_reply-to.yml b/detection-rules/abuse_dropbox_unsolicited_reply-to.yml new file mode 100644 index 00000000000..92811c145ff --- /dev/null +++ b/detection-rules/abuse_dropbox_unsolicited_reply-to.yml @@ -0,0 +1,59 @@ +name: "Service Abuse: Dropbox Share From an Unsolicited Reply-To Address" +description: "This rule detects Dropbox share notifications which contain a reply-to address or domain that has not been previously observed sending messages to or receiving messages from the recipient organization." +type: "rule" +severity: "medium" +source: | + type.inbound + + // Legitimate Dropbox sending infratructure + and sender.email.email == "no-reply@dropbox.com" + and headers.auth_summary.spf.pass + and headers.auth_summary.dmarc.pass + and strings.ends_with(headers.auth_summary.spf.details.designator, + '.dropbox.com' + ) + and strings.icontains(subject.subject, 'shared') + and strings.icontains(subject.subject, 'with you') + + and length(headers.reply_to) > 0 + // reply-to email address has never been sent an email by the org + and not ( + any(headers.reply_to, .email.email in $recipient_emails) + // if the reply-to email address is NOT in free_email_providers, check the domain in recipient_domains + or any(filter(headers.reply_to, + // filter the list to only emails that are not in free_email_providers + ( + .email.domain.domain not in $free_email_providers + or .email.domain.root_domain not in $free_email_providers + ) + ), + .email.domain.domain in $recipient_domains + ) + ) + // reply-to address has never sent an email to the org + and not ( + any(headers.reply_to, .email.email in $sender_emails) + // if the reply-to address is NOT in free_email_providers, check the domain in sender_domains + or any(filter(headers.reply_to, + // filter the list to only emails that are not in free_email_providers + ( + .email.domain.domain not in $free_email_providers + or .email.domain.root_domain not in $free_email_providers + ) + ), + .email.domain.domain in $sender_domains + ) + ) +tags: + - "Attack surface reduction" +attack_types: + - "Callback Phishing" + - "BEC/Fraud" +tactics_and_techniques: + - "Evasion" + - "Social engineering" +detection_methods: + - "Sender analysis" + - "Header analysis" + - "Content analysis" +id: "50a1499f-bb59-5ee0-b4f4-e3cc84a5c41e" From bd3af67d389becb66e67738155e6b444661ef5a3 Mon Sep 17 00:00:00 2001 From: Peter Djordjevic <116412909+peterdj45@users.noreply.github.com> Date: Wed, 18 Dec 2024 20:04:05 -0800 Subject: [PATCH 53/67] Update attachment_callback_phish_with_pdf.yml (#2237) --- detection-rules/attachment_callback_phish_with_pdf.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/detection-rules/attachment_callback_phish_with_pdf.yml b/detection-rules/attachment_callback_phish_with_pdf.yml index 73fecdfc794..94fdd799bcf 100644 --- a/detection-rules/attachment_callback_phish_with_pdf.yml +++ b/detection-rules/attachment_callback_phish_with_pdf.yml @@ -74,6 +74,10 @@ source: | strings.icontains(.scan.ocr.raw, "norton"), strings.icontains(.scan.ocr.raw, "ebay"), strings.icontains(.scan.ocr.raw, "paypal"), + // suspicious attachment name + ( + regex.icontains(.file_name, 'INV(?:_|\s)?\d+(.pdf)$') + ) ) // Negate bank statements and not ( From 3dd4a2ff48edd2ad91c1ac52ab0c7c888852ced4 Mon Sep 17 00:00:00 2001 From: "Brandon 2: Brandon Harder" Date: Thu, 19 Dec 2024 09:41:02 -0600 Subject: [PATCH 54/67] Update link_cyrillic_substitutions_unsolicited.yml (#2240) Co-authored-by: Aiden Mitchell --- .../link_cyrillic_substitutions_unsolicited.yml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/detection-rules/link_cyrillic_substitutions_unsolicited.yml b/detection-rules/link_cyrillic_substitutions_unsolicited.yml index df81e883528..353772b6628 100644 --- a/detection-rules/link_cyrillic_substitutions_unsolicited.yml +++ b/detection-rules/link_cyrillic_substitutions_unsolicited.yml @@ -6,7 +6,14 @@ source: | type.inbound // message contains between 1 and 9 links - and 0 < length(body.links) < 10 + and ( + 0 < length(body.links) < 10 + or ( + length(body.links) == 0 + and length(attachments) > 0 + and body.current_thread.text == "" + ) + ) // display name or subject contains Cyrillic vowels in addition to standard letters and any([subject.subject, sender.display_name], From 36925e953bb9c734e34367df98e7938745b6e700 Mon Sep 17 00:00:00 2001 From: Brandon Murphy <4827852+zoomequipd@users.noreply.github.com> Date: Thu, 19 Dec 2024 10:55:06 -0600 Subject: [PATCH 55/67] Update attachment_callback_phish_with_pdf.yml (#2239) --- detection-rules/attachment_callback_phish_with_pdf.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/detection-rules/attachment_callback_phish_with_pdf.yml b/detection-rules/attachment_callback_phish_with_pdf.yml index 94fdd799bcf..942e53bcce7 100644 --- a/detection-rules/attachment_callback_phish_with_pdf.yml +++ b/detection-rules/attachment_callback_phish_with_pdf.yml @@ -74,9 +74,9 @@ source: | strings.icontains(.scan.ocr.raw, "norton"), strings.icontains(.scan.ocr.raw, "ebay"), strings.icontains(.scan.ocr.raw, "paypal"), - // suspicious attachment name + // suspicious attachment name from the attachment object not file.explode() output ( - regex.icontains(.file_name, 'INV(?:_|\s)?\d+(.pdf)$') + regex.icontains(..file_name, 'INV(?:_|\s)?\d+(.pdf)$') ) ) // Negate bank statements From 6631bf081530e53a19f63ea15281f9c57daf29b0 Mon Sep 17 00:00:00 2001 From: Aiden Mitchell Date: Thu, 19 Dec 2024 09:28:24 -0800 Subject: [PATCH 56/67] Update paypal_invoice_abuse.yml (#2236) --- detection-rules/paypal_invoice_abuse.yml | 35 ++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/detection-rules/paypal_invoice_abuse.yml b/detection-rules/paypal_invoice_abuse.yml index 87e2d188b3c..61de2bd572b 100644 --- a/detection-rules/paypal_invoice_abuse.yml +++ b/detection-rules/paypal_invoice_abuse.yml @@ -20,6 +20,41 @@ source: | and ( strings.ilike(body.html.display_text, "*seller note*") or strings.ilike(body.html.display_text, "*Note from *") + // phone number in subject + // the subject contains the seller's "name", attacks have been seen with the entire callback text in the seller's name + or ( + regex.icontains(strings.replace_confusables(subject.subject), + '.*\+?([lo0-9]{1}.)?\(?[lo0-9]{3}?\)?.[lo0-9]{3}.?[lo0-9]{4}.*' + ) + or regex.icontains(strings.replace_confusables(subject.subject), + '.*\+[lo0-9]{1,3}[lo0-9]{10}.*' + ) + or // +12028001238 + regex.icontains(strings.replace_confusables(subject.subject), + '.*[lo0-9]{3}\.[lo0-9]{3}\.[lo0-9]{4}.*' + ) + or // 202-800-1238 + regex.icontains(strings.replace_confusables(subject.subject), + '.*[lo0-9]{3}-[lo0-9]{3}-[lo0-9]{4}.*' + ) + or // (202) 800-1238 + regex.icontains(strings.replace_confusables(subject.subject), + '.*\([lo0-9]{3}\)\s[lo0-9]{3}-[lo0-9]{4}.*' + ) + or // (202)-800-1238 + regex.icontains(strings.replace_confusables(subject.subject), + '.*\([lo0-9]{3}\)-[lo0-9]{3}-[lo0-9]{4}.*' + ) + or ( // 8123456789 + regex.icontains(strings.replace_confusables(subject.subject), + '.*8[lo0-9]{9}.*' + ) + and regex.icontains(strings.replace_confusables(subject.subject + ), + '\+[1l]' + ) + ) + ) ) and ( ( From aefd975f6d9c35b39e392f12c61a17f1fac08e67 Mon Sep 17 00:00:00 2001 From: Aiden Mitchell Date: Thu, 19 Dec 2024 09:30:25 -0800 Subject: [PATCH 57/67] Create sender_domain_similar_to_cc.yml (#2234) --- insights/sender/sender_domain_similar_to_cc.yml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 insights/sender/sender_domain_similar_to_cc.yml diff --git a/insights/sender/sender_domain_similar_to_cc.yml b/insights/sender/sender_domain_similar_to_cc.yml new file mode 100644 index 00000000000..2ea3b0f4346 --- /dev/null +++ b/insights/sender/sender_domain_similar_to_cc.yml @@ -0,0 +1,15 @@ +name: "CC'd domains similar to sender domain" +type: "query" +source: | + distinct(map(filter(recipients.cc, + any(recipients.cc, + 0 < strings.ilevenshtein(sender.email.domain.sld, + .email.domain.sld + ) < 4 + ) + ), + .email.domain.domain + ), + . + ) +severity: "medium" From 93cbe2ff8c38051ae86f2e09dd35e6a786db6372 Mon Sep 17 00:00:00 2001 From: Aiden Mitchell Date: Thu, 19 Dec 2024 09:33:14 -0800 Subject: [PATCH 58/67] Update suspicious_request_for_quote_or_purchase.yml (#2224) --- ...spicious_request_for_quote_or_purchase.yml | 31 +++++++++++++++++-- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/detection-rules/suspicious_request_for_quote_or_purchase.yml b/detection-rules/suspicious_request_for_quote_or_purchase.yml index 4253793cd24..1f1476624df 100644 --- a/detection-rules/suspicious_request_for_quote_or_purchase.yml +++ b/detection-rules/suspicious_request_for_quote_or_purchase.yml @@ -10,7 +10,12 @@ source: | ( ( length(recipients.to) == 0 - or all(recipients.to, .display_name == "Undisclosed recipients") + or all(recipients.to, + .display_name in ( + "Undisclosed recipients", + "undisclosed-recipients" + ) + ) ) and length(recipients.cc) == 0 and length(recipients.bcc) == 0 @@ -39,10 +44,14 @@ source: | '(sign(ed?)|view).{0,10}(purchase order)|Request for a Quot(e|ation)' ) ), - (regex.icontains(body.current_thread.text, '(please|kindly).{0,30}quot(e|ation)')), + ( + regex.icontains(body.current_thread.text, + '(please|kindly).{0,30}quot(e|ation)' + ) + ), ( regex.icontains(subject.subject, - '(request for (purchase|quot(e|ation))|\bRFQ\b|\bRFP\b)' + '(request for (purchase|quot(e|ation))|\bRFQ\b|\bRFP\b|bid invit(e|ation))' ) ), ( @@ -63,6 +72,22 @@ source: | .name == "purchase_order" and .confidence == "high" ) ), + ( + 0 < length(filter(body.links, + ( + .href_url.domain.domain in $free_subdomain_hosts + or .href_url.domain.domain in $free_file_hosts + or network.whois(.href_url.domain).days_old < 30 + ) + and ( + regex.match(.display_text, '[A-Z ]+') + or any(ml.nlu_classifier(.display_text).entities, + .name in ("request", "urgency") + ) + ) + ) + ) < 3 + ) ) or ( length(attachments) == 1 From 9615ee363e741a4601177566b55f783d3f902a72 Mon Sep 17 00:00:00 2001 From: Aiden Mitchell Date: Thu, 19 Dec 2024 14:30:32 -0800 Subject: [PATCH 59/67] Update impersonation_microsoft_credential_theft.yml (#2242) --- .../impersonation_microsoft_credential_theft.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/detection-rules/impersonation_microsoft_credential_theft.yml b/detection-rules/impersonation_microsoft_credential_theft.yml index fc4d734c2be..6874acdcd09 100644 --- a/detection-rules/impersonation_microsoft_credential_theft.yml +++ b/detection-rules/impersonation_microsoft_credential_theft.yml @@ -58,6 +58,12 @@ source: | and headers.auth_summary.dmarc.details.from.domain == "planner.office365.com" ) + // message is not from sharepoint actual (additional check in case DMARC check above fails to bail out) + and not ( + strings.ilike(headers.message_id, '') + ) + // negate highly trusted sender domains unless they fail DMARC authentication and ( ( From b8e76d6ece4be7b8cec7e0b45551295627b95a35 Mon Sep 17 00:00:00 2001 From: Aiden Mitchell Date: Fri, 20 Dec 2024 10:30:31 -0800 Subject: [PATCH 60/67] Create infra_abuse_hardbacon.yml (#2210) Co-authored-by: ID Generator --- detection-rules/infra_abuse_hardbacon.yml | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 detection-rules/infra_abuse_hardbacon.yml diff --git a/detection-rules/infra_abuse_hardbacon.yml b/detection-rules/infra_abuse_hardbacon.yml new file mode 100644 index 00000000000..5f741f1e27e --- /dev/null +++ b/detection-rules/infra_abuse_hardbacon.yml @@ -0,0 +1,21 @@ +name: "Hardbacon infrastructure abuse" +description: "Hardbacon is a defunct Canadian budgeting app. Attackers have been observed using their marketing platform to send credential phishing messages." +type: "rule" +severity: "high" +source: | + type.inbound + and sender.email.domain.root_domain in ('hardbacon.com', 'hardbacon.ca') + and headers.mailer == 'Sendinblue' + and headers.auth_summary.dmarc.pass + and headers.auth_summary.spf.pass + +attack_types: + - "Credential Phishing" +tactics_and_techniques: + - "Evasion" + - "Impersonation: Brand" + - "Social engineering" +detection_methods: + - "Header analysis" + - "Sender analysis" +id: "5330db42-10d2-5671-bcb2-a99449ac24c2" From 7de69bdb89e5c7de8dc7af24205ffa125bd3821c Mon Sep 17 00:00:00 2001 From: Aiden Mitchell Date: Fri, 20 Dec 2024 14:43:34 -0800 Subject: [PATCH 61/67] Update impersonation_sharepoint_body_credential_theft.yml (#2235) --- .../impersonation_sharepoint_body_credential_theft.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/detection-rules/impersonation_sharepoint_body_credential_theft.yml b/detection-rules/impersonation_sharepoint_body_credential_theft.yml index fb646a8498d..6b91e650cb8 100644 --- a/detection-rules/impersonation_sharepoint_body_credential_theft.yml +++ b/detection-rules/impersonation_sharepoint_body_credential_theft.yml @@ -33,10 +33,8 @@ source: | ) ) and ( - ( - profile.by_sender().prevalence in ("new", "outlier") - and not profile.by_sender().solicited - ) + profile.by_sender_email().prevalence != 'common' + or not profile.by_sender_email().solicited or profile.by_sender().any_messages_malicious_or_spam ) and not profile.by_sender().any_false_positives From e3d97863c94def97bc16ff78578429981e30cad2 Mon Sep 17 00:00:00 2001 From: Aiden Mitchell Date: Fri, 20 Dec 2024 15:30:50 -0800 Subject: [PATCH 62/67] Create venmo_payment_abuse.yml (#2238) Co-authored-by: ID Generator --- detection-rules/venmo_payment_abuse.yml | 110 ++++++++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 detection-rules/venmo_payment_abuse.yml diff --git a/detection-rules/venmo_payment_abuse.yml b/detection-rules/venmo_payment_abuse.yml new file mode 100644 index 00000000000..0c3e7ef4957 --- /dev/null +++ b/detection-rules/venmo_payment_abuse.yml @@ -0,0 +1,110 @@ +name: "Venmo Payment Request Abuse" +description: "A fraudulent payment request found in the body of the message sent by exploiting Venmo's platform. Callback Phishing is an attempt by an attacker to solicit the victim (recipient) to call a phone number. The resulting interaction could lead to a multitude of attacks ranging from Financial theft, Remote Access Trojan (RAT) Installation or Ransomware Deployment." +type: "rule" +severity: "medium" +source: | + type.inbound + and length(attachments) == 0 + and sender.email.domain.root_domain in ("venmo.com") + and strings.ilike(body.html.display_text, "*requests $*") + and ( + ( + // icontains a phone number + ( + regex.icontains(strings.replace_confusables(body.current_thread.text), + '.*\+?([lo0-9]{1}.)?\(?[lo0-9]{3}?\)?.[lo0-9]{3}.?[lo0-9]{4}.*\n' + ) + or regex.icontains(strings.replace_confusables(body.current_thread.text), + '.*\+[lo0-9]{1,3}[lo0-9]{10}.*\n' + ) + or // +12028001238 + regex.icontains(strings.replace_confusables(body.current_thread.text), + '.*[lo0-9]{3}\.[lo0-9]{3}\.[lo0-9]{4}.*\n' + ) + or // 202-800-1238 + regex.icontains(strings.replace_confusables(body.current_thread.text), + '.*[lo0-9]{3}-[lo0-9]{3}-[lo0-9]{4}.*\n' + ) + or // (202) 800-1238 + regex.icontains(strings.replace_confusables(body.current_thread.text), + '.*\([lo0-9]{3}\)\s[lo0-9]{3}-[lo0-9]{4}.*\n' + ) + or // (202)-800-1238 + regex.icontains(strings.replace_confusables(body.current_thread.text), + '.*\([lo0-9]{3}\)-[lo0-9]{3}-[lo0-9]{4}.*\n' + ) + or ( // 8123456789 + regex.icontains(strings.replace_confusables(body.current_thread.text), + '.*8[lo0-9]{9}.*\n' + ) + and regex.icontains(strings.replace_confusables(body.current_thread.text + ), + '\+[1l]' + ) + ) + ) + and ( + ( + 4 of ( + strings.ilike(body.html.inner_text, '*you did not*'), + strings.ilike(body.html.inner_text, '*is not for*'), + strings.ilike(body.html.inner_text, '*done by you*'), + regex.icontains(body.html.inner_text, "didn\'t ma[kd]e this"), + strings.ilike(body.html.inner_text, '*Fruad Alert*'), + strings.ilike(body.html.inner_text, '*Fraud Alert*'), + strings.ilike(body.html.inner_text, '*fraudulent*'), + strings.ilike(body.html.inner_text, '*using your PayPal*'), + strings.ilike(body.html.inner_text, '*subscription*'), + strings.ilike(body.html.inner_text, '*antivirus*'), + strings.ilike(body.html.inner_text, '*order*'), + strings.ilike(body.html.inner_text, '*support*'), + strings.ilike(body.html.inner_text, '*sincerely apologize*'), + strings.ilike(body.html.inner_text, '*receipt*'), + strings.ilike(body.html.inner_text, '*invoice*'), + strings.ilike(body.html.inner_text, '*Purchase*'), + strings.ilike(body.html.inner_text, '*transaction*'), + strings.ilike(body.html.inner_text, '*Market*Value*'), + strings.ilike(body.html.inner_text, '*BTC*'), + strings.ilike(body.html.inner_text, '*call*'), + strings.ilike(body.html.inner_text, '*get in touch with our*'), + strings.ilike(body.html.inner_text, '*quickly inform*'), + strings.ilike(body.html.inner_text, '*quickly reach *'), + strings.ilike(body.html.inner_text, '*detected unusual transactions*'), + strings.ilike(body.html.inner_text, '*without your authorization*'), + strings.ilike(body.html.inner_text, '*cancel*'), + strings.ilike(body.html.inner_text, '*renew*'), + strings.ilike(body.html.inner_text, '*refund*'), + strings.ilike(body.html.inner_text, '*+1*'), + regex.icontains(body.html.inner_text, 'help.{0,3}desk'), + ) + ) + or regex.icontains(body.current_thread.text, + 'note from.{0,50}(?:call|reach|contact|paypal)' + ) + or any(ml.nlu_classifier(body.current_thread.text).intents, + .name == "callback_scam" + ) + or ( + // Unicode confusables words obfuscated in note + regex.icontains(body.html.inner_text, + '\+๐Ÿญ|๐—ฝ๐—ฎ๐˜†๐—บ๐—ฒ๐—ป๐˜|๐—›๐—ฒ๐—น๐—ฝ ๐——๐—ฒ๐˜€๐—ธ|๐—ฟ๐—ฒ๐—ณ๐˜‚๐—ป๐—ฑ|๐—ฎ๐—ป๐˜๐—ถ๐˜ƒ๐—ถ๐—ฟ๐˜‚๐˜€|๐—ฐ๐—ฎ๐—น๐—น|๐—ฐ๐—ฎ๐—ป๐—ฐ๐—ฒ๐—น' + ) + ) + or strings.ilike(body.html.inner_text, '*kindly*') + ) + ) + ) + +attack_types: + - "Callback Phishing" + - "BEC/Fraud" +tactics_and_techniques: + - "Social engineering" + - "Impersonation: Brand" + - "Evasion" +detection_methods: + - "Natural Language Understanding" + - "Content analysis" + - "Sender analysis" + - "HTML analysis" +id: "4450639a-04ec-5348-9697-feb7664ca2dd" From 87d83e2a05f18e09c7aff53341696b841a5a2837 Mon Sep 17 00:00:00 2001 From: Aiden Mitchell Date: Mon, 23 Dec 2024 15:55:35 -0800 Subject: [PATCH 63/67] Update attachment_svg_embedded_js.yml (#2241) --- .../attachment_svg_embedded_js.yml | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/detection-rules/attachment_svg_embedded_js.yml b/detection-rules/attachment_svg_embedded_js.yml index 1bb935303aa..59a59593ed0 100644 --- a/detection-rules/attachment_svg_embedded_js.yml +++ b/detection-rules/attachment_svg_embedded_js.yml @@ -11,14 +11,17 @@ severity: "medium" source: | type.inbound and any(attachments, - (.file_extension =~ "svg" or .file_extension in $file_extensions_common_archives) - and any(file.explode(.), - .file_extension == "svg" - and "script" in~ .scan.xml.tags - // unclear if this is necessary, but it's been observed - // in all payloads we've seen, so we'll include it - // as an extra FP precaution - and any(.scan.strings.strings, strings.icontains(., "CDATA")) + ( + .file_extension =~ "svg" + or .file_extension in $file_extensions_common_archives + ) + and strings.ilike(file.parse_text(.).text, + "*onload*", + "*window.location.href*", + "*onerror*", + "*CDATA*", + "**" ) ) and ( From d7e301360cfc2f6398250b0da120dd588382865c Mon Sep 17 00:00:00 2001 From: Sam Scholten Date: Mon, 23 Dec 2024 19:10:41 -0500 Subject: [PATCH 64/67] Create lookalike_domain_with_suspicious_language.yml (#2197) Co-authored-by: ID Generator --- ...kalike_domain_with_suspicious_language.yml | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 detection-rules/lookalike_domain_with_suspicious_language.yml diff --git a/detection-rules/lookalike_domain_with_suspicious_language.yml b/detection-rules/lookalike_domain_with_suspicious_language.yml new file mode 100644 index 00000000000..29082f487f6 --- /dev/null +++ b/detection-rules/lookalike_domain_with_suspicious_language.yml @@ -0,0 +1,50 @@ +name: "Suspected Lookalike domain with suspicious language" +description: "This rule identifies messages where links use typosquatting or lookalike domains similar to the sender domain, with at least one domain being either unregistered or recently registered (โ‰ค90 days). The messages must also contain indicators of business email compromise (BEC), credential theft, or abusive language patterns like financial terms or polite phrasing such as kindly. This layered approach targets phishing attempts combining domain deception with manipulative content" +type: "rule" +severity: "medium" +source: | + type.inbound + + // levenshtein distance (edit distance) between the SLD of the link and the sender domain is greater than 0 and less than or equal to 2. + // This detects typosquatting or domains that are deceptively similar to the sender. + + and any(body.links, + length(.href_url.domain.sld) > 3 + and 0 < strings.levenshtein(.href_url.domain.sld, + sender.email.domain.sld + ) <= 2 + //exclude onmicrosoft.com + and not sender.email.domain.root_domain == "onmicrosoft.com" + and ( + // domains are not registered or registered within 90d + // network.whois(.href_url.domain).found == false + network.whois(.href_url.domain).days_old <= 90 + or network.whois(sender.email.domain).found == false + or network.whois(sender.email.domain).days_old <= 90 + ) + ) + // the mesasge is intent is BEC or Cred Theft, or is talking about financial invoicing/banking language, or a request contains "kindly" + and any(ml.nlu_classifier(body.current_thread.text).intents, + .name in ("bec", "cred_theft") + or any(ml.nlu_classifier(body.current_thread.text).entities, + .name == "financial" + and ( + .text in ("invoice", "banking information") + or .name == "request" and strings.icontains(.text, "kindly") + ) + ) + ) +tags: + - "Attack surface reduction" +attack_types: + - "BEC/Fraud" +tactics_and_techniques: + - "Evasion" + - "Lookalike domain" + - "Social engineering" +detection_methods: + - "Content analysis" + - "Natural Language Understanding" + - "Sender analysis" + - "Whois" +id: "3674ced0-691c-5faa-9ced-922e7201dc29" From 20b8911f2f62006aa06e8bb79368363dba166fc6 Mon Sep 17 00:00:00 2001 From: Brandon Murphy <4827852+zoomequipd@users.noreply.github.com> Date: Thu, 26 Dec 2024 08:43:05 -0600 Subject: [PATCH 65/67] Update link_credential_phishing_voicemail_language.yml (#2147) --- ...credential_phishing_voicemail_language.yml | 112 ++++++++++++++---- 1 file changed, 88 insertions(+), 24 deletions(-) diff --git a/detection-rules/link_credential_phishing_voicemail_language.yml b/detection-rules/link_credential_phishing_voicemail_language.yml index 22bc6e38250..0c554fa5abb 100644 --- a/detection-rules/link_credential_phishing_voicemail_language.yml +++ b/detection-rules/link_credential_phishing_voicemail_language.yml @@ -13,15 +13,15 @@ source: | any([subject.subject, sender.display_name], regex.icontains(., // split phrases that occur within 3 words between or only punctuation between them - '(?:v[nm](\b|[[:punct:]])?|\bvoice(?:mail|message)?|audio|incoming|missed(?:\sa\s)?|left( a)?|wireless)(?:\w+(\s\w+)?|[[:punct:]]+|\s+){0,3}(?:mail|message|msg|recording|received|notif|support|ca[li1][li1]\d*\b|ca[il1][il1](?:er)?|log|transcript(?:ion)?\b)', + '(?:v[nm](\b|[[:punct:]])?|\bvoice(?:mail|message)?|audi[o0]|incoming|missed(?:\sa\s)?|left( a)?|wireless|v[[:punct:]])(?:\w+(\s\w+)?|[[:punct:]]+|\s+){0,3}(?:mail|message|msg|recording|received|notif|support|ca[li1][li1]\d*\b|ca[il1][il1](?:er)?|log|transcript(?:ion)?\b)', // split phrases that start with "caller" that occur within 3 words between or only punctation - 'ca[li1][li1](?:er)?(?:\w+(\s\w+)?|[[:punct:]]+|\s+){0,3}(?:v[nm](\b|[[:punct:]])?|\bvoice(?:mail|message)?|audio|missed(?:\sa\s)?|left( a)?)', + 'ca[li1][li1](?:er)?(?:\w+(\s\w+)?|[[:punct:]]+|\s+){0,3}(?:v[nm](\b|[[:punct:]])?|\bvoice(?:mail|message)?|audi[o0]|missed(?:\sa\s)?|left( a)?)', // strong phrases - '(?:open mp3|audio note|\.wav|left a vm|[^\s]+voip[^\s]*|unanswered.*ca[li1][li1]|incoming.vm|left msg|wireless ca[li1][li1]er|VM Service|voice message|missed.ca[li1][li1](?:e[rd])?|\bca[li1][li1].(?:support|service)(?: for| log)?|missed.{0,10} VM|new voicemail from|new.v.m.from.\+?\d+|new voicemail?(?:\w+(\s\w+)?|[[:punct:]]+|\s+){0,3}transcript(s|ion)?|message received)', + '(?:open mp3|audi[o0] note|\.wav|left a vm|[^\s]+voip[^\s]*|unanswered.*ca[li1][li1]|incoming.vm|left msg|wireless ca[li1][li1]er|VM Service|voice message|missed.ca[li1][li1](?:e[rd])?|\bca[li1][li1].(?:support|service)(?: for| log)?|missed.{0,10} VM|new voicemail from|new.v.m.from.\+?\d+|new voicemail?(?:\w+(\s\w+)?|[[:punct:]]+|\s+){0,3}transcript(s|ion)?|message received)', // starts in the format of `(4)` and contains some voicemail keywords '^\(\d\)\s(?:\w+(\s\w+)?|[[:punct:]]+|\s+){0,3}(?:message|voip|voice|unread|call)', 'ca[li1][li1](?:er)?(?:\w+(\s\w+)?|[[:punct:]]+|\s+){0,3}(?:playback|transcript)', - + // obfuscated phone number with at least one digit in the area code and at least one obfuscated number in the last group // 555-555-555X, 555-555-XXXX, 555-5XX-XXXX '\b1?\(?(\d{3}|\d{2}[\*X]|\d[\*X]{2})\)?[^a-z0-9]{0,2}(\d{2,3}|\d{2}[\*X]|\d[\*X]{2}|[\*X]{2,3})[^a-z0-9]{0,4}(\d{3}[\*X]|\d{2}[\*X]{2}|\d[\*X]{3}|[\*X]{3,4})[^0-9]', @@ -31,19 +31,18 @@ source: | ) ) // body.current_thread.text inspection should be very specific to avoid FP - or regex.icontains( - strings.replace_confusables(body.current_thread.text), - //body.current_thread.text, - 'you (?:have |received )*(?:\w+(\s\w+)?|[[:punct:]]+|\s+){0,3}\bvoice\s?(?:mail|audio|message)', + or regex.icontains(strings.replace_confusables(body.current_thread.text), + // body.current_thread.text, + 'you (?:have |received )*(?:\w+(\s\w+)?|[[:punct:]]+|\s+){0,3}\bvoice\s?(?:mail|audi[o0]|message)', 'sent (?:from|by) (?:your )?voice (?:mail )?system', - 'new (?:voice(?:mail)?|audio) (?:message|notification|record)', + 'new (?:voice(?:mail)?|audi[o0]) (?:message|notification|record)', 'voicemail (is )?attached', 'an? (?:new )?encrypted voicemail', 'a (?:new )?pending message', 'Your? have (?: an?)?incoming voiceRec', "you(?:\'ve| have) a (?:new )?missed ca[li1][li1]", 'New Voicemail Received', - 'left you a (?:\w+(\s\w+)?|[[:punct:]]+|\s+){0,3}(?:voice(?:mail)?|audio)(?: message)?', + 'left you a (?:\w+(\s\w+)?|[[:punct:]]+|\s+){0,3}(?:voice(?:mail)?|audi[o0])(?: message)?', 'New missed ca[li1][li1] record', 'voicemail transcript(?:ion)?', 'Listen to VoiceMail', @@ -53,7 +52,6 @@ source: | or strings.icontains(body.html.raw, 'Voicemail Notification') or strings.icontains(body.html.raw, '
\s*.*\b(?:your subscription renewal|couldn.?t be processed|trouble renewing subscription|update your details|just update your|continue your subscription|prefer to use EFT|change payment method|verify your account|suspended due to issue|payment declined notice|account needs verification|confirm your billing|immediate action required|failed payment notification|billing information update|service interruption warning|unable to process payment|subscription payment failed|action needed now|update banking information|subscription expiration notice|payment method change)\b.*