Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Format Checker for MITRE ATT&CK Matrix Report Mappings #1360

Merged
merged 4 commits into from
Sep 25, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 57 additions & 0 deletions .scripts/mitre_mapping_check.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
""" This script checks all the MITRE Mappings in the Reports section of each analysis item to
ensure they follow the formal TAXXXX:TXXXX. If MITRE mappings aren't in this format, they don't
display properly in Panther's UI. """

import re
import sys
from pathlib import Path

from panther_analysis_tool.analysis_utils import load_analysis_specs

# All MITRE Tags must match this regex pattern
MITRE_PATTERN = re.compile("^TA\d+\:T\d+(\.\d+)?$")

def main(path: Path) -> bool:
# Load Repo
analysis_items = load_analysis_specs([path], ignore_files=[])

items_with_invalid_mappings = [] # Record all items with bad tags
for analysis_item in analysis_items:
rel_path = analysis_item[0] # Relative path to YAML file
spec = analysis_item[2] # YAML spec as a dict

bad_tags = [] # Record the invalid tags for this analysis item
if reports := spec.get("Reports"):
if mitre := reports.get("MITRE ATT&CK"):
for mapping in mitre:
if not MITRE_PATTERN.match(mapping):
bad_tags.append(mapping)

if bad_tags:
items_with_invalid_mappings.append({
"rel_path": rel_path,
"bad_tags": bad_tags
})

if items_with_invalid_mappings:
print("❌ Some items had invalid MITRE mapping formats:")
print()
for invalid_item in items_with_invalid_mappings:
print(invalid_item.get("rel_path", "<UNKNOWN PATH>"))
for bad_tag in invalid_item.get("bad_tags", []):
print("\t" + bad_tag)
print()

print(("To ensure that your MITRE mappings are correctly displayed in the Panther "
"console, make sure your MITRE mappings are formatted like 'TA0000:T0000'."))
else:
print("✅ No invalid MITRE mappings found! You're in the clear! 👍")

return bool(items_with_invalid_mappings)

if __name__ == "__main__":
path = Path.cwd() # Default to current directory
if len(sys.argv) > 1:
path = Path(sys.argv[1])
if main(path):
exit(1) # Exit with error if issues were found
5 changes: 4 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ deps-update:
global-helpers-unit-test:
pipenv run python -m unittest global_helpers/*_test.py

lint: lint-pylint lint-fmt
lint: lint-pylint lint-fmt lint-misc

lint-pylint:
pipenv run bandit -r $(dirs)
Expand All @@ -43,6 +43,9 @@ lint-fmt:
@echo Checking python file formatting with the black code style checker
pipenv run black --line-length=100 --check $(dirs)

lint-misc:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not introducing lint-mitre and then introduce lint-misc whenever another "misc" linting is added in the future? And the lint-misc will be running the mitre lint and the newly introduced one.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That makes sense! In both cases, the MITRE check will run during make lint, so customers won't need to make any changes to their workflows

pipenv run python3 ./.scripts/mitre_mapping_check.py

venv:
pipenv sync --dev

Expand Down
Loading