From ff372fb170f9ae3bb32a2be1e3bded1e090d51f7 Mon Sep 17 00:00:00 2001 From: pyth0n1c Date: Tue, 4 Feb 2025 12:36:34 -0800 Subject: [PATCH 01/13] initial progress of group cleanup --- contentctl/objects/mitre_attack_enrichment.py | 25 ++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/contentctl/objects/mitre_attack_enrichment.py b/contentctl/objects/mitre_attack_enrichment.py index f915fcd7..082ad41f 100644 --- a/contentctl/objects/mitre_attack_enrichment.py +++ b/contentctl/objects/mitre_attack_enrichment.py @@ -1,8 +1,11 @@ from __future__ import annotations -from pydantic import BaseModel, Field, ConfigDict, HttpUrl, field_validator -from typing import List -from enum import StrEnum + import datetime +from enum import StrEnum +from typing import List + +from pydantic import BaseModel, ConfigDict, Field, HttpUrl, field_validator + from contentctl.objects.annotated_types import MITRE_ATTACK_ID_TYPE @@ -84,6 +87,13 @@ def standardize_contributors(cls, contributors: list[str] | None) -> list[str]: return [] return contributors + def __lt__(self, other: MitreAttackGroup) -> bool: + if not isinstance(object, MitreAttackGroup): + raise Exception( + f"Cannot compare object of type MitreAttackGroup to object of type [{type(object).__name__}]" + ) + return self.group < other.group + class MitreAttackEnrichment(BaseModel): ConfigDict(extra="forbid") @@ -96,3 +106,12 @@ class MitreAttackEnrichment(BaseModel): def __hash__(self) -> int: return id(self) + + @staticmethod + def getUniqueGroups(groups: list[MitreAttackGroup]) -> list[MitreAttackGroup]: + group_set: set[MitreAttackGroup] = set() + for group in groups: + g = set(group) + group_set.update(g) + + return sorted(group_set) From 07a92c11a453a9e32bb8c7b1e1be8589366a99d6 Mon Sep 17 00:00:00 2001 From: pyth0n1c Date: Tue, 4 Feb 2025 17:15:26 -0800 Subject: [PATCH 02/13] Initial support for vetter validation and uniqueness enforcement for groups and mitre tactics. The errors still are not high quality and will take some time to fix. --- contentctl/objects/annotated_types.py | 7 ++- contentctl/objects/detection_tags.py | 6 +++ contentctl/objects/mitre_attack_enrichment.py | 47 +++++++++++++++++-- contentctl/objects/story_tags.py | 11 +++-- 4 files changed, 59 insertions(+), 12 deletions(-) diff --git a/contentctl/objects/annotated_types.py b/contentctl/objects/annotated_types.py index f1291af5..1b81f773 100644 --- a/contentctl/objects/annotated_types.py +++ b/contentctl/objects/annotated_types.py @@ -1,6 +1,9 @@ -from pydantic import Field from typing import Annotated +from pydantic import Field + CVE_TYPE = Annotated[str, Field(pattern=r"^CVE-[1|2]\d{3}-\d+$")] -MITRE_ATTACK_ID_TYPE = Annotated[str, Field(pattern=r"^T\d{4}(.\d{3})?$")] +MITRE_ATTACK_ID_TYPE_PARENT = Annotated[str, Field(pattern=r"^T\d{4}$")] +MITRE_ATTACK_ID_TYPE_SUBTYPE = Annotated[str, Field(pattern=r"^T\d{4}(.\d{3})$")] +MITRE_ATTACK_ID_TYPE = MITRE_ATTACK_ID_TYPE_PARENT | MITRE_ATTACK_ID_TYPE_SUBTYPE APPID_TYPE = Annotated[str, Field(pattern="^[a-zA-Z0-9_-]+$")] diff --git a/contentctl/objects/detection_tags.py b/contentctl/objects/detection_tags.py index cfac4726..ceaa6974 100644 --- a/contentctl/objects/detection_tags.py +++ b/contentctl/objects/detection_tags.py @@ -135,6 +135,12 @@ def addAttackEnrichment(self, info: ValidationInfo): if len(missing_tactics) > 0: raise ValueError(f"Missing Mitre Attack IDs. {missing_tactics} not found.") else: + try: + MitreAttackEnrichment.checkParentTypeNotDefinedWhenSubtypeDefined( + mitre_enrichments + ) + except Exception as e: + raise ValueError(e) self.mitre_attack_enrichments = mitre_enrichments return self diff --git a/contentctl/objects/mitre_attack_enrichment.py b/contentctl/objects/mitre_attack_enrichment.py index 082ad41f..b77fbb24 100644 --- a/contentctl/objects/mitre_attack_enrichment.py +++ b/contentctl/objects/mitre_attack_enrichment.py @@ -108,10 +108,47 @@ def __hash__(self) -> int: return id(self) @staticmethod - def getUniqueGroups(groups: list[MitreAttackGroup]) -> list[MitreAttackGroup]: + def getUniqueGroups( + enrichments: list[MitreAttackEnrichment], + ) -> list[MitreAttackGroup]: group_set: set[MitreAttackGroup] = set() - for group in groups: - g = set(group) - group_set.update(g) - + for enrichment in enrichments: + group_set.update(set(enrichment.mitre_attack_group_objects)) return sorted(group_set) + + @staticmethod + def checkParentTypeNotDefinedWhenSubtypeDefined( + enrichments: list[MitreAttackEnrichment], + ) -> None: + # Get all the mitre_attack_ids + mitre_attack_ids = [enrichment.mitre_attack_id for enrichment in enrichments] + # Split these into two groups - one that just has parents and one which has subtypes as well + mitre_attack_id_parents = [ + mitre_attack_id + for mitre_attack_id in mitre_attack_ids + if "." not in mitre_attack_id + ] + mitre_attack_id_subtypes = [ + mitre_attack_id + for mitre_attack_id in mitre_attack_ids + if "." in mitre_attack_id + ] + + subtype_and_parent_exist_exceptions: list[Exception] = [] + + for mitre_attack_id in mitre_attack_id_subtypes: + parent_id = mitre_attack_id.split(".")[0] + if parent_id in mitre_attack_id_parents: + subtype_and_parent_exist_exceptions.append( + Exception( + f"Overlapping parent and subtype tactic: [Parent: '{parent_id}', Subtype: '{mitre_attack_id}']" + ) + ) + if len(subtype_and_parent_exist_exceptions): + raise ExceptionGroup( + "Error: both MITRE Attack ID Subtype and Parent are defined. " + "A parent tactic OR a subtype tactic may be defined, but not both", + subtype_and_parent_exist_exceptions, + ) + + return None diff --git a/contentctl/objects/story_tags.py b/contentctl/objects/story_tags.py index e611c596..1abf30f3 100644 --- a/contentctl/objects/story_tags.py +++ b/contentctl/objects/story_tags.py @@ -1,17 +1,18 @@ from __future__ import annotations -from pydantic import BaseModel, Field, model_serializer, ConfigDict -from typing import List, Set, Optional from enum import Enum +from typing import List, Optional, Set -from contentctl.objects.mitre_attack_enrichment import MitreAttackEnrichment +from pydantic import BaseModel, ConfigDict, Field, model_serializer + +from contentctl.objects.annotated_types import CVE_TYPE, MITRE_ATTACK_ID_TYPE from contentctl.objects.enums import ( - StoryCategory, DataModel, KillChainPhase, SecurityContentProductName, + StoryCategory, ) -from contentctl.objects.annotated_types import CVE_TYPE, MITRE_ATTACK_ID_TYPE +from contentctl.objects.mitre_attack_enrichment import MitreAttackEnrichment class StoryUseCase(str, Enum): From 421c2ea2b8d2f9ade962c966895401d28f61ba2b Mon Sep 17 00:00:00 2001 From: pyth0n1c Date: Mon, 10 Feb 2025 12:44:34 -0800 Subject: [PATCH 03/13] add function to check for overlapping mitre id type and subtypes --- contentctl/objects/detection_tags.py | 35 +++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/contentctl/objects/detection_tags.py b/contentctl/objects/detection_tags.py index ceaa6974..0e39eb08 100644 --- a/contentctl/objects/detection_tags.py +++ b/contentctl/objects/detection_tags.py @@ -44,7 +44,7 @@ class DetectionTags(BaseModel): asset_type: AssetType = Field(...) group: list[str] = [] - mitre_attack_id: List[MITRE_ATTACK_ID_TYPE] = [] + mitre_attack_id: list[MITRE_ATTACK_ID_TYPE] = [] nist: list[NistCategory] = [] product: list[SecurityContentProductName] = Field(..., min_length=1) @@ -165,6 +165,39 @@ def addAttackEnrichments(cls, v:list[MitreAttackEnrichment], info:ValidationInfo return enrichments """ + @field_validator("mitre_attack_id", mode="after") + @classmethod + def sameTypeAndSubtypeNotPresent( + cls, mitre_ids: list[MITRE_ATTACK_ID_TYPE] + ) -> list[MITRE_ATTACK_ID_TYPE]: + id_types: list[str] = [ + f"{mitre_id}." for mitre_id in mitre_ids if "." not in mitre_id + ] + id_subtypes: list[MITRE_ATTACK_ID_TYPE] = [ + mitre_id for mitre_id in mitre_ids if "." in mitre_id + ] + subtype_and_parent_exist_exceptions: list[ValueError] = [] + + for id_subtype in id_subtypes: + for id_type in id_types: + if id_subtype.startswith(id_type): + subtype_and_parent_exist_exceptions.append( + ValueError( + f" Tactic : {id_type.split('.')[0]}\n" + f" Subtactic: {id_subtype}\n" + ) + ) + + if len(subtype_and_parent_exist_exceptions): + error_string = "\n".join( + str(e) for e in subtype_and_parent_exist_exceptions + ) + raise ValueError( + f"Overlapping MITRE Attack ID Tactics and Subtactics may not be defined:\n{error_string}" + ) + + return mitre_ids + @field_validator("analytic_story", mode="before") @classmethod def mapStoryNamesToStoryObjects( From 8e92fd8b233e270234d56176159cb7c340cd6328 Mon Sep 17 00:00:00 2001 From: pyth0n1c Date: Mon, 10 Feb 2025 13:00:59 -0800 Subject: [PATCH 04/13] Remove redundant code --- contentctl/objects/detection_tags.py | 11 +----- contentctl/objects/mitre_attack_enrichment.py | 37 ------------------- 2 files changed, 2 insertions(+), 46 deletions(-) diff --git a/contentctl/objects/detection_tags.py b/contentctl/objects/detection_tags.py index 0e39eb08..f066a85f 100644 --- a/contentctl/objects/detection_tags.py +++ b/contentctl/objects/detection_tags.py @@ -134,14 +134,6 @@ def addAttackEnrichment(self, info: ValidationInfo): if len(missing_tactics) > 0: raise ValueError(f"Missing Mitre Attack IDs. {missing_tactics} not found.") - else: - try: - MitreAttackEnrichment.checkParentTypeNotDefinedWhenSubtypeDefined( - mitre_enrichments - ) - except Exception as e: - raise ValueError(e) - self.mitre_attack_enrichments = mitre_enrichments return self @@ -193,7 +185,8 @@ def sameTypeAndSubtypeNotPresent( str(e) for e in subtype_and_parent_exist_exceptions ) raise ValueError( - f"Overlapping MITRE Attack ID Tactics and Subtactics may not be defined:\n{error_string}" + "Overlapping MITRE Attack ID Tactics and Subtactics may not be defined. " + f"Remove the tactic and keep the subtactic:\n{error_string}" ) return mitre_ids diff --git a/contentctl/objects/mitre_attack_enrichment.py b/contentctl/objects/mitre_attack_enrichment.py index b77fbb24..c4415c30 100644 --- a/contentctl/objects/mitre_attack_enrichment.py +++ b/contentctl/objects/mitre_attack_enrichment.py @@ -115,40 +115,3 @@ def getUniqueGroups( for enrichment in enrichments: group_set.update(set(enrichment.mitre_attack_group_objects)) return sorted(group_set) - - @staticmethod - def checkParentTypeNotDefinedWhenSubtypeDefined( - enrichments: list[MitreAttackEnrichment], - ) -> None: - # Get all the mitre_attack_ids - mitre_attack_ids = [enrichment.mitre_attack_id for enrichment in enrichments] - # Split these into two groups - one that just has parents and one which has subtypes as well - mitre_attack_id_parents = [ - mitre_attack_id - for mitre_attack_id in mitre_attack_ids - if "." not in mitre_attack_id - ] - mitre_attack_id_subtypes = [ - mitre_attack_id - for mitre_attack_id in mitre_attack_ids - if "." in mitre_attack_id - ] - - subtype_and_parent_exist_exceptions: list[Exception] = [] - - for mitre_attack_id in mitre_attack_id_subtypes: - parent_id = mitre_attack_id.split(".")[0] - if parent_id in mitre_attack_id_parents: - subtype_and_parent_exist_exceptions.append( - Exception( - f"Overlapping parent and subtype tactic: [Parent: '{parent_id}', Subtype: '{mitre_attack_id}']" - ) - ) - if len(subtype_and_parent_exist_exceptions): - raise ExceptionGroup( - "Error: both MITRE Attack ID Subtype and Parent are defined. " - "A parent tactic OR a subtype tactic may be defined, but not both", - subtype_and_parent_exist_exceptions, - ) - - return None From 458861d37364574625a6d3304fa26bff5c61cfa7 Mon Sep 17 00:00:00 2001 From: pyth0n1c Date: Mon, 10 Feb 2025 14:31:19 -0800 Subject: [PATCH 05/13] add a property to get sorted, deduped groups for a detection. this is particularly useful in site gen. --- contentctl/objects/detection_tags.py | 9 ++++++++- contentctl/objects/mitre_attack_enrichment.py | 9 --------- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/contentctl/objects/detection_tags.py b/contentctl/objects/detection_tags.py index f066a85f..14d5d581 100644 --- a/contentctl/objects/detection_tags.py +++ b/contentctl/objects/detection_tags.py @@ -33,7 +33,7 @@ SecurityContentProductName, SecurityDomain, ) -from contentctl.objects.mitre_attack_enrichment import MitreAttackEnrichment +from contentctl.objects.mitre_attack_enrichment import MitreAttackEnrichment, MitreAttackGroup class DetectionTags(BaseModel): @@ -68,6 +68,13 @@ def kill_chain_phases(self) -> list[KillChainPhase]: phases.add(phase) return sorted(list(phases)) + @property + def unique_mitre_attack_groups(self)->list[MitreAttackGroup]: + group_set: set[MitreAttackGroup] = set() + for enrichment in self.enrichments: + group_set.update(set(enrichment.mitre_attack_group_objects)) + return sorted(group_set, lambda k: k.group) + # enum is intentionally Cis18 even though field is named cis20 for legacy reasons @computed_field @property diff --git a/contentctl/objects/mitre_attack_enrichment.py b/contentctl/objects/mitre_attack_enrichment.py index c4415c30..86d9ee49 100644 --- a/contentctl/objects/mitre_attack_enrichment.py +++ b/contentctl/objects/mitre_attack_enrichment.py @@ -106,12 +106,3 @@ class MitreAttackEnrichment(BaseModel): def __hash__(self) -> int: return id(self) - - @staticmethod - def getUniqueGroups( - enrichments: list[MitreAttackEnrichment], - ) -> list[MitreAttackGroup]: - group_set: set[MitreAttackGroup] = set() - for enrichment in enrichments: - group_set.update(set(enrichment.mitre_attack_group_objects)) - return sorted(group_set) From 0745169633c088aebaa22f026b330566b4cb2770 Mon Sep 17 00:00:00 2001 From: pyth0n1c Date: Mon, 10 Feb 2025 16:11:41 -0800 Subject: [PATCH 06/13] fix typing issue and add property decorator so that new field is not serialized --- contentctl/objects/detection_tags.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/contentctl/objects/detection_tags.py b/contentctl/objects/detection_tags.py index 14d5d581..7b6045ea 100644 --- a/contentctl/objects/detection_tags.py +++ b/contentctl/objects/detection_tags.py @@ -33,7 +33,10 @@ SecurityContentProductName, SecurityDomain, ) -from contentctl.objects.mitre_attack_enrichment import MitreAttackEnrichment, MitreAttackGroup +from contentctl.objects.mitre_attack_enrichment import ( + MitreAttackEnrichment, + MitreAttackGroup, +) class DetectionTags(BaseModel): @@ -68,12 +71,14 @@ def kill_chain_phases(self) -> list[KillChainPhase]: phases.add(phase) return sorted(list(phases)) + # We do not want this to be included in serialization. By default, @property + # objects are not included in dumps @property - def unique_mitre_attack_groups(self)->list[MitreAttackGroup]: + def unique_mitre_attack_groups(self) -> list[MitreAttackGroup]: group_set: set[MitreAttackGroup] = set() - for enrichment in self.enrichments: + for enrichment in self.mitre_attack_enrichments: group_set.update(set(enrichment.mitre_attack_group_objects)) - return sorted(group_set, lambda k: k.group) + return sorted(group_set, key=lambda k: k.group) # enum is intentionally Cis18 even though field is named cis20 for legacy reasons @computed_field @@ -277,3 +282,6 @@ def mapAtomicGuidsToAtomicTests( return matched_tests + [ AtomicTest.AtomicTestWhenTestIsMissing(test) for test in missing_tests ] + return matched_tests + [ + AtomicTest.AtomicTestWhenTestIsMissing(test) for test in missing_tests + ] From 4216c45e2fdf5172d3f196d8736b424be49537f2 Mon Sep 17 00:00:00 2001 From: pyth0n1c Date: Tue, 11 Feb 2025 12:37:44 -0800 Subject: [PATCH 07/13] error into message for now --- contentctl/objects/detection_tags.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/contentctl/objects/detection_tags.py b/contentctl/objects/detection_tags.py index 7b6045ea..0ccabebd 100644 --- a/contentctl/objects/detection_tags.py +++ b/contentctl/objects/detection_tags.py @@ -196,7 +196,11 @@ def sameTypeAndSubtypeNotPresent( error_string = "\n".join( str(e) for e in subtype_and_parent_exist_exceptions ) - raise ValueError( + # raise ValueError( + # "Overlapping MITRE Attack ID Tactics and Subtactics may not be defined. " + # f"Remove the tactic and keep the subtactic:\n{error_string}" + # ) + print( "Overlapping MITRE Attack ID Tactics and Subtactics may not be defined. " f"Remove the tactic and keep the subtactic:\n{error_string}" ) From bcdf2e233ef43a3837722a0b48befdbf9ee256f9 Mon Sep 17 00:00:00 2001 From: pyth0n1c Date: Tue, 11 Feb 2025 13:47:43 -0800 Subject: [PATCH 08/13] fix error that was accidentially introduced in previous commit. forgot to actually assign mitre_attack_enrichments to self after resolving them --- contentctl/objects/detection_tags.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/contentctl/objects/detection_tags.py b/contentctl/objects/detection_tags.py index 0ccabebd..9ebcef8d 100644 --- a/contentctl/objects/detection_tags.py +++ b/contentctl/objects/detection_tags.py @@ -147,6 +147,8 @@ def addAttackEnrichment(self, info: ValidationInfo): if len(missing_tactics) > 0: raise ValueError(f"Missing Mitre Attack IDs. {missing_tactics} not found.") + self.mitre_attack_enrichments = mitre_enrichments + return self """ From 1e4f1a843f6e96805d28f07bdff6be3f3fd7f33c Mon Sep 17 00:00:00 2001 From: pyth0n1c Date: Tue, 11 Feb 2025 14:03:04 -0800 Subject: [PATCH 09/13] add hash function to MitreAttackGroup --- contentctl/objects/mitre_attack_enrichment.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/contentctl/objects/mitre_attack_enrichment.py b/contentctl/objects/mitre_attack_enrichment.py index 86d9ee49..4b211712 100644 --- a/contentctl/objects/mitre_attack_enrichment.py +++ b/contentctl/objects/mitre_attack_enrichment.py @@ -94,6 +94,9 @@ def __lt__(self, other: MitreAttackGroup) -> bool: ) return self.group < other.group + def __hash__(self) -> int: + return id(self) + class MitreAttackEnrichment(BaseModel): ConfigDict(extra="forbid") From f80842a20aaae1c6f540f80c8a656cfe7d03a57f Mon Sep 17 00:00:00 2001 From: pyth0n1c Date: Tue, 11 Feb 2025 14:50:45 -0800 Subject: [PATCH 10/13] improve hash method for mitre group --- contentctl/objects/mitre_attack_enrichment.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contentctl/objects/mitre_attack_enrichment.py b/contentctl/objects/mitre_attack_enrichment.py index 4b211712..7d3e72f7 100644 --- a/contentctl/objects/mitre_attack_enrichment.py +++ b/contentctl/objects/mitre_attack_enrichment.py @@ -95,7 +95,7 @@ def __lt__(self, other: MitreAttackGroup) -> bool: return self.group < other.group def __hash__(self) -> int: - return id(self) + return hash(self.group) class MitreAttackEnrichment(BaseModel): From 9c8722a43e139bf94da9a60e0196a0d005f2a01b Mon Sep 17 00:00:00 2001 From: pyth0n1c Date: Tue, 11 Feb 2025 15:04:07 -0800 Subject: [PATCH 11/13] turn printed message back into an error --- contentctl/objects/detection_tags.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/contentctl/objects/detection_tags.py b/contentctl/objects/detection_tags.py index 9ebcef8d..b6cfe5a5 100644 --- a/contentctl/objects/detection_tags.py +++ b/contentctl/objects/detection_tags.py @@ -198,11 +198,7 @@ def sameTypeAndSubtypeNotPresent( error_string = "\n".join( str(e) for e in subtype_and_parent_exist_exceptions ) - # raise ValueError( - # "Overlapping MITRE Attack ID Tactics and Subtactics may not be defined. " - # f"Remove the tactic and keep the subtactic:\n{error_string}" - # ) - print( + raise ValueError( "Overlapping MITRE Attack ID Tactics and Subtactics may not be defined. " f"Remove the tactic and keep the subtactic:\n{error_string}" ) From 4e088f8e70e06422607592be14513e47b80cec1e Mon Sep 17 00:00:00 2001 From: pyth0n1c Date: Tue, 11 Feb 2025 15:51:22 -0800 Subject: [PATCH 12/13] Fix naming of tactics to techniques --- contentctl/objects/detection_tags.py | 30 ++++++++++++++++------------ 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/contentctl/objects/detection_tags.py b/contentctl/objects/detection_tags.py index b6cfe5a5..c723e5c8 100644 --- a/contentctl/objects/detection_tags.py +++ b/contentctl/objects/detection_tags.py @@ -174,23 +174,27 @@ def addAttackEnrichments(cls, v:list[MitreAttackEnrichment], info:ValidationInfo @field_validator("mitre_attack_id", mode="after") @classmethod def sameTypeAndSubtypeNotPresent( - cls, mitre_ids: list[MITRE_ATTACK_ID_TYPE] + cls, techniques_and_subtechniques: list[MITRE_ATTACK_ID_TYPE] ) -> list[MITRE_ATTACK_ID_TYPE]: - id_types: list[str] = [ - f"{mitre_id}." for mitre_id in mitre_ids if "." not in mitre_id + techniques: list[str] = [ + f"{unknown_technique}." + for unknown_technique in techniques_and_subtechniques + if "." not in unknown_technique ] - id_subtypes: list[MITRE_ATTACK_ID_TYPE] = [ - mitre_id for mitre_id in mitre_ids if "." in mitre_id + subtechniques: list[MITRE_ATTACK_ID_TYPE] = [ + unknown_technique + for unknown_technique in techniques_and_subtechniques + if "." in unknown_technique ] subtype_and_parent_exist_exceptions: list[ValueError] = [] - for id_subtype in id_subtypes: - for id_type in id_types: - if id_subtype.startswith(id_type): + for subtechnique in subtechniques: + for technique in techniques: + if subtechnique.startswith(technique): subtype_and_parent_exist_exceptions.append( ValueError( - f" Tactic : {id_type.split('.')[0]}\n" - f" Subtactic: {id_subtype}\n" + f" Technique : {technique.split('.')[0]}\n" + f" SubTechnique: {subtechnique}\n" ) ) @@ -199,11 +203,11 @@ def sameTypeAndSubtypeNotPresent( str(e) for e in subtype_and_parent_exist_exceptions ) raise ValueError( - "Overlapping MITRE Attack ID Tactics and Subtactics may not be defined. " - f"Remove the tactic and keep the subtactic:\n{error_string}" + "Overlapping MITRE Attack ID Techniques and Subtechniques may not be defined. " + f"Remove the Technique and keep the Subtechnique:\n{error_string}" ) - return mitre_ids + return techniques_and_subtechniques @field_validator("analytic_story", mode="before") @classmethod From b5641eeee639fbf317d281a01bb2f9621f01caff Mon Sep 17 00:00:00 2001 From: pyth0n1c Date: Tue, 11 Feb 2025 16:09:14 -0800 Subject: [PATCH 13/13] update template detection to pass new validation --- .../templates/detections/endpoint/anomalous_usage_of_7zip.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/contentctl/templates/detections/endpoint/anomalous_usage_of_7zip.yml b/contentctl/templates/detections/endpoint/anomalous_usage_of_7zip.yml index 3eea8300..23c15a16 100644 --- a/contentctl/templates/detections/endpoint/anomalous_usage_of_7zip.yml +++ b/contentctl/templates/detections/endpoint/anomalous_usage_of_7zip.yml @@ -60,7 +60,6 @@ tags: asset_type: Endpoint mitre_attack_id: - T1560.001 - - T1560 product: - Splunk Enterprise - Splunk Enterprise Security