diff --git a/.github/workflows/mql-mimic-tests.yml b/.github/workflows/mql-mimic-tests.yml deleted file mode 100644 index de506e94e80..00000000000 --- a/.github/workflows/mql-mimic-tests.yml +++ /dev/null @@ -1,40 +0,0 @@ -name: MQL Mimic Tests - -on: - push: - branches: [ "**" ] - -concurrency: - group: ${{ github.ref }} - cancel-in-progress: true - -jobs: - trigger-via-zapier: - name: Trigger Test Run - runs-on: ubuntu-20.04 - permissions: - checks: write - - steps: - - - name: "Trigger MQL Mimic Tests" - env: - trigger_url: '${{ secrets.MQL_MOCK_TRIGGER }}' - branch: '${{ github.ref_name }}' - repo: '${{ github.repository }}' - token: '${{ secrets.GITHUB_TOKEN }}' - sha: '${{ github.sha }}' - run: | - curl -X POST $trigger_url \ - -H 'Content-Type: application/json' \ - -d '{"branch":"'$branch'","repo":"'$repo'","token":"'$token'","sha":"'$sha'"}' - - - name: Wait for check to be completed - uses: fountainhead/action-wait-for-check@v1.1.0 - id: wait-for-build - # Wait for results so that the token remains valid while the test suite is executing and posting a check here. - with: - token: ${{ secrets.GITHUB_TOKEN }} - checkName: "MQL Mimic Tests" - ref: ${{ github.sha }} - timeoutSeconds: 3600 diff --git a/.github/workflows/rule-validate.yml b/.github/workflows/rule-validate.yml index 78efe60f6dc..dc15f63eeba 100644 --- a/.github/workflows/rule-validate.yml +++ b/.github/workflows/rule-validate.yml @@ -30,6 +30,7 @@ jobs: with: ref: ${{ github.head_ref }} repository: ${{ github.event.pull_request.head.repo.full_name }} + depth: 0 - uses: actions/setup-python@v4 with: @@ -92,6 +93,45 @@ jobs: id: get_head run: echo "##[set-output name=HEAD;]$(git rev-parse HEAD)" + - name: Get changed detection-rules + id: changed-files + uses: tj-actions/changed-files@v39 + with: + files: "detection-rules/**" + recover_deleted_files: true + + - name: "Find updated rule IDs" + id: find_ids + run: | + for file in ${{ steps.changed-files.outputs.all_changed_and_modified_files }}; do + echo "$file was changed" + rule_id=$(yq '.id' $file) + + echo "$file has rule ID $rule_id" + altered_rule_ids=$(echo "$rule_id"" ""$altered_rule_ids") + done + + echo "Altered Ruled IDs: [$altered_rule_ids]" + echo "##[set-output name=rule_ids;]$(echo $altered_rule_ids)" + # TODO: This doesn't solve for a modified rule_id. We could merge with any files known on 'main', but changing + # a rule ID is a separate problem. + + - name: "Trigger MQL Mimic Tests" + env: + trigger_url: '${{ secrets.MQL_MOCK_TRIGGER }}' + branch: ${{ github.event_name == 'pull_request_target' && github.head_ref || github.ref }} + repo: ${{ github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.full_name || github.repository }} + token: '${{ secrets.GITHUB_TOKEN }}' + sha: '${{ steps.get_head.outputs.HEAD }}' + only_rule_ids: '${{ steps.find_ids.outputs.rule_ids }}' + run: | + body='{"branch":"'$branch'","repo":"'$repo'","token":"'$token'","sha":"'$sha'","only_rule_ids":"'$only_rule_ids'"}' + echo $body + + curl -X POST $trigger_url \ + -H 'Content-Type: application/json' \ + -d "$body" + # When we add a commit, GitHub won't trigger actions on the auto commit, so we're missing a required check on the # HEAD commit. # Various alternatives were explored, but all run into issues when dealing with forks. This sets a "Check" for @@ -126,3 +166,14 @@ jobs: text: "Rule Tests and ID Updated", }, }); + + - name: Wait for MQL Mimic check to be completed + uses: fountainhead/action-wait-for-check@v1.1.0 + id: wait-for-build + # Wait for results so that the token remains valid while the test suite is executing and posting a check here. + with: + token: ${{ secrets.GITHUB_TOKEN }} + checkName: "MQL Mimic Tests" + ref: ${{ steps.get_head.outputs.HEAD }} + timeoutSeconds: 3600 + diff --git a/.github/workflows/update-test-rules.yml b/.github/workflows/update-test-rules.yml index 89c681c27e0..4ca584c97f1 100644 --- a/.github/workflows/update-test-rules.yml +++ b/.github/workflows/update-test-rules.yml @@ -104,12 +104,13 @@ jobs: done # This workflow is trigerred from an issue comment so we don't automatically have context on what changed in the PR + # TODO: We can only retrieve 100 results, we need to add pagination support. curl -L \ -o pr_files.json \ -H "Accept: application/vnd.github+json" \ -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}"\ -H "X-GitHub-Api-Version: 2022-11-28" \ - https://api.github.com/repos/sublime-security/sublime-rules/pulls/$pr_num/files + https://api.github.com/repos/sublime-security/sublime-rules/pulls/$pr_num/files?per_page=100 # Any files added/changed/modified will be copied to test-rules files_changed=$(jq -r '.[] | select(.status == "added" or .status == "modified" or .status == "changed") | .filename' pr_files.json) @@ -122,6 +123,13 @@ jobs: # but it doesn't seem any simpler). And then add testing metadata. # If multiple PRs modify the same file, only one can be tested. This is solveable, but not something we see often. for file in $files_changed; do + # Skip any LA rules. We'll ignore these downstream anyway, but best to keep the branch clean. + la_count=$(grep -c 'beta.linkanalysis' source/$file || true) + if [[ "$la_count" != '0' ]]; then + echo "Ignoring $file because of linkanalysis usage" + continue + fi + cp source/$file destination/$file yq -i '.testing_pr = env(pr_num)' destination/$file yq -i '.testing_sha = env(sha)' destination/$file diff --git a/detection-rules/attachment_adobe_image_lure_fts.yml b/detection-rules/attachment_adobe_image_lure_fts.yml index 78125362de3..1c222cd97d9 100644 --- a/detection-rules/attachment_adobe_image_lure_fts.yml +++ b/detection-rules/attachment_adobe_image_lure_fts.yml @@ -20,13 +20,10 @@ source: | ) ) and ( - ( - sender.email.domain.root_domain in $free_email_providers - and sender.email.email not in $sender_emails - ) + profile.by_sender().prevalence in ("new", "outlier") or ( - sender.email.domain.root_domain not in $free_email_providers - and sender.email.domain.domain not in $sender_domains + profile.by_sender().any_messages_malicious_or_spam + and not profile.by_sender().any_false_positives ) ) attack_types: diff --git a/detection-rules/attachment_any_html_in_archive_unsolicited.yml b/detection-rules/attachment_any_html_in_archive_unsolicited.yml index ddf0659e54e..f7ab205f57a 100644 --- a/detection-rules/attachment_any_html_in_archive_unsolicited.yml +++ b/detection-rules/attachment_any_html_in_archive_unsolicited.yml @@ -14,13 +14,10 @@ source: | and any(file.explode(.), .depth > 0 and .file_extension in~ ("html", "htm")) ) and ( - ( - sender.email.domain.root_domain in $free_email_providers - and sender.email.email not in $recipient_emails - ) + not profile.by_sender().solicited or ( - sender.email.domain.root_domain not in $free_email_providers - and sender.email.domain.domain not in $recipient_domains + profile.by_sender().any_messages_malicious_or_spam + and not profile.by_sender().any_false_positives ) ) tags: diff --git a/detection-rules/attachment_any_html_new_sender.yml b/detection-rules/attachment_any_html_new_sender.yml index cc22e73e915..117804f24ce 100644 --- a/detection-rules/attachment_any_html_new_sender.yml +++ b/detection-rules/attachment_any_html_new_sender.yml @@ -11,16 +11,11 @@ severity: "medium" source: | type.inbound and any(attachments, .file_extension in~ ('htm', 'html') or .file_type == "html") - - // first-time sender and ( - ( - sender.email.domain.root_domain in $free_email_providers - and sender.email.email not in $sender_emails - ) + profile.by_sender().prevalence in ("new", "outlier") or ( - sender.email.domain.root_domain not in $free_email_providers - and sender.email.domain.domain not in $sender_domains + profile.by_sender().any_messages_malicious_or_spam + and not profile.by_sender().any_false_positives ) ) tags: diff --git a/detection-rules/attachment_any_html_unsolicited.yml b/detection-rules/attachment_any_html_unsolicited.yml index 075feda5569..c5549895fd3 100644 --- a/detection-rules/attachment_any_html_unsolicited.yml +++ b/detection-rules/attachment_any_html_unsolicited.yml @@ -11,16 +11,11 @@ severity: "low" source: | type.inbound and any(attachments, .file_extension in~ ('htm', 'html') or .file_type == "html") - - // unsolicited and ( - ( - sender.email.domain.root_domain in $free_email_providers - and sender.email.email not in $recipient_emails - ) + not profile.by_sender().solicited or ( - sender.email.domain.root_domain not in $free_email_providers - and sender.email.domain.domain not in $recipient_domains + profile.by_sender().any_messages_malicious_or_spam + and not profile.by_sender().any_false_positives ) ) tags: diff --git a/detection-rules/attachment_callback_phish_with_img.yml b/detection-rules/attachment_callback_phish_with_img.yml index e9ce44623c7..19c4f46b120 100644 --- a/detection-rules/attachment_callback_phish_with_img.yml +++ b/detection-rules/attachment_callback_phish_with_img.yml @@ -10,13 +10,10 @@ severity: "high" source: | type.inbound and ( - ( - sender.email.domain.root_domain in $free_email_providers - and sender.email.email not in $recipient_emails - ) + not profile.by_sender().solicited or ( - sender.email.domain.root_domain not in $free_email_providers - and sender.email.domain.domain not in $recipient_domains + profile.by_sender().any_messages_malicious_or_spam + and not profile.by_sender().any_false_positives ) ) and sender.email.domain.root_domain in $free_email_providers diff --git a/detection-rules/attachment_callback_phish_with_pdf.yml b/detection-rules/attachment_callback_phish_with_pdf.yml index 1b6f24a320b..e707ca72c80 100644 --- a/detection-rules/attachment_callback_phish_with_pdf.yml +++ b/detection-rules/attachment_callback_phish_with_pdf.yml @@ -8,13 +8,10 @@ severity: "high" source: | type.inbound and ( - ( - sender.email.domain.root_domain in $free_email_providers - and sender.email.email not in $recipient_emails - ) + not profile.by_sender().solicited or ( - sender.email.domain.root_domain not in $free_email_providers - and sender.email.domain.domain not in $recipient_domains + profile.by_sender().any_messages_malicious_or_spam + and not profile.by_sender().any_false_positives ) ) diff --git a/detection-rules/attachment_cve_2023_38831.yml b/detection-rules/attachment_cve_2023_38831.yml new file mode 100644 index 00000000000..22f0b734b1b --- /dev/null +++ b/detection-rules/attachment_cve_2023_38831.yml @@ -0,0 +1,67 @@ +name: "Attachment: Zip Exploiting CVE-2023-38831 (Unsolicited)" +description: | + A Zip attachment that exhibits attributes required to exploit CVE-2023-38831, a vulnerability in WinRAR (prior to 6.23). +type: "rule" +severity: "critical" +authors: + - twitter: "delivr_to" +references: + - https://twitter.com/GroupIB_TI/status/1694277126944633328 + - https://www.group-ib.com/blog/cve-2023-38831-winrar-zero-day/ + - https://github.com/b1tg/CVE-2023-38831-winrar-exploit/ + - https://delivr.to/payloads?id=ab969e8a-bf5c-45a6-acd0-0dd2b2a34750 +source: | + type.inbound + and any(attachments, + .file_extension in $file_extensions_common_archives and + any(file.explode(.), + ( + .depth == 0 and + any(.scan.zip.all_paths, + regex.match(., + // zip contains a path with spaces and file extensions + // lure.pdf /lure.pdf .cmd + // + // /= Initial file name + // | + // | /= Space + // | | + // | | /= Folder + // | | | + // | | | /= Repeated file name + // | | | | + // | | | | /= Space + // | | | | | + // | | | | | /= Real script ending + // | | | | | | + '\w+\.\w+\s\/\w+\.\w+\s\.\w+' + ) + ) + ) and + ( + // One file name is present in another, e.g. + // delivrto.pdf + // delivrto.pdf /delivrto.pdf .cmd + any(.scan.zip.all_paths, + any(..scan.zip.all_paths, + . != .. and + strings.starts_with(., ..) + ) + ) + ) + ) + ) + and ( + ( + sender.email.domain.root_domain in $free_email_providers + and sender.email.email not in $recipient_emails + ) + or ( + sender.email.domain.root_domain not in $free_email_providers + and sender.email.domain.domain not in $recipient_domains + ) + ) +tags: + - "Suspicious Attachment" + - "CVE-2023-38831" +id: "926b96ae-f40b-525d-a312-bd6c9a5f19fb" diff --git a/detection-rules/attachment_docusign_image_suspicious_links.yml b/detection-rules/attachment_docusign_image_suspicious_links.yml index 514b82554c1..7d802543568 100644 --- a/detection-rules/attachment_docusign_image_suspicious_links.yml +++ b/detection-rules/attachment_docusign_image_suspicious_links.yml @@ -26,13 +26,11 @@ source: | ) ) and ( - ( - sender.email.domain.root_domain in $free_email_providers - and sender.email.email not in $sender_emails - ) + profile.by_sender().prevalence in ("new", "outlier") or ( - sender.email.domain.root_domain not in $free_email_providers - and sender.email.domain.domain not in $sender_domains + profile.by_sender().any_messages_malicious_or_spam + and not profile.by_sender().any_false_positives + ) ) attack_types: diff --git a/detection-rules/attachment_dropbox_image_suspicious_links.yml b/detection-rules/attachment_dropbox_image_suspicious_links.yml index 1de0a856b31..478744466bc 100644 --- a/detection-rules/attachment_dropbox_image_suspicious_links.yml +++ b/detection-rules/attachment_dropbox_image_suspicious_links.yml @@ -14,13 +14,10 @@ source: | ) ) and ( - ( - sender.email.domain.root_domain in $free_email_providers - and sender.email.email not in $sender_emails - ) + profile.by_sender().prevalence in ("new", "outlier") or ( - sender.email.domain.root_domain not in $free_email_providers - and sender.email.domain.domain not in $sender_domains + profile.by_sender().any_messages_malicious_or_spam + and not profile.by_sender().any_false_positives ) ) attack_types: diff --git a/detection-rules/attachment_eml_cred_theft.yml b/detection-rules/attachment_eml_cred_theft.yml index a85a54f7777..d3b647aa504 100644 --- a/detection-rules/attachment_eml_cred_theft.yml +++ b/detection-rules/attachment_eml_cred_theft.yml @@ -29,16 +29,11 @@ source: | and not any(attachments, .content_type == "message/delivery-status") // if the "References" is in the body of the message, it's probably a bounce and not any(headers.references, strings.contains(body.html.display_text, .)) - - // unsolicited and ( - ( - sender.email.domain.root_domain in $free_email_providers - and sender.email.email not in $recipient_emails - ) + not profile.by_sender().solicited or ( - sender.email.domain.root_domain not in $free_email_providers - and sender.email.domain.domain not in $recipient_domains + profile.by_sender().any_messages_malicious_or_spam + and not profile.by_sender().any_false_positives ) ) attack_types: diff --git a/detection-rules/attachment_eml_with_html_attachment.yml b/detection-rules/attachment_eml_with_html_attachment.yml index 68fac95489f..f719bf69097 100644 --- a/detection-rules/attachment_eml_with_html_attachment.yml +++ b/detection-rules/attachment_eml_with_html_attachment.yml @@ -40,16 +40,11 @@ source: | and not any(attachments, .content_type == "message/delivery-status") // if the "References" is in the body of the message, it's probably a bounce and not any(headers.references, strings.contains(body.html.display_text, .)) - - // unsolicited and ( - ( - sender.email.domain.root_domain in $free_email_providers - and sender.email.email not in $recipient_emails - ) + not profile.by_sender().solicited or ( - sender.email.domain.root_domain not in $free_email_providers - and sender.email.domain.domain not in $recipient_domains + profile.by_sender().any_messages_malicious_or_spam + and not profile.by_sender().any_false_positives ) ) tags: diff --git a/detection-rules/attachment_emotet_heavily_padded_doc_in_zip.yml b/detection-rules/attachment_emotet_heavily_padded_doc_in_zip.yml index b23bcff7ba2..0f1e36c18ac 100644 --- a/detection-rules/attachment_emotet_heavily_padded_doc_in_zip.yml +++ b/detection-rules/attachment_emotet_heavily_padded_doc_in_zip.yml @@ -19,13 +19,10 @@ source: | ) ) and ( - ( - sender.email.domain.root_domain in $free_email_providers - and sender.email.email not in $sender_emails - ) + profile.by_sender().prevalence in ("new", "outlier") or ( - sender.email.domain.root_domain not in $free_email_providers - and sender.email.domain.domain not in $sender_domains + profile.by_sender().any_messages_malicious_or_spam + and not profile.by_sender().any_false_positives ) ) tags: diff --git a/detection-rules/attachment_encrypted_ole_unsolicited.yml b/detection-rules/attachment_encrypted_ole_unsolicited.yml index 6e591479b56..10df0004afc 100644 --- a/detection-rules/attachment_encrypted_ole_unsolicited.yml +++ b/detection-rules/attachment_encrypted_ole_unsolicited.yml @@ -13,13 +13,10 @@ source: | and file.oletools(.).indicators.encryption.exists ) and ( - ( - sender.email.domain.root_domain in $free_email_providers - and sender.email.email not in $recipient_emails - ) + not profile.by_sender().solicited or ( - sender.email.domain.root_domain not in $free_email_providers - and sender.email.domain.domain not in $recipient_domains + profile.by_sender().any_messages_malicious_or_spam + and not profile.by_sender().any_false_positives ) ) attack_types: diff --git a/detection-rules/attachment_free_subdomain_suspicious_link_language.yml b/detection-rules/attachment_free_subdomain_suspicious_link_language.yml index 11fa2309c25..628ae4b8c27 100644 --- a/detection-rules/attachment_free_subdomain_suspicious_link_language.yml +++ b/detection-rules/attachment_free_subdomain_suspicious_link_language.yml @@ -15,7 +15,7 @@ source: | and length(recipients.bcc) == 0 and any(body.links, any(file.explode(beta.linkanalysis(.).screenshot), - any(ml.nlu_classifier(.scan.ocr.raw).intents, .name == "cred_theft") + any(ml.nlu_classifier(.scan.ocr.raw).intents, .name == "cred_theft" and .confidence != "low") ) ) attack_types: diff --git a/detection-rules/attachment_html_attachment_login_page.yml b/detection-rules/attachment_html_attachment_login_page.yml index 6f720efda3f..0f513c19103 100644 --- a/detection-rules/attachment_html_attachment_login_page.yml +++ b/detection-rules/attachment_html_attachment_login_page.yml @@ -68,15 +68,11 @@ source: | ) ) ) - // Unsolicited and ( - ( - sender.email.domain.root_domain in $free_email_providers - and sender.email.email not in $recipient_emails - ) + not profile.by_sender().solicited or ( - sender.email.domain.root_domain not in $free_email_providers - and sender.email.domain.domain not in $recipient_domains + profile.by_sender().any_messages_malicious_or_spam + and not profile.by_sender().any_false_positives ) ) attack_types: diff --git a/detection-rules/attachment_html_recipient_in_javascript_identifiers.yml b/detection-rules/attachment_html_recipient_in_javascript_identifiers.yml index 849592d655b..b57a8a5a500 100644 --- a/detection-rules/attachment_html_recipient_in_javascript_identifiers.yml +++ b/detection-rules/attachment_html_recipient_in_javascript_identifiers.yml @@ -7,25 +7,36 @@ source: | type.inbound and any(attachments, ( - .file_extension in~ ("html", "htm", "shtml", "dhtml") + .file_extension in~ ("html", "htm", "shtml", "dhtml", "xhtml") or ( .file_extension is null and .file_type == "unknown" and .content_type == "application/octet-stream" - and .size < 100000000 ) or .file_extension in~ $file_extensions_common_archives or .file_type == "html" + or .content_type == "text/html" ) and any(file.explode(.), // suspicious identifiers - any(.scan.javascript.identifiers, strings.like(., "atob", "decrypt")) - // Recipients address found in javascript - and any(recipients.to, - any(..scan.javascript.strings, strings.icontains(., ..email.email)) + any([.scan.strings.strings, .scan.javascript.identifiers], + any(., strings.like(., "*atob*", "*decrypt*")) ) ) - ) + // Recipients address found in javascript + and any(file.explode(.), + any(recipients.to, + any(..scan.javascript.strings, strings.icontains(., ..email.email)) + ) + + // Negating Cisco Secure Email Encryption + and not any(.scan.javascript.strings, + strings.contains(., "Cisco Registered Envelope Service") + and not strings.contains(., "https://res.cisco.com:443") + ) + ) + ) + attack_types: - "Credential Phishing" tactics_and_techniques: diff --git a/detection-rules/attachment_html_smuggling_body_onload.yml b/detection-rules/attachment_html_smuggling_body_onload.yml new file mode 100644 index 00000000000..98dbb8d552b --- /dev/null +++ b/detection-rules/attachment_html_smuggling_body_onload.yml @@ -0,0 +1,49 @@ +name: "Attachment: HTML smuggling 'body onload' linking to suspicious destination" +description: | + Potential HTML Smuggling. + This rule inspects HTML attachments that contain a single link and leveraging an HTML body onload event. The linked domain must be in the URLhaus trusted repoters list, or have a suspicious TLD. +type: "rule" +severity: "high" +source: | + type.inbound + and any(attachments, + ( + .file_extension in~ ("html", "htm", "shtml", "dhtml", "xhtml") + or ( + .file_extension is null + and .file_type == "unknown" + and .content_type == "application/octet-stream" + ) + or .file_extension in~ $file_extensions_common_archives + or .file_type == "html" + or .content_type == "text/html" + ) + and any(file.explode(.), + not length(.scan.url.invalid_urls) > 0 + and length(.scan.url.urls) == 1 + and any(.scan.strings.strings, strings.ilike(., "*body onload*")) + and ( + any(.scan.url.urls, + .domain.root_domain in $abuse_ch_urlhaus_domains_trusted_reporters + + // To-do uncomment below when list is created + //or .domain.root_domain in $suspicious_root_domains + or .domain.tld in $suspicious_tlds + ) + ) + ) + ) +attack_types: + - "Credential Phishing" + - "Malware/Ransomware" +tactics_and_techniques: + - "Evasion" + - "HTML smuggling" + - "Scripting" +detection_methods: + - "Archive analysis" + - "Content analysis" + - "File analysis" + - "HTML analysis" + - "URL analysis" +id: "c1e2beed-e71e-58d2-b922-9601337645b2" diff --git a/detection-rules/attachment_html_smuggling_decimal_encoding.yml b/detection-rules/attachment_html_smuggling_decimal_encoding.yml new file mode 100644 index 00000000000..236d94bf693 --- /dev/null +++ b/detection-rules/attachment_html_smuggling_decimal_encoding.yml @@ -0,0 +1,39 @@ +name: "Attachment: HTML smuggling with decimal encoding" +description: | + Potential HTML smuggling attack based on large blocks of decimal encoding. Attackers often use decimal encoding as an obfuscation technique to bypass traditional email security measures. +type: "rule" +severity: "high" +source: | + type.inbound + and any(attachments, + ( + .file_extension in~ ("html", "htm", "shtml", "dhtml", "xhtml") + or ( + .file_extension is null + and .file_type == "unknown" + and .content_type == "application/octet-stream" + ) + or .file_extension in~ $file_extensions_common_archives + or .file_type == "html" + or .content_type == "text/html" + ) + and any(file.explode(.), + // suspicious identifiers + any(.scan.strings.strings, + regex.contains(., '(\d{2,3},){60,}') + ) + ) + ) +attack_types: + - "Credential Phishing" + - "Malware/Ransomware" +tactics_and_techniques: + - "Evasion" + - "HTML smuggling" + - "Scripting" +detection_methods: + - "Archive analysis" + - "Content analysis" + - "File analysis" + - "HTML analysis" +id: "f99213c4-7031-50b1-ae81-b45f790d3fa4" diff --git a/detection-rules/attachment_html_smuggling_double_encoded_zip.yml b/detection-rules/attachment_html_smuggling_double_encoded_zip.yml index d1d56ea9890..0d7374033c7 100644 --- a/detection-rules/attachment_html_smuggling_double_encoded_zip.yml +++ b/detection-rules/attachment_html_smuggling_double_encoded_zip.yml @@ -13,13 +13,10 @@ authors: source: | type.inbound and ( - ( - sender.email.domain.root_domain in $free_email_providers - and sender.email.email not in $sender_emails - ) + profile.by_sender().prevalence in ("new", "outlier") or ( - sender.email.domain.root_domain not in $free_email_providers - and sender.email.domain.domain not in $sender_domains + profile.by_sender().any_messages_malicious_or_spam + and not profile.by_sender().any_false_positives ) ) and any(attachments, diff --git a/detection-rules/attachment_html_smuggling_microsoft_signin.yml b/detection-rules/attachment_html_smuggling_microsoft_signin.yml index 5bc76594293..ec988219191 100644 --- a/detection-rules/attachment_html_smuggling_microsoft_signin.yml +++ b/detection-rules/attachment_html_smuggling_microsoft_signin.yml @@ -25,13 +25,10 @@ source: | ) ) and ( - ( - sender.email.domain.root_domain in $free_email_providers - and sender.email.email not in $recipient_emails - ) + not profile.by_sender().solicited or ( - sender.email.domain.root_domain not in $free_email_providers - and sender.email.domain.domain not in $recipient_domains + profile.by_sender().any_messages_malicious_or_spam + and not profile.by_sender().any_false_positives ) ) // allow Microsoft domains just to be safe diff --git a/detection-rules/attachment_html_smuggling_suspicious_onload.yml b/detection-rules/attachment_html_smuggling_suspicious_onload.yml new file mode 100644 index 00000000000..9e007fa74a1 --- /dev/null +++ b/detection-rules/attachment_html_smuggling_suspicious_onload.yml @@ -0,0 +1,39 @@ +name: "Attachment: HTML smuggling 'body onload' with high entropy and suspicious text" +description: | + Potential HTML Smuggling. This rule inspects HTML attachments that contain "body unload", high entropy, and suspicious text. +type: "rule" +severity: "high" +source: | + type.inbound + and any(attachments, + ( + .file_extension in~ ("html", "htm", "shtml", "dhtml", "xhtml") + or ( + .file_extension is null + and .file_type == "unknown" + and .content_type == "application/octet-stream" + ) + or .file_extension in~ $file_extensions_common_archives + or .file_type == "html" + or .content_type == "text/html" + ) + and any(file.explode(.), + .scan.entropy.entropy >= 5 + and any(.scan.strings.strings, strings.ilike(., "*body onload*")) + and any(.scan.strings.strings, regex.icontains(., 'data:image/.*;base64')) + and any(.scan.strings.strings, strings.ilike(., "*document pass*")) + ) + ) +attack_types: + - "Credential Phishing" + - "Malware/Ransomware" +tactics_and_techniques: + - "Evasion" + - "HTML smuggling" + - "Scripting" +detection_methods: + - "Archive analysis" + - "Content analysis" + - "File analysis" + - "HTML analysis" +id: "329ac12d-f74e-577c-936c-1db80ccf860e" diff --git a/detection-rules/attachment_html_smuggling_unescape.yml b/detection-rules/attachment_html_smuggling_unescape.yml index b4ccb82ceb2..7096c7d740b 100644 --- a/detection-rules/attachment_html_smuggling_unescape.yml +++ b/detection-rules/attachment_html_smuggling_unescape.yml @@ -13,7 +13,10 @@ source: | or .file_extension in~ $file_extensions_common_archives or .file_type == "html" ) - and any(file.explode(.), any(.scan.javascript.identifiers, . == "unescape")) + and any(file.explode(.), + any(.scan.javascript.identifiers, . == "unescape") + or any(.scan.strings.strings, regex.contains(., "document.write.{0,10}unescape")) + ) ) attack_types: - "Credential Phishing" diff --git a/detection-rules/attachment_js_file_execution.yml b/detection-rules/attachment_js_file_execution.yml index 642e8a53016..788d141ed21 100644 --- a/detection-rules/attachment_js_file_execution.yml +++ b/detection-rules/attachment_js_file_execution.yml @@ -15,15 +15,11 @@ source: | ) ) ) - // first-time sender and ( - ( - sender.email.domain.root_domain in $free_email_providers - and sender.email.email not in $sender_emails - ) + profile.by_sender().prevalence in ("new", "outlier") or ( - sender.email.domain.root_domain not in $free_email_providers - and sender.email.domain.domain not in $sender_domains + profile.by_sender().any_messages_malicious_or_spam + and not profile.by_sender().any_false_positives ) ) tags: diff --git a/detection-rules/attachment_malwarebazaar.yml b/detection-rules/attachment_malwarebazaar.yml index 96091611291..b8b6025bcd1 100644 --- a/detection-rules/attachment_malwarebazaar.yml +++ b/detection-rules/attachment_malwarebazaar.yml @@ -6,13 +6,10 @@ source: | type.inbound and any(attachments, .sha256 in $abuse_ch_malwarebazaar_sha256_trusted_reporters) and ( - ( - sender.email.domain.root_domain in $free_email_providers - and sender.email.email not in $sender_emails - ) + profile.by_sender().prevalence in ("new", "outlier") or ( - sender.email.domain.root_domain not in $free_email_providers - and sender.email.domain.domain not in $sender_domains + profile.by_sender().any_messages_malicious_or_spam + and not profile.by_sender().any_false_positives ) ) tags: diff --git a/detection-rules/attachment_mht_embedded_vbscript.yml b/detection-rules/attachment_mht_embedded_vbscript.yml index dd75945472b..7820e2b3caa 100644 --- a/detection-rules/attachment_mht_embedded_vbscript.yml +++ b/detection-rules/attachment_mht_embedded_vbscript.yml @@ -14,16 +14,11 @@ source: | and any(file.explode(.), .file_extension =~ "mht") and any(file.explode(.), any(.scan.html.scripts, .language == "VBScript")) ) - - // unsolicited and ( - ( - sender.email.domain.root_domain in $free_email_providers - and sender.email.email not in $recipient_emails - ) + not profile.by_sender().solicited or ( - sender.email.domain.root_domain not in $free_email_providers - and sender.email.domain.domain not in $recipient_domains + profile.by_sender().any_messages_malicious_or_spam + and not profile.by_sender().any_false_positives ) ) attack_types: diff --git a/detection-rules/attachment_microsoft_image_lure_qr_code.yml b/detection-rules/attachment_microsoft_image_lure_qr_code.yml index 893ce305af0..f130fcdcaaa 100644 --- a/detection-rules/attachment_microsoft_image_lure_qr_code.yml +++ b/detection-rules/attachment_microsoft_image_lure_qr_code.yml @@ -7,24 +7,50 @@ source: | type.inbound and ( any(attachments, - .file_type in $file_types_images + (.file_type in $file_types_images or .file_type == "pdf") and any(ml.logo_detect(.).brands, strings.starts_with(.name, "Microsoft")) ) or any(ml.logo_detect(beta.message_screenshot()).brands, strings.starts_with(.name, "Microsoft")) + or (any(attachments, .file_type in~ $file_extensions_macros)) ) and any(attachments, - .file_type in $file_types_images + ( + .file_type in $file_types_images + or .file_type == "pdf" + or .file_type in $file_extensions_macros + ) and ( any(file.explode(.), regex.icontains(.scan.ocr.raw, 'scan|camera') and regex.icontains(.scan.ocr.raw, '\bQR\b|Q\.R\.|barcode') ) - ) - or ( - any(file.explode(.), - .scan.qr.type == "url" - // recipient email address is present in the URL, a common tactic used in credential phishing attacks - and any(recipients.to, strings.icontains(..scan.qr.data, .email.email)) + or ( + any(file.explode(.), + .scan.qr.type == "url" + // recipient email address is present in the URL, a common tactic used in credential phishing attacks + and any(recipients.to, + strings.icontains(..scan.qr.data, .email.email) + + // the recipients sld is in the senders display name + or any(recipients.to, + strings.icontains(sender.display_name, .email.domain.sld) + ) + + // the recipient local is in the body + or any(recipients.to, + strings.icontains(body.current_thread.text, .email.local_part) + ) + + // or the body is null + or body.current_thread.text is null + or body.current_thread.text == "" + + // or the subject contains authentication/urgency verbiage + or regex.contains(subject.subject, + "(Authenticat(e|or|ion)|2fa|Multi.Factor|(qr|bar).code|action.require|alert|Att(n|ention):)" + ) + ) + ) ) ) ) @@ -35,21 +61,19 @@ source: | and sender.email.domain.domain == "microsoft.com" ) ) - // unsolicited and ( - ( - sender.email.domain.root_domain in $free_email_providers - and sender.email.email not in $recipient_emails - ) + not profile.by_sender().solicited or ( - sender.email.domain.root_domain not in $free_email_providers - and sender.email.domain.domain not in $recipient_domains + profile.by_sender().any_messages_malicious_or_spam + and not profile.by_sender().any_false_positives ) ) + attack_types: - "Credential Phishing" tactics_and_techniques: - "Impersonation: Brand" + - "PDF" - "QR code" - "Social engineering" detection_methods: diff --git a/detection-rules/attachment_office365_image.yml b/detection-rules/attachment_office365_image.yml index 012788a6b7a..9622f79a11f 100644 --- a/detection-rules/attachment_office365_image.yml +++ b/detection-rules/attachment_office365_image.yml @@ -54,15 +54,11 @@ source: | and sender.email.domain.domain in ("microsoft.com", "sharepointonline.com") ) ) - // unsolicited and ( - ( - sender.email.domain.root_domain in $free_email_providers - and sender.email.email not in $recipient_emails - ) + not profile.by_sender().solicited or ( - sender.email.domain.root_domain not in $free_email_providers - and sender.email.domain.domain not in $recipient_domains + profile.by_sender().any_messages_malicious_or_spam + and not profile.by_sender().any_false_positives ) ) attack_types: diff --git a/detection-rules/attachment_office_file_relationship_cred_theft.yml b/detection-rules/attachment_office_file_relationship_cred_theft.yml index bf5dd44065f..f7735b69322 100644 --- a/detection-rules/attachment_office_file_relationship_cred_theft.yml +++ b/detection-rules/attachment_office_file_relationship_cred_theft.yml @@ -23,13 +23,10 @@ source: | ) ) and ( - ( - sender.email.domain.root_domain in $free_email_providers - and sender.email.email not in $sender_emails - ) + profile.by_sender().prevalence in ("new", "outlier") or ( - sender.email.domain.root_domain not in $free_email_providers - and sender.email.domain.domain not in $sender_domains + profile.by_sender().any_messages_malicious_or_spam + and not profile.by_sender().any_false_positives ) ) attack_types: diff --git a/detection-rules/attachment_pdf_link_to_dmg.yml b/detection-rules/attachment_pdf_link_to_dmg.yml index da3da87d685..81874a50ef1 100644 --- a/detection-rules/attachment_pdf_link_to_dmg.yml +++ b/detection-rules/attachment_pdf_link_to_dmg.yml @@ -39,17 +39,11 @@ source: | ) ) ) - - - // first time sender and ( - ( - sender.email.domain.root_domain in $free_email_providers - and sender.email.email not in $sender_emails - ) + profile.by_sender().prevalence in ("new", "outlier") or ( - sender.email.domain.root_domain not in $free_email_providers - and sender.email.domain.domain not in $sender_domains + profile.by_sender().any_messages_malicious_or_spam + and not profile.by_sender().any_false_positives ) ) tags: diff --git a/detection-rules/attachment_pdf_linking_to_password_protected_file.yml b/detection-rules/attachment_pdf_linking_to_password_protected_file.yml index ee11e2e24b8..14cc93e7b84 100644 --- a/detection-rules/attachment_pdf_linking_to_password_protected_file.yml +++ b/detection-rules/attachment_pdf_linking_to_password_protected_file.yml @@ -19,13 +19,10 @@ source: | ) ) and ( - ( - sender.email.domain.root_domain in $free_email_providers - and sender.email.email not in $sender_emails - ) + profile.by_sender().prevalence in ("new", "outlier") or ( - sender.email.domain.root_domain not in $free_email_providers - and sender.email.domain.domain not in $sender_domains + profile.by_sender().any_messages_malicious_or_spam + and not profile.by_sender().any_false_positives ) ) attack_types: diff --git a/detection-rules/attachment_pdf_with_google_ae_redirect.yml b/detection-rules/attachment_pdf_with_google_ae_redirect.yml index a002b8b967d..c0a09fcdff2 100644 --- a/detection-rules/attachment_pdf_with_google_ae_redirect.yml +++ b/detection-rules/attachment_pdf_with_google_ae_redirect.yml @@ -1,5 +1,5 @@ -name: "PDF attachment with Google (AE) redirecting to a php file" -description: "Detects a PDF attachment with a link that contains a Google.ae redirect URL" +name: "PDF attachment with Google (AE) redirecting to a php or zip file" +description: "Detects a PDF attachment with a link that contains a Google.ae redirect URL." references: - "https://twitter.com/Cryptolaemus1/status/1649200761610571776?s=20" - "https://analyzer.sublime.security?id=142822c9-8195-47bd-96e3-b8a26267c03c" @@ -13,8 +13,11 @@ source: | any(.scan.pdf.urls, // url encoded q=http strings.starts_with(.query_params, "q=%68%74%74%70") - // url encoded .php - and strings.contains(.query_params, ".%70%68%70") + // url encoded .php or .zip + and ( + strings.contains(.query_params, ".%70%68%70") + or strings.contains(.query_params, "%2e%7a%69%70") + ) and .domain.root_domain == "google.ae" ) ) diff --git a/detection-rules/attachment_pdf_with_low_reputation_link_to_suspicious_files.yml b/detection-rules/attachment_pdf_with_low_reputation_link_to_suspicious_files.yml index c89d21b1247..1b322cbc3a6 100644 --- a/detection-rules/attachment_pdf_with_low_reputation_link_to_suspicious_files.yml +++ b/detection-rules/attachment_pdf_with_low_reputation_link_to_suspicious_files.yml @@ -17,15 +17,11 @@ source: | ) ) ) - // unsolicited and ( - ( - sender.email.domain.root_domain in $free_email_providers - and sender.email.email not in $recipient_emails - ) + not profile.by_sender().solicited or ( - sender.email.domain.root_domain not in $free_email_providers - and sender.email.domain.domain not in $recipient_domains + profile.by_sender().any_messages_malicious_or_spam + and not profile.by_sender().any_false_positives ) ) tags: diff --git a/detection-rules/attachment_pdf_with_low_reputation_link_to_zip_file.yml b/detection-rules/attachment_pdf_with_low_reputation_link_to_zip_file.yml index b198d9f3d6b..d7e2cc43fe0 100644 --- a/detection-rules/attachment_pdf_with_low_reputation_link_to_zip_file.yml +++ b/detection-rules/attachment_pdf_with_low_reputation_link_to_zip_file.yml @@ -18,15 +18,11 @@ source: | ) ) ) - // unsolicited and ( - ( - sender.email.domain.root_domain in $free_email_providers - and sender.email.email not in $recipient_emails - ) + not profile.by_sender().solicited or ( - sender.email.domain.root_domain not in $free_email_providers - and sender.email.domain.domain not in $recipient_domains + profile.by_sender().any_messages_malicious_or_spam + and not profile.by_sender().any_false_positives ) ) tags: diff --git a/detection-rules/attachment_qr_code_suspicious_components.yml b/detection-rules/attachment_qr_code_suspicious_components.yml new file mode 100644 index 00000000000..c081611dfd6 --- /dev/null +++ b/detection-rules/attachment_qr_code_suspicious_components.yml @@ -0,0 +1,81 @@ +name: "Attachment: QR code with credential phishing indicators" +description: | + Detects messages with between 1-3 attachments containing a QR code with suspicious credential theft indicators, such as: LinkAnalysis credential phishing conclusion, decoded QR code url traverses suspicious infrastructure, the final destination is in URLhaus, decoded URL downloads a zip or executable, leverages URL shorteners, known QR abused openredirects, and more. +type: "rule" +severity: "high" +source: | + type.inbound + and 1 <= length(attachments) < 3 + + // Inspects image attachments for QR codes + and any(attachments, + .file_type in $file_types_images + and ( + any(file.explode(.), + .scan.qr.type == "url" + and ( + // pass the QR URL to LinkAnalysis + any([beta.linkanalysis(.scan.qr.url)], + .credphish.disposition == "phishing" + + // any routing traverses via $suspicious_tld list + or any(.redirect_history, .domain.tld in $suspicious_tlds) + + // effective destination in $suspicious_tld list + or .effective_url.domain.tld in $suspicious_tlds + + // or the effective destination domain is in $abuse_ch_urlhaus_domains_trusted_reporters + or .effective_url.domain.root_domain in $abuse_ch_urlhaus_domains_trusted_reporters + + // or any files downloaded are zips or executables + or any(.files_downloaded, + .file_extension in $file_extensions_common_archives + or .file_extension in $file_extensions_executables + ) + ) + or ( + + // or the QR code's root domain is a url_shortener + .scan.qr.url.domain.root_domain in $url_shorteners + + // exclude google maps + and not strings.starts_with(.scan.qr.url.url, 'https://goo.gl/maps') + ) + + // the QR code url is a bing open redirect + or .scan.qr.url.domain.root_domain == 'bing.com' and .scan.qr.url.path =~ '/ck/a' + or ( + + // usap-dc open redirect + .scan.qr.url.domain.root_domain == "usap-dc.org" + and .scan.qr.url.path =~ "/tracker" + and strings.starts_with(.scan.qr.url.query_params, "type=dataset&url=http") + ) + ) + ) + ) + ) + and ( + ( + sender.email.domain.root_domain in $free_email_providers + and sender.email.email not in $sender_emails + ) + or ( + sender.email.domain.root_domain not in $free_email_providers + and sender.email.domain.domain not in $sender_domains + ) + ) +attack_types: + - "Credential Phishing" +tactics_and_techniques: + - "QR code" + - "Social engineering" +detection_methods: + - "Computer Vision" + - "Header analysis" + - "Natural Language Understanding" + - "QR code analysis" + - "Sender analysis" + - "URL analysis" + - "URL screenshot" +id: "9f1681e1-8c15-5edd-9aaa-eb5af1729322" diff --git a/detection-rules/attachment_soliciting_enable_macros.yml b/detection-rules/attachment_soliciting_enable_macros.yml index 3ba77138bc1..c502919588b 100644 --- a/detection-rules/attachment_soliciting_enable_macros.yml +++ b/detection-rules/attachment_soliciting_enable_macros.yml @@ -19,13 +19,10 @@ source: | ) ) and ( - ( - sender.email.domain.root_domain in $free_email_providers - and sender.email.email not in $recipient_emails - ) + not profile.by_sender().solicited or ( - sender.email.domain.root_domain not in $free_email_providers - and sender.email.domain.domain not in $recipient_domains + profile.by_sender().any_messages_malicious_or_spam + and not profile.by_sender().any_false_positives ) ) attack_types: diff --git a/detection-rules/attachment_suspicious_vba_macro_first_time_sender.yml b/detection-rules/attachment_suspicious_vba_macro_first_time_sender.yml index c76d0b80421..5cc38d278ec 100644 --- a/detection-rules/attachment_suspicious_vba_macro_first_time_sender.yml +++ b/detection-rules/attachment_suspicious_vba_macro_first_time_sender.yml @@ -11,13 +11,10 @@ source: | and ml.macro_classifier(.).confidence in ("high") ) and ( - ( - sender.email.domain.root_domain in $free_email_providers - and sender.email.email not in $sender_emails - ) + profile.by_sender().prevalence in ("new", "outlier") or ( - sender.email.domain.root_domain not in $free_email_providers - and sender.email.domain.domain not in $sender_domains + profile.by_sender().any_messages_malicious_or_spam + and not profile.by_sender().any_false_positives ) ) attack_types: diff --git a/detection-rules/attachment_svg_embedded_js.yml b/detection-rules/attachment_svg_embedded_js.yml index 0daca577a33..1bb935303aa 100644 --- a/detection-rules/attachment_svg_embedded_js.yml +++ b/detection-rules/attachment_svg_embedded_js.yml @@ -21,16 +21,11 @@ source: | and any(.scan.strings.strings, strings.icontains(., "CDATA")) ) ) - - // unsolicited and ( - ( - sender.email.domain.root_domain in $free_email_providers - and sender.email.email not in $recipient_emails - ) + not profile.by_sender().solicited or ( - sender.email.domain.root_domain not in $free_email_providers - and sender.email.domain.domain not in $recipient_domains + profile.by_sender().any_messages_malicious_or_spam + and not profile.by_sender().any_false_positives ) ) attack_types: diff --git a/detection-rules/attachment_vba_macro_auto_exec_unsolicited.yml b/detection-rules/attachment_vba_macro_auto_exec_unsolicited.yml index 37e28fd0864..8cc39d8b582 100644 --- a/detection-rules/attachment_vba_macro_auto_exec_unsolicited.yml +++ b/detection-rules/attachment_vba_macro_auto_exec_unsolicited.yml @@ -14,13 +14,10 @@ source: | and any(file.oletools(.).macros.keywords, .type =~ "autoexec") ) and ( - ( - sender.email.domain.root_domain in $free_email_providers - and sender.email.email not in $recipient_emails - ) + not profile.by_sender().solicited or ( - sender.email.domain.root_domain not in $free_email_providers - and sender.email.domain.domain not in $recipient_domains + profile.by_sender().any_messages_malicious_or_spam + and not profile.by_sender().any_false_positives ) ) diff --git a/detection-rules/attachment_vba_macro_auto_open_unsolicited.yml b/detection-rules/attachment_vba_macro_auto_open_unsolicited.yml index 15d1abef2b1..7bbe7543329 100644 --- a/detection-rules/attachment_vba_macro_auto_open_unsolicited.yml +++ b/detection-rules/attachment_vba_macro_auto_open_unsolicited.yml @@ -15,13 +15,10 @@ source: | and any(file.explode(.), any(.scan.vba.auto_exec, . == "AutoOpen")) ) and ( - ( - sender.email.domain.root_domain in $free_email_providers - and sender.email.email not in $recipient_emails - ) + not profile.by_sender().solicited or ( - sender.email.domain.root_domain not in $free_email_providers - and sender.email.domain.domain not in $recipient_domains + profile.by_sender().any_messages_malicious_or_spam + and not profile.by_sender().any_false_positives ) ) attack_types: diff --git a/detection-rules/attachment_vba_macro_employee_impersonation.yml b/detection-rules/attachment_vba_macro_employee_impersonation.yml index 56297c4fc66..ac8d8b2fbba 100644 --- a/detection-rules/attachment_vba_macro_employee_impersonation.yml +++ b/detection-rules/attachment_vba_macro_employee_impersonation.yml @@ -21,13 +21,10 @@ source: | and file.oletools(.).indicators.vba_macros.exists ) and ( - ( - sender.email.domain.root_domain in $free_email_providers - and sender.email.email not in $recipient_emails - ) + not profile.by_sender().solicited or ( - sender.email.domain.root_domain not in $free_email_providers - and sender.email.domain.domain not in $recipient_domains + profile.by_sender().any_messages_malicious_or_spam + and not profile.by_sender().any_false_positives ) ) attack_types: diff --git a/detection-rules/attachment_vba_macro_high_risk.yml b/detection-rules/attachment_vba_macro_high_risk.yml index 87e0802a0d1..8b9ab322c5e 100644 --- a/detection-rules/attachment_vba_macro_high_risk.yml +++ b/detection-rules/attachment_vba_macro_high_risk.yml @@ -12,13 +12,10 @@ source: | and file.oletools(.).indicators.vba_macros.risk == "high" ) and ( - ( - sender.email.domain.root_domain in $free_email_providers - and sender.email.email not in $recipient_emails - ) + not profile.by_sender().solicited or ( - sender.email.domain.root_domain not in $free_email_providers - and sender.email.domain.domain not in $recipient_domains + profile.by_sender().any_messages_malicious_or_spam + and not profile.by_sender().any_false_positives ) ) attack_types: diff --git a/detection-rules/attachment_with_encrypted_zip_unsolicited.yml b/detection-rules/attachment_with_encrypted_zip_unsolicited.yml index 02c3d167ed8..e21351fe9b1 100644 --- a/detection-rules/attachment_with_encrypted_zip_unsolicited.yml +++ b/detection-rules/attachment_with_encrypted_zip_unsolicited.yml @@ -12,13 +12,10 @@ source: | and any(file.explode(.), any(.flavors.yara, . == 'encrypted_zip')) ) and ( - ( - sender.email.domain.root_domain in $free_email_providers - and sender.email.email not in $recipient_emails - ) + not profile.by_sender().solicited or ( - sender.email.domain.root_domain not in $free_email_providers - and sender.email.domain.domain not in $recipient_domains + profile.by_sender().any_messages_malicious_or_spam + and not profile.by_sender().any_false_positives ) ) attack_types: diff --git a/detection-rules/attachment_with_suspicious_author_unsolicited.yml b/detection-rules/attachment_with_suspicious_author_unsolicited.yml index b1a0aefa868..29e1e71901e 100644 --- a/detection-rules/attachment_with_suspicious_author_unsolicited.yml +++ b/detection-rules/attachment_with_suspicious_author_unsolicited.yml @@ -13,13 +13,10 @@ source: | and any(file.explode(.), strings.ilike(.scan.docx.author, "root")) ) and ( - ( - sender.email.domain.root_domain in $free_email_providers - and sender.email.email not in $recipient_emails - ) + not profile.by_sender().solicited or ( - sender.email.domain.root_domain not in $free_email_providers - and sender.email.domain.domain not in $recipient_domains + profile.by_sender().any_messages_malicious_or_spam + and not profile.by_sender().any_false_positives ) ) attack_types: diff --git a/detection-rules/attachment_with_unknown_encrypted_zip_unsolicited.yml b/detection-rules/attachment_with_unknown_encrypted_zip_unsolicited.yml index ea490e8480e..badc0f2862d 100644 --- a/detection-rules/attachment_with_unknown_encrypted_zip_unsolicited.yml +++ b/detection-rules/attachment_with_unknown_encrypted_zip_unsolicited.yml @@ -16,13 +16,10 @@ source: | ) ) and ( - ( - sender.email.domain.root_domain in $free_email_providers - and sender.email.email not in $recipient_emails - ) + not profile.by_sender().solicited or ( - sender.email.domain.root_domain not in $free_email_providers - and sender.email.domain.domain not in $recipient_domains + profile.by_sender().any_messages_malicious_or_spam + and not profile.by_sender().any_false_positives ) ) attack_types: diff --git a/detection-rules/body_business_email_compromise_new_sender.yml b/detection-rules/body_business_email_compromise_new_sender.yml index 1c509c258c0..ffec5179bee 100644 --- a/detection-rules/body_business_email_compromise_new_sender.yml +++ b/detection-rules/body_business_email_compromise_new_sender.yml @@ -10,21 +10,22 @@ source: | ) // negating legit replies and not ( - strings.istarts_with(subject.subject, "RE:") + ( + strings.istarts_with(subject.subject, "RE:") + // out of office auto-reply + // the NLU model will handle these better natively soon + or strings.istarts_with(subject.subject, "Automatic reply:") + ) and ( length(headers.references) > 0 or any(headers.hops, any(.fields, strings.ilike(.name, "In-Reply-To"))) ) ) - // first-time sender and ( - ( - sender.email.domain.root_domain in $free_email_providers - and sender.email.email not in $sender_emails - ) + profile.by_sender().prevalence in ("new", "outlier") or ( - sender.email.domain.root_domain not in $free_email_providers - and sender.email.domain.domain not in $sender_domains + profile.by_sender().any_messages_malicious_or_spam + and not profile.by_sender().any_false_positives ) ) attack_types: diff --git a/detection-rules/body_business_email_compromise_unsolicited.yml b/detection-rules/body_business_email_compromise_unsolicited.yml index f47916f189f..2eb2383c0c6 100644 --- a/detection-rules/body_business_email_compromise_unsolicited.yml +++ b/detection-rules/body_business_email_compromise_unsolicited.yml @@ -27,18 +27,29 @@ source: | ) ), ) - - // unsolicited + + // negate "via" senders via dmarc authentication or gmail autoforwards and ( - ( - sender.email.domain.root_domain in $free_email_providers - and sender.email.email not in $recipient_emails + not ( + any(distinct(headers.hops, .authentication_results.dmarc is not null), + strings.ilike(.authentication_results.dmarc, "pass") + or ( + not any([headers.return_path.email], + strings.ilike(headers.return_path.local_part, "*+caf_=*") + ) + and strings.contains(sender.display_name, "via") + ) + ) ) + ) + and ( + not profile.by_sender().solicited or ( - sender.email.domain.root_domain not in $free_email_providers - and sender.email.domain.domain not in $recipient_domains + profile.by_sender().any_messages_malicious_or_spam + and not profile.by_sender().any_false_positives ) ) + attack_types: - "BEC/Fraud" tactics_and_techniques: diff --git a/detection-rules/body_callback_phishing_no_attachment.yml b/detection-rules/body_callback_phishing_no_attachment.yml index b946d070b17..b4a1caf7d3d 100644 --- a/detection-rules/body_callback_phishing_no_attachment.yml +++ b/detection-rules/body_callback_phishing_no_attachment.yml @@ -9,13 +9,10 @@ source: | type.inbound and length(attachments) == 0 and ( - ( - sender.email.domain.root_domain in $free_email_providers - and sender.email.email not in $recipient_emails - ) + not profile.by_sender().solicited or ( - sender.email.domain.root_domain not in $free_email_providers - and sender.email.domain.domain not in $recipient_domains + profile.by_sender().any_messages_malicious_or_spam + and not profile.by_sender().any_false_positives ) ) and sender.email.domain.root_domain in $free_email_providers diff --git a/detection-rules/body_job_scam_new_sender.yml b/detection-rules/body_job_scam_new_sender.yml index e8f38c799a2..9d002d17203 100644 --- a/detection-rules/body_job_scam_new_sender.yml +++ b/detection-rules/body_job_scam_new_sender.yml @@ -11,13 +11,10 @@ source: | and any(ml.nlu_classifier(body.current_thread.text).entities, .name == "financial") ) and ( - ( - sender.email.domain.root_domain in $free_email_providers - and sender.email.email not in $sender_emails - ) + profile.by_sender().prevalence in ("new", "outlier") or ( - sender.email.domain.root_domain not in $free_email_providers - and sender.email.domain.domain not in $sender_domains + profile.by_sender().any_messages_malicious_or_spam + and not profile.by_sender().any_false_positives ) ) attack_types: diff --git a/detection-rules/callback_phishing_nlu_body_or_attachments.yml b/detection-rules/callback_phishing_nlu_body_or_attachments.yml index 2eaa5c00728..b5b1f1a0c7f 100644 --- a/detection-rules/callback_phishing_nlu_body_or_attachments.yml +++ b/detection-rules/callback_phishing_nlu_body_or_attachments.yml @@ -25,13 +25,10 @@ source: | and strings.icontains(body.html.raw, "bigcommerce.com") ) and ( - ( - sender.email.domain.root_domain in $free_email_providers - and sender.email.email not in $sender_emails - ) + profile.by_sender().prevalence in ("new", "outlier") or ( - sender.email.domain.root_domain not in $free_email_providers - and sender.email.domain.domain not in $sender_domains + profile.by_sender().any_messages_malicious_or_spam + and not profile.by_sender().any_false_positives ) ) attack_types: diff --git a/detection-rules/file_sharing_link_from_suspicious_sender_domain.yml b/detection-rules/file_sharing_link_from_suspicious_sender_domain.yml index 025a1355b86..09b81756466 100644 --- a/detection-rules/file_sharing_link_from_suspicious_sender_domain.yml +++ b/detection-rules/file_sharing_link_from_suspicious_sender_domain.yml @@ -8,13 +8,10 @@ source: | and any(body.links, .href_url.domain.domain in $free_file_hosts) and sender.email.domain.tld in $suspicious_tlds and ( - ( - sender.email.domain.root_domain in $free_email_providers - and sender.email.email not in $recipient_emails - ) + not profile.by_sender().solicited or ( - sender.email.domain.root_domain not in $free_email_providers - and sender.email.domain.domain not in $recipient_domains + profile.by_sender().any_messages_malicious_or_spam + and not profile.by_sender().any_false_positives ) ) attack_types: diff --git a/detection-rules/file_sharing_link_suspicious_subject.yml b/detection-rules/file_sharing_link_suspicious_subject.yml index 88d8b23f04c..09ed51da703 100644 --- a/detection-rules/file_sharing_link_suspicious_subject.yml +++ b/detection-rules/file_sharing_link_suspicious_subject.yml @@ -18,13 +18,10 @@ source: | and regex.icontains(subject.subject, 'immediately', 'urgent') and any(ml.nlu_classifier(body.current_thread.text).intents, .name != "benign") and ( - ( - sender.email.domain.root_domain in $free_email_providers - and sender.email.email not in $recipient_emails - ) + not profile.by_sender().solicited or ( - sender.email.domain.root_domain not in $free_email_providers - and sender.email.domain.domain not in $recipient_domains + profile.by_sender().any_messages_malicious_or_spam + and not profile.by_sender().any_false_positives ) ) attack_types: diff --git a/detection-rules/headers_bec_masked_recipients_no_links_freemail_replyto.yml b/detection-rules/headers_bec_masked_recipients_no_links_freemail_replyto.yml index f255d1269da..4970785d8d3 100644 --- a/detection-rules/headers_bec_masked_recipients_no_links_freemail_replyto.yml +++ b/detection-rules/headers_bec_masked_recipients_no_links_freemail_replyto.yml @@ -16,13 +16,10 @@ source: | and not .email.domain.domain == sender.email.domain.domain ) and ( - ( - sender.email.domain.root_domain in $free_email_providers - and sender.email.email not in $recipient_emails - ) + not profile.by_sender().solicited or ( - sender.email.domain.root_domain not in $free_email_providers - and sender.email.domain.domain not in $recipient_domains + profile.by_sender().any_messages_malicious_or_spam + and not profile.by_sender().any_false_positives ) ) attack_types: diff --git a/detection-rules/headers_replyto_new_domain_nlu_request.yml b/detection-rules/headers_replyto_new_domain_nlu_request.yml index ca6fcd540c8..c26b16bc096 100644 --- a/detection-rules/headers_replyto_new_domain_nlu_request.yml +++ b/detection-rules/headers_replyto_new_domain_nlu_request.yml @@ -24,16 +24,11 @@ source: | .name is not null and .confidence in ("medium", "high") ) ) - - // first-time sender and ( - ( - sender.email.domain.root_domain in $free_email_providers - and sender.email.email not in $sender_emails - ) + profile.by_sender().prevalence in ("new", "outlier") or ( - sender.email.domain.root_domain not in $free_email_providers - and sender.email.domain.domain not in $sender_domains + profile.by_sender().any_messages_malicious_or_spam + and not profile.by_sender().any_false_positives ) ) attack_types: diff --git a/detection-rules/headers_russia_return_path.yml b/detection-rules/headers_russia_return_path.yml index a1aa279d27f..2daabd83ce5 100644 --- a/detection-rules/headers_russia_return_path.yml +++ b/detection-rules/headers_russia_return_path.yml @@ -8,13 +8,10 @@ source: | and headers.return_path.domain.tld == "ru" and sender.email.email not in $recipient_emails and ( - ( - sender.email.domain.root_domain in $free_email_providers - and sender.email.email not in $sender_emails - ) + profile.by_sender().prevalence in ("new", "outlier") or ( - sender.email.domain.root_domain not in $free_email_providers - and sender.email.domain.domain not in $sender_domains + profile.by_sender().any_messages_malicious_or_spam + and not profile.by_sender().any_false_positives ) ) attack_types: diff --git a/detection-rules/impersonation_amazon_suspicious_text.yml b/detection-rules/impersonation_amazon_suspicious_text.yml index 018882fa9dc..e2c7744ad7e 100644 --- a/detection-rules/impersonation_amazon_suspicious_text.yml +++ b/detection-rules/impersonation_amazon_suspicious_text.yml @@ -33,15 +33,11 @@ source: | ) ) ) - // unsolicited and ( - ( - sender.email.domain.root_domain in $free_email_providers - and sender.email.email not in $recipient_emails - ) + not profile.by_sender().solicited or ( - sender.email.domain.root_domain not in $free_email_providers - and sender.email.domain.domain not in $recipient_domains + profile.by_sender().any_messages_malicious_or_spam + and not profile.by_sender().any_false_positives ) ) and sender.email.domain.root_domain not in~ ( diff --git a/detection-rules/impersonation_barracuda.yml b/detection-rules/impersonation_barracuda.yml index ac9b348cb8c..76987ffe608 100644 --- a/detection-rules/impersonation_barracuda.yml +++ b/detection-rules/impersonation_barracuda.yml @@ -20,16 +20,12 @@ source: | 'sharkssports.net', 'sjbarracuda.com' ) - // first-time sender and ( - ( - sender.email.domain.root_domain in $free_email_providers - and sender.email.email not in $sender_emails - ) - or ( - sender.email.domain.root_domain not in $free_email_providers - and sender.email.domain.domain not in $sender_domains - ) + profile.by_sender().prevalence in ("new", "outlier") + or ( + profile.by_sender().any_messages_malicious_or_spam + and not profile.by_sender().any_false_positives + ) ) attack_types: - "Credential Phishing" diff --git a/detection-rules/impersonation_chase.yml b/detection-rules/impersonation_chase.yml index 40990223d26..15a8108ef0b 100644 --- a/detection-rules/impersonation_chase.yml +++ b/detection-rules/impersonation_chase.yml @@ -24,14 +24,11 @@ source: | and sender.display_name not in~ ("chaser", "case") and sender.email.domain.root_domain not in~ ('chase.com', 'united.com', 'transunion.com', 'shopping-chase.com') and ( - ( - sender.email.domain.root_domain in $free_email_providers - and sender.email.email not in $sender_emails - ) - or ( - sender.email.domain.root_domain not in $free_email_providers - and sender.email.domain.domain not in $sender_domains - ) + profile.by_sender().prevalence in ("new", "outlier") + or ( + profile.by_sender().any_messages_malicious_or_spam + and not profile.by_sender().any_false_positives + ) ) attack_types: - "Credential Phishing" diff --git a/detection-rules/impersonation_dhl.yml b/detection-rules/impersonation_dhl.yml index 3fee425bae3..99d9d08539b 100644 --- a/detection-rules/impersonation_dhl.yml +++ b/detection-rules/impersonation_dhl.yml @@ -24,15 +24,11 @@ source: | 'dhl.de', 'dhl.fr' ) - // first-time sender and ( - ( - sender.email.domain.root_domain in $free_email_providers - and sender.email.email not in $sender_emails - ) + profile.by_sender().prevalence in ("new", "outlier") or ( - sender.email.domain.root_domain not in $free_email_providers - and sender.email.domain.domain not in $sender_domains + profile.by_sender().any_messages_malicious_or_spam + and not profile.by_sender().any_false_positives ) ) attack_types: diff --git a/detection-rules/impersonation_docusign.yml b/detection-rules/impersonation_docusign.yml index 07d58391c7a..cfb1539a93b 100644 --- a/detection-rules/impersonation_docusign.yml +++ b/detection-rules/impersonation_docusign.yml @@ -51,15 +51,11 @@ source: | ) and strings.contains(sender.display_name, "via") ) - // unsolicited and ( - ( - sender.email.domain.root_domain in $free_email_providers - and sender.email.email not in $recipient_emails - ) + not profile.by_sender().solicited or ( - sender.email.domain.root_domain not in $free_email_providers - and sender.email.domain.domain not in $recipient_domains + profile.by_sender().any_messages_malicious_or_spam + and not profile.by_sender().any_false_positives ) ) attack_types: diff --git a/detection-rules/impersonation_employee_payroll_fraud.yml b/detection-rules/impersonation_employee_payroll_fraud.yml index 253133f8f10..108b809ed80 100644 --- a/detection-rules/impersonation_employee_payroll_fraud.yml +++ b/detection-rules/impersonation_employee_payroll_fraud.yml @@ -25,13 +25,10 @@ source: | ) ) and ( - ( - sender.email.domain.root_domain in $free_email_providers - and sender.email.email not in $recipient_emails - ) + not profile.by_sender().solicited or ( - sender.email.domain.root_domain not in $free_email_providers - and sender.email.domain.domain not in $recipient_domains + profile.by_sender().any_messages_malicious_or_spam + and not profile.by_sender().any_false_positives ) ) attack_types: diff --git a/detection-rules/impersonation_employee_subject.yml b/detection-rules/impersonation_employee_subject.yml index 1897f23e05d..7704a421d80 100644 --- a/detection-rules/impersonation_employee_subject.yml +++ b/detection-rules/impersonation_employee_subject.yml @@ -15,15 +15,11 @@ source: | any(ml.nlu_classifier(.).intents, .name == "bec" and .confidence in ("medium", "high")) ) - // unsolicited and ( - ( - sender.email.domain.root_domain in $free_email_providers - and sender.email.email not in $recipient_emails - ) + not profile.by_sender().solicited or ( - sender.email.domain.root_domain not in $free_email_providers - and sender.email.domain.domain not in $recipient_domains + profile.by_sender().any_messages_malicious_or_spam + and not profile.by_sender().any_false_positives ) ) attack_types: diff --git a/detection-rules/impersonation_employee_urgent_request.yml b/detection-rules/impersonation_employee_urgent_request.yml index 3f6978174c4..e8d2abda54a 100644 --- a/detection-rules/impersonation_employee_urgent_request.yml +++ b/detection-rules/impersonation_employee_urgent_request.yml @@ -23,16 +23,11 @@ source: | and not strings.istarts_with(subject.subject, "fwd:") ) ) - - // first-time sender and ( - ( - sender.email.domain.root_domain in $free_email_providers - and sender.email.email not in $sender_emails - ) + profile.by_sender().prevalence in ("new", "outlier") or ( - sender.email.domain.root_domain not in $free_email_providers - and sender.email.domain.domain not in $sender_domains + profile.by_sender().any_messages_malicious_or_spam + and not profile.by_sender().any_false_positives ) ) attack_types: diff --git a/detection-rules/impersonation_fake_msg_thread_mismatched_from_freemail_replyto.yml b/detection-rules/impersonation_fake_msg_thread_mismatched_from_freemail_replyto.yml index 126d35c2cd8..ec61e357ec8 100644 --- a/detection-rules/impersonation_fake_msg_thread_mismatched_from_freemail_replyto.yml +++ b/detection-rules/impersonation_fake_msg_thread_mismatched_from_freemail_replyto.yml @@ -8,16 +8,11 @@ type: "rule" severity: "medium" source: | type.inbound - - // First-time sender and ( - ( - sender.email.domain.root_domain in $free_email_providers - and sender.email.email not in $sender_emails - ) + profile.by_sender().prevalence in ("new", "outlier") or ( - sender.email.domain.root_domain not in $free_email_providers - and sender.email.domain.domain not in $sender_domains + profile.by_sender().any_messages_malicious_or_spam + and not profile.by_sender().any_false_positives ) ) diff --git a/detection-rules/impersonation_finra.yml b/detection-rules/impersonation_finra.yml index 8922f317c38..65c10058643 100644 --- a/detection-rules/impersonation_finra.yml +++ b/detection-rules/impersonation_finra.yml @@ -12,16 +12,11 @@ source: | or strings.ilevenshtein(sender.email.domain.sld, 'finra') <= 1 ) and sender.email.domain.root_domain not in~ ('finra.org', 'finrax.com') - - // unsolicited and ( - ( - sender.email.domain.root_domain in $free_email_providers - and sender.email.email not in $sender_emails - ) + profile.by_sender().prevalence in ("new", "outlier") or ( - sender.email.domain.root_domain not in $free_email_providers - and sender.email.domain.domain not in $sender_domains + profile.by_sender().any_messages_malicious_or_spam + and not profile.by_sender().any_false_positives ) ) attack_types: diff --git a/detection-rules/impersonation_github.yml b/detection-rules/impersonation_github.yml index 8b3b3e79a5f..7606ceab8ff 100644 --- a/detection-rules/impersonation_github.yml +++ b/detection-rules/impersonation_github.yml @@ -29,13 +29,10 @@ source: | 'lithub.com' ) and ( - ( - sender.email.domain.root_domain in $free_email_providers - and sender.email.email not in $recipient_emails - ) + not profile.by_sender().solicited or ( - sender.email.domain.root_domain not in $free_email_providers - and sender.email.domain.domain not in $recipient_domains + profile.by_sender().any_messages_malicious_or_spam + and not profile.by_sender().any_false_positives ) ) attack_types: diff --git a/detection-rules/impersonation_human_resources.yml b/detection-rules/impersonation_human_resources.yml index 96c9e0d6bdc..00516688e71 100644 --- a/detection-rules/impersonation_human_resources.yml +++ b/detection-rules/impersonation_human_resources.yml @@ -18,13 +18,10 @@ source: | and not length(ml.nlu_classifier(body.current_thread.text).intents) == 0 ) and ( - ( - sender.email.domain.root_domain in $free_email_providers - and sender.email.email not in $sender_emails - ) + profile.by_sender().prevalence in ("new", "outlier") or ( - sender.email.domain.root_domain not in $free_email_providers - and sender.email.domain.domain not in $sender_domains + profile.by_sender().any_messages_malicious_or_spam + and not profile.by_sender().any_false_positives ) ) attack_types: diff --git a/detection-rules/impersonation_microsoft.yml b/detection-rules/impersonation_microsoft.yml index 19f7c44aa24..d67692062f6 100644 --- a/detection-rules/impersonation_microsoft.yml +++ b/detection-rules/impersonation_microsoft.yml @@ -42,16 +42,11 @@ source: | 'office.com', 'teams-events.com' ) - - // first-time sender and ( - ( - sender.email.domain.root_domain in $free_email_providers - and sender.email.email not in $sender_emails - ) + profile.by_sender().prevalence in ("new", "outlier") or ( - sender.email.domain.root_domain not in $free_email_providers - and sender.email.domain.domain not in $sender_domains + profile.by_sender().any_messages_malicious_or_spam + and not profile.by_sender().any_false_positives ) ) diff --git a/detection-rules/impersonation_paypal.yml b/detection-rules/impersonation_paypal.yml index f8c180384a7..dfb3d3f7e8e 100644 --- a/detection-rules/impersonation_paypal.yml +++ b/detection-rules/impersonation_paypal.yml @@ -52,16 +52,11 @@ source: | 'paypal-prepaid.com', 'xoom.com' ) - - // unsolicited and ( - ( - sender.email.domain.root_domain in $free_email_providers - and sender.email.email not in $recipient_emails - ) + not profile.by_sender().solicited or ( - sender.email.domain.root_domain not in $free_email_providers - and sender.email.domain.domain not in $recipient_domains + profile.by_sender().any_messages_malicious_or_spam + and not profile.by_sender().any_false_positives ) ) attack_types: diff --git a/detection-rules/impersonation_recipient_domain.yml b/detection-rules/impersonation_recipient_domain.yml index d02e2a84f81..89a05768ac4 100644 --- a/detection-rules/impersonation_recipient_domain.yml +++ b/detection-rules/impersonation_recipient_domain.yml @@ -32,15 +32,11 @@ source: | and all(recipients.to, .email.email != sender.email.email) - // first-time sender and ( - ( - sender.email.domain.root_domain in $free_email_providers - and sender.email.email not in $sender_emails - ) + profile.by_sender().prevalence in ("new", "outlier") or ( - sender.email.domain.root_domain not in $free_email_providers - and sender.email.domain.domain not in $sender_domains + profile.by_sender().any_messages_malicious_or_spam + and not profile.by_sender().any_false_positives ) ) attack_types: diff --git a/detection-rules/impersonation_recipient_sld_in_sender_local_fts.yml b/detection-rules/impersonation_recipient_sld_in_sender_local_fts.yml index 193fc25d260..53985558905 100644 --- a/detection-rules/impersonation_recipient_sld_in_sender_local_fts.yml +++ b/detection-rules/impersonation_recipient_sld_in_sender_local_fts.yml @@ -27,13 +27,10 @@ source: | ) and sender.email.domain.root_domain not in $org_domains and ( - ( - sender.email.domain.root_domain in $free_email_providers - and sender.email.email not in $sender_emails - ) + profile.by_sender().prevalence in ("new", "outlier") or ( - sender.email.domain.root_domain not in $free_email_providers - and sender.email.domain.domain not in $sender_domains + profile.by_sender().any_messages_malicious_or_spam + and not profile.by_sender().any_false_positives ) ) attack_types: diff --git a/detection-rules/impersonation_ripple.yml b/detection-rules/impersonation_ripple.yml index da3450cfb57..b3ddee751d1 100644 --- a/detection-rules/impersonation_ripple.yml +++ b/detection-rules/impersonation_ripple.yml @@ -11,13 +11,10 @@ source: | and regex.imatch(sender.display_name, '\bripple\b') and sender.email.domain.root_domain not in ("ripple.com", "ripplejobs.co.uk") and ( - ( - sender.email.domain.root_domain in $free_email_providers - and sender.email.email not in $recipient_emails - ) + not profile.by_sender().solicited or ( - sender.email.domain.root_domain not in $free_email_providers - and sender.email.domain.domain not in $recipient_domains + profile.by_sender().any_messages_malicious_or_spam + and not profile.by_sender().any_false_positives ) ) tags: diff --git a/detection-rules/impersonation_spotify.yml b/detection-rules/impersonation_spotify.yml index cfddbc55737..c1fe24ce78d 100644 --- a/detection-rules/impersonation_spotify.yml +++ b/detection-rules/impersonation_spotify.yml @@ -20,15 +20,11 @@ source: | 'anchor.fm' ) and sender.email.domain.domain not in~ ('privaterelay.appleid.com') - // first-time sender and ( - ( - sender.email.domain.root_domain in $free_email_providers - and sender.email.email not in $sender_emails - ) + profile.by_sender().prevalence in ("new", "outlier") or ( - sender.email.domain.root_domain not in $free_email_providers - and sender.email.domain.domain not in $sender_domains + profile.by_sender().any_messages_malicious_or_spam + and not profile.by_sender().any_false_positives ) ) attack_types: diff --git a/detection-rules/impersonation_stellar.yml b/detection-rules/impersonation_stellar.yml index 0a6c3a65b1e..9cea84869ec 100644 --- a/detection-rules/impersonation_stellar.yml +++ b/detection-rules/impersonation_stellar.yml @@ -11,13 +11,10 @@ source: | and regex.imatch(sender.display_name, '\bstellar\b') and sender.email.domain.root_domain != "stellar.org" and ( - ( - sender.email.domain.root_domain in $free_email_providers - and sender.email.email not in $recipient_emails - ) + not profile.by_sender().solicited or ( - sender.email.domain.root_domain not in $free_email_providers - and sender.email.domain.domain not in $recipient_domains + profile.by_sender().any_messages_malicious_or_spam + and not profile.by_sender().any_false_positives ) ) tags: diff --git a/detection-rules/impersonation_sublime_security.yml b/detection-rules/impersonation_sublime_security.yml index 092022258c8..e69db5c1101 100644 --- a/detection-rules/impersonation_sublime_security.yml +++ b/detection-rules/impersonation_sublime_security.yml @@ -12,15 +12,11 @@ source: | or strings.ilevenshtein(sender.email.domain.domain, 'sublimesecurity.com') <= 2 ) and sender.email.domain.domain != 'sublimesecurity.com' - // first-time sender and ( - ( - sender.email.domain.root_domain in $free_email_providers - and sender.email.email not in $sender_emails - ) + profile.by_sender().prevalence in ("new", "outlier") or ( - sender.email.domain.root_domain not in $free_email_providers - and sender.email.domain.domain not in $sender_domains + profile.by_sender().any_messages_malicious_or_spam + and not profile.by_sender().any_false_positives ) ) attack_types: diff --git a/detection-rules/impersonation_vip_urgent_request.yml b/detection-rules/impersonation_vip_urgent_request.yml index a0b24a6fd91..13f1a9ab7a9 100644 --- a/detection-rules/impersonation_vip_urgent_request.yml +++ b/detection-rules/impersonation_vip_urgent_request.yml @@ -15,15 +15,11 @@ source: | and any(ml.nlu_classifier(body.current_thread.text).entities, .name == "request") ) ) - // first-time sender and ( - ( - sender.email.domain.root_domain in $free_email_providers - and sender.email.email not in $sender_emails - ) + profile.by_sender().prevalence in ("new", "outlier") or ( - sender.email.domain.root_domain not in $free_email_providers - and sender.email.domain.domain not in $sender_domains + profile.by_sender().any_messages_malicious_or_spam + and not profile.by_sender().any_false_positives ) ) attack_types: diff --git a/detection-rules/inline_image_as_message.yml b/detection-rules/inline_image_as_message.yml index ce0948fce12..d9cdfc3b964 100644 --- a/detection-rules/inline_image_as_message.yml +++ b/detection-rules/inline_image_as_message.yml @@ -21,13 +21,10 @@ source: | ) and strings.ilike(body.html.raw, "*img*cid*") and ( - ( - sender.email.domain.root_domain in $free_email_providers - and sender.email.email not in $sender_emails - ) + profile.by_sender().prevalence in ("new", "outlier") or ( - sender.email.domain.root_domain not in $free_email_providers - and sender.email.domain.domain not in $sender_domains + profile.by_sender().any_messages_malicious_or_spam + and not profile.by_sender().any_false_positives ) ) attack_types: diff --git a/detection-rules/link_credential_phishing.yml b/detection-rules/link_credential_phishing.yml index 214ae9fda81..08e9ef5f47e 100644 --- a/detection-rules/link_credential_phishing.yml +++ b/detection-rules/link_credential_phishing.yml @@ -9,15 +9,11 @@ source: | beta.linkanalysis(.).credphish.disposition == "phishing" and beta.linkanalysis(.).credphish.confidence in ("medium", "high") ) - // first-time sender and ( - ( - sender.email.domain.root_domain in $free_email_providers - and sender.email.email not in $sender_emails - ) + profile.by_sender().prevalence in ("new", "outlier") or ( - sender.email.domain.root_domain not in $free_email_providers - and sender.email.domain.domain not in $sender_domains + profile.by_sender().any_messages_malicious_or_spam + and not profile.by_sender().any_false_positives ) ) attack_types: diff --git a/detection-rules/link_credential_phishing_intent_and_other_indicators.yml b/detection-rules/link_credential_phishing_intent_and_other_indicators.yml index c564026ff9a..a9ecc3b8de4 100644 --- a/detection-rules/link_credential_phishing_intent_and_other_indicators.yml +++ b/detection-rules/link_credential_phishing_intent_and_other_indicators.yml @@ -296,16 +296,11 @@ source: | // doesn't match any links in the body or all(body.links, .href_url.domain.root_domain != sender.email.domain.root_domain) ) - - // first-time sender and ( - ( - sender.email.domain.root_domain in $free_email_providers - and sender.email.email not in $sender_emails - ) + profile.by_sender().prevalence in ("new", "outlier") or ( - sender.email.domain.root_domain not in $free_email_providers - and sender.email.domain.domain not in $sender_domains + profile.by_sender().any_messages_malicious_or_spam + and not profile.by_sender().any_false_positives ) ) attack_types: diff --git a/detection-rules/link_credential_phishing_secure_message.yml b/detection-rules/link_credential_phishing_secure_message.yml index 4cf9ed06d0b..1960d5ee9e5 100644 --- a/detection-rules/link_credential_phishing_secure_message.yml +++ b/detection-rules/link_credential_phishing_secure_message.yml @@ -8,35 +8,32 @@ source: | and any(ml.nlu_classifier(body.current_thread.text).intents, .name == "cred_theft" and .confidence == "high" ) - + // ----- other suspicious signals here ----- and strings.icontains(body.html.display_text, "secure message") - + // todo: automated display name / human local part // todo: suspicious link (unfurl click trackers) - + // ---------- - + // has at least 1 link and length(body.links) > 0 - + // negate legitimate message senders and ( sender.email.domain.root_domain not in ("protectedtrust.com") and any(body.links, .href_url.domain.root_domain != sender.email.domain.root_domain ) + // Negate known secure mailer(s) + and not all(body.links, .href_url.domain.root_domain in ("mimecast.com")) ) - - // first-time sender and ( - ( - sender.email.domain.root_domain in $free_email_providers - and sender.email.email not in $sender_emails - ) + profile.by_sender().prevalence in ("new", "outlier") or ( - sender.email.domain.root_domain not in $free_email_providers - and sender.email.domain.domain not in $sender_domains + profile.by_sender().any_messages_malicious_or_spam + and not profile.by_sender().any_false_positives ) ) attack_types: diff --git a/detection-rules/link_credential_phishing_suspicious_sender_tld_and_signals.yml b/detection-rules/link_credential_phishing_suspicious_sender_tld_and_signals.yml index f8d7ac3732c..a0019a6fe00 100644 --- a/detection-rules/link_credential_phishing_suspicious_sender_tld_and_signals.yml +++ b/detection-rules/link_credential_phishing_suspicious_sender_tld_and_signals.yml @@ -44,15 +44,11 @@ source: | any(recipients.to, strings.icontains(subject.subject, .email.email)), ) - // unsolicited and ( - ( - sender.email.domain.root_domain in $free_email_providers - and sender.email.email not in $recipient_emails - ) + not profile.by_sender().solicited or ( - sender.email.domain.root_domain not in $free_email_providers - and sender.email.domain.domain not in $recipient_domains + profile.by_sender().any_messages_malicious_or_spam + and not profile.by_sender().any_false_positives ) ) attack_types: diff --git a/detection-rules/link_credential_phishing_voicemail_language.yml b/detection-rules/link_credential_phishing_voicemail_language.yml index 0df96e25fe3..dc215ca3218 100644 --- a/detection-rules/link_credential_phishing_voicemail_language.yml +++ b/detection-rules/link_credential_phishing_voicemail_language.yml @@ -1,47 +1,74 @@ name: "Fake voicemail notification (unsolicited)" description: | This rule detects a common credential phishing vector enticing the user to engage with links under the premise that they have a voicemail to retrieve. - The rule ensures at least a single link is present with either voicemail in the display name, body, subject or a combination of those elements with a medium to high credential theft NLU Intent from an unsolicited sender. + The rule looks for voicemail verbiage in the display name, body, subject or a combination of those elements with emojis or a medium to high credential theft NLU Intent from an unsolicited sender. type: "rule" severity: "medium" source: | type.inbound - and length(body.links) > 0 - + and length(body.links) < 5 // voicemail related and ( - regex.icontains(body.current_thread.text, 'voice\s?(mail|message|recording|call)') - or (regex.icontains(subject.subject, 'voice\s?(mail|message|recording|call)')) + any([subject.subject, sender.display_name, ], + regex.icontains(., '(voice)\s?(mail|message|recording|call)|transcription') + or regex.contains(body.current_thread.text, '(voice)\s?(mail|message|recording|call)') + ) ) - and 2 of ( - ( - any(ml.nlu_classifier(body.current_thread.text).intents, - .name in ("cred_theft") and .confidence in ("medium", "high") + and 2 of ( + ( + any(ml.nlu_classifier(body.current_thread.text).intents, + .name in ("cred_theft") and .confidence in ("medium", "high") + ) + ), + (regex.icontains(sender.display_name, 'voice\s?(mail|message|recording|call|transcription)')), + ( + // sender domain matches no body domains + all(body.links, + .href_url.domain.root_domain != sender.email.domain.root_domain + and .href_url.domain.root_domain not in $org_domains + and .href_url.domain.root_domain not in ( + "unitelvoice.com", + "googleapis.com", + "dialmycalls.com" + ) + ) + ), + ( + // recipient's SLD is in the sender's display name + any(recipients.to, strings.icontains(sender.display_name, .email.domain.sld)) + ), + ( + any([sender.display_name, subject.subject, body.current_thread.text], + regex.contains(., + '[\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}]' + ) + ) + ), + ) + and ( + sender.email.domain.root_domain not in ("magicjack.com", "unitelvoice.com", "voipinterface.net") + or not any(attachments, strings.starts_with(.content_type, "audio")) + ) + + // negating legit replies + and not ( + ( + strings.istarts_with(subject.subject, "RE:") + // out of office auto-reply + // the NLU model will handle these better natively soon + or strings.istarts_with(subject.subject, "Automatic reply:") ) - ), - (regex.icontains(sender.display_name, 'voice\s?(mail|message|recording|call)')), - ( - // sender domain matches no body domains - all(body.links, - .href_url.domain.root_domain != sender.email.domain.root_domain - and .href_url.domain.root_domain not in $org_domains - and .href_url.domain.root_domain not in ("unitelvoice.com", "googleapis.com", "dialmycalls.com") + and ( + length(headers.references) > 0 + or any(headers.hops, any(.fields, strings.ilike(.name, "In-Reply-To"))) ) - ), - ( - // recipient's SLD is in the sender's display name - any(recipients.to, strings.icontains(sender.display_name, .email.domain.sld)) - ), - ) - and sender.email.domain.root_domain not in ("magicjack.com", "unitelvoice.com") - and ( - ( - sender.email.domain.root_domain in $free_email_providers - and sender.email.email not in $recipient_emails ) + + and ( + not profile.by_sender().solicited or ( - sender.email.domain.root_domain not in $free_email_providers - and sender.email.domain.domain not in $recipient_domains + profile.by_sender().any_messages_malicious_or_spam + and not profile.by_sender().any_false_positives ) ) attack_types: diff --git a/detection-rules/link_download_disk_image_in_encrypted_zip.yml b/detection-rules/link_download_disk_image_in_encrypted_zip.yml index 4d4019a331e..264ebacb2bc 100644 --- a/detection-rules/link_download_disk_image_in_encrypted_zip.yml +++ b/detection-rules/link_download_disk_image_in_encrypted_zip.yml @@ -24,15 +24,11 @@ source: | ) ) ) - // first-time sender and ( - ( - sender.email.domain.root_domain in $free_email_providers - and sender.email.email not in $sender_emails - ) + profile.by_sender().prevalence in ("new", "outlier") or ( - sender.email.domain.root_domain not in $free_email_providers - and sender.email.domain.domain not in $sender_domains + profile.by_sender().any_messages_malicious_or_spam + and not profile.by_sender().any_false_positives ) ) tags: diff --git a/detection-rules/link_download_suspicious_file.yml b/detection-rules/link_download_suspicious_file.yml index 969c0ef8cdb..367753b3220 100644 --- a/detection-rules/link_download_suspicious_file.yml +++ b/detection-rules/link_download_suspicious_file.yml @@ -33,15 +33,11 @@ source: | ) ) ) - // unsolicited and ( - ( - sender.email.domain.root_domain in $free_email_providers - and sender.email.email not in $recipient_emails - ) + not profile.by_sender().solicited or ( - sender.email.domain.root_domain not in $free_email_providers - and sender.email.domain.domain not in $recipient_domains + profile.by_sender().any_messages_malicious_or_spam + and not profile.by_sender().any_false_positives ) ) attack_types: diff --git a/detection-rules/link_fake_fax_low_reputation.yml b/detection-rules/link_fake_fax_low_reputation.yml index 0974ab392d0..f2654141930 100644 --- a/detection-rules/link_fake_fax_low_reputation.yml +++ b/detection-rules/link_fake_fax_low_reputation.yml @@ -43,16 +43,11 @@ source: | ) ) ) - - // first time sender and ( - ( - sender.email.domain.root_domain in $free_email_providers - and sender.email.email not in $sender_emails - ) + profile.by_sender().prevalence in ("new", "outlier") or ( - sender.email.domain.root_domain not in $free_email_providers - and sender.email.domain.domain not in $sender_domains + profile.by_sender().any_messages_malicious_or_spam + and not profile.by_sender().any_false_positives ) ) attack_types: diff --git a/detection-rules/link_google_apps_script_macro.yml b/detection-rules/link_google_apps_script_macro.yml index 646a0a9f669..a71f3ae38bb 100644 --- a/detection-rules/link_google_apps_script_macro.yml +++ b/detection-rules/link_google_apps_script_macro.yml @@ -11,15 +11,11 @@ source: | and any(body.links, .href_url.domain.domain == "script.google.com" and strings.ilike(.href_url.path, "/macros*") ) - // first-time sender and ( - ( - sender.email.domain.root_domain in $free_email_providers - and sender.email.email not in $sender_emails - ) + profile.by_sender().prevalence in ("new", "outlier") or ( - sender.email.domain.root_domain not in $free_email_providers - and sender.email.domain.domain not in $sender_domains + profile.by_sender().any_messages_malicious_or_spam + and not profile.by_sender().any_false_positives ) ) attack_types: diff --git a/detection-rules/link_google_open_redirect_with_suspicious_indicators.yml b/detection-rules/link_google_open_redirect_with_suspicious_indicators.yml index e91911a9a39..a96f0c4381d 100644 --- a/detection-rules/link_google_open_redirect_with_suspicious_indicators.yml +++ b/detection-rules/link_google_open_redirect_with_suspicious_indicators.yml @@ -6,11 +6,13 @@ type: "rule" severity: "medium" source: | type.inbound - // All attachments are images - and length(attachments) > 0 - and all(attachments, .file_type in $file_types_images) + // All attachments are images or 0 attachments + and ( + (length(attachments) > 0 and all(attachments, .file_type in $file_types_images)) + or length(attachments) == 0 + ) and sender.email.domain.root_domain not in $org_domains - + // not a reply and ( length(headers.references) == 0 @@ -52,7 +54,7 @@ source: | ( any(ml.nlu_classifier(body.current_thread.text).entities, .name == "urgency") ), - + // White font is found in html raw ( length(body.html.display_text) < 500 @@ -60,7 +62,7 @@ source: | '