From 49c701e83dae22c97dc6557f091ac6c1341306a4 Mon Sep 17 00:00:00 2001 From: tradebot-elastic <178941316+tradebot-elastic@users.noreply.github.com> Date: Wed, 11 Nov 2026 14:54:52 +0000 Subject: [PATCH] Update latest docs --- ...ion-from-high-number-of-countries.asciidoc | 198 +++++++++++ ...ws-ec2-bulk-user-data-enumeration.asciidoc | 177 ++++++++++ ...identity-bulk-account-enumeration.asciidoc | 166 +++++++++ ...ws-sts-role-assumption-by-service.asciidoc | 166 +++++++++ ...h-potential-enumeration-roadrecon.asciidoc | 228 ++++++++++++ ...azure-diagnostic-settings-deleted.asciidoc | 154 ++++++++ ...et-retrieval-burst-by-application.asciidoc | 148 ++++++++ ...roup-deleted-by-unusual-principal.asciidoc | 163 +++++++++ ...oded-payload-piped-to-interpreter.asciidoc | 216 ++++++++++++ ...data-credential-path-http-request.asciidoc | 149 ++++++++ ...ient-sign-in-to-graph-enumeration.asciidoc | 332 ++++++++++++++++++ ...-user-sign-in-with-unusual-client.asciidoc | 264 ++++++++++++++ ...-19-37-esxi-curl-or-wget-activity.asciidoc | 111 ++++++ ...-19-37-esxi-local-account-created.asciidoc | 115 ++++++ ...sxi-virtual-disk-files-enumerated.asciidoc | 111 ++++++ ...ailures-via-macos-security-events.asciidoc | 163 +++++++++ ...ecution-via-github-actions-runner.asciidoc | 282 +++++++++++++++ ...ference-by-caller-from-source-asn.asciidoc | 132 +++++++ ...rtex-ai-role-granted-to-principal.asciidoc | 159 +++++++++ ...ruction-file-written-to-downloads.asciidoc | 200 +++++++++++ ...github-advanced-security-disabled.asciidoc | 125 +++++++ ...37-github-api-failed-access-burst.asciidoc | 135 +++++++ ...pi-sensitive-resource-enumeration.asciidoc | 170 +++++++++ ...erts-or-security-updates-disabled.asciidoc | 130 +++++++ ...-grained-pat-auto-approve-enabled.asciidoc | 142 ++++++++ ...-37-github-ip-allow-list-modified.asciidoc | 143 ++++++++ ...7-github-mfa-requirement-disabled.asciidoc | 139 ++++++++ ...-app-access-restrictions-disabled.asciidoc | 135 +++++++ ...thub-oauth-application-authorized.asciidoc | 136 +++++++ ...rivate-repository-forking-enabled.asciidoc | 125 +++++++ ...protected-branch-settings-changed.asciidoc | 120 +++++++ ...-8-19-37-github-saml-sso-disabled.asciidoc | 152 ++++++++ ...lert-for-a-publicly-leaked-secret.asciidoc | 124 +++++++ ...h-protection-bypassed-or-disabled.asciidoc | 132 +++++++ ...authority-or-requirement-modified.asciidoc | 142 ++++++++ ...ithub-sso-recovery-codes-activity.asciidoc | 139 ++++++++ ...-created-or-configuration-changed.asciidoc | 137 ++++++++ ...le-path-via-macos-security-events.asciidoc | 133 +++++++ ...uest-predicted-to-be-a-dga-domain.asciidoc | 167 +++++++++ ...with-a-high-dga-probability-score.asciidoc | 165 +++++++++ ...ontent-filter-modified-or-deleted.asciidoc | 138 ++++++++ ...secrets-accessed-by-new-principal.asciidoc | 163 +++++++++ ...connaissance-with-denied-requests.asciidoc | 166 +++++++++ ...prise-jailbreak-prompt-heuristics.asciidoc | 173 +++++++++ ...e-access-followed-by-imds-request.asciidoc | 237 +++++++++++++ ...ilename-via-macos-security-events.asciidoc | 155 ++++++++ ...tence-via-a-hidden-plist-filename.asciidoc | 153 ++++++++ ...ous-launch-agent-or-launch-daemon.asciidoc | 158 +++++++++ ...i-command-executed-by-genai-agent.asciidoc | 230 ++++++++++++ ...ial-low-packet-port-scan-detected.asciidoc | 182 ++++++++++ ...7-potential-network-scan-detected.asciidoc | 184 ++++++++++ ...-potential-network-sweep-detected.asciidoc | 182 ++++++++++ ...ential-persistence-via-login-hook.asciidoc | 169 +++++++++ ...al-php2shell-exploitation-attempt.asciidoc | 124 +++++++ ...liance-extract-argument-injection.asciidoc | 114 ++++++ ...le-modified-by-unexpected-process.asciidoc | 183 ++++++++++ ...-or-run-key-registry-modification.asciidoc | 215 ++++++++++++ ...execution-from-visual-studio-code.asciidoc | 174 +++++++++ ...ious-pbpaste-high-volume-activity.asciidoc | 158 +++++++++ ...ommon-registry-persistence-change.asciidoc | 255 ++++++++++++++ ...ocess-of-macos-screensaver-engine.asciidoc | 155 ++++++++ ...-37-user-added-to-the-admin-group.asciidoc | 158 +++++++++ .../prebuilt-rules-8-19-37-appendix.asciidoc | 68 ++++ .../prebuilt-rules-8-19-37-summary.asciidoc | 136 +++++++ ...ebuilt-rules-downloadable-updates.asciidoc | 5 + .../prebuilt-rules-reference.asciidoc | 140 +++++--- .../prebuilt-rules/rule-desc-index.asciidoc | 33 +- ...ion-from-high-number-of-countries.asciidoc | 198 +++++++++++ ...ws-ec2-bulk-user-data-enumeration.asciidoc | 177 ++++++++++ ...identity-bulk-account-enumeration.asciidoc | 166 +++++++++ ...ws-sts-role-assumption-by-service.asciidoc | 3 +- ...azure-diagnostic-settings-deleted.asciidoc | 68 ++-- ...et-retrieval-burst-by-application.asciidoc | 148 ++++++++ ...roup-deleted-by-unusual-principal.asciidoc | 163 +++++++++ ...oded-payload-piped-to-interpreter.asciidoc | 4 +- ...data-credential-path-http-request.asciidoc | 8 +- ...lobal-administrator-role-assigned.asciidoc | 2 +- ...-guest-account-promoted-to-member.asciidoc | 2 +- ...ient-sign-in-to-graph-enumeration.asciidoc | 332 ++++++++++++++++++ ...application-redirect-uri-modified.asciidoc | 2 +- ...rary-access-pass-created-for-user.asciidoc | 2 +- ...-user-sign-in-with-unusual-client.asciidoc | 8 +- .../esxi-curl-or-wget-activity.asciidoc | 4 +- .../esxi-local-account-created.asciidoc | 4 +- ...sxi-virtual-disk-files-enumerated.asciidoc | 4 +- ...ailures-via-macos-security-events.asciidoc | 4 +- ...on-of-a-downloaded-windows-script.asciidoc | 2 +- ...ecution-via-github-actions-runner.asciidoc | 23 +- ...ference-by-caller-from-source-asn.asciidoc | 132 +++++++ ...rtex-ai-role-granted-to-principal.asciidoc | 159 +++++++++ ...ruction-file-written-to-downloads.asciidoc | 200 +++++++++++ ...github-advanced-security-disabled.asciidoc | 125 +++++++ .../github-api-failed-access-burst.asciidoc | 135 +++++++ ...pi-sensitive-resource-enumeration.asciidoc | 170 +++++++++ ...erts-or-security-updates-disabled.asciidoc | 130 +++++++ ...-grained-pat-auto-approve-enabled.asciidoc | 142 ++++++++ .../github-ip-allow-list-modified.asciidoc | 143 ++++++++ .../github-mfa-requirement-disabled.asciidoc | 139 ++++++++ ...-app-access-restrictions-disabled.asciidoc | 135 +++++++ ...thub-oauth-application-authorized.asciidoc | 4 +- ...rivate-repository-forking-enabled.asciidoc | 125 +++++++ ...protected-branch-settings-changed.asciidoc | 13 +- .../github-saml-sso-disabled.asciidoc | 152 ++++++++ ...lert-for-a-publicly-leaked-secret.asciidoc | 124 +++++++ ...h-protection-bypassed-or-disabled.asciidoc | 132 +++++++ ...authority-or-requirement-modified.asciidoc | 142 ++++++++ ...ithub-sso-recovery-codes-activity.asciidoc | 139 ++++++++ ...-created-or-configuration-changed.asciidoc | 137 ++++++++ ...le-path-via-macos-security-events.asciidoc | 4 +- ...uest-predicted-to-be-a-dga-domain.asciidoc | 6 +- ...with-a-high-dga-probability-score.asciidoc | 5 +- ...ontent-filter-modified-or-deleted.asciidoc | 138 ++++++++ ...secrets-accessed-by-new-principal.asciidoc | 163 +++++++++ ...connaissance-with-denied-requests.asciidoc | 166 +++++++++ ...ise-high-codex-mcp-tool-diversity.asciidoc | 2 +- ...prise-jailbreak-prompt-heuristics.asciidoc | 173 +++++++++ ...prise-unusual-codex-mcp-tool-call.asciidoc | 2 +- ...e-access-followed-by-imds-request.asciidoc | 237 +++++++++++++ ...ilename-via-macos-security-events.asciidoc | 12 +- ...tence-via-a-hidden-plist-filename.asciidoc | 10 +- ...ous-launch-agent-or-launch-daemon.asciidoc | 15 +- ...i-command-executed-by-genai-agent.asciidoc | 5 +- ...ial-low-packet-port-scan-detected.asciidoc | 182 ++++++++++ .../potential-network-scan-detected.asciidoc | 57 ++- .../potential-network-sweep-detected.asciidoc | 46 ++- ...ential-persistence-via-login-hook.asciidoc | 42 ++- ...al-php2shell-exploitation-attempt.asciidoc | 2 +- ...oit-cve-2025-53770-cve-2025-53771.asciidoc | 10 +- ...liance-extract-argument-injection.asciidoc | 4 +- ...le-modified-by-unexpected-process.asciidoc | 42 ++- ...-or-run-key-registry-modification.asciidoc | 8 +- ...execution-from-visual-studio-code.asciidoc | 174 +++++++++ ...ious-pbpaste-high-volume-activity.asciidoc | 58 +-- ...ommon-registry-persistence-change.asciidoc | 7 +- ...ocess-of-macos-screensaver-engine.asciidoc | 44 ++- .../user-added-to-the-admin-group.asciidoc | 46 ++- docs/index.asciidoc | 2 + 137 files changed, 16019 insertions(+), 178 deletions(-) create mode 100644 docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-aws-bedrock-model-invocation-from-high-number-of-countries.asciidoc create mode 100644 docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-aws-ec2-bulk-user-data-enumeration.asciidoc create mode 100644 docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-aws-sts-getcalleridentity-bulk-account-enumeration.asciidoc create mode 100644 docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-aws-sts-role-assumption-by-service.asciidoc create mode 100644 docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-azure-ad-graph-potential-enumeration-roadrecon.asciidoc create mode 100644 docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-azure-diagnostic-settings-deleted.asciidoc create mode 100644 docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-azure-key-vault-multi-vault-secret-retrieval-burst-by-application.asciidoc create mode 100644 docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-azure-resource-group-deleted-by-unusual-principal.asciidoc create mode 100644 docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-base64-decoded-payload-piped-to-interpreter.asciidoc create mode 100644 docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-cloud-instance-metadata-credential-path-http-request.asciidoc create mode 100644 docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-entra-id-managed-device-client-sign-in-to-graph-enumeration.asciidoc create mode 100644 docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-entra-id-user-sign-in-with-unusual-client.asciidoc create mode 100644 docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-esxi-curl-or-wget-activity.asciidoc create mode 100644 docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-esxi-local-account-created.asciidoc create mode 100644 docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-esxi-virtual-disk-files-enumerated.asciidoc create mode 100644 docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-excessive-sudo-authentication-failures-via-macos-security-events.asciidoc create mode 100644 docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-execution-via-github-actions-runner.asciidoc create mode 100644 docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-first-time-gcp-vertex-ai-inference-by-caller-from-source-asn.asciidoc create mode 100644 docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-gcp-vertex-ai-role-granted-to-principal.asciidoc create mode 100644 docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-genai-agent-instruction-file-written-to-downloads.asciidoc create mode 100644 docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-github-advanced-security-disabled.asciidoc create mode 100644 docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-github-api-failed-access-burst.asciidoc create mode 100644 docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-github-api-sensitive-resource-enumeration.asciidoc create mode 100644 docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-github-dependabot-alerts-or-security-updates-disabled.asciidoc create mode 100644 docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-github-fine-grained-pat-auto-approve-enabled.asciidoc create mode 100644 docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-github-ip-allow-list-modified.asciidoc create mode 100644 docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-github-mfa-requirement-disabled.asciidoc create mode 100644 docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-github-oauth-app-access-restrictions-disabled.asciidoc create mode 100644 docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-github-oauth-application-authorized.asciidoc create mode 100644 docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-github-private-repository-forking-enabled.asciidoc create mode 100644 docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-github-protected-branch-settings-changed.asciidoc create mode 100644 docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-github-saml-sso-disabled.asciidoc create mode 100644 docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-github-secret-scanning-alert-for-a-publicly-leaked-secret.asciidoc create mode 100644 docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-github-secret-scanning-push-protection-bypassed-or-disabled.asciidoc create mode 100644 docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-github-ssh-certificate-authority-or-requirement-modified.asciidoc create mode 100644 docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-github-sso-recovery-codes-activity.asciidoc create mode 100644 docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-github-webhook-created-or-configuration-changed.asciidoc create mode 100644 docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-launch-item-registration-with-suspicious-executable-path-via-macos-security-events.asciidoc create mode 100644 docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-machine-learning-detected-a-dns-request-predicted-to-be-a-dga-domain.asciidoc create mode 100644 docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-machine-learning-detected-a-dns-request-with-a-high-dga-probability-score.asciidoc create mode 100644 docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-microsoft-foundry-content-filter-modified-or-deleted.asciidoc create mode 100644 docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-microsoft-foundry-keys-or-connection-secrets-accessed-by-new-principal.asciidoc create mode 100644 docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-microsoft-graph-application-directory-reconnaissance-with-denied-requests.asciidoc create mode 100644 docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-openai-chatgpt-enterprise-jailbreak-prompt-heuristics.asciidoc create mode 100644 docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-package-runtime-secret-file-access-followed-by-imds-request.asciidoc create mode 100644 docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-persistence-via-a-hidden-plist-filename-via-macos-security-events.asciidoc create mode 100644 docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-persistence-via-a-hidden-plist-filename.asciidoc create mode 100644 docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-persistence-via-suspicious-launch-agent-or-launch-daemon.asciidoc create mode 100644 docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-potential-destructive-aws-cli-command-executed-by-genai-agent.asciidoc create mode 100644 docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-potential-low-packet-port-scan-detected.asciidoc create mode 100644 docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-potential-network-scan-detected.asciidoc create mode 100644 docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-potential-network-sweep-detected.asciidoc create mode 100644 docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-potential-persistence-via-login-hook.asciidoc create mode 100644 docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-potential-php2shell-exploitation-attempt.asciidoc create mode 100644 docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-privilege-escalation-via-parallels-appliance-extract-argument-injection.asciidoc create mode 100644 docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-screensaver-plist-file-modified-by-unexpected-process.asciidoc create mode 100644 docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-startup-or-run-key-registry-modification.asciidoc create mode 100644 docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-suspicious-command-execution-from-visual-studio-code.asciidoc create mode 100644 docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-suspicious-pbpaste-high-volume-activity.asciidoc create mode 100644 docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-uncommon-registry-persistence-change.asciidoc create mode 100644 docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-unexpected-child-process-of-macos-screensaver-engine.asciidoc create mode 100644 docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-user-added-to-the-admin-group.asciidoc create mode 100644 docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rules-8-19-37-appendix.asciidoc create mode 100644 docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rules-8-19-37-summary.asciidoc create mode 100644 docs/detections/prebuilt-rules/rule-details/aws-bedrock-model-invocation-from-high-number-of-countries.asciidoc create mode 100644 docs/detections/prebuilt-rules/rule-details/aws-ec2-bulk-user-data-enumeration.asciidoc create mode 100644 docs/detections/prebuilt-rules/rule-details/aws-sts-getcalleridentity-bulk-account-enumeration.asciidoc create mode 100644 docs/detections/prebuilt-rules/rule-details/azure-key-vault-multi-vault-secret-retrieval-burst-by-application.asciidoc create mode 100644 docs/detections/prebuilt-rules/rule-details/azure-resource-group-deleted-by-unusual-principal.asciidoc create mode 100644 docs/detections/prebuilt-rules/rule-details/entra-id-managed-device-client-sign-in-to-graph-enumeration.asciidoc create mode 100644 docs/detections/prebuilt-rules/rule-details/first-time-gcp-vertex-ai-inference-by-caller-from-source-asn.asciidoc create mode 100644 docs/detections/prebuilt-rules/rule-details/gcp-vertex-ai-role-granted-to-principal.asciidoc create mode 100644 docs/detections/prebuilt-rules/rule-details/genai-agent-instruction-file-written-to-downloads.asciidoc create mode 100644 docs/detections/prebuilt-rules/rule-details/github-advanced-security-disabled.asciidoc create mode 100644 docs/detections/prebuilt-rules/rule-details/github-api-failed-access-burst.asciidoc create mode 100644 docs/detections/prebuilt-rules/rule-details/github-api-sensitive-resource-enumeration.asciidoc create mode 100644 docs/detections/prebuilt-rules/rule-details/github-dependabot-alerts-or-security-updates-disabled.asciidoc create mode 100644 docs/detections/prebuilt-rules/rule-details/github-fine-grained-pat-auto-approve-enabled.asciidoc create mode 100644 docs/detections/prebuilt-rules/rule-details/github-ip-allow-list-modified.asciidoc create mode 100644 docs/detections/prebuilt-rules/rule-details/github-mfa-requirement-disabled.asciidoc create mode 100644 docs/detections/prebuilt-rules/rule-details/github-oauth-app-access-restrictions-disabled.asciidoc create mode 100644 docs/detections/prebuilt-rules/rule-details/github-private-repository-forking-enabled.asciidoc create mode 100644 docs/detections/prebuilt-rules/rule-details/github-saml-sso-disabled.asciidoc create mode 100644 docs/detections/prebuilt-rules/rule-details/github-secret-scanning-alert-for-a-publicly-leaked-secret.asciidoc create mode 100644 docs/detections/prebuilt-rules/rule-details/github-secret-scanning-push-protection-bypassed-or-disabled.asciidoc create mode 100644 docs/detections/prebuilt-rules/rule-details/github-ssh-certificate-authority-or-requirement-modified.asciidoc create mode 100644 docs/detections/prebuilt-rules/rule-details/github-sso-recovery-codes-activity.asciidoc create mode 100644 docs/detections/prebuilt-rules/rule-details/github-webhook-created-or-configuration-changed.asciidoc create mode 100644 docs/detections/prebuilt-rules/rule-details/microsoft-foundry-content-filter-modified-or-deleted.asciidoc create mode 100644 docs/detections/prebuilt-rules/rule-details/microsoft-foundry-keys-or-connection-secrets-accessed-by-new-principal.asciidoc create mode 100644 docs/detections/prebuilt-rules/rule-details/microsoft-graph-application-directory-reconnaissance-with-denied-requests.asciidoc create mode 100644 docs/detections/prebuilt-rules/rule-details/openai-chatgpt-enterprise-jailbreak-prompt-heuristics.asciidoc create mode 100644 docs/detections/prebuilt-rules/rule-details/package-runtime-secret-file-access-followed-by-imds-request.asciidoc create mode 100644 docs/detections/prebuilt-rules/rule-details/potential-low-packet-port-scan-detected.asciidoc create mode 100644 docs/detections/prebuilt-rules/rule-details/suspicious-command-execution-from-visual-studio-code.asciidoc diff --git a/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-aws-bedrock-model-invocation-from-high-number-of-countries.asciidoc b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-aws-bedrock-model-invocation-from-high-number-of-countries.asciidoc new file mode 100644 index 0000000000..4fd357893b --- /dev/null +++ b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-aws-bedrock-model-invocation-from-high-number-of-countries.asciidoc @@ -0,0 +1,198 @@ +[[prebuilt-rule-8-19-37-aws-bedrock-model-invocation-from-high-number-of-countries]] +=== AWS Bedrock Model Invocation From High Number of Countries + +Detects a single AWS principal invoking Amazon Bedrock models from three or more countries and three or more source IPs within the lookback window. LLMjacking operators often distribute stolen AWS credentials across proxies or resell them to multiple buyers, which produces inference traffic for one identity from many unrelated locations. + +*Rule type*: esql + +*Rule indices*: None + +*Severity*: critical + +*Risk score*: 99 + +*Runs every*: 15m + +*Searches indices from*: now-4h ({ref}/common-options.html#date-math[Date Math format], see also <>) + +*Maximum alerts per execution*: 100 + +*References*: + +* https://docs.aws.amazon.com/bedrock/latest/userguide/logging-using-cloudtrail.html +* https://www.elastic.co/docs/reference/integrations/aws/cloudtrail + +*Tags*: + +* Domain: Cloud +* Domain: GenAI +* Data Source: AWS +* Data Source: Amazon Web Services +* Data Source: AWS CloudTrail +* Platform: AWS +* Service: AWS Bedrock +* Use Case: Threat Detection +* Tactic: Credential Access +* Tactic: Initial Access +* Threat: Impossible Travel +* Threat: LLMjacking +* Threat: Unauthorized AI Usage +* Mitre Atlas: AML.T0012 +* Mitre Atlas: AML.T0091 +* Mitre Atlas: AML.T0091.000 +* Resources: Investigation Guide +* Rule Type: ES|QL + +*Version*: 1 + +*Rule authors*: + +* Elastic + +*Rule license*: Elastic License v2 + + +==== Investigation guide + + + +*Triage and analysis* + + + +*Investigating AWS Bedrock Model Invocation From High Number of Countries* + + +One AWS principal (role issuer ARN when present, otherwise `aws.cloudtrail.user_identity.arn`) invoked Amazon Bedrock +models from at least three countries and three source IPs inside the lookback window. Assumed-role sessions are grouped +by the issuing role so re-assumes of the same role still correlate. This pattern fits credentials that have been shared, +resold, or proxied for LLMjacking. + + +*Possible investigation steps* + + +- Review `Esql.source_geo_country_name_values`, `Esql.source_ip_values`, and + `Esql.source_as_organization_name_values`. Residential proxies and hosting ASNs across several countries are more + suspicious than one corporate VPN provider. +- Check `Esql.aws_cloudtrail_user_identity_access_key_id_values` and `Esql.aws_cloudtrail_user_identity_type_values`. + A single long-term `AKIA` key seen in many countries is a strong indicator of credential theft. +- Compare `Esql.user_agent_original_values`. Several distinct clients for one identity often means several operators. +- Search CloudTrail for the principal's other activity in the window, especially model access changes, guardrail or + logging changes, and IAM changes. +- Review Bedrock cost and usage for the account over the same period. + + +*False positive analysis* + + +- Shared identities for global workloads. Move these to region-scoped roles or add an exception for the principal. +- VPN and privacy relay users. Confirm with the account owner before rotating credentials. + + +*Response and remediation* + + +- If the activity is not explained, deactivate the access key or revoke the role session, rotate credentials, and + restrict `bedrock:InvokeModel*` permissions. +- Set AWS Budgets or service quotas to limit the cost of further abuse. + + +==== Setup + + + +*Setup* + + +This rule requires AWS CloudTrail management events ingested via the AWS integration (`aws.cloudtrail` data stream) +with `source.geo.country_name` populated by the integration's GeoIP enrichment. Bedrock runtime operations are logged +as management events by default; no Bedrock model invocation logging is required. + + +==== Rule query + + +[source, js] +---------------------------------- +from logs-aws.cloudtrail-* +| where + data_stream.dataset == "aws.cloudtrail" and + event.provider == "bedrock.amazonaws.com" and + event.action in ("InvokeModel", "InvokeModelWithResponseStream", "Converse", "ConverseStream") and + event.outcome == "success" and + aws.cloudtrail.user_identity.arn is not null and + source.ip is not null and + source.geo.country_name is not null +| eval + Esql.identity = coalesce( + aws.cloudtrail.user_identity.session_context.session_issuer.arn, + aws.cloudtrail.user_identity.arn + ) +| stats + Esql.country_count = count_distinct(source.geo.country_name), + Esql.source_ip_count = count_distinct(source.ip), + Esql.user_agent_count = count_distinct(user_agent.original), + Esql.event_count = count(*), + Esql.event_action_values = values(event.action), + Esql.source_ip_values = values(source.ip), + Esql.source_geo_country_name_values = values(source.geo.country_name), + Esql.source_geo_city_name_values = values(source.geo.city_name), + Esql.source_as_organization_name_values = values(source.as.organization.name), + Esql.user_agent_original_values = values(user_agent.original), + Esql.aws_cloudtrail_user_identity_arn_values = values(aws.cloudtrail.user_identity.arn), + Esql.aws_cloudtrail_user_identity_type_values = values(aws.cloudtrail.user_identity.type), + Esql.aws_cloudtrail_user_identity_access_key_id_values = values(aws.cloudtrail.user_identity.access_key_id), + Esql.cloud_region_values = values(cloud.region), + Esql.timestamp_first_seen = min(@timestamp), + Esql.timestamp_last_seen = max(@timestamp) + by + Esql.identity, + cloud.account.id +| where Esql.country_count >= 3 and Esql.source_ip_count >= 3 +| eval source.ip = mv_first(Esql.source_ip_values) +| keep + Esql.identity, + cloud.account.id, + source.ip, + Esql.country_count, + Esql.source_ip_count, + Esql.user_agent_count, + Esql.event_count, + Esql.event_action_values, + Esql.source_ip_values, + Esql.source_geo_country_name_values, + Esql.source_geo_city_name_values, + Esql.source_as_organization_name_values, + Esql.user_agent_original_values, + Esql.aws_cloudtrail_user_identity_arn_values, + Esql.aws_cloudtrail_user_identity_type_values, + Esql.aws_cloudtrail_user_identity_access_key_id_values, + Esql.cloud_region_values, + Esql.timestamp_first_seen, + Esql.timestamp_last_seen + +---------------------------------- + +*Framework*: MITRE ATT&CK^TM^ + +* Tactic: +** Name: Credential Access +** ID: TA0006 +** Reference URL: https://attack.mitre.org/tactics/TA0006/ +* Technique: +** Name: Steal Application Access Token +** ID: T1528 +** Reference URL: https://attack.mitre.org/techniques/T1528/ +* Tactic: +** Name: Initial Access +** ID: TA0001 +** Reference URL: https://attack.mitre.org/tactics/TA0001/ +* Technique: +** Name: Valid Accounts +** ID: T1078 +** Reference URL: https://attack.mitre.org/techniques/T1078/ +* Sub-technique: +** Name: Cloud Accounts +** ID: T1078.004 +** Reference URL: https://attack.mitre.org/techniques/T1078/004/ diff --git a/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-aws-ec2-bulk-user-data-enumeration.asciidoc b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-aws-ec2-bulk-user-data-enumeration.asciidoc new file mode 100644 index 0000000000..023fb0ca7d --- /dev/null +++ b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-aws-ec2-bulk-user-data-enumeration.asciidoc @@ -0,0 +1,177 @@ +[[prebuilt-rule-8-19-37-aws-ec2-bulk-user-data-enumeration]] +=== AWS EC2 Bulk User Data Enumeration + +Identifies when the same AWS principal, from the same source IP, successfully calls EC2 "DescribeInstanceAttribute" for the "userData" attribute against more than 20 distinct instances within a 10-minute lookback. Instance user data often contains bootstrap scripts and hardcoded credentials, so retrieving it across many instances in a short window can indicate reconnaissance or credential harvesting. Known CSPM roles, AWS service invocations, and Terraform calls from major cloud and carrier networks are excluded. + +*Rule type*: esql + +*Rule indices*: None + +*Severity*: high + +*Risk score*: 73 + +*Runs every*: 5m + +*Searches indices from*: now-10m ({ref}/common-options.html#date-math[Date Math format], see also <>) + +*Maximum alerts per execution*: 100 + +*References*: + +* https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeInstanceAttribute.html +* https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/user-data.html +* https://hackingthe.cloud/aws/exploitation/local_ec2_priv_esc_through_user_data + +*Tags*: + +* Domain: Cloud +* Data Source: AWS +* Data Source: Amazon Web Services +* Data Source: AWS CloudTrail +* Platform: AWS +* Service: AWS EC2 +* Use Case: Threat Detection +* Tactic: Discovery +* Tactic: Credential Access +* Resources: Investigation Guide +* Rule Type: ES|QL + +*Version*: 1 + +*Rule authors*: + +* Elastic + +*Rule license*: Elastic License v2 + + +==== Investigation guide + + + +*Triage and analysis* + + + +*Investigating AWS EC2 Bulk User Data Enumeration* + + +EC2 `userData` is returned by `DescribeInstanceAttribute` when `attribute` is `userData`. It is frequently used for +bootstrap scripts and sometimes contains credentials or tokens. This rule alerts when one principal +(`aws.cloudtrail.user_identity.arn`), identity type, source IP, and source ASN reads that attribute for more than 20 +distinct `aws.cloudtrail.request_parameters` values in the 10-minute lookback. For this API those values correspond to +distinct instance requests. + + +*Possible investigation steps* + + +- Review `aws.cloudtrail.user_identity.arn` and `aws.cloudtrail.user_identity.type`. Confirm whether this identity is + expected to read instance user data at fleet scale. +- Review `Esql.count_distinct_instance_id` and `Esql.aws_request_parameters_values`. Extract the `instanceId` values and + check whether the instances belong to sensitive workloads. +- Review `source.ip`, `source.as.organization.name`, and `Esql.user_agent_values`. Unexpected ASNs or clients such as + the AWS CLI or an SDK from an unfamiliar network are higher priority than a known automation host. +- Search CloudTrail for the same principal and source IP in the surrounding hour for `ModifyInstanceAttribute`, + `RunInstances`, `GetPasswordData`, `AssumeRole`, and IAM changes. +- If the instances are still available, inspect their current user data for secrets. Prefer AWS Secrets Manager or + Parameter Store over credentials stored in user data. + + +*False positive analysis* + + +- Approved CSPM and inventory tools. This rule already excludes principal names matching CrowdStrike CSPM, Orca + Security, Aikido Security, Stream Security (`streamsec-*`), and `AWSReservedSSO_Poweruser`. +- Calls invoked by AWS Internal, CloudFormation, AI DevOps, EMR, or AIOps. +- Terraform user agents whose source ASN is Amazon, Google, Microsoft, Verizon, or AT&T. +- Add further exceptions by principal ARN or user agent when the behavior is documented and recurring. + + +*Response and remediation* + + +- If the activity is not authorized, revoke the role session or disable the access key and restrict the source IP. +- Rotate any credentials found in the retrieved user data and remove secrets from instance user data. +- Limit `ec2:DescribeInstanceAttribute` to principals that need it. + + +==== Setup + + + +*Setup* + + +The AWS integration must collect CloudTrail management events into `logs-aws.cloudtrail-*`. +`DescribeInstanceAttribute` is a management event logged by default. `source.ip` and +`source.as.organization.name` must be populated, because events missing either field are excluded. + + +==== Rule query + + +[source, js] +---------------------------------- +from logs-aws.cloudtrail-* +| where KQL("""event.provider: "ec2.amazonaws.com" and event.action: "DescribeInstanceAttribute" and event.outcome: "success" and aws.cloudtrail.flattened.request_parameters.attribute: "userData" and source.ip: * and source.as.organization.name: * and not user.name: (*CrowdStrikeCSPMReader* or *OrcaSecurityRole* or *AikidoSecurityRole* or *streamsec-*) and not aws.cloudtrail.user_identity.invoked_by: ("AWS Internal" or "cloudformation.amazonaws.com" or "aidevops.amazonaws.com" or "elasticmapreduce.amazonaws.com" or "aiops.amazonaws.com")""") + and not ( + user_agent.original like "*Terraform*" + and source.as.organization.name in ( + "Amazon.com, Inc.", + "Google LLC", + "Microsoft Corporation", + "Verizon Business", + "AT&T Enterprises, LLC" + ) + ) +| grok aws.cloudtrail.request_parameters """instanceId=(?[^,}\]]+)""" +| where Esql.instance_id is not null +| stats + Esql.count_distinct_instance_id = count_distinct(Esql.instance_id), + Esql.aws_request_parameters_values = values(aws.cloudtrail.request_parameters), + Esql.user_agent_values = values(user_agent.original) + by + data_stream.namespace, + aws.cloudtrail.user_identity.arn, + aws.cloudtrail.user_identity.type, + source.as.organization.name, + source.ip, + source.`as`.number +| where Esql.count_distinct_instance_id > 20 +| keep + Esql.count_distinct_instance_id, + data_stream.namespace, + aws.cloudtrail.user_identity.arn, + aws.cloudtrail.user_identity.type, + source.ip, + source.`as`.number, + source.as.organization.name, + Esql.aws_request_parameters_values, + Esql.user_agent_values + +---------------------------------- + +*Framework*: MITRE ATT&CK^TM^ + +* Tactic: +** Name: Discovery +** ID: TA0007 +** Reference URL: https://attack.mitre.org/tactics/TA0007/ +* Technique: +** Name: Cloud Infrastructure Discovery +** ID: T1580 +** Reference URL: https://attack.mitre.org/techniques/T1580/ +* Tactic: +** Name: Credential Access +** ID: TA0006 +** Reference URL: https://attack.mitre.org/tactics/TA0006/ +* Technique: +** Name: Unsecured Credentials +** ID: T1552 +** Reference URL: https://attack.mitre.org/techniques/T1552/ +* Sub-technique: +** Name: Cloud Instance Metadata API +** ID: T1552.005 +** Reference URL: https://attack.mitre.org/techniques/T1552/005/ diff --git a/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-aws-sts-getcalleridentity-bulk-account-enumeration.asciidoc b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-aws-sts-getcalleridentity-bulk-account-enumeration.asciidoc new file mode 100644 index 0000000000..fda5b2b065 --- /dev/null +++ b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-aws-sts-getcalleridentity-bulk-account-enumeration.asciidoc @@ -0,0 +1,166 @@ +[[prebuilt-rule-8-19-37-aws-sts-getcalleridentity-bulk-account-enumeration]] +=== AWS STS GetCallerIdentity Bulk Account Enumeration + +Identifies three or more distinct AWS principals calling STS "GetCallerIdentity" from the same source IP and autonomous system within a 10-minute window. "GetCallerIdentity" returns the account and identity behind a credential and requires no permissions, so a burst of different non-role identities from one external address is a common credential-validation and account-enumeration step. Assumed roles, Vault OIDC users, and calls from major cloud and carrier networks are excluded. + +*Rule type*: esql + +*Rule indices*: None + +*Severity*: high + +*Risk score*: 73 + +*Runs every*: 5m + +*Searches indices from*: now-10m ({ref}/common-options.html#date-math[Date Math format], see also <>) + +*Maximum alerts per execution*: 100 + +*References*: + +* https://docs.aws.amazon.com/STS/latest/APIReference/API_GetCallerIdentity.html +* https://www.secureworks.com/research/detecting-the-use-of-stolen-aws-lambda-credentials +* https://detectioninthe.cloud/ttps/discovery/sts_get_caller_identity + +*Tags*: + +* Domain: Cloud +* Data Source: AWS +* Data Source: Amazon Web Services +* Data Source: AWS CloudTrail +* Platform: AWS +* Service: AWS STS +* Use Case: Threat Detection +* Tactic: Discovery +* Resources: Investigation Guide +* Rule Type: ES|QL + +*Version*: 1 + +*Rule authors*: + +* Elastic + +*Rule license*: Elastic License v2 + + +==== Investigation guide + + + +*Triage and analysis* + + + +*Investigating AWS STS GetCallerIdentity Bulk Account Enumeration* + + +`GetCallerIdentity` returns the account and principal for the credentials that called it. No IAM permission is +required. This rule groups successful calls that are not `AssumedRole` by source IP and source ASN. It alerts when +that group contains at least three distinct `user.name` values. The rule runs every 5 minutes and looks back 10 +minutes, so the threshold is the last 10 minutes of activity. Alerts for the same `source.ip` are suppressed for +24 hours. + +This complements **AWS STS GetCallerIdentity API Called for the First Time**, which alerts on the first call from +one identity. This rule alerts when several identities are checked from one external address. + + +*Possible investigation steps* + + +- Review `source.ip`, `source.as.organization.name`, and `Esql.user_agent_original_values`. An AWS CLI, SDK, or + unknown client from an unfamiliar ASN is higher priority than a known management host. +- Review `Esql.user_name_values` and `Esql.aws_cloudtrail_user_identity_arn_values`. Check whether the identities + are unrelated IAM users, include privileged users, or share one access key. +- Compare `Esql.user_name_count_distinct` with `Esql.aws_cloudtrail_user_identity_arn_count_distinct`. A higher ARN + count than user count can mean several keys or federation sessions for the same user names. +- Search CloudTrail for those identities in the surrounding hour for `AssumeRole`, `GetSessionToken`, IAM changes, + and discovery calls such as `ListUsers`, `ListBuckets`, and `DescribeInstances`. +- Determine whether any of the credentials were used successfully after the identity check. + + +*False positive analysis* + + +- Users named `vault-oidc-*` are excluded. +- `AssumedRole` sessions are excluded. IAM users, federated users, and the root user remain in scope. +- Calls whose source ASN is Amazon, Google, Microsoft, Verizon, or AT&T are excluded. +- Shared egress that is not in that ASN list can still reach three users. Exclude the source IP or user agent when + the behavior is documented. + + +*Response and remediation* + + +- If the activity is not authorized, disable the access keys for the listed users and revoke active sessions. +- Rotate credentials that were validated from the source IP. +- Review CloudTrail for follow-on use of those identities and contain any resources they touched. + + +==== Setup + + + +*Setup* + + +The AWS integration must collect CloudTrail management events into `logs-aws.cloudtrail-*`. +`GetCallerIdentity` is a management event logged by default. `source.as.organization.name` must be populated, +because events missing it are excluded. + + +==== Rule query + + +[source, js] +---------------------------------- +from logs-aws.cloudtrail-* +| where KQL("""data_stream.dataset: "aws.cloudtrail" and event.provider: "sts.amazonaws.com" and event.action: "GetCallerIdentity" and event.outcome: "success" and not aws.cloudtrail.user_identity.type: "AssumedRole" and source.as.organization.name: * and not user.name: vault-oidc-*""") + and source.ip is not null + and not source.as.organization.name in ( + "Amazon.com, Inc.", + "AMAZON-02", + "AMAZON-AES", + "Google LLC", + "Microsoft Corporation", + "Verizon Business", + "AT&T Enterprises, LLC" + ) +| stats + Esql.aws_cloudtrail_user_identity_arn_count_distinct = count_distinct(aws.cloudtrail.user_identity.arn), + Esql.user_name_count_distinct = count_distinct(user.name), + Esql.user_name_values = values(user.name), + Esql.user_agent_original_values = values(user_agent.original), + Esql.aws_cloudtrail_user_identity_arn_values = values(aws.cloudtrail.user_identity.arn) + by source.ip, source.as.organization.name +| where Esql.user_name_count_distinct >= 3 +| keep + Esql.user_name_count_distinct, + Esql.aws_cloudtrail_user_identity_arn_count_distinct, + source.ip, + source.as.organization.name, + Esql.user_name_values, + Esql.user_agent_original_values, + Esql.aws_cloudtrail_user_identity_arn_values + +---------------------------------- + +*Framework*: MITRE ATT&CK^TM^ + +* Tactic: +** Name: Discovery +** ID: TA0007 +** Reference URL: https://attack.mitre.org/tactics/TA0007/ +* Technique: +** Name: Account Discovery +** ID: T1087 +** Reference URL: https://attack.mitre.org/techniques/T1087/ +* Sub-technique: +** Name: Cloud Account +** ID: T1087.004 +** Reference URL: https://attack.mitre.org/techniques/T1087/004/ +* Technique: +** Name: System Owner/User Discovery +** ID: T1033 +** Reference URL: https://attack.mitre.org/techniques/T1033/ diff --git a/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-aws-sts-role-assumption-by-service.asciidoc b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-aws-sts-role-assumption-by-service.asciidoc new file mode 100644 index 0000000000..803e22ce61 --- /dev/null +++ b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-aws-sts-role-assumption-by-service.asciidoc @@ -0,0 +1,166 @@ +[[prebuilt-rule-8-19-37-aws-sts-role-assumption-by-service]] +=== AWS STS Role Assumption by Service + +Identifies when a service has assumed a role in AWS Security Token Service (STS). Services can assume a role to obtain temporary credentials and access AWS resources. Adversaries can use this technique for credential access and privilege escalation. This is a New Terms rule that identifies when a service assumes a role in AWS Security Token Service (STS) to obtain temporary credentials and access AWS resources. While often legitimate, adversaries may use this technique for unauthorized access, privilege escalation, or lateral movement within an AWS environment. + +*Rule type*: new_terms + +*Rule indices*: + +* filebeat-* +* logs-aws.cloudtrail-* + +*Severity*: low + +*Risk score*: 21 + +*Runs every*: 5m + +*Searches indices from*: now-6m ({ref}/common-options.html#date-math[Date Math format], see also <>) + +*Maximum alerts per execution*: 100 + +*References*: + +* https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRole.html + +*Tags*: + +* Domain: Cloud +* Data Source: AWS +* Data Source: Amazon Web Services +* Data Source: AWS STS +* Resources: Investigation Guide +* Use Case: Identity and Access Audit +* Tactic: Privilege Escalation +* Tactic: Lateral Movement +* Noise: High +* Performance: Normal +* Profile: Aggressive +* Rule Type: New Terms +* Platform: AWS +* Data Source: AWS CloudTrail +* Service: AWS STS + +*Version*: 218 + +*Rule authors*: + +* Elastic +* Austin Songer + +*Rule license*: Elastic License v2 + + +==== Investigation guide + + + +*Triage and analysis* + + + +*Investigating AWS STS Role Assumption by Service* + + +This rule identifies instances where AWS STS (Security Token Service) is used to assume a role, granting temporary credentials for AWS resource access. While this action is often legitimate, it can be exploited by adversaries to obtain unauthorized access, escalate privileges, or move laterally within an AWS environment. + + +*Possible Investigation Steps* + + +- **Identify the Actor and Assumed Role**: + - **User Identity**: Review the `aws.cloudtrail.user_identity.invoked_by` field to determine which service initiated the `AssumeRole` action. + - **Role Assumed**: Check the `aws.cloudtrail.resources.arn` field to confirm the assumed role and ensure it aligns with expected responsibilities. + - **Session Name**: Observe the `aws.cloudtrail.flattened.request_parameters.roleSessionName` for context on the session's intended purpose, if available. + - **Expiration Time**: Verify `aws.cloudtrail.flattened.response_elements.credentials.expiration` to determine when the credentials expire or expired. + +- **Inspect the User Agent for Tooling Identification**: + - **User Agent Details**: Review the `user_agent.original` field to identify the tool or SDK used for the role assumption. Indicators include: + - **AWS SDKs (e.g., Boto3)**: Often used in automated workflows or scripts. + - **AWS CLI**: Suggests command-line access, potentially indicating direct user interaction. + - **Custom Tooling**: Unusual user agents may signify custom or suspicious tools. + +- **Contextualize with Related Events**: + - **Review Event Patterns**: Check surrounding CloudTrail events to see if other actions coincide with this `AssumeRole` activity, such as attempts to access sensitive resources. + - **Identify High-Volume Exceptions**: Due to the potential volume of `AssumeRole` events, determine common, legitimate `roleArn` values or `user_agent` patterns, and consider adding these as exceptions to reduce noise. + +- **Evaluate the Privilege Level of the Assumed Role**: + - **Permissions**: Inspect permissions associated with the assumed role to understand its access level. + - **Authorized Usage**: Confirm whether the role is typically used for administrative purposes and if the assuming entity frequently accesses it as part of regular responsibilities. + + +*False Positive Analysis* + + +- **Automated Workflows and Applications**: Many applications or scheduled tasks may assume roles for standard operations. Check user agents and ARNs for consistency with known workflows. +- **Routine AWS Service Actions**: Historical data may reveal if the same service assumes new roles regularly as part of authorized operations. + + +*Response and Remediation* + + +- **Revoke Unauthorized Sessions**: If unauthorized, consider revoking the session by adjusting IAM policies or permissions associated with the assumed role. +- **Enhance Monitoring and Alerts**: Set up enhanced monitoring for high-risk roles, especially those with elevated privileges. +- **Manage Exceptions**: Regularly review and manage high-frequency roles and user agent patterns, adding trusted ARNs and user agents to exception lists to minimize alert fatigue. +- **Incident Response**: If malicious behavior is identified, follow incident response protocols, including containment, investigation, and remediation. + + +*Additional Information* + + +For more information on managing and securing AWS STS, refer to the https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRole.html[AWS STS documentation] and AWS security best practices. + + +==== Rule query + + +[source, js] +---------------------------------- +data_stream.dataset: "aws.cloudtrail" + and event.provider: "sts.amazonaws.com" + and event.action: "AssumeRole" + and event.outcome: "success" + and aws.cloudtrail.user_identity.type: "AWSService" + and aws.cloudtrail.user_identity.invoked_by: ( + "ec2.amazonaws.com" or + "lambda.amazonaws.com" or + "rds.amazonaws.com" or + "ssm.amazonaws.com" or + "ecs-tasks.amazonaws.com" or + "ecs.amazonaws.com" or + "eks.amazonaws.com" or + "eks-fargate.amazonaws.com" or + "codepipeline.amazonaws.com" or + "codebuild.amazonaws.com" or + "autoscaling.amazonaws.com") + and aws.cloudtrail.resources.arn: (* and not *role/aws-service-role*) + +---------------------------------- + +*Framework*: MITRE ATT&CK^TM^ + +* Tactic: +** Name: Privilege Escalation +** ID: TA0004 +** Reference URL: https://attack.mitre.org/tactics/TA0004/ +* Technique: +** Name: Abuse Elevation Control Mechanism +** ID: T1548 +** Reference URL: https://attack.mitre.org/techniques/T1548/ +* Sub-technique: +** Name: Temporary Elevated Cloud Access +** ID: T1548.005 +** Reference URL: https://attack.mitre.org/techniques/T1548/005/ +* Tactic: +** Name: Lateral Movement +** ID: TA0008 +** Reference URL: https://attack.mitre.org/tactics/TA0008/ +* Technique: +** Name: Use Alternate Authentication Material +** ID: T1550 +** Reference URL: https://attack.mitre.org/techniques/T1550/ +* Sub-technique: +** Name: Application Access Token +** ID: T1550.001 +** Reference URL: https://attack.mitre.org/techniques/T1550/001/ diff --git a/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-azure-ad-graph-potential-enumeration-roadrecon.asciidoc b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-azure-ad-graph-potential-enumeration-roadrecon.asciidoc new file mode 100644 index 0000000000..5018d2ee38 --- /dev/null +++ b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-azure-ad-graph-potential-enumeration-roadrecon.asciidoc @@ -0,0 +1,228 @@ +[[prebuilt-rule-8-19-37-azure-ad-graph-potential-enumeration-roadrecon]] +=== Azure AD Graph Potential Enumeration (ROADrecon) + +Detects a burst of Azure AD Graph (graph.windows.net) directory enumeration by a single identity, keyed on the internal API version that ROADrecon hardcodes (`1.61-internal`, with `1.6-internal` as a related tooling value) plus a per-user request burst. ROADrecon's gather command walks the directory via this internal API version using aiohttp. This rule also detects the "evade" argument that routes every read through a single "/$batch" OData endpoint under a benign "Microsoft ADO.NET Data Services" user-agent. A lower burst threshold applies when a scripting user-agent (aiohttp/python/fasthttp) is present and a higher volume threshold applies otherwise. + +*Rule type*: esql + +*Rule indices*: None + +*Severity*: high + +*Risk score*: 73 + +*Runs every*: 5m + +*Searches indices from*: now-9m ({ref}/common-options.html#date-math[Date Math format], see also <>) + +*Maximum alerts per execution*: 100 + +*References*: + +* https://github.com/dirkjanm/ROADtools +* https://github.com/dirkjanm/ROADtools/blob/master/roadrecon/roadtools/roadrecon/gather.py +* https://unit42.paloaltonetworks.com/roadtools-cloud-attacks/ +* https://learn.microsoft.com/en-us/graph/migrate-azure-ad-graph-overview + +*Tags*: + +* Domain: Cloud +* Data Source: Azure +* Data Source: Azure AD Graph +* Data Source: Azure AD Graph Activity Logs +* Use Case: Threat Detection +* Tactic: Discovery +* Resources: Investigation Guide +* Noise: Unknown +* Performance: Fast +* Rule Type: ES|QL +* Platform: Entra ID +* Domain: Identity + +*Version*: 4 + +*Rule authors*: + +* Elastic + +*Rule license*: Elastic License v2 + + +==== Investigation guide + + + +*Triage and analysis* + + + +*Investigating Azure AD Graph Potential Enumeration (ROADrecon)* + + +This is an ES|QL aggregation rule. Alert documents contain summarized fields per burst window: the calling identity, the tenant, and a one-minute bucket. The alert itself is the signal that something resembling ROADrecon's `gather` walk happened against AAD Graph; the actual investigation happens against the raw `logs-azure.aadgraphactivitylogs-*` events for the same identity and window. + +The rule anchors on the hardcoded internal API version and a per-user burst rather than the user-agent alone, so it catches all three `gather` transports: + +- Default: `aiohttp` user-agent across ~16 directory collections. +- `--evade`: a single `/$batch` OData endpoint under a `Microsoft ADO.NET Data Services` user-agent (defeats user-agent and distinct-endpoint based matching). +- `-ua `: an arbitrary browser user-agent. + + +*Possible investigation steps* + + +- Confirm the burst by filtering raw AAD Graph activity for the alerting user, tenant, and time window. + - Filter `logs-azure.aadgraphactivitylogs-*` on the alerting user, tenant, and burst window. + - A default `gather` walks ~16 collections (many distinct `url.path`); `--evade` concentrates volume on `/$batch` (high `request_count`, one path). +- Tool fingerprint: the internal API version is the primary anchor. + - `api_version = 1.61-internal` (hardcoded in `gather.py`, returns internal-only fields like `strongAuthenticationDetail`). No first-party Microsoft component pins this at volume. + - `user_agent.original` is a secondary tell: `aiohttp`/`python` (overt), `Microsoft ADO.NET Data Services` with `/$batch` (the `--evade` signature), or a browser string (`-ua`). +- Calling client + auth method: the typical device-code-flow ROADrecon entrypoint. + - ROADrecon is usually pointed at the Azure CLI client (`04b07795-…`) via the `-c` flag. + - Uses a public-client auth method (no client secret or certificate). +- HTTP shape distinguishes enumeration from operator follow-on. + - `gather` reads only, so GETs dominate (the `--evade` `/$batch` requests are POSTs to the batch endpoint). + - A 403/404 tail indicates the identity probing endpoints it lacks permission for. + - PATCH / POST / DELETE against directory objects in the same burst means the operator did more than enumerate. +- Source posture: residential ISP, generic VPS, or anonymising-network egress raises triage priority. +- Pivot to sign-in logs (`logs-azure.signinlogs-*`) via the sign-in correlation ID on each AAD Graph event to land on the originating token-mint. +- Pivot to audit logs (`logs-azure.auditlogs-*`) for any directory writes by the same user near the burst that suggest persistence or modification activity. +- Confirm the activity is not attributable to authorized testing before treating as malicious. + - Check for red team engagement, penetration test, or internal tooling validation. + - Validate against the engagement window and the operator's known source range. + + +*Response and remediation* + + +- Enumerate device registrations created by the user during or around the burst window. + - `GET /v1.0/users/{id}/registeredDevices` and `GET /v1.0/users/{id}/ownedDevices`. + - De-register anything not attributable to a known endpoint via `DELETE /v1.0/devices/{deviceObjectId}`. + - Do this BEFORE session revocation: device-bound PRTs survive `revokeSignInSessions`. +- Revoke refresh tokens and active sessions for the calling user. + - `POST /v1.0/users/{id}/revokeSignInSessions`. +- Temporarily disable the user if the alert is high-confidence or you need to halt further activity while investigation continues. + - `PATCH /v1.0/users/{id}` with body `{"accountEnabled": false}`. +- Audit OAuth grants and app role assignments the user holds; revoke anything minted from a kit-egress or otherwise suspicious source. + - `GET /v1.0/oauth2PermissionGrants?$filter=principalId eq '{id}'`, revoke via `DELETE /v1.0/oauth2PermissionGrants/{grantId}`. + - `GET /v1.0/users/{id}/appRoleAssignments`, revoke via `DELETE /v1.0/servicePrincipals/{spId}/appRoleAssignedTo/{assignmentId}`. +- Reset the user's password and audit authentication methods added during the window. + - `GET /v1.0/users/{id}/authentication/methods` to list. + - Remove anything unexpected via the method-type-specific endpoint. +- Audit directory writes by the user near the burst and roll back unauthorized changes. + - Query `logs-azure.auditlogs-*` for `Register device`, `Update user`, `User registered security info`, role assignment activity by the same user in the window. +- If the calling application has no legitimate AAD Graph dependency, block further use by that app. + - `PATCH /beta/applications/{id}` with body `{"authenticationBehaviors": {"blockAzureADGraphAccess": true}}`. + - This property lives on the Graph beta endpoint, not v1.0. + + +==== Setup + + + +*Azure AD Graph Activity Logs* + +Requires Azure AD Graph Activity Logs ingested into `logs-azure.aadgraphactivitylogs-*` via the Elastic Azure integration. Enable the `AzureADGraphActivityLogs` diagnostic-settings category on Entra ID. + + +==== Rule query + + +[source, js] +---------------------------------- +from logs-azure.aadgraphactivitylogs-* metadata _id, _version, _index + +| where data_stream.dataset == "azure.aadgraphactivitylogs" + and azure.aadgraphactivitylogs.properties.api_version in ("1.61-internal", "1.6-internal") + +| eval Esql.ua_lower = to_lower(user_agent.original) +| eval Esql.scripting_user_agent = Esql.ua_lower like "*aiohttp*" or Esql.ua_lower like "python*" or Esql.ua_lower like "*fasthttp*" +| eval Esql.target_endpoint = case( + url.path like "*$batch*", "batch", + url.path like "*/eligibleRoleAssignments*", "eligibleRoleAssignments", + url.path like "*/roleAssignments*", "roleAssignments", + url.path like "*/users*", "users", + url.path like "*/groups*", "groups", + url.path like "*/servicePrincipals*", "servicePrincipals", + url.path like "*/applications*", "applications", + url.path like "*/devices*", "devices", + url.path like "*/directoryRoles*", "directoryRoles", + url.path like "*/roleDefinitions*", "roleDefinitions", + url.path like "*/administrativeUnits*", "administrativeUnits", + url.path like "*/contacts*", "contacts", + url.path like "*/oauth2PermissionGrants*", "oauth2PermissionGrants", + url.path like "*/authorizationPolicy*", "authorizationPolicy", + url.path like "*/settings*", "settings", + url.path like "*/policies*", "policies", + url.path like "*/tenantDetails*", "tenantDetails", + "other" + ) + +| eval Esql.time_window = date_trunc(1 minutes, @timestamp) + +| stats + Esql.request_count = count(*), + Esql.distinct_endpoints = count_distinct(url.path), + Esql.collections = values(Esql.target_endpoint), + Esql.scripting_user_agent_seen = max(case(Esql.scripting_user_agent, 1, 0)), + Esql.api_versions = values(azure.aadgraphactivitylogs.properties.api_version), + Esql.app_ids = values(azure.aadgraphactivitylogs.properties.app_id), + Esql.user_agents = values(user_agent.original), + Esql.http_methods = values(http.request.method), + Esql.status_codes = values(http.response.status_code), + Esql.source_ips = values(source.ip), + Esql.source_asn_orgs = values(source.`as`.organization.name), + Esql.source_countries = values(source.geo.country_name), + Esql.actor_types = values(azure.aadgraphactivitylogs.properties.actor_type), + Esql.client_auth_methods = values(azure.aadgraphactivitylogs.properties.client_auth_method), + Esql.session_ids = values(azure.aadgraphactivitylogs.properties.session_id), + Esql.sign_in_activity_ids = values(azure.aadgraphactivitylogs.properties.sign_in_activity_id), + Esql.scopes = values(azure.aadgraphactivitylogs.properties.scopes), + Esql.first_seen = min(@timestamp), + Esql.last_seen = max(@timestamp) + by + user.id, + azure.tenant_id, + Esql.time_window + +| eval Esql.enum_detected = case( + Esql.scripting_user_agent_seen == 1 and Esql.distinct_endpoints >= 5, true, + Esql.distinct_endpoints >= 15, true, + Esql.request_count >= 150, true, + false + ) +| where Esql.enum_detected == true + +| keep + user.id, + azure.tenant_id, + Esql.* + +---------------------------------- + +*Framework*: MITRE ATT&CK^TM^ + +* Tactic: +** Name: Discovery +** ID: TA0007 +** Reference URL: https://attack.mitre.org/tactics/TA0007/ +* Technique: +** Name: Permission Groups Discovery +** ID: T1069 +** Reference URL: https://attack.mitre.org/techniques/T1069/ +* Sub-technique: +** Name: Cloud Groups +** ID: T1069.003 +** Reference URL: https://attack.mitre.org/techniques/T1069/003/ +* Technique: +** Name: Account Discovery +** ID: T1087 +** Reference URL: https://attack.mitre.org/techniques/T1087/ +* Sub-technique: +** Name: Cloud Account +** ID: T1087.004 +** Reference URL: https://attack.mitre.org/techniques/T1087/004/ +* Technique: +** Name: Cloud Service Discovery +** ID: T1526 +** Reference URL: https://attack.mitre.org/techniques/T1526/ diff --git a/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-azure-diagnostic-settings-deleted.asciidoc b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-azure-diagnostic-settings-deleted.asciidoc new file mode 100644 index 0000000000..8976125df1 --- /dev/null +++ b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-azure-diagnostic-settings-deleted.asciidoc @@ -0,0 +1,154 @@ +[[prebuilt-rule-8-19-37-azure-diagnostic-settings-deleted]] +=== Azure Diagnostic Settings Deleted + +Identifies deletion of Azure diagnostic settings for a resource group that has not had this operation in the prior 7 days. Diagnostic settings send platform logs and metrics to Log Analytics, Event Hubs, or storage; removing them blinds monitoring and detection. This rule uses an ES|QL first-seen (new terms) approach keyed on the resource group so groups that constantly churn logging configuration are suppressed after the first occurrence, while a newly seen group still alerts. + +*Rule type*: esql + +*Rule indices*: None + +*Severity*: medium + +*Risk score*: 47 + +*Runs every*: 5m + +*Searches indices from*: now-7d ({ref}/common-options.html#date-math[Date Math format], see also <>) + +*Maximum alerts per execution*: 100 + +*References*: + +* https://docs.microsoft.com/en-us/azure/azure-monitor/platform/diagnostic-settings +* https://www.microsoft.com/en-us/security/blog/2025/10/20/inside-the-attack-chain-threat-activity-targeting-azure-blob-storage/ + +*Tags*: + +* Domain: Cloud +* Data Source: Azure +* Data Source: Azure Activity Logs +* Use Case: Threat Detection +* Tactic: Defense Evasion +* Resources: Investigation Guide +* Noise: Low +* Performance: Normal +* Profile: Recommended +* Rule Type: ES|QL +* Platform: Azure +* Service: Azure Resource Manager + +*Version*: 112 + +*Rule authors*: + +* Elastic + +*Rule license*: Elastic License v2 + + +==== Investigation guide + + + +*Triage and analysis* + + + +*Investigating Azure Diagnostic Settings Deleted* + + +Azure Diagnostic Settings are crucial for monitoring and logging platform activities, sending data to various destinations for analysis. Adversaries may delete these settings to hinder detection and analysis of their activities, effectively evading defenses. The detection rule identifies such deletions by aggregating successful `DIAGNOSTICSETTINGS/DELETE` operations over a 7-day lookback and alerting when a resource group's first delete in that window falls in the current schedule interval. + + +*Possible investigation steps* + + +- Identify the user or service principal responsible for the deletion from `Esql.principal_id_values` and `Esql.principal_type_values`. Resolve the human-readable name from `Esql.initiated_by_user_values`. +- If this is a service principal, determine which application is associated with it via `Esql.appid_values` and examine credential use with authentication sources to identify potential compromise. +- Examine the resource group (`azure.resource.group`) and subscription (`Esql.subscription_id_values`) context to understand the scope of the deletion and whether it affects critical resources. +- Check `Esql.first_time_seen` to determine when the diagnostic settings were removed and correlate this with other security events or alerts around the same time. Pivot on `Esql.session_id_values`, `Esql.unique_token_id_values`, and `Esql.correlation_id_values`. +- Investigate the affected resources by identifying which diagnostic settings were deleted (`Esql.resource_name_values`, `Esql.resource_id_values`) and assess the potential impact on monitoring and logging capabilities. +- Review any recent changes or activities performed by the identified user or service principal to determine if there are other suspicious actions that might indicate malicious intent. Review `Esql.role_values` and `Esql.role_assignment_id_values`. +- Assess the current security posture by ensuring that diagnostic settings are reconfigured and that logging and monitoring are restored to maintain visibility into platform activities. + + +*False positive analysis* + + +- Examine the service principal or user account involved in the deletion to determine if it is part of an automated process or legitimate administrative activity. +- Automated scripts or tools used for managing Azure resources might delete diagnostic settings as part of their operation. Review and whitelist these scripts if they are verified as non-threatening. +- Changes in organizational policy or compliance requirements could lead to legitimate deletions. Confirm with relevant teams if such policy changes are in effect. +- Test environments often undergo frequent configuration changes, including the deletion of diagnostic settings. Consider excluding these environments from the rule or adjusting the rule to account for their unique behavior. +- Ensure that any third-party integrations or services with access to Azure resources are reviewed, as they might inadvertently delete diagnostic settings during their operations. + + +*Response and remediation* + + +- Immediately isolate affected Azure resources to prevent further unauthorized changes or deletions. This may involve temporarily restricting access to the affected subscriptions or resource groups. +- Review the Azure activity logs to identify the source of the deletion request, including the user account, service principal and IP address involved. This will help determine if the action was authorized or malicious. +- Recreate the deleted diagnostic settings as soon as possible to restore logging and monitoring capabilities. Ensure that logs are being sent to secure and appropriate destinations. +- Conduct a thorough investigation of the user account or service principal involved in the deletion. If the account is compromised, reset credentials, and review permissions to ensure they are appropriate and follow the principle of least privilege. +- Escalate the incident to the security operations team for further analysis and to determine if additional resources or expertise are needed to address the threat. +- Implement additional monitoring and alerting for similar deletion activities to ensure rapid detection and response to future attempts. +- Review and update access controls and policies related to diagnostic settings to prevent unauthorized deletions, ensuring that only trusted and necessary personnel have the ability to modify these settings. + + +==== Rule query + + +[source, js] +---------------------------------- +FROM logs-azure.activitylogs-* +| WHERE data_stream.dataset == "azure.activitylogs" + AND event.action == "MICROSOFT.INSIGHTS/DIAGNOSTICSETTINGS/DELETE" + AND event.outcome IN ("success", "Success") + AND azure.resource.group IS NOT NULL +| STATS Esql.first_time_seen = MIN(@timestamp), + Esql.last_time_seen = MAX(@timestamp), + Esql.event_count = COUNT(*), + Esql.event_action_values = VALUES(event.action), + Esql.resource_name_values = VALUES(azure.resource.name), + Esql.resource_id_values = VALUES(azure.resource.id), + Esql.resource_provider_values = VALUES(azure.resource.provider), + Esql.principal_id_values = VALUES(azure.activitylogs.identity.authorization.evidence.principal_id), + Esql.principal_type_values = VALUES(azure.activitylogs.identity.authorization.evidence.principal_type), + Esql.initiated_by_user_values = VALUES(azure.activitylogs.identity.claims_initiated_by_user.name), + Esql.appid_values = VALUES(azure.activitylogs.identity.claims.appid), + Esql.session_id_values = VALUES(azure.activitylogs.identity.claims.sid), + Esql.unique_token_id_values = VALUES(azure.activitylogs.identity.claims.uti), + Esql.correlation_id_values = VALUES(azure.correlation_id), + Esql.role_values = VALUES(azure.activitylogs.identity.authorization.evidence.role), + Esql.role_assignment_id_values = VALUES(azure.activitylogs.identity.authorization.evidence.role_assignment_id), + Esql.role_assignment_scope_values = VALUES(azure.activitylogs.identity.authorization.evidence.role_assignment_scope), + Esql.source_ip_values = VALUES(source.ip), + Esql.source_country_values = VALUES(source.geo.country_name), + Esql.source_as_number_values = VALUES(source.`as`.number), + Esql.subscription_id_values = VALUES(azure.subscription_id) + BY azure.resource.group +// new terms emulation: fire when this resource group's first_seen falls in the current interval +// (schedule + ingest-lag buffer), i.e. it was absent from the rest of the 7-day window +| EVAL Esql.recent_minutes = DATE_DIFF("minute", Esql.first_time_seen, NOW()) +| WHERE Esql.recent_minutes <= 10 +| KEEP azure.*, Esql.* + +---------------------------------- + +*Framework*: MITRE ATT&CK^TM^ + +* Tactic: +** Name: Defense Evasion +** ID: TA0005 +** Reference URL: https://attack.mitre.org/tactics/TA0005/ +* Technique: +** Name: Impair Defenses +** ID: T1562 +** Reference URL: https://attack.mitre.org/techniques/T1562/ +* Sub-technique: +** Name: Disable or Modify Tools +** ID: T1562.001 +** Reference URL: https://attack.mitre.org/techniques/T1562/001/ +* Sub-technique: +** Name: Disable or Modify Cloud Logs +** ID: T1562.008 +** Reference URL: https://attack.mitre.org/techniques/T1562/008/ diff --git a/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-azure-key-vault-multi-vault-secret-retrieval-burst-by-application.asciidoc b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-azure-key-vault-multi-vault-secret-retrieval-burst-by-application.asciidoc new file mode 100644 index 0000000000..55286b3504 --- /dev/null +++ b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-azure-key-vault-multi-vault-secret-retrieval-burst-by-application.asciidoc @@ -0,0 +1,148 @@ +[[prebuilt-rule-8-19-37-azure-key-vault-multi-vault-secret-retrieval-burst-by-application]] +=== Azure Key Vault Multi-Vault Secret Retrieval Burst by Application + +Identifies a burst of successful Azure Key Vault secret retrievals by the same principal and application across multiple vaults. Adversaries with compromised application credentials may collect stored secrets at scale to access additional services or move laterally. + +*Rule type*: esql + +*Rule indices*: None + +*Severity*: medium + +*Risk score*: 47 + +*Runs every*: 5m + +*Searches indices from*: now-30m ({ref}/common-options.html#date-math[Date Math format], see also <>) + +*Maximum alerts per execution*: 100 + +*References*: + +* https://www.microsoft.com/en-us/security/blog/2026/10/21/storm-0940-uses-artex-agentic-ai-connectwise-supply-chain-compromise/ +* https://learn.microsoft.com/en-us/azure/key-vault/general/logging + +*Tags*: + +* Domain: Cloud +* Domain: Identity +* Data Source: Azure +* Data Source: Azure Platform Logs +* Use Case: Threat Detection +* Tactic: Credential Access +* Resources: Investigation Guide +* Rule Type: ES|QL +* Platform: Azure +* Service: Azure Key Vault + +*Version*: 1 + +*Rule authors*: + +* Elastic + +*Rule license*: Elastic License v2 + + +==== Investigation guide + + + +*Triage and analysis* + + + +*Investigating Azure Key Vault Multi-Vault Secret Retrieval Burst by Application* + + +Azure Key Vault stores credentials that applications use to access other services. A compromised identity can use its existing vault permissions to collect these credentials and extend access to additional resources. This rule matches the Storm-0940 hunting pattern: at least 20 successful SecretGet requests by one principal and application across at least three vaults in a 15-minute window. Single-vault application startup and refresh traffic is outside this threshold. Repeated reads of the same secret still count toward the volume. + + +*Possible investigation steps* + + +- Identify the principal and application using `azure.platformlogs.identity.claim.oid` and `azure.platformlogs.identity.claim.appid`. Use `azure.platformlogs.identity.claim.iss` to establish the issuing tenant, and resolve the object against the tenant's identity inventory. +- Review `Esql.time_window`, `Esql.secret_read_count`, `Esql.vault_count`, `Esql.vaults`, and `Esql.source_ips` to establish the access volume, affected vaults, and request sources. +- Review the original events and the `azure.platformlogs.properties.requestUri` and `azure.platformlogs.properties.id` values to identify the secrets accessed. Confirm successful retrieval using `azure.platformlogs.properties.httpStatusCode`; the normalized event outcome alone may not distinguish reads from denials. +- Determine whether the principal is an application, managed identity, or user acting through an application. Application and object claims can also appear in delegated tokens, and an absent user principal name does not establish app-only authentication. +- Correlate the activity with service-principal or managed-identity sign-ins, recent credential additions, permission changes, and access to services that use the retrieved secrets. +- Check whether the application owner expected a multi-vault inventory, migration, or deployment during the alert window. + + +*False positive analysis* + + +- Authorized inventory, migration, and multi-vault deployment pipelines can produce this pattern. Compare the vault set and sources with the application's normal activity and change records. +- Scope any justified exception to the issuer, principal, application, and expected vault set, and reassess it when ownership or permissions change. + + +*Response and remediation* + + +- If compromise is confirmed, restrict the principal's access to the affected vaults and remove compromised application credentials according to the incident response process. +- Determine which secrets were exposed and rotate them, including credentials for downstream services where necessary. +- Review and remove unauthorized permissions or credentials associated with the principal. Verify that access is denied after containment; removing an application credential alone does not immediately invalidate every issued access token. +- Preserve the relevant Key Vault, sign-in, and audit events for investigation. + + +==== Setup + + + +*Azure Key Vault AuditEvent Logs* + + +Enable AuditEvent diagnostic logging for the relevant Key Vaults and ingest it through the Azure integration's +platform logs data stream into `logs-azure.platformlogs-*`. Retain the token issuer, object ID, application ID, +vault resource ID, and HTTP status in the original events. The HTTP status is a subfield of the flattened +`azure.platformlogs.properties` field and is selected with KQL. Events missing the required identity or vault +fields are excluded. A user principal name is not required. + +The rule evaluates a 30-minute ingestion lookback every five minutes and groups requests into fixed 15-minute +event-time windows. Requests split across window boundaries or ingested more than 30 minutes apart may not be +combined. Review delivery latency and repeated aggregate alerts when tuning the schedule. + + +==== Rule query + + +[source, js] +---------------------------------- +from logs-azure.platformlogs-* metadata _id, _index +| where data_stream.dataset == "azure.platformlogs" + and event.action == "SecretGet" + and azure.platformlogs.identity.claim.iss is not null and azure.platformlogs.identity.claim.iss != "" + and azure.platformlogs.identity.claim.oid is not null and azure.platformlogs.identity.claim.oid != "" + and azure.platformlogs.identity.claim.appid is not null and azure.platformlogs.identity.claim.appid != "" + and azure.resource.id is not null and azure.resource.id != "" + and KQL("azure.platformlogs.properties.httpStatusCode:200") +| eval Esql.time_window = date_trunc(15 minutes, @timestamp) +| stats + Esql.secret_read_count = count(*), + Esql.vault_count = count_distinct(azure.resource.id), + Esql.vaults = values(azure.resource.id), + Esql.source_ips = values(source.ip), + Esql.first_seen = min(@timestamp), + Esql.last_seen = max(@timestamp) + by Esql.time_window, azure.platformlogs.identity.claim.iss, azure.platformlogs.identity.claim.oid, + azure.platformlogs.identity.claim.appid +| where Esql.secret_read_count >= 20 and Esql.vault_count >= 3 +| keep azure.platformlogs.identity.claim.iss, azure.platformlogs.identity.claim.oid, + azure.platformlogs.identity.claim.appid, Esql.* + +---------------------------------- + +*Framework*: MITRE ATT&CK^TM^ + +* Tactic: +** Name: Credential Access +** ID: TA0006 +** Reference URL: https://attack.mitre.org/tactics/TA0006/ +* Technique: +** Name: Credentials from Password Stores +** ID: T1555 +** Reference URL: https://attack.mitre.org/techniques/T1555/ +* Sub-technique: +** Name: Cloud Secrets Management Stores +** ID: T1555.006 +** Reference URL: https://attack.mitre.org/techniques/T1555/006/ diff --git a/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-azure-resource-group-deleted-by-unusual-principal.asciidoc b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-azure-resource-group-deleted-by-unusual-principal.asciidoc new file mode 100644 index 0000000000..d33a6b130e --- /dev/null +++ b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-azure-resource-group-deleted-by-unusual-principal.asciidoc @@ -0,0 +1,163 @@ +[[prebuilt-rule-8-19-37-azure-resource-group-deleted-by-unusual-principal]] +=== Azure Resource Group Deleted by Unusual Principal + +Identifies Azure resource group deletions by a principal that has not performed this operation in the prior 7 days. Deletion of a resource group is permanent and removes all resources in the group. This rule uses an ES|QL first-seen (new terms) approach keyed on the acting principal so routine infrastructure-as-code teardown is suppressed after the first occurrence, while still surfacing first-time or unusual identities performing the delete. + +*Rule type*: esql + +*Rule indices*: None + +*Severity*: medium + +*Risk score*: 47 + +*Runs every*: 5m + +*Searches indices from*: now-7d ({ref}/common-options.html#date-math[Date Math format], see also <>) + +*Maximum alerts per execution*: 100 + +*References*: + +* https://docs.microsoft.com/en-us/azure/azure-resource-manager/management/manage-resource-groups-portal + +*Tags*: + +* Domain: Cloud +* Data Source: Azure +* Use Case: Log Auditing +* Tactic: Impact +* Resources: Investigation Guide +* Noise: Low +* Performance: Fast +* Profile: Recommended +* Tactic: Defense Evasion +* Rule Type: ES|QL +* Platform: Azure +* Data Source: Azure Activity Logs +* Service: Azure Resource Manager + +*Version*: 112 + +*Rule authors*: + +* Elastic + +*Rule license*: Elastic License v2 + + +==== Investigation guide + + + +*Triage and analysis* + + + +*Investigating Azure Resource Group Deleted by Unusual Principal* + + +Azure Resource Groups contain related resources for a solution. Deleting a group is irreversible and removes every resource in it. This rule aggregates successful `RESOURCEGROUPS/DELETE` operations over a 7-day lookback and alerts when a principal's first delete in that window falls in the current schedule interval. Repeat deletes by the same automation identity are suppressed; a newly seen user or service principal is not. + + +*Possible investigation steps* + + +- Identify the acting principal from `azure.activitylogs.identity.authorization.evidence.principal_id` and check `Esql.principal_type_values` (User vs ServicePrincipal vs Group). Resolve the human-readable name from `Esql.initiated_by_user_values`. +- Review `Esql.appid_values` and `Esql.role_values` to distinguish first-party / IaC identities from interactive clients such as Azure Portal or Azure CLI. `Esql.role_assignment_id_values` shows which assignment granted delete. +- Pivot on `Esql.session_id_values` (`azure.activitylogs.identity.claims.sid`) and `Esql.unique_token_id_values` to Entra sign-in logs and Microsoft Graph activity for the same session. +- Use `Esql.correlation_id_values` to find related ARM operations (lock removal, mass deletes, RBAC changes) in the same activity-log transaction. +- Inspect `Esql.resource_group_values` and `Esql.resource_id_values` for the groups that were deleted and whether they look like lab, ephemeral, or production naming. +- Check `Esql.source_ip_values`, `Esql.source_country_values`, and `Esql.source_as_number_values`, then correlate Entra ID sign-in logs for the same principal around `Esql.first_time_seen`. +- Look for related activity by the same principal: role assignments, lock removal, mass resource deletes, or snapshot/backup deletion. +- Confirm whether the delete was ticketed or matches a known pipeline / GitOps controller. + + +*False positive analysis* + + +- Crossplane, Terraform, GitHub Actions, and similar automation will alert on the first resource-group delete per principal in 7 days, then go quiet. Exclude verified automation principals after review. +- AKS and other Microsoft-owned control-plane identities may delete managed node resource groups as part of cluster lifecycle. +- Newly provisioned automation identities performing expected teardown will fire once; do not allowlist by tenant or user GUID. + + +*Response and remediation* + + +- If unauthorized, disable the principal, revoke standing Contributor/Owner on the subscription, and place resource locks on remaining critical groups. +- Restore from backup or IaC state if the deleted group hosted production resources. +- Audit other deletes and RBAC changes by the same principal during the same window. +- Require privileged delete operations to go through PIM or a change-control pipeline. + + +==== Rule query + + +[source, js] +---------------------------------- +FROM logs-azure.activitylogs-*, filebeat-* +| WHERE data_stream.dataset == "azure.activitylogs" + AND event.action == "MICROSOFT.RESOURCES/SUBSCRIPTIONS/RESOURCEGROUPS/DELETE" + AND event.outcome IN ("success", "Success") + AND azure.activitylogs.identity.authorization.evidence.principal_id IS NOT NULL +| STATS Esql.first_time_seen = MIN(@timestamp), + Esql.last_time_seen = MAX(@timestamp), + Esql.event_count = COUNT(*), + Esql.resource_group_values = VALUES(azure.resource.group), + Esql.resource_name_values = VALUES(azure.resource.name), + Esql.resource_id_values = VALUES(azure.resource.id), + Esql.principal_type_values = VALUES(azure.activitylogs.identity.authorization.evidence.principal_type), + Esql.initiated_by_user_values = VALUES(azure.activitylogs.identity.claims_initiated_by_user.name), + Esql.appid_values = VALUES(azure.activitylogs.identity.claims.appid), + Esql.session_id_values = VALUES(azure.activitylogs.identity.claims.sid), + Esql.unique_token_id_values = VALUES(azure.activitylogs.identity.claims.uti), + Esql.correlation_id_values = VALUES(azure.correlation_id), + Esql.role_values = VALUES(azure.activitylogs.identity.authorization.evidence.role), + Esql.role_assignment_id_values = VALUES(azure.activitylogs.identity.authorization.evidence.role_assignment_id), + Esql.source_ip_values = VALUES(source.ip), + Esql.source_country_values = VALUES(source.geo.country_name), + Esql.source_as_number_values = VALUES(source.`as`.number), + Esql.subscription_id_values = VALUES(azure.subscription_id) + BY azure.activitylogs.identity.authorization.evidence.principal_id +// new terms emulation: fire when this principal's first_seen falls in the current interval +// (schedule + ingest-lag buffer), i.e. it was absent from the rest of the 7-day window +| EVAL Esql.recent_minutes = DATE_DIFF("minute", Esql.first_time_seen, NOW()) +| WHERE Esql.recent_minutes <= 10 +| KEEP azure.*, Esql.* + +---------------------------------- + +*Framework*: MITRE ATT&CK^TM^ + +* Tactic: +** Name: Impact +** ID: TA0040 +** Reference URL: https://attack.mitre.org/tactics/TA0040/ +* Technique: +** Name: System Shutdown/Reboot +** ID: T1529 +** Reference URL: https://attack.mitre.org/techniques/T1529/ +* Technique: +** Name: Inhibit System Recovery +** ID: T1490 +** Reference URL: https://attack.mitre.org/techniques/T1490/ +* Technique: +** Name: Service Stop +** ID: T1489 +** Reference URL: https://attack.mitre.org/techniques/T1489/ +* Technique: +** Name: Data Destruction +** ID: T1485 +** Reference URL: https://attack.mitre.org/techniques/T1485/ +* Tactic: +** Name: Defense Evasion +** ID: TA0005 +** Reference URL: https://attack.mitre.org/tactics/TA0005/ +* Technique: +** Name: Impair Defenses +** ID: T1562 +** Reference URL: https://attack.mitre.org/techniques/T1562/ +* Sub-technique: +** Name: Disable or Modify Tools +** ID: T1562.001 +** Reference URL: https://attack.mitre.org/techniques/T1562/001/ diff --git a/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-base64-decoded-payload-piped-to-interpreter.asciidoc b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-base64-decoded-payload-piped-to-interpreter.asciidoc new file mode 100644 index 0000000000..f3bd471f0c --- /dev/null +++ b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-base64-decoded-payload-piped-to-interpreter.asciidoc @@ -0,0 +1,216 @@ +[[prebuilt-rule-8-19-37-base64-decoded-payload-piped-to-interpreter]] +=== Base64 Decoded Payload Piped to Interpreter + +This rule detects when a base64 decoded payload is piped to an interpreter on Linux systems. Adversaries may use base64 encoding to obfuscate data and pipe it to an interpreter to execute malicious code. This technique may be used to evade detection by host- or network-based security controls. + +*Rule type*: eql + +*Rule indices*: + +* logs-endpoint.events.process* +* logs-crowdstrike.fdr* + +*Severity*: high + +*Risk score*: 73 + +*Runs every*: 5m + +*Searches indices from*: now-9m ({ref}/common-options.html#date-math[Date Math format], see also <>) + +*Maximum alerts per execution*: 100 + +*References*: None + +*Tags*: + +* Domain: Endpoint +* OS: Linux +* Use Case: Threat Detection +* Tactic: Defense Evasion +* Tactic: Execution +* Data Source: Elastic Defend +* Resources: Investigation Guide +* Data Source: Crowdstrike +* Noise: High +* Performance: Normal +* Profile: Aggressive +* Threat: Encoding-Based Obfuscation +* Rule Type: Event Correlation (EQL) +* Platform: Linux + +*Version*: 13 + +*Rule authors*: + +* Elastic + +*Rule license*: Elastic License v2 + + +==== Investigation guide + + + ## Triage and analysis + +> **Disclaimer**: +> This investigation guide was created using generative AI technology and has been reviewed to improve its accuracy and relevance. While every effort has been made to ensure its quality, we recommend validating the content and adapting it to suit your specific environment and operational needs. + + +*Investigating Base64 Decoded Payload Piped to Interpreter* + + +Base64 encoding is a method to encode binary data into ASCII text, often used for data obfuscation. Adversaries exploit this by encoding malicious payloads and decoding them on a target system, piping the output to interpreters like bash or python for execution. The detection rule identifies such activities by monitoring for processes that decode Base64 and subsequently execute scripts, indicating potential malicious behavior. + + +*Possible investigation steps* + + +- Review the process command line arguments to identify the specific Base64 decoding activity, focusing on the presence of flags like `-d` or `-a` in conjunction with tools such as `base64`, `openssl`, or scripting languages like `python`, `perl`, or `ruby`. +- Examine the parent process entity ID and command line to understand the context in which the Base64 decoding was initiated, identifying any potentially suspicious parent processes. +- Investigate the subsequent interpreter process that was executed, such as `bash`, `python`, or `ruby`, to determine the nature of the script or command being run, looking for any signs of malicious activity. +- Check the timing and sequence of the processes involved to confirm if the Base64 decoding and interpreter execution occurred within the specified maxspan of 3 seconds, indicating a likely automated or scripted action. +- Analyze the host ID and any associated user accounts to determine if the activity aligns with expected behavior for that system or user, or if it suggests unauthorized access or compromise. +- Correlate the alert with other security events or logs from the same host or user to identify any additional indicators of compromise or related suspicious activities. + + +*False positive analysis* + + +- Legitimate administrative scripts may use Base64 encoding to handle data securely. Review the context of the script execution and consider excluding specific scripts or directories from monitoring if they are verified as safe. +- Automated backup or data transfer processes might use Base64 encoding for data integrity. Identify these processes and create exceptions for known, trusted applications or scripts. +- Development environments often use Base64 encoding for testing purposes. If a development tool or script is frequently triggering alerts, consider excluding the specific development environment or user accounts from this rule. +- Security tools or monitoring solutions may use Base64 encoding as part of their normal operations. Verify the source of the alert and exclude known security tools from triggering this rule. +- System updates or package installations might involve Base64 operations. Monitor the timing and context of these alerts and exclude specific update processes if they are consistently identified as false positives. + + +*Response and remediation* + + +- Isolate the affected system from the network to prevent further execution of potentially malicious code and lateral movement. +- Terminate any suspicious processes identified by the detection rule, particularly those involving base64 decoding and piping to interpreters. +- Conduct a forensic analysis of the affected system to identify any additional indicators of compromise, such as unauthorized file modifications or network connections. +- Restore the system from a known good backup if malicious activity is confirmed and the integrity of the system is compromised. +- Update and patch all software and systems to mitigate vulnerabilities that could be exploited by similar techniques. +- Implement enhanced monitoring and logging for base64 decoding activities and interpreter executions to detect similar threats in the future. +- Escalate the incident to the security operations center (SOC) or incident response team for further investigation and to determine if broader organizational impacts exist. + + +==== Setup + + + +*Setup* + + +This rule requires data coming in from Elastic Defend. + + +*Elastic Defend Integration Setup* + +Elastic Defend is integrated into the Elastic Agent using Fleet. Upon configuration, the integration allows the Elastic Agent to monitor events on your host and send data to the Elastic Security app. + + +*Prerequisite Requirements:* + +- Fleet is required for Elastic Defend. +- To configure Fleet Server refer to the https://www.elastic.co/guide/en/fleet/current/fleet-server.html[documentation]. + + +*The following steps should be executed in order to add the Elastic Defend integration on a Linux System:* + +- Go to the Kibana home page and click "Add integrations". +- In the query bar, search for "Elastic Defend" and select the integration to see more details about it. +- Click "Add Elastic Defend". +- Configure the integration name and optionally add a description. +- Select the type of environment you want to protect, either "Traditional Endpoints" or "Cloud Workloads". +- Select a configuration preset. Each preset comes with different default settings for Elastic Agent, you can further customize these later by configuring the Elastic Defend integration policy. https://www.elastic.co/guide/en/security/current/configure-endpoint-integration-policy.html[Helper guide]. +- We suggest selecting "Complete EDR (Endpoint Detection and Response)" as a configuration setting, that provides "All events; all preventions" +- Enter a name for the agent policy in "New agent policy name". If other agent policies already exist, you can click the "Existing hosts" tab and select an existing policy instead. +For more details on Elastic Agent configuration settings, refer to the https://www.elastic.co/guide/en/fleet/8.10/agent-policy.html[helper guide]. +- Click "Save and Continue". +- To complete the integration, select "Add Elastic Agent to your hosts" and continue to the next section to install the Elastic Agent on your hosts. +For more details on Elastic Defend refer to the https://www.elastic.co/guide/en/security/current/install-endpoint.html[helper guide]. + + +==== Rule query + + +[source, js] +---------------------------------- +sequence by host.id, process.parent.entity_id with maxspan=3s + [process where host.os.type == "linux" and event.type == "start" and event.action in ("exec", "ProcessRollup2") and ( + (process.name in ("base64", "base64plain", "base64url", "base64mime", "base64pem", "base32", "base16") and process.command_line like~ "*-*d*") or + (process.name == "openssl" and process.args == "enc" and process.args in ("-d", "-base64", "-a")) or + (process.name like "python*" and + (process.args == "base64" and process.args in ("-d", "-u", "-t")) or + (process.args == "-c" and process.args like "*base64*" and process.command_line like~ "*b64decode*") + ) or + (process.name like "perl*" and process.command_line like~ "*decode_base64*") or + (process.name like "ruby*" and process.args == "-e" and process.command_line like~ "*Base64.decode64*") + )] + [process where host.os.type == "linux" and event.type == "start" and event.action in ("exec", "ProcessRollup2") and process.name like~ ( + "bash", "dash", "sh", "tcsh", "csh", "zsh", "ksh", "fish", "python*", "perl*", "ruby*", "lua*", "php*" + ) and + not ( + ?process.parent.command_line in ( + "bash ./run_tests.sh unit-integration", + "/bin/sh /var/lib/dpkg/info/nmap-common.postinst configure", + "bash -c base64 -d <<< Zm9yIHN2YyBpbiBxZW11LWt2bSBvdnMtdnN3aXRjaGQgbGlidmlydGQgdmlydGxvY2tkIHBhY2VtYWtlciBwY3NkOyBkbyBzeXN0ZW1jdGwgaXMtYWN0aXZlICRzdmM7IGRvbmU= | bash -l" + ) or + process.command_line == "/usr/bin/perl /usr/bin/shasum -a 256" or + ?process.working_directory like ( + "/usr/local/zeek", "/opt/zeek", "/var/lib/docker/overlay2/*/opt/zeek", "/usr/local/zeek_old_install", + "/var/lib/docker/overlay2/*/usr/local/zeek", "/proc/self/fd/*/usr/local/zeek" + ) or + (process.parent.name == "zsh" and ?process.parent.command_line like "*extendedglob*") or + (process.name like "python*" and process.parent.name like "python*") or + process.args like "/tmp/apt-key-gpghome*" or + ?process.parent.executable like ("/home/*/.local/bin/claude", "/home/*/.opencode/bin/opencode", "/home/*/.nvm/*/bin/opencode", "/home/*/.nvm/*/bin/claude") or + ?process.parent.command_line like "*/home/*/.claude/shell-snapshots/snapshot-*" + )] + +---------------------------------- + +*Framework*: MITRE ATT&CK^TM^ + +* Tactic: +** Name: Defense Evasion +** ID: TA0005 +** Reference URL: https://attack.mitre.org/tactics/TA0005/ +* Technique: +** Name: Obfuscated Files or Information +** ID: T1027 +** Reference URL: https://attack.mitre.org/techniques/T1027/ +* Technique: +** Name: Deobfuscate/Decode Files or Information +** ID: T1140 +** Reference URL: https://attack.mitre.org/techniques/T1140/ +* Tactic: +** Name: Execution +** ID: TA0002 +** Reference URL: https://attack.mitre.org/tactics/TA0002/ +* Technique: +** Name: Command and Scripting Interpreter +** ID: T1059 +** Reference URL: https://attack.mitre.org/techniques/T1059/ +* Sub-technique: +** Name: Unix Shell +** ID: T1059.004 +** Reference URL: https://attack.mitre.org/techniques/T1059/004/ +* Sub-technique: +** Name: Python +** ID: T1059.006 +** Reference URL: https://attack.mitre.org/techniques/T1059/006/ +* Sub-technique: +** Name: Lua +** ID: T1059.011 +** Reference URL: https://attack.mitre.org/techniques/T1059/011/ +* Technique: +** Name: User Execution +** ID: T1204 +** Reference URL: https://attack.mitre.org/techniques/T1204/ +* Sub-technique: +** Name: Malicious File +** ID: T1204.002 +** Reference URL: https://attack.mitre.org/techniques/T1204/002/ diff --git a/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-cloud-instance-metadata-credential-path-http-request.asciidoc b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-cloud-instance-metadata-credential-path-http-request.asciidoc new file mode 100644 index 0000000000..6d86820455 --- /dev/null +++ b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-cloud-instance-metadata-credential-path-http-request.asciidoc @@ -0,0 +1,149 @@ +[[prebuilt-rule-8-19-37-cloud-instance-metadata-credential-path-http-request]] +=== Cloud Instance Metadata Credential Path HTTP Request + +Detects HTTP GET requests to the link-local instance metadata service (169.254.169.254) for cloud credential or token paths on AWS, GCP, or Azure. Adversaries and vulnerable workloads use scripts, shells, or application runtimes to read IAM role credentials or OAuth tokens from the metadata API. Requires the Network Packet Capture integration with HTTP decoding on ports 80 and 443 and process enrichment enabled so "process.*" fields are present. + +*Rule type*: eql + +*Rule indices*: + +* logs-network_traffic.http* +* packetbeat-* + +*Severity*: medium + +*Risk score*: 47 + +*Runs every*: 5m + +*Searches indices from*: now-9m ({ref}/common-options.html#date-math[Date Math format], see also <>) + +*Maximum alerts per execution*: 100 + +*References*: + +* https://www.elastic.co/docs/reference/integrations/network_traffic +* https://hackingthe.cloud/aws/general-knowledge/intro_metadata_service/ + +*Tags*: + +* Domain: Cloud +* Domain: Network +* OS: Linux +* OS: Windows +* OS: macOS +* Use Case: Threat Detection +* Tactic: Credential Access +* Data Source: Network Packet Capture +* Resources: Investigation Guide +* Noise: Unknown +* Performance: Fast +* Profile: Recommended +* Threat: IMDS Credential Theft +* Rule Type: Event Correlation (EQL) +* Platform: Windows +* Platform: Linux +* Platform: macOS + +*Version*: 3 + +*Rule authors*: + +* Elastic + +*Rule license*: Elastic License v2 + + +==== Investigation guide + + + +*Triage and analysis* + + + +*Investigating Cloud Instance Metadata Credential Path HTTP Request* + + +This rule matches outbound HTTP GETs to `169.254.169.254` where the URL path requests IAM credentials or cloud OAuth +tokens, filtered to common scripting runtimes, suspicious executable paths, or tool-like user agents. + + +*Investigation steps* + + +- Confirm `url.path` (AWS `security-credentials`, GCP `oauth2/access_token`, Azure `metadata/identity/oauth2/token`). +- Review `process.name`, `process.executable`, and `user_agent.original` — scripted tools and temp-path binaries are higher risk. +- Check `host.name` or `host.hostname` and whether the workload should run on a cloud VM with an instance profile or managed identity. +- Correlate with cloud audit or sign-in logs for role assumption or token use shortly after the request. +- If credentials may have been exposed, rotate the instance role or managed identity and review API activity from that principal. + + +*False positives* + + +- Platform agents and bootstrap scripts on new instances; allowlist by user agent or host group where validated. + + +*Response* + + +- Restrict IMDS access (IMDSv2 hop limit, network policy) and remove unnecessary instance permissions. +- Investigate the host for follow-on credential use or lateral movement. + +Deploy the https://www.elastic.co/docs/reference/integrations/network_traffic[Network Packet Capture] integration via Fleet on cloud workloads. + +- Enable **Capture HTTP Traffic** and include ports **80** and **443**. +- Enable **Monitor Processes** so network events include the process that initiated the connection. +- Network Packet Capture 2.0.0 and later always applies ECS compatibility remapping. On earlier integration versions, + enable `map_to_ecs` (the default since 1.31.1). + +==== Setup + + +Deploy the Network Packet Capture integration via Fleet on cloud workloads. + +Enable Capture HTTP Traffic and include ports 80 and 443.Enable Monitor Processes so network events include the process that initiated the connection.Network Packet Capture 2.0.0 and later always applies ECS compatibility remapping. On earlier integration versions, +enable `map_to_ecs` (the default since 1.31.1). + +==== Rule query + + +[source, js] +---------------------------------- +network where event.module == "network_traffic" and destination.ip == "169.254.169.254" and destination.port == 80 and +http.request.method == "GET" and url.path : ( + "/latest/meta-data/iam/security-credentials/*", + "*computeMetadata/v1/instance/service-accounts/*/oauth2/access_token*", + "*metadata/identity/oauth2/token*" +) and ( + ?process.name : ( + "curl", "wget", "python*", "node", "bun", "php*", "ruby", "perl", "bash", "dash", "sh", "tcsh", "tclsh", "wish", + "csh", "zsh", "ksh", "fish", "mksh", "busybox", + "bun.exe", "node.exe", "powershell.exe", "cmd.exe", "curl.exe", "wget.exe", "rundll32.exe", "w3wp.exe", "java*", + "go", "nc", "netcat", "nginx", "apache*", "httpd", "tomcat*", "catalina", "spring*", "dotnet", "gunicorn", "uwsgi", + ".*", "osascript" + ) or ?process.executable : ( + "/tmp/*", "/var/tmp/*", "/dev/shm/*", "/home/*/*", "/var/run/*", "/run/*", "/boot/*", "/.*", "C:\\Users\\*", "?:\\ProgramData\\*" + ) or user_agent.original : ( + "curl*", "wget*", "python*", "ruby*", "Go-http-client*", "node*", "axios*", "undici*", "java*", "php*", "Bun*", + "Apache-HttpClient*", "okhttp*", "RestTemplate*", "*WindowsPowerShell*", "*roadtools*", "*fasthttp*", "*azurehound*", "*bloodhound*", "*aiohttp*" + ) +) + +---------------------------------- + +*Framework*: MITRE ATT&CK^TM^ + +* Tactic: +** Name: Credential Access +** ID: TA0006 +** Reference URL: https://attack.mitre.org/tactics/TA0006/ +* Technique: +** Name: Unsecured Credentials +** ID: T1552 +** Reference URL: https://attack.mitre.org/techniques/T1552/ +* Sub-technique: +** Name: Cloud Instance Metadata API +** ID: T1552.005 +** Reference URL: https://attack.mitre.org/techniques/T1552/005/ diff --git a/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-entra-id-managed-device-client-sign-in-to-graph-enumeration.asciidoc b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-entra-id-managed-device-client-sign-in-to-graph-enumeration.asciidoc new file mode 100644 index 0000000000..a295365d82 --- /dev/null +++ b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-entra-id-managed-device-client-sign-in-to-graph-enumeration.asciidoc @@ -0,0 +1,332 @@ +[[prebuilt-rule-8-19-37-entra-id-managed-device-client-sign-in-to-graph-enumeration]] +=== Entra ID Managed Device Client Sign-In to Graph Enumeration + +Identifies a successful non-interactive Microsoft Entra ID client sign-in for Microsoft Graph that carries managed, joined device context and reports an Edge client when the exact access token is subsequently used by a scripted client to query at least three distinct Microsoft Graph directory-enumeration paths. The rule correlates the Entra sign-in token identifier with Microsoft Graph activity rather than relying on the broader session identifier, which can be shared by legitimate application activity and multiple tokens. + +*Rule type*: esql + +*Rule indices*: None + +*Severity*: medium + +*Risk score*: 47 + +*Runs every*: 5m + +*Searches indices from*: now-60m ({ref}/common-options.html#date-math[Date Math format], see also <>) + +*Maximum alerts per execution*: 100 + +*References*: + +* https://github.com/dirkjanm/askWAM +* https://github.com/SpecterOps/AzureHound +* https://github.com/dafthack/GraphRunner +* https://github.com/mlcsec/Graphpython + +*Tags*: + +* Domain: Cloud +* Domain: Identity +* Data Source: Azure +* Data Source: Microsoft Graph Activity Logs +* Platform: Entra ID +* Use Case: Identity and Access Audit +* Use Case: Threat Detection +* Resources: Investigation Guide +* Rule Type: ESQL +* Tactic: Defense Evasion +* Tactic: Discovery + +*Version*: 1 + +*Rule authors*: + +* Elastic + +*Rule license*: Elastic License v2 + + +==== Investigation guide + + + +*Triage and analysis* + + + +*Investigating Entra ID Managed Device Client Sign-In to Graph Enumeration* + + +This rule joins a non-interactive Entra sign-in to Microsoft Graph activity using the exact token identifier: +`azure.signinlogs.properties.unique_token_identifier` on the sign-in and `token.id` on Graph activity. The shared +session ID, user ID, and application ID provide supporting context but are not sufficient correlation keys by +themselves. + +The sign-in half requires an `Azure AD joined` trust type, a non-empty device ID, managed device status, an incoming +refresh token or Primary Refresh Token, the Microsoft Graph resource, a mobile or desktop client, and a parsed Edge +user agent. These values describe the device and client context asserted in the sign-in; they do not prove the request +originated from that physical device or that WAM/WinRT generated it. + + +*Possible investigation steps* + + +- Review `Esql.token_id`, `Esql.azure_signinlogs_properties_id_values`, and + `Esql.azure_graphactivitylogs_properties_operation_id_values` to pivot to the original events. +- Compare `Esql.user_agent_original_client_signin_values` with + `Esql.user_agent_original_scripted_enum_values`. A client sign-in followed by PowerShell, Python, + AzureHound, a generic HTTP library, or another scripted Graph client using the same token can indicate unauthorized + access-token use. +- A browser-like Graph user agent does not clear the activity. GraphRunner and Graphpython can forge browser strings; + this rule intentionally avoids matching broad Mozilla, Chrome, Edge, or Safari values because they are too noisy. +- Review `Esql.url_original_values` and `Esql.url_path_values` to determine what identities, groups, applications, + service principals, roles, or tenant metadata were enumerated. `Esql.url_path_lower_count_distinct` must be at least + three. The count uses the lowercased path, so casing variants of the same path count once. Query parameters and + pagination are not part of `url.path` and do not increase this count. +- Validate `Esql.app_id`, `Esql.user_id`, `Esql.session_id`, `Esql.device_id`, and source addresses. +- Review adjacent Endpoint telemetry for unusual access to + `Microsoft\TokenBroker\Cache\*.tbres`, WAM-related call stacks, or untrusted processes loading `vaultcli.dll`. +- Do not require `azure.graphactivitylogs.properties.token_issued_at` to equal the sign-in time. Access-token issue + times can be backdated for clock-skew tolerance; the token identifier is the precise join key. + + +*False positive analysis* + + +- First-party Microsoft desktop applications commonly satisfy the sign-in half of this rule. The suspicious behavior + is the same access token subsequently appearing from a scripted client against a directory-enumeration path. +- Confirm whether the user routinely uses Microsoft Graph PowerShell, custom administration scripts, or development + tools that acquire and use delegated access tokens. +- Determine whether the requested paths align with an approved administrative workflow. +- Prefer narrowly scoped exceptions for reviewed user and application combinations rather than excluding a scripted + user agent globally. + + +*Response and remediation* + + +- Revoke active user sessions and refresh tokens if the activity is unauthorized. +- Review all Graph activity associated with the token ID and session ID for additional discovery or data access. +- Investigate the originating endpoint for token theft, export, or unauthorized scripted use. +- Review Conditional Access and token-protection controls for the affected user and application. + + +==== Setup + + + +*Required Microsoft Entra ID and Microsoft Graph logs* + + +Enable Microsoft Entra ID sign-in logs and Microsoft Graph activity logs through the Azure integration. The rule +requires `azure.signinlogs.properties.unique_token_identifier` and the normalized Graph `token.id` field so it can +join issuance and use of the same access token. + + +==== Rule query + + +[source, js] +---------------------------------- +FROM logs-azure.signinlogs-*, logs-azure.graphactivitylogs-* METADATA _id, _version, _index + +// normalize the token, user, app, device and session ids +| EVAL + Esql.token_id = COALESCE( + azure.signinlogs.properties.unique_token_identifier, + token.id + ), + Esql.session_id = COALESCE( + azure.signinlogs.properties.session_id, + azure.graphactivitylogs.properties.c_sid + ), + Esql.user_id = COALESCE( + azure.signinlogs.properties.user_id, + azure.graphactivitylogs.properties.user_principal_object_id + ), + Esql.app_id = COALESCE( + azure.signinlogs.properties.app_id, + azure.graphactivitylogs.properties.app_id + ), + Esql.device_id = COALESCE( + azure.signinlogs.properties.device_detail.device_id, + azure.graphactivitylogs.properties.c_device_id + ), + Esql.user_agent_original_lower = TO_LOWER(user_agent.original), + Esql.url_path_lower = TO_LOWER(url.path) + +// filter for Entra ID client sign-in and token acquisition context +| WHERE + Esql.token_id IS NOT NULL AND + Esql.session_id IS NOT NULL AND + Esql.user_id IS NOT NULL AND + Esql.app_id IS NOT NULL AND + Esql.device_id IS NOT NULL AND + Esql.device_id != "" +| EVAL Esql.azure_signinlogs_is_client_signin = + event.dataset == "azure.signinlogs" AND + azure.signinlogs.properties.status.error_code == 0 AND + azure.signinlogs.properties.device_detail.trust_type == "Azure AD joined" AND + azure.signinlogs.properties.device_detail.device_id IS NOT NULL AND + azure.signinlogs.properties.device_detail.device_id != "" AND + azure.signinlogs.properties.device_detail.is_managed == true AND + azure.signinlogs.properties.is_interactive == false AND + azure.signinlogs.properties.incoming_token_type IN ("refreshToken", "primaryRefreshToken") AND + azure.signinlogs.properties.client_app_used == "Mobile Apps and Desktop clients" AND + azure.signinlogs.properties.resource_id == "00000003-0000-0000-c000-000000000000" AND + user_agent.name == "Edge" + +// filter for scripted Graph enumeration for a user identity +// based on red teaming tooling and in-the-wild observations +| EVAL Esql.azure_graphactivitylogs_is_scripted_enum = + event.dataset == "azure.graphactivitylogs" AND + azure.graphactivitylogs.properties.c_idtyp == "user" AND + azure.graphactivitylogs.properties.client_auth_method == 0 AND + http.request.method == "GET" AND + ( + Esql.user_agent_original_lower LIKE "*powershell*" OR + Esql.user_agent_original_lower LIKE "*python-requests/*" OR + Esql.user_agent_original_lower LIKE "*python-httpx/*" OR + Esql.user_agent_original_lower LIKE "*curl/*" OR + Esql.user_agent_original_lower LIKE "*aiohttp/*" OR + Esql.user_agent_original_lower LIKE "*fasthttp*" OR + Esql.user_agent_original_lower LIKE "*go-http-client/*" OR + Esql.user_agent_original_lower LIKE "*go-resty/*" OR + Esql.user_agent_original_lower LIKE "*okhttp/*" OR + Esql.user_agent_original_lower LIKE "*restsharp/*" OR + Esql.user_agent_original_lower LIKE "*postmanruntime/*" OR + Esql.user_agent_original_lower LIKE "*axios/*" OR + Esql.user_agent_original_lower == "node" OR + Esql.user_agent_original_lower LIKE "*node-fetch/*" OR + Esql.user_agent_original_lower LIKE "*undici*" OR + Esql.user_agent_original_lower LIKE "*azurehound/*" OR + Esql.user_agent_original_lower LIKE "*sharphound/*" OR + Esql.user_agent_original_lower LIKE "*bloodhound/*" OR + Esql.user_agent_original_lower LIKE "*aadinternals*" OR + Esql.user_agent_original_lower LIKE "*bav2ropc*" OR + Esql.user_agent_original_lower LIKE "*roadtools*" OR + Esql.user_agent_original_lower LIKE "*roadrecon*" OR + Esql.user_agent_original_lower LIKE "*roadtx*" OR + Esql.user_agent_original_lower LIKE "*graphpython*" OR + Esql.user_agent_original_lower LIKE "*msgraphx*" + ) AND + ( + // Documented collection reads. Query parameters are not part of url.path. + Esql.url_path_lower IN ( + "/v1.0/users", + "/beta/users", + "/v1.0/groups", + "/beta/groups", + "/v1.0/applications", + "/beta/applications", + "/v1.0/serviceprincipals", + "/beta/serviceprincipals", + "/v1.0/devices", + "/beta/devices", + "/v1.0/directoryroles", + "/beta/directoryroles", + "/v1.0/organization", + "/beta/organization", + "/v1.0/subscribedskus", + "/beta/subscribedskus", + "/v1.0/rolemanagement/directory/roledefinitions", + "/beta/rolemanagement/directory/roledefinitions", + "/v1.0/rolemanagement/directory/roleassignments", + "/beta/rolemanagement/directory/roleassignments", + "/v1.0/rolemanagement/directory/roleeligibilityschedules", + "/beta/rolemanagement/directory/roleeligibilityschedules", + "/v1.0/rolemanagement/directory/roleeligibilityscheduleinstances", + "/beta/rolemanagement/directory/roleeligibilityscheduleinstances" + ) + ) +| WHERE Esql.azure_signinlogs_is_client_signin OR Esql.azure_graphactivitylogs_is_scripted_enum + +// aggregate the events for the rule by session, user, app, device, token and tenant +| STATS + Esql.azure_signinlogs_properties_id_count_distinct = COUNT_DISTINCT( + azure.signinlogs.properties.id + ) WHERE Esql.azure_signinlogs_is_client_signin, + Esql.azure_graphactivitylogs_properties_operation_id_count_distinct = COUNT_DISTINCT( + azure.graphactivitylogs.properties.operation_id + ) WHERE Esql.azure_graphactivitylogs_is_scripted_enum, + Esql.url_path_lower_count_distinct = COUNT_DISTINCT( + Esql.url_path_lower + ) WHERE Esql.azure_graphactivitylogs_is_scripted_enum, + Esql.timestamp_client_signin_min = MIN( + CASE(Esql.azure_signinlogs_is_client_signin, @timestamp, NULL) + ), + Esql.timestamp_scripted_enum_min = MIN( + CASE(Esql.azure_graphactivitylogs_is_scripted_enum, @timestamp, NULL) + ), + Esql.user_agent_original_client_signin_values = VALUES( + user_agent.original + ) WHERE Esql.azure_signinlogs_is_client_signin, + Esql.user_agent_original_scripted_enum_values = VALUES( + user_agent.original + ) WHERE Esql.azure_graphactivitylogs_is_scripted_enum, + Esql.url_path_values = VALUES(url.path) WHERE Esql.azure_graphactivitylogs_is_scripted_enum, + Esql.url_original_values = VALUES(url.original) WHERE Esql.azure_graphactivitylogs_is_scripted_enum, + Esql.source_ip_values = VALUES(source.ip), + Esql.azure_signinlogs_properties_id_values = VALUES( + azure.signinlogs.properties.id + ) WHERE Esql.azure_signinlogs_is_client_signin, + Esql.azure_graphactivitylogs_properties_operation_id_values = VALUES( + azure.graphactivitylogs.properties.operation_id + ) WHERE Esql.azure_graphactivitylogs_is_scripted_enum, + Esql.azure_signinlogs_properties_app_display_name_values = VALUES( + azure.signinlogs.properties.app_display_name + ) WHERE Esql.azure_signinlogs_is_client_signin, + Esql_priv.azure_signinlogs_properties_user_principal_name_values = VALUES( + azure.signinlogs.properties.user_principal_name + ) WHERE Esql.azure_signinlogs_is_client_signin + BY + Esql.token_id, + Esql.session_id, + Esql.user_id, + Esql.app_id, + Esql.device_id, + azure.tenant_id + +// filter by client sign-in and scripted Graph enumeration events +| WHERE + Esql.azure_signinlogs_properties_id_count_distinct > 0 AND + Esql.azure_graphactivitylogs_properties_operation_id_count_distinct > 0 AND + Esql.url_path_lower_count_distinct >= 3 AND + Esql.timestamp_client_signin_min IS NOT NULL AND + Esql.timestamp_scripted_enum_min IS NOT NULL AND + Esql.timestamp_scripted_enum_min >= Esql.timestamp_client_signin_min +| KEEP Esql.*, Esql_priv.*, azure.tenant_id + +---------------------------------- + +*Framework*: MITRE ATT&CK^TM^ + +* Tactic: +** Name: Discovery +** ID: TA0007 +** Reference URL: https://attack.mitre.org/tactics/TA0007/ +* Technique: +** Name: Account Discovery +** ID: T1087 +** Reference URL: https://attack.mitre.org/techniques/T1087/ +* Sub-technique: +** Name: Cloud Account +** ID: T1087.004 +** Reference URL: https://attack.mitre.org/techniques/T1087/004/ +* Technique: +** Name: Cloud Service Discovery +** ID: T1526 +** Reference URL: https://attack.mitre.org/techniques/T1526/ +* Tactic: +** Name: Defense Evasion +** ID: TA0005 +** Reference URL: https://attack.mitre.org/tactics/TA0005/ +* Technique: +** Name: Use Alternate Authentication Material +** ID: T1550 +** Reference URL: https://attack.mitre.org/techniques/T1550/ +* Sub-technique: +** Name: Application Access Token +** ID: T1550.001 +** Reference URL: https://attack.mitre.org/techniques/T1550/001/ diff --git a/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-entra-id-user-sign-in-with-unusual-client.asciidoc b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-entra-id-user-sign-in-with-unusual-client.asciidoc new file mode 100644 index 0000000000..1aaece9088 --- /dev/null +++ b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-entra-id-user-sign-in-with-unusual-client.asciidoc @@ -0,0 +1,264 @@ +[[prebuilt-rule-8-19-37-entra-id-user-sign-in-with-unusual-client]] +=== Entra ID User Sign-in with Unusual Client + +Detects rare non-interactive sign-ins where an Entra ID client application authenticates on behalf of a principal user using an application (client) ID that is not commonly associated with that user's historical sign-in behavior. Adversaries with stolen credentials or OAuth tokens may abuse Entra ID–managed or first-party client IDs to perform on-behalf-of (OBO) authentication, blending into legitimate cloud traffic while avoiding traditional interactive sign-in flows. This technique is commonly observed in OAuth phishing, token theft, and access broker operations, and may precede lateral movement, persistence, or data access via Microsoft Graph or other cloud resources. The rule uses a New Terms approach to identify first-seen combinations of the UPN and Client ID within a defined history window, helping surface unexpected client usage that may indicate compromised identities, malicious automation, or unauthorized application impersonation. + +*Rule type*: new_terms + +*Rule indices*: + +* filebeat-* +* logs-azure.signinlogs-* + +*Severity*: medium + +*Risk score*: 47 + +*Runs every*: 5m + +*Searches indices from*: now-9m ({ref}/common-options.html#date-math[Date Math format], see also <>) + +*Maximum alerts per execution*: 100 + +*References*: + +* https://securityscorecard.com/wp-content/uploads/2025/02/MassiveBotnet-Report_022125_03.pdf + +*Tags*: + +* Domain: Cloud +* Domain: Identity +* Data Source: Azure +* Data Source: Entra ID +* Data Source: Entra ID Sign-In +* Platform: Entra ID +* Use Case: Identity and Access Audit +* Use Case: Threat Detection +* Tactic: Initial Access +* Resources: Investigation Guide +* Noise: High +* Performance: Normal +* Profile: Aggressive +* Rule Type: New Terms + +*Version*: 12 + +*Rule authors*: + +* Elastic + +*Rule license*: Elastic License v2 + + +==== Investigation guide + + + +*Triage and analysis* + + + +*Investigating Entra ID User Sign-in with Unusual Client* + + +This rule identifies rare Azure Entra apps IDs requesting authentication on-behalf-of a principal user. An adversary with stolen credentials may specify an Azure-managed app ID to authenticate on-behalf-of a user. This is a rare event and may indicate an attempt to bypass conditional access policies (CAP) and multi-factor authentication (MFA) requirements. The app ID specified may not be commonly used by the user based on their historical sign-in activity. + + +*Possible investigation steps* + + +- Identify the source IP address from which the failed login attempts originated by reviewing `source.ip`. Determine if the IP is associated with known malicious activity using threat intelligence sources or if it belongs to a corporate VPN, proxy, or automation process. +- Analyze affected user accounts by reviewing `azure.signinlogs.properties.user_principal_name` to determine if they belong to privileged roles or high-value users. Look for patterns indicating multiple failed attempts across different users, which could suggest a password spraying attempt. +- Examine the authentication method used in `azure.signinlogs.properties.authentication_details` to identify which authentication protocols were attempted and why they failed. Legacy authentication methods may be more susceptible to brute-force attacks. +- Review the authentication error codes found in `azure.signinlogs.properties.status.error_code` to understand why the login attempts failed. Common errors include `50126` for invalid credentials, `50053` for account lockouts, `50055` for expired passwords, and `50056` for users without a password. +- Correlate failed logins with other sign-in activity by looking at `event.outcome`. Identify if there were any successful logins from the same user shortly after multiple failures or if there are different geolocations or device fingerprints associated with the same account. +- Review `azure.signinlogs.properties.app_id` to identify which applications were initiating the authentication attempts. Determine if these applications are Microsoft-owned, third-party, or custom applications and if they are authorized to access the resources. +- Check for any conditional access policies that may have been triggered by the failed login attempts by reviewing `azure.signinlogs.properties.authentication_requirement`. This can help identify if the failed attempts were due to policy enforcement or misconfiguration. + + +*False positive analysis* + + +- Automated scripts or applications using non-interactive authentication may trigger this detection, particularly if they rely on legacy authentication protocols recorded in `azure.signinlogs.properties.authentication_protocol`. +- Corporate proxies or VPNs may cause multiple users to authenticate from the same IP, appearing as repeated failed attempts under `source.ip`. +- User account lockouts from forgotten passwords or misconfigured applications may show multiple authentication failures in `azure.signinlogs.properties.status.error_code`. +- Exclude known trusted IPs, such as corporate infrastructure, from alerts by filtering `source.ip`. +- Exclude known custom applications from `azure.signinlogs.properties.app_id` that are authorized to use non-interactive authentication. +- Microsoft Feedback Portal UX generates benign first-seen client activity through PRT-based, non-interactive sign-ins and is excluded by application ID. +- Microsoft Teams routinely requests tokens for its internal Teams Services, IC3 Gateway, Chat Aggregator, and CMD Services resources; these client-resource combinations are excluded. +- Managed Windows devices routinely request OfficeHome PRTs with Microsoft 365 Copilot scopes through the standard Microsoft 365 desktop client; this combination is excluded. +- Ignore principals with a history of failed logins due to legitimate reasons, such as expired passwords or account lockouts, by filtering `azure.signinlogs.properties.user_principal_name`. +- Correlate sign-in failures with password reset events or normal user behavior before triggering an alert. + + +*Response and remediation* + + +- Block the source IP address in `source.ip` if determined to be malicious. +- Reset passwords for all affected user accounts listed in `azure.signinlogs.properties.user_principal_name` and enforce stronger password policies. +- Ensure basic authentication is disabled for all applications using legacy authentication protocols listed in `azure.signinlogs.properties.authentication_protocol`. +- Enable multi-factor authentication (MFA) for impacted accounts to mitigate credential-based attacks. +- Review conditional access policies to ensure they are correctly configured to block unauthorized access attempts recorded in `azure.signinlogs.properties.authentication_requirement`. +- Review Conditional Access policies to enforce risk-based authentication and block unauthorized access attempts recorded in `azure.signinlogs.properties.authentication_requirement`. +- Implement a zero-trust security model by enforcing least privilege access and continuous authentication. +- Regularly review and update conditional access policies to ensure they are effective against evolving threats. +- Restrict the use of legacy authentication protocols by disabling authentication methods listed in `azure.signinlogs.properties.client_app_used`. +- Regularly audit authentication logs in `azure.signinlogs` to detect abnormal login behavior and ensure early detection of potential attacks. +- Regularly rotate client credentials and secrets for applications using non-interactive authentication to reduce the risk of credential theft. + + +==== Rule query + + +[source, js] +---------------------------------- +data_stream.dataset: "azure.signinlogs" and event.category: "authentication" + and azure.signinlogs.properties.is_interactive: false + and azure.signinlogs.properties.user_type: "Member" + and not azure.signinlogs.properties.client_app_used: "Browser" + and not source.as.organization.name: "MICROSOFT-CORP-MSN-AS-BLOCK" + and not azure.signinlogs.properties.app_id: ( + "1b3c667f-cde3-4090-b60b-3d2abd0117f0" or + "26a7ee05-5602-4d76-a7ba-eae8b7b67941" or + "4b0964e4-58f1-47f4-a552-e2e1fc56dcd7" or + "ecd6b820-32c2-49b6-98a6-444530e5a77a" or + "268761a2-03f3-40df-8a8b-c3db24145b6b" or + "fc0f3af4-6835-4174-b806-f7db311fd2f3" or + "de50c81f-5f80-4771-b66b-cebd28ccdfc1" or + "ab9b8c07-8f02-4f72-87fa-80105867a763" or + "6f7e0f60-9401-4f5b-98e2-cf15bd5fd5e3" or + "d7b530a4-7680-4c23-a8bf-c52c121d2e87" or + "52c2e0b5-c7b6-4d11-a89c-21e42bcec444" or + "38aa3b87-a06d-4817-b275-7a316988d93b" or + "27922004-5251-4030-b22d-91ecd9a37ea4" or + "9ba1a5c7-f17a-4de9-a1f1-6178c8d51223" or + "cab96880-db5b-4e15-90a7-f3f1d62ffe39" or + "3a4d129e-7f50-4e0d-a7fd-033add0a29f4" or + "29d9ed98-a469-4536-ade2-f981bc1d605e" or + "c0ab8ce9-e9a0-42e7-b064-33d422df41f1" or + "9ea1ad79-fdb6-4f9a-8bc3-2b70f96e34c7" or + "4813382a-8fa7-425e-ab75-3b753aab3abb" or + "08e18876-6177-487e-b8b5-cf950c1e598c" or + "0ec893e0-5785-4de6-99da-4ed124e5296c" or + "d3590ed6-52b3-4102-aeff-aad2292ab01c" or + "0dc2408a-bbc0-4238-871e-13b372f0200f" or + "af124e86-4e96-495a-b70a-90f90ab96707" or + "e9c51622-460d-4d3d-952d-966a5b1da34c" or + "f44b1140-bc5e-48c6-8dc0-5cf5a53c0e34" or + "e2ef5054-0287-4db6-afa3-013d96881fd3" or + "82864fa0-ed49-4711-8395-a0e6003dca1f" or + "60c8bde5-3167-4f92-8fdb-059f6176dc0f" or + "5d661950-3475-41cd-a2c3-d671a3162bc1" or + "145fc680-eb72-4bcf-b4d5-8277021a1ce8" or + "c1c74fed-04c9-4704-80dc-9f79a2e515cb" or + "a2760c41-63c9-42b5-8d58-bfa1fd9e2eb3" or + "6dec647e-42c4-45a6-8f13-e8250d34e033" or + "c98e5057-edde-4666-b301-186a01b4dc58" or + "0a31c71e-0abf-4238-add7-b1a24c165dc1" or + "a8759234-4b8b-4d94-8c0a-ee1ab73af270" or + "dae89220-69ba-4957-a77a-47b78695e883" or + "fd5f78f6-a28f-450b-abc7-777f3dbbfcba" or + "821caec6-bec3-4542-bead-d3c5fb6b4ef0" or + "a40d7d7d-59aa-447e-a655-679a4107e548" or + "bed12bc0-3a62-470d-998c-e47546e7b039" or + "f4060917-6abe-40d7-baa6-f634c0eda4ac" or + "b26aadf8-566f-4478-926f-589f601d9c74" or + "1f7f6f43-2f81-429c-8499-293566d0ab0c" or + "75f31797-37c9-498e-8dc9-53c16a36afca" or + "3e050dd7-7815-46a0-8263-b73168a42c10" or + "243c63a3-247d-41c5-9d83-7788c43f1c43" or + "75efb5bc-18a1-4e7b-8a66-2ad2503d79c6" or + "d32f3b53-b7d7-48df-8d0f-f8bf233b3f1f" or + "95de633a-083e-42f5-b444-a4295d8e9314" or + "3ff8e6ba-7dc3-4e9e-ba40-ee12b60d6d48" or + "871c010f-5e61-4fb1-83ac-98610a7e9110" or + "3e62f81e-590b-425b-9531-cad6683656cf" or + "8ec6bc83-69c8-4392-8f08-b3c986009232" or + "d326c1ce-6cc6-4de2-bebc-4591e5e13ef0" or + "dd762716-544d-4aeb-a526-687b73838a22" or + "7f8f922d-7ee4-40a6-b435-aad8b84ebde0" or + "f8d98a96-0999-43f5-8af3-69971c7bb423" or + "aa580612-c342-4ace-9055-8edee43ccb89" or + "7f67af8a-fedc-4b08-8b4e-37c4d127b6cf" or + "00bf137d-f689-4c5d-83d9-7fc31904a7ea" or + "ceb96695-e468-48ba-ba21-35e2a242d396" or + "7fba38f4-ec1f-458d-906c-f4e3c4f41335" or + "a2a1fecc-b06e-4a1e-95c1-2afd94bcadff" or + "15ddab63-ba81-45db-9bb6-6f8bc445c459" or + "bc59ab01-8403-45c6-8796-ac3ef710b3e3" or + "00000003-0000-0ff1-ce00-000000000000" or + "4e291c71-d680-4d0e-9640-0a3358e31177" or + "4fb5cc57-dbbc-4cdc-9595-748adff5f414" or + "22098786-6e16-43cc-a27d-191a01a1e3b5" or + "ebde7daf-df42-4ade-81a4-d67b339b49e9" or + "c0d2a505-13b8-4ae0-aa9e-cddd5eab0b12" or + "a672d62c-fc7b-4e81-a576-e60dc46e951d" or + "0b1df6d3-2deb-44d4-b44b-7101937e0726" or + "04f0c124-f2bc-4f59-8241-bf6df9866bbd" or + "86f4c005-6582-4559-b6cf-8b3111236736" or + "a0a3c1d3-7b82-4010-bdb0-e7048fb8f1fe" or + "a187e399-0c36-4b98-8f04-1edc167a0996" or + "2d4d3d8e-2be3-4bef-9f87-7875a61c29de" or + "c475db56-f463-48d8-931a-cfa7cd642289" or + "71a7c376-13e6-4100-968e-92ce98c5d3d2" or + "3138fe80-4087-4b04-80a6-8866c738028a" or + "e8be65d6-d430-4289-a665-51bf2a194bda" or + "bb893c22-978d-4cd4-a6f7-bb6cc0d6e6ce" or + "4354e225-50c9-4423-9ece-2d5afd904870" + ) + and not ( + azure.signinlogs.properties.app_id: "1fec8e78-bce4-4aaf-ab1b-5451cc387264" and + azure.signinlogs.properties.resource_id: ( + "cc15fd57-2c6c-4117-a88c-83b1d56b4bbe" or + "39aaf054-81a5-48c7-a4f8-0293012095b9" or + "b1379a75-ce5e-4fa3-80c6-89bb39bf646c" or + "6bc3b958-689b-49f5-9006-36d165f30e00" + ) + ) + and not ( + azure.signinlogs.properties.app_id: "4765445b-32c6-49b0-83e6-1d93765276ca" and + azure.signinlogs.properties.resource_id: "4765445b-32c6-49b0-83e6-1d93765276ca" and + azure.signinlogs.properties.authentication_processing_details: *M365Copilot.Read.All* and + azure.signinlogs.properties.incoming_token_type: "primaryRefreshToken" and + azure.signinlogs.properties.client_app_used: "Mobile Apps and Desktop clients" and + azure.signinlogs.properties.device_detail.is_managed: true and + azure.signinlogs.properties.device_detail.operating_system: "Windows10" and + user_agent.original: Mozilla*Edge/18.* + ) + +---------------------------------- + +*Framework*: MITRE ATT&CK^TM^ + +* Tactic: +** Name: Initial Access +** ID: TA0001 +** Reference URL: https://attack.mitre.org/tactics/TA0001/ +* Technique: +** Name: Valid Accounts +** ID: T1078 +** Reference URL: https://attack.mitre.org/techniques/T1078/ +* Sub-technique: +** Name: Cloud Accounts +** ID: T1078.004 +** Reference URL: https://attack.mitre.org/techniques/T1078/004/ +* Tactic: +** Name: Credential Access +** ID: TA0006 +** Reference URL: https://attack.mitre.org/tactics/TA0006/ +* Technique: +** Name: Steal Application Access Token +** ID: T1528 +** Reference URL: https://attack.mitre.org/techniques/T1528/ +* Tactic: +** Name: Defense Evasion +** ID: TA0005 +** Reference URL: https://attack.mitre.org/tactics/TA0005/ +* Technique: +** Name: Use Alternate Authentication Material +** ID: T1550 +** Reference URL: https://attack.mitre.org/techniques/T1550/ +* Sub-technique: +** Name: Application Access Token +** ID: T1550.001 +** Reference URL: https://attack.mitre.org/techniques/T1550/001/ diff --git a/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-esxi-curl-or-wget-activity.asciidoc b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-esxi-curl-or-wget-activity.asciidoc new file mode 100644 index 0000000000..ab0424512a --- /dev/null +++ b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-esxi-curl-or-wget-activity.asciidoc @@ -0,0 +1,111 @@ +[[prebuilt-rule-8-19-37-esxi-curl-or-wget-activity]] +=== ESXi Curl or Wget Activity + +Detects `curl` or `wget` from the ESXi shell. These tools download a file or contact a remote URL from the hypervisor. A successful transfer can place a package or script on the host, often under `/tmp`, where a later command can execute it against the datastore. + +*Rule type*: query + +*Rule indices*: + +* logs-vsphere.log-* + +*Severity*: medium + +*Risk score*: 47 + +*Runs every*: 5m + +*Searches indices from*: now-9m ({ref}/common-options.html#date-math[Date Math format], see also <>) + +*Maximum alerts per execution*: 100 + +*References*: + +* https://lolesxi-project.github.io/LOLESXi/# +* https://blogs.vmware.com/security/2022/10/esxi-targeting-ransomware-tactics-and-techniques-part-2.html +* https://detect.fyi/vmware-esxi-logging-detection-opportunities-4fb56411ec21 + +*Tags*: + +* Domain: Endpoint +* Data Source: VMware vSphere +* Use Case: Threat Detection +* Tactic: Command and Control +* Resources: Investigation Guide +* Rule Type: Custom Query (KQL) +* Platform: VMware ESXi +* Threat: Ransomware + +*Version*: 2 + +*Rule authors*: + +* Elastic + +*Rule license*: Elastic License v2 + + +==== Investigation guide + + + +*Triage and analysis* + + + +*Investigating ESXi Curl or Wget Activity* + + +curl and wget download a file or check a URL from the ESXi shell. The shell log records the command even when the binary is missing or the host has no route to the destination. + + +*Possible investigation steps* + + +- Read the URL and output path in message. +- Check the same session for a file under /tmp, chmod, or execution of the downloaded file. +- Confirm the URL with the virtualization owner. + + +*False positive analysis* + + +A documented download of a vendor package is commonly benign. A download of an unknown file into /tmp, followed by chmod, deserves review. + + +*Response and remediation* + + +- If the download was not approved, remove the file and end the shell session. +- Preserve shell.log and review commands issued after the download. + + +==== Setup + + + +*Setup* + + +This rule requires ESXi host logs collected by the Elastic vSphere integration: https://www.elastic.co/docs/reference/integrations/vsphere + + +==== Rule query + + +[source, js] +---------------------------------- +data_stream.dataset:vsphere.log and event.module:vsphere and message:((curl or wget) and not ("cURL Error" or "curl failed" or localhost or vmware.com)) + +---------------------------------- + +*Framework*: MITRE ATT&CK^TM^ + +* Tactic: +** Name: Command and Control +** ID: TA0011 +** Reference URL: https://attack.mitre.org/tactics/TA0011/ +* Technique: +** Name: Ingress Tool Transfer +** ID: T1105 +** Reference URL: https://attack.mitre.org/techniques/T1105/ diff --git a/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-esxi-local-account-created.asciidoc b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-esxi-local-account-created.asciidoc new file mode 100644 index 0000000000..9be3ed6097 --- /dev/null +++ b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-esxi-local-account-created.asciidoc @@ -0,0 +1,115 @@ +[[prebuilt-rule-8-19-37-esxi-local-account-created]] +=== ESXi Local Account Created + +Detects creation of a local ESXi account. A new account is a separate login that remains after the session that created it. It has no rights until a role is assigned, and it is the first step toward a persistent login on the host. + +*Rule type*: query + +*Rule indices*: + +* logs-vsphere.log-* + +*Severity*: medium + +*Risk score*: 47 + +*Runs every*: 5m + +*Searches indices from*: now-9m ({ref}/common-options.html#date-math[Date Math format], see also <>) + +*Maximum alerts per execution*: 100 + +*References*: + +* https://lolesxi-project.github.io/LOLESXi/# +* https://blogs.vmware.com/security/2022/10/esxi-targeting-ransomware-tactics-and-techniques-part-2.html +* https://detect.fyi/vmware-esxi-logging-detection-opportunities-4fb56411ec21 + +*Tags*: + +* Domain: Endpoint +* Data Source: VMware vSphere +* Use Case: Threat Detection +* Tactic: Persistence +* Resources: Investigation Guide +* Rule Type: Custom Query (KQL) +* Platform: VMware ESXi +* Threat: Ransomware + +*Version*: 2 + +*Rule authors*: + +* Elastic + +*Rule license*: Elastic License v2 + + +==== Investigation guide + + + +*Triage and analysis* + + + +*Investigating ESXi Local Account Created* + + +Hostd records Account was created on host when an account is added from the Host Client or API. The shell records esxcli system account add. The new account has no role until a later permission change. + + +*Possible investigation steps* + + +- Read the account name in message and the user field on the hostd event, which is the account that created it. +- Look for a following esxcli system permission set or an Admin role grant for the same account. +- Compare the account with the approved list for that host. + + +*False positive analysis* + + +A documented joiner or break-glass account is commonly benign. An unknown account created by root over the Host Client, then granted Admin, deserves review. + + +*Response and remediation* + + +- If the account was not approved, remove it with esxcli system account remove --id . +- Preserve hostd.log and shell.log for the creating session. + + +==== Setup + + + +*Setup* + + +This rule requires ESXi host logs collected by the Elastic vSphere integration: https://www.elastic.co/docs/reference/integrations/vsphere + + +==== Rule query + + +[source, js] +---------------------------------- +data_stream.dataset:vsphere.log and event.module:vsphere and message:("esxcli system account add" or Account and "was created on host") + +---------------------------------- + +*Framework*: MITRE ATT&CK^TM^ + +* Tactic: +** Name: Persistence +** ID: TA0003 +** Reference URL: https://attack.mitre.org/tactics/TA0003/ +* Technique: +** Name: Create Account +** ID: T1136 +** Reference URL: https://attack.mitre.org/techniques/T1136/ +* Sub-technique: +** Name: Local Account +** ID: T1136.001 +** Reference URL: https://attack.mitre.org/techniques/T1136/001/ diff --git a/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-esxi-virtual-disk-files-enumerated.asciidoc b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-esxi-virtual-disk-files-enumerated.asciidoc new file mode 100644 index 0000000000..fda8ec58b3 --- /dev/null +++ b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-esxi-virtual-disk-files-enumerated.asciidoc @@ -0,0 +1,111 @@ +[[prebuilt-rule-8-19-37-esxi-virtual-disk-files-enumerated]] +=== ESXi Virtual Disk Files Enumerated + +Detects a shell search under `/vmfs/volumes` for virtual disk and snapshot files (`vmdk`, `vmsn`, `vmsd`). Those files are the guest disks and their on-host recovery points. Listing them builds the set of files a later process can encrypt or delete. + +*Rule type*: query + +*Rule indices*: + +* logs-vsphere.log-* + +*Severity*: low + +*Risk score*: 21 + +*Runs every*: 5m + +*Searches indices from*: now-9m ({ref}/common-options.html#date-math[Date Math format], see also <>) + +*Maximum alerts per execution*: 100 + +*References*: + +* https://lolesxi-project.github.io/LOLESXi/# +* https://blogs.vmware.com/security/2022/10/esxi-targeting-ransomware-tactics-and-techniques-part-2.html +* https://detect.fyi/vmware-esxi-logging-detection-opportunities-4fb56411ec21 + +*Tags*: + +* Domain: Endpoint +* Data Source: VMware vSphere +* Use Case: Threat Detection +* Tactic: Discovery +* Resources: Investigation Guide +* Rule Type: Custom Query (KQL) +* Platform: VMware ESXi +* Threat: Ransomware + +*Version*: 2 + +*Rule authors*: + +* Elastic + +*Rule license*: Elastic License v2 + + +==== Investigation guide + + + +*Triage and analysis* + + + +*Investigating ESXi Virtual Disk Files Enumerated* + + +The datastore path and the vmdk family of extensions are how ESXi ransomware chooses what to encrypt. The search itself does not change files. + + +*Possible investigation steps* + + +- Read the exact find arguments in message, including any -name filter. +- Correlate with later vm process kill, power.off, or snapshot.removeall from the same session. +- If the command stands alone during a known support window, it is often benign. + + +*False positive analysis* + + +Support bundles and storage reports list virtual disks. Escalation is for a search followed by VM shutdown or snapshot deletion. + + +*Response and remediation* + + +- If the same session starts killing VMs or deleting snapshots, isolate the host. +- Otherwise record the account and command for hunting across other ESXi hosts. + + +==== Setup + + + +*Setup* + + +This rule requires ESXi host logs collected by the Elastic vSphere integration: https://www.elastic.co/docs/reference/integrations/vsphere + + +==== Rule query + + +[source, js] +---------------------------------- +data_stream.dataset:vsphere.log and message:(/vmfs/volumes and find and (vmdk or vmsd or vmsn) and not ("Could not find the file" or "Failed to open" or "No such file" or "failed to open")) + +---------------------------------- + +*Framework*: MITRE ATT&CK^TM^ + +* Tactic: +** Name: Discovery +** ID: TA0007 +** Reference URL: https://attack.mitre.org/tactics/TA0007/ +* Technique: +** Name: File and Directory Discovery +** ID: T1083 +** Reference URL: https://attack.mitre.org/techniques/T1083/ diff --git a/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-excessive-sudo-authentication-failures-via-macos-security-events.asciidoc b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-excessive-sudo-authentication-failures-via-macos-security-events.asciidoc new file mode 100644 index 0000000000..46b4b0640d --- /dev/null +++ b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-excessive-sudo-authentication-failures-via-macos-security-events.asciidoc @@ -0,0 +1,163 @@ +[[prebuilt-rule-8-19-37-excessive-sudo-authentication-failures-via-macos-security-events]] +=== Excessive Sudo Authentication Failures via macOS Security Events + +Identifies a high number of failed sudo password attempts on a macOS host within a short time window, using sudo messages collected by the Authentication data stream of the macOS Security Events integration. Repeated sudo authentication failures may indicate an adversary with access to a low-privileged account attempting to guess an administrator password to escalate privileges. + +*Rule type*: esql + +*Rule indices*: None + +*Severity*: low + +*Risk score*: 21 + +*Runs every*: 5m + +*Searches indices from*: now-9m ({ref}/common-options.html#date-math[Date Math format], see also <>) + +*Maximum alerts per execution*: 100 + +*References*: + +* https://themittenmac.com/detecting-ssh-activity-via-process-monitoring/ + +*Tags*: + +* Domain: Endpoint +* OS: macOS +* Platform: macOS +* Use Case: Threat Detection +* Tactic: Privilege Escalation +* Tactic: Credential Access +* Data Source: macOS Security Events +* Rule Type: ES|QL +* Resources: Investigation Guide + +*Version*: 3 + +*Rule authors*: + +* Elastic + +*Rule license*: Elastic License v2 + + +==== Investigation guide + + + +*Triage and analysis* + + +> **Disclaimer**: +> This investigation guide was created using generative AI technology and has been reviewed to improve its accuracy and relevance. While every effort has been made to ensure its quality, we recommend validating the content and adapting it to suit your specific environment and operational needs. + + +*Investigating Excessive Sudo Authentication Failures via macOS Security Events* + + +On macOS, `sudo` prompts for the invoking user's password and, after the configured number of incorrect attempts +(three by default), logs a message of the form ` : incorrect password attempts ; TTY= ; PWD= ; +USER= ; COMMAND=` to the unified log. This rule sums the reported attempt counts per host within the +rule window and alerts when the total reaches the threshold. The invoking user, target user, TTY, and attempted commands +are extracted from the messages and reported in the alert as `Esql.user_name_values`, `Esql.target_user_values`, +`Esql.tty_values`, and `Esql.command_values`. + + +*Possible investigation steps* + + +- Review `Esql.attempt_total`, `Esql.user_name_values`, and `Esql.command_values` in the alert to identify who was +attempting to elevate, how many times, and what they were trying to run. +- Determine whether the invoking account is expected to have sudo rights. Failures from an account that is not an +administrator suggest privilege escalation attempts rather than mistyped passwords. +- Review the attempted commands for reconnaissance, persistence, or credential access tooling (for example, `dscl`, +`launchctl`, `security`, `defaults`, shell interpreters, or scripts in user-writable locations). +- Check whether a successful sudo invocation by the same user follows the failures in `logs-macos.authentication-*`, +which would indicate the password was eventually guessed or known. +- Review how the session originated: a local console session (`ttys` with a preceding login window login) versus an SSH +session, and correlate with SSH authentication alerts on the same host. +- Correlate with other alerts or events from the same host and user during the same period. + + +*False positive analysis* + + +- Administrators who mistype their password. The default three-attempt limit per invocation and the threshold make this +unlikely from a single interactive session, but repeated invocations can approach it. +- Scripts or automation that invoke `sudo` with stale or incorrect credentials in a loop. +- Users who are not administrators habitually attempting `sudo`; consider tuning by user or excluding known cases if +this is expected behavior. + + +*Response and remediation* + + +- Identify the invoking account and its session origin; if the account is not expected to use sudo or the session is +remote and unexpected, terminate the session and disable or reset the account. +- Review the attempted commands and the host for evidence of prior compromise of the low-privileged account. +- Reset the administrator password if there is any indication it may have been guessed or exposed. +- Review sudo configuration and administrator group membership on the host; remove unnecessary admin rights. +- Escalate to the security operations team if additional hosts show similar patterns. + + +==== Setup + + + +*Setup* + + +This rule requires data from the macOS Security Events integration. +Integration setup instructions: https://www.elastic.co/docs/reference/integrations/macos[macOS Security Events Integration for Elastic] + + +==== Rule query + + +[source, js] +---------------------------------- +FROM logs-macos.authentication-* +| WHERE data_stream.dataset == "macos.authentication" and + macos.process.image_path LIKE "*/sudo" and + macos.event.message.description LIKE "*incorrect password attempt*" +| GROK macos.event.message.description "%{NOTSPACE:user_name} : %{NUMBER:attempt_count:int} incorrect password attempt%{DATA} ; TTY=%{NOTSPACE:tty} ; PWD=%{DATA:pwd} ; USER=%{NOTSPACE:target_user} ; COMMAND=%{GREEDYDATA:command}" +| STATS + Esql.failure_event_count = COUNT(*), + Esql.attempt_total = SUM(attempt_count), + Esql.user_name_values = VALUES(user_name), + Esql.target_user_values = VALUES(target_user), + Esql.tty_values = VALUES(tty), + Esql.command_values = VALUES(command) + BY host.id, host.name +| WHERE Esql.attempt_total >= 10 +| KEEP host.id, host.name, Esql.failure_event_count, Esql.attempt_total, Esql.user_name_values, Esql.target_user_values, Esql.tty_values, Esql.command_values + +---------------------------------- + +*Framework*: MITRE ATT&CK^TM^ + +* Tactic: +** Name: Privilege Escalation +** ID: TA0004 +** Reference URL: https://attack.mitre.org/tactics/TA0004/ +* Technique: +** Name: Abuse Elevation Control Mechanism +** ID: T1548 +** Reference URL: https://attack.mitre.org/techniques/T1548/ +* Sub-technique: +** Name: Sudo and Sudo Caching +** ID: T1548.003 +** Reference URL: https://attack.mitre.org/techniques/T1548/003/ +* Tactic: +** Name: Credential Access +** ID: TA0006 +** Reference URL: https://attack.mitre.org/tactics/TA0006/ +* Technique: +** Name: Brute Force +** ID: T1110 +** Reference URL: https://attack.mitre.org/techniques/T1110/ +* Sub-technique: +** Name: Password Guessing +** ID: T1110.001 +** Reference URL: https://attack.mitre.org/techniques/T1110/001/ diff --git a/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-execution-via-github-actions-runner.asciidoc b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-execution-via-github-actions-runner.asciidoc new file mode 100644 index 0000000000..5c600fbaa7 --- /dev/null +++ b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-execution-via-github-actions-runner.asciidoc @@ -0,0 +1,282 @@ +[[prebuilt-rule-8-19-37-execution-via-github-actions-runner]] +=== Execution via GitHub Actions Runner + +This rule detects potentially dangerous commands spawned by the GitHub Actions Runner.Worker process or by shell interpreters launched via a runner entrypoint script on self-hosted runner machines. Adversaries who gain the ability to modify or trigger workflows in a linked GitHub repository can execute arbitrary commands on the runner host. This behavior may indicate malicious or unexpected workflow activity, including code execution, reconnaissance, credential harvesting, or network exfiltration initiated through a compromised repository or unauthorized workflow. + +*Rule type*: eql + +*Rule indices*: + +* endgame-* +* logs-crowdstrike.fdr* +* logs-endpoint.events.process-* +* logs-m365_defender.event-* +* logs-sentinel_one_cloud_funnel.* +* logs-system.security* +* logs-windows.forwarded* +* logs-windows.sysmon_operational-* +* winlogbeat-* +* auditbeat-* +* logs-auditd_manager.auditd-* + +*Severity*: medium + +*Risk score*: 47 + +*Runs every*: 5m + +*Searches indices from*: now-9m ({ref}/common-options.html#date-math[Date Math format], see also <>) + +*Maximum alerts per execution*: 100 + +*References*: + +* https://www.elastic.co/blog/shai-hulud-worm-npm-supply-chain-compromise +* https://socket.dev/blog/shai-hulud-strikes-again-v2 + +*Tags*: + +* Domain: Endpoint +* OS: Linux +* OS: Windows +* OS: macOS +* Use Case: Threat Detection +* Tactic: Execution +* Tactic: Initial Access +* Data Source: Elastic Endgame +* Data Source: Elastic Defend +* Data Source: Windows Security Event Logs +* Data Source: Microsoft Defender XDR +* Data Source: Sysmon +* Data Source: SentinelOne +* Data Source: Crowdstrike +* Data Source: Auditd Manager +* Resources: Investigation Guide +* Noise: High +* Performance: Normal +* Profile: Aggressive +* Threat: Supply Chain +* Threat: Living off the Land +* Rule Type: Event Correlation (EQL) +* Platform: Windows +* Platform: Linux +* Platform: macOS + +*Version*: 6 + +*Rule authors*: + +* Elastic + +*Rule license*: Elastic License v2 + + +==== Investigation guide + + + +*Triage and analysis* + + + +*Investigating Execution via GitHub Actions Runner* + + +Adversaries who gain the ability to modify or trigger workflows in a linked GitHub repository can execute arbitrary +commands on the runner host. This rule covers two parent process paths: +- **Direct execution**: process spawned directly by `Runner.Worker` / `Runner.Worker.exe`. +- **Entrypoint script execution**: process spawned by a shell (`sh`, `bash`, `zsh`) whose command line references + a runner `entrypoint.sh` script, a common pattern when the runner bootstraps workflow steps via a shell script. + + +*Possible investigation steps* + + +- Review `process.command_line` and `process.parent.command_line` to determine whether the activity matches a known, + authorized workflow step. +- For `grep`, `find`, `pgrep`, `printenv`, and `env` hits, assess whether the command targets sensitive paths, environment + variables (e.g. secrets, tokens), or process listings inconsistent with the declared workflow. +- For `openssl` and `base64` hits, inspect arguments for encoding/decoding operations that may indicate credential + harvesting, data staging, or a C2 channel. +- For `tr` and `cat` hits, assess whether they are chained with other suspicious commands (e.g. `cat /etc/passwd | base64`, + `cat ~/.ssh/id_rsa`) to read and encode sensitive files for exfiltration. +- For `nc`, `ncat`, `netcat`, and `socat` hits, check arguments for reverse shell patterns or port-forwarding to + attacker-controlled infrastructure. +- For `wg` and `wg-quick` hits, inspect arguments for tunnel configuration that may establish a covert egress channel. +- For `ssh` hits, review arguments for reverse tunnel flags (`-R`) or connections to unexpected remote hosts. +- For `kubectl` and `helm` hits, assess whether commands target sensitive namespaces, extract secrets, or deploy + workloads inconsistent with the declared workflow. +- For `vault` hits, inspect arguments for secret reads (`vault kv get`) or token operations that may indicate + credential harvesting from a HashiCorp Vault instance. +- For `gh` hits, review arguments for repository cloning, secret access (`gh secret`), or actions that escalate + access via the runner's GitHub token. +- For `nmap` hits, assess whether the command performs host or port discovery against internal network ranges, + indicating lateral movement preparation. +- Examine associated network activity for unexpected outbound connections, especially following `curl`, `wget`, or + `openssl s_client` invocations. +- Verify whether the triggering workflow run was initiated by an authorized actor and matches the repository's + expected workflow definitions. +- Correlate with file-write and file-access events to identify any sensitive file staging or collection activity. +- Correlate with other alerts to determine if this activity is part of a broader supply chain or CI/CD compromise. + + +*False positive analysis* + + +- Authorized GitHub workflow actions that legitimately use discovery utilities (`find`, `grep`, `env`, `nmap`), data + manipulation tools (`cat`, `tr`), encoding tools (`openssl`, `base64`), remote access tools (`ssh`), or + infrastructure CLIs (`kubectl`, `helm`, `vault`, `gh`) as part of their build, test, or deploy steps may trigger + this rule. Validate against known workflow definitions and consider adding workflow-specific exclusions if the + volume is high. + + +*Response and remediation* + + +- Immediately isolate the affected system from the network to prevent further unauthorized command execution and potential lateral movement. +- Terminate any suspicious child processes that were initiated by the Github actions runner. +- Conduct a thorough review of the affected system's logs and configurations to identify any unauthorized changes or additional indicators of compromise. +- Restore the system from a known good backup if any unauthorized changes or malicious activities are confirmed. +- Implement application whitelisting to prevent unauthorized execution. +- Escalate the incident to the security operations center (SOC) or incident response team for further investigation and to assess the potential impact on the broader network. + +==== Rule query + + +[source, js] +---------------------------------- +process where event.type == "start" and event.action in ("exec", "exec_event", "start", "ProcessRollup2", "executed", "process_started") and + ( + /* Direct child of the GitHub Actions Runner.Worker process */ + process.parent.name in ("Runner.Worker", "Runner.Worker.exe") or + + /* Child of a shell interpreter launched via a runner entrypoint script + (e.g. /home/runner/runners//run/entrypoint.sh or similar paths) */ + ( + process.parent.name in ("sh", "bash", "zsh") and + process.parent.command_line like "*runner*entrypoint.sh" + ) + ) and + ( + process.name : ( + /* Network / download utilities */ + "curl", "curl.exe", "wget", "wget.exe", + /* Windows scripting & LOLBins */ + "powershell.exe", "cmd.exe", "pwsh.exe", "certutil.exe", "rundll32.exe", + /* Unix shells */ + "bash", "sh", "zsh", "dash", "ash", "tcsh", "csh", "ksh", "fish", "mksh", "busybox", "pwsh", + /* File / archive manipulation */ + "tar", "gzip", "rm", "sed", "chmod", + /* macOS-specific */ + "osascript", + /* Process persistence helpers */ + "nohup", "setsid", + /* Scripting runtimes */ + "python*", "perl*", "ruby*", "lua*", "php*", "node", "nodejs", "node.exe", + /* Discovery & reconnaissance */ + "pgrep", "grep", "find", "printenv", "env", "nmap", + /* Crypto / encoding (potential exfiltration or C2 channel) */ + "openssl", "base64", "basez", "base64plain", "base64url", "base64mime", "base64pem", "basenc", "base32", "base16", "xxd", + /* Data manipulation / inspection */ + "tr", "cat", + /* Network relay / tunneling */ + "nc", "ncat", "netcat", "nc.traditional", "nc.openbsd", "socat", "wg", "wg-quick", + /* Remote access */ + "ssh", "ssh.exe", "ftp", "tftp", "scp", "sftp", + /* Kubernetes / infrastructure */ + "kubectl", "helm", "docker", "ctr", "crictl", + /* Secret management */ + "vault", + /* GitHub CLI */ + "gh", + /* AWS CLI */ + "aws", + /*Azure CLI */ + "az", + /*GCP CLI */ + "gcloud", + /* Google Workspace CLI */ + "gws" + ) or + process.executable : ("/tmp/*", "/private/tmp/*", "/var/tmp/*", "/dev/shm/*", "/run/*", "/var/run/*", "?:\\Users\\*") + ) and +not ( + /* Runner orchestration layer. Runner.Worker writes every `run:` step to /_work/_temp/. + and launches the configured shell on it (bash/sh/pwsh/powershell/cmd/python built-ins all use the + same template), and runs JavaScript actions as node /_work/_actions////... + The exclusion is anchored on the runner `_work/_temp` and `_work/_actions` directories so that + admin-configured job-extension hook scripts on an arbitrary path that merely contains `_temp` are + NOT suppressed. docker and tar are intentionally NOT excluded, because an attacker-controlled + workflow can invoke them directly to stage, archive, or execute payloads. */ + process.parent.name in ("Runner.Worker", "Runner.Worker.exe") and + ( + (process.name : ("bash", "sh", "dash", "cmd.exe", "python", "python3", "python.exe") and + process.args : ("*/_work/_temp/*", "*\\_work\\_temp\\*")) or + (process.name : ("pwsh", "pwsh.exe", "powershell.exe") and + process.args : ("*/_work/_temp/*.ps1*", "*\\_work\\_temp\\*.ps1*")) or + (process.name : ("node", "node.exe") and + process.args : ("*/_work/_actions/*", "*\\_work\\_actions\\*")) + ) and + not process.executable : ("/tmp/*", "/private/tmp/*", "/var/tmp/*", "/dev/shm/*") +) + +---------------------------------- + +*Framework*: MITRE ATT&CK^TM^ + +* Tactic: +** Name: Execution +** ID: TA0002 +** Reference URL: https://attack.mitre.org/tactics/TA0002/ +* Technique: +** Name: Command and Scripting Interpreter +** ID: T1059 +** Reference URL: https://attack.mitre.org/techniques/T1059/ +* Sub-technique: +** Name: PowerShell +** ID: T1059.001 +** Reference URL: https://attack.mitre.org/techniques/T1059/001/ +* Sub-technique: +** Name: AppleScript +** ID: T1059.002 +** Reference URL: https://attack.mitre.org/techniques/T1059/002/ +* Sub-technique: +** Name: Windows Command Shell +** ID: T1059.003 +** Reference URL: https://attack.mitre.org/techniques/T1059/003/ +* Sub-technique: +** Name: Unix Shell +** ID: T1059.004 +** Reference URL: https://attack.mitre.org/techniques/T1059/004/ +* Sub-technique: +** Name: Python +** ID: T1059.006 +** Reference URL: https://attack.mitre.org/techniques/T1059/006/ +* Sub-technique: +** Name: JavaScript +** ID: T1059.007 +** Reference URL: https://attack.mitre.org/techniques/T1059/007/ +* Tactic: +** Name: Initial Access +** ID: TA0001 +** Reference URL: https://attack.mitre.org/tactics/TA0001/ +* Technique: +** Name: Supply Chain Compromise +** ID: T1195 +** Reference URL: https://attack.mitre.org/techniques/T1195/ +* Sub-technique: +** Name: Compromise Software Supply Chain +** ID: T1195.002 +** Reference URL: https://attack.mitre.org/techniques/T1195/002/ +* Tactic: +** Name: Defense Evasion +** ID: TA0005 +** Reference URL: https://attack.mitre.org/tactics/TA0005/ +* Technique: +** Name: System Binary Proxy Execution +** ID: T1218 +** Reference URL: https://attack.mitre.org/techniques/T1218/ +* Sub-technique: +** Name: Rundll32 +** ID: T1218.011 +** Reference URL: https://attack.mitre.org/techniques/T1218/011/ diff --git a/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-first-time-gcp-vertex-ai-inference-by-caller-from-source-asn.asciidoc b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-first-time-gcp-vertex-ai-inference-by-caller-from-source-asn.asciidoc new file mode 100644 index 0000000000..942c9e48ac --- /dev/null +++ b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-first-time-gcp-vertex-ai-inference-by-caller-from-source-asn.asciidoc @@ -0,0 +1,132 @@ +[[prebuilt-rule-8-19-37-first-time-gcp-vertex-ai-inference-by-caller-from-source-asn]] +=== First Time GCP Vertex AI Inference by Caller from Source ASN + +Detects the first time in 14 days that a Vertex AI caller (user or service account) runs model inference (GenerateContent, StreamGenerateContent, Predict, or RawPredict) from a source autonomous system (ASN). Stolen Google Cloud credentials, including exported service account keys and OAuth tokens, are used for LLMjacking from attacker infrastructure, which shows up as the victim identity calling models from a hosting provider, VPN, or residential proxy network it has never used before. + +*Rule type*: new_terms + +*Rule indices*: + +* logs-gcp_vertexai.auditlogs-* + +*Severity*: low + +*Risk score*: 21 + +*Runs every*: 10m + +*Searches indices from*: now-60m ({ref}/common-options.html#date-math[Date Math format], see also <>) + +*Maximum alerts per execution*: 100 + +*References*: + +* https://cloud.google.com/vertex-ai/docs/general/audit-logging +* https://www.elastic.co/docs/reference/integrations/gcp_vertexai + +*Tags*: + +* Domain: GenAI +* Domain: Cloud +* Data Source: GCP Vertex AI +* Data Source: GCP +* Data Source: Google Cloud Platform +* Platform: GCP +* Service: GCP Vertex AI +* Use Case: Threat Detection +* Tactic: Initial Access +* Threat: LLMjacking +* Threat: Unauthorized AI Usage +* Mitre Atlas: AML.T0012 +* Resources: Investigation Guide +* Rule Type: New Terms + +*Version*: 1 + +*Rule authors*: + +* Elastic + +*Rule license*: Elastic License v2 + + +==== Investigation guide + + + +*Triage and analysis* + + + +*Investigating First Time GCP Vertex AI Inference by Caller from Source ASN* + + +A Vertex AI caller (`client.user.email`) made a successful inference call from a source ASN (`source.as.number`) that +it has not used for inference in the last 14 days. For a stolen credential this is often the first visible sign of +abuse, because the attacker calls models from their own infrastructure. + + +*Possible investigation steps* + + +- Review `source.as.organization.name`, `source.ip`, and `source.geo.country_name`. Hosting providers, VPN services, + and residential proxy networks are more suspicious than a known corporate or home ISP. +- Determine whether `client.user.email` is a human user or a service account (`*.gserviceaccount.com`). A service + account normally runs from a fixed set of networks, so a new ASN is a stronger signal. +- Compare `user_agent.original` with the caller's previous inference activity. A switch from the Google SDK or console + to a generic HTTP client is a common LLMjacking pattern. +- Check `gcp.vertexai.audit.resource_name` for the model being called, and look for a jump in request volume from the + new ASN using GCP Vertex AI High Request and Token Volume or the integration's metrics. +- Review GCP audit logs for service account key creation, key download, or IAM changes for the caller shortly before + this event. + + +*False positive analysis* + + +- Users on new networks. Confirm with the user before acting. +- Workloads that legitimately move between networks. Exclude these service accounts by email. + + +*Response and remediation* + + +- If the activity is not authorized, disable or delete the service account key, revoke the user's sessions and OAuth + tokens, and review IAM bindings that grant `aiplatform.endpoints.predict`. +- Review Vertex AI usage and billing for the project and set quotas or budgets to limit abuse. + + +==== Setup + + + +*Setup* + + +Requires GCP Vertex AI `auditlogs` with Data Access audit logs enabled for `aiplatform.googleapis.com`, and with +`client.user.email` and `source.as.number` populated by the integration. + + +==== Rule query + + +[source, js] +---------------------------------- +data_stream.dataset:gcp_vertexai.auditlogs and event.action:(*PredictionService.GenerateContent* or *PredictionService.StreamGenerateContent* or *PredictionService.Predict* or *PredictionService.RawPredict*) and gcp.vertexai.audit.service_name:aiplatform.googleapis.com and client.user.email:* and source.as.number:* and gcp.vertexai.audit.status.code:(0 or not *) + +---------------------------------- + +*Framework*: MITRE ATT&CK^TM^ + +* Tactic: +** Name: Initial Access +** ID: TA0001 +** Reference URL: https://attack.mitre.org/tactics/TA0001/ +* Technique: +** Name: Valid Accounts +** ID: T1078 +** Reference URL: https://attack.mitre.org/techniques/T1078/ +* Sub-technique: +** Name: Cloud Accounts +** ID: T1078.004 +** Reference URL: https://attack.mitre.org/techniques/T1078/004/ diff --git a/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-gcp-vertex-ai-role-granted-to-principal.asciidoc b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-gcp-vertex-ai-role-granted-to-principal.asciidoc new file mode 100644 index 0000000000..76da904bd9 --- /dev/null +++ b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-gcp-vertex-ai-role-granted-to-principal.asciidoc @@ -0,0 +1,159 @@ +[[prebuilt-rule-8-19-37-gcp-vertex-ai-role-granted-to-principal]] +=== GCP Vertex AI Role Granted to Principal + +Identifies an IAM policy change on a Google Cloud project, folder, or organization that grants a Vertex AI role (`roles/aiplatform.*`) to a principal. Vertex AI roles control who can invoke models, deploy endpoints, run agents, and read prompt and training data. An adversary who has gained IAM administration rights can grant a Vertex AI role to an identity they control to keep model access after the original foothold is removed, or to run LLMjacking workloads under the victim's billing. Google-managed service agent roles are excluded because Google grants them automatically when the API is enabled. + +*Rule type*: query + +*Rule indices*: + +* logs-gcp.audit-* + +*Severity*: medium + +*Risk score*: 47 + +*Runs every*: 5m + +*Searches indices from*: now-9m ({ref}/common-options.html#date-math[Date Math format], see also <>) + +*Maximum alerts per execution*: 100 + +*References*: + +* https://cloud.google.com/vertex-ai/docs/general/access-control +* https://cloud.google.com/iam/docs/audit-logging +* https://www.elastic.co/docs/reference/integrations/gcp/audit + +*Tags*: + +* Domain: Cloud +* Domain: GenAI +* Domain: Identity +* Data Source: GCP +* Data Source: Google Cloud Platform +* Platform: GCP +* Service: GCP Vertex AI +* Use Case: Identity and Access Audit +* Use Case: Threat Detection +* Tactic: Persistence +* Tactic: Privilege Escalation +* Threat: Unauthorized AI Usage +* Mitre Atlas: AML.T0012 +* Resources: Investigation Guide +* Rule Type: Custom Query (KQL) + +*Version*: 1 + +*Rule authors*: + +* Elastic + +*Rule license*: Elastic License v2 + + +==== Investigation guide + + + +*Triage and analysis* + + + +*Investigating GCP Vertex AI Role Granted to Principal* + + +A Google Cloud IAM policy change added a binding for a Vertex AI role (`roles/aiplatform.*`). Roles such as +`roles/aiplatform.admin` and `roles/aiplatform.user` allow the member to call models, manage endpoints and agents, and +access prompt and training data in the project. + + +*Possible investigation steps* + + +- Identify the caller that changed the policy from `client.user.email`, and review `source.ip` and + `user_agent.original` for the change. +- Review `gcp.audit.service_data.policy_delta.binding_deltas` for the role and member that were added. Members outside + the organization's domain, newly created service accounts, and `allUsers` or `allAuthenticatedUsers` are the most + concerning. +- Check `gcp.audit.resource_name` to see whether the grant was made at the project, folder, or organization level. + Grants above the project level reach every project underneath. +- Look for follow-on activity by the new member in Vertex AI audit logs, such as inference calls from new networks, + endpoint deployment, or agent creation. +- Review other recent IAM changes by the same caller, especially service account key creation and grants of IAM admin + roles. + + +*False positive analysis* + + +- Approved access requests for ML and data science teams. Confirm with the request owner. +- IAM automation that reapplies bindings. Exclude those service accounts by email. + + +*Response and remediation* + + +- If the grant is not authorized, remove the binding and review what the member accessed since the grant. +- Investigate how the caller obtained IAM administration rights, rotate its credentials, and review its other changes. +- Restrict `resourcemanager.projects.setIamPolicy` to a small set of administrators and consider an Organization Policy + that limits allowed member domains. + + +==== Setup + + + +*Setup* + + +This rule requires Google Cloud Audit Logs ingested via the GCP integration (`gcp.audit` data stream). IAM policy +changes are Admin Activity audit logs and are always logged. + + +==== Rule query + + +[source, js] +---------------------------------- +data_stream.dataset: "gcp.audit" + and event.action: ( + "SetIamPolicy" or + google.cloud.resourcemanager.v*.Folders.SetIamPolicy or + google.cloud.resourcemanager.v*.Organizations.SetIamPolicy or + google.cloud.resourcemanager.v*.Projects.SetIamPolicy + ) + and not event.outcome: "failure" + and gcp.audit.service_data.policy_delta.binding_deltas:{ + action: "ADD" and + role: (roles/aiplatform.* and not (*ServiceAgent or *serviceAgent)) + } + +---------------------------------- + +*Framework*: MITRE ATT&CK^TM^ + +* Tactic: +** Name: Persistence +** ID: TA0003 +** Reference URL: https://attack.mitre.org/tactics/TA0003/ +* Technique: +** Name: Account Manipulation +** ID: T1098 +** Reference URL: https://attack.mitre.org/techniques/T1098/ +* Sub-technique: +** Name: Additional Cloud Roles +** ID: T1098.003 +** Reference URL: https://attack.mitre.org/techniques/T1098/003/ +* Tactic: +** Name: Privilege Escalation +** ID: TA0004 +** Reference URL: https://attack.mitre.org/tactics/TA0004/ +* Technique: +** Name: Account Manipulation +** ID: T1098 +** Reference URL: https://attack.mitre.org/techniques/T1098/ +* Sub-technique: +** Name: Additional Cloud Roles +** ID: T1098.003 +** Reference URL: https://attack.mitre.org/techniques/T1098/003/ diff --git a/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-genai-agent-instruction-file-written-to-downloads.asciidoc b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-genai-agent-instruction-file-written-to-downloads.asciidoc new file mode 100644 index 0000000000..53ce0e04dc --- /dev/null +++ b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-genai-agent-instruction-file-written-to-downloads.asciidoc @@ -0,0 +1,200 @@ +[[prebuilt-rule-8-19-37-genai-agent-instruction-file-written-to-downloads]] +=== GenAI Agent Instruction File Written to Downloads + +Detects creation or change of an AI coding-agent instruction file (agents.md or claude.md) in a user Downloads folder by a browser or an archive tool. A web page can save AGENTS.md or CLAUDE.md into Downloads without a click, and opening an archive can extract the same files there. Codex and Claude Code treat those files as trusted project instructions, which can lead them to rewrite their own configuration, install a package, or leak a login token. + +*Rule type*: esql + +*Rule indices*: None + +*Severity*: medium + +*Risk score*: 47 + +*Runs every*: 5m + +*Searches indices from*: now-9m ({ref}/common-options.html#date-math[Date Math format], see also <>) + +*Maximum alerts per execution*: 100 + +*References*: + +* https://forever.security/blog/hijacking-ai-agents-via-downloads-folder + +*Tags*: + +* Domain: Endpoint +* Domain: GenAI +* Mitre Atlas: AML.T0051 +* Mitre Atlas: AML.T0093 +* OS: Linux +* OS: Windows +* OS: macOS +* Use Case: Threat Detection +* Tactic: Initial Access +* Tactic: Execution +* Data Source: Elastic Defend +* Resources: Investigation Guide +* Threat: Unauthorized AI Usage +* Rule Type: ES|QL +* Platform: Windows +* Platform: Linux +* Platform: macOS + +*Version*: 1 + +*Rule authors*: + +* Elastic + +*Rule license*: Elastic License v2 + + +==== Investigation guide + + + +*Triage and analysis* + + + +*Investigating GenAI Agent Instruction File Written to Downloads* + + +`AGENTS.md` and `CLAUDE.md` are instruction files that coding agents such as OpenAI Codex and Claude Code read when +a session starts in that folder and then follow. Downloads is a folder a browser can write to on its own, and it is +also where archive tools extract files the user opened. A planted instruction file can tell the agent to register a +malicious MCP server, install a package, or point its API traffic at an attacker-controlled gateway. + + +*Possible investigation steps* + + +- Open `file.path` and read the file. Look for instructions that edit agent config (`~/.codex/config.toml`, + `.claude/settings.json`, `mcp.json`), register an MCP server, run `npx` or `npm install`, or set + `ANTHROPIC_BASE_URL` or a similar API base URL. +- Review `process.name` and `process.executable`. A browser or browser helper means the file was saved from the web. + An archive tool (`7z`, `WinRAR`, `tar`, `unzip`, Archive Utility) means it was extracted from a download. +- On the same host and user, look for a preceding download of a zip, rar, or 7z into the same Downloads folder, and + for follow-on writes to `.codex`, `.claude`, or other GenAI config paths. +- Check whether Codex, Claude, or another agent was later started with that Downloads folder as its workspace, and + whether it spawned `npm`, `npx`, `node`, or a shell afterward. +- If the file is malicious, hunt the same filename and content hash on other hosts. + + +*False positive analysis* + + +- Cloning or downloading a legitimate repository into Downloads extracts a real `AGENTS.md` or `CLAUDE.md`. Confirm + the archive or URL and the file contents before excluding. +- Saving those files from a browser while working on an agent project in Downloads is expected. Scope exceptions to + a known path, user, or parent archive, not to the filename alone. + + +*Response and remediation* + + +- Quarantine the instruction file and any archive it came from. Collect the hash and the download URL if present. +- If an agent already consumed the file, review `~/.codex/config.toml`, `.claude/settings.json`, and other MCP + config for new servers or API base URLs, and remove unauthorized entries. +- Rotate agent login tokens and any credentials the session could have read. Remove packages the agent installed + as part of the instructions, such as an unexpected npm package. + + +==== Setup + + + +*Setup* + + +This rule is designed for data generated by https://www.elastic.co/security/endpoint-security[Elastic Defend], which provides native endpoint detection and response, along with event enrichments designed to work with our detection rules. + +Setup instructions: https://ela.st/install-elastic-defend + + +==== Rule query + + +[source, js] +---------------------------------- +FROM logs-endpoint.events.file-* METADATA _id, _version, _index +| WHERE event.type IN ("creation", "change") + AND TO_LOWER(file.name) IN ("agents.md", "claude.md") + AND ( + file.path LIKE "/Users/*/Downloads/*" + OR file.path LIKE "/home/*/Downloads/*" + OR file.path LIKE """C:\\Users\\*\\Downloads\\*""" + ) + AND ( + TO_LOWER(process.name) IN ( + "google chrome", "chrome.exe", "chrome", "chromium", "chromium-browser", "google-chrome", + "microsoft edge", "msedge.exe", "microsoft-edge", + "firefox", "firefox.exe", + "safari", + "brave browser", "brave.exe", "brave", "brave-browser", + "opera", "opera.exe", + "vivaldi", "vivaldi.exe", + "explorer.exe", + "com.apple.webkit.networking", + "7z.exe", "7zg.exe", "7zfm.exe", "7z", "7zz", + "winrar.exe", "rar.exe", "unrar.exe", "rar", "unrar", + "winzip.exe", "winzip64.exe", + "bandizip.exe", "peazip.exe", + "tar.exe", "tar", "bsdtar", + "unzip.exe", "unzip", "unar", "ditto", + "archive utility", "bomarchivehelper", + "the unarchiver", "keka", + "file-roller", "ark" + ) + OR TO_LOWER(process.name) LIKE ( + "google chrome helper*", + "microsoft edge helper*", + "brave browser helper*", + "opera helper*", + "vivaldi helper*" + ) + ) +| KEEP + _id, + _version, + _index, + data_stream.namespace, + @timestamp, + host.name, + host.id, + agent.id, + user.name, + user.domain, + event.type, + event.action, + file.name, + file.path, + process.name, + process.executable, + process.entity_id + +---------------------------------- + +*Framework*: MITRE ATT&CK^TM^ + +* Tactic: +** Name: Initial Access +** ID: TA0001 +** Reference URL: https://attack.mitre.org/tactics/TA0001/ +* Technique: +** Name: Drive-by Compromise +** ID: T1189 +** Reference URL: https://attack.mitre.org/techniques/T1189/ +* Tactic: +** Name: Execution +** ID: TA0002 +** Reference URL: https://attack.mitre.org/tactics/TA0002/ +* Technique: +** Name: User Execution +** ID: T1204 +** Reference URL: https://attack.mitre.org/techniques/T1204/ +* Sub-technique: +** Name: Malicious File +** ID: T1204.002 +** Reference URL: https://attack.mitre.org/techniques/T1204/002/ diff --git a/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-github-advanced-security-disabled.asciidoc b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-github-advanced-security-disabled.asciidoc new file mode 100644 index 0000000000..4aac46ddff --- /dev/null +++ b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-github-advanced-security-disabled.asciidoc @@ -0,0 +1,125 @@ +[[prebuilt-rule-8-19-37-github-advanced-security-disabled]] +=== GitHub Advanced Security Disabled + +Detects GitHub Advanced Security being disabled for an enterprise, for all or new repositories in an organization, for existing or new user-namespace repositories, or for selected members via enterprise policy. Disabling GHAS removes secret scanning, code scanning, and related controls. + +*Rule type*: esql + +*Rule indices*: None + +*Severity*: medium + +*Risk score*: 47 + +*Runs every*: 5m + +*Searches indices from*: now-9m ({ref}/common-options.html#date-math[Date Math format], see also <>) + +*Maximum alerts per execution*: 100 + +*References*: + +* https://docs.github.com/en/get-started/learning-about-github/about-github-advanced-security + +*Tags*: + +* Domain: Cloud +* Domain: SaaS +* Platform: GitHub +* Use Case: Threat Detection +* Tactic: Defense Evasion +* Data Source: Github +* Data Source: GitHub Audit Logs +* Rule Type: ESQL +* Resources: Investigation Guide + +*Version*: 1 + +*Rule authors*: + +* Elastic + +*Rule license*: Elastic License v2 + + +==== Investigation guide + + + +*Triage and analysis* + + + +*Investigating GitHub Advanced Security Disabled* + + +Enterprise `business_advanced_security.*` disable actions (for the business, new repositories, and existing or new user-namespace repositories) and org-level `org.advanced_security_*` disable actions (all repos, new repos, and selected-member policy) strip scanning coverage. This is separate from a single-repo `repository_secret_scanning.disable`. + + +*Possible investigation steps* + + +- Identify `user.name`, `event.action`, and `github.org`. +- Check secret scanning, Dependabot, and code scanning on critical repositories. + + +*False positive analysis* + + +- License downsizing with a finance ticket. + + +*Response and remediation* + + +- Re-enable Advanced Security. Review commits made while scanning was off. + + +==== Rule query + + +[source, js] +---------------------------------- +from logs-github.audit-* metadata _id, _index, _version +| where + event.module == "github" and data_stream.dataset == "github.audit" + and event.action in ( + "business_advanced_security.disabled", + "business_advanced_security.disabled_for_new_repos", + "business_advanced_security.disabled_for_new_user_namespace_repos", + "business_advanced_security.user_namespace_repos_disabled", + "org.advanced_security_disabled_on_all_repos", + "org.advanced_security_disabled_for_new_repos", + "org.advanced_security_policy_selected_member_disabled" + ) +| keep + _id, + _index, + _version, + @timestamp, + event.action, + user.name, + github.org, + github.repo, + github.actor_ip, + github.hashed_token, + github.programmatic_access_type, + github.user_agent, + github.business + +---------------------------------- + +*Framework*: MITRE ATT&CK^TM^ + +* Tactic: +** Name: Defense Evasion +** ID: TA0005 +** Reference URL: https://attack.mitre.org/tactics/TA0005/ +* Technique: +** Name: Impair Defenses +** ID: T1562 +** Reference URL: https://attack.mitre.org/techniques/T1562/ +* Sub-technique: +** Name: Disable or Modify Tools +** ID: T1562.001 +** Reference URL: https://attack.mitre.org/techniques/T1562/001/ diff --git a/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-github-api-failed-access-burst.asciidoc b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-github-api-failed-access-burst.asciidoc new file mode 100644 index 0000000000..e8cc83aa3c --- /dev/null +++ b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-github-api-failed-access-burst.asciidoc @@ -0,0 +1,135 @@ +[[prebuilt-rule-8-19-37-github-api-failed-access-burst]] +=== GitHub API Failed Access Burst + +Detects a burst of failed GitHub API requests (HTTP 4xx/5xx) recorded as `api.request`, where a single non-bot actor and source IP generate a high volume of failures spread across many distinct API routes within a short window. An adversary probing private repositories, secrets, or admin routes produces clusters of 401/403/404 responses across many endpoints, whereas broken automation usually hammers a small number of routes. Grouping by actor and source IP and requiring both a high failure count and a high number of distinct routes separates broad enumeration from a single misconfigured integration. Requires API Request Events on GitHub audit log streaming. + +*Rule type*: esql + +*Rule indices*: None + +*Severity*: low + +*Risk score*: 21 + +*Runs every*: 10m + +*Searches indices from*: now-11m ({ref}/common-options.html#date-math[Date Math format], see also <>) + +*Maximum alerts per execution*: 100 + +*References*: + +* https://securitylabs.datadoghq.com/articles/mapping-out-your-unknown-threat-hunters-guide-to-github/ +* https://docs.github.com/en/enterprise-cloud@latest/admin/monitoring-activity-in-your-enterprise/reviewing-audit-logs-for-your-enterprise/streaming-the-audit-log-for-your-enterprise#enabling-api-request-events + +*Tags*: + +* Domain: Cloud +* Domain: SaaS +* Platform: GitHub +* Use Case: Threat Detection +* Tactic: Discovery +* Data Source: Github +* Data Source: GitHub Audit Logs +* Rule Type: ES|QL +* Resources: Investigation Guide + +*Version*: 1 + +*Rule authors*: + +* Elastic + +*Rule license*: Elastic License v2 + + +==== Investigation guide + + + +*Triage and analysis* + + +> **Disclaimer**: +> This investigation guide was created using generative AI technology and has been reviewed to improve its accuracy and relevance. While every effort has been made to ensure its quality, we recommend validating the content and adapting it to suit your specific environment and operational needs. + + +*Investigating GitHub API Failed Access Burst* + + +Failed `api.request` status codes often precede successful enumeration after the attacker finds a valid path or token. This rule groups failed requests by `user.name` and `github.actor_ip` and fires when a single actor/IP produces at least 15 failures spread across 10 or more distinct API routes in the window, which distinguishes broad enumeration from a single broken integration hammering one endpoint. + + +*Possible investigation steps* + + +- Review the alerting `user.name` and `github.actor_ip`, and inspect `Esql.distinct_route_count` and `Esql.github_route_values` to see which routes were probed. +- Review `Esql.github_status_code_values` to confirm the mix of 401/403/404 responses typical of access probing. +- Pivot on `Esql.github_token_id_values` and `Esql.github_programmatic_access_type_values` to identify the token and access method used. +- Check `Esql.distinct_repo_count` and `Esql.github_org_values` to gauge how broadly the actor is probing across repositories and organizations. +- Look for a later run of 200s on secrets, trees, or contents from the same actor or token, which indicates successful enumeration. + + +*False positive analysis* + + +- CI or inventory tooling using a token that lacks repo scope against private repositories. These typically hit a small number of routes, so review `Esql.distinct_route_count` and the route values before dismissing. +- Expired or rotated tokens causing widespread 401s from a known automation IP. + + +*Response and remediation* + + +- Revoke the token if the actor is not a known automation identity. Tighten org PAT policies. +- Block or monitor the source IP if the activity is clearly reconnaissance. +- Review whether any probed route later returned a success for the same actor. + + +==== Setup + + + +*Setup* + + +Requires the Elastic GitHub integration, GitHub Enterprise audit log streaming, and **Enable API Request Events**. + + +==== Rule query + + +[source, js] +---------------------------------- +from logs-github.audit-* metadata _id, _index, _version +| where + data_stream.dataset == "github.audit" and event.action == "api.request" and github.status_code >= 400 + and (github.actor_is_bot == false or github.actor_is_bot is null) +| stats + Esql.event_count = COUNT(*), + Esql.distinct_route_count = COUNT_DISTINCT(github.route), + Esql.distinct_repo_count = COUNT_DISTINCT(github.repo), + Esql.github_route_values = values(github.route), + Esql.github_status_code_values = values(github.status_code), + Esql.github_org_values = values(github.org), + Esql.github_programmatic_access_type_values = values(github.programmatic_access_type), + Esql.github_user_agent_values = values(github.user_agent), + Esql.agent_id_values = values(agent.id), + Esql.data_stream_dataset_values = values(data_stream.dataset), + Esql.data_stream_namespace_values = values(data_stream.namespace), + Esql.github_token_id_values = values(github.token_id) + by user.name, github.actor_ip +| keep user.name, github.actor_ip, Esql.* +| where Esql.event_count >= 15 and Esql.distinct_route_count >= 10 + +---------------------------------- + +*Framework*: MITRE ATT&CK^TM^ + +* Tactic: +** Name: Discovery +** ID: TA0007 +** Reference URL: https://attack.mitre.org/tactics/TA0007/ +* Technique: +** Name: Cloud Service Discovery +** ID: T1526 +** Reference URL: https://attack.mitre.org/techniques/T1526/ diff --git a/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-github-api-sensitive-resource-enumeration.asciidoc b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-github-api-sensitive-resource-enumeration.asciidoc new file mode 100644 index 0000000000..334bdafda3 --- /dev/null +++ b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-github-api-sensitive-resource-enumeration.asciidoc @@ -0,0 +1,170 @@ +[[prebuilt-rule-8-19-37-github-api-sensitive-resource-enumeration]] +=== GitHub API Sensitive Resource Enumeration + +Detects a burst of GitHub `api.request` events from a single non-bot actor and source IP against sensitive routes such as Actions/Dependabot/environment secrets, public keys, git trees and contents, zipball archives, organization repository and member lists, webhooks, installations, and personal access tokens. Grouping by actor and source IP and requiring a high request count spread across several distinct sensitive routes separates broad enumeration from a single high-volume endpoint. This pattern is commonly used for credential discovery and source collection after token theft. Requires GitHub Enterprise audit log streaming with API Request Events enabled. + +*Rule type*: esql + +*Rule indices*: None + +*Severity*: medium + +*Risk score*: 47 + +*Runs every*: 10m + +*Searches indices from*: now-11m ({ref}/common-options.html#date-math[Date Math format], see also <>) + +*Maximum alerts per execution*: 100 + +*References*: + +* https://securitylabs.datadoghq.com/articles/mapping-out-your-unknown-threat-hunters-guide-to-github/ +* https://docs.github.com/en/enterprise-cloud@latest/admin/monitoring-activity-in-your-enterprise/reviewing-audit-logs-for-your-enterprise/streaming-the-audit-log-for-your-enterprise#enabling-api-request-events + +*Tags*: + +* Domain: Cloud +* Domain: SaaS +* Platform: GitHub +* Use Case: Threat Detection +* Tactic: Discovery +* Tactic: Credential Access +* Tactic: Collection +* Data Source: Github +* Data Source: GitHub Audit Logs +* Rule Type: ES|QL +* Resources: Investigation Guide + +*Version*: 1 + +*Rule authors*: + +* Elastic + +*Rule license*: Elastic License v2 + + +==== Investigation guide + + + +*Triage and analysis* + + +> **Disclaimer**: +> This investigation guide was created using generative AI technology and has been reviewed to improve its accuracy and relevance. While every effort has been made to ensure its quality, we recommend validating the content and adapting it to suit your specific environment and operational needs. + + +*Investigating GitHub API Sensitive Resource Enumeration* + + +`api.request` is a streaming-only audit action (available with GitHub Enterprise audit log streaming and API Request Events enabled). Sensitive routes include Actions/Dependabot/environment secrets, public keys, git trees, contents, zipball archives, organization repository lists, members, webhooks, installations, and personal access tokens. The rule groups requests by `user.name` and `github.actor_ip` in a 10-minute window and fires on >= 15 requests spanning >= 3 distinct sensitive routes, which distinguishes broad enumeration from a single high-volume route. Automated actors (`github.actor_is_bot: true`) and requests without an actor IP are excluded. An adversary who has stolen a token commonly enumerates these routes to locate secrets and source code before pulling them, so this activity frequently precedes successful credential access or source collection. + + +*Possible investigation steps* + + +- Review the distinct routes probed (`Esql.github_route_values`, `Esql.github_route_unique_count`) and the breadth across repositories and organizations (`Esql.github_repo_unique_count`, `Esql.github_org_values`) to gauge how targeted or broad the enumeration is. +- Identify the token and access method from `Esql.github_token_id_values` and `Esql.github_programmatic_access_type_values`, and confirm whether the token belongs to known automation. +- Review `Esql.github_user_agent_values` for the client; treat user agents containing tooling signatures such as `trufflehog` or `nord-stream` as credential-stealer tooling. +- Pivot on `github.actor_ip` and `user.name` and correlate with `git.clone`, `repo.download_zip`, and secret-scanning alerts from the same actor or token, which indicate the enumeration led to collection. +- Check for a later run of successful (2xx) requests on secrets, trees, or contents from the same actor or token, which indicates successful enumeration rather than failed probing. + + +*False positive analysis* + + +- Internal inventory, backup, or secret-rotation automation and GitHub App servers that enumerate installations, repositories, and secrets. These typically use a known token and user agent; confirm and scope exceptions by actor, token, or user agent when expected. +- Security tooling that legitimately scans repositories for exposed secrets from a known source. + + +*Response and remediation* + + +- Revoke the token if the actor is not a known automation identity, and rotate any secrets exposed on the enumerated routes. +- Review PAT and OAuth grants for the actor, and tighten organization PAT access and approval policies. +- Block or monitor the source IP if the activity is clearly reconnaissance, and review whether any probed route later returned a success for the same actor. +- Escalate to incident response if the enumeration is followed by secret access, repository cloning, or ZIP downloads from the same actor or token. + + +==== Setup + + + +*Setup* + + +Requires the Elastic GitHub integration (`logs-github.audit-*`), GitHub Enterprise audit log streaming, and **Enable API Request Events** on the enterprise. `api.request` is not available via the REST audit-log API. + + +==== Rule query + + +[source, js] +---------------------------------- +from logs-github.audit-* metadata _id, _index, _version +| where + data_stream.dataset == "github.audit" and event.action == "api.request" and + github.actor_ip is not null and (github.actor_is_bot is not null and github.actor_is_bot == false) and + ( + github.route like "*secrets*" or + github.route like "*public-key*" or + github.route like "*git/trees*" or + github.route like "*contents*" or + github.route like "*zipball*" or + github.route like "*hooks*" or + github.route like "*installations*" or + github.route like "*members*" or + github.route like "*outside_collaborators*" or + github.route like "*personal-access-token*" or + github.route == "/organizations/:organization_id/repos" + ) +| stats + Esql.event_count = COUNT(*), + Esql.github_route_unique_count = COUNT_DISTINCT(github.route), + Esql.github_repo_unique_count = COUNT_DISTINCT(github.repo), + Esql.github_route_values = VALUES(github.route), + Esql.github_org_values = VALUES(github.org), + Esql.github_programmatic_access_type_values = VALUES(github.programmatic_access_type), + Esql.github_user_agent_values = VALUES(github.user_agent), + Esql.agent_id_values = VALUES(agent.id), + Esql.data_stream_dataset_values = VALUES(data_stream.dataset), + Esql.data_stream_namespace_values = VALUES(data_stream.namespace), + Esql.github_token_id_values = VALUES(github.token_id) + by user.name, github.actor_ip, Esql.time_window = DATE_TRUNC(10 minutes, @timestamp) +| keep user.name, github.actor_ip, Esql.* +| where Esql.event_count >= 15 and Esql.github_route_unique_count >= 3 + +---------------------------------- + +*Framework*: MITRE ATT&CK^TM^ + +* Tactic: +** Name: Discovery +** ID: TA0007 +** Reference URL: https://attack.mitre.org/tactics/TA0007/ +* Technique: +** Name: Cloud Service Discovery +** ID: T1526 +** Reference URL: https://attack.mitre.org/techniques/T1526/ +* Tactic: +** Name: Credential Access +** ID: TA0006 +** Reference URL: https://attack.mitre.org/tactics/TA0006/ +* Technique: +** Name: Unsecured Credentials +** ID: T1552 +** Reference URL: https://attack.mitre.org/techniques/T1552/ +* Tactic: +** Name: Collection +** ID: TA0009 +** Reference URL: https://attack.mitre.org/tactics/TA0009/ +* Technique: +** Name: Data from Information Repositories +** ID: T1213 +** Reference URL: https://attack.mitre.org/techniques/T1213/ +* Sub-technique: +** Name: Code Repositories +** ID: T1213.003 +** Reference URL: https://attack.mitre.org/techniques/T1213/003/ diff --git a/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-github-dependabot-alerts-or-security-updates-disabled.asciidoc b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-github-dependabot-alerts-or-security-updates-disabled.asciidoc new file mode 100644 index 0000000000..d8dd5171b6 --- /dev/null +++ b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-github-dependabot-alerts-or-security-updates-disabled.asciidoc @@ -0,0 +1,130 @@ +[[prebuilt-rule-8-19-37-github-dependabot-alerts-or-security-updates-disabled]] +=== GitHub Dependabot Alerts or Security Updates Disabled + +Detects when Dependabot alerts or security updates are disabled at the repository, organization, or enterprise level in GitHub. Adversaries may turn off Dependabot to reduce the chance that a malicious or vulnerable dependency they introduced is flagged; disabling it for an organization or enterprise removes this coverage across many repositories at once. + +*Rule type*: esql + +*Rule indices*: None + +*Severity*: medium + +*Risk score*: 47 + +*Runs every*: 5m + +*Searches indices from*: now-9m ({ref}/common-options.html#date-math[Date Math format], see also <>) + +*Maximum alerts per execution*: 100 + +*References*: + +* https://docs.github.com/en/code-security/getting-started/dependabot-quickstart-guide + +*Tags*: + +* Domain: Cloud +* Domain: SaaS +* Platform: GitHub +* Use Case: Threat Detection +* Tactic: Defense Evasion +* Data Source: Github +* Data Source: GitHub Audit Logs +* Rule Type: ESQL +* Resources: Investigation Guide + +*Version*: 1 + +*Rule authors*: + +* Elastic + +*Rule license*: Elastic License v2 + + +==== Investigation guide + + + +*Triage and analysis* + + + +*Investigating GitHub Dependabot Alerts or Security Updates Disabled* + + +Disabling Dependabot removes automated visibility into vulnerable and malicious packages. This can precede a supply-chain commit or lockfile change. Repository-level actions affect a single repo, while `dependabot_*` (organization) and `business_dependabot_*` (enterprise) actions remove coverage across many repositories at once. + + +*Possible investigation steps* + + +- Identify `user.name`, `github.org`, `github.repo`, `event.action`, and `github.programmatic_access_type`, and note whether the action is repository-, organization-, or enterprise-scoped. +- Review commits and dependency manifest changes around the disable timestamp. +- Check whether Secret Scanning, code scanning, or the org security configuration were also changed. +- Re-enable Dependabot unless there is an approved exception. + + +*False positive analysis* + + +- Bulk disable on forks, mirrors, or documentation-only repositories. +- Org-policy automation that detaches a security configuration. + + +*Response and remediation* + + +- Re-enable Dependabot alerts (and security updates if required by policy). +- Audit recently added dependencies and workflow files. +- Rotate credentials if the actor is not a known admin. + + +==== Rule query + + +[source, js] +---------------------------------- +from logs-github.audit-* metadata _id, _index, _version +| where + event.module == "github" and data_stream.dataset == "github.audit" + and event.action in ( + "repository_vulnerability_alerts.disable", + "repository_security_updates.disable", + "dependabot_alerts.disable", + "dependabot_alerts_new_repos.disable", + "dependabot_security_updates.disable", + "dependabot_security_updates_new_repos.disable", + "business_dependabot_alerts.disable", + "business_dependabot_alerts_new_repos.disable" + ) +| keep + _id, + _index, + _version, + @timestamp, + event.action, + user.name, + github.org, + github.repo, + github.actor_ip, + github.hashed_token, + github.programmatic_access_type, + github.user_agent + +---------------------------------- + +*Framework*: MITRE ATT&CK^TM^ + +* Tactic: +** Name: Defense Evasion +** ID: TA0005 +** Reference URL: https://attack.mitre.org/tactics/TA0005/ +* Technique: +** Name: Impair Defenses +** ID: T1562 +** Reference URL: https://attack.mitre.org/techniques/T1562/ +* Sub-technique: +** Name: Disable or Modify Tools +** ID: T1562.001 +** Reference URL: https://attack.mitre.org/techniques/T1562/001/ diff --git a/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-github-fine-grained-pat-auto-approve-enabled.asciidoc b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-github-fine-grained-pat-auto-approve-enabled.asciidoc new file mode 100644 index 0000000000..20f314af3d --- /dev/null +++ b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-github-fine-grained-pat-auto-approve-enabled.asciidoc @@ -0,0 +1,142 @@ +[[prebuilt-rule-8-19-37-github-fine-grained-pat-auto-approve-enabled]] +=== GitHub Fine-Grained PAT Auto-Approve Enabled + +Detects when automatic approval of fine-grained personal access token (PAT) requests is enabled for a GitHub organization. With auto-approval off, an owner must review and approve each fine-grained PAT before it can access organization resources; once enabled, members' PAT requests gain access without that review, removing a key control over programmatic access. Following an account takeover, an adversary with owner access may enable auto-approval to quietly provision long-lived, organization-scoped tokens for persistence and data access, making this a high-impact change to the organization's programmatic-access controls. + +*Rule type*: esql + +*Rule indices*: None + +*Severity*: medium + +*Risk score*: 47 + +*Runs every*: 5m + +*Searches indices from*: now-9m ({ref}/common-options.html#date-math[Date Math format], see also <>) + +*Maximum alerts per execution*: 100 + +*References*: + +* https://github.blog/security/application-security/introducing-fine-grained-personal-access-tokens-for-github/ +* https://docs.github.com/en/organizations/managing-programmatic-access-to-your-organization/setting-a-personal-access-token-policy-for-your-organization + +*Tags*: + +* Domain: Cloud +* Domain: SaaS +* Platform: GitHub +* Use Case: Threat Detection +* Tactic: Persistence +* Tactic: Defense Evasion +* Data Source: Github +* Data Source: GitHub Audit Logs +* Rule Type: ESQL +* Resources: Investigation Guide + +*Version*: 1 + +*Rule authors*: + +* Elastic + +*Rule license*: Elastic License v2 + + +==== Investigation guide + + + +*Triage and analysis* + + +> **Disclaimer**: +> This investigation guide was created using generative AI technology and has been reviewed to improve its accuracy and relevance. While every effort has been made to ensure its quality, we recommend validating the content and adapting it to suit your specific environment and operational needs. + + +*Investigating GitHub Fine-Grained PAT Auto-Approve Enabled* + + +`auto_approve_personal_access_token_requests.enable` turns on automatic approval of fine-grained personal access token (PAT) requests for an organization. Once enabled, members' fine-grained PAT requests gain access to organization resources without an owner reviewing and approving each request, removing a key control over programmatic access. Adversaries with owner access may enable this to quietly provision long-lived, organization-scoped tokens for persistence. + +This is a different control from the PAT *access restriction*. Disabling that restriction is `personal_access_token.access_restriction_disabled`, which is covered by a separate rule. Disabling auto-approval (`auto_approve_personal_access_token_requests.disable`) restores the owner-review requirement and is a hardening action, so it is intentionally not alerted here. + + +*Possible investigation steps* + + +- Review `user.name`, `github.org`, and `github.actor_ip` to confirm whether an authorized organization owner made the change, and from an expected location and client. +- Determine whether the change aligns with a documented policy decision or change ticket; auto-approval is sometimes enabled intentionally to streamline trusted PAT workflows. +- List `personal_access_token.access_granted` events after the change to identify PATs that were auto-approved, and review their scopes and target repositories. +- Correlate with private `git.clone` / `git.push` and other programmatic activity performed by the newly granted tokens. +- Check for other recent control changes (owner additions, PAT access restriction disabled, MFA or OAuth App restriction changes) that may indicate a broader tampering campaign. + + +*False positive analysis* + + +- Organizations may legitimately enable auto-approval to reduce administrative overhead for trusted internal fine-grained PAT workflows. Confirm the change is expected and, if so, scope exceptions by actor or correlate with a change ticket. +- Policy experiments in non-production organizations. + + +*Response and remediation* + + +- If the change is unauthorized, disable auto-approval to restore the owner-review requirement. +- Review and revoke fine-grained PATs that were granted while auto-approval was enabled. +- Audit the resources and repositories accessed by those tokens and rotate any exposed secrets. +- Confirm the actor's account is not compromised and review their other recent administrative actions. + + +==== Rule query + + +[source, js] +---------------------------------- +from logs-github.audit-* metadata _id, _index, _version +| where + event.module == "github" and data_stream.dataset == "github.audit" + and event.action == "auto_approve_personal_access_token_requests.enable" +| keep + _id, + _index, + _version, + @timestamp, + event.action, + user.name, + github.org, + github.repo, + github.actor_ip, + github.hashed_token, + github.programmatic_access_type, + github.user_agent + +---------------------------------- + +*Framework*: MITRE ATT&CK^TM^ + +* Tactic: +** Name: Defense Evasion +** ID: TA0005 +** Reference URL: https://attack.mitre.org/tactics/TA0005/ +* Technique: +** Name: Impair Defenses +** ID: T1562 +** Reference URL: https://attack.mitre.org/techniques/T1562/ +* Technique: +** Name: Domain or Tenant Policy Modification +** ID: T1484 +** Reference URL: https://attack.mitre.org/techniques/T1484/ +* Tactic: +** Name: Persistence +** ID: TA0003 +** Reference URL: https://attack.mitre.org/tactics/TA0003/ +* Technique: +** Name: Account Manipulation +** ID: T1098 +** Reference URL: https://attack.mitre.org/techniques/T1098/ +* Sub-technique: +** Name: Additional Cloud Credentials +** ID: T1098.001 +** Reference URL: https://attack.mitre.org/techniques/T1098/001/ diff --git a/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-github-ip-allow-list-modified.asciidoc b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-github-ip-allow-list-modified.asciidoc new file mode 100644 index 0000000000..217b1be506 --- /dev/null +++ b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-github-ip-allow-list-modified.asciidoc @@ -0,0 +1,143 @@ +[[prebuilt-rule-8-19-37-github-ip-allow-list-modified]] +=== GitHub IP Allow List Modified + +Detects changes to a GitHub organization IP allow list: creating, updating, or deleting allow-list entries, or enabling/disabling allow-list enforcement (including enforcement for installed GitHub Apps, the IdP-provided web allow list, and user-level enforcement). Adversaries with org-owner access may add or modify their own address, then enable enforcement, or weaken enforcement and remove legitimate entries to lock out administrators. + +*Rule type*: esql + +*Rule indices*: None + +*Severity*: medium + +*Risk score*: 47 + +*Runs every*: 5m + +*Searches indices from*: now-9m ({ref}/common-options.html#date-math[Date Math format], see also <>) + +*Maximum alerts per execution*: 100 + +*References*: + +* https://docs.github.com/en/organizations/keeping-your-organization-secure/managing-security-settings-for-your-organization/managing-allowed-ip-addresses-for-your-organization + +*Tags*: + +* Domain: Cloud +* Domain: SaaS +* Platform: GitHub +* Use Case: Threat Detection +* Tactic: Defense Evasion +* Tactic: Persistence +* Data Source: Github +* Data Source: GitHub Audit Logs +* Rule Type: ESQL +* Resources: Investigation Guide + +*Version*: 1 + +*Rule authors*: + +* Elastic + +*Rule license*: Elastic License v2 + + +==== Investigation guide + + + +*Triage and analysis* + + + +*Investigating GitHub IP Allow List Modified* + + +IP allow list entries are often staged before enforcement. An attacker can add a malicious egress IP, then enable the list to persist access and lock out responders. + + +*Possible investigation steps* + + +- Identify `user.name`, `github.actor_ip`, and `github.programmatic_access_type`. +- In GitHub org authentication security settings, review the entry that was added or removed and whether the allow list is enabled. +- Treat `ip_allow_list.enable` as higher urgency than an entry create: enforcement can lock out responders. +- Correlate with unusual `git.clone` / `git.push` from new source IPs. + + +*False positive analysis* + + +- Adding and removing a test entry during network onboarding. +- Automation that syncs allow list entries from a CMDB. + + +*Response and remediation* + + +- Remove unauthorized entries and confirm enforcement state matches policy. +- Do not enable enforcement until trusted egress IPs are present, to avoid lockout. +- Rotate credentials for the actor if the change was not approved. + + +==== Rule query + + +[source, js] +---------------------------------- +from logs-github.audit-* metadata _id, _index, _version +| where + event.module == "github" and data_stream.dataset == "github.audit" + and event.action in ( + "ip_allow_list_entry.create", + "ip_allow_list_entry.update", + "ip_allow_list_entry.destroy", + "ip_allow_list.enable", + "ip_allow_list.disable", + "ip_allow_list.enable_for_installed_apps", + "ip_allow_list.disable_for_installed_apps", + "ip_allow_list.enable_idp_ip_allowlist_for_web", + "ip_allow_list.disable_idp_ip_allowlist_for_web", + "ip_allow_list.enable_user_level_enforcement", + "ip_allow_list.disable_user_level_enforcement" + ) +| keep + _id, + _index, + _version, + @timestamp, + event.action, + user.name, + github.org, + github.repo, + github.actor_ip, + github.hashed_token, + github.programmatic_access_type, + github.user_agent, + github.name + +---------------------------------- + +*Framework*: MITRE ATT&CK^TM^ + +* Tactic: +** Name: Defense Evasion +** ID: TA0005 +** Reference URL: https://attack.mitre.org/tactics/TA0005/ +* Technique: +** Name: Impair Defenses +** ID: T1562 +** Reference URL: https://attack.mitre.org/techniques/T1562/ +* Sub-technique: +** Name: Disable or Modify Cloud Firewall +** ID: T1562.007 +** Reference URL: https://attack.mitre.org/techniques/T1562/007/ +* Tactic: +** Name: Persistence +** ID: TA0003 +** Reference URL: https://attack.mitre.org/tactics/TA0003/ +* Technique: +** Name: Modify Authentication Process +** ID: T1556 +** Reference URL: https://attack.mitre.org/techniques/T1556/ diff --git a/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-github-mfa-requirement-disabled.asciidoc b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-github-mfa-requirement-disabled.asciidoc new file mode 100644 index 0000000000..47dd31b4e8 --- /dev/null +++ b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-github-mfa-requirement-disabled.asciidoc @@ -0,0 +1,139 @@ +[[prebuilt-rule-8-19-37-github-mfa-requirement-disabled]] +=== GitHub MFA Requirement Disabled + +Detects when the two-factor authentication (2FA) requirement is disabled for a GitHub organization or enterprise. Removing the requirement downgrades every member in scope to password-only authentication and allows new members to be added without 2FA. Following an account takeover, an adversary may disable the requirement to preserve password-based access, reduce friction for enrolling attacker-controlled accounts, and lower the organization's overall account-takeover resistance, making this a high-impact identity-control change. + +*Rule type*: esql + +*Rule indices*: None + +*Severity*: high + +*Risk score*: 73 + +*Runs every*: 5m + +*Searches indices from*: now-9m ({ref}/common-options.html#date-math[Date Math format], see also <>) + +*Maximum alerts per execution*: 100 + +*References*: + +* https://docs.github.com/en/organizations/keeping-your-organization-secure/managing-two-factor-authentication-for-your-organization/requiring-two-factor-authentication-in-your-organization +* https://docs.github.com/en/enterprise-cloud@latest/admin/monitoring-activity-in-your-enterprise/reviewing-audit-logs-for-your-enterprise/audit-log-events-for-your-enterprise + +*Tags*: + +* Domain: Cloud +* Domain: SaaS +* Platform: GitHub +* Use Case: Threat Detection +* Tactic: Credential Access +* Tactic: Defense Evasion +* Data Source: Github +* Data Source: GitHub Audit Logs +* Rule Type: ESQL +* Resources: Investigation Guide + +*Version*: 1 + +*Rule authors*: + +* Elastic + +*Rule license*: Elastic License v2 + + +==== Investigation guide + + + +*Triage and analysis* + + +> **Disclaimer**: +> This investigation guide was created using generative AI technology and has been reviewed to improve its accuracy and relevance. While every effort has been made to ensure its quality, we recommend validating the content and adapting it to suit your specific environment and operational needs. + + +*Investigating GitHub MFA Requirement Disabled* + + +This rule triggers on `business.disable_two_factor_requirement` and `org.disable_two_factor_requirement`, which turn off the enforced two-factor authentication (2FA) requirement for an entire GitHub enterprise or organization. Removing the requirement downgrades every member in scope to password-only authentication and permits new members to be invited without 2FA. An adversary who has taken over an owner or enterprise-admin account may disable the requirement to preserve password-based access, reduce friction for adding attacker-controlled accounts, and lower the organization's account-takeover resistance before pursuing persistence, privilege escalation, or data theft. + + +*Possible investigation steps* + + +- Identify the actor from `user.name`, `github.actor_ip`, `github.user_agent`, and `github.programmatic_access_type`, and confirm whether they legitimately hold organization owner or enterprise admin privileges. +- Determine the scope of the change from `event.action` (`org.disable_two_factor_requirement` vs `business.disable_two_factor_requirement`) and the affected `github.org`/`github.business`, and verify whether it was approved in change-management records. +- Review authentication context for the actor around the event time for signs of takeover, such as sign-ins from new `github.actor_ip` addresses, unfamiliar user agents, or token-based access (`github.programmatic_access_type`) in place of normal interactive activity. +- Correlate for other high-impact identity changes near the same timestamp, including owner or member additions, PAT or OAuth app grants, SSH/GPG key additions, SSO/SAML changes, and IP allow-list modifications. +- If the change is unauthorized, re-enable the 2FA requirement before continuing the investigation to limit exposure. + + +*False positive analysis* + + +- A documented break-glass procedure during an identity-provider or 2FA outage may require temporarily disabling the requirement; this should be rare, ticketed, time-bounded, and followed by immediate re-enablement. +- A planned governance or migration change (for example, consolidating organizations or adjusting enrollment policy) performed by a known administrator can generate this event as expected activity. + + +*Response and remediation* + + +- Re-enable the required 2FA setting for the affected organization or enterprise as soon as the change is confirmed unauthorized. +- Force sign-out of active sessions and audit the member list for accounts not enrolled in 2FA, requiring enrollment or suspending them. +- Rotate credentials and tokens created or used after the requirement was disabled, including PATs, OAuth app grants, and SSH keys. +- Review org and enterprise audit logs for other changes made by the actor after the disable event, and revert any unauthorized modifications. +- Escalate to incident response if the actor is unknown or unauthorized, or if the disable event is accompanied by new owner additions, token grants, or sign-ins from unfamiliar infrastructure. +- Harden by enforcing 2FA at the enterprise level, restricting who can change organization security settings, and alerting on future changes to the 2FA requirement. + + +==== Rule query + + +[source, js] +---------------------------------- +from logs-github.audit-* metadata _id, _index, _version +| where + event.module == "github" and data_stream.dataset == "github.audit" + and event.action in ("business.disable_two_factor_requirement", "org.disable_two_factor_requirement") +| keep + _id, + _index, + _version, + @timestamp, + event.action, + user.name, + github.org, + github.repo, + github.actor_ip, + github.hashed_token, + github.programmatic_access_type, + github.user_agent, + github.business + +---------------------------------- + +*Framework*: MITRE ATT&CK^TM^ + +* Tactic: +** Name: Defense Evasion +** ID: TA0005 +** Reference URL: https://attack.mitre.org/tactics/TA0005/ +* Technique: +** Name: Impair Defenses +** ID: T1562 +** Reference URL: https://attack.mitre.org/techniques/T1562/ +* Tactic: +** Name: Credential Access +** ID: TA0006 +** Reference URL: https://attack.mitre.org/tactics/TA0006/ +* Technique: +** Name: Modify Authentication Process +** ID: T1556 +** Reference URL: https://attack.mitre.org/techniques/T1556/ +* Sub-technique: +** Name: Multi-Factor Authentication +** ID: T1556.006 +** Reference URL: https://attack.mitre.org/techniques/T1556/006/ diff --git a/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-github-oauth-app-access-restrictions-disabled.asciidoc b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-github-oauth-app-access-restrictions-disabled.asciidoc new file mode 100644 index 0000000000..40200577df --- /dev/null +++ b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-github-oauth-app-access-restrictions-disabled.asciidoc @@ -0,0 +1,135 @@ +[[prebuilt-rule-8-19-37-github-oauth-app-access-restrictions-disabled]] +=== GitHub OAuth App Access Restrictions Disabled + +Detects when OAuth App access restrictions are disabled for a GitHub organization. With restrictions enabled, only owner-approved OAuth Apps can access organization data; once disabled, any OAuth App that a member authorizes gains access without owner review. Following an account takeover, an adversary may disable restrictions and then authorize a malicious or attacker-controlled OAuth App to establish token-based persistence and exfiltrate repository data, making this a high-impact change to the organization's third-party access controls. + +*Rule type*: esql + +*Rule indices*: None + +*Severity*: high + +*Risk score*: 73 + +*Runs every*: 5m + +*Searches indices from*: now-9m ({ref}/common-options.html#date-math[Date Math format], see also <>) + +*Maximum alerts per execution*: 100 + +*References*: + +* https://docs.github.com/en/organizations/managing-oauth-access-to-your-organizations-data/disabling-oauth-app-access-restrictions-for-your-organization + +*Tags*: + +* Domain: Cloud +* Domain: SaaS +* Platform: GitHub +* Use Case: Threat Detection +* Tactic: Defense Evasion +* Data Source: Github +* Data Source: GitHub Audit Logs +* Rule Type: ES|QL +* Resources: Investigation Guide + +*Version*: 1 + +*Rule authors*: + +* Elastic + +*Rule license*: Elastic License v2 + + +==== Investigation guide + + + +*Triage and analysis* + + +> **Disclaimer**: +> This investigation guide was created using generative AI technology and has been reviewed to improve its accuracy and relevance. While every effort has been made to ensure its quality, we recommend validating the content and adapting it to suit your specific environment and operational needs. + + +*Investigating GitHub OAuth App Access Restrictions Disabled* + + +This rule triggers on `org.disable_oauth_app_restrictions`, which turns off the organization control that limits third-party OAuth App access to owner-approved apps. Once disabled, any OAuth App a member authorizes can access organization data without owner review. An adversary who has taken over an owner account commonly chains this with `oauth_authorization.create` to grant a malicious OAuth App broad, token-based access to repositories and organization resources, establishing persistence and a data-exfiltration path that survives password and session resets. + + +*Possible investigation steps* + + +- Identify the actor from `user.name`, `github.actor_ip`, `github.user_agent`, and `github.programmatic_access_type`, and confirm whether they legitimately hold organization owner privileges. +- Determine whether the change was expected by checking change-management records and the affected `github.org`, and confirm whether OAuth App restrictions were previously enforced. +- Review OAuth authorization events (`oauth_authorization.create`) and third-party app grants created after the disable timestamp, prioritizing apps with broad scopes or unfamiliar publishers. +- Review authentication context for the actor around the event time for signs of takeover, such as sign-ins from new `github.actor_ip` addresses, unfamiliar user agents, or token-based access (`github.programmatic_access_type`) instead of normal interactive activity. +- Correlate for other high-impact identity or policy changes near the same timestamp, including owner or member additions, PAT grants, SSO/SAML changes, and 2FA requirement changes. + + +*False positive analysis* + + +- An organization owner temporarily disables restrictions to onboard an approved vendor app; this should be ticketed and followed by re-enabling restrictions and explicitly approving the specific app instead. +- A planned governance or migration change performed by a known administrator can generate this event as expected activity. + + +*Response and remediation* + + +- Re-enable OAuth App access restrictions for the organization as soon as the change is confirmed unauthorized, and approve required apps individually rather than leaving restrictions off. +- Review and revoke OAuth App authorizations granted after the disable event, especially apps with broad scopes or no business justification. +- Rotate credentials and tokens potentially exposed through authorized apps, including PATs, OAuth grants, and any secrets accessible to the granted apps. +- Review org audit logs for other changes made by the actor after the disable event, and revert any unauthorized modifications. +- Escalate to incident response if the actor is unknown or unauthorized, or if the disable event is followed by new OAuth grants, owner additions, or sign-ins from unfamiliar infrastructure. +- Harden by enforcing OAuth App access restrictions org-wide, restricting who can change organization security settings, and alerting on future changes to OAuth App restrictions and new third-party app authorizations. + + +==== Rule query + + +[source, js] +---------------------------------- +from logs-github.audit-* metadata _id, _index, _version +| where + event.module == "github" and data_stream.dataset == "github.audit" + and event.action == "org.disable_oauth_app_restrictions" +| keep + _id, + _index, + _version, + @timestamp, + event.action, + user.name, + github.org, + github.actor_ip, + github.hashed_token, + github.programmatic_access_type, + github.user_agent + +---------------------------------- + +*Framework*: MITRE ATT&CK^TM^ + +* Tactic: +** Name: Defense Evasion +** ID: TA0005 +** Reference URL: https://attack.mitre.org/tactics/TA0005/ +* Technique: +** Name: Domain or Tenant Policy Modification +** ID: T1484 +** Reference URL: https://attack.mitre.org/techniques/T1484/ +* Technique: +** Name: Impair Defenses +** ID: T1562 +** Reference URL: https://attack.mitre.org/techniques/T1562/ +* Sub-technique: +** Name: Disable or Modify Tools +** ID: T1562.001 +** Reference URL: https://attack.mitre.org/techniques/T1562/001/ +* Technique: +** Name: Domain or Tenant Policy Modification +** ID: T1484 +** Reference URL: https://attack.mitre.org/techniques/T1484/ diff --git a/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-github-oauth-application-authorized.asciidoc b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-github-oauth-application-authorized.asciidoc new file mode 100644 index 0000000000..43a7a2c6f9 --- /dev/null +++ b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-github-oauth-application-authorized.asciidoc @@ -0,0 +1,136 @@ +[[prebuilt-rule-8-19-37-github-oauth-application-authorized]] +=== GitHub OAuth Application Authorized + +Detects when a user authorizes a GitHub OAuth application. Stolen OAuth grants persist after password changes until revoked and can clone or ZIP private repositories. This is not a GitHub App installation (integration_installation.create). + +*Rule type*: esql + +*Rule indices*: None + +*Severity*: low + +*Risk score*: 21 + +*Runs every*: 5m + +*Searches indices from*: now-9m ({ref}/common-options.html#date-math[Date Math format], see also <>) + +*Maximum alerts per execution*: 100 + +*References*: + +* https://securitylabs.datadoghq.com/articles/mapping-out-your-unknown-threat-hunters-guide-to-github/ +* https://github.blog/news-insights/company-news/security-alert-stolen-oauth-user-tokens/ +* https://github.blog/news-insights/company-news/security-alert-new-phishing-campaign-targets-github-users/ +* https://docs.github.com/en/apps/oauth-apps/using-oauth-apps/authorizing-oauth-apps + +*Tags*: + +* Domain: Cloud +* Domain: SaaS +* Domain: Identity +* Platform: GitHub +* Profile: Beta +* Use Case: Threat Detection +* Tactic: Credential Access +* Tactic: Persistence +* Threat: OAuth App Consent +* Data Source: Github +* Data Source: GitHub Audit Logs +* Rule Type: ES|QL +* Resources: Investigation Guide + +*Version*: 2 + +*Rule authors*: + +* Elastic + +*Rule license*: Elastic License v2 + + +==== Investigation guide + + + +*Triage and analysis* + + + +*Investigating GitHub OAuth Application Authorized* + + +`oauth_authorization.create` is a user grant of an OAuth App. It is distinct from installing a GitHub App. After a grant, look for `git.clone` or `repo.download_zip` with `programmatic_access_type` of OAuth access token. + + +*Possible investigation steps* + + +- Identify `user.name`, `github.oauth_application_name` / `github.oauth_application_id`, `github.actor_ip`, and `github.user_agent`. +- Confirm the app is approved by the organization. Review requested scopes. +- Pivot to clone, ZIP, and `api.request` activity from the same user shortly after the grant. + + +*False positive analysis* + + +- First-time login to an approved CI, IDE, or SaaS integration. + + +*Response and remediation* + + +- If unauthorized, revoke the OAuth grant and the application's tokens, then force a password reset and session invalidation. +- Review org third-party application restrictions. + + +==== Rule query + + +[source, js] +---------------------------------- +from logs-github.audit-* metadata _id, _index, _version +| where + event.module == "github" and data_stream.dataset == "github.audit" + and event.action == "oauth_authorization.create" +| keep + _id, + _index, + _version, + @timestamp, + event.action, + user.name, + github.org, + github.repo, + github.actor_ip, + github.hashed_token, + github.oauth_application_name, + github.oauth_application_id, + github.programmatic_access_type, + github.user_agent, + github.name + +---------------------------------- + +*Framework*: MITRE ATT&CK^TM^ + +* Tactic: +** Name: Persistence +** ID: TA0003 +** Reference URL: https://attack.mitre.org/tactics/TA0003/ +* Technique: +** Name: Valid Accounts +** ID: T1078 +** Reference URL: https://attack.mitre.org/techniques/T1078/ +* Sub-technique: +** Name: Cloud Accounts +** ID: T1078.004 +** Reference URL: https://attack.mitre.org/techniques/T1078/004/ +* Tactic: +** Name: Credential Access +** ID: TA0006 +** Reference URL: https://attack.mitre.org/tactics/TA0006/ +* Technique: +** Name: Steal Application Access Token +** ID: T1528 +** Reference URL: https://attack.mitre.org/techniques/T1528/ diff --git a/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-github-private-repository-forking-enabled.asciidoc b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-github-private-repository-forking-enabled.asciidoc new file mode 100644 index 0000000000..30dabf0fb9 --- /dev/null +++ b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-github-private-repository-forking-enabled.asciidoc @@ -0,0 +1,125 @@ +[[prebuilt-rule-8-19-37-github-private-repository-forking-enabled]] +=== GitHub Private Repository Forking Enabled + +Detects enabling of private repository forking on a GitHub organization. Allowing forks of private repositories lets code leave the organization into personal forks, which is a common collection path after an org-owner compromise. + +*Rule type*: esql + +*Rule indices*: None + +*Severity*: medium + +*Risk score*: 47 + +*Runs every*: 5m + +*Searches indices from*: now-9m ({ref}/common-options.html#date-math[Date Math format], see also <>) + +*Maximum alerts per execution*: 100 + +*References*: + +* https://docs.github.com/en/organizations/managing-organization-settings/managing-the-forking-policy-for-your-organization + +*Tags*: + +* Domain: Cloud +* Domain: SaaS +* Platform: GitHub +* Use Case: Threat Detection +* Tactic: Collection +* Tactic: Defense Evasion +* Data Source: GitHub Audit Logs +* Rule Type: ESQL +* Resources: Investigation Guide + +*Version*: 1 + +*Rule authors*: + +* Elastic + +*Rule license*: Elastic License v2 + + +==== Investigation guide + + + +*Triage and analysis* + + + +*Investigating GitHub Private Repository Forking Enabled* + + +`private_repository_forking.enable` is an organization policy change. Follow with `repo.fork` if present. + + +*Possible investigation steps* + + +- Identify `user.name`, `github.org`, and `github.actor_ip`. +- Check whether private repos were forked afterward and to which accounts. + + +*False positive analysis* + + +- Approved inner-source programs that temporarily enable forking. + + +*Response and remediation* + + +- Disable private repository forking unless required. Review forks created in the same window and transfer or delete unauthorized copies. + + +==== Rule query + + +[source, js] +---------------------------------- +from logs-github.audit-* metadata _id, _index, _version +| where + event.module == "github" and data_stream.dataset == "github.audit" + and event.action == "private_repository_forking.enable" +| keep + _id, + _index, + _version, + @timestamp, + event.action, + user.name, + github.org, + github.repo, + github.actor_ip, + github.hashed_token, + github.programmatic_access_type, + github.user_agent, + github.visibility + +---------------------------------- + +*Framework*: MITRE ATT&CK^TM^ + +* Tactic: +** Name: Collection +** ID: TA0009 +** Reference URL: https://attack.mitre.org/tactics/TA0009/ +* Technique: +** Name: Data from Information Repositories +** ID: T1213 +** Reference URL: https://attack.mitre.org/techniques/T1213/ +* Sub-technique: +** Name: Code Repositories +** ID: T1213.003 +** Reference URL: https://attack.mitre.org/techniques/T1213/003/ +* Tactic: +** Name: Defense Evasion +** ID: TA0005 +** Reference URL: https://attack.mitre.org/tactics/TA0005/ +* Technique: +** Name: Domain or Tenant Policy Modification +** ID: T1484 +** Reference URL: https://attack.mitre.org/techniques/T1484/ diff --git a/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-github-protected-branch-settings-changed.asciidoc b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-github-protected-branch-settings-changed.asciidoc new file mode 100644 index 0000000000..ab28a53ce4 --- /dev/null +++ b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-github-protected-branch-settings-changed.asciidoc @@ -0,0 +1,120 @@ +[[prebuilt-rule-8-19-37-github-protected-branch-settings-changed]] +=== GitHub Protected Branch Settings Changed + +This rule detects protected branch setting changes on a GitHub repository originating from a user agent not previously seen performing protected branch changes in the last 7 days. Branch protection rules enforce workflows and requirements before a contributor can push changes to a branch. Unauthorized changes could be used to lower your organization's security posture and leave you exposed for future attacks. Both push-time enforcement events (`protected_branch.rejected_ref_update`, a push blocked by branch protection) and administrative bypasses (`protected_branch.policy_override`) are retained, because a failed modification attempt and an admin override are each security-relevant indicators, particularly during CI/CD compromise once administrative access is obtained. Keying on a new user agent suppresses the recurring, expected automation that drives most of the event volume while surfacing changes from unfamiliar tooling or clients. If a specific user agent is noisy in a given environment, scope it with an exception rather than removing the action from the query. + +*Rule type*: new_terms + +*Rule indices*: + +* logs-github.audit-* + +*Severity*: medium + +*Risk score*: 47 + +*Runs every*: 5m + +*Searches indices from*: now-9m ({ref}/common-options.html#date-math[Date Math format], see also <>) + +*Maximum alerts per execution*: 100 + +*References*: None + +*Tags*: + +* Domain: Cloud +* Use Case: Threat Detection +* Tactic: Defense Evasion +* Data Source: Github +* Data Source: GitHub Audit Logs +* Resources: Investigation Guide +* Noise: High +* Performance: Fast +* Profile: Aggressive +* Rule Type: New Terms +* Platform: GitHub +* Domain: SaaS + +*Version*: 213 + +*Rule authors*: + +* Elastic + +*Rule license*: Elastic License v2 + + +==== Investigation guide + + + +*Triage and analysis* + + +> **Disclaimer**: +> This investigation guide was created using generative AI technology and has been reviewed to improve its accuracy and relevance. While every effort has been made to ensure its quality, we recommend validating the content and adapting it to suit your specific environment and operational needs. + + +*Investigating GitHub Protected Branch Settings Changed* + + +GitHub's protected branch settings are crucial for maintaining code integrity by enforcing rules like requiring reviews before merging. Adversaries may alter these settings to bypass security measures, facilitating unauthorized code changes. The detection rule monitors audit logs for changes in branch protection, flagging potential defense evasion attempts for further investigation. + + +*Possible investigation steps* + + +- Review the GitHub audit logs to identify the specific changes made to the protected branch settings, focusing on entries where event.dataset is "github.audit" and github.category is "protected_branch". +- Determine the user account responsible for the changes by examining the audit log details, and verify if the account has a legitimate reason to modify branch protection settings. +- Check the timing of the changes to see if they coincide with any other suspicious activities or known incidents within the organization. +- Investigate the context of the change by reviewing recent pull requests or commits to the affected branch to assess if the changes align with ongoing development activities. +- Communicate with the repository owner or relevant team members to confirm if the changes were authorized and necessary for current project requirements. +- Evaluate the impact of the changes on the repository's security posture and consider reverting the changes if they were unauthorized or pose a security risk. + + +*False positive analysis* + + +- Routine updates by trusted team members may trigger alerts. To manage this, create exceptions for specific users or teams who regularly update branch protection settings as part of their role. +- Automated tools or scripts that modify branch settings for legitimate reasons can cause false positives. Identify these tools and whitelist their activities in the monitoring system. +- Scheduled maintenance or policy updates might lead to expected changes in branch protection settings. Document these events and adjust the detection rule to ignore changes during these periods. +- Changes made by administrators during onboarding or offboarding processes can be mistaken for unauthorized activity. Ensure these processes are well-documented and communicated to the security team to prevent unnecessary alerts. + + +*Response and remediation* + + +- Immediately revert any unauthorized changes to the protected branch settings to restore the original security posture. +- Conduct a review of recent commits and merges to the affected branch to identify any unauthorized code changes that may have occurred during the period of altered settings. +- Temporarily restrict access to the repository for users who made unauthorized changes until a full investigation is completed. +- Notify the security team and relevant stakeholders about the incident for further analysis and to determine if additional security measures are needed. +- Implement additional monitoring on the affected repository to detect any further unauthorized changes or suspicious activities. +- Review and update access controls and permissions for the repository to ensure that only authorized personnel can modify branch protection settings. +- Document the incident, including the timeline of events and actions taken, to improve future response efforts and update incident response plans. + +==== Rule query + + +[source, js] +---------------------------------- +data_stream.dataset: "github.audit" and + github.category: "protected_branch" and + event.type: "change" + +---------------------------------- + +*Framework*: MITRE ATT&CK^TM^ + +* Tactic: +** Name: Defense Evasion +** ID: TA0005 +** Reference URL: https://attack.mitre.org/tactics/TA0005/ +* Technique: +** Name: Impair Defenses +** ID: T1562 +** Reference URL: https://attack.mitre.org/techniques/T1562/ +* Sub-technique: +** Name: Disable or Modify Tools +** ID: T1562.001 +** Reference URL: https://attack.mitre.org/techniques/T1562/001/ diff --git a/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-github-saml-sso-disabled.asciidoc b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-github-saml-sso-disabled.asciidoc new file mode 100644 index 0000000000..a4ae01f383 --- /dev/null +++ b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-github-saml-sso-disabled.asciidoc @@ -0,0 +1,152 @@ +[[prebuilt-rule-8-19-37-github-saml-sso-disabled]] +=== GitHub SAML SSO Disabled + +Detects when SAML single sign-on (SSO) is disabled for a GitHub enterprise or organization. SAML SSO delegates authentication to an external identity provider (IdP) and lets administrators enforce IdP-side controls such as MFA, conditional access, and centralized deprovisioning. Disabling it removes those controls and allows members to authenticate with GitHub credentials alone. Following an account takeover, an adversary may disable SSO to evade IdP-enforced access policies and maintain access that survives IdP-side session revocation and deprovisioning, making this a high-impact identity-control change. + +*Rule type*: esql + +*Rule indices*: None + +*Severity*: high + +*Risk score*: 73 + +*Runs every*: 5m + +*Searches indices from*: now-9m ({ref}/common-options.html#date-math[Date Math format], see also <>) + +*Maximum alerts per execution*: 100 + +*References*: + +* https://docs.github.com/en/enterprise-cloud@latest/admin/identity-and-access-management/using-saml-for-enterprise-iam/configuring-saml-single-sign-on-for-your-enterprise + +*Tags*: + +* Domain: Cloud +* Domain: SaaS +* Platform: GitHub +* Use Case: Threat Detection +* Tactic: Credential Access +* Tactic: Defense Evasion +* Tactic: Persistence +* Data Source: Github +* Data Source: GitHub Audit Logs +* Rule Type: ES|QL +* Resources: Investigation Guide + +*Version*: 1 + +*Rule authors*: + +* Elastic + +*Rule license*: Elastic License v2 + + +==== Investigation guide + + + +*Triage and analysis* + + +> **Disclaimer**: +> This investigation guide was created using generative AI technology and has been reviewed to improve its accuracy and relevance. While every effort has been made to ensure its quality, we recommend validating the content and adapting it to suit your specific environment and operational needs. + + +*Investigating GitHub SAML SSO Disabled* + + +This rule triggers on `business.disable_saml` and `org.disable_saml`, which record the disabling of SAML single sign-on at the enterprise or organization level. SAML SSO delegates authentication to an external identity provider (IdP) and lets administrators enforce IdP-side controls such as MFA, conditional access, and centralized deprovisioning. Disabling it removes those controls and allows members to authenticate with GitHub credentials alone, which is a common defense-evasion and persistence step after an owner account is compromised: it severs IdP-enforced policy and keeps access alive even if the IdP later revokes sessions or deprovisions the user. These events only apply to enterprises/orgs that have SAML configured and will not fire on a personal-account GHEC trial without SSO. + + +*Possible investigation steps* + + +- Identify the actor from `user.name`, `github.actor_ip`, `github.user_agent`, and `github.programmatic_access_type`, and confirm whether they legitimately hold enterprise or organization owner privileges. +- Determine the scope from `event.action` (`org.disable_saml` vs `business.disable_saml`) and the affected `github.org`/`github.business`, and verify whether the change was approved in an IdP-migration or SAML-reconfiguration change ticket. +- Pivot on `github.hashed_token` and `github.programmatic_access_type` to determine whether the change was made interactively in the UI or via a token, and treat token-driven changes as a stronger compromise signal. +- Check for correlated account-takeover indicators in the same window: recovery-code usage, new owner or member additions, PAT grants, OAuth App authorizations, 2FA requirement changes, and sign-ins from unusual IPs or ASNs. +- Review membership, access, and credential changes made while SSO was disabled, since members could authenticate without IdP enforcement during that period. +- If the change is unauthorized, re-enable SAML SSO before continuing the investigation to restore IdP-enforced access control. + + +*False positive analysis* + + +- A planned IdP cutover or SAML provider reconfiguration performed within an approved change window; this should be ticketed, keep a second owner session active, and re-enable SSO as soon as the new provider is ready. +- A governance or migration change (for example, consolidating organizations under an enterprise) performed by a known administrator can generate this event as expected activity. + + +*Response and remediation* + + +- Re-enable SAML SSO and require SSO for all members as soon as the change is confirmed unauthorized. +- Invalidate active sessions and force re-authentication through the IdP so that access is re-gated by IdP-enforced controls. +- Review and reverse any membership, access, or credential changes made while SSO was disabled, and revoke tokens created during that period. +- Review org and enterprise audit logs for other changes made by the actor after the disable event, and revert any unauthorized modifications. +- Escalate to incident response if the actor is unknown or unauthorized, or if the disable event is accompanied by new owner additions, token grants, recovery-code usage, or sign-ins from unfamiliar infrastructure. +- Harden by requiring SSO for all members, restricting who can change enterprise/organization authentication settings, and alerting on future changes to the SAML configuration. + + +==== Rule query + + +[source, js] +---------------------------------- +from logs-github.audit-* metadata _id, _index, _version +| where + event.module == "github" and data_stream.dataset == "github.audit" + and event.action in ("business.disable_saml", "org.disable_saml") +| keep + _id, + _index, + _version, + @timestamp, + event.action, + user.name, + github.org, + github.repo, + github.actor_ip, + github.hashed_token, + github.programmatic_access_type, + github.user_agent, + github.business + +---------------------------------- + +*Framework*: MITRE ATT&CK^TM^ + +* Tactic: +** Name: Defense Evasion +** ID: TA0005 +** Reference URL: https://attack.mitre.org/tactics/TA0005/ +* Technique: +** Name: Impair Defenses +** ID: T1562 +** Reference URL: https://attack.mitre.org/techniques/T1562/ +* Tactic: +** Name: Credential Access +** ID: TA0006 +** Reference URL: https://attack.mitre.org/tactics/TA0006/ +* Technique: +** Name: Modify Authentication Process +** ID: T1556 +** Reference URL: https://attack.mitre.org/techniques/T1556/ +* Sub-technique: +** Name: Hybrid Identity +** ID: T1556.007 +** Reference URL: https://attack.mitre.org/techniques/T1556/007/ +* Tactic: +** Name: Persistence +** ID: TA0003 +** Reference URL: https://attack.mitre.org/tactics/TA0003/ +* Technique: +** Name: Modify Authentication Process +** ID: T1556 +** Reference URL: https://attack.mitre.org/techniques/T1556/ +* Sub-technique: +** Name: Hybrid Identity +** ID: T1556.007 +** Reference URL: https://attack.mitre.org/techniques/T1556/007/ diff --git a/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-github-secret-scanning-alert-for-a-publicly-leaked-secret.asciidoc b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-github-secret-scanning-alert-for-a-publicly-leaked-secret.asciidoc new file mode 100644 index 0000000000..67a23903af --- /dev/null +++ b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-github-secret-scanning-alert-for-a-publicly-leaked-secret.asciidoc @@ -0,0 +1,124 @@ +[[prebuilt-rule-8-19-37-github-secret-scanning-alert-for-a-publicly-leaked-secret]] +=== GitHub Secret Scanning Alert for a Publicly Leaked Secret + +Detects GitHub secret scanning creating an alert for a secret that it has determined is publicly leaked ("github.publicly_leaked == true"). Unlike a generic secret-scanning finding, a publicly leaked secret means GitHub observed the credential exposed outside the repository's access boundary (for example in a public repository, gist, or other public location), so it should be treated as a confirmed credential compromise requiring immediate rotation rather than a low-signal scanner event. Gating on the public-leak flag also removes most of the noise from dummy strings and test fixtures, which are typically confined to private repositories and are not flagged as publicly leaked. + +*Rule type*: esql + +*Rule indices*: None + +*Severity*: high + +*Risk score*: 73 + +*Runs every*: 5m + +*Searches indices from*: now-9m ({ref}/common-options.html#date-math[Date Math format], see also <>) + +*Maximum alerts per execution*: 100 + +*References*: + +* https://docs.github.com/en/code-security/secret-scanning/introduction/about-secret-scanning + +*Tags*: + +* Domain: Cloud +* Domain: SaaS +* Platform: GitHub +* Use Case: Threat Detection +* Tactic: Credential Access +* Data Source: GitHub Audit Logs +* Service: GitHub Code Scanning +* Rule Type: ESQL +* Resources: Investigation Guide + +*Version*: 1 + +*Rule authors*: + +* Elastic + +*Rule license*: Elastic License v2 + + +==== Investigation guide + + + +*Triage and analysis* + + + +*Investigating GitHub Secret Scanning Alert for a Publicly Leaked Secret* + + +`secret_scanning_alert.create` with `github.publicly_leaked == true` means GitHub determined the matched secret is exposed in a public location, not just committed to the repository. Treat the credential as compromised and rotate it immediately. + + +*Possible investigation steps* + + +- Identify the exposed credential type from `github.secret_type` / `github.secret_type_display_name` and the affected `github.repo` and `github.org`. +- Review `github.multi_repo`; if true, the same secret was detected across multiple repositories, widening the blast radius. +- Identify the committer via `user.name` (vs the `github` service actor) and corroborate with `github.actor_ip` and `github.user_agent`. +- Determine the source and scope of the public exposure and whether the secret grants access to production systems. + + +*False positive analysis* + + +- Example or dummy keys intentionally published to a public repository can be flagged as publicly leaked. Scope these by repository or `github.secret_type`. + + +*Response and remediation* + + +- Revoke and rotate the exposed credential immediately, then invalidate any sessions or tokens derived from it. +- Remove the secret from git history if required by policy and audit for any use of the credential prior to rotation. + + +==== Rule query + + +[source, js] +---------------------------------- +from logs-github.audit-* metadata _id, _index, _version +| where + event.module == "github" and data_stream.dataset == "github.audit" + and event.action == "secret_scanning_alert.create" + and github.publicly_leaked == true +| keep + _id, + _index, + _version, + @timestamp, + event.action, + user.name, + github.org, + github.repo, + github.actor_ip, + github.hashed_token, + github.programmatic_access_type, + github.user_agent, + github.secret_type, + github.secret_type_display_name, + github.publicly_leaked, + github.multi_repo + +---------------------------------- + +*Framework*: MITRE ATT&CK^TM^ + +* Tactic: +** Name: Credential Access +** ID: TA0006 +** Reference URL: https://attack.mitre.org/tactics/TA0006/ +* Technique: +** Name: Unsecured Credentials +** ID: T1552 +** Reference URL: https://attack.mitre.org/techniques/T1552/ +* Sub-technique: +** Name: Credentials In Files +** ID: T1552.001 +** Reference URL: https://attack.mitre.org/techniques/T1552/001/ diff --git a/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-github-secret-scanning-push-protection-bypassed-or-disabled.asciidoc b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-github-secret-scanning-push-protection-bypassed-or-disabled.asciidoc new file mode 100644 index 0000000000..933714404c --- /dev/null +++ b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-github-secret-scanning-push-protection-bypassed-or-disabled.asciidoc @@ -0,0 +1,132 @@ +[[prebuilt-rule-8-19-37-github-secret-scanning-push-protection-bypassed-or-disabled]] +=== GitHub Secret Scanning Push Protection Bypassed or Disabled + +Detects bypass of GitHub secret scanning push protection, approval of a bypass request, or disabling push protection at enterprise, organization, or repository scope. This is separate from turning secret scanning off. Bypass means a detected secret was allowed into the repository — the pattern used after tj-actions and similar CI secret-dump attacks. + +*Rule type*: esql + +*Rule indices*: None + +*Severity*: medium + +*Risk score*: 47 + +*Runs every*: 5m + +*Searches indices from*: now-9m ({ref}/common-options.html#date-math[Date Math format], see also <>) + +*Maximum alerts per execution*: 100 + +*References*: + +* https://github.com/SigmaHQ/sigma/blob/master/rules/application/github/audit/github_push_protection_bypass_detected.yml +* https://docs.github.com/en/code-security/secret-scanning/working-with-secret-scanning-and-push-protection/working-with-push-protection-from-the-command-line + +*Tags*: + +* Domain: Cloud +* Domain: SaaS +* Platform: GitHub +* Use Case: Threat Detection +* Tactic: Defense Evasion +* Data Source: Github +* Data Source: GitHub Audit Logs +* Rule Type: ESQL +* Resources: Investigation Guide + +*Version*: 1 + +*Rule authors*: + +* Elastic + +*Rule license*: Elastic License v2 + + +==== Investigation guide + + + +*Triage and analysis* + + + +*Investigating GitHub Secret Scanning Push Protection Bypassed or Disabled* + + +`secret_scanning_push_protection.bypass` fires when a user pushes a detected secret anyway. `secret_scanning_push_protection_request.approve` is a reviewer allowing that push. `business_secret_scanning_push_protection.disable`, `org.secret_scanning_push_protection_disable`, and `repository_secret_scanning_push_protection.disable` turn the control off at enterprise, organization, and repository scope respectively (the `*_new_repos_disable` actions turn it off for newly created repositories). This is separate from disabling secret scanning itself, which is covered by the `GitHub Secret Scanning Disabled` rule. + + +*Possible investigation steps* + + +- Identify `user.name`, `github.repo`, `event.action`, and `github.secret_type`, and confirm whether the actor is expected to bypass or administer this control. +- Review `github.actor_ip` and `github.user_agent` to validate the source of the change, and pivot on `github.hashed_token` / `github.programmatic_access_type` to determine whether it was performed via the UI or a token. +- For a bypass or approved bypass: inspect the commit that landed, rotate the secret type reported in `github.secret_type`, and check workflow logs for printed credentials. +- For a disable: re-enable push protection and review commits pushed during the window it was off. +- Correlate with other control changes in the same window (secret scanning disabled, bypass-list additions, new owners, PAT grants) that may indicate broader tampering. + + +*False positive analysis* + + +- Security team testing push protection with a known dummy value during an approved exercise. +- A noisy custom pattern that maintainers temporarily disable. Confirm no live secret was pushed and that the control is re-enabled afterward. + + +*Response and remediation* + + +- Re-enable push protection at the affected scope. Rotate any secret that was bypassed. +- Restrict who can bypass or disable the control, and review the push-protection bypass list. +- Review Actions secrets and PATs created in the same window, and confirm the acting account is not compromised. + + +==== Rule query + + +[source, js] +---------------------------------- +from logs-github.audit-* metadata _id, _index, _version +| where + data_stream.dataset == "github.audit" + and event.action in ( + "secret_scanning_push_protection.bypass", + "secret_scanning_push_protection_request.approve", + "business_secret_scanning_push_protection.disable", + "business_secret_scanning_push_protection.disabled_for_new_repos", + "org.secret_scanning_push_protection_disable", + "org.secret_scanning_push_protection_new_repos_disable", + "repository_secret_scanning_push_protection.disable" + ) +| keep + _id, + _index, + _version, + @timestamp, + event.action, + user.name, + github.org, + github.repo, + github.actor_ip, + github.hashed_token, + github.programmatic_access_type, + github.user_agent, + github.secret_type + +---------------------------------- + +*Framework*: MITRE ATT&CK^TM^ + +* Tactic: +** Name: Defense Evasion +** ID: TA0005 +** Reference URL: https://attack.mitre.org/tactics/TA0005/ +* Technique: +** Name: Impair Defenses +** ID: T1562 +** Reference URL: https://attack.mitre.org/techniques/T1562/ +* Sub-technique: +** Name: Disable or Modify Tools +** ID: T1562.001 +** Reference URL: https://attack.mitre.org/techniques/T1562/001/ diff --git a/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-github-ssh-certificate-authority-or-requirement-modified.asciidoc b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-github-ssh-certificate-authority-or-requirement-modified.asciidoc new file mode 100644 index 0000000000..44254ee51d --- /dev/null +++ b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-github-ssh-certificate-authority-or-requirement-modified.asciidoc @@ -0,0 +1,142 @@ +[[prebuilt-rule-8-19-37-github-ssh-certificate-authority-or-requirement-modified]] +=== GitHub SSH Certificate Authority or Requirement Modified + +Detects creation or deletion of a GitHub SSH certificate authority (CA), or disabling the requirement that members use SSH certificates, for an organization or enterprise. A CA lets an org issue short-lived SSH certificates and optionally require them in place of personal SSH keys, centralizing and time-bounding Git access. Destroying the CA or dropping the requirement makes ordinary unmanaged SSH keys acceptable again. Following an account takeover, an adversary may make these changes to authenticate with keys the organization does not manage and evade certificate-based access control, making this a high-impact change to Git access controls. + +*Rule type*: esql + +*Rule indices*: None + +*Severity*: high + +*Risk score*: 73 + +*Runs every*: 5m + +*Searches indices from*: now-9m ({ref}/common-options.html#date-math[Date Math format], see also <>) + +*Maximum alerts per execution*: 100 + +*References*: + +* https://docs.github.com/en/organizations/managing-git-access-to-your-organizations-repositories/about-ssh-certificate-authorities + +*Tags*: + +* Domain: Cloud +* Domain: SaaS +* Platform: GitHub +* Use Case: Threat Detection +* Tactic: Defense Evasion +* Tactic: Persistence +* Data Source: Github +* Data Source: GitHub Audit Logs +* Rule Type: ESQL +* Resources: Investigation Guide + +*Version*: 1 + +*Rule authors*: + +* Elastic + +*Rule license*: Elastic License v2 + + +==== Investigation guide + + + +*Triage and analysis* + + +> **Disclaimer**: +> This investigation guide was created using generative AI technology and has been reviewed to improve its accuracy and relevance. While every effort has been made to ensure its quality, we recommend validating the content and adapting it to suit your specific environment and operational needs. + + +*Investigating GitHub SSH Certificate Authority or Requirement Modified* + + +A GitHub SSH certificate authority (CA) lets an organization or enterprise issue short-lived SSH certificates and optionally require that members use them instead of personal SSH keys. `ssh_certificate_authority.create` adds a CA, `ssh_certificate_authority.destroy` removes one, and `ssh_certificate_requirement.disable` drops the requirement so ordinary (unmanaged) SSH keys are accepted again. Destroying a CA or disabling the requirement weakens Git access control and can let an adversary authenticate with keys the organization does not manage. After an owner account is compromised, these changes are a defense-evasion step that re-opens key-based access the organization previously centralized and time-bounded. + + +*Possible investigation steps* + + +- Identify the actor from `user.name`, `github.actor_ip`, `github.user_agent`, and `github.programmatic_access_type`, and confirm whether they legitimately hold organization or enterprise owner privileges. +- Determine the scope and nature of the change from `event.action` and the affected `github.org`/`github.business`, and verify whether it matches a documented CA rotation or policy decision. +- Distinguish rotation from tampering: a `ssh_certificate_authority.create` immediately followed by a `destroy` of the old CA can be a legitimate rotation, whereas a lone `destroy` or a `ssh_certificate_requirement.disable` with no replacement is higher risk. +- Confirm whether a replacement CA exists and whether the certificate requirement is still enabled after the change. +- Review `public_key.create` events after the change to spot unmanaged SSH keys added while the requirement was off, and review subsequent Git access using those keys. +- Pivot on `github.hashed_token` and `github.programmatic_access_type` to determine whether the change was made interactively in the UI or via a token, and check for correlated takeover indicators (new owner additions, PAT grants, 2FA/SSO changes, sign-ins from unusual IPs or ASNs) in the same window. + + +*False positive analysis* + + +- A controlled CA rotation performed within an approved change window; the replacement CA should be created before the old one is deleted, and the certificate requirement should not be disabled except during a documented outage. +- A planned governance or migration change performed by a known administrator can generate these events as expected activity. + + +*Response and remediation* + + +- If the change is unauthorized, restore the CA and re-enable the SSH certificate requirement as soon as possible. +- Revoke unexpected or unmanaged SSH keys added while the requirement was disabled, and audit Git access performed with those keys. +- Review org and enterprise audit logs for other changes made by the actor after the event, and revert any unauthorized modifications. +- Rotate credentials for the acting owner account if compromise is suspected, and force re-authentication. +- Escalate to incident response if the actor is unknown or unauthorized, or if the change is accompanied by new SSH keys, owner additions, token grants, or sign-ins from unfamiliar infrastructure. +- Harden by requiring SSH certificates org-wide, restricting who can manage the SSH CA and certificate requirement, and alerting on future CA creation/deletion and requirement changes. + + +==== Rule query + + +[source, js] +---------------------------------- +from logs-github.audit-* metadata _id, _index, _version +| where + event.module == "github" and data_stream.dataset == "github.audit" + and event.action in ( + "ssh_certificate_authority.create", + "ssh_certificate_authority.destroy", + "ssh_certificate_requirement.disable" + ) +| keep + _id, + _index, + _version, + @timestamp, + event.action, + user.name, + github.org, + github.actor_ip, + github.hashed_token, + github.programmatic_access_type, + github.user_agent, + github.business + +---------------------------------- + +*Framework*: MITRE ATT&CK^TM^ + +* Tactic: +** Name: Defense Evasion +** ID: TA0005 +** Reference URL: https://attack.mitre.org/tactics/TA0005/ +* Technique: +** Name: Impair Defenses +** ID: T1562 +** Reference URL: https://attack.mitre.org/techniques/T1562/ +* Sub-technique: +** Name: Disable or Modify Tools +** ID: T1562.001 +** Reference URL: https://attack.mitre.org/techniques/T1562/001/ +* Tactic: +** Name: Persistence +** ID: TA0003 +** Reference URL: https://attack.mitre.org/tactics/TA0003/ +* Technique: +** Name: Modify Authentication Process +** ID: T1556 +** Reference URL: https://attack.mitre.org/techniques/T1556/ diff --git a/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-github-sso-recovery-codes-activity.asciidoc b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-github-sso-recovery-codes-activity.asciidoc new file mode 100644 index 0000000000..35aeaa19be --- /dev/null +++ b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-github-sso-recovery-codes-activity.asciidoc @@ -0,0 +1,139 @@ +[[prebuilt-rule-8-19-37-github-sso-recovery-codes-activity]] +=== GitHub SSO Recovery Codes Activity + +Detects viewing, downloading, printing, generating, or using GitHub enterprise or organization SSO recovery codes. These codes bypass the IdP and are break-glass credentials. + +*Rule type*: esql + +*Rule indices*: None + +*Severity*: high + +*Risk score*: 73 + +*Runs every*: 5m + +*Searches indices from*: now-9m ({ref}/common-options.html#date-math[Date Math format], see also <>) + +*Maximum alerts per execution*: 100 + +*References*: + +* https://docs.github.com/en/enterprise-cloud@latest/admin/identity-and-access-management/managing-recovery-codes-for-your-enterprise/downloading-your-enterprise-accounts-single-sign-on-recovery-codes + +*Tags*: + +* Domain: Cloud +* Domain: SaaS +* Platform: GitHub +* Use Case: Threat Detection +* Tactic: Credential Access +* Tactic: Persistence +* Data Source: GitHub Audit Logs +* Rule Type: ESQL +* Resources: Investigation Guide + +*Version*: 1 + +*Rule authors*: + +* Elastic + +*Rule license*: Elastic License v2 + + +==== Investigation guide + + + +*Triage and analysis* + + + +*Investigating GitHub SSO Recovery Codes Activity* + + +Recovery-code events are rare. Download/view/print/generate often precede an SSO bypass. Use/fail events indicate an actual sign-in attempt with a recovery code. + + +*Possible investigation steps* + + +- Identify `user.name`, `event.action`, and `github.actor_ip`. +- Correlate with `business.disable_saml` / MFA disable and new owner invites. + + +*False positive analysis* + + +- Scheduled recovery-code rotation with two-person integrity. + + +*Response and remediation* + + +- Rotate recovery codes, review SSO configuration, and force re-authentication of enterprise owners. + + +==== Rule query + + +[source, js] +---------------------------------- +from logs-github.audit-* metadata _id, _index, _version +| where + event.module == "github" and data_stream.dataset == "github.audit" + and event.action in ( + "business.recovery_codes_downloaded", + "business.recovery_codes_generated", + "business.recovery_codes_printed", + "business.recovery_codes_viewed", + "business.recovery_code_used", + "business.recovery_code_failed", + "org.recovery_codes_downloaded", + "org.recovery_codes_generated", + "org.recovery_codes_printed", + "org.recovery_codes_viewed", + "org.recovery_code_used", + "org.recovery_code_failed" + ) +| keep + _id, + _index, + _version, + @timestamp, + event.action, + user.name, + github.org, + github.actor_is_bot, + github.repo, + github.actor_ip, + github.hashed_token, + github.programmatic_access_type, + github.user_agent, + github.business + +---------------------------------- + +*Framework*: MITRE ATT&CK^TM^ + +* Tactic: +** Name: Credential Access +** ID: TA0006 +** Reference URL: https://attack.mitre.org/tactics/TA0006/ +* Technique: +** Name: Unsecured Credentials +** ID: T1552 +** Reference URL: https://attack.mitre.org/techniques/T1552/ +* Tactic: +** Name: Persistence +** ID: TA0003 +** Reference URL: https://attack.mitre.org/tactics/TA0003/ +* Technique: +** Name: Valid Accounts +** ID: T1078 +** Reference URL: https://attack.mitre.org/techniques/T1078/ +* Sub-technique: +** Name: Cloud Accounts +** ID: T1078.004 +** Reference URL: https://attack.mitre.org/techniques/T1078/004/ diff --git a/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-github-webhook-created-or-configuration-changed.asciidoc b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-github-webhook-created-or-configuration-changed.asciidoc new file mode 100644 index 0000000000..fdf7d227ec --- /dev/null +++ b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-github-webhook-created-or-configuration-changed.asciidoc @@ -0,0 +1,137 @@ +[[prebuilt-rule-8-19-37-github-webhook-created-or-configuration-changed]] +=== GitHub Webhook Created or Configuration Changed + +Detects creation or configuration change of a GitHub webhook. Attackers can add a hook to copy push, pull request, and workflow payloads (including secrets that land in those events) to an external URL. + +*Rule type*: esql + +*Rule indices*: None + +*Severity*: low + +*Risk score*: 21 + +*Runs every*: 5m + +*Searches indices from*: now-9m ({ref}/common-options.html#date-math[Date Math format], see also <>) + +*Maximum alerts per execution*: 100 + +*References*: + +* https://docs.github.com/en/webhooks/about-webhooks +* https://docs.github.com/en/organizations/keeping-your-organization-secure/managing-security-settings-for-your-organization/audit-log-events-for-your-organization + +*Tags*: + +* Domain: Cloud +* Domain: SaaS +* Platform: GitHub +* Use Case: Threat Detection +* Tactic: Collection +* Tactic: Exfiltration +* Data Source: Github +* Data Source: GitHub Audit Logs +* Rule Type: ES|QL +* Resources: Investigation Guide + +*Version*: 1 + +*Rule authors*: + +* Elastic + +*Rule license*: Elastic License v2 + + +==== Investigation guide + + + +*Triage and analysis* + + + +*Investigating GitHub Webhook Created or Configuration Changed* + + +`hook.create` adds a webhook. `hook.config_changed` updates the payload URL or other hook settings. Either action can send repository events to an attacker-controlled endpoint. + + +*Possible investigation steps* + + +- Identify `user.name`, `github.repo`, `github.actor_ip`, and `github.programmatic_access_type`. +- In repository Settings → Webhooks, inspect the payload URL, content type, and subscribed events. Treat unknown hosts as compromised. +- Pivot to `git.push`, `repo.download_zip`, and Actions secret creates by the same actor. + + +*False positive analysis* + + +- First-time install of Slack, Jira, or a deploy bot that registers a webhook. +- Terraform or GitHub App automation that manages hooks. + + +*Response and remediation* + + +- Delete unauthorized webhooks. Rotate secrets that may have been delivered in payloads. +- Revoke the actor's tokens if the hook was not approved. + + +==== Rule query + + +[source, js] +---------------------------------- +from logs-github.audit-* metadata _id, _index, _version +| where + data_stream.dataset == "github.audit" + and (github.actor_is_bot is not null and github.actor_is_bot == false) + and event.action in ("hook.create", "hook.config_changed") +| keep + _id, + _index, + _version, + @timestamp, + event.action, + user.name, + github.org, + github.repo, + github.actor_ip, + github.hashed_token, + github.programmatic_access_type, + github.user_agent, + github.hook_id, + github.name, + github.actor_is_bot + +---------------------------------- + +*Framework*: MITRE ATT&CK^TM^ + +* Tactic: +** Name: Collection +** ID: TA0009 +** Reference URL: https://attack.mitre.org/tactics/TA0009/ +* Technique: +** Name: Data from Information Repositories +** ID: T1213 +** Reference URL: https://attack.mitre.org/techniques/T1213/ +* Sub-technique: +** Name: Code Repositories +** ID: T1213.003 +** Reference URL: https://attack.mitre.org/techniques/T1213/003/ +* Tactic: +** Name: Exfiltration +** ID: TA0010 +** Reference URL: https://attack.mitre.org/tactics/TA0010/ +* Technique: +** Name: Exfiltration Over Web Service +** ID: T1567 +** Reference URL: https://attack.mitre.org/techniques/T1567/ +* Sub-technique: +** Name: Exfiltration Over Webhook +** ID: T1567.004 +** Reference URL: https://attack.mitre.org/techniques/T1567/004/ diff --git a/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-launch-item-registration-with-suspicious-executable-path-via-macos-security-events.asciidoc b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-launch-item-registration-with-suspicious-executable-path-via-macos-security-events.asciidoc new file mode 100644 index 0000000000..a22876f5d6 --- /dev/null +++ b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-launch-item-registration-with-suspicious-executable-path-via-macos-security-events.asciidoc @@ -0,0 +1,133 @@ +[[prebuilt-rule-8-19-37-launch-item-registration-with-suspicious-executable-path-via-macos-security-events]] +=== Launch Item Registration with Suspicious Executable Path via macOS Security Events + +Identifies the registration of a launch agent or launch daemon whose target executable resides in a temporary or user-writable location, using launch item registration messages collected by the macOS Security Events integration. An adversary may establish persistence with a launch agent or daemon that runs a program staged in a world-writable or temporary directory, which is uncommon for legitimate software. + +*Rule type*: esql + +*Rule indices*: None + +*Severity*: medium + +*Risk score*: 47 + +*Runs every*: 5m + +*Searches indices from*: now-9m ({ref}/common-options.html#date-math[Date Math format], see also <>) + +*Maximum alerts per execution*: 100 + +*References*: + +* https://www.welivesecurity.com/2022/07/19/i-see-what-you-did-there-look-cloudmensis-macos-spyware/ +* https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingLaunchdJobs.html + +*Tags*: + +* OS: macOS +* Use Case: Threat Detection +* Tactic: Persistence +* Data Source: macOS Security Events +* Resources: Investigation Guide +* Rule Type: ES|QL +* Platform: macOS +* Domain: Endpoint + +*Version*: 3 + +*Rule authors*: + +* Elastic + +*Rule license*: Elastic License v2 + + +==== Investigation guide + + + +*Triage and analysis* + + +> **Disclaimer**: +> This investigation guide was created using generative AI technology and has been reviewed to improve its accuracy and relevance. While every effort has been made to ensure its quality, we recommend validating the content and adapting it to suit your specific environment and operational needs. + + +*Investigating Launch Item Registration with Suspicious Executable Path via macOS Security Events* + + +On macOS, launch agents and launch daemons run a program defined in their property list (plist). When a launch item is registered, the BackgroundTaskManagement subsystem logs the plist path and the target executable path to the unified log. Legitimate persistent software almost always runs an executable from a system or application directory. An executable staged in a temporary or world-writable directory (for example `/tmp`, `/private/tmp`, `/var/tmp`, `/Users/Shared`, or `/var/folders`) is a strong indicator of malicious persistence. This rule alerts on launch item registrations whose executable resides in such a location, and reports the plist path, item type, and executable. + + +*Possible investigation steps* + + +- Review `Esql.executable` and `Esql.plist_path` in the alert to identify the staged program and its launch item. +- Retrieve and analyze the executable. Determine whether it is signed, what it does, and how it arrived on the host. +- Determine how and when the plist and executable were created, and by which process, using Elastic Defend telemetry if available. +- Review other alerts and activity for the host and associated user during the same period. + + +*False positive analysis* + + +- Developer and build tooling occasionally runs helper executables from temporary or user directories. +- Verify the executable and its origin; exclude known-good paths or signing identities if the behavior is expected. + + +*Response and remediation* + + +- If the launch item is not legitimate, unload it with `launchctl bootout`, remove the plist, and remove or quarantine the executable. +- Investigate the host for the initial access vector and any activity performed by the program. +- Reset credentials for the affected user and review the host for additional compromise. +- Escalate to the security operations team if additional hosts show similar patterns. + + +==== Setup + + + +*Setup* + + +This rule requires data from the macOS Security Events integration. +Integration setup instructions: https://www.elastic.co/docs/reference/integrations/macos[macOS Security Events Integration for Elastic] + + +==== Rule query + + +[source, js] +---------------------------------- +FROM logs-macos.process_execution_monitoring-* metadata _id, _version, _index +| WHERE data_stream.dataset == "macos.process_execution_monitoring" and + macos.event.message.description LIKE "*effectiveItemDisposition*" and + (macos.event.message.description LIKE "*url=file://*/Library/LaunchAgents/*" or + macos.event.message.description LIKE "*url=file://*/Library/LaunchDaemons/*") +| GROK macos.event.message.description "url=file://%{DATA:Esql.plist_path}, config" +| GROK macos.event.message.description "type=%{DATA:Esql.item_type}," +| GROK macos.event.message.description "BTMConfigExecutablePath = \"%{DATA:Esql.executable}\"" +| WHERE Esql.executable RLIKE "/(private/)?(tmp|var/tmp|var/folders)/.*|/Users/Shared/.*|/Users/[^/]+/(Downloads|Public|Library/Caches)/.*" +| KEEP _id, _version, _index, @timestamp, host.name, Esql.executable, Esql.plist_path, Esql.item_type, macos.event.message.description + +---------------------------------- + +*Framework*: MITRE ATT&CK^TM^ + +* Tactic: +** Name: Persistence +** ID: TA0003 +** Reference URL: https://attack.mitre.org/tactics/TA0003/ +* Technique: +** Name: Create or Modify System Process +** ID: T1543 +** Reference URL: https://attack.mitre.org/techniques/T1543/ +* Sub-technique: +** Name: Launch Agent +** ID: T1543.001 +** Reference URL: https://attack.mitre.org/techniques/T1543/001/ +* Sub-technique: +** Name: Launch Daemon +** ID: T1543.004 +** Reference URL: https://attack.mitre.org/techniques/T1543/004/ diff --git a/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-machine-learning-detected-a-dns-request-predicted-to-be-a-dga-domain.asciidoc b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-machine-learning-detected-a-dns-request-predicted-to-be-a-dga-domain.asciidoc new file mode 100644 index 0000000000..81f07d8dd1 --- /dev/null +++ b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-machine-learning-detected-a-dns-request-predicted-to-be-a-dga-domain.asciidoc @@ -0,0 +1,167 @@ +[[prebuilt-rule-8-19-37-machine-learning-detected-a-dns-request-predicted-to-be-a-dga-domain]] +=== Machine Learning Detected a DNS Request Predicted to be a DGA Domain + +A supervised machine learning model has identified a DNS question name that is predicted to be the result of a Domain Generation Algorithm (DGA), which could indicate command and control network activity. + +*Rule type*: query + +*Rule indices*: + +* logs-endpoint.events.* +* logs-network_traffic.* + +*Severity*: low + +*Risk score*: 21 + +*Runs every*: 5m + +*Searches indices from*: now-10m ({ref}/common-options.html#date-math[Date Math format], see also <>) + +*Maximum alerts per execution*: 100 + +*References*: + +* https://www.elastic.co/guide/en/security/current/prebuilt-ml-jobs.html +* https://docs.elastic.co/en/integrations/dga +* https://www.elastic.co/security-labs/detect-domain-generation-algorithm-activity-with-new-kibana-integration + +*Tags*: + +* Domain: Network +* Domain: Endpoint +* Data Source: Elastic Defend +* Use Case: Domain Generation Algorithm Detection +* Rule Type: ML +* Rule Type: Machine Learning +* Tactic: Command and Control +* Resources: Investigation Guide +* Noise: Medium +* Performance: Normal +* Rule Type: Custom Query (KQL) +* Data Source: Network Packet Capture + +*Version*: 11 + +*Rule authors*: + +* Elastic + +*Rule license*: Elastic License v2 + + +==== Investigation guide + + + +*Triage and analysis* + + +> **Disclaimer**: +> This investigation guide was created using generative AI technology and has been reviewed to improve its accuracy and relevance. While every effort has been made to ensure its quality, we recommend validating the content and adapting it to suit your specific environment and operational needs. + + +*Investigating Machine Learning Detected a DNS Request Predicted to be a DGA Domain* + + +Machine learning models can identify patterns in DNS requests that suggest the use of Domain Generation Algorithms (DGAs), which adversaries use to dynamically generate domain names for command and control (C2) communication. This detection rule leverages such models to flag DNS queries likely generated by DGAs, excluding known benign domains, thus helping to identify potential C2 activity. + + +*Possible investigation steps* + + +- Review the DNS query logs to identify the specific domain flagged by the machine learning model as a potential DGA domain. Focus on the field ml_is_dga.malicious_prediction:1 to confirm the prediction. +- Cross-reference the flagged domain with threat intelligence sources to determine if it is associated with known malicious activity or threat actors. +- Investigate the source IP address of the DNS request to identify the device or user responsible for the query. This can help determine if the activity is isolated or part of a larger pattern. +- Analyze network traffic logs for any additional suspicious activity originating from the same source IP, such as unusual outbound connections or data transfers. +- Check for any recent changes or anomalies in the endpoint's behavior or configuration that could indicate compromise or unauthorized software installation. +- If the domain is confirmed to be malicious, initiate containment procedures to block further communication with the domain and prevent potential data exfiltration or further compromise. + + +*False positive analysis* + + +- DNS requests to content delivery networks or cloud service providers can be flagged as DGA domains due to their dynamic nature. Users should review these domains and consider adding them to an exception list if they are verified as legitimate. +- Internal applications that generate dynamic DNS requests for load balancing or failover purposes might trigger false positives. Identify these applications and exclude their domains from the rule to prevent unnecessary alerts. +- Automated testing environments often generate numerous DNS requests that can appear suspicious. Regularly update the exception list with domains used by these environments to minimize false alerts. +- Frequent updates or patches from software vendors may involve dynamic DNS requests. Verify these domains and exclude them if they are confirmed to be part of legitimate update processes. +- Consider monitoring the frequency and pattern of flagged DNS requests. If a domain is consistently flagged but verified as non-threatening, it may be a candidate for exclusion from the rule. + + +*Response and remediation* + + +- Isolate the affected system from the network to prevent further potential command and control communication. +- Conduct a thorough scan of the isolated system using updated antivirus and anti-malware tools to identify and remove any malicious software. +- Review and block the identified DGA domain and any associated IP addresses at the network perimeter to prevent further access. +- Analyze network traffic logs to identify any other systems that may have communicated with the DGA domain and apply similar containment measures. +- Escalate the incident to the security operations center (SOC) or incident response team for further investigation and to determine the scope of the compromise. +- Implement enhanced monitoring for similar DGA patterns and update detection capabilities to quickly identify future occurrences. +- Review and update firewall and intrusion detection/prevention system (IDS/IPS) rules to block known DGA patterns and suspicious DNS activity. + +==== Setup + + + +*Setup* + + +The rule requires the Domain Generation Algorithm (DGA) Detection integration assets to be installed, as well as DNS events collected by integrations such as Elastic Defend, Network Packet Capture, or Packetbeat. + + +*DGA Detection Setup* + +The DGA Detection integration consists of an ML-based framework to detect DGA activity in DNS events. + + +*Prerequisite Requirements:* + +- Fleet is required for DGA Detection. +- To configure Fleet Server refer to the https://www.elastic.co/guide/en/fleet/current/fleet-server.html[documentation]. +- DNS events collected by the https://docs.elastic.co/en/integrations/endpoint[Elastic Defend], https://docs.elastic.co/integrations/network_traffic[Network Packet Capture] integration, or https://www.elastic.co/guide/en/beats/packetbeat/current/packetbeat-overview.html[Packetbeat]. +- To install Elastic Defend, refer to the https://www.elastic.co/guide/en/security/current/install-endpoint.html[documentation]. +- To add the Network Packet Capture integration to an Elastic Agent policy, refer to https://www.elastic.co/guide/en/fleet/current/add-integration-to-policy.html[this] guide. +- To set up and run Packetbeat, follow https://www.elastic.co/guide/en/beats/packetbeat/current/setting-up-and-running.html[this] guide. + + +*The following steps should be executed to install assets associated with the DGA Detection integration:* + +- Go to the Kibana homepage. Under Management, click Integrations. +- In the query bar, search for Domain Generation Algorithm Detection and select the integration to see more details about it. +- Follow the instructions under the **Installation** section. +- For this rule to work, complete the instructions through **Configure the ingest pipeline**. + + +==== Rule query + + +[source, js] +---------------------------------- +ml_is_dga.malicious_prediction:1 and +not dns.question.registered_domain:avsvmcloud.com and +not dns.question.name:(_*._tcp.* or _*._udp.* or _*._tls.* or _*._sctp.*) + +---------------------------------- + +*Framework*: MITRE ATT&CK^TM^ + +* Tactic: +** Name: Command and Control +** ID: TA0011 +** Reference URL: https://attack.mitre.org/tactics/TA0011/ +* Technique: +** Name: Application Layer Protocol +** ID: T1071 +** Reference URL: https://attack.mitre.org/techniques/T1071/ +* Sub-technique: +** Name: DNS +** ID: T1071.004 +** Reference URL: https://attack.mitre.org/techniques/T1071/004/ +* Technique: +** Name: Dynamic Resolution +** ID: T1568 +** Reference URL: https://attack.mitre.org/techniques/T1568/ +* Sub-technique: +** Name: Domain Generation Algorithms +** ID: T1568.002 +** Reference URL: https://attack.mitre.org/techniques/T1568/002/ diff --git a/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-machine-learning-detected-a-dns-request-with-a-high-dga-probability-score.asciidoc b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-machine-learning-detected-a-dns-request-with-a-high-dga-probability-score.asciidoc new file mode 100644 index 0000000000..041d97671b --- /dev/null +++ b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-machine-learning-detected-a-dns-request-with-a-high-dga-probability-score.asciidoc @@ -0,0 +1,165 @@ +[[prebuilt-rule-8-19-37-machine-learning-detected-a-dns-request-with-a-high-dga-probability-score]] +=== Machine Learning Detected a DNS Request With a High DGA Probability Score + +A supervised machine learning model has identified a DNS question name with a high probability of sourcing from a Domain Generation Algorithm (DGA), which could indicate command and control network activity. + +*Rule type*: query + +*Rule indices*: + +* logs-endpoint.events.* +* logs-network_traffic.* + +*Severity*: low + +*Risk score*: 21 + +*Runs every*: 5m + +*Searches indices from*: now-10m ({ref}/common-options.html#date-math[Date Math format], see also <>) + +*Maximum alerts per execution*: 100 + +*References*: + +* https://www.elastic.co/guide/en/security/current/prebuilt-ml-jobs.html +* https://docs.elastic.co/en/integrations/dga +* https://www.elastic.co/security-labs/detect-domain-generation-algorithm-activity-with-new-kibana-integration + +*Tags*: + +* Domain: Network +* Domain: Endpoint +* Data Source: Elastic Defend +* Use Case: Domain Generation Algorithm Detection +* Rule Type: ML +* Rule Type: Machine Learning +* Tactic: Command and Control +* Resources: Investigation Guide +* Noise: Medium +* Performance: Normal +* Rule Type: Custom Query (KQL) +* Data Source: Network Packet Capture + +*Version*: 11 + +*Rule authors*: + +* Elastic + +*Rule license*: Elastic License v2 + + +==== Investigation guide + + + +*Triage and analysis* + + +> **Disclaimer**: +> This investigation guide was created using generative AI technology and has been reviewed to improve its accuracy and relevance. While every effort has been made to ensure its quality, we recommend validating the content and adapting it to suit your specific environment and operational needs. + + +*Investigating Machine Learning Detected a DNS Request With a High DGA Probability Score* + + +Machine learning models analyze DNS requests to identify patterns indicative of Domain Generation Algorithms (DGAs), often used by attackers to establish command and control channels. These algorithms generate numerous domain names, making detection challenging. The detection rule leverages a model to flag DNS queries with high DGA probability, aiding in identifying potential malicious activity. + + +*Possible investigation steps* + + +- Review the DNS query logs to identify the specific domain name associated with the high DGA probability score and gather additional context about the request, such as the timestamp and the source IP address. +- Cross-reference the identified domain name with threat intelligence databases to determine if it is a known malicious domain or associated with any known threat actors or campaigns. +- Investigate the source IP address to determine if it belongs to a legitimate user or system within the network, and check for any unusual or suspicious activity associated with this IP address. +- Analyze network traffic logs to identify any additional communication attempts to the flagged domain or other suspicious domains, which may indicate further command and control activity. +- Check endpoint security logs for any signs of compromise or suspicious behavior on the device that initiated the DNS request, such as unexpected processes or connections. +- Consider isolating the affected system from the network if there is strong evidence of compromise, to prevent further potential malicious activity while conducting a deeper forensic analysis. + + +*False positive analysis* + + +- Legitimate software updates or services may use domain generation techniques for load balancing or redundancy, leading to false positives. Users can create exceptions for known update services or trusted software to reduce these alerts. +- Content delivery networks (CDNs) often use dynamically generated domains to optimize content delivery, which might be flagged. Identifying and whitelisting these CDN domains can help minimize unnecessary alerts. +- Some security tools and applications use DGA-like patterns for legitimate purposes, such as generating unique identifiers. Users should verify the source and purpose of these requests and consider excluding them if they are confirmed to be non-threatening. +- Internal testing environments or development tools might generate domains that resemble DGA activity. Users can exclude these environments from monitoring or adjust the rule to ignore specific internal IP ranges or domain patterns. + + +*Response and remediation* + + +- Isolate the affected system from the network to prevent further potential command and control communication. +- Conduct a thorough scan of the isolated system using updated antivirus and anti-malware tools to identify and remove any malicious software. +- Review and block the identified suspicious domain names at the network perimeter to prevent any further communication attempts. +- Analyze network traffic logs to identify any other systems that may have communicated with the flagged domains and apply similar containment measures. +- Escalate the incident to the security operations center (SOC) for further investigation and to determine if the threat is part of a larger attack campaign. +- Implement additional monitoring on the affected system and network segment to detect any signs of persistence or further malicious activity. +- Update and reinforce endpoint protection measures, ensuring all systems have the latest security patches and configurations to prevent similar threats in the future. + +==== Setup + + + +*Setup* + + +The rule requires the Domain Generation Algorithm (DGA) Detection integration assets to be installed, as well as DNS events collected by integrations such as Elastic Defend, Network Packet Capture, or Packetbeat. + + +*DGA Detection Setup* + +The DGA Detection integration consists of an ML-based framework to detect DGA activity in DNS events. + + +*Prerequisite Requirements:* + +- Fleet is required for DGA Detection. +- To configure Fleet Server refer to the https://www.elastic.co/guide/en/fleet/current/fleet-server.html[documentation]. +- DNS events collected by the https://docs.elastic.co/en/integrations/endpoint[Elastic Defend], https://docs.elastic.co/integrations/network_traffic[Network Packet Capture] integration, or https://www.elastic.co/guide/en/beats/packetbeat/current/packetbeat-overview.html[Packetbeat]. +- To install Elastic Defend, refer to the https://www.elastic.co/guide/en/security/current/install-endpoint.html[documentation]. +- To add the Network Packet Capture integration to an Elastic Agent policy, refer to https://www.elastic.co/guide/en/fleet/current/add-integration-to-policy.html[this] guide. +- To set up and run Packetbeat, follow https://www.elastic.co/guide/en/beats/packetbeat/current/setting-up-and-running.html[this] guide. + + +*The following steps should be executed to install assets associated with the DGA Detection integration:* + +- Go to the Kibana homepage. Under Management, click Integrations. +- In the query bar, search for Domain Generation Algorithm Detection and select the integration to see more details about it. +- Follow the instructions under the **Installation** section. +- For this rule to work, complete the instructions through **Configure the ingest pipeline**. + + +==== Rule query + + +[source, js] +---------------------------------- +ml_is_dga.malicious_probability > 0.98 and +not dns.question.name:(_*._tcp.* or _*._udp.* or _*._tls.* or _*._sctp.*) + +---------------------------------- + +*Framework*: MITRE ATT&CK^TM^ + +* Tactic: +** Name: Command and Control +** ID: TA0011 +** Reference URL: https://attack.mitre.org/tactics/TA0011/ +* Technique: +** Name: Application Layer Protocol +** ID: T1071 +** Reference URL: https://attack.mitre.org/techniques/T1071/ +* Sub-technique: +** Name: DNS +** ID: T1071.004 +** Reference URL: https://attack.mitre.org/techniques/T1071/004/ +* Technique: +** Name: Dynamic Resolution +** ID: T1568 +** Reference URL: https://attack.mitre.org/techniques/T1568/ +* Sub-technique: +** Name: Domain Generation Algorithms +** ID: T1568.002 +** Reference URL: https://attack.mitre.org/techniques/T1568/002/ diff --git a/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-microsoft-foundry-content-filter-modified-or-deleted.asciidoc b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-microsoft-foundry-content-filter-modified-or-deleted.asciidoc new file mode 100644 index 0000000000..c5f25f7dbd --- /dev/null +++ b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-microsoft-foundry-content-filter-modified-or-deleted.asciidoc @@ -0,0 +1,138 @@ +[[prebuilt-rule-8-19-37-microsoft-foundry-content-filter-modified-or-deleted]] +=== Microsoft Foundry Content Filter Modified or Deleted + +Identifies the creation, modification, or deletion of a content filter (RAI policy) or a custom blocklist on a Microsoft Foundry (Azure AI Services) account. Content filters decide which prompt and completion categories, jailbreak attempts, and protected material a model deployment blocks. An adversary with control of the account can weaken or remove these filters so that harmful prompts and outputs are no longer blocked or logged as filtered, which removes a guardrail and the detections that depend on its verdicts. + +*Rule type*: query + +*Rule indices*: + +* logs-azure.activitylogs-* + +*Severity*: medium + +*Risk score*: 47 + +*Runs every*: 5m + +*Searches indices from*: now-9m ({ref}/common-options.html#date-math[Date Math format], see also <>) + +*Maximum alerts per execution*: 100 + +*References*: + +* https://learn.microsoft.com/en-us/azure/ai-foundry/openai/concepts/content-filter +* https://learn.microsoft.com/en-us/azure/ai-foundry/openai/how-to/content-filters +* https://www.elastic.co/docs/reference/integrations/azure/activitylogs + +*Tags*: + +* Domain: Cloud +* Domain: GenAI +* Data Source: Azure +* Data Source: Azure Activity Logs +* Data Source: Microsoft Foundry +* Platform: Azure +* Use Case: Threat Detection +* Tactic: Defense Evasion +* Resources: Investigation Guide +* Rule Type: Custom Query (KQL) + +*Version*: 1 + +*Rule authors*: + +* Elastic + +*Rule license*: Elastic License v2 + + +==== Investigation guide + + + +*Triage and analysis* + + + +*Investigating Microsoft Foundry Content Filter Modified or Deleted* + + +Microsoft Foundry content filters are stored as RAI policies on the AI Services account +(`Microsoft.CognitiveServices/accounts/raiPolicies`) and are referenced by each model deployment. Custom blocklists +(`raiBlocklists`) add term-level blocking on top of those policies. This rule fires when a policy or blocklist is +written or deleted. + + +*Possible investigation steps* + + +- Identify the caller from `azure.activitylogs.identity.authorization.evidence.principal_id`, `user.name`, and + `azure.activitylogs.identity.authorization.evidence.role`. +- Review `azure.resource.id` to identify the policy or blocklist name and the account it belongs to, and + `azure.activitylogs.operation_name` to determine whether it was a write or a delete. +- Compare the policy with the previous version in the Foundry portal or with `az cognitiveservices account` tooling. + Lowered severity thresholds, disabled prompt shields, or a policy switched to annotate-only mode are the changes of + most concern. +- Check whether any deployment on the account was changed to use the modified policy around the same time. +- Review `source.ip` and `source.geo.country_name` for the caller and look for other recent changes by the same + principal, such as key listing, diagnostic setting deletion, or new role assignments. +- If Microsoft Foundry logs are ingested, look for a drop in filtered or jailbreak-flagged requests after the change. + + +*False positive analysis* + + +- Planned content filter tuning by AI platform owners. Confirm with the owner and the change ticket. +- Deployment pipelines that rewrite RAI policies. Exclude those service principals by ID. + + +*Response and remediation* + + +- If the change is not authorized, restore the previous content filter configuration and reassign it to affected + deployments. +- Revoke the caller's sessions, reset its credentials, and review its role assignments on the account. +- Restrict `Microsoft.CognitiveServices/accounts/raiPolicies/*` permissions to a small set of administrators. + + +==== Setup + + + +*Setup* + + +This rule requires Azure Activity Logs ingested via the Azure integration (`azure.activitylogs` data stream). RAI +policy and blocklist changes are Administrative control-plane events and are logged by default. + + +==== Rule query + + +[source, js] +---------------------------------- +data_stream.dataset: "azure.activitylogs" and +azure.activitylogs.operation_name: ( + "MICROSOFT.COGNITIVESERVICES/ACCOUNTS/RAIPOLICIES/WRITE" or + "MICROSOFT.COGNITIVESERVICES/ACCOUNTS/RAIPOLICIES/DELETE" or + "MICROSOFT.COGNITIVESERVICES/ACCOUNTS/RAIBLOCKLISTS/WRITE" or + "MICROSOFT.COGNITIVESERVICES/ACCOUNTS/RAIBLOCKLISTS/DELETE" +) and event.outcome: "success" + +---------------------------------- + +*Framework*: MITRE ATT&CK^TM^ + +* Tactic: +** Name: Defense Evasion +** ID: TA0005 +** Reference URL: https://attack.mitre.org/tactics/TA0005/ +* Technique: +** Name: Impair Defenses +** ID: T1562 +** Reference URL: https://attack.mitre.org/techniques/T1562/ +* Sub-technique: +** Name: Disable or Modify Tools +** ID: T1562.001 +** Reference URL: https://attack.mitre.org/techniques/T1562/001/ diff --git a/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-microsoft-foundry-keys-or-connection-secrets-accessed-by-new-principal.asciidoc b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-microsoft-foundry-keys-or-connection-secrets-accessed-by-new-principal.asciidoc new file mode 100644 index 0000000000..2e3c6ea461 --- /dev/null +++ b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-microsoft-foundry-keys-or-connection-secrets-accessed-by-new-principal.asciidoc @@ -0,0 +1,163 @@ +[[prebuilt-rule-8-19-37-microsoft-foundry-keys-or-connection-secrets-accessed-by-new-principal]] +=== Microsoft Foundry Keys or Connection Secrets Accessed by New Principal + +Identifies the first time in seven days that a high-privilege Azure principal lists or regenerates the API keys of a Microsoft Foundry (Azure AI Services) account, or reads the stored secrets of a Foundry account or project connection. Account keys grant direct inference access to every model deployment on the account and bypass Entra ID conditional access, and connection secrets hold credentials for downstream services such as Azure OpenAI, storage, and search. A compromised identity retrieving these keys is a common first step in LLMjacking and in pivoting from a Foundry project to the data it is connected to. + +*Rule type*: new_terms + +*Rule indices*: + +* logs-azure.activitylogs-* + +*Severity*: medium + +*Risk score*: 47 + +*Runs every*: 5m + +*Searches indices from*: now-9m ({ref}/common-options.html#date-math[Date Math format], see also <>) + +*Maximum alerts per execution*: 100 + +*References*: + +* https://learn.microsoft.com/en-us/azure/ai-services/authentication +* https://learn.microsoft.com/en-us/azure/ai-foundry/how-to/connections-add +* https://www.elastic.co/docs/reference/integrations/azure/activitylogs + +*Tags*: + +* Domain: Cloud +* Domain: GenAI +* Data Source: Azure +* Data Source: Azure Activity Logs +* Data Source: Microsoft Foundry +* Platform: Azure +* Use Case: Threat Detection +* Tactic: Credential Access +* Tactic: Initial Access +* Threat: LLMjacking +* Threat: Unauthorized AI Usage +* Mitre Atlas: AML.T0055 +* Resources: Investigation Guide +* Rule Type: New Terms + +*Version*: 1 + +*Rule authors*: + +* Elastic + +*Rule license*: Elastic License v2 + + +==== Investigation guide + + + +*Triage and analysis* + + + +*Investigating Microsoft Foundry Keys or Connection Secrets Accessed by New Principal* + + +Microsoft Foundry accounts (`Microsoft.CognitiveServices/accounts`) expose two API keys that authorize inference against +every model deployment on the account. Foundry accounts and projects also store connection secrets for linked resources. +This rule fires when a high-privilege principal that has not done so for that resource in the last seven days lists or +regenerates account keys, or reads account or project connection secrets. + + +*Possible investigation steps* + + +- Identify the caller from `azure.activitylogs.identity.authorization.evidence.principal_id`, `user.name`, and + `azure.activitylogs.identity.authorization.evidence.principal_type`, and confirm the role in + `azure.activitylogs.identity.authorization.evidence.role`. +- Review `azure.resource.name`, `azure.resource.group`, and `azure.subscription_id` to determine which Foundry account + or project was affected and what model deployments or connections it holds. +- Check `source.ip` and `source.geo.country_name` against the principal's normal sign-in locations, and review Entra ID + sign-in logs for the same principal around the event. +- For `REGENERATEKEY`, determine whether a legitimate key rotation was scheduled. An unplanned regeneration can also be + used to lock out legitimate applications. +- Look for follow-on activity from the same principal, such as deployment or content filter changes, diagnostic setting + deletion, or new role assignments on the account. + + +*False positive analysis* + + +- Portal users with privileged roles viewing keys during setup or troubleshooting. Confirm with the user and their + change records. +- Deployment automation that reads keys on every release. Exclude those service principals by ID. + + +*Response and remediation* + + +- If the access is not authorized, regenerate both account keys, rotate any connection secrets that were read, and + review recent inference usage and cost on the account. +- Revoke the principal's sessions, reset its credentials, and review its role assignments. +- Set `disableLocalAuth` on the account to require Entra ID authentication instead of keys where possible. + + +==== Setup + + + +*Setup* + + +This rule requires Azure Activity Logs ingested via the Azure integration (`azure.activitylogs` data stream). Key +listing, key regeneration, and connection secret reads are Administrative control-plane events and are logged by +default. + + +==== Rule query + + +[source, js] +---------------------------------- +data_stream.dataset: "azure.activitylogs" and +azure.activitylogs.operation_name: ( + "MICROSOFT.COGNITIVESERVICES/ACCOUNTS/LISTKEYS/ACTION" or + "MICROSOFT.COGNITIVESERVICES/ACCOUNTS/REGENERATEKEY/ACTION" or + "MICROSOFT.COGNITIVESERVICES/ACCOUNTS/CONNECTIONS/LISTSECRETS/ACTION" or + "MICROSOFT.COGNITIVESERVICES/ACCOUNTS/PROJECTS/CONNECTIONS/LISTSECRETS/ACTION" +) and +azure.activitylogs.identity.authorization.evidence.role: ( + "Owner" or + "Contributor" or + "Cognitive Services Contributor" or + "Cognitive Services OpenAI Contributor" or + "User Access Administrator" +) and event.outcome: "success" + +---------------------------------- + +*Framework*: MITRE ATT&CK^TM^ + +* Tactic: +** Name: Credential Access +** ID: TA0006 +** Reference URL: https://attack.mitre.org/tactics/TA0006/ +* Technique: +** Name: Credentials from Password Stores +** ID: T1555 +** Reference URL: https://attack.mitre.org/techniques/T1555/ +* Sub-technique: +** Name: Cloud Secrets Management Stores +** ID: T1555.006 +** Reference URL: https://attack.mitre.org/techniques/T1555/006/ +* Tactic: +** Name: Initial Access +** ID: TA0001 +** Reference URL: https://attack.mitre.org/tactics/TA0001/ +* Technique: +** Name: Valid Accounts +** ID: T1078 +** Reference URL: https://attack.mitre.org/techniques/T1078/ +* Sub-technique: +** Name: Cloud Accounts +** ID: T1078.004 +** Reference URL: https://attack.mitre.org/techniques/T1078/004/ diff --git a/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-microsoft-graph-application-directory-reconnaissance-with-denied-requests.asciidoc b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-microsoft-graph-application-directory-reconnaissance-with-denied-requests.asciidoc new file mode 100644 index 0000000000..608d3026cd --- /dev/null +++ b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-microsoft-graph-application-directory-reconnaissance-with-denied-requests.asciidoc @@ -0,0 +1,166 @@ +[[prebuilt-rule-8-19-37-microsoft-graph-application-directory-reconnaissance-with-denied-requests]] +=== Microsoft Graph Application Directory Reconnaissance with Denied Requests + +Identifies a Microsoft Graph application querying multiple directory collections and encountering access denials. Adversaries with compromised application credentials may enumerate users, groups, applications, service principals, directory roles, role assignments, and OAuth grants to identify privileged identities and opportunities for further access. + +*Rule type*: esql + +*Rule indices*: None + +*Severity*: medium + +*Risk score*: 47 + +*Runs every*: 5m + +*Searches indices from*: now-30m ({ref}/common-options.html#date-math[Date Math format], see also <>) + +*Maximum alerts per execution*: 100 + +*References*: + +* https://www.microsoft.com/en-us/security/blog/2026/10/21/storm-0940-uses-artex-agentic-ai-connectwise-supply-chain-compromise/ +* https://learn.microsoft.com/en-us/graph/microsoft-graph-activity-logs-overview + +*Tags*: + +* Domain: Cloud +* Domain: Identity +* Data Source: Azure +* Data Source: Microsoft Graph Activity Logs +* Use Case: Threat Detection +* Tactic: Discovery +* Resources: Investigation Guide +* Rule Type: ES|QL +* Platform: Microsoft Graph +* Platform: Azure + +*Version*: 1 + +*Rule authors*: + +* Elastic + +*Rule license*: Elastic License v2 + + +==== Investigation guide + + + +*Triage and analysis* + + + +*Investigating Microsoft Graph Application Directory Reconnaissance with Denied Requests* + + +Microsoft Graph exposes directory information that can help an adversary identify accounts, privileged identities, and applications to target. This rule identifies app-only requests to at least three common directory discovery collections (applications, service principals, users, groups, directory roles, role assignments, and OAuth permission grants) within a 15-minute window, with at least one HTTP 403 response. The denial requirement reduces noise from authorized inventory applications that succeed across the collections they are granted. A denied request shows attempted discovery, not successful retrieval of that collection. + + +*Possible investigation steps* + + +- Identify the calling principal using `azure.tenant_id` and `azure.graphactivitylogs.properties.service_principal_id`. Review `Esql.app_ids` and resolve the application owner and expected directory permissions. +- Review `Esql.time_window`, `Esql.request_count`, `Esql.category_count`, and `Esql.denied_count` to establish the scope of the discovery. Use `Esql.paths`, `Esql.status_codes`, and `Esql.source_ips` to review the targeted collections, outcomes, and sources. +- Examine the original Graph events to distinguish successfully accessed collections from denied requests. Determine whether the queried collections are needed for the application's documented purpose. +- Correlate the principal with service-principal sign-ins, recent application credential additions, and changes to application permissions. Where available, compare `azure.signinlogs.properties.service_principal_credential_key_id` with the credential added in audit records. +- Look for related role-assignment attempts, successful privilege changes, secret access, and access to other services. Distinguish the calling application from applications returned or targeted by its requests. +- Confirm whether an inventory, directory synchronization, onboarding, or permission-validation workflow explains the activity. + + +*False positive analysis* + + +- Directory inventory and synchronization applications may access several collections and encounter expected permission denials. Validate the activity with the application owner and compare it with normal sources and access patterns. +- Onboarding and permission-validation scripts may generate similar requests. Scope any justified exception to the tenant, principal, and expected workflow, and reassess it when permissions or ownership change. + + +*Response and remediation* + + +- If compromise is confirmed, restrict the affected principal and remove the specific compromised credential and unnecessary permissions according to the incident response process. +- Review and remediate unauthorized privilege changes or downstream resource access associated with the principal. +- Verify that subsequent access is denied after containment; credential removal alone does not establish that previously issued access tokens are unusable. +- Preserve the original Graph activity, audit, and sign-in events for investigation. + + +==== Setup + + + +*Microsoft Graph Activity Logs* + + +Enable Microsoft Graph Activity Logs and ingest them through the Azure integration into +`logs-azure.graphactivitylogs-*`. Retain the tenant and service-principal IDs, HTTP method, URL path, and response +status. The `azure.graphactivitylogs.properties.c_idtyp` field must be populated with the token actor type; +this rule selects `app` and does not infer app-only authentication from an application ID alone. + +The rule evaluates a 30-minute ingestion lookback every five minutes and groups requests into fixed 15-minute +event-time windows. Requests split across window boundaries or ingested more than 30 minutes apart may not be +combined. Review delivery latency and repeated aggregate alerts when tuning the schedule. The rule covers +the direct v1.0 collection paths in the query; beta endpoints and other request paths are outside its scope. + + +==== Rule query + + +[source, js] +---------------------------------- +from logs-azure.graphactivitylogs-* metadata _id, _index +| where data_stream.dataset == "azure.graphactivitylogs" + and azure.graphactivitylogs.properties.c_idtyp == "app" + and azure.tenant_id is not null and azure.tenant_id != "" + and azure.graphactivitylogs.properties.service_principal_id is not null + and azure.graphactivitylogs.properties.service_principal_id != "" + and http.request.method == "GET" + and http.response.status_code in (200, 403) + and url.path in ( + "/v1.0/applications", + "/v1.0/servicePrincipals", + "/v1.0/users", + "/v1.0/groups", + "/v1.0/directoryRoles", + "/v1.0/roleManagement/directory/roleAssignments", + "/v1.0/oauth2PermissionGrants" +) +| eval Esql.time_window = date_trunc(15 minutes, @timestamp) +| stats + Esql.request_count = count(*), + Esql.category_count = count_distinct(url.path), + Esql.denied_count = sum(case(http.response.status_code == 403, 1, 0)), + Esql.paths = values(url.path), + Esql.status_codes = values(http.response.status_code), + Esql.app_ids = values(azure.graphactivitylogs.properties.app_id), + Esql.source_ips = values(source.ip), + Esql.first_seen = min(@timestamp), + Esql.last_seen = max(@timestamp) + by Esql.time_window, azure.tenant_id, azure.graphactivitylogs.properties.service_principal_id +| where Esql.category_count >= 3 and Esql.denied_count >= 1 +| keep azure.tenant_id, azure.graphactivitylogs.properties.service_principal_id, Esql.* + +---------------------------------- + +*Framework*: MITRE ATT&CK^TM^ + +* Tactic: +** Name: Discovery +** ID: TA0007 +** Reference URL: https://attack.mitre.org/tactics/TA0007/ +* Technique: +** Name: Permission Groups Discovery +** ID: T1069 +** Reference URL: https://attack.mitre.org/techniques/T1069/ +* Sub-technique: +** Name: Cloud Groups +** ID: T1069.003 +** Reference URL: https://attack.mitre.org/techniques/T1069/003/ +* Technique: +** Name: Account Discovery +** ID: T1087 +** Reference URL: https://attack.mitre.org/techniques/T1087/ +* Sub-technique: +** Name: Cloud Account +** ID: T1087.004 +** Reference URL: https://attack.mitre.org/techniques/T1087/004/ diff --git a/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-openai-chatgpt-enterprise-jailbreak-prompt-heuristics.asciidoc b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-openai-chatgpt-enterprise-jailbreak-prompt-heuristics.asciidoc new file mode 100644 index 0000000000..bb71fa79cc --- /dev/null +++ b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-openai-chatgpt-enterprise-jailbreak-prompt-heuristics.asciidoc @@ -0,0 +1,173 @@ +[[prebuilt-rule-8-19-37-openai-chatgpt-enterprise-jailbreak-prompt-heuristics]] +=== OpenAI ChatGPT Enterprise Jailbreak Prompt Heuristics + +Detects ChatGPT Enterprise user messages that combine two or more common jailbreak techniques: overriding prior or system instructions, switching the assistant into an unrestricted persona or mode (for example DAN or developer mode), asking it to operate without safety restrictions or filters, or asking it to reveal its system prompt. Jailbreak prompts stack these techniques to talk the model out of its safety policy, and a user doing so in a managed workspace may be attempting to generate prohibited content or to probe the workspace's controls. Requiring more than one technique keeps documents that merely quote a single jailbreak phrase from alerting. + +*Rule type*: esql + +*Rule indices*: None + +*Severity*: medium + +*Risk score*: 47 + +*Runs every*: 5m + +*Searches indices from*: now-9m ({ref}/common-options.html#date-math[Date Math format], see also <>) + +*Maximum alerts per execution*: 100 + +*References*: + +* https://atlas.mitre.org/techniques/AML.T0054 +* https://www.elastic.co/docs/reference/integrations/openai_chatgpt_enterprise + +*Tags*: + +* Domain: GenAI +* Platform: OpenAI +* Data Source: OpenAI ChatGPT Enterprise +* Service: OpenAI ChatGPT Enterprise +* Use Case: Policy Violation +* Use Case: Threat Detection +* Resources: Investigation Guide +* Rule Type: ES|QL +* Tactic: Defense Evasion +* Mitre Atlas: AML.T0051 +* Mitre Atlas: AML.T0054 + +*Version*: 1 + +*Rule authors*: + +* Elastic + +*Rule license*: Elastic License v2 + + +==== Investigation guide + + + +*Triage and analysis* + + + +*Investigating OpenAI ChatGPT Enterprise Jailbreak Prompt Heuristics* + + +A ChatGPT Enterprise user message matched two or more jailbreak technique categories. The categories are tracked +separately in `Esql.has_instruction_override`, `Esql.has_persona_switch`, `Esql.has_restriction_removal`, and +`Esql.has_system_prompt_extraction`, and their total is `Esql.indicator_count`. + + +*Possible investigation steps* + + +- Read `message` and decide whether the user is attempting a jailbreak or is quoting, analyzing, or documenting one. + A short prompt addressed to the assistant is more suspicious than a long pasted document. +- Review the rest of the conversation using `openai_chatgpt_enterprise.conversation_message.conversation.id`. Look + at whether the assistant refused, and whether the user rephrased and retried. +- Check `user.email` and `user.id` for related alerts, such as OpenAI ChatGPT Enterprise Repeated Assistant Refusals, + credential sharing in conversations, or unusual connector use. +- Determine whether the user belongs to a team that legitimately researches jailbreaks or prompt injection. + + +*False positive analysis* + + +- AI safety and security researchers analyzing jailbreak techniques. Add exceptions for these users. +- Documentation that lists several jailbreak phrases. These messages tend to be long and descriptive rather than + addressed to the assistant. + + +*Response and remediation* + + +- If the attempt is not sanctioned, follow the organization's acceptable use process for the user. +- Review whether any content produced in the conversation should be reported or removed, and whether workspace + policies or custom GPT instructions need tightening. + + +==== Setup + + + +*Setup* + + +This rule requires the OpenAI ChatGPT Enterprise integration to collect compliance logs into Elasticsearch, including +the `conversation_message` data stream. +https://www.elastic.co/docs/reference/integrations/openai_chatgpt_enterprise + + +==== Rule query + + +[source, js] +---------------------------------- +from logs-openai_chatgpt_enterprise.conversation_message-* metadata _id, _version, _index +| where + data_stream.dataset == "openai_chatgpt_enterprise.conversation_message" and + openai_chatgpt_enterprise.conversation_message.message.author.type == "user" and + message is not null +| eval + Esql.message_text = to_lower(message), + Esql.message_length = length(message) +| eval + Esql.has_instruction_override = case( + Esql.message_text rlike """.*(ignore|disregard|forget|override) (all |any )?(of )?(your |the |my )?(previous|prior|above|earlier|original|system|developer) (instructions|prompts?|rules|guidelines|directives|programming).*""" or + Esql.message_text rlike """.*(ignore|disregard|forget) (all |any )?(of )?(the )?(instructions|rules|guidelines) (you (got|were given|received)|given to you).*""" or + Esql.message_text like "*forget everything you were told*", + 1, 0 + ), + Esql.has_persona_switch = case( + Esql.message_text rlike """.*(you are|act as|pretend (to be|you are)|roleplay as|from now on,? you are) (now )?(dan|stan|dude|aim|an? (unfiltered|unrestricted|uncensored|amoral) (ai|assistant|model|chatbot)).*""" or + Esql.message_text like "*do anything now*" or + Esql.message_text rlike """.*(enable|enter|activate|switch to) (developer|god|jailbreak|unrestricted|dan) mode.*""", + 1, 0 + ), + Esql.has_restriction_removal = case( + Esql.message_text rlike """.*(without|with no|free (of|from)|ignoring) (any |your |all )?(ethical |content |safety |moral )?(restrictions|filters|guidelines|limitations|censorship).*""" or + Esql.message_text rlike """.*(bypass|disable|turn off|ignore) (your |the |all )?(safety|content) (filters?|polic(y|ies)|guidelines|guardrails).*""" or + Esql.message_text rlike """.*(do not|does not|don't|doesn't) have to (abide by|follow|obey) (the |any |your )?(rules|guidelines|policies).*""", + 1, 0 + ), + Esql.has_system_prompt_extraction = case( + Esql.message_text rlike """.*(reveal|print|show|repeat|output) (me )?(your |the )?(full |hidden |original )?(system prompt|initial instructions|hidden instructions).*""", + 1, 0 + ) +| eval + Esql.indicator_count = Esql.has_instruction_override + Esql.has_persona_switch + Esql.has_restriction_removal + Esql.has_system_prompt_extraction +| where Esql.indicator_count >= 2 +| keep + _id, + _version, + _index, + @timestamp, + message, + user.id, + user.email, + openai_chatgpt_enterprise.conversation_message.conversation.id, + openai_chatgpt_enterprise.conversation_message.conversation.title, + openai_chatgpt_enterprise.conversation_message.message.id, + Esql.message_length, + Esql.indicator_count, + Esql.has_instruction_override, + Esql.has_persona_switch, + Esql.has_restriction_removal, + Esql.has_system_prompt_extraction, + data_stream.* + +---------------------------------- + +*Framework*: MITRE ATT&CK^TM^ + +* Tactic: +** Name: Defense Evasion +** ID: TA0005 +** Reference URL: https://attack.mitre.org/tactics/TA0005/ +* Technique: +** Name: Impair Defenses +** ID: T1562 +** Reference URL: https://attack.mitre.org/techniques/T1562/ diff --git a/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-package-runtime-secret-file-access-followed-by-imds-request.asciidoc b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-package-runtime-secret-file-access-followed-by-imds-request.asciidoc new file mode 100644 index 0000000000..cddd896c88 --- /dev/null +++ b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-package-runtime-secret-file-access-followed-by-imds-request.asciidoc @@ -0,0 +1,237 @@ +[[prebuilt-rule-8-19-37-package-runtime-secret-file-access-followed-by-imds-request]] +=== Package Runtime Secret File Access Followed by IMDS Request + +Identifies a Python, Node.js, Bun, Deno, Ruby, PHP or Perl runtime, or a binary executing from a package install location, that opens a developer secret (SSH keys, package registry tokens, source control credentials or AI coding assistant credentials) and then connects to a cloud instance metadata service (IMDS) endpoint within one minute. This sequence matches credential stealers delivered through compromised packages, such as the malicious LiteLLM PyPI releases, while cloud provider credential files are excluded because legitimate cloud SDK credential chains read them before falling back to IMDS. + +*Rule type*: eql + +*Rule indices*: + +* logs-endpoint.events.file-* +* logs-endpoint.events.network-* + +*Severity*: high + +*Risk score*: 73 + +*Runs every*: 5m + +*Searches indices from*: now-9m ({ref}/common-options.html#date-math[Date Math format], see also <>) + +*Maximum alerts per execution*: 100 + +*References*: None + +*Tags*: + +* Domain: Endpoint +* Domain: Cloud +* OS: macOS +* OS: Windows +* Use Case: Threat Detection +* Tactic: Credential Access +* Tactic: Initial Access +* Data Source: Elastic Defend +* Resources: Investigation Guide +* Threat: Supply Chain +* Threat: IMDS Credential Theft +* Rule Type: Event Correlation (EQL) +* Platform: macOS +* Platform: Windows +* Domain: GenAI +* Mitre Atlas: AML.T0010 +* Mitre Atlas: AML.T0010.001 +* Mitre Atlas: AML.T0055 +* Mitre Atlas: AML.T0083 + +*Version*: 1 + +*Rule authors*: + +* Elastic + +*Rule license*: Elastic License v2 + + +==== Investigation guide + + + +*Triage and analysis* + + + +*Investigating Package Runtime Secret File Access Followed by IMDS Request* + + +This rule correlates two behaviors from the same package ecosystem runtime process (`process.entity_id`) within one +minute: opening a local secret store that cloud SDKs never read, followed by a connection to a cloud instance metadata endpoint +(`169.254.169.254`, the ECS and EKS Pod Identity credential endpoints, the AWS IPv6 IMDS endpoints, or the Alibaba +Cloud metadata endpoint). Legitimate software rarely needs both an SSH key, registry token or AI assistant credential +and cloud role credentials. Infostealers delivered through compromised packages routinely do both, typically from a +Python or Node.js interpreter that imported the malicious package. + + +*Possible investigation steps* + + +- Identify the process (`process.executable`, `process.entity_id`) and walk its ancestry to determine what launched it. + Pay close attention to package managers, CI runners, notebooks, IDEs, AI coding agents, and interpreters executing + from virtual environments or `site-packages`/`node_modules`. +- Review all file events for the same `process.entity_id` to scope which secrets were accessed. Stealers usually + enumerate many credential locations in a short burst. +- Review all network events for the same `process.entity_id` for outbound connections to non-metadata destinations + immediately after the IMDS request, which may indicate exfiltration of the harvested data. +- Look for Python `.pth` files, `sitecustomize.py`/`usercustomize.py`, or recently installed or upgraded packages in the + interpreter's environment that could have executed the code at import time. +- Check cloud audit logs (CloudTrail, GCP Audit, Azure Activity) for use of the instance role credentials from IP + addresses outside the instance's expected egress. + + +*False positive analysis* + + +- Release or deployment scripts on cloud-hosted build agents may read a registry or source control token and then + request instance role credentials from the same interpreter. Confirm the script is an approved part of a build or + release pipeline on that host. +- AI coding assistants on cloud instances may read their own credential file before falling back to the metadata server + for cloud authentication. Confirm the process is the assistant that owns the credential file. + + +*Response and remediation* + + +- Isolate the host and terminate the offending process tree. +- Rotate every secret the process opened (SSH keys, npm/PyPI tokens, Git and GitHub CLI tokens, Vault and Terraform + tokens, AI assistant OAuth tokens) and revoke active sessions for the instance role or workload identity. +- Identify and remove the malicious package version from the environment, lock files and internal mirrors, and hunt for + the same package version across other hosts and CI runners. +- Enforce IMDSv2 with a hop limit of 1 where possible and scope instance roles to least privilege. + + +==== Setup + + + +*Setup* + + +This rule requires data from Elastic Defend with file and network event collection enabled. + +Elastic Defend only generates file `open` events on macOS and Windows, and only for paths in its event-on-access file +path list. That list is delivered through the Elastic Defend global configuration artifact and can be extended per +policy with the `advanced.events.event_on_access.file_paths` advanced setting. Credential paths in this rule that are +not yet present in the deployed global configuration only match after they are added to that setting. On Windows, +repeated access events for the same path are deduplicated for one hour by default. + +This rule is scoped to macOS and Windows because Elastic Defend does not generate file `open` events on Linux. + + +==== Rule query + + +[source, js] +---------------------------------- +sequence by process.entity_id with maxspan=1m + [file where event.action == "open" and host.os.type in ("macos", "windows") and + file.path like~ ( + /* SSH private keys */ + "/Users/*/.ssh/id_*", "?:\\Users\\*\\.ssh\\id_*", + + /* Package registry, source control and secrets manager tokens */ + "/Users/*/.npmrc", "?:\\Users\\*\\.npmrc", + "/Users/*/.pypirc", "?:\\Users\\*\\.pypirc", + "/Users/*/.git-credentials", "?:\\Users\\*\\.git-credentials", + "/Users/*/.config/git/credentials", "?:\\Users\\*\\.config\\git\\credentials", + "/Users/*/.config/gh/hosts.yml", "?:\\Users\\*\\AppData\\Roaming\\GitHub CLI\\hosts.yml", + "/Users/*/.vault-token", "?:\\Users\\*\\.vault-token", + "/Users/*/.terraform.d/credentials.tfrc.json", "?:\\Users\\*\\AppData\\Roaming\\terraform.d\\credentials.tfrc.json", + + /* Additional package registry and AI/ML platform tokens */ + "/Users/*/.yarnrc.yml", "?:\\Users\\*\\.yarnrc.yml", + "/Users/*/.gem/credentials", "?:\\Users\\*\\.gem\\credentials", + "/Users/*/.cargo/credentials.toml", "?:\\Users\\*\\.cargo\\credentials.toml", + "/Users/*/.composer/auth.json", "/Users/*/.config/composer/auth.json", "?:\\Users\\*\\AppData\\Roaming\\Composer\\auth.json", + "/Users/*/.cache/huggingface/token", "/Users/*/.huggingface/token", "?:\\Users\\*\\.cache\\huggingface\\token", "?:\\Users\\*\\.huggingface\\token", + "/Users/*/.config/github-copilot/apps.json", "/Users/*/.config/github-copilot/hosts.json", + "?:\\Users\\*\\AppData\\Local\\github-copilot\\apps.json", "?:\\Users\\*\\AppData\\Local\\github-copilot\\hosts.json", + "/Users/*/.ollama/id_ed25519", "?:\\Users\\*\\.ollama\\id_ed25519", + + /* AI coding assistant credentials */ + "/Users/*/.claude/.credentials.json", "?:\\Users\\*\\.claude\\.credentials.json", + "/Users/*/.codex/auth.json", "?:\\Users\\*\\.codex\\auth.json", + "/Users/*/.codex/.credentials.json", "?:\\Users\\*\\.codex\\.credentials.json", + "/Users/*/.codex/secrets/*.age", "?:\\Users\\*\\.codex\\secrets\\*.age", + "/Users/*/.gemini/oauth_creds.json", "?:\\Users\\*\\.gemini\\oauth_creds.json", + "/Users/*/.gemini/gemini-credentials.json", "?:\\Users\\*\\.gemini\\gemini-credentials.json", + "/Users/*/.gemini/mcp-oauth-tokens.json", "?:\\Users\\*\\.gemini\\mcp-oauth-tokens.json", + "/Users/*/.gemini/a2a-oauth-tokens.json", "?:\\Users\\*\\.gemini\\a2a-oauth-tokens.json", + "/Users/*/.qwen/oauth_creds.json", "?:\\Users\\*\\.qwen\\oauth_creds.json", + "/Users/*/.qwen/mcp-oauth-tokens.json", "?:\\Users\\*\\.qwen\\mcp-oauth-tokens.json", + "/Users/*/.aws/sso/cache/kiro-auth-token.json", "?:\\Users\\*\\.aws\\sso\\cache\\kiro-auth-token.json", + "/Users/*/.local/share/opencode/auth.json", "?:\\Users\\*\\.local\\share\\opencode\\auth.json", + "/Users/*/.local/share/opencode/mcp-auth.json", "?:\\Users\\*\\.local\\share\\opencode\\mcp-auth.json", + "/Users/*/.local/share/amp/secrets.json", "?:\\Users\\*\\.local\\share\\amp\\secrets.json", + "/Users/*/.augment/session.json", "?:\\Users\\*\\.augment\\session.json", + "/Users/*/.kimi/credentials/kimi-code.json", "?:\\Users\\*\\.kimi\\credentials\\kimi-code.json", + "/Users/*/.cursor/auth.json", "?:\\Users\\*\\.cursor\\auth.json", + "/Users/*/.pi/agent/auth.json", "?:\\Users\\*\\.pi\\agent\\auth.json", + "/Users/*/.config/goose/secrets.yaml", "?:\\Users\\*\\AppData\\Roaming\\Block\\goose\\config\\secrets.yaml", + "/Users/*/.config/muse/auth.json", "?:\\Users\\*\\.config\\muse\\auth.json", + "/Users/*/.local/share/devin/credentials.toml", "?:\\Users\\*\\AppData\\Roaming\\devin\\credentials.toml", + "/Users/*/.openclaw/credentials/oauth.json", "?:\\Users\\*\\.openclaw\\credentials\\oauth.json", + "/Users/*/.openclaw/agents/*/agent/auth-profiles.json", "?:\\Users\\*\\.openclaw\\agents\\*\\agent\\auth-profiles.json", + "/Users/*/.openclaw/agents/*/agent/auth.json", "?:\\Users\\*\\.openclaw\\agents\\*\\agent\\auth.json" + ) and + + /* SSH public keys are not secrets and are routinely read by SSH and cloud tooling */ + not file.path like~ "*.pub" and + + /* Package ecosystem runtimes or binaries executing from package install locations */ + ( + process.name like~ ("python*", "node", "node.exe", "nodejs", "bun", "bun.exe", "deno", "deno.exe", "ruby*", "php*", "perl*") or + process.executable like~ ("*/site-packages/*", "*/dist-packages/*", "*/node_modules/*", "*\\site-packages\\*", "*\\node_modules\\*", + "*/.venv/*", "*/venv/*", "*\\.venv\\*", "*\\venv\\*") + ) + ] + [network where + cidrmatch(destination.ip, "169.254.169.254/32", "169.254.170.2/32", "169.254.170.23/32", "100.100.100.200/32", "fd00:ec2::254/128", "fd00:ec2::23/128") and + destination.port == 80 and event.action == "connection_attempted" and host.os.type in ("macos", "windows") + ] + +---------------------------------- + +*Framework*: MITRE ATT&CK^TM^ + +* Tactic: +** Name: Credential Access +** ID: TA0006 +** Reference URL: https://attack.mitre.org/tactics/TA0006/ +* Technique: +** Name: Unsecured Credentials +** ID: T1552 +** Reference URL: https://attack.mitre.org/techniques/T1552/ +* Sub-technique: +** Name: Credentials In Files +** ID: T1552.001 +** Reference URL: https://attack.mitre.org/techniques/T1552/001/ +* Sub-technique: +** Name: Private Keys +** ID: T1552.004 +** Reference URL: https://attack.mitre.org/techniques/T1552/004/ +* Sub-technique: +** Name: Cloud Instance Metadata API +** ID: T1552.005 +** Reference URL: https://attack.mitre.org/techniques/T1552/005/ +* Tactic: +** Name: Initial Access +** ID: TA0001 +** Reference URL: https://attack.mitre.org/tactics/TA0001/ +* Technique: +** Name: Supply Chain Compromise +** ID: T1195 +** Reference URL: https://attack.mitre.org/techniques/T1195/ +* Sub-technique: +** Name: Compromise Software Dependencies and Development Tools +** ID: T1195.001 +** Reference URL: https://attack.mitre.org/techniques/T1195/001/ diff --git a/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-persistence-via-a-hidden-plist-filename-via-macos-security-events.asciidoc b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-persistence-via-a-hidden-plist-filename-via-macos-security-events.asciidoc new file mode 100644 index 0000000000..daf7a98b0a --- /dev/null +++ b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-persistence-via-a-hidden-plist-filename-via-macos-security-events.asciidoc @@ -0,0 +1,155 @@ +[[prebuilt-rule-8-19-37-persistence-via-a-hidden-plist-filename-via-macos-security-events]] +=== Persistence via a Hidden Plist Filename via macOS Security Events + +Identifies the registration of a launch agent or launch daemon whose property list (plist) filename begins with a dot, using launch item registration messages collected by the macOS Security Events integration. An adversary may establish persistence by installing a launch agent or daemon that executes at login or boot; plist files with filenames starting with a dot are hidden from default directory listings and are particularly suspicious. + +*Rule type*: esql + +*Rule indices*: None + +*Severity*: medium + +*Risk score*: 47 + +*Runs every*: 5m + +*Searches indices from*: now-9m ({ref}/common-options.html#date-math[Date Math format], see also <>) + +*Maximum alerts per execution*: 100 + +*References*: + +* https://www.welivesecurity.com/2022/07/19/i-see-what-you-did-there-look-cloudmensis-macos-spyware/ +* https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingLaunchdJobs.html + +*Tags*: + +* OS: macOS +* Use Case: Threat Detection +* Tactic: Persistence +* Tactic: Defense Evasion +* Data Source: macOS Security Events +* Resources: Investigation Guide +* Rule Type: ES|QL +* Platform: macOS +* Domain: Endpoint + +*Version*: 5 + +*Rule authors*: + +* Elastic + +*Rule license*: Elastic License v2 + + +==== Investigation guide + + + +*Triage and analysis* + + +> **Disclaimer**: +> This investigation guide was created using generative AI technology and has been reviewed to improve its accuracy and relevance. While every effort has been made to ensure its quality, we recommend validating the content and adapting it to suit your specific environment and operational needs. + + +*Investigating Persistence via a Hidden Plist Filename via macOS Security Events* + + +On macOS, launch agents and launch daemons provide persistence by running a program defined in a property list (plist) file located in a LaunchAgents or LaunchDaemons directory. When a launch item is registered, the BackgroundTaskManagement subsystem logs its path, type, and target executable to the unified log. Adversaries name the plist with a leading dot (for example `.com.evil.agent.plist`) so it is hidden from default directory listings while still functioning as persistence. This rule alerts when a registered launch item's plist filename begins with a dot, and reports the plist path, item type, and target executable extracted from the message. + + +*Possible investigation steps* + + +- Review `Esql.plist_path`, `Esql.item_type`, and `Esql.executable` in the alert to identify the hidden plist, whether it is a launch agent (per-user) or launch daemon (system-wide), and what it runs. +- Retrieve and examine the plist and its target executable on the host. Determine whether the program is signed, where it is located, and what it does; executables in user-writable or temporary locations are higher risk. +- Determine how and when the plist was created, and by which process, using Elastic Defend file telemetry if available. +- Check whether the label or filename masquerades as a legitimate Apple or vendor service. +- Review other alerts and activity for the host and associated user during the same period. + + +*False positive analysis* + + +- Some legitimate software and management tooling create dot-prefixed plists as part of atomic file writes or internal bookkeeping. +- Verify the executable and signing status before escalating; recurring benign cases can be excluded by plist path or executable. + + +*Response and remediation* + + +- If the launch item is not legitimate, unload it with `launchctl bootout` and remove the plist, then remove or quarantine the target executable. +- Investigate the host for related persistence, the initial access vector, and any activity performed by the launch item's program. +- Reset credentials for the affected user and review the host for additional compromise. +- Escalate to the security operations team if additional hosts show similar patterns. + + +==== Setup + + + +*Setup* + + +This rule requires data from the macOS Security Events integration. +Integration setup instructions: https://www.elastic.co/docs/reference/integrations/macos[macOS Security Events Integration for Elastic] + + +==== Rule query + + +[source, js] +---------------------------------- +FROM logs-macos.process_execution_monitoring-* metadata _id, _version, _index +| WHERE data_stream.dataset == "macos.process_execution_monitoring" and + macos.event.message.description LIKE "*effectiveItemDisposition*" and + (macos.event.message.description LIKE "*url=file://*/Library/LaunchAgents/.*" or + macos.event.message.description LIKE "*url=file://*/Library/LaunchDaemons/.*") +| GROK macos.event.message.description "url=file://%{DATA:Esql.plist_path}, config" +| GROK macos.event.message.description "type=%{DATA:Esql.item_type}," +| GROK macos.event.message.description "BTMConfigExecutablePath = \"%{DATA:Esql.executable}\"" +| WHERE Esql.plist_path RLIKE ".*/Library/Launch(Agents|Daemons)/\\..*\\.plist" +| KEEP _id, _version, _index, @timestamp, host.name, Esql.plist_path, Esql.item_type, Esql.executable, macos.event.message.description + +---------------------------------- + +*Framework*: MITRE ATT&CK^TM^ + +* Tactic: +** Name: Persistence +** ID: TA0003 +** Reference URL: https://attack.mitre.org/tactics/TA0003/ +* Technique: +** Name: Boot or Logon Autostart Execution +** ID: T1547 +** Reference URL: https://attack.mitre.org/techniques/T1547/ +* Technique: +** Name: Create or Modify System Process +** ID: T1543 +** Reference URL: https://attack.mitre.org/techniques/T1543/ +* Sub-technique: +** Name: Launch Agent +** ID: T1543.001 +** Reference URL: https://attack.mitre.org/techniques/T1543/001/ +* Sub-technique: +** Name: Launch Daemon +** ID: T1543.004 +** Reference URL: https://attack.mitre.org/techniques/T1543/004/ +* Tactic: +** Name: Defense Evasion +** ID: TA0005 +** Reference URL: https://attack.mitre.org/tactics/TA0005/ +* Technique: +** Name: Plist File Modification +** ID: T1647 +** Reference URL: https://attack.mitre.org/techniques/T1647/ +* Technique: +** Name: Hide Artifacts +** ID: T1564 +** Reference URL: https://attack.mitre.org/techniques/T1564/ +* Sub-technique: +** Name: Hidden Files and Directories +** ID: T1564.001 +** Reference URL: https://attack.mitre.org/techniques/T1564/001/ diff --git a/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-persistence-via-a-hidden-plist-filename.asciidoc b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-persistence-via-a-hidden-plist-filename.asciidoc new file mode 100644 index 0000000000..575e616d44 --- /dev/null +++ b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-persistence-via-a-hidden-plist-filename.asciidoc @@ -0,0 +1,153 @@ +[[prebuilt-rule-8-19-37-persistence-via-a-hidden-plist-filename]] +=== Persistence via a Hidden Plist Filename + +Identifies the creation of a hidden launch agent or daemon property list file. An adversary may establish persistence by installing a new launch agent or daemon which executes at login. Hidden plist files with filenames starting with a dot are particularly suspicious. + +*Rule type*: eql + +*Rule indices*: + +* logs-endpoint.events.file-* + +*Severity*: high + +*Risk score*: 73 + +*Runs every*: 5m + +*Searches indices from*: now-9m ({ref}/common-options.html#date-math[Date Math format], see also <>) + +*Maximum alerts per execution*: 100 + +*References*: + +* https://www.welivesecurity.com/2022/07/19/i-see-what-you-did-there-look-cloudmensis-macos-spyware/ +* https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingLaunchdJobs.html + +*Tags*: + +* Domain: Endpoint +* OS: macOS +* Use Case: Threat Detection +* Tactic: Persistence +* Tactic: Defense Evasion +* Data Source: Elastic Defend +* Resources: Investigation Guide +* Noise: Low +* Performance: Fast +* Profile: Recommended +* Rule Type: Event Correlation (EQL) +* Platform: macOS + +*Version*: 4 + +*Rule authors*: + +* Elastic + +*Rule license*: Elastic License v2 + + +==== Investigation guide + + + +*Triage and analysis* + + +> **Disclaimer**: +> This investigation guide was created using generative AI technology and has been reviewed to improve its accuracy and relevance. While every effort has been made to ensure its quality, we recommend validating the content and adapting it to suit your specific environment and operational needs. + + +*Investigating Persistence via a Hidden Plist Filename* + + +LaunchAgents and LaunchDaemons are macOS persistence mechanisms that automatically execute programs at login or system startup. Files with names starting with a dot (.) are hidden from standard directory listings in macOS, making them less visible to users and administrators. Threat actors combine these techniques by creating hidden plist files in LaunchAgent/LaunchDaemon directories to establish stealthy persistence that survives reboots while evading casual inspection. This behavior was notably observed in the CloudMensis macOS spyware campaign. + + +*Possible investigation steps* + + +- Examine the file.path to identify the full path of the hidden plist file and determine whether it is in a user-specific or system-wide LaunchAgent/LaunchDaemon directory. +- Use plutil or defaults to read the plist contents and identify the executable path, arguments, and execution conditions configured in the ProgramArguments or Program keys. +- Locate the binary or script referenced in the plist file and calculate its hash for threat intelligence lookups. +- Analyze the binary's code signature using codesign -dvvv to determine if it is signed, and by whom. +- Review the process.executable that created the plist file to understand the initial delivery mechanism. +- Check file creation timestamps to determine when the hidden plist was created and correlate with other security events. +- Search for other hidden files in LaunchAgent and LaunchDaemon directories across the system. + + +*False positive analysis* + + +- Chef configuration management may create hidden plists matching .chef-com* patterns. These are already excluded in the query. +- Some legitimate applications may temporarily create dot-prefixed files during installation. Verify the process that created the file and its signature. +- Backup and synchronization tools occasionally create hidden configuration files. Confirm the tool's legitimacy and expected behavior. +- System processes like sed may create temporary hidden files during in-place editing operations. These are partially excluded in the query. + + +*Response and remediation* + + +- Immediately unload the hidden LaunchAgent or LaunchDaemon using launchctl unload with the plist path. +- Remove the hidden plist file from the LaunchAgent or LaunchDaemon directory. +- Locate and remove the malicious binary or script referenced in the plist's Program or ProgramArguments keys. +- Search for related hidden files, configuration files, or staging directories that may be part of the same malware deployment. +- Review system logs for evidence of the hidden persistence mechanism executing and what actions it performed. +- Check for data exfiltration or command and control communication if the behavior matches known spyware patterns like CloudMensis. +- Reset credentials that may have been accessed while the persistence mechanism was active. +- Monitor for recreation of hidden plist files in LaunchAgent and LaunchDaemon directories. + + +==== Rule query + + +[source, js] +---------------------------------- +file where host.os.type == "macos" and event.type != "deletion" and + file.path like~ ( + "/System/Library/LaunchAgents/.*.plist", + "/Library/LaunchAgents/.*.plist", + "/Users/*/Library/LaunchAgents/.*.plist", + "/System/Library/LaunchDaemons/.*.plist", + "/Library/LaunchDaemons/.*.plist" + ) and + not (file.name like ".chef-com*.plist" and process.executable like "/opt/chef/embedded/bin/ruby") and + not (process.executable in ("/usr/bin/sed", "/bin/bash") and file.name like ".!*!*.plist") + +---------------------------------- + +*Framework*: MITRE ATT&CK^TM^ + +* Tactic: +** Name: Persistence +** ID: TA0003 +** Reference URL: https://attack.mitre.org/tactics/TA0003/ +* Technique: +** Name: Boot or Logon Autostart Execution +** ID: T1547 +** Reference URL: https://attack.mitre.org/techniques/T1547/ +* Technique: +** Name: Create or Modify System Process +** ID: T1543 +** Reference URL: https://attack.mitre.org/techniques/T1543/ +* Sub-technique: +** Name: Launch Agent +** ID: T1543.001 +** Reference URL: https://attack.mitre.org/techniques/T1543/001/ +* Tactic: +** Name: Defense Evasion +** ID: TA0005 +** Reference URL: https://attack.mitre.org/tactics/TA0005/ +* Technique: +** Name: Plist File Modification +** ID: T1647 +** Reference URL: https://attack.mitre.org/techniques/T1647/ +* Technique: +** Name: Hide Artifacts +** ID: T1564 +** Reference URL: https://attack.mitre.org/techniques/T1564/ +* Sub-technique: +** Name: Hidden Files and Directories +** ID: T1564.001 +** Reference URL: https://attack.mitre.org/techniques/T1564/001/ diff --git a/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-persistence-via-suspicious-launch-agent-or-launch-daemon.asciidoc b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-persistence-via-suspicious-launch-agent-or-launch-daemon.asciidoc new file mode 100644 index 0000000000..2f26039af5 --- /dev/null +++ b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-persistence-via-suspicious-launch-agent-or-launch-daemon.asciidoc @@ -0,0 +1,158 @@ +[[prebuilt-rule-8-19-37-persistence-via-suspicious-launch-agent-or-launch-daemon]] +=== Persistence via Suspicious Launch Agent or Launch Daemon + +Identifies the creation of a launch agent or daemon property list file containing abnormal or suspicious values. An adversary may establish persistence by installing a new launch agent or daemon which executes at login. This rule looks for plist files created in LaunchAgents/LaunchDaemons directories with paths commonly used by malware. + +*Rule type*: eql + +*Rule indices*: + +* logs-endpoint.events.file-* + +*Severity*: high + +*Risk score*: 73 + +*Runs every*: 5m + +*Searches indices from*: now-9m ({ref}/common-options.html#date-math[Date Math format], see also <>) + +*Maximum alerts per execution*: 100 + +*References*: + +* https://medium.com/red-teaming-with-a-blue-team-mentality/a-brief-look-at-macos-detections-and-post-infection-analysis-b0ede7ecfeb9 +* https://objective-see.org/blog +* https://www.elastic.co/security-labs/DPRK-strikes-using-a-new-variant-of-rustbucket + +*Tags*: + +* Domain: Endpoint +* OS: macOS +* Use Case: Threat Detection +* Tactic: Persistence +* Tactic: Defense Evasion +* Data Source: Elastic Defend +* Resources: Investigation Guide +* Noise: Medium +* Performance: Fast +* Rule Type: Event Correlation (EQL) +* Platform: macOS + +*Version*: 5 + +*Rule authors*: + +* Elastic + +*Rule license*: Elastic License v2 + + +==== Investigation guide + + + +*Triage and analysis* + + +> **Disclaimer**: +> This investigation guide was created using generative AI technology and has been reviewed to improve its accuracy and relevance. While every effort has been made to ensure its quality, we recommend validating the content and adapting it to suit your specific environment and operational needs. + + +*Investigating Persistence via Suspicious Launch Agent or Launch Daemon* + + +LaunchAgents and LaunchDaemons are the standard macOS mechanisms for starting programs automatically at user login or system boot. While essential for legitimate software, these persistence mechanisms are heavily abused by malware including RustBucket (DPRK), Shlayer, and CloudMensis. This detection rule identifies plist file creation in LaunchAgent/LaunchDaemon directories when performed by suspicious processes including scripts executing from temporary directories, unsigned binaries, or scripting interpreters like Python and osascript. + + +*Possible investigation steps* + + +- Examine the file.path to identify the specific plist file created and its location (user vs system LaunchAgent/LaunchDaemon directory). +- Read the plist contents using plutil or defaults to identify the Program or ProgramArguments configured for execution. +- Analyze the process.executable to understand what created the plist file and assess whether execution from that location (temp directory, hidden folder) is suspicious. +- Check the process.name and process.code_signature fields to determine if the creating process was a scripting interpreter or unsigned binary. +- Locate the binary or script referenced in the plist and calculate its hash for threat intelligence lookups. +- Review the parent process chain to trace back to the initial execution vector that led to plist creation. +- Correlate with other file and process events to identify additional malware components that may have been deployed simultaneously. + + +*False positive analysis* + + +- Legitimate software installers may create LaunchAgents/LaunchDaemons during setup, but typically from signed installer processes rather than scripts in temp directories. +- Development and testing environments may use scripting languages to create launch items. Verify with development teams if such activities are expected. +- Several legitimate signing IDs are already excluded including vim, JetBrains Toolbox, and Sublime Text. +- System utilities like cfprefsd may modify plist files during normal operations and are excluded. +- Enterprise deployment tools may use scripts to configure launch items. Document and exclude approved deployment processes. + + +*Response and remediation* + + +- Immediately unload the suspicious LaunchAgent or LaunchDaemon using launchctl unload with the plist path. +- Remove the malicious plist file from the LaunchAgent or LaunchDaemon directory. +- Locate and remove the executable or script referenced in the plist's Program or ProgramArguments keys. +- Check for other persistence mechanisms that may have been deployed by the same threat actor. +- Review system logs for evidence of the persistence mechanism executing and what actions it performed. +- If the detection matches patterns of known malware families (RustBucket, Shlayer), perform comprehensive IOC searches and threat hunting. +- Reset any credentials that may have been accessed while the malicious process was running. +- Monitor for recreation of similar plist files to detect persistent access or ongoing compromise. + + +==== Rule query + + +[source, js] +---------------------------------- +file where host.os.type == "macos" and event.type != "deletion" and + file.extension == "plist" and + file.path like ("/Library/LaunchAgents/*", "/Library/LaunchDaemons/*", + "/Users/*/Library/LaunchAgents/*", "/System/Library/LaunchAgents/*", + "/System/Library/LaunchDaemons/*") and + (process.executable like ("/private/tmp/*", "/private/var/root/Library/*", "/var/tmp/*", + "/tmp/*", "/var/folders/*", "/Users/Shared/*", "/var/root/*", + "/Library/WebServer/*", "/Library/Graphics/*", "/Library/Fonts/*") or + process.name like~ ("python*", "osascript", "bash", "zsh", "sh", "curl", "nscurl", "wget", "java")) and + not process.executable like ("/System/*", "/Library/PrivilegedHelperTools/*") and + not (process.code_signature.signing_id in ("com.apple.vim", "com.apple.cat", "com.apple.cfprefsd", + "com.jetbrains.toolbox", "com.apple.pico", "com.apple.shove", + "com.sublimetext.4", "com.apple.ditto") and process.code_signature.trusted == true) and + not (file.path like ("/Library/LaunchDaemons/com.jumpcloud.*", + "/Library/LaunchAgents/com.jumpcloud.*", + "/Library/LaunchDaemons/com.wazuh.*", + "/Library/LaunchDaemons/com.zscaler.service.plist") and + process.executable == "/bin/bash") + +---------------------------------- + +*Framework*: MITRE ATT&CK^TM^ + +* Tactic: +** Name: Persistence +** ID: TA0003 +** Reference URL: https://attack.mitre.org/tactics/TA0003/ +* Technique: +** Name: Boot or Logon Autostart Execution +** ID: T1547 +** Reference URL: https://attack.mitre.org/techniques/T1547/ +* Technique: +** Name: Create or Modify System Process +** ID: T1543 +** Reference URL: https://attack.mitre.org/techniques/T1543/ +* Sub-technique: +** Name: Launch Agent +** ID: T1543.001 +** Reference URL: https://attack.mitre.org/techniques/T1543/001/ +* Sub-technique: +** Name: Launch Daemon +** ID: T1543.004 +** Reference URL: https://attack.mitre.org/techniques/T1543/004/ +* Tactic: +** Name: Defense Evasion +** ID: TA0005 +** Reference URL: https://attack.mitre.org/tactics/TA0005/ +* Technique: +** Name: Plist File Modification +** ID: T1647 +** Reference URL: https://attack.mitre.org/techniques/T1647/ diff --git a/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-potential-destructive-aws-cli-command-executed-by-genai-agent.asciidoc b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-potential-destructive-aws-cli-command-executed-by-genai-agent.asciidoc new file mode 100644 index 0000000000..c881e66936 --- /dev/null +++ b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-potential-destructive-aws-cli-command-executed-by-genai-agent.asciidoc @@ -0,0 +1,230 @@ +[[prebuilt-rule-8-19-37-potential-destructive-aws-cli-command-executed-by-genai-agent]] +=== Potential Destructive AWS CLI Command Executed by GenAI Agent + +Identifies a cloud CLI command that destroys infrastructure or identities, such as terminating EC2 instances, removing S3 buckets, or deleting IAM users, when it is spawned by a GenAI coding agent directly or through the agent's shell wrapper. A compromised or prompt-injected agent can be steered into wiping the developer's environment and cloud account using the credentials it already holds, as seen in the malicious Amazon Q Developer for VS Code v1.84.0 release (AWS-2025-015). + +*Rule type*: query + +*Rule indices*: + +* logs-endpoint.events.process* + +*Severity*: high + +*Risk score*: 73 + +*Runs every*: 5m + +*Searches indices from*: now-9m ({ref}/common-options.html#date-math[Date Math format], see also <>) + +*Maximum alerts per execution*: 100 + +*References*: + +* https://aws.amazon.com/security/security-bulletins/AWS-2025-015/ +* https://github.com/aws/aws-toolkit-vscode/security/advisories/GHSA-7g7f-ff96-5gcw +* https://www.theregister.com/2025/07/24/amazon_q_ai_prompt/ +* https://www.pointguardai.com/blog/clean-to-factory-state-the-ai-prompt-that-nearly-wiped-aws-accounts + +*Tags*: + +* Domain: Endpoint +* Domain: Cloud +* Domain: GenAI +* Platform: AWS +* Platform: Linux +* Platform: macOS +* Platform: Windows +* Platform: Kubernetes +* OS: Linux +* OS: macOS +* OS: Windows +* Service: AWS EC2 +* Service: AWS S3 +* Service: AWS IAM +* Service: AWS RDS +* Service: AWS Lambda +* Tactic: Impact +* Tactic: Defense Evasion +* Data Source: Elastic Defend +* Rule Type: Custom Query (KQL) +* Resources: Investigation Guide +* Mitre Atlas: AML.T0053 +* Mitre Atlas: AML.T0101 + +*Version*: 3 + +*Rule authors*: + +* Elastic + +*Rule license*: Elastic License v2 + + +==== Investigation guide + + + +*Triage and analysis* + + + +*Investigating Potential Destructive AWS CLI Command Executed by GenAI Agent* + + +This rule detects a GenAI coding agent spawning a cloud CLI command that destroys infrastructure or identities. A compromised or prompt-injected agent can be steered into wiping the developer's AWS account without any separate credential theft step, since the agent already holds the developer's credentials. The malicious Amazon Q Developer pull request in July 2025 (AWS-2025-015) is the canonical real-world example of this attack pattern. + + +*Possible investigation steps* + + +- Identify the GenAI agent parent process and determine whether it was running in an autonomous or interactive mode at the time of the alert. +- Review the full CLI command arguments to assess the scope of the destruction (resource IDs, `--recursive` flags, etc.). +- Check for a preceding unusual or injected prompt in the agent's context, such as content from a recently cloned repository, an opened file, or a web fetch result. +- Query AWS CloudTrail for the corresponding API call and confirm whether the destructive action was actually executed or was blocked. +- Determine if the user initiated the teardown intentionally or if it was triggered autonomously. + + +*False positive analysis* + + +- Authorized infrastructure teardown automation invoked through a GenAI interface may legitimately trigger this rule. Correlate with change management records and known deployment pipeline identities before escalating. +- Developers who explicitly instruct a GenAI agent to clean up development environments will generate alerts for legitimate use. + + +*Response and remediation* + + +- Initiate the incident response process based on the outcome of the triage. +- If the destructive command executed, immediately assess which resources were deleted and begin recovery from backups or infrastructure-as-code. +- Revoke the developer's AWS credentials and rotate them after confirming the scope of the compromise. +- Review the agent's recent conversation history and any external content it processed to identify the prompt injection source. +- Apply IAM permission boundaries on developer credentials to restrict the blast radius of future incidents. + + +==== Setup + + + +*Setup* + + +This rule requires data coming in from Elastic Defend. + + +*Elastic Defend Integration Setup* + +Elastic Defend is integrated into the Elastic Agent using Fleet. Upon configuration, the integration allows the +Elastic Agent to monitor events on your host and send data to the Elastic Security app. + + +*Prerequisite Requirements:* + +- Fleet is required for Elastic Defend. +- To configure Fleet Server refer to the https://www.elastic.co/guide/en/fleet/current/fleet-server.html[documentation]. + + +*The following steps should be executed in order to add the Elastic Defend integration:* + +- Go to the Kibana home page and click "Add integrations". +- In the query bar, search for "Elastic Defend" and select the integration to see more details about it. +- Click "Add Elastic Defend". +- Configure the integration name and optionally add a description. +- Select the type of environment you want to protect, either "Traditional Endpoints" or "Cloud Workloads". +- Enter a name for the agent policy in "New agent policy name". If other agent policies already exist, you can + click the "Existing hosts" tab and select an existing policy instead. +- Click "Save and Continue". +- To complete the integration, select "Add Elastic Agent to your hosts" and install Elastic Agent on your hosts. +For more details on Elastic Defend refer to the https://www.elastic.co/guide/en/security/current/install-endpoint.html[helper guide]. + + +==== Rule query + + +[source, js] +---------------------------------- +event.category : "process" and event.type : "start" and event.action : (start or exec) and +( + process.parent.name : ( + qterm or qterm.exe or qchat or qchat.exe or + kiro or "kiro-cli" or "kiro-cli-chat" or "kiro-cli-term" or + kiro.exe or "kiro-cli.exe" or "kiro-cli-chat.exe" or "kiro-cli-term.exe" or + claude or "claude-bin" or claude.exe or codex or codex.exe or + copilot or copilot.exe or cursor or cursor.exe or "Cursor Helper (Plugin)" or "Cursor Helper" or + "gemini-cli" or "gemini-cli.exe" or windsurf or windsurf.exe or + aider or aider.exe or cline or goose or goose.exe or opencode or opencode.exe + ) or + process.parent.executable : ( + */.local/bin/q or */usr/local/bin/q or + *\\Users\\*\\AppData\\Local\\Programs\\Amazon Q\\q.exe or + *\\Users\\*\\AppData\\Local\\Programs\\Amazon Q\\*\\q.exe or + *\\Program Files\\Amazon Q\\q.exe or + *\\Program Files\\Amazon Q\\*\\q.exe + ) or + ( + process.parent.name : (bash or zsh or sh or dash or cmd.exe or powershell.exe or pwsh or pwsh.exe) and + process.parent.command_line : ( + */.claude/shell-snapshots/* or *\\.claude\\shell-snapshots\\* or + */.codex/* or *\\.codex\\* or + */.kiro/* or *\\.kiro\\* or + */.aws/amazonq/* or *\\.aws\\amazonq\\* or + */.goose/* or */.opencode/* or */.aider* + ) + ) +) and +( + ( + process.name : (aws or aws.exe) and + process.command_line : ( + *ec2 terminate-instances* or *ec2 delete-volume* or *ec2 delete-snapshot* or + *s3 rb* or *s3 rm*--recursive* or *s3api delete-bucket* or *s3api delete-objects* or + *iam delete-user* or *iam delete-role* or *iam delete-login-profile* or *iam delete-access-key* or + *rds delete-db-instance* or *rds delete-db-cluster* or *dynamodb delete-table* or + *efs delete-file-system* or *eks delete-cluster* or *ecs delete-cluster* or + *lambda delete-function* or *kms schedule-key-deletion* or + *cloudformation delete-stack* or + *cloudtrail delete-trail* or *cloudtrail stop-logging* or + *backup delete-recovery-point* or *organizations close-account* + ) + ) or + ( + process.name : (sam or sam.exe) and process.command_line : *sam delete* + ) or + ( + process.name : (terraform or terraform.exe or tofu or tofu.exe) and + process.command_line : *destroy*-auto-approve* + ) or + ( + process.name : (kubectl or kubectl.exe) and + process.command_line : (*delete*--all* or *delete namespace* or *delete ns*) + ) +) and not process.args : ("--dry-run*" or "--help*" or "-help*" or "-h" or "help" or "--version*") + +---------------------------------- + +*Framework*: MITRE ATT&CK^TM^ + +* Tactic: +** Name: Impact +** ID: TA0040 +** Reference URL: https://attack.mitre.org/tactics/TA0040/ +* Technique: +** Name: Data Destruction +** ID: T1485 +** Reference URL: https://attack.mitre.org/techniques/T1485/ +* Technique: +** Name: Account Access Removal +** ID: T1531 +** Reference URL: https://attack.mitre.org/techniques/T1531/ +* Tactic: +** Name: Defense Evasion +** ID: TA0005 +** Reference URL: https://attack.mitre.org/tactics/TA0005/ +* Technique: +** Name: Impair Defenses +** ID: T1562 +** Reference URL: https://attack.mitre.org/techniques/T1562/ +* Sub-technique: +** Name: Disable or Modify Cloud Logs +** ID: T1562.008 +** Reference URL: https://attack.mitre.org/techniques/T1562/008/ diff --git a/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-potential-low-packet-port-scan-detected.asciidoc b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-potential-low-packet-port-scan-detected.asciidoc new file mode 100644 index 0000000000..51773c7142 --- /dev/null +++ b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-potential-low-packet-port-scan-detected.asciidoc @@ -0,0 +1,182 @@ +[[prebuilt-rule-8-19-37-potential-low-packet-port-scan-detected]] +=== Potential Low-Packet Port Scan Detected + +This rule identifies a potential low-packet port scan. It detects final flows or firewall connection attempts from one internal source to many destination ports on one destination and transport, while requiring no more than two packets in each matching observation. Attackers can use low-packet scans to identify exposed services while minimizing completed connections. Low packet count is a scan heuristic and does not by itself prove that the traffic contains bare TCP SYN packets. + +*Rule type*: threshold + +*Rule indices*: + +* logs-network_traffic.* +* packetbeat-* +* filebeat-* +* logs-panw.panos* + +*Severity*: low + +*Risk score*: 21 + +*Runs every*: 5m + +*Searches indices from*: now-9m ({ref}/common-options.html#date-math[Date Math format], see also <>) + +*Maximum alerts per execution*: 5 + +*References*: None + +*Tags*: + +* Domain: Network +* Tactic: Discovery +* Tactic: Reconnaissance +* Use Case: Network Security Monitoring +* Data Source: PAN-OS +* Resources: Investigation Guide +* Noise: High +* Performance: Normal +* Profile: Aggressive +* Rule Type: Threshold +* Data Source: Network Packet Capture + +*Version*: 17 + +*Rule authors*: + +* Elastic + +*Rule license*: Elastic License v2 + + +==== Investigation guide + + + +*Triage and analysis* + + +> **Disclaimer**: +> This investigation guide was created using generative AI technology and has been reviewed to improve its accuracy and relevance. While every effort has been made to ensure its quality, we recommend validating the content and adapting it to suit your specific environment and operational needs. + + +*Investigating Potential Low-Packet Port Scan Detected* + + +Low-packet port scanning is a reconnaissance technique where an actor probes many ports while completing little or no +application exchange. This method helps adversaries identify exposed services for potential exploitation. The rule +flags final flows or firewall attempt records from an internal source to many ports on one destination and transport +when each observation contains no more than two packets. The heuristic does not verify TCP SYN flags. + + +*Possible investigation steps* + + +- Review the source IP address involved in the alert to determine if it belongs to a known or authorized scanner. Check for any recent changes or unusual activity associated with this IP. +- Analyze the destination ports targeted by the scan to identify any patterns or specific services that may be of interest to the attacker. Determine if these ports are associated with critical or vulnerable services. +- Review `network.transport` and raw flow or firewall records. For TCP, inspect TCP flags or connection state from another source before classifying the activity as a SYN scan. +- Examine historical logs to identify any previous scanning activity from the same source IP or similar patterns of behavior. This can help establish whether the activity is part of a larger reconnaissance effort. +- Correlate the alert with other security events or alerts to assess if there is a broader attack campaign underway. Look for related alerts that might indicate subsequent exploitation attempts. +- Investigate the timing and frequency of the scan attempts to understand if they coincide with other suspicious activities or known attack windows. This can provide context on the attacker's intent and urgency. +- Assess the network's current security posture and ensure that appropriate defenses, such as firewalls and intrusion detection systems, are configured to mitigate potential exploitation of identified open ports. + + +*False positive analysis* + + +- Internal network scanning tools or scripts used by IT teams for legitimate network mapping can trigger this rule. To manage this, create exceptions for known internal IP addresses or subnets used by IT for network discovery. +- Automated monitoring systems or security appliances that perform regular port checks might be flagged. Identify these systems and exclude their IP addresses from the rule to prevent false positives. +- Software updates or patch management systems that check multiple ports for service availability can be mistaken for a low-packet port scan. Add exceptions for these systems after validation. +- Load balancers or network devices that perform health checks across multiple ports may trigger the rule. Exclude these devices from the rule to ensure accurate detection. +- Development or testing environments where multiple port scans are part of routine operations can cause false positives. Implement exceptions for these environments to maintain focus on genuine threats. + + +*Response and remediation* + + +- Isolate the affected internal IP address to prevent further reconnaissance or potential exploitation of identified open ports. +- Conduct a thorough review of firewall and network access control lists to ensure that only necessary ports are open and accessible from internal networks. +- Implement appropriate connection-attempt rate limits or access controls to reduce unauthorized scanning. +- Monitor the network for any unusual outbound traffic from the affected IP address, which may indicate further malicious activity or data exfiltration attempts. +- Escalate the incident to the security operations team for further analysis and to determine if additional network segments or systems are affected. +- Update intrusion detection and prevention systems to enhance detection capabilities for similar low-packet scanning activity. +- Review and update network segmentation policies to limit the exposure of critical services and systems to internal reconnaissance activities. + +==== Setup + + + +*Setup* + + +This rule supports final flow records from the Elastic Network Packet Capture integration and PAN-OS traffic attempt +records. It also retains a compatibility branch for standalone Packetbeat. + +Network Packet Capture 2.0.0 and later always applies ECS compatibility remapping. On earlier integration versions, +enable `map_to_ecs` (the default since 1.31.1) so completed flows contain +`data_stream.dataset:network_traffic.flow`, `event.action:network_flow`, and +`network_traffic.flow.final:true`. The standalone Packetbeat branch uses the root `flow.final` field and requires +`type:flow`. + +This rule requires cumulative lifetime flow counters. For standalone Packetbeat, configure +`packetbeat.flows.enable_delta_flow_reports: false`. Network Packet Capture package 1.34.3 does not expose that setting +in its Fleet policy template and uses cumulative reports by default; verify the deployed package and agent version +before relying on the rule. Delta flow reporting is unsupported because a final delta can contain zero or few packets +even when the complete connection transferred many packets. + +For PAN-OS, ingest TRAFFIC records through the PAN-OS integration. The rule counts session starts and does not include +terminated, dropped, or denied flows. + +The rule evaluates TCP and UDP separately. The `network.packets <= 2` condition identifies low-packet observations but +is not TCP-flag evidence. Create exceptions for approved scanners and monitoring infrastructure after validation. + + +==== Rule query + + +[source, js] +---------------------------------- +( + ( + data_stream.dataset:network_traffic.flow and + event.action:network_flow and + network_traffic.flow.final:true + ) or + ( + type:flow and + event.action:network_flow and + flow.final:true + ) or + ( + (data_stream.dataset:panw.panos or event.dataset:panw.panos) and + panw.panos.type:TRAFFIC and + event.action:flow_started + ) +) and +destination.port:* and +network.transport:(tcp or udp) and +network.packets <= 2 and +source.ip:(10.0.0.0/8 or 172.16.0.0/12 or 192.168.0.0/16) + +---------------------------------- + +*Framework*: MITRE ATT&CK^TM^ + +* Tactic: +** Name: Discovery +** ID: TA0007 +** Reference URL: https://attack.mitre.org/tactics/TA0007/ +* Technique: +** Name: Network Service Discovery +** ID: T1046 +** Reference URL: https://attack.mitre.org/techniques/T1046/ +* Tactic: +** Name: Reconnaissance +** ID: TA0043 +** Reference URL: https://attack.mitre.org/tactics/TA0043/ +* Technique: +** Name: Active Scanning +** ID: T1595 +** Reference URL: https://attack.mitre.org/techniques/T1595/ +* Sub-technique: +** Name: Scanning IP Blocks +** ID: T1595.001 +** Reference URL: https://attack.mitre.org/techniques/T1595/001/ diff --git a/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-potential-network-scan-detected.asciidoc b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-potential-network-scan-detected.asciidoc new file mode 100644 index 0000000000..356a3b2df4 --- /dev/null +++ b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-potential-network-scan-detected.asciidoc @@ -0,0 +1,184 @@ +[[prebuilt-rule-8-19-37-potential-network-scan-detected]] +=== Potential Network Scan Detected + +This rule identifies a potential port scan from an internal IP address. A port scan is a method utilized by attackers to systematically scan a target system for open ports, allowing them to identify available services and potential vulnerabilities. By mapping out the open ports, attackers can gather critical information to plan and execute targeted attacks, gaining unauthorized access, compromising security, and potentially leading to data breaches, unauthorized control, or further exploitation of the targeted system. This rule defines a threshold-based approach to detect connection attempts from a single internal source to a wide range of destination ports on a single destination. + +*Rule type*: esql + +*Rule indices*: None + +*Severity*: low + +*Risk score*: 21 + +*Runs every*: 5m + +*Searches indices from*: now-9m ({ref}/common-options.html#date-math[Date Math format], see also <>) + +*Maximum alerts per execution*: 5 + +*References*: None + +*Tags*: + +* Domain: Network +* Tactic: Discovery +* Tactic: Reconnaissance +* Use Case: Network Security Monitoring +* Data Source: PAN-OS +* Resources: Investigation Guide +* Noise: High +* Performance: Normal +* Profile: Aggressive +* Rule Type: ES|QL +* Data Source: Network Packet Capture + +*Version*: 18 + +*Rule authors*: + +* Elastic + +*Rule license*: Elastic License v2 + + +==== Investigation guide + + + +*Triage and analysis* + + +> **Disclaimer**: +> This investigation guide was created using generative AI technology and has been reviewed to improve its accuracy and relevance. While every effort has been made to ensure its quality, we recommend validating the content and adapting it to suit your specific environment and operational needs. + + +*Investigating Potential Network Scan Detected* + + +Network scanning is a technique used to identify open ports and services on a network, often exploited by attackers to find vulnerabilities. Adversaries may use this method to map out a network's structure and identify weak points for further exploitation. The detection rule identifies suspicious activity by monitoring for multiple connection attempts from a single source to numerous destination ports, indicating a potential scan. This helps in early detection and mitigation of reconnaissance activities. + + +*Possible investigation steps* + + +- Review the source IP address involved in the alert to determine if it belongs to a known or trusted entity within the organization. Check if the IP falls within the specified ranges: 10.0.0.0/8, 172.16.0.0/12, or 192.168.0.0/16. +- Analyze the network flow logs to identify the specific destination ports that were targeted by the source IP. Determine if these ports are associated with critical services or known vulnerabilities. +- Correlate the detected activity with any recent changes or updates in the network infrastructure that might explain the scanning behavior, such as new devices or services being deployed. +- Investigate if there are any other alerts or logs indicating similar scanning activities from the same source IP or other IPs within the same subnet, which might suggest a coordinated scanning effort. +- Check for any historical data or past incidents involving the source IP to assess if this behavior is part of a recurring pattern or a new anomaly. +- Consult with network administrators to verify if the detected activity aligns with any scheduled network assessments or security tests that might have been conducted without prior notification. + + +*False positive analysis* + + +- Internal network scanning tools used for legitimate security assessments can trigger this rule. To manage this, create exceptions for known IP addresses of authorized scanning tools. +- Automated network monitoring systems that check service availability across multiple ports may be flagged. Exclude these systems by identifying their IP addresses and adding them to an exception list. +- Load balancers and network devices that perform health checks on various services might cause false positives. Identify these devices and configure the rule to ignore their IP addresses. +- Development and testing environments where frequent port scanning is part of routine operations can be mistakenly flagged. Implement exceptions for these environments by specifying their IP ranges. +- Regularly scheduled vulnerability assessments conducted by internal security teams can appear as network scans. Document these activities and exclude the associated IPs from triggering the rule. + + +*Response and remediation* + + +- Isolate the affected host: Immediately disconnect the source IP from the network to prevent further scanning or potential exploitation of identified vulnerabilities. +- Conduct a thorough investigation: Analyze the source IP's activity logs to determine if any unauthorized access or data exfiltration has occurred. This will help assess the extent of the threat. +- Update firewall rules: Implement stricter access controls to limit the number of open ports and restrict unnecessary inbound and outbound traffic from the affected IP range. +- Patch and update systems: Ensure all systems and services identified during the scan are up-to-date with the latest security patches to mitigate known vulnerabilities. +- Monitor for recurrence: Set up enhanced monitoring for the source IP and similar scanning patterns to quickly detect and respond to any future scanning attempts. +- Escalate to security operations: If the scan is part of a larger attack or if sensitive data is at risk, escalate the incident to the security operations team for further analysis and response. +- Review and enhance detection capabilities: Evaluate the effectiveness of current detection mechanisms and consider integrating additional threat intelligence sources to improve early detection of similar threats. + +==== Setup + + + +*Setup* + + +This rule supports connection observations from the Elastic Network Packet Capture integration, PAN-OS TRAFFIC +session-start records, and a compatibility branch for standalone Packetbeat. + +Network Packet Capture 2.0.0 and later always applies ECS compatibility remapping. On earlier integration versions, +enable `map_to_ecs` (the default since 1.31.1). The rule counts interim and final flow reports that emit +`event.action:network_flow` and include `connection` in `event.type`. The standalone Packetbeat branch requires +`agent.type:packetbeat` with the same ECS action and type values; verify that branch against the deployed Packetbeat +version and configuration before relying on it. + +For PAN-OS, ingest TRAFFIC records through the PAN-OS integration. The rule counts session starts. + +The rule evaluates TCP and UDP separately. Repeated lifecycle reports for one source/destination/port tuple do not +increase distinct-port cardinality within a one-minute bucket. Reports in later buckets can qualify again; one-hour +alert suppression groups repeated alerts by source, destination, and transport. Create exceptions for approved +scanners, inventory systems, and monitoring infrastructure after validating their source addresses. + + +==== Rule query + + +[source, js] +---------------------------------- +from logs-network_traffic.flow-*, packetbeat-*, logs-panw.panos* +| mv_expand event.action +| mv_expand event.type +| where + ( + ( + event.action == "network_flow" + and event.type == "connection" + and ( + data_stream.dataset == "network_traffic.flow" + or agent.type == "packetbeat" + ) + ) + or ( + event.action == "flow_started" + and event.type == "connection" + and ( + data_stream.dataset == "panw.panos" + or event.dataset == "panw.panos" + ) + ) + ) + and destination.port is not null + and source.ip is not null + and destination.ip is not null + and network.transport in ("tcp", "udp") +| eval Esql.time_window = DATE_TRUNC(1min, @timestamp) +| where CIDR_MATCH(source.ip, "10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16") +| eval sensitive_port = case(destination.port IN (21, 22, 23, 53, 88, 139, 389, 445, 3389, 5900, 5985, 5986, 9389), true, false) +| stats + Esql.count_distinct_destination_ports = COUNT_DISTINCT(destination.port), + Esql.count_distinct_sensitive_ports = COUNT_DISTINCT(destination.port) where sensitive_port == true, + Esql.values_destination_ports = VALUES(destination.port), + Esql.values_sensitive_ports = VALUES(destination.port) where sensitive_port == true + by Esql.time_window, destination.ip, source.ip, network.transport +| where (Esql.count_distinct_destination_ports >= 50 or Esql.count_distinct_sensitive_ports >= 5) +| keep source.ip, destination.ip, network.transport, Esql.* + +---------------------------------- + +*Framework*: MITRE ATT&CK^TM^ + +* Tactic: +** Name: Discovery +** ID: TA0007 +** Reference URL: https://attack.mitre.org/tactics/TA0007/ +* Technique: +** Name: Network Service Discovery +** ID: T1046 +** Reference URL: https://attack.mitre.org/techniques/T1046/ +* Tactic: +** Name: Reconnaissance +** ID: TA0043 +** Reference URL: https://attack.mitre.org/tactics/TA0043/ +* Technique: +** Name: Active Scanning +** ID: T1595 +** Reference URL: https://attack.mitre.org/techniques/T1595/ +* Sub-technique: +** Name: Scanning IP Blocks +** ID: T1595.001 +** Reference URL: https://attack.mitre.org/techniques/T1595/001/ diff --git a/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-potential-network-sweep-detected.asciidoc b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-potential-network-sweep-detected.asciidoc new file mode 100644 index 0000000000..bc065ebe2b --- /dev/null +++ b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-potential-network-sweep-detected.asciidoc @@ -0,0 +1,182 @@ +[[prebuilt-rule-8-19-37-potential-network-sweep-detected]] +=== Potential Network Sweep Detected + +This rule identifies a potential network sweep. A network sweep is a method used by attackers to scan a target network, identifying active hosts, open ports, and available services to gather information on vulnerabilities and weaknesses. This reconnaissance helps them plan subsequent attacks and exploit potential entry points for unauthorized access, data theft, or other malicious activities. This rule defines a threshold-based approach to detect multiple connection attempts from a single host to numerous destination hosts over commonly used network services. + +*Rule type*: threshold + +*Rule indices*: + +* packetbeat-* +* filebeat-* +* logs-network_traffic.* +* logs-panw.panos* + +*Severity*: low + +*Risk score*: 21 + +*Runs every*: 5m + +*Searches indices from*: now-9m ({ref}/common-options.html#date-math[Date Math format], see also <>) + +*Maximum alerts per execution*: 5 + +*References*: None + +*Tags*: + +* Domain: Network +* Tactic: Discovery +* Tactic: Reconnaissance +* Use Case: Network Security Monitoring +* Data Source: PAN-OS +* Resources: Investigation Guide +* Noise: High +* Performance: Normal +* Profile: Aggressive +* Rule Type: Threshold +* Data Source: Network Packet Capture + +*Version*: 17 + +*Rule authors*: + +* Elastic + +*Rule license*: Elastic License v2 + + +==== Investigation guide + + + +*Triage and analysis* + + +> **Disclaimer**: +> This investigation guide was created using generative AI technology and has been reviewed to improve its accuracy and relevance. While every effort has been made to ensure its quality, we recommend validating the content and adapting it to suit your specific environment and operational needs. + + +*Investigating Potential Network Sweep Detected* + + +Network sweeps are reconnaissance techniques where attackers scan networks to identify active hosts and services, often targeting common ports. This activity helps adversaries map out network vulnerabilities for future exploitation. The detection rule identifies such sweeps by monitoring connection attempts from a single source to multiple destinations on key ports, flagging potential reconnaissance activities for further investigation. + + +*Possible investigation steps* + + +- Review the source IP address to determine if it belongs to a known or trusted entity within the network, focusing on the private IP ranges specified in the query (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16). +- Analyze the destination IP addresses to identify any patterns or commonalities, such as specific subnets or devices, that could indicate targeted reconnaissance. +- Check historical logs for previous connection attempts from the same source IP to see if there is a pattern of repeated scanning behavior or if this is an isolated incident. +- Investigate the specific ports targeted (21, 22, 23, 25, 139, 445, 3389, 5985, 5986) to determine if they are associated with critical services or known vulnerabilities within the network. +- Correlate the detected activity with any recent changes or incidents in the network environment that might explain the behavior, such as new device deployments or configuration changes. +- Consult threat intelligence sources to determine if the source IP or similar scanning patterns have been associated with known threat actors or campaigns. + + +*False positive analysis* + + +- Internal network scans by IT teams can trigger the rule. Regularly scheduled scans for security assessments should be documented and their source IPs added to an exception list to prevent false alerts. +- Automated monitoring tools that check network health might cause false positives. Identify these tools and exclude their IP addresses from the rule to avoid unnecessary alerts. +- Load balancers or network devices that perform health checks across multiple hosts can be mistaken for network sweeps. Exclude these devices by adding their IPs to a whitelist. +- Development or testing environments where multiple connections are made for legitimate purposes can trigger the rule. Ensure these environments are recognized and their IP ranges are excluded from monitoring. +- Misconfigured devices that repeatedly attempt to connect to multiple hosts can appear as network sweeps. Investigate and correct the configuration, then exclude these devices if necessary. + + +*Response and remediation* + + +- Isolate the source IP: Immediately isolate the source IP address identified in the alert from the network to prevent further reconnaissance or potential exploitation of identified vulnerabilities. + +- Block suspicious ports: Implement firewall rules to block incoming and outgoing traffic on the commonly targeted ports (21, 22, 23, 25, 139, 445, 3389, 5985, 5986) from the source IP to mitigate further scanning attempts. + +- Conduct a network-wide scan: Perform a comprehensive scan of the network to identify any unauthorized access or changes that may have occurred as a result of the network sweep. + +- Review and update access controls: Ensure that access controls and permissions are appropriately configured to limit exposure of critical services and sensitive data. + +- Monitor for recurrence: Set up enhanced monitoring and alerting for any future connection attempts from the source IP or similar patterns of network sweep activity. + +- Escalate to security operations: Notify the security operations team to conduct a deeper investigation into the source of the network sweep and assess any potential threats or breaches. + +- Document and report: Record all findings, actions taken, and lessons learned in an incident report to inform future response strategies and improve network defenses. + +==== Setup + + + +*Setup* + + +This rule supports connection observations from the Elastic Network Packet Capture integration, PAN-OS TRAFFIC +session-start records, and a compatibility branch for standalone Packetbeat. + +Network Packet Capture 2.0.0 and later always applies ECS compatibility remapping. On earlier integration versions, +enable `map_to_ecs` (the default since 1.31.1). The rule counts interim and final flow reports with +`data_stream.dataset:network_traffic.flow`, `event.action:network_flow`, and `event.type:connection`. The standalone +Packetbeat branch requires `type:flow` with the same ECS action and type values; verify that branch against the deployed +Packetbeat version and configuration before relying on it. + +For PAN-OS, ingest TRAFFIC records through the PAN-OS integration. The rule counts session starts. + +The threshold intentionally counts destinations across the selected service ports and transports for each source. This +preserves mixed-port host-sweep coverage. Repeated lifecycle reports for one source/destination pair do not increase +distinct-destination cardinality within one execution window, but reports in later windows can produce repeated +alerts. Create exceptions for approved scanners, inventory systems, and monitoring infrastructure after validating +their source addresses. + + +==== Rule query + + +[source, js] +---------------------------------- +( + ( + data_stream.dataset:network_traffic.flow and + event.action:network_flow and + event.type:connection + ) or + ( + type:flow and + event.action:network_flow and + event.type:connection + ) or + ( + (data_stream.dataset:panw.panos or event.dataset:panw.panos) and + panw.panos.type:TRAFFIC and + event.action:flow_started + ) +) and +destination.port:(21 or 22 or 23 or 25 or 139 or 445 or 3389 or 5985 or 5986) and +source.ip:(10.0.0.0/8 or 172.16.0.0/12 or 192.168.0.0/16) + +---------------------------------- + +*Framework*: MITRE ATT&CK^TM^ + +* Tactic: +** Name: Discovery +** ID: TA0007 +** Reference URL: https://attack.mitre.org/tactics/TA0007/ +* Technique: +** Name: Remote System Discovery +** ID: T1018 +** Reference URL: https://attack.mitre.org/techniques/T1018/ +* Technique: +** Name: Network Service Discovery +** ID: T1046 +** Reference URL: https://attack.mitre.org/techniques/T1046/ +* Tactic: +** Name: Reconnaissance +** ID: TA0043 +** Reference URL: https://attack.mitre.org/tactics/TA0043/ +* Technique: +** Name: Active Scanning +** ID: T1595 +** Reference URL: https://attack.mitre.org/techniques/T1595/ +* Sub-technique: +** Name: Scanning IP Blocks +** ID: T1595.001 +** Reference URL: https://attack.mitre.org/techniques/T1595/001/ diff --git a/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-potential-persistence-via-login-hook.asciidoc b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-potential-persistence-via-login-hook.asciidoc new file mode 100644 index 0000000000..1b467d457c --- /dev/null +++ b/docs/detections/prebuilt-rules/downloadable-packages/8-19-37/prebuilt-rule-8-19-37-potential-persistence-via-login-hook.asciidoc @@ -0,0 +1,169 @@ +[[prebuilt-rule-8-19-37-potential-persistence-via-login-hook]] +=== Potential Persistence via Login Hook + +Identifies the creation or modification of the login window property list (plist). Adversaries may modify plist files to run a program during system boot or user login for persistence. + +*Rule type*: query + +*Rule indices*: + +* logs-endpoint.events.* + +*Severity*: medium + +*Risk score*: 47 + +*Runs every*: 5m + +*Searches indices from*: now-9m ({ref}/common-options.html#date-math[Date Math format], see also <>) + +*Maximum alerts per execution*: 100 + +*References*: + +* https://github.com/D00MFist/PersistentJXA/blob/master/LoginScript.js + +*Tags*: + +* Domain: Endpoint +* OS: macOS +* Use Case: Threat Detection +* Tactic: Persistence +* Data Source: Elastic Defend +* Resources: Investigation Guide +* Noise: High +* Performance: Normal +* Profile: Aggressive +* Rule Type: Custom Query (KQL) +* Platform: macOS + +*Version*: 115 + +*Rule authors*: + +* Elastic + +*Rule license*: Elastic License v2 + + +==== Investigation guide + + + +*Triage and analysis* + + +> **Disclaimer**: +> This investigation guide was created using generative AI technology and has been reviewed to improve its accuracy and relevance. While every effort has been made to ensure its quality, we recommend validating the content and adapting it to suit your specific environment and operational needs. + + +*Investigating Potential Persistence via Login Hook* + + +The `com.apple.loginwindow` preferences domain controls login window behavior. It supports the deprecated `LoginHook` and `LogoutHook` keys, which run a script as root each time a user logs in or out. Hooks are typically set with `sudo defaults write com.apple.loginwindow LoginHook