From 9745ce92fe2898772006e374325a3afce6a1011b Mon Sep 17 00:00:00 2001 From: Jose Hernandez Date: Wed, 5 Mar 2025 13:27:02 -0800 Subject: [PATCH] updated mitre map gen --- contentctl/output/attack_nav_output.py | 15 +++-- contentctl/output/attack_nav_writer.py | 90 +++++++++++++++----------- 2 files changed, 64 insertions(+), 41 deletions(-) diff --git a/contentctl/output/attack_nav_output.py b/contentctl/output/attack_nav_output.py index 13076b51..61436fe7 100644 --- a/contentctl/output/attack_nav_output.py +++ b/contentctl/output/attack_nav_output.py @@ -1,5 +1,5 @@ -from typing import List, Union import pathlib +from typing import List, Union from contentctl.objects.detection import Detection from contentctl.output.attack_nav_writer import AttackNavWriter @@ -10,14 +10,21 @@ def writeObjects( self, detections: List[Detection], output_path: pathlib.Path ) -> None: techniques: dict[str, dict[str, Union[List[str], int]]] = {} + for detection in detections: for tactic in detection.tags.mitre_attack_id: if tactic not in techniques: techniques[tactic] = {"score": 0, "file_paths": []} - detection_url = f"https://github.com/splunk/security_content/blob/develop/detections/{detection.source}/{detection.file_path.name}" - techniques[tactic]["score"] += 1 - techniques[tactic]["file_paths"].append(detection_url) + detection_type = detection.source + detection_id = detection.id + + # Store all three pieces of information separately + detection_info = f"{detection_type}|{detection_id}|{detection.name}" + + techniques[tactic]["score"] = techniques[tactic].get("score", 0) + 1 + if isinstance(techniques[tactic]["file_paths"], list): + techniques[tactic]["file_paths"].append(detection_info) """ for detection in objects: diff --git a/contentctl/output/attack_nav_writer.py b/contentctl/output/attack_nav_writer.py index 7d7be94f..51c39e24 100644 --- a/contentctl/output/attack_nav_writer.py +++ b/contentctl/output/attack_nav_writer.py @@ -1,11 +1,11 @@ import json -from typing import Union, List import pathlib +from typing import List, Union -VERSION = "4.3" +VERSION = "4.5" NAME = "Detection Coverage" -DESCRIPTION = "security_content detection coverage" -DOMAIN = "mitre-enterprise" +DESCRIPTION = "Security Content Detection Coverage" +DOMAIN = "enterprise-attack" class AttackNavWriter: @@ -14,52 +14,68 @@ def writeAttackNavFile( mitre_techniques: dict[str, dict[str, Union[List[str], int]]], output_path: pathlib.Path, ) -> None: - max_count = 0 - for technique_id in mitre_techniques.keys(): - if mitre_techniques[technique_id]["score"] > max_count: - max_count = mitre_techniques[technique_id]["score"] + max_count = max( + (technique["score"] for technique in mitre_techniques.values()), default=0 + ) layer_json = { - "version": VERSION, + "versions": {"attack": "16", "navigator": "5.1.0", "layer": VERSION}, "name": NAME, "description": DESCRIPTION, "domain": DOMAIN, "techniques": [], + "gradient": { + "colors": ["#ffffff", "#66b1ff", "#096ed7"], + "minValue": 0, + "maxValue": max_count, + }, + "filters": { + "platforms": [ + "Windows", + "Linux", + "macOS", + "Network", + "AWS", + "GCP", + "Azure", + "Azure AD", + "Office 365", + "SaaS", + ] + }, + "layout": { + "layout": "side", + "showName": True, + "showID": True, + "showAggregateScores": False, + }, + "legendItems": [ + {"label": "No detections", "color": "#ffffff"}, + {"label": "Has detections", "color": "#66b1ff"}, + ], + "showTacticRowBackground": True, + "tacticRowBackground": "#dddddd", + "selectTechniquesAcrossTactics": True, } - layer_json["gradient"] = { - "colors": ["#ffffff", "#66b1ff", "#096ed7"], - "minValue": 0, - "maxValue": max_count, - } - - layer_json["filters"] = { - "platforms": [ - "Windows", - "Linux", - "macOS", - "AWS", - "GCP", - "Azure", - "Office 365", - "SaaS", - ] - } + for technique_id, data in mitre_techniques.items(): + links = [] + for detection_info in data["file_paths"]: + # Split the detection info into its components + detection_type, detection_id, detection_name = detection_info.split("|") - layer_json["legendItems"] = [ - {"label": "NO available detections", "color": "#ffffff"}, - {"label": "Some detections available", "color": "#66b1ff"}, - ] + # Construct research website URL (without the name) + research_url = ( + f"https://research.splunk.com/{detection_type}/{detection_id}/" + ) - layer_json["showTacticRowBackground"] = True - layer_json["tacticRowBackground"] = "#dddddd" - layer_json["sorting"] = 3 + links.append({"label": detection_name, "url": research_url}) - for technique_id in mitre_techniques.keys(): layer_technique = { "techniqueID": technique_id, - "score": mitre_techniques[technique_id]["score"], - "comment": "\n\n".join(mitre_techniques[technique_id]["file_paths"]), + "score": data["score"], + "enabled": True, + "links": links, } layer_json["techniques"].append(layer_technique)