Generate ATT&CK navigator layer files and links (#1787)

* Generate attack layer files and build with package
* add update-navigator-gists command
* add workflow to update navigator gists on pushes to main
* Add coverage readme
* fix keys for links
* update navigator layer names
* purge gist files prior to update; add badge
* Update how the navigator links are displayed
* moved navigator code to dedicated and refactored to dataclasses
* convert gist links to permalink versions
* alphabetize; catch 404 for gist update
This commit is contained in:
Justin Ibarra
2022-03-04 08:20:44 -09:00
committed by GitHub
parent a6582351b5
commit 254b4eb23f
12 changed files with 509 additions and 8 deletions
+5
View File
@@ -49,3 +49,8 @@ jobs:
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
+1 -1
View File
@@ -23,7 +23,7 @@ jobs:
uses: actions/github-script@v3
with:
script: |
if ('refs/heads/main' === '${{github.event.ref}}') {
if ('refs/heads/main' === '${{github.ref}}') {
core.setFailed('Forbidden branch')
}
+1
View File
@@ -1,6 +1,7 @@
[![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
+2
View File
@@ -18,6 +18,7 @@ from . import ( # noqa: E402
mappings,
ml,
misc,
navigator,
rule_formatter,
rule_loader,
schemas,
@@ -34,6 +35,7 @@ __all__ = (
"main",
'misc',
'ml',
'navigator',
'rule_formatter',
'rule_loader',
'schemas',
+6
View File
@@ -33,7 +33,13 @@ def get_attack_file_path() -> str:
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()))
+71 -2
View File
@@ -14,10 +14,12 @@ 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
@@ -26,10 +28,10 @@ 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
from .ghwrap import GithubClient, update_gist
from .main import root
from .misc import PYTHON_LICENSE, add_client, client_error
from .packaging import PACKAGE_FILE, Package, RELEASE_DIR, current_stack_version
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
@@ -39,6 +41,11 @@ 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]:
@@ -739,6 +746,68 @@ def update_schemas():
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."""
+2 -1
View File
@@ -16,7 +16,7 @@ from typing import Dict, Iterable, Optional, Union
import json
import xlsxwriter
from .attack import technique_lookup, matrix, attack_tm, tactics
from .attack import attack_tm, matrix, tactics, technique_lookup
from .packaging import Package
from .rule_loader import DeprecatedCollection, RuleCollection
from .rule import ThreatMapping, TOMLRule
@@ -220,6 +220,7 @@ class PackageDocument(xlsxwriter.Workbook):
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
+35
View File
@@ -19,6 +19,7 @@ from zipfile import ZipFile
import click
import requests
from requests import Response
from .schemas import definitions
@@ -98,6 +99,40 @@ def download_gh_asset(url: str, path: str, overwrite=False):
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."""
+2 -2
View File
@@ -59,8 +59,8 @@ class ClientError(click.ClickException):
def show(self, file=None, err=True):
"""Print the error to the console."""
err = 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()}'
# 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)
+287
View File
@@ -0,0 +1,287 @@
# 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
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
+15 -2
View File
@@ -13,12 +13,13 @@ import shutil
import textwrap
from collections import defaultdict
from pathlib import Path
from typing import Optional, Tuple
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
@@ -73,6 +74,9 @@ def load_current_package_version() -> str:
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."""
@@ -138,7 +142,7 @@ class Package(object):
with open(os.path.join(save_dir, 'index.ts'), 'wt') as f:
f.write('\n'.join(index_ts))
def save_release_files(self, directory, changed_rules, new_rules, removed_rules):
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:
@@ -146,6 +150,8 @@ class Package(object):
with open(os.path.join(directory, f'{self.name}-changelog-entry.md'), 'w') as f:
f.write(changelog)
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)
@@ -356,6 +362,13 @@ class Package(object):
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
+82
View File
@@ -0,0 +1,82 @@
# 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-*](https://mitre-attack.github.io/attack-navigator/#layerURL=https%3A%2F%2Fgist.githubusercontent.com%2Fbrokensound77%2F1a3f65224822a30a8228a8ed20289a89%2Fraw%2FElastic-detection-rules-indexes-auditbeat-%2A.json&leave_site_dialog=false&tabs=false)|
|[Elastic-detection-rules-indexes-filebeat-*](https://mitre-attack.github.io/attack-navigator/#layerURL=https%3A%2F%2Fgist.githubusercontent.com%2Fbrokensound77%2F1a3f65224822a30a8228a8ed20289a89%2Fraw%2FElastic-detection-rules-indexes-filebeat-%2A.json&leave_site_dialog=false&tabs=false)|
|[Elastic-detection-rules-indexes-logs-*](https://mitre-attack.github.io/attack-navigator/#layerURL=https%3A%2F%2Fgist.githubusercontent.com%2Fbrokensound77%2F1a3f65224822a30a8228a8ed20289a89%2Fraw%2FElastic-detection-rules-indexes-logs-%2A.json&leave_site_dialog=false&tabs=false)|
|[Elastic-detection-rules-indexes-logs-aws*](https://mitre-attack.github.io/attack-navigator/#layerURL=https%3A%2F%2Fgist.githubusercontent.com%2Fbrokensound77%2F1a3f65224822a30a8228a8ed20289a89%2Fraw%2FElastic-detection-rules-indexes-logs-aws%2A.json&leave_site_dialog=false&tabs=false)|
|[Elastic-detection-rules-indexes-logs-azure*](https://mitre-attack.github.io/attack-navigator/#layerURL=https%3A%2F%2Fgist.githubusercontent.com%2Fbrokensound77%2F1a3f65224822a30a8228a8ed20289a89%2Fraw%2FElastic-detection-rules-indexes-logs-azure%2A.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-gcp*](https://mitre-attack.github.io/attack-navigator/#layerURL=https%3A%2F%2Fgist.githubusercontent.com%2Fbrokensound77%2F1a3f65224822a30a8228a8ed20289a89%2Fraw%2FElastic-detection-rules-indexes-logs-gcp%2A.json&leave_site_dialog=false&tabs=false)|
|[Elastic-detection-rules-indexes-logs-google_workspace*](https://mitre-attack.github.io/attack-navigator/#layerURL=https%3A%2F%2Fgist.githubusercontent.com%2Fbrokensound77%2F1a3f65224822a30a8228a8ed20289a89%2Fraw%2FElastic-detection-rules-indexes-logs-google_workspace%2A.json&leave_site_dialog=false&tabs=false)|
|[Elastic-detection-rules-indexes-logs-o365*](https://mitre-attack.github.io/attack-navigator/#layerURL=https%3A%2F%2Fgist.githubusercontent.com%2Fbrokensound77%2F1a3f65224822a30a8228a8ed20289a89%2Fraw%2FElastic-detection-rules-indexes-logs-o365%2A.json&leave_site_dialog=false&tabs=false)|
|[Elastic-detection-rules-indexes-logs-okta*](https://mitre-attack.github.io/attack-navigator/#layerURL=https%3A%2F%2Fgist.githubusercontent.com%2Fbrokensound77%2F1a3f65224822a30a8228a8ed20289a89%2Fraw%2FElastic-detection-rules-indexes-logs-okta%2A.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-*](https://mitre-attack.github.io/attack-navigator/#layerURL=https%3A%2F%2Fgist.githubusercontent.com%2Fbrokensound77%2F1a3f65224822a30a8228a8ed20289a89%2Fraw%2FElastic-detection-rules-indexes-metrics-%2A.json&leave_site_dialog=false&tabs=false)|
|[Elastic-detection-rules-indexes-packetbeat-*](https://mitre-attack.github.io/attack-navigator/#layerURL=https%3A%2F%2Fgist.githubusercontent.com%2Fbrokensound77%2F1a3f65224822a30a8228a8ed20289a89%2Fraw%2FElastic-detection-rules-indexes-packetbeat-%2A.json&leave_site_dialog=false&tabs=false)|
|[Elastic-detection-rules-indexes-traces-*](https://mitre-attack.github.io/attack-navigator/#layerURL=https%3A%2F%2Fgist.githubusercontent.com%2Fbrokensound77%2F1a3f65224822a30a8228a8ed20289a89%2Fraw%2FElastic-detection-rules-indexes-traces-%2A.json&leave_site_dialog=false&tabs=false)|
|[Elastic-detection-rules-indexes-winlogbeat-*](https://mitre-attack.github.io/attack-navigator/#layerURL=https%3A%2F%2Fgist.githubusercontent.com%2Fbrokensound77%2F1a3f65224822a30a8228a8ed20289a89%2Fraw%2FElastic-detection-rules-indexes-winlogbeat-%2A.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-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)|