From 6b4af25ead91c15a4d913dda2d8d500e1cef71e5 Mon Sep 17 00:00:00 2001 From: Jared Ondricek Date: Fri, 26 Sep 2025 08:36:28 -0500 Subject: [PATCH 01/29] fix: update logic to work with new detection strategy objects --- mitreattack/diffStix/changelog_helper.py | 94 ++++++++++++++++++------ 1 file changed, 71 insertions(+), 23 deletions(-) diff --git a/mitreattack/diffStix/changelog_helper.py b/mitreattack/diffStix/changelog_helper.py index 0b1364de..2556eb0c 100644 --- a/mitreattack/diffStix/changelog_helper.py +++ b/mitreattack/diffStix/changelog_helper.py @@ -495,14 +495,23 @@ def find_technique_detection_changes(self, new_stix_obj: dict, domain: str): continue if stix_id == detection_relationship["target_ref"]: old_sourceref_id = detection_relationship["source_ref"] + # Datacomponent -> Data source relation used to exist via x_mitre_data_source_ref. + # New STIX may not include parent datasources; attempt explicit ref first, then a heuristic lookup. if old_sourceref_id in all_old_domain_datacomponents: old_datacomponent = all_old_domain_datacomponents[old_sourceref_id] - old_datasource_id = old_datacomponent["x_mitre_data_source_ref"] - old_datasource = all_old_domain_datasources[old_datasource_id] - old_datasource_attack_id = get_attack_id(stix_obj=old_datasource) - old_datacomponent_detections[old_sourceref_id] = ( - f"{old_datasource_attack_id}: {old_datasource['name']} ({old_datacomponent['name']})" - ) + old_datasource_id = old_datacomponent.get("x_mitre_data_source_ref") + if not old_datasource_id: + # Best-effort fallback: try to resolve a parent datasource from available datasource objects. + old_datasource_id = resolve_datacomponent_parent(old_datacomponent, all_old_domain_datasources) + if old_datasource_id and old_datasource_id in all_old_domain_datasources: + old_datasource = all_old_domain_datasources[old_datasource_id] + old_datasource_attack_id = get_attack_id(stix_obj=old_datasource) + old_datacomponent_detections[old_sourceref_id] = ( + f"{old_datasource_attack_id}: {old_datasource['name']} ({old_datacomponent['name']})" + ) + else: + # No parent datasource identified — show the datacomponent name as standalone. + old_datacomponent_detections[old_sourceref_id] = f"{old_datacomponent['name']}" if old_sourceref_id in all_old_domain_detectionstrategies: old_detectionstrategy = all_old_domain_detectionstrategies[old_sourceref_id] old_detectionstrategy_attack_id = get_attack_id(stix_obj=old_detectionstrategy) @@ -515,14 +524,22 @@ def find_technique_detection_changes(self, new_stix_obj: dict, domain: str): continue if stix_id == detection_relationship["target_ref"]: new_sourceref_id = detection_relationship["source_ref"] + # Handle datacomponents that may no longer reference a datasource. if new_sourceref_id in all_new_domain_datacomponents: new_datacomponent = all_new_domain_datacomponents[new_sourceref_id] - new_datasource_id = new_datacomponent["x_mitre_data_source_ref"] - new_datasource = all_new_domain_datasources[new_datasource_id] - new_datasource_attack_id = get_attack_id(stix_obj=new_datasource) - new_datacomponent_detections[new_sourceref_id] = ( - f"{new_datasource_attack_id}: {new_datasource['name']} ({new_datacomponent['name']})" - ) + new_datasource_id = new_datacomponent.get("x_mitre_data_source_ref") + if not new_datasource_id: + # Best-effort fallback lookup into datasources + new_datasource_id = resolve_datacomponent_parent(new_datacomponent, all_new_domain_datasources) + if new_datasource_id and new_datasource_id in all_new_domain_datasources: + new_datasource = all_new_domain_datasources[new_datasource_id] + new_datasource_attack_id = get_attack_id(stix_obj=new_datasource) + new_datacomponent_detections[new_sourceref_id] = ( + f"{new_datasource_attack_id}: {new_datasource['name']} ({new_datacomponent['name']})" + ) + else: + # No parent datasource identified — show the datacomponent name as standalone. + new_datacomponent_detections[new_sourceref_id] = f"{new_datacomponent['name']}" if new_sourceref_id in all_new_domain_detectionstrategies: new_detectionstrategy = all_new_domain_detectionstrategies[new_sourceref_id] new_detectionstrategy_attack_id = get_attack_id(stix_obj=new_detectionstrategy) @@ -813,11 +830,15 @@ def get_groupings(self, object_type: str, stix_objects: List, section: str, doma if datacomponent["id"] not in children: continue - parent_datasource_id = datacomponent["x_mitre_data_source_ref"] + # Prefer explicit reference, otherwise try a heuristic lookup + parent_datasource_id = datacomponent.get("x_mitre_data_source_ref") + if not parent_datasource_id: + parent_datasource_id = resolve_datacomponent_parent(datacomponent, datasources) the_datacomponent = children[datacomponent["id"]] - if parent_datasource_id not in parentToChildren: - parentToChildren[parent_datasource_id] = [] - parentToChildren[parent_datasource_id].append(the_datacomponent) + if parent_datasource_id: + if parent_datasource_id not in parentToChildren: + parentToChildren[parent_datasource_id] = [] + parentToChildren[parent_datasource_id].append(the_datacomponent) # now group parents and children groupings = [] @@ -898,7 +919,11 @@ def get_parent_stix_object(self, stix_object: dict, datastore_version: str, doma parent_id = subtechnique_relationship["target_ref"] return techniques[parent_id] elif stix_object["type"] == "x-mitre-data-component": - return datasources[stix_object.get("x_mitre_data_source_ref")] + parent_ref = stix_object.get("x_mitre_data_source_ref") + if parent_ref and parent_ref in datasources: + return datasources[parent_ref] + # No parent datasource available for this datacomponent. + return {} # possible reasons for no parent object: deprecated/revoked/wrong object type passed in return {} @@ -944,12 +969,16 @@ def placard(self, stix_object: dict, section: str, domain: str) -> str: parent_object = self.get_parent_stix_object( stix_object=revoker, datastore_version=datastore_version, domain=domain ) - parent_name = parent_object.get("name", "ERROR NO PARENT") - relative_url = get_relative_data_component_url(datasource=parent_object, datacomponent=stix_object) - revoker_link = f"{self.site_prefix}/{relative_url}" - placard_string = ( - f"{stix_object['name']} (revoked by {parent_name}: [{revoker['name']}]({revoker_link}))" - ) + if parent_object: + parent_name = parent_object.get("name", "ERROR NO PARENT") + relative_url = get_relative_data_component_url(datasource=parent_object, datacomponent=stix_object) + revoker_link = f"{self.site_prefix}/{relative_url}" + placard_string = ( + f"{stix_object['name']} (revoked by {parent_name}: [{revoker['name']}]({revoker_link}))" + ) + else: + # No parent datasource available — fall back to a plain-text representation. + placard_string = f"{stix_object['name']} (revoked by {revoker['name']})" else: relative_url = get_relative_url_from_stix(stix_object=revoker) @@ -964,6 +993,9 @@ def placard(self, stix_object: dict, section: str, domain: str) -> str: if parent_object: relative_url = get_relative_data_component_url(datasource=parent_object, datacomponent=stix_object) placard_string = f"[{stix_object['name']}]({self.site_prefix}/{relative_url})" + else: + # No parent datasource available — display datacomponent name as plain text. + placard_string = stix_object["name"] else: relative_url = get_relative_url_from_stix(stix_object=stix_object) @@ -1273,6 +1305,22 @@ def cleanup_values(groupings: List[dict]) -> List[dict]: return new_values +def resolve_datacomponent_parent(datacomponent: dict, datasources: Dict[str, dict]) -> Optional[str]: + """Best-effort resolution of a datacomponent's parent datasource when an explicit x_mitre_data_source_ref is not present. + + Strategy: + 1. If the datacomponent contains an explicit 'x_mitre_data_source_ref', return it. + 2. If no match, return None. + """ + # explicit ref + parent_ref = datacomponent.get("x_mitre_data_source_ref") + if parent_ref: + return parent_ref + + # nothing matched + return None + + def version_increment_is_valid( old_version: AttackObjectVersion | None, new_version: AttackObjectVersion | None, section: str ) -> bool: From 46aebcd78bd92bdc187b14d9cae1c25b12e933d0 Mon Sep 17 00:00:00 2001 From: Evan Lucchesi Leon <189633144+elucchesileon@users.noreply.github.com> Date: Fri, 26 Sep 2025 15:39:50 -0400 Subject: [PATCH 02/29] fix: handle missing x_mitre_data_source_ref in data components --- mitreattack/attackToExcel/stixToDf.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mitreattack/attackToExcel/stixToDf.py b/mitreattack/attackToExcel/stixToDf.py index 80eb5136..c5588d35 100644 --- a/mitreattack/attackToExcel/stixToDf.py +++ b/mitreattack/attackToExcel/stixToDf.py @@ -290,7 +290,8 @@ def datasourcesToDf(src): if "x_mitre_aliases" in data_object: row["aliases"] = ", ".join(sorted(data_object["x_mitre_aliases"][1:])) if data_object["type"] == "x-mitre-data-component": - row["name"] = f"{source_lookup[data_object['x_mitre_data_source_ref']]}: {data_object['name']}" + if "x_mitre_data_source_ref" in data_object: + row["name"] = f"{source_lookup[data_object['x_mitre_data_source_ref']]}: {data_object['name']}" row["type"] = "datacomponent" else: row["type"] = "datasource" From ba5cf3d9db1bd6bb42518bcda61086e7659dded2 Mon Sep 17 00:00:00 2001 From: Jared Ondricek Date: Fri, 3 Oct 2025 17:40:29 -0500 Subject: [PATCH 03/29] fix: handle new detection strategy STIX bundles that have altered how datasources work --- mitreattack/attackToExcel/stixToDf.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/mitreattack/attackToExcel/stixToDf.py b/mitreattack/attackToExcel/stixToDf.py index c5588d35..5cec84ab 100644 --- a/mitreattack/attackToExcel/stixToDf.py +++ b/mitreattack/attackToExcel/stixToDf.py @@ -974,7 +974,13 @@ def relationshipsToDf(src, relatedType=None): relationship_rows.append(row) citations = get_citations(relationships) - relationships = pd.DataFrame(relationship_rows).sort_values( + + relationship_df = pd.DataFrame(relationship_rows) + if relationship_df.empty or "mapping type" not in relationship_df.columns: + logger.warning(f"No relationships found for relatedType={relatedType}. Returning empty dataframe.") + return {} + + relationships = relationship_df.sort_values( [ "mapping type", "source type", From bad4597d300b345e2cf1d144bbe3a2a7efc6f776 Mon Sep 17 00:00:00 2001 From: Evan Lucchesi Leon <189633144+elucchesileon@users.noreply.github.com> Date: Tue, 7 Oct 2025 11:20:36 -0400 Subject: [PATCH 04/29] fix: remove warnings for data component with no parent --- mitreattack/diffStix/changelog_helper.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/mitreattack/diffStix/changelog_helper.py b/mitreattack/diffStix/changelog_helper.py index 2556eb0c..80924f35 100644 --- a/mitreattack/diffStix/changelog_helper.py +++ b/mitreattack/diffStix/changelog_helper.py @@ -1731,16 +1731,12 @@ def write_detailed_html(html_file_detailed: str, diffStix: DiffStix): if parent_object: nameplate = f"{parent_object.get('name')}: {stix_object['name']}" else: - logger.warning(f"[{stix_object['id']}] {attack_id} has no parent!") - nameplate = f"{stix_object['name']} (No parent object identified. It is likely revoked or deprecated)" + nameplate = f"{stix_object['name']}" else: nameplate = stix_object["name"] if attack_id: nameplate = f"[{attack_id}] {nameplate}" - else: - if stix_object["type"] != "x-mitre-data-component": - logger.warning(f"{stix_object['id']} does not have an ATT&CK ID") lines.append("
") lines.append(f"

{nameplate}

") From aaa587460d311ce8d85633ebc19e45fb21e6538d Mon Sep 17 00:00:00 2001 From: Evan Lucchesi Leon <189633144+elucchesileon@users.noreply.github.com> Date: Tue, 7 Oct 2025 15:16:12 -0400 Subject: [PATCH 05/29] fix: remove references to log source SDOs --- mitreattack/diffStix/changelog_helper.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/mitreattack/diffStix/changelog_helper.py b/mitreattack/diffStix/changelog_helper.py index 80924f35..330be61d 100644 --- a/mitreattack/diffStix/changelog_helper.py +++ b/mitreattack/diffStix/changelog_helper.py @@ -122,7 +122,6 @@ def __init__( "datacomponents", "detectionstrategies", "analytics", - "logsources", ] self.use_mitre_cti = use_mitre_cti self.verbose = verbose @@ -144,7 +143,6 @@ def __init__( "datacomponents": "Data Components", "detectionstrategies": "Detection Strategies", "analytics": "Analytics", - "logsources": "Log Sources", } self.section_descriptions = { @@ -675,7 +673,6 @@ def parse_extra_data(self, data_store: stix2.MemoryStore, domain: str, datastore "datacomponents": [Filter("type", "=", "x-mitre-data-component")], "detectionstrategies": [Filter("type", "=", "x-mitre-detection-strategy")], "analytics": [Filter("type", "=", "x-mitre-analytic")], - "logsources": [Filter("type", "=", "x-mitre-log-source")], } for object_type, stix_filters in attack_type_to_stix_filter.items(): raw_data = [] From 440283b77a1ad39d4d307854bac2c3477484f88f Mon Sep 17 00:00:00 2001 From: Evan Lucchesi Leon <189633144+elucchesileon@users.noreply.github.com> Date: Fri, 10 Oct 2025 08:43:25 -0400 Subject: [PATCH 06/29] feat: add attack spec version 3.3.0 objects to stix20/ code --- mitreattack/stix20/MitreAttackData.py | 153 ++++++++++++++++++++ mitreattack/stix20/custom_attack_objects.py | 78 ++++++++++ 2 files changed, 231 insertions(+) diff --git a/mitreattack/stix20/MitreAttackData.py b/mitreattack/stix20/MitreAttackData.py index 436b675c..18032b26 100644 --- a/mitreattack/stix20/MitreAttackData.py +++ b/mitreattack/stix20/MitreAttackData.py @@ -26,10 +26,12 @@ from stix2.utils import get_type_from_id from mitreattack.stix20.custom_attack_objects import ( + Analytic, Asset, CustomStixObject, DataComponent, DataSource, + DetectionStrategy, Matrix, StixObjectFactory, Tactic, @@ -106,6 +108,8 @@ class MitreAttackData: "x-mitre-data-source", "x-mitre-data-component", "x-mitre-asset", + "x-mitre-analytic", + "x-mitre-detection-strategy", ] # --- Software/Group Relationships --- @@ -148,6 +152,10 @@ class MitreAttackData: all_techniques_targeting_all_assets: Optional[RelationshipMapT[Technique]] = None all_assets_targeted_by_all_techniques: Optional[RelationshipMapT[Asset]] = None + # --- Detection Strategy/Technique Relationships --- + all_detection_strategies_detecting_all_techniques: Optional[RelationshipMapT[DetectionStrategy]] = None + all_techniques_detected_by_all_detection_strategies: Optional[RelationshipMapT[Technique]] = None + def __init__(self, stix_filepath: str | None = None, src: stix2.MemoryStore | None = None): """Initialize a MitreAttackData object. @@ -431,6 +439,36 @@ def get_datacomponents(self, remove_revoked_deprecated: bool = False) -> list[Da """ return self.get_objects_by_type("x-mitre-data-component", remove_revoked_deprecated) + def get_analytics(self, remove_revoked_deprecated: bool = False) -> list[Analytic]: + """Retrieve all analytic objects. + + Parameters + ---------- + remove_revoked_deprecated : bool, optional + Remove revoked or deprecated objects from the query, by default False. + + Returns + ------- + list[Analytic] + A list of Analytic objects. + """ + return self.get_objects_by_type("x-mitre-analytic", remove_revoked_deprecated) + + def get_detectionstrategies(self, remove_revoked_deprecated: bool = False) -> list[DetectionStrategy]: + """Retrieve all detection strategy objects. + + Parameters + ---------- + remove_revoked_deprecated : bool, optional + Remove revoked or deprecated objects from the query, by default False. + + Returns + ------- + list[DetectionStrategy] + A list of DetectionStrategy objects. + """ + return self.get_objects_by_type("x-mitre-detection-strategy", remove_revoked_deprecated) + ################################### # Get STIX Objects by Value ################################### @@ -733,6 +771,37 @@ def get_techniques_used_by_group_software(self, group_stix_id: str) -> list[Tech technique_ids = [r.target_ref for r in software_uses] return self.src.query([Filter("type", "=", "attack-pattern"), Filter("id", "in", technique_ids)]) + def get_analytics_by_detection_strategy( + self, detection_strategy_stix_id: str, remove_revoked_deprecated: bool = False + ) -> list[Analytic]: + """Retrieve analytics for a detection strategy. + + Parameters + ---------- + detection_strategy_stix_id: str + Detection Strategy to search. + remove_revoked_deprecated : bool, optional + Remove revoked or deprecated objects from the query, by default False. + + Returns + ------- + list[Analytic] + A list of Analytic objects referenced by the given detection strategy. + + Raises + ------ + ValueError + If no detection strategy with the given STIX ID is found. + """ + detection_strategy = self.get_object_by_stix_id(detection_strategy_stix_id) + analytic_refs = self.get_field(detection_strategy, "x_mitre_analytic_refs", []) + + filters = [Filter("type", "=", "x-mitre-analytic"), Filter("id", "in", analytic_refs)] + analytics = self.src.query(filters) + if remove_revoked_deprecated: + analytics = self.remove_revoked_deprecated(analytics) + return analytics + ################################### # Get STIX Object by Value ################################### @@ -1960,3 +2029,87 @@ def get_assets_targeted_by_technique(self, technique_stix_id: str) -> list[Relat if technique_stix_id in assets_targeted_by_techniques else [] ) + + ############################################ + # Detection Strategy/Technique Relationships + ############################################ + + def get_all_detection_strategies_detecting_all_techniques(self) -> RelationshipMapT[DetectionStrategy]: + """Get all detection strategies detecting all techniques. + + Returns + ------- + RelationshipMapT[DetectionStrategy] + Mapping of asset_stix_id to RelationshipEntry[DetectionStrategy] for each detection strategy detecting the technique. + """ + # return data if it has already been fetched + if self.all_detection_strategies_detecting_all_techniques: + return self.all_detection_strategies_detecting_all_techniques + + self.all_detection_strategies_detecting_all_techniques = self.get_related( + "x-mitre-detection-strategy", "detects", "attack-pattern", reverse=True + ) + + return self.all_detection_strategies_detecting_all_techniques + + def get_detection_strategies_detecting_technique( + self, technique_stix_id: str + ) -> list[RelationshipEntry[DetectionStrategy]]: + """Get all detection strategies detecting a technique. + + Parameters + ---------- + technique_stix_id : str + The STIX ID of the technique. + + Returns + ------- + list[RelationshipEntry[DetectionStrategy]] + List of RelationshipEntry[DetectionStrategy] for each detection strategy detecting the technique. + """ + detection_strategies_detecting_techniques = self.get_all_detection_strategies_detecting_all_techniques() + return ( + detection_strategies_detecting_techniques[technique_stix_id] + if technique_stix_id in detection_strategies_detecting_techniques + else [] + ) + + def get_all_techniques_detected_by_all_detection_strategies(self) -> RelationshipMapT[Technique]: + """Get all techniques detected by all detection strategies. + + Returns + ------- + RelationshipMapT[Technique] + Mapping of detection_strategy_stix_id to RelationshipEntry[Technique] for each technique detected by the detection strategy. + """ + # return data if it has already been fetched + if self.all_techniques_detected_by_all_detection_strategies: + return self.all_techniques_detected_by_all_detection_strategies + + self.all_techniques_detected_by_all_detection_strategies = self.get_related( + "x-mitre-detection-strategy", "detects", "attack-pattern" + ) + + return self.all_techniques_detected_by_all_detection_strategies + + def get_techniques_detected_by_detection_strategy( + self, detection_strategy_stix_id: str + ) -> list[RelationshipEntry[Technique]]: + """Get all techniques detected by a detection strategy. + + Parameters + ---------- + detection_strategy_stix_id : str + The STIX ID of the detection strategy. + + Returns + ------- + list[RelationshipEntry[Technique]] + List of RelationshipEntry[Technique] for each technique detected by the detection strategy. + """ + techniques_detected_by_detection_strategies = self.get_all_techniques_detected_by_all_detection_strategies() + return ( + techniques_detected_by_detection_strategies[detection_strategy_stix_id] + if detection_strategy_stix_id in techniques_detected_by_detection_strategies + else [] + ) diff --git a/mitreattack/stix20/custom_attack_objects.py b/mitreattack/stix20/custom_attack_objects.py index 6609c1ec..62f36727 100644 --- a/mitreattack/stix20/custom_attack_objects.py +++ b/mitreattack/stix20/custom_attack_objects.py @@ -80,6 +80,8 @@ def StixObjectFactory(data: dict) -> Union[CustomStixObject, stix2.v20.sdo._Doma "x-mitre-data-source": DataSource, "x-mitre-data-component": DataComponent, "x-mitre-asset": Asset, + "x-mitre-analytic": Analytic, + "x-mitre-detection-strategy": DetectionStrategy, } stix_type = data.get("type") @@ -220,6 +222,7 @@ class DataSource(CustomStixObject, object): ("x_mitre_attack_spec_version", StringProperty()), # Data Component Properties ("x_mitre_data_source_ref", ReferenceProperty(valid_types="x-mitre-data-source", spec_version="2.0")), + ("x_mitre_log_sources", ListProperty(DictionaryProperty())), ], ) class DataComponent(CustomStixObject, object): @@ -228,6 +231,7 @@ class DataComponent(CustomStixObject, object): Custom Properties ----------------- x_mitre_data_source_ref: str + x_mitre_log_sources: list[object] """ pass @@ -268,3 +272,77 @@ class Asset(CustomStixObject, object): """ pass + + +@CustomObject( + "x-mitre-analytic", + [ + # SDO Common Properties + ("id", IDProperty("x-mitre-analytic", spec_version="2.0")), + ("type", TypeProperty("x-mitre-analytic", spec_version="2.0")), + ("created_by_ref", ReferenceProperty(valid_types="identity", spec_version="2.0")), + ("created", TimestampProperty(precision="millisecond")), + ("modified", TimestampProperty(precision="millisecond")), + ("revoked", BooleanProperty(default=lambda: False)), + ("external_references", ListProperty(ExternalReference)), + ("object_marking_refs", ListProperty(ReferenceProperty(valid_types="marking-definition", spec_version="2.0"))), + ("name", StringProperty(required=True)), + ("description", StringProperty()), + ("x_mitre_modified_by_ref", ReferenceProperty(valid_types="identity", spec_version="2.0")), + ("x_mitre_version", StringProperty()), + ("x_mitre_attack_spec_version", StringProperty()), + ("x_mitre_domains", ListProperty(StringProperty())), + ("x_mitre_contributors", ListProperty(StringProperty())), + ("x-mitre-deprecated", BooleanProperty(default=lambda: False)), + # Analytic Properties + ("x_mitre_platforms", ListProperty(StringProperty())), + ("x_mitre_log_source_references", ListProperty(DictionaryProperty())), + ("x_mitre_mutable_elements", ListProperty(DictionaryProperty())), + ], +) +class Analytic(CustomStixObject, object): + """Custom Analytic object of type stix2.CustomObject. + + Custom Properties + ----------------- + x_mitre_platforms: list[str] + x_mitre_log_source_references: list[object] + x_mitre_mutable_elements: list[object] + """ + + pass + + +@CustomObject( + "x-mitre-detection-strategy", + [ + # SDO Common Properties + ("id", IDProperty("x-mitre-detection-strategy", spec_version="2.0")), + ("type", TypeProperty("x-mitre-detection-strategy", spec_version="2.0")), + ("created_by_ref", ReferenceProperty(valid_types="identity", spec_version="2.0")), + ("created", TimestampProperty(precision="millisecond")), + ("modified", TimestampProperty(precision="millisecond")), + ("revoked", BooleanProperty(default=lambda: False)), + ("external_references", ListProperty(ExternalReference)), + ("object_marking_refs", ListProperty(ReferenceProperty(valid_types="marking-definition", spec_version="2.0"))), + ("name", StringProperty(required=True)), + ("description", StringProperty()), + ("x_mitre_modified_by_ref", ReferenceProperty(valid_types="identity", spec_version="2.0")), + ("x_mitre_version", StringProperty()), + ("x_mitre_attack_spec_version", StringProperty()), + ("x_mitre_domains", ListProperty(StringProperty())), + ("x_mitre_contributors", ListProperty(StringProperty())), + ("x-mitre-deprecated", BooleanProperty(default=lambda: False)), + # Detection Strategy Properties + ("x_mitre_analytic_refs", ListProperty(StringProperty())), + ], +) +class DetectionStrategy(CustomStixObject, object): + """Custom Detection Strategy object of type stix2.CustomObject. + + Custom Properties + ----------------- + x_mitre_analytic_refs: list[str] + """ + + pass From 3a6542b81da5fd6a4a0b9491a9e5cc7849ec8b3b Mon Sep 17 00:00:00 2001 From: Evan Lucchesi Leon <189633144+elucchesileon@users.noreply.github.com> Date: Fri, 10 Oct 2025 08:43:45 -0400 Subject: [PATCH 07/29] fix: lint errors, add x_mitre_deprecated to stix20/ custom objects --- mitreattack/stix20/MitreAttackData.py | 8 ++++---- mitreattack/stix20/custom_attack_objects.py | 5 +++++ 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/mitreattack/stix20/MitreAttackData.py b/mitreattack/stix20/MitreAttackData.py index 18032b26..1aef3f7a 100644 --- a/mitreattack/stix20/MitreAttackData.py +++ b/mitreattack/stix20/MitreAttackData.py @@ -981,8 +981,8 @@ def get_attack_id(self, stix_id: str) -> str | None: The ATT&CK ID of the object, or None if not found. """ obj = self.get_object_by_stix_id(stix_id) - external_references = obj.get("external_references") - if external_references: + external_references = self.get_field(obj, "external_references", []) + if external_references and len(external_references) > 0: attack_source = external_references[0] if attack_source.get("external_id") and attack_source.get("source_name") == "mitre-attack": return attack_source["external_id"] @@ -1018,8 +1018,8 @@ def get_name(self, stix_id: str) -> str | None: """ obj = self.get_object_by_stix_id(stix_id) # name = MitreAttackData.get_field(obj, "name") - name = obj.get("name") - return name if name is not None else None + name = self.get_field(obj, "name") + return name ################################### # Relationship Section diff --git a/mitreattack/stix20/custom_attack_objects.py b/mitreattack/stix20/custom_attack_objects.py index 62f36727..9c8f5cab 100644 --- a/mitreattack/stix20/custom_attack_objects.py +++ b/mitreattack/stix20/custom_attack_objects.py @@ -108,6 +108,7 @@ def StixObjectFactory(data: dict) -> Union[CustomStixObject, stix2.v20.sdo._Doma ("x_mitre_modified_by_ref", ReferenceProperty(valid_types="identity", spec_version="2.0")), ("x_mitre_version", StringProperty()), ("x_mitre_attack_spec_version", StringProperty()), + ("x-mitre-deprecated", BooleanProperty(default=lambda: False)), # Matrix Properties ("tactic_refs", ListProperty(ReferenceProperty(valid_types="x-mitre-tactic", spec_version="2.0"))), ], @@ -141,6 +142,7 @@ class Matrix(CustomStixObject, object): ("x_mitre_modified_by_ref", ReferenceProperty(valid_types="identity", spec_version="2.0")), ("x_mitre_version", StringProperty()), ("x_mitre_attack_spec_version", StringProperty()), + ("x-mitre-deprecated", BooleanProperty(default=lambda: False)), # Tactic Properties ("x_mitre_shortname", StringProperty()), ], @@ -186,6 +188,7 @@ def get_shortname(self) -> str: ("x_mitre_modified_by_ref", ReferenceProperty(valid_types="identity", spec_version="2.0")), ("x_mitre_version", StringProperty()), ("x_mitre_attack_spec_version", StringProperty()), + ("x-mitre-deprecated", BooleanProperty(default=lambda: False)), # Data Source Properties ("x_mitre_platforms", ListProperty(StringProperty())), ("x_mitre_collection_layers", ListProperty(StringProperty())), @@ -220,6 +223,7 @@ class DataSource(CustomStixObject, object): ("x_mitre_modified_by_ref", ReferenceProperty(valid_types="identity", spec_version="2.0")), ("x_mitre_version", StringProperty()), ("x_mitre_attack_spec_version", StringProperty()), + ("x-mitre-deprecated", BooleanProperty(default=lambda: False)), # Data Component Properties ("x_mitre_data_source_ref", ReferenceProperty(valid_types="x-mitre-data-source", spec_version="2.0")), ("x_mitre_log_sources", ListProperty(DictionaryProperty())), @@ -256,6 +260,7 @@ class DataComponent(CustomStixObject, object): ("x_mitre_attack_spec_version", StringProperty()), ("x_mitre_domains", ListProperty(StringProperty())), ("x_mitre_contributors", ListProperty(StringProperty())), + ("x-mitre-deprecated", BooleanProperty(default=lambda: False)), # Asset Properties ("sectors", ListProperty(StringProperty())), ("x_mitre_related_assets", ListProperty(DictionaryProperty())), From 39657a078cc25d92c07b21c9cce62b5478693970 Mon Sep 17 00:00:00 2001 From: Evan Lucchesi Leon <189633144+elucchesileon@users.noreply.github.com> Date: Fri, 10 Oct 2025 08:51:46 -0400 Subject: [PATCH 08/29] fix: add tests for previous 2 commits, fix resulting bugs --- mitreattack/stix20/__init__.py | 4 ++- mitreattack/stix20/custom_attack_objects.py | 2 +- tests/test_stix20.py | 37 ++++++++++++++++++--- 3 files changed, 37 insertions(+), 6 deletions(-) diff --git a/mitreattack/stix20/__init__.py b/mitreattack/stix20/__init__.py index 608b7c0e..29904d8b 100644 --- a/mitreattack/stix20/__init__.py +++ b/mitreattack/stix20/__init__.py @@ -1,4 +1,4 @@ -from .custom_attack_objects import Asset, DataComponent, DataSource, Matrix, StixObjectFactory, Tactic +from .custom_attack_objects import Asset, DataComponent, DataSource, Matrix, StixObjectFactory, Tactic, Analytic, DetectionStrategy from .MitreAttackData import MitreAttackData __all__ = [ @@ -9,4 +9,6 @@ "StixObjectFactory", "Tactic", "MitreAttackData", + "Analytic", + "DetectionStrategy", ] diff --git a/mitreattack/stix20/custom_attack_objects.py b/mitreattack/stix20/custom_attack_objects.py index 9c8f5cab..00147f7f 100644 --- a/mitreattack/stix20/custom_attack_objects.py +++ b/mitreattack/stix20/custom_attack_objects.py @@ -339,7 +339,7 @@ class Analytic(CustomStixObject, object): ("x_mitre_contributors", ListProperty(StringProperty())), ("x-mitre-deprecated", BooleanProperty(default=lambda: False)), # Detection Strategy Properties - ("x_mitre_analytic_refs", ListProperty(StringProperty())), + ("x_mitre_analytic_refs", ListProperty(ReferenceProperty(valid_types="x-mitre-analytic", spec_version="2.0"))), ], ) class DetectionStrategy(CustomStixObject, object): diff --git a/tests/test_stix20.py b/tests/test_stix20.py index 73568a6a..b0367c4c 100644 --- a/tests/test_stix20.py +++ b/tests/test_stix20.py @@ -2,22 +2,33 @@ Tests for custom STIX 2.0 attack objects in the mitreattack.stix20 module. This module verifies the correct behavior and properties of custom ATT&CK objects -such as DataComponent, DataSource, Matrix, Tactic, Asset, and the StixObjectFactory. +including DataComponent, DataSource, Matrix, Tactic, Asset, Analytic, +DetectionStrategy, and the StixObjectFactory. """ import pytest import stix2 import stix2.exceptions -from mitreattack.stix20.custom_attack_objects import Asset, DataComponent, DataSource, Matrix, StixObjectFactory, Tactic +from mitreattack.stix20.custom_attack_objects import ( + Analytic, + Asset, + DataComponent, + DataSource, + DetectionStrategy, + Matrix, + StixObjectFactory, + Tactic, +) class TestCustomAttackObjects: """ Test suite for custom ATT&CK STIX 2.0 objects and their factory. - This class contains tests for the creation and properties of custom ATT&CK objects, - including DataComponent, DataSource, Matrix, Tactic, Asset, and the StixObjectFactory. + This class contains tests for the creation and properties of custom ATT&CK objects + including DataComponent, DataSource, Matrix, Tactic, Asset, Analytic, + DetectionStrategy, and the StixObjectFactory. """ def test_data_component(self): @@ -52,6 +63,8 @@ def test_stix_object_factory(self): "x-mitre-matrix": Matrix, "x-mitre-tactic": Tactic, "x-mitre-asset": Asset, + "x-mitre-analytic": Analytic, + "x-mitre-detection-strategy": DetectionStrategy, } object_name = "Object name" @@ -88,3 +101,19 @@ def test_asset(self): assert asset.name == name assert asset.type == "x-mitre-asset" + + def test_analytic(self): + """Test Analytic creation and properties.""" + name = "Analytic" + analytic = Analytic(name=name) + + assert analytic.name == name + assert analytic.type == "x-mitre-analytic" + + def test_detection_strategy(self): + """Test Detection Strategy creation and properties.""" + name = "Detection Strategy" + detection_strategy = DetectionStrategy(name=name) + + assert detection_strategy.name == name + assert detection_strategy.type == "x-mitre-detection-strategy" From bbffa44a2fe310f492b37ab9b0f467e1b28c562f Mon Sep 17 00:00:00 2001 From: Evan Lucchesi Leon <189633144+elucchesileon@users.noreply.github.com> Date: Fri, 10 Oct 2025 12:06:51 -0400 Subject: [PATCH 09/29] feat: add analytics and detection strategies to excel outputs --- mitreattack/attackToExcel/attackToExcel.py | 2 + mitreattack/attackToExcel/stixToDf.py | 70 ++++++++++++++++++++++ 2 files changed, 72 insertions(+) diff --git a/mitreattack/attackToExcel/attackToExcel.py b/mitreattack/attackToExcel/attackToExcel.py index d03a61ac..4714f31b 100644 --- a/mitreattack/attackToExcel/attackToExcel.py +++ b/mitreattack/attackToExcel/attackToExcel.py @@ -108,6 +108,8 @@ def build_dataframes(src: MemoryStore, domain: str) -> Dict: "matrices": stixToDf.matricesToDf(src, domain), "relationships": stixToDf.relationshipsToDf(src), "datasources": stixToDf.datasourcesToDf(src), + "analytics": stixToDf.analyticsToDf(src), + "detectionstrategies": stixToDf.detectionstrategiesToDf(src), } return df diff --git a/mitreattack/attackToExcel/stixToDf.py b/mitreattack/attackToExcel/stixToDf.py index 5cec84ab..2e669d8c 100644 --- a/mitreattack/attackToExcel/stixToDf.py +++ b/mitreattack/attackToExcel/stixToDf.py @@ -333,6 +333,66 @@ def datasourcesToDf(src): return dataframes +def analyticsToDf(src): + """Parse STIX Analytics from the given data and return corresponding pandas dataframes. + + :param src: MemoryStore or other stix2 DataSource object holding the domain data + :returns: a lookup of labels (descriptors/names) to dataframes + """ + analytics = src.query([Filter("type", "=", "x-mitre-analytic")]) + analytics = remove_revoked_deprecated(analytics) + + analytic_rows = [] + for analytic in tqdm(analytics, desc="parsing analytics"): + analytic_rows.append(parseBaseStix(analytic)) + + citations = get_citations(analytics) + dataframes = { + "analytics": pd.DataFrame(analytic_rows).sort_values("name"), + } + if not citations.empty: + dataframes["citations"] = citations.sort_values("reference") + + return dataframes + + +def detectionstrategiesToDf(src): + """Parse STIX Detection Strategies from the given data and return corresponding pandas dataframes. + + :param src: MemoryStore or other stix2 DataSource object holding the domain data + :returns: a lookup of labels (descriptors/names) to dataframes + """ + detection_strategies = src.query([Filter("type", "=", "x-mitre-detection-strategy")]) + detection_strategies = remove_revoked_deprecated(detection_strategies) + + detection_strategy_rows = [] + for detection_strategy in tqdm(detection_strategies, desc="parsing detection strategies"): + detection_strategy_rows.append(parseBaseStix(detection_strategy)) + + citations = get_citations(detection_strategies) + dataframes = { + "detectionstrategies": pd.DataFrame(detection_strategy_rows).sort_values("name"), + } + + # add relationships + codex = relationshipsToDf(src, relatedType="detectionstrategy") + dataframes.update(codex) + # add relationship references + dataframes["detectionstrategies"]["relationship citations"] = _get_relationship_citations( + dataframes["detectionstrategies"], codex + ) + # add/merge citations + if not citations.empty: + if "citations" in dataframes: # append to existing citations from references + dataframes["citations"] = pd.concat([dataframes["citations"], citations]) + else: # add citations + dataframes["citations"] = citations + + dataframes["citations"].sort_values("reference") + + return dataframes + + def softwareToDf(src): """Parse STIX software from the given data and return corresponding pandas dataframes. @@ -893,6 +953,7 @@ def relationshipsToDf(src, relatedType=None): "mitigation": ["course-of-action"], "matrix": ["x-mitre-matrix"], "datasource": ["x-mitre-data-component"], + "detectionstrategy": ["x-mitre-detection-strategy"], } stixToAttackTerm = { "attack-pattern": "technique", @@ -906,6 +967,7 @@ def relationshipsToDf(src, relatedType=None): "x-mitre-data-source": "datasource", "campaign": "campaign", "x-mitre-asset": "asset", + "x-mitre-detection-strategy": "detectionstrategy", } mitre_attack_data = MitreAttackData(src=src) @@ -1022,6 +1084,7 @@ def relationshipsToDf(src, relatedType=None): attributedCampaignGroup = relationships.query("`mapping type` == 'attributed-to' and `target type` == 'group'") relatedMitigations = relationships.query("`mapping type` == 'mitigates'") targetedAssets = relationships.query("`mapping type` == 'targets' and `target type` == 'asset'") + detectedTechniques = relationships.query("`mapping type` == 'detects' and `source type` == 'detectionstrategy'") if not relatedGroupSoftware.empty: if relatedType == "group": @@ -1067,6 +1130,13 @@ def relationshipsToDf(src, relatedType=None): sheet_name = "associated techniques" dataframes[sheet_name] = targetedAssets + if not detectedTechniques.empty: + if relatedType == "detectionstrategy": + sheet_name = "techniques detected" + else: + sheet_name = "associated detection strategies" + dataframes[sheet_name] = detectedTechniques + if not citations.empty: # filter citations by ones actually used # build master list of used citations From 7263af2554074ef31416af8d1f8664bcb0963ac9 Mon Sep 17 00:00:00 2001 From: Evan Lucchesi Leon <189633144+elucchesileon@users.noreply.github.com> Date: Fri, 10 Oct 2025 12:07:14 -0400 Subject: [PATCH 10/29] fix: modified date in excel for datasources/datacomponents wasn't showing --- mitreattack/attackToExcel/stixToDf.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/mitreattack/attackToExcel/stixToDf.py b/mitreattack/attackToExcel/stixToDf.py index 2e669d8c..62907aa0 100644 --- a/mitreattack/attackToExcel/stixToDf.py +++ b/mitreattack/attackToExcel/stixToDf.py @@ -263,7 +263,7 @@ def datasourcesToDf(src): :returns: a lookup of labels (descriptors/names) to dataframes """ data = list( - chain.from_iterable( # software are the union of the tool and malware types + chain.from_iterable( # collect all data components and data sources src.query(f) for f in [ Filter("type", "=", "x-mitre-data-component"), @@ -280,9 +280,9 @@ def datasourcesToDf(src): if x["type"] == "x-mitre-data-source": source_lookup[x["id"]] = x["name"] for data_object in tqdm(refined, desc="parsing data sources"): - # add common STIx fields + # add common STIX fields row = parseBaseStix(data_object) - # add software-specific fields + # add data source/data component-specific fields if "x_mitre_platforms" in data_object: row["platforms"] = ", ".join(sorted(data_object["x_mitre_platforms"])) if "x_mitre_collection_layers" in data_object: @@ -310,7 +310,7 @@ def datasourcesToDf(src): "collection layers", "platforms", "created", - "modified", + "last modified", "type", "version", "url", From a75ae8ec0d02575e217b1853673b2d49ea2411e4 Mon Sep 17 00:00:00 2001 From: Evan Lucchesi Leon <189633144+elucchesileon@users.noreply.github.com> Date: Fri, 10 Oct 2025 12:59:22 -0400 Subject: [PATCH 11/29] fix: type errors --- examples/analytic_extractor.py | 2 +- mitreattack/navlayers/core/layerobj.py | 20 +++++++++---------- .../navlayers/generators/usage_generator.py | 5 ++++- mitreattack/release_info.py | 5 ++++- tests/changelog/test_utils.py | 3 ++- 5 files changed, 21 insertions(+), 14 deletions(-) diff --git a/examples/analytic_extractor.py b/examples/analytic_extractor.py index 76986ab3..78cc7ef5 100644 --- a/examples/analytic_extractor.py +++ b/examples/analytic_extractor.py @@ -11,7 +11,7 @@ # Prune an input string to remove any non-analytic text # This assumes that all analytics start the

html block -STRING_RE = "Analytic(\s|.)*" +STRING_RE = r"Analytic(\s|.)*" def pruneString(in_string): diff --git a/mitreattack/navlayers/core/layerobj.py b/mitreattack/navlayers/core/layerobj.py index 65830297..5a654288 100644 --- a/mitreattack/navlayers/core/layerobj.py +++ b/mitreattack/navlayers/core/layerobj.py @@ -52,14 +52,14 @@ def __init__(self, name, domain): @property def version(self): """Getter for version.""" - if self.__versions != UNSETVALUE: + if self.__versions != UNSETVALUE and not isinstance(self.__versions, str): return self.__versions.layer @version.setter def version(self, version): typeChecker(type(self).__name__, version, str, "version") categoryChecker(type(self).__name__, version, ["3.0", "4.0", "4.1", "4.2", "4.3"], "version") - if self.__versions is UNSETVALUE: + if self.__versions is UNSETVALUE or isinstance(self.__versions, str): self.__versions = Versions() self.__versions.layer = version @@ -350,7 +350,7 @@ def links(self): @links.setter def links(self, links): typeChecker(type(self).__name__, links, list, "links") - if not handle_object_placement(self.__links, links, Link): + if not handle_object_placement(self.__links, links, Link) or isinstance(self.__links, str): self.__links = [] entry = "" try: @@ -418,21 +418,21 @@ def get_dict(self): if self.description: temp["description"] = self.description - if self.versions: + if self.versions and not isinstance(self.versions, str): temp["versions"] = self.versions.get_dict() - if self.filters: + if self.filters and not isinstance(self.filters, str): temp["filters"] = self.filters.get_dict() if self.sorting: temp["sorting"] = self.sorting - if self.layout: + if self.layout and not isinstance(self.layout, str): temp["layout"] = self.layout.get_dict() if self.hideDisabled is not None: temp["hideDisabled"] = self.hideDisabled - if self.techniques: + if self.techniques and isinstance(self.techniques, list): temp["techniques"] = [x.get_dict() for x in self.techniques] - if self.gradient: + if self.gradient and not isinstance(self.gradient, str): temp["gradient"] = self.gradient.get_dict() - if self.legendItems: + if self.legendItems and isinstance(self.legendItems, list): temp["legendItems"] = [x.get_dict() for x in self.legendItems] if self.showTacticRowBackground is not None: temp["showTacticRowBackground"] = self.showTacticRowBackground @@ -444,7 +444,7 @@ def get_dict(self): temp["selectSubtechniquesWithParent"] = self.selectSubtechniquesWithParent if self.selectVisibleTechniques is not None: temp["selectVisibleTechniques"] = self.selectVisibleTechniques - if self.metadata: + if self.metadata and isinstance(self.metadata, list): temp["metadata"] = [x.get_dict() for x in self.metadata] return temp diff --git a/mitreattack/navlayers/generators/usage_generator.py b/mitreattack/navlayers/generators/usage_generator.py index e41b89e6..76ac78f6 100644 --- a/mitreattack/navlayers/generators/usage_generator.py +++ b/mitreattack/navlayers/generators/usage_generator.py @@ -2,6 +2,7 @@ import copy from itertools import chain +from typing import Any from stix2 import Filter @@ -149,7 +150,9 @@ def generate_layer(self, match): raise StixObjectIsNotValid a_id = get_attack_id(matched_obj) processed_listing = self.generate_technique_data(raw_data) - raw_layer = dict(name=f"{matched_obj['name']} ({matched_obj['id']})", domain=self.domain + "-attack") + raw_layer: dict[str, Any] = dict( + name=f"{matched_obj['name']} ({matched_obj['id']})", domain=self.domain + "-attack" + ) raw_layer["techniques"] = processed_listing output_layer = Layer(raw_layer) if matched_obj["type"] != "x-mitre-data-component": diff --git a/mitreattack/release_info.py b/mitreattack/release_info.py index 82603d2a..7286374d 100644 --- a/mitreattack/release_info.py +++ b/mitreattack/release_info.py @@ -231,7 +231,7 @@ def get_attack_version( - domain: str, stix_version: str = "2.0", stix_file: str = None, stix_content: bytes = None + domain: str, stix_version: str = "2.0", stix_file: Optional[str] = None, stix_content: Optional[bytes] = None ) -> Optional[str]: """Determine the version of ATT&CK based on either a file or contents of a file. @@ -277,6 +277,9 @@ def get_attack_version( stix_hash_data = STIX20 elif stix_version == "2.1": stix_hash_data = STIX21 + else: + logger.error(f"Invalid stix_version given: {stix_version}") + return None releases = {} if domain == "enterprise-attack": diff --git a/tests/changelog/test_utils.py b/tests/changelog/test_utils.py index 080bd6d7..cc0ef428 100644 --- a/tests/changelog/test_utils.py +++ b/tests/changelog/test_utils.py @@ -5,6 +5,7 @@ """ import json +from collections.abc import Callable from pathlib import Path from typing import Any, Dict, List, Optional, Union @@ -184,7 +185,7 @@ def assert_diffstix_data_structure_valid(diffstix_instance) -> None: def create_test_files_and_validate( - file_paths: Dict[str, Union[str, Path]], validation_funcs: Dict[str, callable] + file_paths: Dict[str, Union[str, Path]], validation_funcs: Dict[str, Callable] ) -> None: """Create test files and validate their contents. From 47e6374da3ee512008f4ce2e1ecc566faff270f2 Mon Sep 17 00:00:00 2001 From: Evan Lucchesi Leon <189633144+elucchesileon@users.noreply.github.com> Date: Fri, 10 Oct 2025 14:49:31 -0400 Subject: [PATCH 12/29] fix: handle empty lists of analytics/detection strategies --- mitreattack/attackToExcel/stixToDf.py | 70 +++++++++++++++------------ 1 file changed, 40 insertions(+), 30 deletions(-) diff --git a/mitreattack/attackToExcel/stixToDf.py b/mitreattack/attackToExcel/stixToDf.py index 62907aa0..326d5870 100644 --- a/mitreattack/attackToExcel/stixToDf.py +++ b/mitreattack/attackToExcel/stixToDf.py @@ -342,16 +342,21 @@ def analyticsToDf(src): analytics = src.query([Filter("type", "=", "x-mitre-analytic")]) analytics = remove_revoked_deprecated(analytics) - analytic_rows = [] - for analytic in tqdm(analytics, desc="parsing analytics"): - analytic_rows.append(parseBaseStix(analytic)) + dataframes = {} + if analytics: + analytic_rows = [] + for analytic in tqdm(analytics, desc="parsing analytics"): + analytic_rows.append(parseBaseStix(analytic)) - citations = get_citations(analytics) - dataframes = { - "analytics": pd.DataFrame(analytic_rows).sort_values("name"), - } - if not citations.empty: - dataframes["citations"] = citations.sort_values("reference") + citations = get_citations(analytics) + dataframes = { + "analytics": pd.DataFrame(analytic_rows).sort_values("name"), + } + if not citations.empty: + dataframes["citations"] = citations.sort_values("reference") + + else: + logger.warning("No analytics found - nothing to parse") return dataframes @@ -365,30 +370,35 @@ def detectionstrategiesToDf(src): detection_strategies = src.query([Filter("type", "=", "x-mitre-detection-strategy")]) detection_strategies = remove_revoked_deprecated(detection_strategies) - detection_strategy_rows = [] - for detection_strategy in tqdm(detection_strategies, desc="parsing detection strategies"): - detection_strategy_rows.append(parseBaseStix(detection_strategy)) + dataframes = {} + if detection_strategies: + detection_strategy_rows = [] + for detection_strategy in tqdm(detection_strategies, desc="parsing detection strategies"): + detection_strategy_rows.append(parseBaseStix(detection_strategy)) - citations = get_citations(detection_strategies) - dataframes = { - "detectionstrategies": pd.DataFrame(detection_strategy_rows).sort_values("name"), - } + citations = get_citations(detection_strategies) + dataframes = { + "detectionstrategies": pd.DataFrame(detection_strategy_rows).sort_values("name"), + } - # add relationships - codex = relationshipsToDf(src, relatedType="detectionstrategy") - dataframes.update(codex) - # add relationship references - dataframes["detectionstrategies"]["relationship citations"] = _get_relationship_citations( - dataframes["detectionstrategies"], codex - ) - # add/merge citations - if not citations.empty: - if "citations" in dataframes: # append to existing citations from references - dataframes["citations"] = pd.concat([dataframes["citations"], citations]) - else: # add citations - dataframes["citations"] = citations + # add relationships + codex = relationshipsToDf(src, relatedType="detectionstrategy") + dataframes.update(codex) + # add relationship references + dataframes["detectionstrategies"]["relationship citations"] = _get_relationship_citations( + dataframes["detectionstrategies"], codex + ) + # add/merge citations + if not citations.empty: + if "citations" in dataframes: # append to existing citations from references + dataframes["citations"] = pd.concat([dataframes["citations"], citations]) + else: # add citations + dataframes["citations"] = citations - dataframes["citations"].sort_values("reference") + dataframes["citations"].sort_values("reference") + + else: + logger.warning("No detection strategies found - nothing to parse") return dataframes From 44d48e016754b54f08eae05a72c12377fa30d552 Mon Sep 17 00:00:00 2001 From: Jared Ondricek Date: Mon, 13 Oct 2025 18:15:04 -0500 Subject: [PATCH 13/29] chore: update examples to optionally use environment variables to read STIX bundles --- examples/.env.example | 16 ++++ examples/README.md | 79 +++++++++++++++++++ examples/get_all_assets.py | 5 +- ...t_all_assets_targeted_by_all_techniques.py | 5 +- examples/get_all_campaigns.py | 5 +- ..._all_campaigns_attributed_to_all_groups.py | 5 +- .../get_all_campaigns_using_all_software.py | 5 +- .../get_all_campaigns_using_all_techniques.py | 5 +- examples/get_all_datacomponents.py | 6 +- ...datacomponents_detecting_all_techniques.py | 5 +- examples/get_all_datasources.py | 5 +- examples/get_all_groups.py | 5 +- ...all_groups_attributing_to_all_campaigns.py | 5 +- examples/get_all_groups_using_all_software.py | 5 +- .../get_all_groups_using_all_techniques.py | 5 +- examples/get_all_matrices.py | 5 +- examples/get_all_mitigations.py | 5 +- ...l_mitigations_mitigating_all_techniques.py | 5 +- examples/get_all_parent_techniques.py | 5 +- ..._parent_techniques_of_all_subtechniques.py | 5 +- examples/get_all_software.py | 5 +- .../get_all_software_used_by_all_campaigns.py | 5 +- .../get_all_software_used_by_all_groups.py | 5 +- .../get_all_software_using_all_techniques.py | 5 +- examples/get_all_subtechniques.py | 5 +- ...get_all_subtechniques_of_all_techniques.py | 5 +- examples/get_all_tactics.py | 5 +- examples/get_all_techniques.py | 5 +- ...chniques_detected_by_all_datacomponents.py | 5 +- ...techniques_mitigated_by_all_mitigations.py | 5 +- ...get_all_techniques_targeting_all_assets.py | 5 +- ...et_all_techniques_used_by_all_campaigns.py | 5 +- .../get_all_techniques_used_by_all_groups.py | 5 +- ...get_all_techniques_used_by_all_software.py | 5 +- examples/get_assets_targeted_by_technique.py | 5 +- examples/get_attack_id.py | 5 +- examples/get_campaigns_attributed_to_group.py | 5 +- examples/get_campaigns_by_alias.py | 5 +- examples/get_campaigns_using_software.py | 5 +- examples/get_campaigns_using_technique.py | 5 +- .../get_datacomponents_detecting_technique.py | 5 +- .../get_groups_attributing_to_campaign.py | 5 +- examples/get_groups_by_alias.py | 5 +- examples/get_groups_using_software.py | 5 +- examples/get_groups_using_technique.py | 5 +- .../get_mitigations_mitigating_technique.py | 5 +- examples/get_name.py | 5 +- examples/get_object_by_attack_id.py | 5 +- examples/get_object_by_stix_id.py | 5 +- examples/get_objects_by_content.py | 5 +- examples/get_objects_by_name.py | 5 +- examples/get_objects_by_type.py | 5 +- examples/get_objects_created_after.py | 5 +- examples/get_objects_modified_after.py | 5 +- .../get_parent_technique_of_subtechnique.py | 5 +- examples/get_procedure_examples_by_tactic.py | 6 +- .../get_procedure_examples_by_technique.py | 5 +- examples/get_revoked_techniques.py | 5 +- examples/get_software_by_alias.py | 5 +- examples/get_software_used_by_campaign.py | 5 +- examples/get_software_used_by_group.py | 5 +- examples/get_software_using_technique.py | 5 +- examples/get_stix_type.py | 5 +- examples/get_subtechniques_of_technique.py | 5 +- examples/get_tactics_by_matrix.py | 5 +- examples/get_tactics_by_technique.py | 5 +- examples/get_techniques_by_platform.py | 5 +- examples/get_techniques_by_tactic.py | 5 +- ...et_techniques_detected_by_datacomponent.py | 5 +- .../get_techniques_mitigated_by_mitigation.py | 5 +- examples/get_techniques_targeting_asset.py | 5 +- examples/get_techniques_used_by_campaign.py | 5 +- examples/get_techniques_used_by_group.py | 5 +- .../get_techniques_used_by_group_software.py | 5 +- examples/get_techniques_used_by_software.py | 5 +- 75 files changed, 389 insertions(+), 73 deletions(-) create mode 100644 examples/.env.example create mode 100644 examples/README.md diff --git a/examples/.env.example b/examples/.env.example new file mode 100644 index 00000000..7e2d9dcd --- /dev/null +++ b/examples/.env.example @@ -0,0 +1,16 @@ +# These environment variables can be helpful when running scripts in the examples directory +# +# In order to use them, copy this file to .env and modify the values as needed +# Two optional tools worth considering to automatically use the .env file are: +# 1. `python-dotenv` python library: https://github.com/theskumar/python-dotenv +# 2. `direnv` tool: https://direnv.net +# Setting up these tools is out of scope for this example. +# +# if you have mitreattack-python installed, you can use the following command to download all STIX bundles: +# +# download_attack_stix --all +# +# the default download directory from the above command is "attack-releases" + +STIX_BASE_DIR=attack-releases/stix-2.0/v17.1 +STIX_BUNDLE=attack-releases/stix-2.0/v17.1/enterprise-attack.json diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 00000000..d503d31b --- /dev/null +++ b/examples/README.md @@ -0,0 +1,79 @@ +# Examples Directory + +This directory contains example scripts demonstrating how to use the [`mitreattack-python`](https://github.com/mitre-attack/mitreattack-python) +library to extract, analyze, and report on MITRE ATT&CK data. +These scripts cover a variety of use cases, including querying STIX bundles, generating reports, and automating ATT&CK data analysis. + +## Full Example Listing & Documentation + +A complete, categorized list of example scripts, usage details, and direct links is maintained in the built documentation: + +- [mitreattack-python Examples Documentation](https://mitreattack-python.readthedocs.io/en/latest/mitre_attack_data/examples.html) + +## Setup + +Many example scripts allow optional configuration via environment variables for paths to STIX bundles. +If you want to set this up you can follow these instructions. + +- Copy the provided [`examples/.env.example`](examples/.env.example:1) file to `.env`: + + ```sh + cp .env.example .env + ``` + +- Edit `.env` to set the correct paths and variables for your environment. + +Creating a .env file is not enough however. You will need to use a tool such as the following to help manage the environment variables: + +- [`python-dotenv`](https://pypi.org/project/python-dotenv/) (automatically loads `.env` in Python scripts) +- [`direnv`](https://direnv.net/) (manages environment variables per directory) + +Setting up these tools is out of scope for this README. + +### Dependencies + +- [`mitreattack-python`](https://github.com/mitre-attack/mitreattack-python) +- Python 3.x +- ATT&CK STIX bundles + +### Downloading ATT&CK STIX Bundles + +Many example scripts require ATT&CK STIX bundles, which must be downloaded and placed in the directory specified in your `.env` file (e.g., `attack-releases/stix-2.0/v17.1`). +You can download these bundles using the provided CLI command if you have mitreattack-python installed: + +```sh +download_attack_stix --all +``` + +This will download all available ATT&CK releases in STIX format to the default directory (`attack-releases`). +You can customize the download location and versions using additional options. For example: + +- Download the latest release (default): + + ```sh + download_attack_stix + ``` + +- Download specific versions: + + ```sh + download_attack_stix -v 16.1 -v 17.1 + ``` + +- Download all releases in both STIX formats: + + ```sh + download_attack_stix --all --stix21 + ``` + +## How to Run Scripts + +- Run individual scripts with Python: + + ```sh + python get_all_techniques.py + ``` + +## Contribution & Customization + +Feel free to adapt these scripts for your own use cases. Contributions and improvements are welcome! diff --git a/examples/get_all_assets.py b/examples/get_all_assets.py index 24c0feba..fe3078d6 100644 --- a/examples/get_all_assets.py +++ b/examples/get_all_assets.py @@ -1,8 +1,11 @@ +import os + from mitreattack.stix20 import MitreAttackData def main(): - mitre_attack_data = MitreAttackData("ics-attack.json") + stix_filepath = os.environ.get("STIX_BUNDLE", "ics-attack.json") + mitre_attack_data = MitreAttackData(stix_filepath=stix_filepath) assets = mitre_attack_data.get_assets(remove_revoked_deprecated=True) diff --git a/examples/get_all_assets_targeted_by_all_techniques.py b/examples/get_all_assets_targeted_by_all_techniques.py index daf84029..ab80f85e 100644 --- a/examples/get_all_assets_targeted_by_all_techniques.py +++ b/examples/get_all_assets_targeted_by_all_techniques.py @@ -1,8 +1,11 @@ +import os + from mitreattack.stix20 import MitreAttackData def main(): - mitre_attack_data = MitreAttackData("ics-attack.json") + stix_filepath = os.environ.get("STIX_BUNDLE", "ics-attack.json") + mitre_attack_data = MitreAttackData(stix_filepath=stix_filepath) # get all assets targeted by techniques assets_targeted_by_techniques = mitre_attack_data.get_all_assets_targeted_by_all_techniques() diff --git a/examples/get_all_campaigns.py b/examples/get_all_campaigns.py index cbbd844e..e643b4d4 100644 --- a/examples/get_all_campaigns.py +++ b/examples/get_all_campaigns.py @@ -1,8 +1,11 @@ +import os + from mitreattack.stix20 import MitreAttackData def main(): - mitre_attack_data = MitreAttackData("enterprise-attack.json") + stix_filepath = os.environ.get("STIX_BUNDLE", "enterprise-attack.json") + mitre_attack_data = MitreAttackData(stix_filepath=stix_filepath) campaigns = mitre_attack_data.get_campaigns(remove_revoked_deprecated=True) diff --git a/examples/get_all_campaigns_attributed_to_all_groups.py b/examples/get_all_campaigns_attributed_to_all_groups.py index 0acd84d7..3ddd3543 100644 --- a/examples/get_all_campaigns_attributed_to_all_groups.py +++ b/examples/get_all_campaigns_attributed_to_all_groups.py @@ -1,8 +1,11 @@ +import os + from mitreattack.stix20 import MitreAttackData def main(): - mitre_attack_data = MitreAttackData("enterprise-attack.json") + stix_filepath = os.environ.get("STIX_BUNDLE", "enterprise-attack.json") + mitre_attack_data = MitreAttackData(stix_filepath=stix_filepath) # get all campaigns related to groups campaigns_attributed = mitre_attack_data.get_all_campaigns_attributed_to_all_groups() diff --git a/examples/get_all_campaigns_using_all_software.py b/examples/get_all_campaigns_using_all_software.py index a7fe40e2..ade5117f 100644 --- a/examples/get_all_campaigns_using_all_software.py +++ b/examples/get_all_campaigns_using_all_software.py @@ -1,8 +1,11 @@ +import os + from mitreattack.stix20 import MitreAttackData def main(): - mitre_attack_data = MitreAttackData("enterprise-attack.json") + stix_filepath = os.environ.get("STIX_BUNDLE", "enterprise-attack.json") + mitre_attack_data = MitreAttackData(stix_filepath=stix_filepath) # get all campaigns related to software campaigns_using_software = mitre_attack_data.get_all_campaigns_using_all_software() diff --git a/examples/get_all_campaigns_using_all_techniques.py b/examples/get_all_campaigns_using_all_techniques.py index eccd5c78..686c0946 100644 --- a/examples/get_all_campaigns_using_all_techniques.py +++ b/examples/get_all_campaigns_using_all_techniques.py @@ -1,8 +1,11 @@ +import os + from mitreattack.stix20 import MitreAttackData def main(): - mitre_attack_data = MitreAttackData("enterprise-attack.json") + stix_filepath = os.environ.get("STIX_BUNDLE", "enterprise-attack.json") + mitre_attack_data = MitreAttackData(stix_filepath=stix_filepath) # get all campaigns related to techniques campaigns_using_techniques = mitre_attack_data.get_all_campaigns_using_all_techniques() diff --git a/examples/get_all_datacomponents.py b/examples/get_all_datacomponents.py index 000027ff..2096e536 100644 --- a/examples/get_all_datacomponents.py +++ b/examples/get_all_datacomponents.py @@ -1,8 +1,12 @@ +import os + from mitreattack.stix20 import MitreAttackData def main(): - mitre_attack_data = MitreAttackData("enterprise-attack.json") + stix_filepath = os.environ.get("STIX_BUNDLE", "enterprise-attack.json") + mitre_attack_data = MitreAttackData(stix_filepath=stix_filepath) + datacomponents = mitre_attack_data.get_datacomponents(remove_revoked_deprecated=True) diff --git a/examples/get_all_datacomponents_detecting_all_techniques.py b/examples/get_all_datacomponents_detecting_all_techniques.py index e7d0bea8..30b95d8e 100644 --- a/examples/get_all_datacomponents_detecting_all_techniques.py +++ b/examples/get_all_datacomponents_detecting_all_techniques.py @@ -1,8 +1,11 @@ +import os + from mitreattack.stix20 import MitreAttackData def main(): - mitre_attack_data = MitreAttackData("enterprise-attack.json") + stix_filepath = os.environ.get("STIX_BUNDLE", "enterprise-attack.json") + mitre_attack_data = MitreAttackData(stix_filepath=stix_filepath) # get all data components related to techniques datacomponents_detecting = mitre_attack_data.get_all_datacomponents_detecting_all_techniques() diff --git a/examples/get_all_datasources.py b/examples/get_all_datasources.py index 9e3f73b8..1acf70f9 100644 --- a/examples/get_all_datasources.py +++ b/examples/get_all_datasources.py @@ -1,8 +1,11 @@ +import os + from mitreattack.stix20 import MitreAttackData def main(): - mitre_attack_data = MitreAttackData("enterprise-attack.json") + stix_filepath = os.environ.get("STIX_BUNDLE", "enterprise-attack.json") + mitre_attack_data = MitreAttackData(stix_filepath=stix_filepath) datasources = mitre_attack_data.get_datasources(remove_revoked_deprecated=True) diff --git a/examples/get_all_groups.py b/examples/get_all_groups.py index 54446d24..d589b54b 100644 --- a/examples/get_all_groups.py +++ b/examples/get_all_groups.py @@ -1,8 +1,11 @@ +import os + from mitreattack.stix20 import MitreAttackData def main(): - mitre_attack_data = MitreAttackData("enterprise-attack.json") + stix_filepath = os.environ.get("STIX_BUNDLE", "enterprise-attack.json") + mitre_attack_data = MitreAttackData(stix_filepath=stix_filepath) groups = mitre_attack_data.get_groups(remove_revoked_deprecated=True) diff --git a/examples/get_all_groups_attributing_to_all_campaigns.py b/examples/get_all_groups_attributing_to_all_campaigns.py index ab549fce..621b455b 100644 --- a/examples/get_all_groups_attributing_to_all_campaigns.py +++ b/examples/get_all_groups_attributing_to_all_campaigns.py @@ -1,8 +1,11 @@ +import os + from mitreattack.stix20 import MitreAttackData def main(): - mitre_attack_data = MitreAttackData("enterprise-attack.json") + stix_filepath = os.environ.get("STIX_BUNDLE", "enterprise-attack.json") + mitre_attack_data = MitreAttackData(stix_filepath=stix_filepath) # get all groups related to campaigns groups_attributing = mitre_attack_data.get_all_groups_attributing_to_all_campaigns() diff --git a/examples/get_all_groups_using_all_software.py b/examples/get_all_groups_using_all_software.py index f7df18ae..02464be4 100644 --- a/examples/get_all_groups_using_all_software.py +++ b/examples/get_all_groups_using_all_software.py @@ -1,8 +1,11 @@ +import os + from mitreattack.stix20 import MitreAttackData def main(): - mitre_attack_data = MitreAttackData("enterprise-attack.json") + stix_filepath = os.environ.get("STIX_BUNDLE", "enterprise-attack.json") + mitre_attack_data = MitreAttackData(stix_filepath=stix_filepath) # get all groups related to software all_groups_using_all_software = mitre_attack_data.get_all_groups_using_all_software() diff --git a/examples/get_all_groups_using_all_techniques.py b/examples/get_all_groups_using_all_techniques.py index d15ba3ae..28b2e64b 100644 --- a/examples/get_all_groups_using_all_techniques.py +++ b/examples/get_all_groups_using_all_techniques.py @@ -1,8 +1,11 @@ +import os + from mitreattack.stix20 import MitreAttackData def main(): - mitre_attack_data = MitreAttackData("enterprise-attack.json") + stix_filepath = os.environ.get("STIX_BUNDLE", "enterprise-attack.json") + mitre_attack_data = MitreAttackData(stix_filepath=stix_filepath) # get all groups related to techniques groups_using_techniques = mitre_attack_data.get_all_groups_using_all_techniques() diff --git a/examples/get_all_matrices.py b/examples/get_all_matrices.py index 94b5cfee..54e69a16 100644 --- a/examples/get_all_matrices.py +++ b/examples/get_all_matrices.py @@ -1,8 +1,11 @@ +import os + from mitreattack.stix20 import MitreAttackData def main(): - mitre_attack_data = MitreAttackData("enterprise-attack.json") + stix_filepath = os.environ.get("STIX_BUNDLE", "enterprise-attack.json") + mitre_attack_data = MitreAttackData(stix_filepath=stix_filepath) matrices = mitre_attack_data.get_matrices(remove_revoked_deprecated=True) diff --git a/examples/get_all_mitigations.py b/examples/get_all_mitigations.py index 3b850a11..cddf2fe2 100644 --- a/examples/get_all_mitigations.py +++ b/examples/get_all_mitigations.py @@ -1,8 +1,11 @@ +import os + from mitreattack.stix20 import MitreAttackData def main(): - mitre_attack_data = MitreAttackData("enterprise-attack.json") + stix_filepath = os.environ.get("STIX_BUNDLE", "enterprise-attack.json") + mitre_attack_data = MitreAttackData(stix_filepath=stix_filepath) mitigations = mitre_attack_data.get_mitigations(remove_revoked_deprecated=True) diff --git a/examples/get_all_mitigations_mitigating_all_techniques.py b/examples/get_all_mitigations_mitigating_all_techniques.py index 3ee5cf55..f09a075c 100644 --- a/examples/get_all_mitigations_mitigating_all_techniques.py +++ b/examples/get_all_mitigations_mitigating_all_techniques.py @@ -1,8 +1,11 @@ +import os + from mitreattack.stix20 import MitreAttackData def main(): - mitre_attack_data = MitreAttackData("enterprise-attack.json") + stix_filepath = os.environ.get("STIX_BUNDLE", "enterprise-attack.json") + mitre_attack_data = MitreAttackData(stix_filepath=stix_filepath) # get all mitigations related to techniques mitigations_mitigating = mitre_attack_data.get_all_mitigations_mitigating_all_techniques() diff --git a/examples/get_all_parent_techniques.py b/examples/get_all_parent_techniques.py index 12cea975..bd6bb5ae 100644 --- a/examples/get_all_parent_techniques.py +++ b/examples/get_all_parent_techniques.py @@ -1,8 +1,11 @@ +import os + from mitreattack.stix20 import MitreAttackData def main(): - mitre_attack_data = MitreAttackData("enterprise-attack.json") + stix_filepath = os.environ.get("STIX_BUNDLE", "enterprise-attack.json") + mitre_attack_data = MitreAttackData(stix_filepath=stix_filepath) parent_techniques = mitre_attack_data.get_techniques(include_subtechniques=False, remove_revoked_deprecated=True) diff --git a/examples/get_all_parent_techniques_of_all_subtechniques.py b/examples/get_all_parent_techniques_of_all_subtechniques.py index 5b1707e6..de956a9d 100644 --- a/examples/get_all_parent_techniques_of_all_subtechniques.py +++ b/examples/get_all_parent_techniques_of_all_subtechniques.py @@ -1,8 +1,11 @@ +import os + from mitreattack.stix20 import MitreAttackData def main(): - mitre_attack_data = MitreAttackData("enterprise-attack.json") + stix_filepath = os.environ.get("STIX_BUNDLE", "enterprise-attack.json") + mitre_attack_data = MitreAttackData(stix_filepath=stix_filepath) # get parent techniques of sub-techniques parent_techniques = mitre_attack_data.get_all_parent_techniques_of_all_subtechniques() diff --git a/examples/get_all_software.py b/examples/get_all_software.py index b91a6c01..92894af0 100644 --- a/examples/get_all_software.py +++ b/examples/get_all_software.py @@ -1,8 +1,11 @@ +import os + from mitreattack.stix20 import MitreAttackData def main(): - mitre_attack_data = MitreAttackData("enterprise-attack.json") + stix_filepath = os.environ.get("STIX_BUNDLE", "enterprise-attack.json") + mitre_attack_data = MitreAttackData(stix_filepath=stix_filepath) software = mitre_attack_data.get_software(remove_revoked_deprecated=True) diff --git a/examples/get_all_software_used_by_all_campaigns.py b/examples/get_all_software_used_by_all_campaigns.py index 8b002460..530e195e 100644 --- a/examples/get_all_software_used_by_all_campaigns.py +++ b/examples/get_all_software_used_by_all_campaigns.py @@ -1,8 +1,11 @@ +import os + from mitreattack.stix20 import MitreAttackData def main(): - mitre_attack_data = MitreAttackData("enterprise-attack.json") + stix_filepath = os.environ.get("STIX_BUNDLE", "enterprise-attack.json") + mitre_attack_data = MitreAttackData(stix_filepath=stix_filepath) # get all software related to campaigns software_used_by_campaigns = mitre_attack_data.get_all_software_used_by_all_campaigns() diff --git a/examples/get_all_software_used_by_all_groups.py b/examples/get_all_software_used_by_all_groups.py index 87bef3f5..3fbe559b 100644 --- a/examples/get_all_software_used_by_all_groups.py +++ b/examples/get_all_software_used_by_all_groups.py @@ -1,8 +1,11 @@ +import os + from mitreattack.stix20 import MitreAttackData def main(): - mitre_attack_data = MitreAttackData("enterprise-attack.json") + stix_filepath = os.environ.get("STIX_BUNDLE", "enterprise-attack.json") + mitre_attack_data = MitreAttackData(stix_filepath=stix_filepath) # get all software related to groups all_software_used_by_all_groups = mitre_attack_data.get_all_software_used_by_all_groups() diff --git a/examples/get_all_software_using_all_techniques.py b/examples/get_all_software_using_all_techniques.py index 9f7f2779..913da0fe 100644 --- a/examples/get_all_software_using_all_techniques.py +++ b/examples/get_all_software_using_all_techniques.py @@ -1,8 +1,11 @@ +import os + from mitreattack.stix20 import MitreAttackData def main(): - mitre_attack_data = MitreAttackData("enterprise-attack.json") + stix_filepath = os.environ.get("STIX_BUNDLE", "enterprise-attack.json") + mitre_attack_data = MitreAttackData(stix_filepath=stix_filepath) # get all software related to techniques software_using_techniques = mitre_attack_data.get_all_software_using_all_techniques() diff --git a/examples/get_all_subtechniques.py b/examples/get_all_subtechniques.py index b163d8aa..f1fa136c 100644 --- a/examples/get_all_subtechniques.py +++ b/examples/get_all_subtechniques.py @@ -1,8 +1,11 @@ +import os + from mitreattack.stix20 import MitreAttackData def main(): - mitre_attack_data = MitreAttackData("enterprise-attack.json") + stix_filepath = os.environ.get("STIX_BUNDLE", "enterprise-attack.json") + mitre_attack_data = MitreAttackData(stix_filepath=stix_filepath) subtechniques = mitre_attack_data.get_subtechniques(remove_revoked_deprecated=True) diff --git a/examples/get_all_subtechniques_of_all_techniques.py b/examples/get_all_subtechniques_of_all_techniques.py index 3c2aeab6..75bcc048 100644 --- a/examples/get_all_subtechniques_of_all_techniques.py +++ b/examples/get_all_subtechniques_of_all_techniques.py @@ -1,8 +1,11 @@ +import os + from mitreattack.stix20 import MitreAttackData def main(): - mitre_attack_data = MitreAttackData("enterprise-attack.json") + stix_filepath = os.environ.get("STIX_BUNDLE", "enterprise-attack.json") + mitre_attack_data = MitreAttackData(stix_filepath=stix_filepath) # get subtechniques of techniques subtechniques = mitre_attack_data.get_all_subtechniques_of_all_techniques() diff --git a/examples/get_all_tactics.py b/examples/get_all_tactics.py index 56d08541..238db983 100644 --- a/examples/get_all_tactics.py +++ b/examples/get_all_tactics.py @@ -1,8 +1,11 @@ +import os + from mitreattack.stix20 import MitreAttackData def main(): - mitre_attack_data = MitreAttackData("enterprise-attack.json") + stix_filepath = os.environ.get("STIX_BUNDLE", "enterprise-attack.json") + mitre_attack_data = MitreAttackData(stix_filepath=stix_filepath) tactics = mitre_attack_data.get_tactics(remove_revoked_deprecated=True) diff --git a/examples/get_all_techniques.py b/examples/get_all_techniques.py index 6b6fb905..f1ea9612 100644 --- a/examples/get_all_techniques.py +++ b/examples/get_all_techniques.py @@ -1,8 +1,11 @@ +import os + from mitreattack.stix20 import MitreAttackData def main(): - mitre_attack_data = MitreAttackData("enterprise-attack.json") + stix_filepath = os.environ.get("STIX_BUNDLE", "enterprise-attack.json") + mitre_attack_data = MitreAttackData(stix_filepath=stix_filepath) techniques = mitre_attack_data.get_techniques(remove_revoked_deprecated=True) diff --git a/examples/get_all_techniques_detected_by_all_datacomponents.py b/examples/get_all_techniques_detected_by_all_datacomponents.py index 959cc60d..0968eccc 100644 --- a/examples/get_all_techniques_detected_by_all_datacomponents.py +++ b/examples/get_all_techniques_detected_by_all_datacomponents.py @@ -1,8 +1,11 @@ +import os + from mitreattack.stix20 import MitreAttackData def main(): - mitre_attack_data = MitreAttackData("enterprise-attack.json") + stix_filepath = os.environ.get("STIX_BUNDLE", "enterprise-attack.json") + mitre_attack_data = MitreAttackData(stix_filepath=stix_filepath) # get all techniques related to data components techniques_detected = mitre_attack_data.get_all_techniques_detected_by_all_datacomponents() diff --git a/examples/get_all_techniques_mitigated_by_all_mitigations.py b/examples/get_all_techniques_mitigated_by_all_mitigations.py index 58ee57f8..5feb2ed3 100644 --- a/examples/get_all_techniques_mitigated_by_all_mitigations.py +++ b/examples/get_all_techniques_mitigated_by_all_mitigations.py @@ -1,8 +1,11 @@ +import os + from mitreattack.stix20 import MitreAttackData def main(): - mitre_attack_data = MitreAttackData("enterprise-attack.json") + stix_filepath = os.environ.get("STIX_BUNDLE", "enterprise-attack.json") + mitre_attack_data = MitreAttackData(stix_filepath=stix_filepath) # get all techniques related to mitigations techniques_mitigated = mitre_attack_data.get_all_techniques_mitigated_by_all_mitigations() diff --git a/examples/get_all_techniques_targeting_all_assets.py b/examples/get_all_techniques_targeting_all_assets.py index 376ea21a..4227385f 100644 --- a/examples/get_all_techniques_targeting_all_assets.py +++ b/examples/get_all_techniques_targeting_all_assets.py @@ -1,8 +1,11 @@ +import os + from mitreattack.stix20 import MitreAttackData def main(): - mitre_attack_data = MitreAttackData("ics-attack.json") + stix_filepath = os.environ.get("STIX_BUNDLE", "ics-attack.json") + mitre_attack_data = MitreAttackData(stix_filepath=stix_filepath) techniques_targeting_assets = mitre_attack_data.get_all_techniques_targeting_all_assets() diff --git a/examples/get_all_techniques_used_by_all_campaigns.py b/examples/get_all_techniques_used_by_all_campaigns.py index 3dc9bf72..acd8d93d 100644 --- a/examples/get_all_techniques_used_by_all_campaigns.py +++ b/examples/get_all_techniques_used_by_all_campaigns.py @@ -1,8 +1,11 @@ +import os + from mitreattack.stix20 import MitreAttackData def main(): - mitre_attack_data = MitreAttackData("enterprise-attack.json") + stix_filepath = os.environ.get("STIX_BUNDLE", "enterprise-attack.json") + mitre_attack_data = MitreAttackData(stix_filepath=stix_filepath) # get all techniques related to campaigns techniques_used_by_campaigns = mitre_attack_data.get_all_techniques_used_by_all_campaigns() diff --git a/examples/get_all_techniques_used_by_all_groups.py b/examples/get_all_techniques_used_by_all_groups.py index 77a19be9..6d4ef85f 100644 --- a/examples/get_all_techniques_used_by_all_groups.py +++ b/examples/get_all_techniques_used_by_all_groups.py @@ -1,8 +1,11 @@ +import os + from mitreattack.stix20 import MitreAttackData def main(): - mitre_attack_data = MitreAttackData("enterprise-attack.json") + stix_filepath = os.environ.get("STIX_BUNDLE", "enterprise-attack.json") + mitre_attack_data = MitreAttackData(stix_filepath=stix_filepath) # get all techniques related to groups techniques_used_by_groups = mitre_attack_data.get_all_techniques_used_by_all_groups() diff --git a/examples/get_all_techniques_used_by_all_software.py b/examples/get_all_techniques_used_by_all_software.py index 0afa6303..86515cb0 100644 --- a/examples/get_all_techniques_used_by_all_software.py +++ b/examples/get_all_techniques_used_by_all_software.py @@ -1,8 +1,11 @@ +import os + from mitreattack.stix20 import MitreAttackData def main(): - mitre_attack_data = MitreAttackData("enterprise-attack.json") + stix_filepath = os.environ.get("STIX_BUNDLE", "enterprise-attack.json") + mitre_attack_data = MitreAttackData(stix_filepath=stix_filepath) # get all techniques related to software techniques_used_by_software = mitre_attack_data.get_all_techniques_used_by_all_software() diff --git a/examples/get_assets_targeted_by_technique.py b/examples/get_assets_targeted_by_technique.py index a16634f8..990b0fb5 100644 --- a/examples/get_assets_targeted_by_technique.py +++ b/examples/get_assets_targeted_by_technique.py @@ -1,8 +1,11 @@ +import os + from mitreattack.stix20 import MitreAttackData def main(): - mitre_attack_data = MitreAttackData("ics-attack.json") + stix_filepath = os.environ.get("STIX_BUNDLE", "ics-attack.json") + mitre_attack_data = MitreAttackData(stix_filepath=stix_filepath) # get assets targeted by T0806 technique_stix_id = "attack-pattern--8e7089d3-fba2-44f8-94a8-9a79c53920c4" diff --git a/examples/get_attack_id.py b/examples/get_attack_id.py index 209d9089..97f1cbb4 100644 --- a/examples/get_attack_id.py +++ b/examples/get_attack_id.py @@ -1,8 +1,11 @@ +import os + from mitreattack.stix20 import MitreAttackData def main(): - mitre_attack_data = MitreAttackData("enterprise-attack.json") + stix_filepath = os.environ.get("STIX_BUNDLE", "enterprise-attack.json") + mitre_attack_data = MitreAttackData(stix_filepath=stix_filepath) attack_id = mitre_attack_data.get_attack_id("intrusion-set--f40eb8ce-2a74-4e56-89a1-227021410142") diff --git a/examples/get_campaigns_attributed_to_group.py b/examples/get_campaigns_attributed_to_group.py index 5f5c400e..ca4d058a 100644 --- a/examples/get_campaigns_attributed_to_group.py +++ b/examples/get_campaigns_attributed_to_group.py @@ -1,8 +1,11 @@ +import os + from mitreattack.stix20 import MitreAttackData def main(): - mitre_attack_data = MitreAttackData("enterprise-attack.json") + stix_filepath = os.environ.get("STIX_BUNDLE", "enterprise-attack.json") + mitre_attack_data = MitreAttackData(stix_filepath=stix_filepath) # get campaigns related to G0134 group_stix_id = "intrusion-set--e44e0985-bc65-4a8f-b578-211c858128e3" diff --git a/examples/get_campaigns_by_alias.py b/examples/get_campaigns_by_alias.py index c37de79c..ee33d478 100644 --- a/examples/get_campaigns_by_alias.py +++ b/examples/get_campaigns_by_alias.py @@ -1,8 +1,11 @@ +import os + from mitreattack.stix20 import MitreAttackData def main(): - mitre_attack_data = MitreAttackData("enterprise-attack.json") + stix_filepath = os.environ.get("STIX_BUNDLE", "enterprise-attack.json") + mitre_attack_data = MitreAttackData(stix_filepath=stix_filepath) campaigns = mitre_attack_data.get_campaigns_by_alias("Frankenstein") diff --git a/examples/get_campaigns_using_software.py b/examples/get_campaigns_using_software.py index ef4e2027..424241d8 100644 --- a/examples/get_campaigns_using_software.py +++ b/examples/get_campaigns_using_software.py @@ -1,8 +1,11 @@ +import os + from mitreattack.stix20 import MitreAttackData def main(): - mitre_attack_data = MitreAttackData("enterprise-attack.json") + stix_filepath = os.environ.get("STIX_BUNDLE", "enterprise-attack.json") + mitre_attack_data = MitreAttackData(stix_filepath=stix_filepath) # get campaigns related to S0096 software_stix_id = "tool--7fcbc4e8-1989-441f-9ac5-e7b6ff5806f1" diff --git a/examples/get_campaigns_using_technique.py b/examples/get_campaigns_using_technique.py index 14041407..fd9ec5f5 100644 --- a/examples/get_campaigns_using_technique.py +++ b/examples/get_campaigns_using_technique.py @@ -1,8 +1,11 @@ +import os + from mitreattack.stix20 import MitreAttackData def main(): - mitre_attack_data = MitreAttackData("enterprise-attack.json") + stix_filepath = os.environ.get("STIX_BUNDLE", "enterprise-attack.json") + mitre_attack_data = MitreAttackData(stix_filepath=stix_filepath) # get campaigns related to T1049 technique_stix_id = "attack-pattern--7e150503-88e7-4861-866b-ff1ac82c4475" diff --git a/examples/get_datacomponents_detecting_technique.py b/examples/get_datacomponents_detecting_technique.py index e07fc018..1b4ddbd5 100644 --- a/examples/get_datacomponents_detecting_technique.py +++ b/examples/get_datacomponents_detecting_technique.py @@ -1,8 +1,11 @@ +import os + from mitreattack.stix20 import MitreAttackData def main(): - mitre_attack_data = MitreAttackData("enterprise-attack.json") + stix_filepath = os.environ.get("STIX_BUNDLE", "enterprise-attack.json") + mitre_attack_data = MitreAttackData(stix_filepath=stix_filepath) # get data components detecting T1112 technique_stix_id = "attack-pattern--57340c81-c025-4189-8fa0-fc7ede51bae4" diff --git a/examples/get_groups_attributing_to_campaign.py b/examples/get_groups_attributing_to_campaign.py index 23230a00..c22beddc 100644 --- a/examples/get_groups_attributing_to_campaign.py +++ b/examples/get_groups_attributing_to_campaign.py @@ -1,8 +1,11 @@ +import os + from mitreattack.stix20 import MitreAttackData def main(): - mitre_attack_data = MitreAttackData("enterprise-attack.json") + stix_filepath = os.environ.get("STIX_BUNDLE", "enterprise-attack.json") + mitre_attack_data = MitreAttackData(stix_filepath=stix_filepath) # get groups related to C0011 campaign_stix_id = "campaign--b4e5a4a9-f3be-4631-ba8f-da6ebb067fac" diff --git a/examples/get_groups_by_alias.py b/examples/get_groups_by_alias.py index 6ffce3a0..a1ebd21e 100644 --- a/examples/get_groups_by_alias.py +++ b/examples/get_groups_by_alias.py @@ -1,8 +1,11 @@ +import os + from mitreattack.stix20 import MitreAttackData def main(): - mitre_attack_data = MitreAttackData("enterprise-attack.json") + stix_filepath = os.environ.get("STIX_BUNDLE", "enterprise-attack.json") + mitre_attack_data = MitreAttackData(stix_filepath=stix_filepath) groups = mitre_attack_data.get_groups_by_alias("Cozy Bear") diff --git a/examples/get_groups_using_software.py b/examples/get_groups_using_software.py index d4ffa73d..3dcfb22d 100644 --- a/examples/get_groups_using_software.py +++ b/examples/get_groups_using_software.py @@ -1,8 +1,11 @@ +import os + from mitreattack.stix20 import MitreAttackData def main(): - mitre_attack_data = MitreAttackData("enterprise-attack.json") + stix_filepath = os.environ.get("STIX_BUNDLE", "enterprise-attack.json") + mitre_attack_data = MitreAttackData(stix_filepath=stix_filepath) # get groups related to S0349 software_stix_id = "tool--b76b2d94-60e4-4107-a903-4a3a7622fb3b" diff --git a/examples/get_groups_using_technique.py b/examples/get_groups_using_technique.py index 585f80df..4c0d6e68 100644 --- a/examples/get_groups_using_technique.py +++ b/examples/get_groups_using_technique.py @@ -1,8 +1,11 @@ +import os + from mitreattack.stix20 import MitreAttackData def main(): - mitre_attack_data = MitreAttackData("enterprise-attack.json") + stix_filepath = os.environ.get("STIX_BUNDLE", "enterprise-attack.json") + mitre_attack_data = MitreAttackData(stix_filepath=stix_filepath) # get groups related to T1014 technique_stix_id = "attack-pattern--0f20e3cb-245b-4a61-8a91-2d93f7cb0e9b" diff --git a/examples/get_mitigations_mitigating_technique.py b/examples/get_mitigations_mitigating_technique.py index 6f298760..5fe147e5 100644 --- a/examples/get_mitigations_mitigating_technique.py +++ b/examples/get_mitigations_mitigating_technique.py @@ -1,8 +1,11 @@ +import os + from mitreattack.stix20 import MitreAttackData def main(): - mitre_attack_data = MitreAttackData("enterprise-attack.json") + stix_filepath = os.environ.get("STIX_BUNDLE", "enterprise-attack.json") + mitre_attack_data = MitreAttackData(stix_filepath=stix_filepath) # get groups related to T1014 technique_stix_id = "attack-pattern--0f20e3cb-245b-4a61-8a91-2d93f7cb0e9b" diff --git a/examples/get_name.py b/examples/get_name.py index 99225fdc..219a2031 100644 --- a/examples/get_name.py +++ b/examples/get_name.py @@ -1,8 +1,11 @@ +import os + from mitreattack.stix20 import MitreAttackData def main(): - mitre_attack_data = MitreAttackData("enterprise-attack.json") + stix_filepath = os.environ.get("STIX_BUNDLE", "enterprise-attack.json") + mitre_attack_data = MitreAttackData(stix_filepath=stix_filepath) stix_id = "intrusion-set--f40eb8ce-2a74-4e56-89a1-227021410142" object_name = mitre_attack_data.get_name(stix_id) diff --git a/examples/get_object_by_attack_id.py b/examples/get_object_by_attack_id.py index ec684d1b..3b0eaa8f 100644 --- a/examples/get_object_by_attack_id.py +++ b/examples/get_object_by_attack_id.py @@ -1,8 +1,11 @@ +import os + from mitreattack.stix20 import MitreAttackData def main(): - mitre_attack_data = MitreAttackData("enterprise-attack.json") + stix_filepath = os.environ.get("STIX_BUNDLE", "enterprise-attack.json") + mitre_attack_data = MitreAttackData(stix_filepath=stix_filepath) T1134 = mitre_attack_data.get_object_by_attack_id("T1134", "attack-pattern") diff --git a/examples/get_object_by_stix_id.py b/examples/get_object_by_stix_id.py index 834b9561..97a5796a 100644 --- a/examples/get_object_by_stix_id.py +++ b/examples/get_object_by_stix_id.py @@ -1,8 +1,11 @@ +import os + from mitreattack.stix20 import MitreAttackData def main(): - mitre_attack_data = MitreAttackData("enterprise-attack.json") + stix_filepath = os.environ.get("STIX_BUNDLE", "enterprise-attack.json") + mitre_attack_data = MitreAttackData(stix_filepath=stix_filepath) G0075 = mitre_attack_data.get_object_by_stix_id("intrusion-set--f40eb8ce-2a74-4e56-89a1-227021410142") diff --git a/examples/get_objects_by_content.py b/examples/get_objects_by_content.py index 183483d6..d989949b 100644 --- a/examples/get_objects_by_content.py +++ b/examples/get_objects_by_content.py @@ -1,8 +1,11 @@ +import os + from mitreattack.stix20 import MitreAttackData def main(): - mitre_attack_data = MitreAttackData("enterprise-attack.json") + stix_filepath = os.environ.get("STIX_BUNDLE", "enterprise-attack.json") + mitre_attack_data = MitreAttackData(stix_filepath=stix_filepath) # retrieve techniques by the content of their description techniques = mitre_attack_data.get_objects_by_content("LSASS", "attack-pattern", remove_revoked_deprecated=True) diff --git a/examples/get_objects_by_name.py b/examples/get_objects_by_name.py index 4c93485f..4028730d 100644 --- a/examples/get_objects_by_name.py +++ b/examples/get_objects_by_name.py @@ -1,8 +1,11 @@ +import os + from mitreattack.stix20 import MitreAttackData def main(): - mitre_attack_data = MitreAttackData("enterprise-attack.json") + stix_filepath = os.environ.get("STIX_BUNDLE", "enterprise-attack.json") + mitre_attack_data = MitreAttackData(stix_filepath=stix_filepath) techniques = mitre_attack_data.get_objects_by_name("System Information Discovery", "attack-pattern") diff --git a/examples/get_objects_by_type.py b/examples/get_objects_by_type.py index 0f4f5c53..bd1adcae 100644 --- a/examples/get_objects_by_type.py +++ b/examples/get_objects_by_type.py @@ -1,8 +1,11 @@ +import os + from mitreattack.stix20 import MitreAttackData def main(): - mitre_attack_data = MitreAttackData("enterprise-attack.json") + stix_filepath = os.environ.get("STIX_BUNDLE", "enterprise-attack.json") + mitre_attack_data = MitreAttackData(stix_filepath=stix_filepath) techniques = mitre_attack_data.get_objects_by_type("attack-pattern", remove_revoked_deprecated=True) diff --git a/examples/get_objects_created_after.py b/examples/get_objects_created_after.py index 358cceb4..acc58a3e 100644 --- a/examples/get_objects_created_after.py +++ b/examples/get_objects_created_after.py @@ -1,8 +1,11 @@ +import os + from mitreattack.stix20 import MitreAttackData def main(): - mitre_attack_data = MitreAttackData("enterprise-attack.json") + stix_filepath = os.environ.get("STIX_BUNDLE", "enterprise-attack.json") + mitre_attack_data = MitreAttackData(stix_filepath=stix_filepath) objects = mitre_attack_data.get_objects_created_after("2022-10-01T00:00:00.000Z") diff --git a/examples/get_objects_modified_after.py b/examples/get_objects_modified_after.py index 4ec9f258..208421e6 100644 --- a/examples/get_objects_modified_after.py +++ b/examples/get_objects_modified_after.py @@ -1,8 +1,11 @@ +import os + from mitreattack.stix20 import MitreAttackData def main(): - mitre_attack_data = MitreAttackData("enterprise-attack.json") + stix_filepath = os.environ.get("STIX_BUNDLE", "enterprise-attack.json") + mitre_attack_data = MitreAttackData(stix_filepath=stix_filepath) date = "2022-10-01" objects = mitre_attack_data.get_objects_modified_after(date) diff --git a/examples/get_parent_technique_of_subtechnique.py b/examples/get_parent_technique_of_subtechnique.py index c6a06116..504fbff7 100644 --- a/examples/get_parent_technique_of_subtechnique.py +++ b/examples/get_parent_technique_of_subtechnique.py @@ -1,8 +1,11 @@ +import os + from mitreattack.stix20 import MitreAttackData def main(): - mitre_attack_data = MitreAttackData("enterprise-attack.json") + stix_filepath = os.environ.get("STIX_BUNDLE", "enterprise-attack.json") + mitre_attack_data = MitreAttackData(stix_filepath=stix_filepath) # get parent technique of T1195.002 subtechnique_stix_id = "attack-pattern--bd369cd9-abb8-41ce-b5bb-fff23ee86c00" diff --git a/examples/get_procedure_examples_by_tactic.py b/examples/get_procedure_examples_by_tactic.py index 0de3091a..0d06a3d4 100644 --- a/examples/get_procedure_examples_by_tactic.py +++ b/examples/get_procedure_examples_by_tactic.py @@ -1,3 +1,5 @@ +import os + from mitreattack.stix20 import MitreAttackData @@ -12,7 +14,9 @@ def print_procedure_examples(mitre_attack_data, attack_objects_using_technique): def main(): - mitre_attack_data = MitreAttackData("enterprise-attack.json") + stix_filepath = os.environ.get("STIX_BUNDLE", "enterprise-attack.json") + + mitre_attack_data = MitreAttackData(stix_filepath=stix_filepath) tactics = mitre_attack_data.get_tactics(remove_revoked_deprecated=True) for tactic in tactics: diff --git a/examples/get_procedure_examples_by_technique.py b/examples/get_procedure_examples_by_technique.py index f9d6bf83..d65245ff 100644 --- a/examples/get_procedure_examples_by_technique.py +++ b/examples/get_procedure_examples_by_technique.py @@ -1,8 +1,11 @@ +import os + from mitreattack.stix20 import MitreAttackData def main(): - mitre_attack_data = MitreAttackData("enterprise-attack.json") + stix_filepath = os.environ.get("STIX_BUNDLE", "enterprise-attack.json") + mitre_attack_data = MitreAttackData(stix_filepath=stix_filepath) technique_id = "attack-pattern--03259939-0b57-482f-8eb5-87c0e0d54334" procedure_examples = mitre_attack_data.get_procedure_examples_by_technique(technique_id) diff --git a/examples/get_revoked_techniques.py b/examples/get_revoked_techniques.py index 0f7786f6..7893916d 100644 --- a/examples/get_revoked_techniques.py +++ b/examples/get_revoked_techniques.py @@ -1,8 +1,11 @@ +import os + from mitreattack.stix20 import MitreAttackData def main(): - mitre_attack_data = MitreAttackData("enterprise-attack.json") + stix_filepath = os.environ.get("STIX_BUNDLE", "enterprise-attack.json") + mitre_attack_data = MitreAttackData(stix_filepath=stix_filepath) techniques = mitre_attack_data.get_techniques() for technique in techniques: diff --git a/examples/get_software_by_alias.py b/examples/get_software_by_alias.py index 81082890..6351769e 100644 --- a/examples/get_software_by_alias.py +++ b/examples/get_software_by_alias.py @@ -1,8 +1,11 @@ +import os + from mitreattack.stix20 import MitreAttackData def main(): - mitre_attack_data = MitreAttackData("enterprise-attack.json") + stix_filepath = os.environ.get("STIX_BUNDLE", "enterprise-attack.json") + mitre_attack_data = MitreAttackData(stix_filepath=stix_filepath) software = mitre_attack_data.get_software_by_alias("ShellTea") diff --git a/examples/get_software_used_by_campaign.py b/examples/get_software_used_by_campaign.py index f524e897..de1f783f 100644 --- a/examples/get_software_used_by_campaign.py +++ b/examples/get_software_used_by_campaign.py @@ -1,8 +1,11 @@ +import os + from mitreattack.stix20 import MitreAttackData def main(): - mitre_attack_data = MitreAttackData("enterprise-attack.json") + stix_filepath = os.environ.get("STIX_BUNDLE", "enterprise-attack.json") + mitre_attack_data = MitreAttackData(stix_filepath=stix_filepath) # get software used by C0007 campaign_stix_id = "campaign--8d2bc130-89fe-466e-a4f9-6bce6129c2b8" diff --git a/examples/get_software_used_by_group.py b/examples/get_software_used_by_group.py index 79f6f0f3..6ea4938b 100644 --- a/examples/get_software_used_by_group.py +++ b/examples/get_software_used_by_group.py @@ -1,8 +1,11 @@ +import os + from mitreattack.stix20 import MitreAttackData def main(): - mitre_attack_data = MitreAttackData("enterprise-attack.json") + stix_filepath = os.environ.get("STIX_BUNDLE", "enterprise-attack.json") + mitre_attack_data = MitreAttackData(stix_filepath=stix_filepath) # get software used by G0019 group_stix_id = "intrusion-set--2a158b0a-7ef8-43cb-9985-bf34d1e12050" diff --git a/examples/get_software_using_technique.py b/examples/get_software_using_technique.py index 1c3be8bf..8a2179cd 100644 --- a/examples/get_software_using_technique.py +++ b/examples/get_software_using_technique.py @@ -1,8 +1,11 @@ +import os + from mitreattack.stix20 import MitreAttackData def main(): - mitre_attack_data = MitreAttackData("enterprise-attack.json") + stix_filepath = os.environ.get("STIX_BUNDLE", "enterprise-attack.json") + mitre_attack_data = MitreAttackData(stix_filepath=stix_filepath) # get software related to T1014 technique_stix_id = "attack-pattern--0f20e3cb-245b-4a61-8a91-2d93f7cb0e9b" diff --git a/examples/get_stix_type.py b/examples/get_stix_type.py index 5c077fb1..2549f1e4 100644 --- a/examples/get_stix_type.py +++ b/examples/get_stix_type.py @@ -1,8 +1,11 @@ +import os + from mitreattack.stix20 import MitreAttackData def main(): - mitre_attack_data = MitreAttackData("enterprise-attack.json") + stix_filepath = os.environ.get("STIX_BUNDLE", "enterprise-attack.json") + mitre_attack_data = MitreAttackData(stix_filepath=stix_filepath) stix_id = "intrusion-set--f40eb8ce-2a74-4e56-89a1-227021410142" object_type = mitre_attack_data.get_stix_type(stix_id) diff --git a/examples/get_subtechniques_of_technique.py b/examples/get_subtechniques_of_technique.py index 7cbfd7ce..b08b9b6a 100644 --- a/examples/get_subtechniques_of_technique.py +++ b/examples/get_subtechniques_of_technique.py @@ -1,8 +1,11 @@ +import os + from mitreattack.stix20 import MitreAttackData def main(): - mitre_attack_data = MitreAttackData("enterprise-attack.json") + stix_filepath = os.environ.get("STIX_BUNDLE", "enterprise-attack.json") + mitre_attack_data = MitreAttackData(stix_filepath=stix_filepath) # get the subtechniques of T1195 technique_stix_id = "attack-pattern--3f18edba-28f4-4bb9-82c3-8aa60dcac5f7" diff --git a/examples/get_tactics_by_matrix.py b/examples/get_tactics_by_matrix.py index 569ab7df..ec3e7131 100644 --- a/examples/get_tactics_by_matrix.py +++ b/examples/get_tactics_by_matrix.py @@ -1,8 +1,11 @@ +import os + from mitreattack.stix20 import MitreAttackData def main(): - mitre_attack_data = MitreAttackData("enterprise-attack.json") + stix_filepath = os.environ.get("STIX_BUNDLE", "enterprise-attack.json") + mitre_attack_data = MitreAttackData(stix_filepath=stix_filepath) tactics_map = mitre_attack_data.get_tactics_by_matrix() diff --git a/examples/get_tactics_by_technique.py b/examples/get_tactics_by_technique.py index 1f1aa8ff..c29df853 100644 --- a/examples/get_tactics_by_technique.py +++ b/examples/get_tactics_by_technique.py @@ -1,8 +1,11 @@ +import os + from mitreattack.stix20 import MitreAttackData def main(): - mitre_attack_data = MitreAttackData("enterprise-attack.json") + stix_filepath = os.environ.get("STIX_BUNDLE", "enterprise-attack.json") + mitre_attack_data = MitreAttackData(stix_filepath=stix_filepath) technique_id = "attack-pattern--7e150503-88e7-4861-866b-ff1ac82c4475" tactics = mitre_attack_data.get_tactics_by_technique(technique_id) diff --git a/examples/get_techniques_by_platform.py b/examples/get_techniques_by_platform.py index 2711d5f3..79f0c0aa 100644 --- a/examples/get_techniques_by_platform.py +++ b/examples/get_techniques_by_platform.py @@ -1,8 +1,11 @@ +import os + from mitreattack.stix20 import MitreAttackData def main(): - mitre_attack_data = MitreAttackData("enterprise-attack.json") + stix_filepath = os.environ.get("STIX_BUNDLE", "enterprise-attack.json") + mitre_attack_data = MitreAttackData(stix_filepath=stix_filepath) techniques = mitre_attack_data.get_techniques_by_platform("Windows", remove_revoked_deprecated=True) diff --git a/examples/get_techniques_by_tactic.py b/examples/get_techniques_by_tactic.py index 6a262d4a..5ae35c69 100644 --- a/examples/get_techniques_by_tactic.py +++ b/examples/get_techniques_by_tactic.py @@ -1,8 +1,11 @@ +import os + from mitreattack.stix20 import MitreAttackData def main(): - mitre_attack_data = MitreAttackData("enterprise-attack.json") + stix_filepath = os.environ.get("STIX_BUNDLE", "enterprise-attack.json") + mitre_attack_data = MitreAttackData(stix_filepath=stix_filepath) techniques = mitre_attack_data.get_techniques_by_tactic( "defense-evasion", "enterprise-attack", remove_revoked_deprecated=True diff --git a/examples/get_techniques_detected_by_datacomponent.py b/examples/get_techniques_detected_by_datacomponent.py index 11e48daf..c547b5b0 100644 --- a/examples/get_techniques_detected_by_datacomponent.py +++ b/examples/get_techniques_detected_by_datacomponent.py @@ -1,8 +1,11 @@ +import os + from mitreattack.stix20 import MitreAttackData def main(): - mitre_attack_data = MitreAttackData("enterprise-attack.json") + stix_filepath = os.environ.get("STIX_BUNDLE", "enterprise-attack.json") + mitre_attack_data = MitreAttackData(stix_filepath=stix_filepath) # get techniques detected by Certificate: Certificate Registration datacomponent_stix_id = "x-mitre-data-component--1dad5aa4-4bb5-45e4-9e42-55d40003cfa6" diff --git a/examples/get_techniques_mitigated_by_mitigation.py b/examples/get_techniques_mitigated_by_mitigation.py index 4353d1d3..ebcccc86 100644 --- a/examples/get_techniques_mitigated_by_mitigation.py +++ b/examples/get_techniques_mitigated_by_mitigation.py @@ -1,8 +1,11 @@ +import os + from mitreattack.stix20 import MitreAttackData def main(): - mitre_attack_data = MitreAttackData("enterprise-attack.json") + stix_filepath = os.environ.get("STIX_BUNDLE", "enterprise-attack.json") + mitre_attack_data = MitreAttackData(stix_filepath=stix_filepath) # get techniques mitigated by M1020 mitigation_stix_id = "course-of-action--7bb5fae9-53ad-4424-866b-f0ea2a8b731d" diff --git a/examples/get_techniques_targeting_asset.py b/examples/get_techniques_targeting_asset.py index 2886016e..b807cd09 100644 --- a/examples/get_techniques_targeting_asset.py +++ b/examples/get_techniques_targeting_asset.py @@ -1,8 +1,11 @@ +import os + from mitreattack.stix20 import MitreAttackData def main(): - mitre_attack_data = MitreAttackData("ics-attack.json") + stix_filepath = os.environ.get("STIX_BUNDLE", "ics-attack.json") + mitre_attack_data = MitreAttackData(stix_filepath=stix_filepath) # get techniques targeting A0004 asset_stix_id = "x-mitre-asset--1769c499-55e5-462f-bab2-c39b8cd5ae32" diff --git a/examples/get_techniques_used_by_campaign.py b/examples/get_techniques_used_by_campaign.py index 6bf34be3..ee54d03a 100644 --- a/examples/get_techniques_used_by_campaign.py +++ b/examples/get_techniques_used_by_campaign.py @@ -1,8 +1,11 @@ +import os + from mitreattack.stix20 import MitreAttackData def main(): - mitre_attack_data = MitreAttackData("enterprise-attack.json") + stix_filepath = os.environ.get("STIX_BUNDLE", "enterprise-attack.json") + mitre_attack_data = MitreAttackData(stix_filepath=stix_filepath) # get techniques used by C0011 campaign_stix_id = "campaign--b4e5a4a9-f3be-4631-ba8f-da6ebb067fac" diff --git a/examples/get_techniques_used_by_group.py b/examples/get_techniques_used_by_group.py index fe3722f5..594bb1e4 100644 --- a/examples/get_techniques_used_by_group.py +++ b/examples/get_techniques_used_by_group.py @@ -1,8 +1,11 @@ +import os + from mitreattack.stix20 import MitreAttackData def main(): - mitre_attack_data = MitreAttackData("enterprise-attack.json") + stix_filepath = os.environ.get("STIX_BUNDLE", "enterprise-attack.json") + mitre_attack_data = MitreAttackData(stix_filepath=stix_filepath) # get techniques used by G0019 group_stix_id = "intrusion-set--2a158b0a-7ef8-43cb-9985-bf34d1e12050" diff --git a/examples/get_techniques_used_by_group_software.py b/examples/get_techniques_used_by_group_software.py index b1efcaf4..9b9d411a 100644 --- a/examples/get_techniques_used_by_group_software.py +++ b/examples/get_techniques_used_by_group_software.py @@ -1,8 +1,11 @@ +import os + from mitreattack.stix20 import MitreAttackData def main(): - mitre_attack_data = MitreAttackData("enterprise-attack.json") + stix_filepath = os.environ.get("STIX_BUNDLE", "enterprise-attack.json") + mitre_attack_data = MitreAttackData(stix_filepath=stix_filepath) # Get techniques used by G0087's software group_stix_id = "intrusion-set--44e43fad-ffcb-4210-abcf-eaaed9735f80" diff --git a/examples/get_techniques_used_by_software.py b/examples/get_techniques_used_by_software.py index 82fe8587..4edd10a7 100644 --- a/examples/get_techniques_used_by_software.py +++ b/examples/get_techniques_used_by_software.py @@ -1,8 +1,11 @@ +import os + from mitreattack.stix20 import MitreAttackData def main(): - mitre_attack_data = MitreAttackData("enterprise-attack.json") + stix_filepath = os.environ.get("STIX_BUNDLE", "enterprise-attack.json") + mitre_attack_data = MitreAttackData(stix_filepath=stix_filepath) # get techniques used by S0349 software_stix_id = "tool--b76b2d94-60e4-4107-a903-4a3a7622fb3b" From 0ec91f376b3771538ee774432d9cd612a6b96eae Mon Sep 17 00:00:00 2001 From: Jared Ondricek Date: Mon, 13 Oct 2025 18:16:58 -0500 Subject: [PATCH 14/29] chore: add script to generate excel files --- examples/generate_excel_files.py | 34 ++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 examples/generate_excel_files.py diff --git a/examples/generate_excel_files.py b/examples/generate_excel_files.py new file mode 100644 index 00000000..3b51f633 --- /dev/null +++ b/examples/generate_excel_files.py @@ -0,0 +1,34 @@ +from mitreattack.attackToExcel import attackToExcel +from stix2 import MemoryStore +import os + +def main(): + # List of domains and version to process + domains = ["enterprise-attack", "mobile-attack", "ics-attack"] + output_dir = "output/" + + # Path to the STIX bundles for each domain (assumes STIX files are downloaded) + stix_base_dir = os.environ.get("STIX_BASE_DIR", "attack-releases/stix-2.0/v17.1") + stix_files = { + "enterprise-attack": os.path.join(stix_base_dir, "enterprise-attack.json"), + "mobile-attack": os.path.join(stix_base_dir, "mobile-attack.json"), + "ics-attack": os.path.join(stix_base_dir, "ics-attack.json"), + } + + for domain in domains: + stix_file = stix_files[domain] + print(f"Exporting {domain} to Excel...") + + # Load STIX data into MemoryStore + mem_store = MemoryStore() + mem_store.load_from_file(stix_file) + + # Export to Excel + attackToExcel.export( + domain=domain, + output_dir=output_dir, + mem_store=mem_store, + ) + +if __name__ == "__main__": + main() From bf4b78a96cf55545d306e9c17d6ee7d32c9f9f40 Mon Sep 17 00:00:00 2001 From: Jared Ondricek Date: Mon, 13 Oct 2025 18:27:00 -0500 Subject: [PATCH 15/29] docs: update readme and license --- LICENSE.txt | 2 +- README.md | 49 +++---------------------------------------------- 2 files changed, 4 insertions(+), 47 deletions(-) diff --git a/LICENSE.txt b/LICENSE.txt index f49a4e16..07c4245a 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright [yyyy] [name of copyright owner] + Copyright [2025] [The MITRE Corporation] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/README.md b/README.md index af297307..26fa0a99 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # mitreattack-python -This repository contains a library of Python tools and utilities for working with ATT&CK data. For more information, -see the [full documentation](https://mitreattack-python.readthedocs.io/) on ReadTheDocs. +This repository contains a library of Python tools and utilities for working with ATT&CK data. +For more information, see the [full documentation](https://mitreattack-python.readthedocs.io/) on ReadTheDocs. ## Install @@ -11,26 +11,12 @@ To use this package, install the mitreattack-python library with [pip](https://p pip install mitreattack-python ``` -Note: the library requires [python3](https://www.python.org/). - ## MitreAttackData Library -The ``MitreAttackData`` library is used to read in and work with MITRE ATT&CK STIX 2.0 content. This library provides +The ``MitreAttackData`` library is used to read in and work with MITRE ATT&CK STIX 2.0 content. This library provides the ability to query the dataset for objects and their related objects. This is the main content of mitreattack-python; you can read more about other modules in this library under "Additional Modules". -## Additional Modules - -More detailed information and examples about the specific usage of the additional modules in this package can be found in the individual README files for each module linked below. - -| module | description | documentation | -|:------------|:------------|:--------------| -| [navlayers](https://github.com/mitre-attack/mitreattack-python/tree/main/mitreattack/navlayers) | A collection of utilities for working with [ATT&CK Navigator](https://github.com/mitre-attack/attack-navigator) layers. Provides the ability to import, export, and manipulate layers. Layers can be read in from the filesystem or python dictionaries, combined and edited, and then exported to excel or SVG images. | Further documentation can be found [here](https://github.com/mitre-attack/mitreattack-python/blob/main/mitreattack/navlayers/README.md).| -| [attackToExcel](https://github.com/mitre-attack/mitreattack-python/tree/main/mitreattack/attackToExcel) | A collection of utilities for converting [ATT&CK STIX data](https://github.com/mitre/cti) to Excel spreadsheets. It also provides access to [Pandas](https://pandas.pydata.org/) DataFrames representing the dataset for use in data analysis. | Further documentation can be found [here](https://github.com/mitre-attack/mitreattack-python/blob/main/mitreattack/attackToExcel/README.md).| -| [collections](https://github.com/mitre-attack/mitreattack-python/tree/main/mitreattack/collections) | A set of utilities for working with [ATT&CK Collections and Collection Indexes](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/blob/main/docs/collections.md). Provides functionalities for converting and summarizing data in collections and collection indexes, as well as generating a collection from a raw stix bundle input. | Further documentation can be found [here](https://github.com/mitre-attack/mitreattack-python/blob/main/mitreattack/collections/README.md).| -| [diffStix](https://github.com/mitre-attack/mitreattack-python/tree/main/mitreattack/diffStix) | Create markdown, HTML, JSON and/or ATT&CK Navigator layers reporting on the changes between two versions of the STIX2 bundles representing the ATT&CK content. Run `diff_stix -h` for full usage instructions. | Further documentation can be found [here](https://github.com/mitre-attack/mitreattack-python/blob/main/mitreattack/diffStix/README.md).| - - ## Related MITRE Work ### CTI @@ -60,36 +46,7 @@ STIX is designed to improve many capabilities, such as collaborative threat anal -### ATT&CK scripts - -One-off scripts and code examples you can use as inspiration for how to work with ATT&CK programmatically. Many of the functionalities found in the mitreattack-python package were originally posted on attack-scripts. - - - - ## Contributing To contribute to this project, either through a bug report, feature request, or merge request, please see the [Contributors Guide](https://github.com/mitre-attack/mitreattack-python/blob/main/docs/CONTRIBUTING.md). - -## Notice - -Copyright 2025 The MITRE Corporation - -Approved for Public Release; Distribution Unlimited. Case Number 19-0486. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. - -This project makes use of ATT&CK® - -[ATT&CK Terms of Use](https://attack.mitre.org/resources/terms-of-use/) From 180c64d6a7156243c3d43f2877c7a8427dcf4adc Mon Sep 17 00:00:00 2001 From: Jared Ondricek <90368810+jondricek@users.noreply.github.com> Date: Mon, 20 Oct 2025 08:59:40 -0500 Subject: [PATCH 16/29] chore: add object counter --- examples/attack-object-counter.py | 186 ++++++++++++++++++++++++++++++ 1 file changed, 186 insertions(+) create mode 100644 examples/attack-object-counter.py diff --git a/examples/attack-object-counter.py b/examples/attack-object-counter.py new file mode 100644 index 00000000..a2ef90ef --- /dev/null +++ b/examples/attack-object-counter.py @@ -0,0 +1,186 @@ +"""Print comprehensive ATT&CK statistics across all domains.""" + +import os +from dataclasses import dataclass + +from mitreattack.stix20 import MitreAttackData + +# Get STIX base directory from environment or use default +STIX_BASE_DIR = os.environ.get("STIX_BASE_DIR", "attack-releases/stix-2.0/v17.1") + + +@dataclass +class DomainStatistics: + """Statistics for a single ATT&CK domain.""" + + name: str + tactics: int + techniques: int + subtechniques: int + groups: int + software: int + campaigns: int + mitigations: int + datasources: int + assets: int = 0 + + def format_output(self) -> str: + """ + Format domain statistics as a string. + + Returns + ------- + str + Formatted statistics string for display. + """ + # Define all possible statistics with their labels + stats = [ + (self.tactics, "Tactics"), + (self.techniques, "Techniques"), + (self.subtechniques, "Sub-Techniques"), + (self.groups, "Groups"), + (self.software, "Pieces of Software"), + (self.campaigns, "Campaigns"), + (self.mitigations, "Mitigations"), + (self.assets, "Assets"), + (self.datasources, "Data Sources"), + ] + + # Build parts list, only including items with count > 0 + parts = [f"{count} {label}" for count, label in stats if count > 0] + + # Join all parts with proper formatting + return f"- {self.name}: {', '.join(parts[:-1])}, and {parts[-1]}" + + +def load_domain_data() -> dict[str, MitreAttackData]: + """ + Load STIX data for all ATT&CK domains. + + Returns + ------- + dict of str to MitreAttackData + Mapping of domain names to loaded MitreAttackData objects. + """ + domains = { + "enterprise": "enterprise-attack.json", + "mobile": "mobile-attack.json", + "ics": "ics-attack.json", + } + + return { + domain: MitreAttackData(stix_filepath=os.path.join(STIX_BASE_DIR, filename)) + for domain, filename in domains.items() + } + + +def collect_domain_statistics(data: MitreAttackData, domain_name: str) -> DomainStatistics: + """ + Collect statistics for a single domain. + + Parameters + ---------- + data : MitreAttackData + The MitreAttackData object for the domain. + domain_name : str + Display name of the domain. + + Returns + ------- + DomainStatistics + Statistics for the domain. + """ + # Get all object types, removing revoked and deprecated + tactics = data.get_tactics(remove_revoked_deprecated=True) + techniques = data.get_techniques(include_subtechniques=False, remove_revoked_deprecated=True) + subtechniques = data.get_subtechniques(remove_revoked_deprecated=True) + groups = data.get_groups(remove_revoked_deprecated=True) + software = data.get_software(remove_revoked_deprecated=True) + campaigns = data.get_campaigns(remove_revoked_deprecated=True) + mitigations = data.get_mitigations(remove_revoked_deprecated=True) + datasources = data.get_datasources(remove_revoked_deprecated=True) + + # ICS domain has assets + assets = 0 + if domain_name == "ICS": + assets = len(data.get_assets(remove_revoked_deprecated=True)) + + return DomainStatistics( + name=domain_name, + tactics=len(tactics), + techniques=len(techniques), + subtechniques=len(subtechniques), + groups=len(groups), + software=len(software), + campaigns=len(campaigns), + mitigations=len(mitigations), + datasources=len(datasources), + assets=assets, + ) + + +def collect_unique_object_counts(domain_data: dict[str, MitreAttackData]) -> dict[str, int]: + """ + Collect counts of unique objects across all domains. + + Some objects (Software, Groups, Campaigns) may appear in multiple domains. + This function counts unique objects to avoid double-counting. + + Parameters + ---------- + domain_data : dict of str to MitreAttackData + Mapping of domain names to MitreAttackData objects. + + Returns + ------- + dict of str to int + Counts of unique software, groups, and campaigns. + """ + all_software_ids = set() + all_groups_ids = set() + all_campaigns_ids = set() + + for data in domain_data.values(): + software = data.get_software(remove_revoked_deprecated=True) + groups = data.get_groups(remove_revoked_deprecated=True) + campaigns = data.get_campaigns(remove_revoked_deprecated=True) + + all_software_ids.update(obj["id"] for obj in software) + all_groups_ids.update(obj["id"] for obj in groups) + all_campaigns_ids.update(obj["id"] for obj in campaigns) + + return { + "software": len(all_software_ids), + "groups": len(all_groups_ids), + "campaigns": len(all_campaigns_ids), + } + + +def main(): + """Print ATT&CK statistics for all domains.""" + # Load data for all domains + domain_data = load_domain_data() + + # Collect unique object counts across all domains + unique_counts = collect_unique_object_counts(domain_data) + + # Collect statistics for each domain + enterprise_stats = collect_domain_statistics(domain_data["enterprise"], "Enterprise") + mobile_stats = collect_domain_statistics(domain_data["mobile"], "Mobile") + ics_stats = collect_domain_statistics(domain_data["ics"], "ICS") + + # Print summary output + print( + f"This version of ATT&CK contains {unique_counts['software']} Pieces of Software, " + f"{unique_counts['groups']} Groups, and {unique_counts['campaigns']} Campaigns" + ) + print("Broken out by domain:\n") + + # Print domain statistics + print(enterprise_stats.format_output()) + print(mobile_stats.format_output()) + print(ics_stats.format_output()) + + +if __name__ == "__main__": + main() From 5028631f6451b3d37b07943e0f2a5232e945028e Mon Sep 17 00:00:00 2001 From: Jared Ondricek <90368810+jondricek@users.noreply.github.com> Date: Mon, 20 Oct 2025 09:27:29 -0500 Subject: [PATCH 17/29] feat: add statistics section to changelog --- mitreattack/diffStix/changelog_helper.py | 191 +++++++++++++++++++++++ 1 file changed, 191 insertions(+) diff --git a/mitreattack/diffStix/changelog_helper.py b/mitreattack/diffStix/changelog_helper.py index 330be61d..915f376e 100644 --- a/mitreattack/diffStix/changelog_helper.py +++ b/mitreattack/diffStix/changelog_helper.py @@ -24,6 +24,7 @@ from tqdm import tqdm from mitreattack import release_info +from mitreattack.stix20 import MitreAttackData # explanation of modification types to data objects for legend in layer files date = datetime.datetime.today() @@ -47,6 +48,53 @@ def __repr__(self): """Return a string representation of the ATT&CK object version.""" return f"{self.major}.{self.minor}" +@dataclass +class DomainStatistics: + """Statistics for a single ATT&CK domain.""" + + name: str + tactics: int + techniques: int + subtechniques: int + groups: int + software: int + campaigns: int + mitigations: int + datasources: int + assets: int = 0 + + def format_output(self) -> str: + """ + Format domain statistics as a string. + + Returns + ------- + str + Formatted statistics string for display. + """ + # Define all possible statistics with their labels + stats = [ + (self.tactics, "Tactics"), + (self.techniques, "Techniques"), + (self.subtechniques, "Sub-Techniques"), + (self.groups, "Groups"), + (self.software, "Pieces of Software"), + (self.campaigns, "Campaigns"), + (self.mitigations, "Mitigations"), + (self.assets, "Assets"), + (self.datasources, "Data Sources"), + ] + + # Build parts list, only including items with count > 0 + parts = [f"{count} {label}" for count, label in stats if count > 0] + + # Join all parts with proper formatting + if len(parts) == 0: + return f"- {self.name}: No objects" + elif len(parts) == 1: + return f"- {self.name}: {parts[0]}" + else: + return f"- {self.name}: {', '.join(parts[:-1])}, and {parts[-1]}" # TODO: Implement a custom decoder as well. Possible solution at this link # https://alexisgomes19.medium.com/custom-json-encoder-with-python-f52c91b48cd2 @@ -1002,6 +1050,144 @@ def placard(self, stix_object: dict, section: str, domain: str) -> str: full_placard_string = f"{placard_string} {version_string}" return full_placard_string + def _collect_domain_statistics(self, datastore: MemoryStore, domain_name: str) -> DomainStatistics: + """ + Collect statistics for a single domain from a STIX datastore. + + Parameters + ---------- + datastore : MemoryStore + The STIX MemoryStore containing the domain data. + domain_name : str + Display name of the domain (e.g., "Enterprise", "Mobile", "ICS"). + + Returns + ------- + DomainStatistics + Statistics for the domain. + """ + # Create MitreAttackData instance from the datastore + data = MitreAttackData(src=datastore) + + # Get all object types, removing revoked and deprecated + tactics = data.get_tactics(remove_revoked_deprecated=True) + techniques = data.get_techniques(include_subtechniques=False, remove_revoked_deprecated=True) + subtechniques = data.get_subtechniques(remove_revoked_deprecated=True) + groups = data.get_groups(remove_revoked_deprecated=True) + software = data.get_software(remove_revoked_deprecated=True) + campaigns = data.get_campaigns(remove_revoked_deprecated=True) + mitigations = data.get_mitigations(remove_revoked_deprecated=True) + + # Try to get datasources - may fail on test data with STIX version mismatches + datasources = [] + try: + datasources = data.get_datasources(remove_revoked_deprecated=True) + except Exception: + # Silently skip datasources if there are STIX version issues + pass + + # ICS domain has assets + assets = 0 + if domain_name == "ICS": + try: + assets = len(data.get_assets(remove_revoked_deprecated=True)) + except Exception: + # Silently skip assets if there are STIX version issues + pass + + return DomainStatistics( + name=domain_name, + tactics=len(tactics), + techniques=len(techniques), + subtechniques=len(subtechniques), + groups=len(groups), + software=len(software), + campaigns=len(campaigns), + mitigations=len(mitigations), + datasources=len(datasources), + assets=assets, + ) + + def _collect_unique_object_counts(self, datastore_version: str) -> dict[str, int]: + """ + Collect counts of unique objects across all domains for a specific version. + + Some objects (Software, Groups, Campaigns) may appear in multiple domains. + This function counts unique objects to avoid double-counting. + + Parameters + ---------- + datastore_version : str + Either "old" or "new" to specify which version's data to analyze. + + Returns + ------- + dict of str to int + Counts of unique software, groups, and campaigns. + """ + all_software_ids = set() + all_groups_ids = set() + all_campaigns_ids = set() + + for domain in self.domains: + datastore = self.data[datastore_version][domain]["stix_datastore"] + data = MitreAttackData(src=datastore) + + software = data.get_software(remove_revoked_deprecated=True) + groups = data.get_groups(remove_revoked_deprecated=True) + campaigns = data.get_campaigns(remove_revoked_deprecated=True) + + all_software_ids.update(obj["id"] for obj in software) + all_groups_ids.update(obj["id"] for obj in groups) + all_campaigns_ids.update(obj["id"] for obj in campaigns) + + return { + "software": len(all_software_ids), + "groups": len(all_groups_ids), + "campaigns": len(all_campaigns_ids), + } + + def get_statistics_section(self, datastore_version: str = "new") -> str: + """ + Generate a markdown section with ATT&CK statistics for all domains. + + Parameters + ---------- + datastore_version : str, optional + Either "old" or "new" to specify which version's statistics to generate. + Defaults to "new". + + Returns + ------- + str + Markdown-formatted statistics section. + """ + # Collect unique object counts across all domains + unique_counts = self._collect_unique_object_counts(datastore_version) + + # Collect statistics for each domain + domain_stats = [] + for domain in self.domains: + datastore = self.data[datastore_version][domain]["stix_datastore"] + domain_label = self.domain_to_domain_label[domain] + stats = self._collect_domain_statistics(datastore, domain_label) + domain_stats.append(stats) + + # Build the statistics section + version_label = "New" if datastore_version == "new" else "Old" + output = f"## {version_label} ATT&CK Version Statistics\n\n" + output += ( + f"This version of ATT&CK contains {unique_counts['software']} Pieces of Software, " + f"{unique_counts['groups']} Groups, and {unique_counts['campaigns']} Campaigns.\n\n" + ) + output += "Broken out by domain:\n\n" + + for stats in domain_stats: + output += stats.format_output() + "\n" + + output += "\n" + return output + def get_markdown_section_data(self, groupings, section: str, domain: str) -> str: """Parse a list of STIX objects in a section and return a string for the whole section.""" sectionString = "" @@ -1056,6 +1242,11 @@ def get_markdown_string(self) -> str: key_content = self.get_md_key() content = f"{key_content}\n\n" + # Add statistics section for the new version + logger.info("Generating statistics section") + stats_section = self.get_statistics_section(datastore_version="new") + content += stats_section + for object_type in self.types: domains = "" From 049f1c17c89612f8d2a330b08c7edec1ebe2cbba Mon Sep 17 00:00:00 2001 From: Evan Lucchesi Leon <189633144+elucchesileon@users.noreply.github.com> Date: Tue, 21 Oct 2025 11:43:12 -0400 Subject: [PATCH 18/29] fix: handle missing/deprecated data sources, separate data component parsing in v18+ --- mitreattack/attackToExcel/attackToExcel.py | 48 ++++++++++++++++++++-- mitreattack/attackToExcel/stixToDf.py | 42 ++++++++++++------- 2 files changed, 72 insertions(+), 18 deletions(-) diff --git a/mitreattack/attackToExcel/attackToExcel.py b/mitreattack/attackToExcel/attackToExcel.py index 4714f31b..c1f0c180 100644 --- a/mitreattack/attackToExcel/attackToExcel.py +++ b/mitreattack/attackToExcel/attackToExcel.py @@ -2,6 +2,7 @@ import argparse import os +import re from typing import Dict, List, Optional import pandas as pd @@ -80,10 +81,10 @@ def get_stix_data( return mem_store -def build_dataframes(src: MemoryStore, domain: str) -> Dict: +def build_dataframes_pre_v18(src: MemoryStore, domain: str) -> Dict: """Build pandas dataframes for each attack type, and return a dictionary lookup for each type to the relevant dataframe. - :returns: + This version of the function is used for ATT&CK versions prior to v18, to account for changes to data components/data sources. Parameters ---------- @@ -114,6 +115,38 @@ def build_dataframes(src: MemoryStore, domain: str) -> Dict: return df +def build_dataframes(src: MemoryStore, domain: str) -> Dict: + """Build pandas dataframes for each attack type, and return a dictionary lookup for each type to the relevant dataframe. + + Parameters + ---------- + src : MemoryStore + MemoryStore or other stix2 DataSource object + domain : str + domain of ATT&CK src corresponds to, e.g "enterprise-attack" + + Returns + ------- + dict + A dict lookup of each ATT&CK type to dataframes for the given type to be ingested by write_excel + """ + df = { + "techniques": stixToDf.techniquesToDf(src, domain), + "tactics": stixToDf.tacticsToDf(src), + "software": stixToDf.softwareToDf(src), + "groups": stixToDf.groupsToDf(src), + "campaigns": stixToDf.campaignsToDf(src), + "assets": stixToDf.assetsToDf(src), + "mitigations": stixToDf.mitigationsToDf(src), + "matrices": stixToDf.matricesToDf(src, domain), + "relationships": stixToDf.relationshipsToDf(src), + "datacomponents": stixToDf.datacomponentsToDf(src), + "analytics": stixToDf.analyticsToDf(src), + "detectionstrategies": stixToDf.detectionstrategiesToDf(src), + } + return df + + def write_excel(dataframes: Dict, domain: str, version: Optional[str] = None, output_dir: str = ".") -> List: """Given a set of dataframes from build_dataframes, write the ATT&CK dataset to output directory. @@ -148,7 +181,7 @@ def write_excel(dataframes: Dict, domain: str, version: Optional[str] = None, ou os.makedirs(output_directory) # master dataset file master_fp = os.path.join(output_directory, f"{domain_version_string}.xlsx") - with pd.ExcelWriter(master_fp, engine="xlsxwriter") as master_writer: + with pd.ExcelWriter(path=master_fp, engine="xlsxwriter") as master_writer: # master list of citations citations = pd.DataFrame() @@ -324,6 +357,15 @@ def export( logger.info(f"************ Exporting {domain} to Excel ************") # build dataframes + if version: + version_pattern = r"v(\d+)\.(\d+)$" + match = re.search(version_pattern, version) + if match: + major_version = int(match.group(1)) + if major_version < 18: + dataframes = build_dataframes_pre_v18(src=mem_store, domain=domain) + write_excel(dataframes=dataframes, domain=domain, version=version, output_dir=output_dir) + dataframes = build_dataframes(src=mem_store, domain=domain) write_excel(dataframes=dataframes, domain=domain, version=version, output_dir=output_dir) diff --git a/mitreattack/attackToExcel/stixToDf.py b/mitreattack/attackToExcel/stixToDf.py index 326d5870..bf7290f6 100644 --- a/mitreattack/attackToExcel/stixToDf.py +++ b/mitreattack/attackToExcel/stixToDf.py @@ -259,6 +259,8 @@ def tacticsToDf(src): def datasourcesToDf(src): """Parse STIX Data Sources and their Data components from the given data and return corresponding pandas dataframes. + This is only used in versions of ATT&CK before v18. + :param src: MemoryStore or other stix2 DataSource object holding the domain data :returns: a lookup of labels (descriptors/names) to dataframes """ @@ -290,7 +292,7 @@ def datasourcesToDf(src): if "x_mitre_aliases" in data_object: row["aliases"] = ", ".join(sorted(data_object["x_mitre_aliases"][1:])) if data_object["type"] == "x-mitre-data-component": - if "x_mitre_data_source_ref" in data_object: + if "x_mitre_data_source_ref" in data_object and data_object["x_mitre_data_source_ref"] in source_lookup: row["name"] = f"{source_lookup[data_object['x_mitre_data_source_ref']]}: {data_object['name']}" row["type"] = "datacomponent" else: @@ -333,6 +335,29 @@ def datasourcesToDf(src): return dataframes +def datacomponentsToDf(src): + """Parse STIX Data components from the given data and return corresponding pandas dataframes. + + :param src: MemoryStore or other stix2 DataSource object holding the domain data + :returns: a lookup of labels (descriptors/names) to dataframes + """ + data_components = src.query([Filter("type", "=", "x-mitre-data-component")]) + data_components = remove_revoked_deprecated(data_components) + + data_component_rows = [] + for data_component in tqdm(data_components, desc="parsing data components"): + data_component_rows.append(parseBaseStix(data_component)) + + citations = get_citations(data_components) + dataframes = { + "datacomponents": pd.DataFrame(data_component_rows).sort_values("name"), + } + if not citations.empty: + dataframes["citations"] = citations.sort_values("reference") + + return dataframes + + def analyticsToDf(src): """Parse STIX Analytics from the given data and return corresponding pandas dataframes. @@ -380,22 +405,9 @@ def detectionstrategiesToDf(src): dataframes = { "detectionstrategies": pd.DataFrame(detection_strategy_rows).sort_values("name"), } - - # add relationships - codex = relationshipsToDf(src, relatedType="detectionstrategy") - dataframes.update(codex) - # add relationship references - dataframes["detectionstrategies"]["relationship citations"] = _get_relationship_citations( - dataframes["detectionstrategies"], codex - ) - # add/merge citations if not citations.empty: if "citations" in dataframes: # append to existing citations from references - dataframes["citations"] = pd.concat([dataframes["citations"], citations]) - else: # add citations - dataframes["citations"] = citations - - dataframes["citations"].sort_values("reference") + dataframes["citations"] = citations.sort_values("reference") else: logger.warning("No detection strategies found - nothing to parse") From 365e4104cd809b6123866e9b198c9549c9306ace Mon Sep 17 00:00:00 2001 From: Evan Lucchesi Leon <189633144+elucchesileon@users.noreply.github.com> Date: Tue, 21 Oct 2025 13:33:05 -0400 Subject: [PATCH 19/29] fix: ruff format --- mitreattack/diffStix/changelog_helper.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/mitreattack/diffStix/changelog_helper.py b/mitreattack/diffStix/changelog_helper.py index 915f376e..e20efa4a 100644 --- a/mitreattack/diffStix/changelog_helper.py +++ b/mitreattack/diffStix/changelog_helper.py @@ -48,6 +48,7 @@ def __repr__(self): """Return a string representation of the ATT&CK object version.""" return f"{self.major}.{self.minor}" + @dataclass class DomainStatistics: """Statistics for a single ATT&CK domain.""" @@ -96,6 +97,7 @@ def format_output(self) -> str: else: return f"- {self.name}: {', '.join(parts[:-1])}, and {parts[-1]}" + # TODO: Implement a custom decoder as well. Possible solution at this link # https://alexisgomes19.medium.com/custom-json-encoder-with-python-f52c91b48cd2 class AttackChangesEncoder(json.JSONEncoder): From 74cdb81f1bca034ae01b24c2059b4375798ea000 Mon Sep 17 00:00:00 2001 From: Evan Lucchesi Leon <189633144+elucchesileon@users.noreply.github.com> Date: Tue, 21 Oct 2025 13:38:36 -0400 Subject: [PATCH 20/29] fix: proper handling of typer.Option in defaults --- mitreattack/download_stix.py | 31 +++++++++++++++++-------------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/mitreattack/download_stix.py b/mitreattack/download_stix.py index f610675a..09fbb774 100644 --- a/mitreattack/download_stix.py +++ b/mitreattack/download_stix.py @@ -6,6 +6,7 @@ import pooch import typer from loguru import logger +from typing_extensions import Annotated from mitreattack import release_info @@ -191,20 +192,22 @@ def _validate_versions(versions: List[str], stix20: bool, stix21: bool): @app.command() def download_attack_stix( - download_dir: str = typer.Option( - "attack-releases", "--download-dir", "-d", help="Folder to save downloaded STIX data." - ), - all_versions: bool = typer.Option( - False, "--all", "-a", help="Download all ATT&CK releases. Mutually exclusive with --version." - ), - attack_versions: Optional[List[str]] = typer.Option( - None, - "--version", - "-v", - help="Download specific ATT&CK version(s). Can be specified multiple times. Mutually exclusive with --all.", - ), - stix20: bool = typer.Option(True, help="Download STIX 2.0 data."), - stix21: bool = typer.Option(False, help="Download STIX 2.1 data."), + download_dir: Annotated[ + str, typer.Option("--download-dir", "-d", help="Folder to save downloaded STIX data.") + ] = "attack-releases", + all_versions: Annotated[ + bool, typer.Option("--all", "-a", help="Download all ATT&CK releases. Mutually exclusive with --version.") + ] = False, + attack_versions: Annotated[ + Optional[List[str]], + typer.Option( + "--version", + "-v", + help="Download specific ATT&CK version(s). Can be specified multiple times. Mutually exclusive with --all.", + ), + ] = None, + stix20: Annotated[bool, typer.Option(help="Download STIX 2.0 data.")] = True, + stix21: Annotated[bool, typer.Option(help="Download STIX 2.1 data.")] = False, ): """Download the ATT&CK STIX data from GitHub in JSON format. From 5d598f3c953ae050c42663f80900b742c4c342ce Mon Sep 17 00:00:00 2001 From: Evan Lucchesi Leon <189633144+elucchesileon@users.noreply.github.com> Date: Tue, 21 Oct 2025 13:47:04 -0400 Subject: [PATCH 21/29] fix: only build excel once when version < 18 --- mitreattack/attackToExcel/attackToExcel.py | 1 + 1 file changed, 1 insertion(+) diff --git a/mitreattack/attackToExcel/attackToExcel.py b/mitreattack/attackToExcel/attackToExcel.py index c1f0c180..29db7e4c 100644 --- a/mitreattack/attackToExcel/attackToExcel.py +++ b/mitreattack/attackToExcel/attackToExcel.py @@ -365,6 +365,7 @@ def export( if major_version < 18: dataframes = build_dataframes_pre_v18(src=mem_store, domain=domain) write_excel(dataframes=dataframes, domain=domain, version=version, output_dir=output_dir) + return dataframes = build_dataframes(src=mem_store, domain=domain) write_excel(dataframes=dataframes, domain=domain, version=version, output_dir=output_dir) From ec19b155a6a9743bec4a01336d8f6342ecef997f Mon Sep 17 00:00:00 2001 From: Jared Ondricek Date: Tue, 21 Oct 2025 17:17:26 -0500 Subject: [PATCH 22/29] test: remove logsources from tests since we decided not to use them --- tests/changelog/core/test_diffstix_methods.py | 1 - .../test_diffstix_output_generation.py | 1 - .../changelog-v16.1_to_v17.0/changelog.json | 30 ------------------- 3 files changed, 32 deletions(-) diff --git a/tests/changelog/core/test_diffstix_methods.py b/tests/changelog/core/test_diffstix_methods.py index 666b383e..f7b80c35 100644 --- a/tests/changelog/core/test_diffstix_methods.py +++ b/tests/changelog/core/test_diffstix_methods.py @@ -202,7 +202,6 @@ def test_get_changes_dict_real_structure(self, lightweight_diffstix): "datasources", "datacomponents", "detectionstrategies", - "logsources", "analytics", ] for obj_type in expected_types: diff --git a/tests/changelog/integration/test_diffstix_output_generation.py b/tests/changelog/integration/test_diffstix_output_generation.py index f2193854..47ca399f 100644 --- a/tests/changelog/integration/test_diffstix_output_generation.py +++ b/tests/changelog/integration/test_diffstix_output_generation.py @@ -58,7 +58,6 @@ def test_get_changes_dict_comprehensive_structure(self, lightweight_diffstix): "datasources", "datacomponents", "detectionstrategies", - "logsources", "analytics", ] for obj_type in expected_types: diff --git a/tests/resources/changelog-v16.1_to_v17.0/changelog.json b/tests/resources/changelog-v16.1_to_v17.0/changelog.json index 91b3987c..d77e574d 100644 --- a/tests/resources/changelog-v16.1_to_v17.0/changelog.json +++ b/tests/resources/changelog-v16.1_to_v17.0/changelog.json @@ -100181,16 +100181,6 @@ "revocations": [], "deprecations": [], "deletions": [] - }, - "logsources": { - "additions": [], - "major_version_changes": [], - "minor_version_changes": [], - "other_version_changes": [], - "patches": [], - "revocations": [], - "deprecations": [], - "deletions": [] } }, "mobile-attack": { @@ -114153,16 +114143,6 @@ "revocations": [], "deprecations": [], "deletions": [] - }, - "logsources": { - "additions": [], - "major_version_changes": [], - "minor_version_changes": [], - "other_version_changes": [], - "patches": [], - "revocations": [], - "deprecations": [], - "deletions": [] } }, "ics-attack": { @@ -125846,16 +125826,6 @@ "revocations": [], "deprecations": [], "deletions": [] - }, - "logsources": { - "additions": [], - "major_version_changes": [], - "minor_version_changes": [], - "other_version_changes": [], - "patches": [], - "revocations": [], - "deprecations": [], - "deletions": [] } }, "new-contributors": [ From 83a5330d2e05b930fadd1ecdf492785bb07cb555 Mon Sep 17 00:00:00 2001 From: Jared Ondricek Date: Wed, 22 Oct 2025 11:30:14 -0500 Subject: [PATCH 23/29] fix: update changelog output and pytest golden output to match it --- mitreattack/diffStix/changelog_helper.py | 58 +- .../changelog-v16.1_to_v17.0/changelog.md | 751 +++++++++--------- 2 files changed, 407 insertions(+), 402 deletions(-) diff --git a/mitreattack/diffStix/changelog_helper.py b/mitreattack/diffStix/changelog_helper.py index e20efa4a..228957e0 100644 --- a/mitreattack/diffStix/changelog_helper.py +++ b/mitreattack/diffStix/changelog_helper.py @@ -61,8 +61,11 @@ class DomainStatistics: software: int campaigns: int mitigations: int + assets: int datasources: int - assets: int = 0 + detectionstrategies: int + analytics: int + datacomponents: int def format_output(self) -> str: """ @@ -79,11 +82,14 @@ def format_output(self) -> str: (self.techniques, "Techniques"), (self.subtechniques, "Sub-Techniques"), (self.groups, "Groups"), - (self.software, "Pieces of Software"), + (self.software, "Software"), (self.campaigns, "Campaigns"), (self.mitigations, "Mitigations"), (self.assets, "Assets"), (self.datasources, "Data Sources"), + (self.detectionstrategies, "Detection Strategies"), + (self.analytics, "Analytics"), + (self.datacomponents, "Data Components"), ] # Build parts list, only including items with count > 0 @@ -91,11 +97,11 @@ def format_output(self) -> str: # Join all parts with proper formatting if len(parts) == 0: - return f"- {self.name}: No objects" + return f"* {self.name}: No objects" elif len(parts) == 1: - return f"- {self.name}: {parts[0]}" + return f"* {self.name}: {parts[0]}" else: - return f"- {self.name}: {', '.join(parts[:-1])}, and {parts[-1]}" + return f"* {self.name}: {', '.join(parts[:-1])}, and {parts[-1]}" # TODO: Implement a custom decoder as well. Possible solution at this link @@ -1079,23 +1085,11 @@ def _collect_domain_statistics(self, datastore: MemoryStore, domain_name: str) - software = data.get_software(remove_revoked_deprecated=True) campaigns = data.get_campaigns(remove_revoked_deprecated=True) mitigations = data.get_mitigations(remove_revoked_deprecated=True) - - # Try to get datasources - may fail on test data with STIX version mismatches - datasources = [] - try: - datasources = data.get_datasources(remove_revoked_deprecated=True) - except Exception: - # Silently skip datasources if there are STIX version issues - pass - - # ICS domain has assets - assets = 0 - if domain_name == "ICS": - try: - assets = len(data.get_assets(remove_revoked_deprecated=True)) - except Exception: - # Silently skip assets if there are STIX version issues - pass + assets = data.get_assets(remove_revoked_deprecated=True) + datasources = data.get_datasources(remove_revoked_deprecated=True) + detectionstrategies = data.get_detectionstrategies(remove_revoked_deprecated=True) + analytics = data.get_analytics(remove_revoked_deprecated=True) + datacomponents = data.get_datacomponents(remove_revoked_deprecated=True) return DomainStatistics( name=domain_name, @@ -1106,8 +1100,11 @@ def _collect_domain_statistics(self, datastore: MemoryStore, domain_name: str) - software=len(software), campaigns=len(campaigns), mitigations=len(mitigations), + assets=len(assets), datasources=len(datasources), - assets=assets, + detectionstrategies=len(detectionstrategies), + analytics=len(analytics), + datacomponents=len(datacomponents), ) def _collect_unique_object_counts(self, datastore_version: str) -> dict[str, int]: @@ -1176,10 +1173,9 @@ def get_statistics_section(self, datastore_version: str = "new") -> str: domain_stats.append(stats) # Build the statistics section - version_label = "New" if datastore_version == "new" else "Old" - output = f"## {version_label} ATT&CK Version Statistics\n\n" + output = "## Statistics\n\n" output += ( - f"This version of ATT&CK contains {unique_counts['software']} Pieces of Software, " + f"This version of ATT&CK contains {unique_counts['software']} Software, " f"{unique_counts['groups']} Groups, and {unique_counts['campaigns']} Campaigns.\n\n" ) output += "Broken out by domain:\n\n" @@ -1203,7 +1199,7 @@ def get_markdown_section_data(self, groupings, section: str, domain: str) -> str placard_string = self.placard(stix_object=child, section=section, domain=domain) if grouping["parentInSection"]: - sectionString += f" * {placard_string}\n" + sectionString += f" * {placard_string}\n" else: sectionString += f"* {grouping['parent']['name']}: {placard_string}\n" @@ -1240,15 +1236,15 @@ def get_markdown_string(self) -> str: logger.info("Generating markdown output") content = "" - if self.show_key: - key_content = self.get_md_key() - content = f"{key_content}\n\n" - # Add statistics section for the new version logger.info("Generating statistics section") stats_section = self.get_statistics_section(datastore_version="new") content += stats_section + if self.show_key: + key_content = self.get_md_key() + content += f"{key_content}\n" + for object_type in self.types: domains = "" diff --git a/tests/resources/changelog-v16.1_to_v17.0/changelog.md b/tests/resources/changelog-v16.1_to_v17.0/changelog.md index 8b2722a5..b285a89d 100644 --- a/tests/resources/changelog-v16.1_to_v17.0/changelog.md +++ b/tests/resources/changelog-v16.1_to_v17.0/changelog.md @@ -1,3 +1,13 @@ +## Statistics + +This version of ATT&CK contains 877 Software, 170 Groups, and 50 Campaigns. + +Broken out by domain: + +* Enterprise: 14 Tactics, 211 Techniques, 468 Sub-Techniques, 166 Groups, 755 Software, 47 Campaigns, 44 Mitigations, 37 Data Sources, and 106 Data Components +* Mobile: 12 Tactics, 75 Techniques, 46 Sub-Techniques, 15 Groups, 118 Software, 3 Campaigns, 13 Mitigations, 6 Data Sources, and 17 Data Components +* ICS: 12 Tactics, 83 Techniques, 14 Groups, 23 Software, 7 Campaigns, 52 Mitigations, 14 Assets, 17 Data Sources, and 36 Data Components + ## Key * New objects: ATT&CK objects which are only present in the new release. @@ -9,7 +19,6 @@ * Object deprecations: ATT&CK objects which are deprecated and no longer in use, and not replaced. * Object deletions: ATT&CK objects which are no longer found in the STIX data. - ## Techniques ### Enterprise @@ -53,122 +62,122 @@ #### Minor Version Changes * [Abuse Elevation Control Mechanism](/techniques/T1548) (v1.4→v1.5) - * [Bypass User Account Control](/techniques/T1548/002) (v2.1→v2.2) - * [Elevated Execution with Prompt](/techniques/T1548/004) (v1.0→v1.1) - * [Setuid and Setgid](/techniques/T1548/001) (v1.1→v1.2) - * [Sudo and Sudo Caching](/techniques/T1548/003) (v1.0→v1.1) + * [Bypass User Account Control](/techniques/T1548/002) (v2.1→v2.2) + * [Elevated Execution with Prompt](/techniques/T1548/004) (v1.0→v1.1) + * [Setuid and Setgid](/techniques/T1548/001) (v1.1→v1.2) + * [Sudo and Sudo Caching](/techniques/T1548/003) (v1.0→v1.1) * [Access Token Manipulation](/techniques/T1134) (v2.0→v2.1) - * [Create Process with Token](/techniques/T1134/002) (v1.2→v1.3) - * [Make and Impersonate Token](/techniques/T1134/003) (v1.1→v1.2) - * [Parent PID Spoofing](/techniques/T1134/004) (v1.0→v1.1) - * [SID-History Injection](/techniques/T1134/005) (v1.0→v1.1) - * [Token Impersonation/Theft](/techniques/T1134/001) (v1.2→v1.3) + * [Create Process with Token](/techniques/T1134/002) (v1.2→v1.3) + * [Make and Impersonate Token](/techniques/T1134/003) (v1.1→v1.2) + * [Parent PID Spoofing](/techniques/T1134/004) (v1.0→v1.1) + * [SID-History Injection](/techniques/T1134/005) (v1.0→v1.1) + * [Token Impersonation/Theft](/techniques/T1134/001) (v1.2→v1.3) * [Account Access Removal](/techniques/T1531) (v1.3→v1.4) * [Account Discovery](/techniques/T1087) (v2.5→v2.6) - * [Local Account](/techniques/T1087/001) (v1.4→v1.5) + * [Local Account](/techniques/T1087/001) (v1.4→v1.5) * [Account Manipulation](/techniques/T1098) (v2.7→v2.8) - * [SSH Authorized Keys](/techniques/T1098/004) (v1.3→v1.4) + * [SSH Authorized Keys](/techniques/T1098/004) (v1.3→v1.4) * Acquire Infrastructure: [Botnet](/techniques/T1583/005) (v1.0→v1.1) * Acquire Infrastructure: [Web Services](/techniques/T1583/006) (v1.2→v1.3) * [Adversary-in-the-Middle](/techniques/T1557) (v2.4→v2.5) - * [Evil Twin](/techniques/T1557/004) (v1.0→v1.1) + * [Evil Twin](/techniques/T1557/004) (v1.0→v1.1) * [Application Layer Protocol](/techniques/T1071) (v2.3→v2.4) - * [DNS](/techniques/T1071/004) (v1.2→v1.3) - * [File Transfer Protocols](/techniques/T1071/002) (v1.2→v1.3) - * [Mail Protocols](/techniques/T1071/003) (v1.1→v1.2) - * [Publish/Subscribe Protocols](/techniques/T1071/005) (v1.0→v1.1) - * [Web Protocols](/techniques/T1071/001) (v1.3→v1.4) + * [DNS](/techniques/T1071/004) (v1.2→v1.3) + * [File Transfer Protocols](/techniques/T1071/002) (v1.2→v1.3) + * [Mail Protocols](/techniques/T1071/003) (v1.1→v1.2) + * [Publish/Subscribe Protocols](/techniques/T1071/005) (v1.0→v1.1) + * [Web Protocols](/techniques/T1071/001) (v1.3→v1.4) * [Automated Collection](/techniques/T1119) (v1.3→v1.4) * [Automated Exfiltration](/techniques/T1020) (v1.2→v1.3) - * [Traffic Duplication](/techniques/T1020/001) (v1.3→v1.4) + * [Traffic Duplication](/techniques/T1020/001) (v1.3→v1.4) * [BITS Jobs](/techniques/T1197) (v1.4→v1.5) * [Boot or Logon Autostart Execution](/techniques/T1547) (v1.2→v1.3) - * [Active Setup](/techniques/T1547/014) (v1.0→v1.1) - * [Authentication Package](/techniques/T1547/002) (v1.0→v1.1) - * [Kernel Modules and Extensions](/techniques/T1547/006) (v1.3→v1.4) - * [LSASS Driver](/techniques/T1547/008) (v1.0→v1.1) - * [Login Items](/techniques/T1547/015) (v1.0→v1.1) - * [Port Monitors](/techniques/T1547/010) (v1.2→v1.3) - * [Print Processors](/techniques/T1547/012) (v1.1→v1.2) - * [Re-opened Applications](/techniques/T1547/007) (v1.1→v1.2) - * [Registry Run Keys / Startup Folder](/techniques/T1547/001) (v2.0→v2.1) - * [Security Support Provider](/techniques/T1547/005) (v1.0→v1.1) - * [Shortcut Modification](/techniques/T1547/009) (v1.2→v1.3) - * [Time Providers](/techniques/T1547/003) (v1.1→v1.2) - * [Winlogon Helper DLL](/techniques/T1547/004) (v1.2→v1.3) - * [XDG Autostart Entries](/techniques/T1547/013) (v1.1→v1.2) + * [Active Setup](/techniques/T1547/014) (v1.0→v1.1) + * [Authentication Package](/techniques/T1547/002) (v1.0→v1.1) + * [Kernel Modules and Extensions](/techniques/T1547/006) (v1.3→v1.4) + * [LSASS Driver](/techniques/T1547/008) (v1.0→v1.1) + * [Login Items](/techniques/T1547/015) (v1.0→v1.1) + * [Port Monitors](/techniques/T1547/010) (v1.2→v1.3) + * [Print Processors](/techniques/T1547/012) (v1.1→v1.2) + * [Re-opened Applications](/techniques/T1547/007) (v1.1→v1.2) + * [Registry Run Keys / Startup Folder](/techniques/T1547/001) (v2.0→v2.1) + * [Security Support Provider](/techniques/T1547/005) (v1.0→v1.1) + * [Shortcut Modification](/techniques/T1547/009) (v1.2→v1.3) + * [Time Providers](/techniques/T1547/003) (v1.1→v1.2) + * [Winlogon Helper DLL](/techniques/T1547/004) (v1.2→v1.3) + * [XDG Autostart Entries](/techniques/T1547/013) (v1.1→v1.2) * [Boot or Logon Initialization Scripts](/techniques/T1037) (v2.3→v2.4) - * [RC Scripts](/techniques/T1037/004) (v2.1→v2.2) - * [Startup Items](/techniques/T1037/005) (v1.0→v1.1) + * [RC Scripts](/techniques/T1037/004) (v2.1→v2.2) + * [Startup Items](/techniques/T1037/005) (v1.0→v1.1) * [Browser Session Hijacking](/techniques/T1185) (v2.0→v2.1) * [Brute Force](/techniques/T1110) (v2.6→v2.7) - * [Credential Stuffing](/techniques/T1110/004) (v1.6→v1.7) - * [Password Cracking](/techniques/T1110/002) (v1.3→v1.4) - * [Password Guessing](/techniques/T1110/001) (v1.6→v1.7) - * [Password Spraying](/techniques/T1110/003) (v1.6→v1.7) + * [Credential Stuffing](/techniques/T1110/004) (v1.6→v1.7) + * [Password Cracking](/techniques/T1110/002) (v1.3→v1.4) + * [Password Guessing](/techniques/T1110/001) (v1.6→v1.7) + * [Password Spraying](/techniques/T1110/003) (v1.6→v1.7) * [Cloud Administration Command](/techniques/T1651) (v2.0→v2.1) * [Cloud Service Dashboard](/techniques/T1538) (v1.4→v1.5) * [Command and Scripting Interpreter](/techniques/T1059) (v2.5→v2.6) - * [AppleScript](/techniques/T1059/002) (v1.2→v1.3) - * [AutoHotKey & AutoIT](/techniques/T1059/010) (v1.0→v1.1) - * [Cloud API](/techniques/T1059/009) (v1.1→v1.2) - * [Lua](/techniques/T1059/011) (v1.0→v1.1) - * [Network Device CLI](/techniques/T1059/008) (v1.1→v1.2) - * [PowerShell](/techniques/T1059/001) (v1.4→v1.5) - * [Python](/techniques/T1059/006) (v1.0→v1.1) - * [Unix Shell](/techniques/T1059/004) (v1.2→v1.3) - * [Visual Basic](/techniques/T1059/005) (v1.4→v1.5) - * [Windows Command Shell](/techniques/T1059/003) (v1.4→v1.5) + * [AppleScript](/techniques/T1059/002) (v1.2→v1.3) + * [AutoHotKey & AutoIT](/techniques/T1059/010) (v1.0→v1.1) + * [Cloud API](/techniques/T1059/009) (v1.1→v1.2) + * [Lua](/techniques/T1059/011) (v1.0→v1.1) + * [Network Device CLI](/techniques/T1059/008) (v1.1→v1.2) + * [PowerShell](/techniques/T1059/001) (v1.4→v1.5) + * [Python](/techniques/T1059/006) (v1.0→v1.1) + * [Unix Shell](/techniques/T1059/004) (v1.2→v1.3) + * [Visual Basic](/techniques/T1059/005) (v1.4→v1.5) + * [Windows Command Shell](/techniques/T1059/003) (v1.4→v1.5) * [Compromise Host Software Binary](/techniques/T1554) (v2.1→v2.2) * [Compromise Infrastructure](/techniques/T1584) (v1.5→v1.6) * [Container Administration Command](/techniques/T1609) (v1.2→v1.3) * [Create Account](/techniques/T1136) (v2.5→v2.6) - * [Local Account](/techniques/T1136/001) (v1.3→v1.4) + * [Local Account](/techniques/T1136/001) (v1.3→v1.4) * Create or Modify System Process: [Launch Agent](/techniques/T1543/001) (v1.4→v1.5) * Create or Modify System Process: [Launch Daemon](/techniques/T1543/004) (v1.2→v1.3) * Create or Modify System Process: [Systemd Service](/techniques/T1543/002) (v1.5→v1.6) * Create or Modify System Process: [Windows Service](/techniques/T1543/003) (v1.5→v1.6) * [Data Destruction](/techniques/T1485) (v1.3→v1.4) - * [Lifecycle-Triggered Deletion](/techniques/T1485/001) (v1.0→v1.1) + * [Lifecycle-Triggered Deletion](/techniques/T1485/001) (v1.0→v1.1) * [Data Encoding](/techniques/T1132) (v1.2→v1.3) - * [Non-Standard Encoding](/techniques/T1132/002) (v1.0→v1.1) - * [Standard Encoding](/techniques/T1132/001) (v1.0→v1.1) + * [Non-Standard Encoding](/techniques/T1132/002) (v1.0→v1.1) + * [Standard Encoding](/techniques/T1132/001) (v1.0→v1.1) * [Data Encrypted for Impact](/techniques/T1486) (v1.4→v1.5) * [Data Obfuscation](/techniques/T1001) (v1.1→v1.2) - * [Junk Data](/techniques/T1001/001) (v1.0→v1.1) - * [Protocol or Service Impersonation](/techniques/T1001/003) (v2.0→v2.1) - * [Steganography](/techniques/T1001/002) (v1.0→v1.1) + * [Junk Data](/techniques/T1001/001) (v1.0→v1.1) + * [Protocol or Service Impersonation](/techniques/T1001/003) (v2.0→v2.1) + * [Steganography](/techniques/T1001/002) (v1.0→v1.1) * [Data Staged](/techniques/T1074) (v1.4→v1.5) - * [Local Data Staging](/techniques/T1074/001) (v1.1→v1.2) - * [Remote Data Staging](/techniques/T1074/002) (v1.1→v1.2) + * [Local Data Staging](/techniques/T1074/001) (v1.1→v1.2) + * [Remote Data Staging](/techniques/T1074/002) (v1.1→v1.2) * [Data Transfer Size Limits](/techniques/T1030) (v1.0→v1.1) * [Data from Configuration Repository](/techniques/T1602) (v1.0→v1.1) - * [Network Device Configuration Dump](/techniques/T1602/002) (v1.0→v1.1) - * [SNMP (MIB Dump)](/techniques/T1602/001) (v1.0→v1.1) + * [Network Device Configuration Dump](/techniques/T1602/002) (v1.0→v1.1) + * [SNMP (MIB Dump)](/techniques/T1602/001) (v1.0→v1.1) * [Data from Local System](/techniques/T1005) (v1.6→v1.7) * [Data from Network Shared Drive](/techniques/T1039) (v1.4→v1.5) * [Data from Removable Media](/techniques/T1025) (v1.2→v1.3) * [Debugger Evasion](/techniques/T1622) (v1.0→v1.1) * [Defacement](/techniques/T1491) (v1.3→v1.4) - * [Internal Defacement](/techniques/T1491/001) (v1.1→v1.2) + * [Internal Defacement](/techniques/T1491/001) (v1.1→v1.2) * [Deobfuscate/Decode Files or Information](/techniques/T1140) (v1.3→v1.4) * [Deploy Container](/techniques/T1610) (v1.3→v1.4) * [Direct Volume Access](/techniques/T1006) (v2.2→v2.3) * [Disk Wipe](/techniques/T1561) (v1.1→v1.2) - * [Disk Content Wipe](/techniques/T1561/001) (v1.1→v1.2) - * [Disk Structure Wipe](/techniques/T1561/002) (v1.1→v1.2) + * [Disk Content Wipe](/techniques/T1561/001) (v1.1→v1.2) + * [Disk Structure Wipe](/techniques/T1561/002) (v1.1→v1.2) * [Domain or Tenant Policy Modification](/techniques/T1484) (v3.1→v3.2) - * [Group Policy Modification](/techniques/T1484/001) (v1.0→v1.1) - * [Trust Modification](/techniques/T1484/002) (v2.1→v2.2) + * [Group Policy Modification](/techniques/T1484/001) (v1.0→v1.1) + * [Trust Modification](/techniques/T1484/002) (v2.1→v2.2) * [Drive-by Compromise](/techniques/T1189) (v1.6→v1.7) * [Dynamic Resolution](/techniques/T1568) (v1.0→v1.1) - * [DNS Calculation](/techniques/T1568/003) (v1.0→v1.1) - * [Domain Generation Algorithms](/techniques/T1568/002) (v1.1→v1.2) - * [Fast Flux DNS](/techniques/T1568/001) (v1.0→v1.1) + * [DNS Calculation](/techniques/T1568/003) (v1.0→v1.1) + * [Domain Generation Algorithms](/techniques/T1568/002) (v1.1→v1.2) + * [Fast Flux DNS](/techniques/T1568/001) (v1.0→v1.1) * Email Collection: [Local Email Collection](/techniques/T1114/001) (v1.0→v1.1) * [Encrypted Channel](/techniques/T1573) (v1.1→v1.2) - * [Asymmetric Cryptography](/techniques/T1573/002) (v1.1→v1.2) - * [Symmetric Cryptography](/techniques/T1573/001) (v1.1→v1.2) + * [Asymmetric Cryptography](/techniques/T1573/002) (v1.1→v1.2) + * [Symmetric Cryptography](/techniques/T1573/001) (v1.1→v1.2) * [Escape to Host](/techniques/T1611) (v1.5→v1.6) * Event Triggered Execution: [Accessibility Features](/techniques/T1546/008) (v1.1→v1.2) * Event Triggered Execution: [AppCert DLLs](/techniques/T1546/009) (v1.0→v1.1) @@ -187,20 +196,20 @@ * Event Triggered Execution: [Unix Shell Configuration Modification](/techniques/T1546/004) (v2.1→v2.2) * Event Triggered Execution: [Windows Management Instrumentation Event Subscription](/techniques/T1546/003) (v1.4→v1.5) * [Execution Guardrails](/techniques/T1480) (v1.2→v1.3) - * [Environmental Keying](/techniques/T1480/001) (v1.0→v1.1) + * [Environmental Keying](/techniques/T1480/001) (v1.0→v1.1) * [Exfiltration Over Alternative Protocol](/techniques/T1048) (v1.5→v1.6) - * [Exfiltration Over Asymmetric Encrypted Non-C2 Protocol](/techniques/T1048/002) (v1.1→v1.2) - * [Exfiltration Over Symmetric Encrypted Non-C2 Protocol](/techniques/T1048/001) (v1.0→v1.1) - * [Exfiltration Over Unencrypted Non-C2 Protocol](/techniques/T1048/003) (v2.1→v2.2) + * [Exfiltration Over Asymmetric Encrypted Non-C2 Protocol](/techniques/T1048/002) (v1.1→v1.2) + * [Exfiltration Over Symmetric Encrypted Non-C2 Protocol](/techniques/T1048/001) (v1.0→v1.1) + * [Exfiltration Over Unencrypted Non-C2 Protocol](/techniques/T1048/003) (v2.1→v2.2) * [Exfiltration Over C2 Channel](/techniques/T1041) (v2.2→v2.3) * Exfiltration Over Other Network Medium: [Exfiltration Over Bluetooth](/techniques/T1011/001) (v1.1→v1.2) * [Exfiltration Over Physical Medium](/techniques/T1052) (v1.2→v1.3) - * [Exfiltration over USB](/techniques/T1052/001) (v1.1→v1.2) + * [Exfiltration over USB](/techniques/T1052/001) (v1.1→v1.2) * [Exfiltration Over Web Service](/techniques/T1567) (v1.4→v1.5) - * [Exfiltration Over Webhook](/techniques/T1567/004) (v1.1→v1.2) - * [Exfiltration to Cloud Storage](/techniques/T1567/002) (v1.2→v1.3) - * [Exfiltration to Code Repository](/techniques/T1567/001) (v1.1→v1.2) - * [Exfiltration to Text Storage Sites](/techniques/T1567/003) (v1.0→v1.1) + * [Exfiltration Over Webhook](/techniques/T1567/004) (v1.1→v1.2) + * [Exfiltration to Cloud Storage](/techniques/T1567/002) (v1.2→v1.3) + * [Exfiltration to Code Repository](/techniques/T1567/001) (v1.1→v1.2) + * [Exfiltration to Text Storage Sites](/techniques/T1567/003) (v1.0→v1.1) * [Exploit Public-Facing Application](/techniques/T1190) (v2.6→v2.7) * [Exploitation for Client Execution](/techniques/T1203) (v1.4→v1.5) * [Exploitation for Defense Evasion](/techniques/T1211) (v1.4→v1.5) @@ -212,69 +221,69 @@ * [Firmware Corruption](/techniques/T1495) (v1.2→v1.3) * [Hardware Additions](/techniques/T1200) (v1.6→v1.7) * [Hide Artifacts](/techniques/T1564) (v1.3→v1.4) - * [Hidden File System](/techniques/T1564/005) (v1.0→v1.1) - * [Hidden Files and Directories](/techniques/T1564/001) (v1.0→v1.1) - * [Hidden Window](/techniques/T1564/003) (v1.2→v1.3) - * [NTFS File Attributes](/techniques/T1564/004) (v1.1→v1.2) - * [Process Argument Spoofing](/techniques/T1564/010) (v1.0→v1.1) - * [Resource Forking](/techniques/T1564/009) (v1.0→v1.1) - * [Run Virtual Instance](/techniques/T1564/006) (v1.1→v1.2) - * [VBA Stomping](/techniques/T1564/007) (v1.1→v1.2) + * [Hidden File System](/techniques/T1564/005) (v1.0→v1.1) + * [Hidden Files and Directories](/techniques/T1564/001) (v1.0→v1.1) + * [Hidden Window](/techniques/T1564/003) (v1.2→v1.3) + * [NTFS File Attributes](/techniques/T1564/004) (v1.1→v1.2) + * [Process Argument Spoofing](/techniques/T1564/010) (v1.0→v1.1) + * [Resource Forking](/techniques/T1564/009) (v1.0→v1.1) + * [Run Virtual Instance](/techniques/T1564/006) (v1.1→v1.2) + * [VBA Stomping](/techniques/T1564/007) (v1.1→v1.2) * [Hide Infrastructure](/techniques/T1665) (v1.0→v1.1) * [Hijack Execution Flow](/techniques/T1574) (v1.2→v1.3) - * [COR_PROFILER](/techniques/T1574/012) (v1.0→v1.1) - * [Dylib Hijacking](/techniques/T1574/004) (v2.0→v2.1) - * [Dynamic Linker Hijacking](/techniques/T1574/006) (v2.0→v2.1) - * [Executable Installer File Permissions Weakness](/techniques/T1574/005) (v1.0→v1.1) - * [Path Interception by PATH Environment Variable](/techniques/T1574/007) (v1.1→v1.2) - * [Path Interception by Search Order Hijacking](/techniques/T1574/008) (v1.0→v1.1) - * [Services File Permissions Weakness](/techniques/T1574/010) (v1.0→v1.1) - * [Services Registry Permissions Weakness](/techniques/T1574/011) (v1.1→v1.2) + * [COR_PROFILER](/techniques/T1574/012) (v1.0→v1.1) + * [Dylib Hijacking](/techniques/T1574/004) (v2.0→v2.1) + * [Dynamic Linker Hijacking](/techniques/T1574/006) (v2.0→v2.1) + * [Executable Installer File Permissions Weakness](/techniques/T1574/005) (v1.0→v1.1) + * [Path Interception by PATH Environment Variable](/techniques/T1574/007) (v1.1→v1.2) + * [Path Interception by Search Order Hijacking](/techniques/T1574/008) (v1.0→v1.1) + * [Services File Permissions Weakness](/techniques/T1574/010) (v1.0→v1.1) + * [Services Registry Permissions Weakness](/techniques/T1574/011) (v1.1→v1.2) * [Impair Defenses](/techniques/T1562) (v1.6→v1.7) - * [Disable Windows Event Logging](/techniques/T1562/002) (v1.3→v1.4) - * [Disable or Modify System Firewall](/techniques/T1562/004) (v1.2→v1.3) - * [Disable or Modify Tools](/techniques/T1562/001) (v1.5→v1.6) - * [Downgrade Attack](/techniques/T1562/010) (v1.2→v1.3) - * [Impair Command History Logging](/techniques/T1562/003) (v2.2→v2.3) - * [Indicator Blocking](/techniques/T1562/006) (v1.4→v1.5) - * [Safe Mode Boot](/techniques/T1562/009) (v1.0→v1.1) + * [Disable Windows Event Logging](/techniques/T1562/002) (v1.3→v1.4) + * [Disable or Modify System Firewall](/techniques/T1562/004) (v1.2→v1.3) + * [Disable or Modify Tools](/techniques/T1562/001) (v1.5→v1.6) + * [Downgrade Attack](/techniques/T1562/010) (v1.2→v1.3) + * [Impair Command History Logging](/techniques/T1562/003) (v2.2→v2.3) + * [Indicator Blocking](/techniques/T1562/006) (v1.4→v1.5) + * [Safe Mode Boot](/techniques/T1562/009) (v1.0→v1.1) * [Implant Internal Image](/techniques/T1525) (v2.1→v2.2) * [Indicator Removal](/techniques/T1070) (v2.2→v2.3) - * [Clear Command History](/techniques/T1070/003) (v1.5→v1.6) - * [Clear Network Connection History and Configurations](/techniques/T1070/007) (v1.1→v1.2) - * [Clear Persistence](/techniques/T1070/009) (v1.1→v1.2) - * [Clear Windows Event Logs](/techniques/T1070/001) (v1.4→v1.5) - * [File Deletion](/techniques/T1070/004) (v1.1→v1.2) - * [Network Share Connection Removal](/techniques/T1070/005) (v1.1→v1.2) - * [Relocate Malware](/techniques/T1070/010) (v1.0→v1.1) - * [Timestomp](/techniques/T1070/006) (v1.1→v1.2) + * [Clear Command History](/techniques/T1070/003) (v1.5→v1.6) + * [Clear Network Connection History and Configurations](/techniques/T1070/007) (v1.1→v1.2) + * [Clear Persistence](/techniques/T1070/009) (v1.1→v1.2) + * [Clear Windows Event Logs](/techniques/T1070/001) (v1.4→v1.5) + * [File Deletion](/techniques/T1070/004) (v1.1→v1.2) + * [Network Share Connection Removal](/techniques/T1070/005) (v1.1→v1.2) + * [Relocate Malware](/techniques/T1070/010) (v1.0→v1.1) + * [Timestomp](/techniques/T1070/006) (v1.1→v1.2) * [Indirect Command Execution](/techniques/T1202) (v1.2→v1.3) * [Ingress Tool Transfer](/techniques/T1105) (v2.4→v2.5) * [Inhibit System Recovery](/techniques/T1490) (v1.5→v1.6) * [Input Capture](/techniques/T1056) (v1.3→v1.4) - * [Credential API Hooking](/techniques/T1056/004) (v1.1→v1.2) - * [Keylogging](/techniques/T1056/001) (v1.2→v1.3) - * [Web Portal Capture](/techniques/T1056/003) (v1.0→v1.1) + * [Credential API Hooking](/techniques/T1056/004) (v1.1→v1.2) + * [Keylogging](/techniques/T1056/001) (v1.2→v1.3) + * [Web Portal Capture](/techniques/T1056/003) (v1.0→v1.1) * [Inter-Process Communication](/techniques/T1559) (v1.3→v1.4) - * [Component Object Model](/techniques/T1559/001) (v1.1→v1.2) - * [Dynamic Data Exchange](/techniques/T1559/002) (v1.3→v1.4) - * [XPC Services](/techniques/T1559/003) (v1.0→v1.1) + * [Component Object Model](/techniques/T1559/001) (v1.1→v1.2) + * [Dynamic Data Exchange](/techniques/T1559/002) (v1.3→v1.4) + * [XPC Services](/techniques/T1559/003) (v1.0→v1.1) * [Lateral Tool Transfer](/techniques/T1570) (v1.3→v1.4) * [Log Enumeration](/techniques/T1654) (v1.1→v1.2) * [Masquerading](/techniques/T1036) (v1.7→v1.8) - * [Masquerade File Type](/techniques/T1036/008) (v1.0→v1.1) - * [Space after Filename](/techniques/T1036/006) (v1.0→v1.1) + * [Masquerade File Type](/techniques/T1036/008) (v1.0→v1.1) + * [Space after Filename](/techniques/T1036/006) (v1.0→v1.1) * [Modify Authentication Process](/techniques/T1556) (v2.5→v2.6) - * [Multi-Factor Authentication](/techniques/T1556/006) (v1.3→v1.4) - * [Network Device Authentication](/techniques/T1556/004) (v2.0→v2.1) + * [Multi-Factor Authentication](/techniques/T1556/006) (v1.3→v1.4) + * [Network Device Authentication](/techniques/T1556/004) (v2.0→v2.1) * Modify Cloud Compute Infrastructure: [Revert Cloud Instance](/techniques/T1578/004) (v1.1→v1.2) * [Modify System Image](/techniques/T1601) (v1.0→v1.1) - * [Downgrade System Image](/techniques/T1601/002) (v1.0→v1.1) - * [Patch System Image](/techniques/T1601/001) (v1.0→v1.1) + * [Downgrade System Image](/techniques/T1601/002) (v1.0→v1.1) + * [Patch System Image](/techniques/T1601/001) (v1.0→v1.1) * [Multi-Stage Channels](/techniques/T1104) (v1.0→v1.1) * [Native API](/techniques/T1106) (v2.2→v2.3) * [Network Boundary Bridging](/techniques/T1599) (v1.1→v1.2) - * [Network Address Translation Traversal](/techniques/T1599/001) (v1.0→v1.1) + * [Network Address Translation Traversal](/techniques/T1599/001) (v1.0→v1.1) * [Network Service Discovery](/techniques/T1046) (v3.1→v3.2) * [Network Sniffing](/techniques/T1040) (v1.6→v1.7) * [Non-Application Layer Protocol](/techniques/T1095) (v2.3→v2.4) @@ -282,70 +291,70 @@ * OS Credential Dumping: [/etc/passwd and /etc/shadow](/techniques/T1003/008) (v1.1→v1.2) * OS Credential Dumping: [NTDS](/techniques/T1003/003) (v1.2→v1.3) * [Obfuscated Files or Information](/techniques/T1027) (v1.6→v1.7) - * [Binary Padding](/techniques/T1027/001) (v1.2→v1.3) - * [Compile After Delivery](/techniques/T1027/004) (v1.1→v1.2) - * [Embedded Payloads](/techniques/T1027/009) (v1.1→v1.2) - * [Encrypted/Encoded File](/techniques/T1027/013) (v1.0→v1.1) - * [HTML Smuggling](/techniques/T1027/006) (v1.1→v1.2) - * [Indicator Removal from Tools](/techniques/T1027/005) (v1.1→v1.2) - * [Polymorphic Code](/techniques/T1027/014) (v1.0→v1.1) - * [Software Packing](/techniques/T1027/002) (v1.2→v1.3) - * [Stripped Payloads](/techniques/T1027/008) (v1.1→v1.2) + * [Binary Padding](/techniques/T1027/001) (v1.2→v1.3) + * [Compile After Delivery](/techniques/T1027/004) (v1.1→v1.2) + * [Embedded Payloads](/techniques/T1027/009) (v1.1→v1.2) + * [Encrypted/Encoded File](/techniques/T1027/013) (v1.0→v1.1) + * [HTML Smuggling](/techniques/T1027/006) (v1.1→v1.2) + * [Indicator Removal from Tools](/techniques/T1027/005) (v1.1→v1.2) + * [Polymorphic Code](/techniques/T1027/014) (v1.0→v1.1) + * [Software Packing](/techniques/T1027/002) (v1.2→v1.3) + * [Stripped Payloads](/techniques/T1027/008) (v1.1→v1.2) * Obtain Capabilities: [Artificial Intelligence](/techniques/T1588/007) (v1.0→v1.1) * [Password Policy Discovery](/techniques/T1201) (v1.6→v1.7) * [Peripheral Device Discovery](/techniques/T1120) (v1.3→v1.4) * [Phishing](/techniques/T1566) (v2.6→v2.7) - * [Spearphishing Voice](/techniques/T1566/004) (v1.1→v1.2) + * [Spearphishing Voice](/techniques/T1566/004) (v1.1→v1.2) * [Phishing for Information](/techniques/T1598) (v1.3→v1.4) - * [Spearphishing Attachment](/techniques/T1598/002) (v1.1→v1.2) + * [Spearphishing Attachment](/techniques/T1598/002) (v1.1→v1.2) * [Power Settings](/techniques/T1653) (v1.0→v1.1) * [Pre-OS Boot](/techniques/T1542) (v1.2→v1.3) - * [Bootkit](/techniques/T1542/003) (v1.1→v1.2) - * [Component Firmware](/techniques/T1542/002) (v1.1→v1.2) - * [ROMMONkit](/techniques/T1542/004) (v1.0→v1.1) - * [System Firmware](/techniques/T1542/001) (v1.1→v1.2) - * [TFTP Boot](/techniques/T1542/005) (v1.0→v1.1) + * [Bootkit](/techniques/T1542/003) (v1.1→v1.2) + * [Component Firmware](/techniques/T1542/002) (v1.1→v1.2) + * [ROMMONkit](/techniques/T1542/004) (v1.0→v1.1) + * [System Firmware](/techniques/T1542/001) (v1.1→v1.2) + * [TFTP Boot](/techniques/T1542/005) (v1.0→v1.1) * [Process Discovery](/techniques/T1057) (v1.5→v1.6) * [Process Injection](/techniques/T1055) (v1.3→v1.4) - * [Asynchronous Procedure Call](/techniques/T1055/004) (v1.1→v1.2) - * [Dynamic-link Library Injection](/techniques/T1055/001) (v1.3→v1.4) - * [Extra Window Memory Injection](/techniques/T1055/011) (v1.0→v1.1) - * [ListPlanting](/techniques/T1055/015) (v1.1→v1.2) - * [Portable Executable Injection](/techniques/T1055/002) (v1.1→v1.2) - * [Proc Memory](/techniques/T1055/009) (v1.0→v1.1) - * [Process Doppelgänging](/techniques/T1055/013) (v1.0→v1.1) - * [Process Hollowing](/techniques/T1055/012) (v1.3→v1.4) - * [Ptrace System Calls](/techniques/T1055/008) (v1.1→v1.2) - * [Thread Execution Hijacking](/techniques/T1055/003) (v1.1→v1.2) - * [Thread Local Storage](/techniques/T1055/005) (v1.1→v1.2) - * [VDSO Hijacking](/techniques/T1055/014) (v1.1→v1.2) + * [Asynchronous Procedure Call](/techniques/T1055/004) (v1.1→v1.2) + * [Dynamic-link Library Injection](/techniques/T1055/001) (v1.3→v1.4) + * [Extra Window Memory Injection](/techniques/T1055/011) (v1.0→v1.1) + * [ListPlanting](/techniques/T1055/015) (v1.1→v1.2) + * [Portable Executable Injection](/techniques/T1055/002) (v1.1→v1.2) + * [Proc Memory](/techniques/T1055/009) (v1.0→v1.1) + * [Process Doppelgänging](/techniques/T1055/013) (v1.0→v1.1) + * [Process Hollowing](/techniques/T1055/012) (v1.3→v1.4) + * [Ptrace System Calls](/techniques/T1055/008) (v1.1→v1.2) + * [Thread Execution Hijacking](/techniques/T1055/003) (v1.1→v1.2) + * [Thread Local Storage](/techniques/T1055/005) (v1.1→v1.2) + * [VDSO Hijacking](/techniques/T1055/014) (v1.1→v1.2) * [Protocol Tunneling](/techniques/T1572) (v1.0→v1.1) * [Proxy](/techniques/T1090) (v3.1→v3.2) - * [Domain Fronting](/techniques/T1090/004) (v1.1→v1.2) - * [External Proxy](/techniques/T1090/002) (v1.1→v1.2) - * [Internal Proxy](/techniques/T1090/001) (v1.1→v1.2) - * [Multi-hop Proxy](/techniques/T1090/003) (v2.2→v2.3) + * [Domain Fronting](/techniques/T1090/004) (v1.1→v1.2) + * [External Proxy](/techniques/T1090/002) (v1.1→v1.2) + * [Internal Proxy](/techniques/T1090/001) (v1.1→v1.2) + * [Multi-hop Proxy](/techniques/T1090/003) (v2.2→v2.3) * [Reflective Code Loading](/techniques/T1620) (v1.2→v1.3) * Remote Service Session Hijacking: [SSH Hijacking](/techniques/T1563/001) (v1.0→v1.1) * [Remote Services](/techniques/T1021) (v1.5→v1.6) - * [Remote Desktop Protocol](/techniques/T1021/001) (v1.2→v1.3) - * [SMB/Windows Admin Shares](/techniques/T1021/002) (v1.2→v1.3) - * [SSH](/techniques/T1021/004) (v1.2→v1.3) - * [VNC](/techniques/T1021/005) (v1.1→v1.2) + * [Remote Desktop Protocol](/techniques/T1021/001) (v1.2→v1.3) + * [SMB/Windows Admin Shares](/techniques/T1021/002) (v1.2→v1.3) + * [SSH](/techniques/T1021/004) (v1.2→v1.3) + * [VNC](/techniques/T1021/005) (v1.1→v1.2) * [Remote System Discovery](/techniques/T1018) (v3.5→v3.6) * [Replication Through Removable Media](/techniques/T1091) (v1.2→v1.3) * [Rogue Domain Controller](/techniques/T1207) (v2.1→v2.2) * [Rootkit](/techniques/T1014) (v1.1→v1.2) * [Scheduled Task/Job](/techniques/T1053) (v2.3→v2.4) - * [At](/techniques/T1053/002) (v2.3→v2.4) - * [Container Orchestration Job](/techniques/T1053/007) (v1.3→v1.4) - * [Cron](/techniques/T1053/003) (v1.2→v1.3) - * [Scheduled Task](/techniques/T1053/005) (v1.6→v1.7) - * [Systemd Timers](/techniques/T1053/006) (v1.2→v1.3) + * [At](/techniques/T1053/002) (v2.3→v2.4) + * [Container Orchestration Job](/techniques/T1053/007) (v1.3→v1.4) + * [Cron](/techniques/T1053/003) (v1.2→v1.3) + * [Scheduled Task](/techniques/T1053/005) (v1.6→v1.7) + * [Systemd Timers](/techniques/T1053/006) (v1.2→v1.3) * [Server Software Component](/techniques/T1505) (v1.4→v1.5) - * [IIS Components](/techniques/T1505/004) (v1.0→v1.1) - * [Transport Agent](/techniques/T1505/002) (v1.0→v1.1) - * [Web Shell](/techniques/T1505/003) (v1.4→v1.5) + * [IIS Components](/techniques/T1505/004) (v1.0→v1.1) + * [Transport Agent](/techniques/T1505/002) (v1.0→v1.1) + * [Web Shell](/techniques/T1505/003) (v1.4→v1.5) * [Serverless Execution](/techniques/T1648) (v1.1→v1.2) * [Service Stop](/techniques/T1489) (v1.2→v1.3) * [Shared Modules](/techniques/T1129) (v2.2→v2.3) @@ -353,80 +362,80 @@ * [Software Discovery](/techniques/T1518) (v1.4→v1.5) * [Steal Application Access Token](/techniques/T1528) (v1.4→v1.5) * [Steal or Forge Kerberos Tickets](/techniques/T1558) (v1.6→v1.7) - * [AS-REP Roasting](/techniques/T1558/004) (v1.1→v1.2) - * [Golden Ticket](/techniques/T1558/001) (v1.1→v1.2) - * [Kerberoasting](/techniques/T1558/003) (v1.2→v1.3) - * [Silver Ticket](/techniques/T1558/002) (v1.0→v1.1) + * [AS-REP Roasting](/techniques/T1558/004) (v1.1→v1.2) + * [Golden Ticket](/techniques/T1558/001) (v1.1→v1.2) + * [Kerberoasting](/techniques/T1558/003) (v1.2→v1.3) + * [Silver Ticket](/techniques/T1558/002) (v1.0→v1.1) * [Subvert Trust Controls](/techniques/T1553) (v1.2→v1.3) - * [Code Signing](/techniques/T1553/002) (v1.1→v1.2) - * [Code Signing Policy Modification](/techniques/T1553/006) (v1.0→v1.1) - * [Gatekeeper Bypass](/techniques/T1553/001) (v1.2→v1.3) - * [Install Root Certificate](/techniques/T1553/004) (v1.2→v1.3) - * [Mark-of-the-Web Bypass](/techniques/T1553/005) (v1.1→v1.2) - * [SIP and Trust Provider Hijacking](/techniques/T1553/003) (v1.0→v1.1) + * [Code Signing](/techniques/T1553/002) (v1.1→v1.2) + * [Code Signing Policy Modification](/techniques/T1553/006) (v1.0→v1.1) + * [Gatekeeper Bypass](/techniques/T1553/001) (v1.2→v1.3) + * [Install Root Certificate](/techniques/T1553/004) (v1.2→v1.3) + * [Mark-of-the-Web Bypass](/techniques/T1553/005) (v1.1→v1.2) + * [SIP and Trust Provider Hijacking](/techniques/T1553/003) (v1.0→v1.1) * [System Binary Proxy Execution](/techniques/T1218) (v3.1→v3.2) - * [CMSTP](/techniques/T1218/003) (v2.1→v2.2) - * [Compiled HTML File](/techniques/T1218/001) (v2.1→v2.2) - * [Control Panel](/techniques/T1218/002) (v2.0→v2.1) - * [InstallUtil](/techniques/T1218/004) (v2.0→v2.1) - * [MMC](/techniques/T1218/014) (v2.0→v2.1) - * [Mshta](/techniques/T1218/005) (v2.0→v2.1) - * [Msiexec](/techniques/T1218/007) (v2.0→v2.1) - * [Odbcconf](/techniques/T1218/008) (v2.0→v2.1) - * [Regsvcs/Regasm](/techniques/T1218/009) (v2.0→v2.1) - * [Regsvr32](/techniques/T1218/010) (v2.1→v2.2) - * [Rundll32](/techniques/T1218/011) (v2.3→v2.4) - * [Verclsid](/techniques/T1218/012) (v2.0→v2.1) + * [CMSTP](/techniques/T1218/003) (v2.1→v2.2) + * [Compiled HTML File](/techniques/T1218/001) (v2.1→v2.2) + * [Control Panel](/techniques/T1218/002) (v2.0→v2.1) + * [InstallUtil](/techniques/T1218/004) (v2.0→v2.1) + * [MMC](/techniques/T1218/014) (v2.0→v2.1) + * [Mshta](/techniques/T1218/005) (v2.0→v2.1) + * [Msiexec](/techniques/T1218/007) (v2.0→v2.1) + * [Odbcconf](/techniques/T1218/008) (v2.0→v2.1) + * [Regsvcs/Regasm](/techniques/T1218/009) (v2.0→v2.1) + * [Regsvr32](/techniques/T1218/010) (v2.1→v2.2) + * [Rundll32](/techniques/T1218/011) (v2.3→v2.4) + * [Verclsid](/techniques/T1218/012) (v2.0→v2.1) * [System Information Discovery](/techniques/T1082) (v2.5→v2.6) * System Location Discovery: [System Language Discovery](/techniques/T1614/001) (v1.0→v1.1) * [System Network Configuration Discovery](/techniques/T1016) (v1.6→v1.7) - * [Internet Connection Discovery](/techniques/T1016/001) (v1.0→v1.1) + * [Internet Connection Discovery](/techniques/T1016/001) (v1.0→v1.1) * [System Network Connections Discovery](/techniques/T1049) (v2.4→v2.5) * [System Owner/User Discovery](/techniques/T1033) (v1.5→v1.6) * [System Script Proxy Execution](/techniques/T1216) (v2.0→v2.1) - * [PubPrn](/techniques/T1216/001) (v2.0→v2.1) + * [PubPrn](/techniques/T1216/001) (v2.0→v2.1) * [System Services](/techniques/T1569) (v1.3→v1.4) - * [Launchctl](/techniques/T1569/001) (v1.2→v1.3) - * [Service Execution](/techniques/T1569/002) (v1.2→v1.3) + * [Launchctl](/techniques/T1569/001) (v1.2→v1.3) + * [Service Execution](/techniques/T1569/002) (v1.2→v1.3) * [System Shutdown/Reboot](/techniques/T1529) (v1.3→v1.4) * [System Time Discovery](/techniques/T1124) (v1.4→v1.5) * [Taint Shared Content](/techniques/T1080) (v1.5→v1.6) * [Template Injection](/techniques/T1221) (v1.3→v1.4) * [Traffic Signaling](/techniques/T1205) (v2.4→v2.5) - * [Port Knocking](/techniques/T1205/001) (v1.1→v1.2) + * [Port Knocking](/techniques/T1205/001) (v1.1→v1.2) * [Trusted Developer Utilities Proxy Execution](/techniques/T1127) (v1.2→v1.3) - * [ClickOnce](/techniques/T1127/002) (v1.0→v1.1) - * [MSBuild](/techniques/T1127/001) (v1.3→v1.4) + * [ClickOnce](/techniques/T1127/002) (v1.0→v1.1) + * [MSBuild](/techniques/T1127/001) (v1.3→v1.4) * [Unsecured Credentials](/techniques/T1552) (v1.4→v1.5) - * [Credentials In Files](/techniques/T1552/001) (v1.2→v1.3) - * [Credentials in Registry](/techniques/T1552/002) (v1.1→v1.2) - * [Private Keys](/techniques/T1552/004) (v1.2→v1.3) + * [Credentials In Files](/techniques/T1552/001) (v1.2→v1.3) + * [Credentials in Registry](/techniques/T1552/002) (v1.1→v1.2) + * [Private Keys](/techniques/T1552/004) (v1.2→v1.3) * [Use Alternate Authentication Material](/techniques/T1550) (v1.4→v1.5) - * [Application Access Token](/techniques/T1550/001) (v1.7→v1.8) - * [Pass the Hash](/techniques/T1550/002) (v1.2→v1.3) - * [Pass the Ticket](/techniques/T1550/003) (v1.1→v1.2) - * [Web Session Cookie](/techniques/T1550/004) (v1.4→v1.5) + * [Application Access Token](/techniques/T1550/001) (v1.7→v1.8) + * [Pass the Hash](/techniques/T1550/002) (v1.2→v1.3) + * [Pass the Ticket](/techniques/T1550/003) (v1.1→v1.2) + * [Web Session Cookie](/techniques/T1550/004) (v1.4→v1.5) * [User Execution](/techniques/T1204) (v1.7→v1.8) - * [Malicious File](/techniques/T1204/002) (v1.4→v1.5) - * [Malicious Image](/techniques/T1204/003) (v1.1→v1.2) - * [Malicious Link](/techniques/T1204/001) (v1.1→v1.2) + * [Malicious File](/techniques/T1204/002) (v1.4→v1.5) + * [Malicious Image](/techniques/T1204/003) (v1.1→v1.2) + * [Malicious Link](/techniques/T1204/001) (v1.1→v1.2) * [Valid Accounts](/techniques/T1078) (v2.7→v2.8) - * [Cloud Accounts](/techniques/T1078/004) (v1.8→v1.9) - * [Default Accounts](/techniques/T1078/001) (v1.4→v1.5) - * [Domain Accounts](/techniques/T1078/002) (v1.4→v1.5) - * [Local Accounts](/techniques/T1078/003) (v1.4→v1.5) + * [Cloud Accounts](/techniques/T1078/004) (v1.8→v1.9) + * [Default Accounts](/techniques/T1078/001) (v1.4→v1.5) + * [Domain Accounts](/techniques/T1078/002) (v1.4→v1.5) + * [Local Accounts](/techniques/T1078/003) (v1.4→v1.5) * [Video Capture](/techniques/T1125) (v1.1→v1.2) * [Virtualization/Sandbox Evasion](/techniques/T1497) (v1.3→v1.4) - * [System Checks](/techniques/T1497/001) (v2.2→v2.3) - * [Time Based Evasion](/techniques/T1497/003) (v1.2→v1.3) - * [User Activity Based Checks](/techniques/T1497/002) (v1.1→v1.2) + * [System Checks](/techniques/T1497/001) (v2.2→v2.3) + * [Time Based Evasion](/techniques/T1497/003) (v1.2→v1.3) + * [User Activity Based Checks](/techniques/T1497/002) (v1.1→v1.2) * [Weaken Encryption](/techniques/T1600) (v1.0→v1.1) - * [Disable Crypto Hardware](/techniques/T1600/002) (v1.0→v1.1) - * [Reduce Key Space](/techniques/T1600/001) (v1.0→v1.1) + * [Disable Crypto Hardware](/techniques/T1600/002) (v1.0→v1.1) + * [Reduce Key Space](/techniques/T1600/001) (v1.0→v1.1) * [Web Service](/techniques/T1102) (v1.2→v1.3) - * [Bidirectional Communication](/techniques/T1102/002) (v1.0→v1.1) - * [Dead Drop Resolver](/techniques/T1102/001) (v1.0→v1.1) - * [One-Way Communication](/techniques/T1102/003) (v1.0→v1.1) + * [Bidirectional Communication](/techniques/T1102/002) (v1.0→v1.1) + * [Dead Drop Resolver](/techniques/T1102/001) (v1.0→v1.1) + * [One-Way Communication](/techniques/T1102/003) (v1.0→v1.1) * [Windows Management Instrumentation](/techniques/T1047) (v1.5→v1.6) * [XSL Script Processing](/techniques/T1220) (v1.2→v1.3) @@ -445,24 +454,24 @@ * Account Manipulation: [Device Registration](/techniques/T1098/005) (v1.3) * [Acquire Access](/techniques/T1650) (v1.0) * [Acquire Infrastructure](/techniques/T1583) (v1.4) - * [DNS Server](/techniques/T1583/002) (v1.0) - * [Domains](/techniques/T1583/001) (v1.4) - * [Malvertising](/techniques/T1583/008) (v1.0) - * [Server](/techniques/T1583/004) (v1.3) - * [Serverless](/techniques/T1583/007) (v1.1) - * [Virtual Private Server](/techniques/T1583/003) (v1.1) + * [DNS Server](/techniques/T1583/002) (v1.0) + * [Domains](/techniques/T1583/001) (v1.4) + * [Malvertising](/techniques/T1583/008) (v1.0) + * [Server](/techniques/T1583/004) (v1.3) + * [Serverless](/techniques/T1583/007) (v1.1) + * [Virtual Private Server](/techniques/T1583/003) (v1.1) * [Active Scanning](/techniques/T1595) (v1.0) - * [Scanning IP Blocks](/techniques/T1595/001) (v1.1) - * [Vulnerability Scanning](/techniques/T1595/002) (v1.0) - * [Wordlist Scanning](/techniques/T1595/003) (v1.0) + * [Scanning IP Blocks](/techniques/T1595/001) (v1.1) + * [Vulnerability Scanning](/techniques/T1595/002) (v1.0) + * [Wordlist Scanning](/techniques/T1595/003) (v1.0) * Adversary-in-the-Middle: [ARP Cache Poisoning](/techniques/T1557/002) (v1.1) * Adversary-in-the-Middle: [DHCP Spoofing](/techniques/T1557/003) (v1.1) * Adversary-in-the-Middle: [LLMNR/NBT-NS Poisoning and SMB Relay](/techniques/T1557/001) (v1.4) * [Application Window Discovery](/techniques/T1010) (v1.3) * [Archive Collected Data](/techniques/T1560) (v1.0) - * [Archive via Custom Method](/techniques/T1560/003) (v1.0) - * [Archive via Library](/techniques/T1560/002) (v1.0) - * [Archive via Utility](/techniques/T1560/001) (v1.3) + * [Archive via Custom Method](/techniques/T1560/003) (v1.0) + * [Archive via Library](/techniques/T1560/002) (v1.0) + * [Archive via Utility](/techniques/T1560/001) (v1.3) * [Audio Capture](/techniques/T1123) (v1.0) * Boot or Logon Initialization Scripts: [Login Hook](/techniques/T1037/002) (v2.0) * Boot or Logon Initialization Scripts: [Logon Script (Windows)](/techniques/T1037/001) (v1.0) @@ -476,9 +485,9 @@ * Command and Scripting Interpreter: [JavaScript](/techniques/T1059/007) (v2.2) * [Communication Through Removable Media](/techniques/T1092) (v1.0) * [Compromise Accounts](/techniques/T1586) (v1.2) - * [Cloud Accounts](/techniques/T1586/003) (v1.1) - * [Email Accounts](/techniques/T1586/002) (v1.1) - * [Social Media Accounts](/techniques/T1586/001) (v1.1) + * [Cloud Accounts](/techniques/T1586/003) (v1.1) + * [Email Accounts](/techniques/T1586/002) (v1.1) + * [Social Media Accounts](/techniques/T1586/001) (v1.1) * Compromise Infrastructure: [Botnet](/techniques/T1584/005) (v1.0) * Compromise Infrastructure: [DNS Server](/techniques/T1584/002) (v1.2) * Compromise Infrastructure: [Domains](/techniques/T1584/001) (v1.4) @@ -492,47 +501,47 @@ * Create Account: [Cloud Account](/techniques/T1136/003) (v1.6) * Create Account: [Domain Account](/techniques/T1136/002) (v1.1) * [Create or Modify System Process](/techniques/T1543) (v1.2) - * [Container Service](/techniques/T1543/005) (v1.0) + * [Container Service](/techniques/T1543/005) (v1.0) * [Credentials from Password Stores](/techniques/T1555) (v1.2) - * [Cloud Secrets Management Stores](/techniques/T1555/006) (v1.0) - * [Credentials from Web Browsers](/techniques/T1555/003) (v1.2) - * [Keychain](/techniques/T1555/001) (v1.1) - * [Password Managers](/techniques/T1555/005) (v1.1) - * [Securityd Memory](/techniques/T1555/002) (v1.2) - * [Windows Credential Manager](/techniques/T1555/004) (v1.1) + * [Cloud Secrets Management Stores](/techniques/T1555/006) (v1.0) + * [Credentials from Web Browsers](/techniques/T1555/003) (v1.2) + * [Keychain](/techniques/T1555/001) (v1.1) + * [Password Managers](/techniques/T1555/005) (v1.1) + * [Securityd Memory](/techniques/T1555/002) (v1.2) + * [Windows Credential Manager](/techniques/T1555/004) (v1.1) * [Data Manipulation](/techniques/T1565) (v1.1) - * [Runtime Data Manipulation](/techniques/T1565/003) (v1.2) - * [Stored Data Manipulation](/techniques/T1565/001) (v1.1) - * [Transmitted Data Manipulation](/techniques/T1565/002) (v1.1) + * [Runtime Data Manipulation](/techniques/T1565/003) (v1.2) + * [Stored Data Manipulation](/techniques/T1565/001) (v1.1) + * [Transmitted Data Manipulation](/techniques/T1565/002) (v1.1) * [Data from Cloud Storage](/techniques/T1530) (v2.2) * [Data from Information Repositories](/techniques/T1213) (v3.4) - * [Code Repositories](/techniques/T1213/003) (v1.2) - * [Confluence](/techniques/T1213/001) (v1.1) - * [Customer Relationship Management Software](/techniques/T1213/004) (v1.0) - * [Messaging Applications](/techniques/T1213/005) (v1.0) - * [Sharepoint](/techniques/T1213/002) (v1.1) + * [Code Repositories](/techniques/T1213/003) (v1.2) + * [Confluence](/techniques/T1213/001) (v1.1) + * [Customer Relationship Management Software](/techniques/T1213/004) (v1.0) + * [Messaging Applications](/techniques/T1213/005) (v1.0) + * [Sharepoint](/techniques/T1213/002) (v1.1) * Defacement: [External Defacement](/techniques/T1491/002) (v1.2) * [Develop Capabilities](/techniques/T1587) (v1.1) - * [Code Signing Certificates](/techniques/T1587/002) (v1.1) - * [Digital Certificates](/techniques/T1587/003) (v1.2) - * [Exploits](/techniques/T1587/004) (v1.0) - * [Malware](/techniques/T1587/001) (v1.2) + * [Code Signing Certificates](/techniques/T1587/002) (v1.1) + * [Digital Certificates](/techniques/T1587/003) (v1.2) + * [Exploits](/techniques/T1587/004) (v1.0) + * [Malware](/techniques/T1587/001) (v1.2) * [Device Driver Discovery](/techniques/T1652) (v1.0) * [Domain Trust Discovery](/techniques/T1482) (v1.2) * [Email Collection](/techniques/T1114) (v2.6) - * [Email Forwarding Rule](/techniques/T1114/003) (v1.4) - * [Remote Email Collection](/techniques/T1114/002) (v1.3) + * [Email Forwarding Rule](/techniques/T1114/003) (v1.4) + * [Remote Email Collection](/techniques/T1114/002) (v1.3) * [Endpoint Denial of Service](/techniques/T1499) (v1.2) - * [Application Exhaustion Flood](/techniques/T1499/003) (v1.3) - * [Application or System Exploitation](/techniques/T1499/004) (v1.3) - * [OS Exhaustion Flood](/techniques/T1499/001) (v1.2) - * [Service Exhaustion Flood](/techniques/T1499/002) (v1.4) + * [Application Exhaustion Flood](/techniques/T1499/003) (v1.3) + * [Application or System Exploitation](/techniques/T1499/004) (v1.3) + * [OS Exhaustion Flood](/techniques/T1499/001) (v1.2) + * [Service Exhaustion Flood](/techniques/T1499/002) (v1.4) * [Establish Accounts](/techniques/T1585) (v1.3) - * [Cloud Accounts](/techniques/T1585/003) (v1.1) - * [Email Accounts](/techniques/T1585/002) (v1.1) - * [Social Media Accounts](/techniques/T1585/001) (v1.1) + * [Cloud Accounts](/techniques/T1585/003) (v1.1) + * [Email Accounts](/techniques/T1585/002) (v1.1) + * [Social Media Accounts](/techniques/T1585/001) (v1.1) * [Event Triggered Execution](/techniques/T1546) (v1.4) - * [Udev Rules](/techniques/T1546/017) (v1.0) + * [Udev Rules](/techniques/T1546/017) (v1.0) * Execution Guardrails: [Mutual Exclusion](/techniques/T1480/002) (v1.0) * [Exfiltration Over Other Network Medium](/techniques/T1011) (v1.2) * [Exploitation for Credential Access](/techniques/T1212) (v1.6) @@ -542,29 +551,29 @@ * [Financial Theft](/techniques/T1657) (v1.2) * [Forced Authentication](/techniques/T1187) (v1.3) * [Forge Web Credentials](/techniques/T1606) (v1.5) - * [SAML Tokens](/techniques/T1606/002) (v1.4) - * [Web Cookies](/techniques/T1606/001) (v1.1) + * [SAML Tokens](/techniques/T1606/002) (v1.4) + * [Web Cookies](/techniques/T1606/001) (v1.1) * [Gather Victim Host Information](/techniques/T1592) (v1.2) - * [Client Configurations](/techniques/T1592/004) (v1.1) - * [Firmware](/techniques/T1592/003) (v1.0) - * [Hardware](/techniques/T1592/001) (v1.1) - * [Software](/techniques/T1592/002) (v1.1) + * [Client Configurations](/techniques/T1592/004) (v1.1) + * [Firmware](/techniques/T1592/003) (v1.0) + * [Hardware](/techniques/T1592/001) (v1.1) + * [Software](/techniques/T1592/002) (v1.1) * [Gather Victim Identity Information](/techniques/T1589) (v1.3) - * [Credentials](/techniques/T1589/001) (v1.2) - * [Email Addresses](/techniques/T1589/002) (v1.2) - * [Employee Names](/techniques/T1589/003) (v1.0) + * [Credentials](/techniques/T1589/001) (v1.2) + * [Email Addresses](/techniques/T1589/002) (v1.2) + * [Employee Names](/techniques/T1589/003) (v1.0) * [Gather Victim Network Information](/techniques/T1590) (v1.0) - * [DNS](/techniques/T1590/002) (v1.2) - * [Domain Properties](/techniques/T1590/001) (v1.1) - * [IP Addresses](/techniques/T1590/005) (v1.0) - * [Network Security Appliances](/techniques/T1590/006) (v1.0) - * [Network Topology](/techniques/T1590/004) (v1.0) - * [Network Trust Dependencies](/techniques/T1590/003) (v1.0) + * [DNS](/techniques/T1590/002) (v1.2) + * [Domain Properties](/techniques/T1590/001) (v1.1) + * [IP Addresses](/techniques/T1590/005) (v1.0) + * [Network Security Appliances](/techniques/T1590/006) (v1.0) + * [Network Topology](/techniques/T1590/004) (v1.0) + * [Network Trust Dependencies](/techniques/T1590/003) (v1.0) * [Gather Victim Org Information](/techniques/T1591) (v1.1) - * [Business Relationships](/techniques/T1591/002) (v1.0) - * [Determine Physical Locations](/techniques/T1591/001) (v1.1) - * [Identify Business Tempo](/techniques/T1591/003) (v1.0) - * [Identify Roles](/techniques/T1591/004) (v1.0) + * [Business Relationships](/techniques/T1591/002) (v1.0) + * [Determine Physical Locations](/techniques/T1591/001) (v1.1) + * [Identify Business Tempo](/techniques/T1591/003) (v1.0) + * [Identify Roles](/techniques/T1591/004) (v1.0) * [Group Policy Discovery](/techniques/T1615) (v1.1) * Hide Artifacts: [Email Hiding Rules](/techniques/T1564/008) (v1.4) * Hide Artifacts: [File/Path Exclusions](/techniques/T1564/012) (v1.0) @@ -596,47 +605,47 @@ * Modify Authentication Process: [Pluggable Authentication Modules](/techniques/T1556/003) (v2.1) * Modify Authentication Process: [Reversible Encryption](/techniques/T1556/005) (v1.1) * [Modify Cloud Compute Infrastructure](/techniques/T1578) (v1.2) - * [Create Cloud Instance](/techniques/T1578/002) (v1.2) - * [Create Snapshot](/techniques/T1578/001) (v1.2) - * [Delete Cloud Instance](/techniques/T1578/003) (v1.2) - * [Modify Cloud Compute Configurations](/techniques/T1578/005) (v2.0) + * [Create Cloud Instance](/techniques/T1578/002) (v1.2) + * [Create Snapshot](/techniques/T1578/001) (v1.2) + * [Delete Cloud Instance](/techniques/T1578/003) (v1.2) + * [Modify Cloud Compute Configurations](/techniques/T1578/005) (v2.0) * [Modify Cloud Resource Hierarchy](/techniques/T1666) (v1.0) * [Multi-Factor Authentication Interception](/techniques/T1111) (v2.1) * [Multi-Factor Authentication Request Generation](/techniques/T1621) (v1.2) * [Network Denial of Service](/techniques/T1498) (v1.2) - * [Direct Network Flood](/techniques/T1498/001) (v1.4) - * [Reflection Amplification](/techniques/T1498/002) (v1.4) + * [Direct Network Flood](/techniques/T1498/001) (v1.4) + * [Reflection Amplification](/techniques/T1498/002) (v1.4) * [Network Share Discovery](/techniques/T1135) (v3.2) * [OS Credential Dumping](/techniques/T1003) (v2.2) - * [Cached Domain Credentials](/techniques/T1003/005) (v1.1) - * [DCSync](/techniques/T1003/006) (v1.1) - * [LSA Secrets](/techniques/T1003/004) (v1.1) - * [LSASS Memory](/techniques/T1003/001) (v1.5) - * [Proc Filesystem](/techniques/T1003/007) (v1.2) - * [Security Account Manager](/techniques/T1003/002) (v1.1) + * [Cached Domain Credentials](/techniques/T1003/005) (v1.1) + * [DCSync](/techniques/T1003/006) (v1.1) + * [LSA Secrets](/techniques/T1003/004) (v1.1) + * [LSASS Memory](/techniques/T1003/001) (v1.5) + * [Proc Filesystem](/techniques/T1003/007) (v1.2) + * [Security Account Manager](/techniques/T1003/002) (v1.1) * Obfuscated Files or Information: [Command Obfuscation](/techniques/T1027/010) (v1.0) * Obfuscated Files or Information: [Dynamic API Resolution](/techniques/T1027/007) (v1.0) * Obfuscated Files or Information: [Fileless Storage](/techniques/T1027/011) (v2.0) * Obfuscated Files or Information: [LNK Icon Smuggling](/techniques/T1027/012) (v1.0) * Obfuscated Files or Information: [Steganography](/techniques/T1027/003) (v1.2) * [Obtain Capabilities](/techniques/T1588) (v1.1) - * [Code Signing Certificates](/techniques/T1588/003) (v1.1) - * [Digital Certificates](/techniques/T1588/004) (v1.2) - * [Exploits](/techniques/T1588/005) (v1.0) - * [Malware](/techniques/T1588/001) (v1.1) - * [Tool](/techniques/T1588/002) (v1.1) - * [Vulnerabilities](/techniques/T1588/006) (v1.0) + * [Code Signing Certificates](/techniques/T1588/003) (v1.1) + * [Digital Certificates](/techniques/T1588/004) (v1.2) + * [Exploits](/techniques/T1588/005) (v1.0) + * [Malware](/techniques/T1588/001) (v1.1) + * [Tool](/techniques/T1588/002) (v1.1) + * [Vulnerabilities](/techniques/T1588/006) (v1.0) * [Office Application Startup](/techniques/T1137) (v1.4) - * [Add-ins](/techniques/T1137/006) (v1.2) - * [Office Template Macros](/techniques/T1137/001) (v1.2) - * [Office Test](/techniques/T1137/002) (v1.3) - * [Outlook Forms](/techniques/T1137/003) (v1.2) - * [Outlook Home Page](/techniques/T1137/004) (v1.2) - * [Outlook Rules](/techniques/T1137/005) (v1.2) + * [Add-ins](/techniques/T1137/006) (v1.2) + * [Office Template Macros](/techniques/T1137/001) (v1.2) + * [Office Test](/techniques/T1137/002) (v1.3) + * [Outlook Forms](/techniques/T1137/003) (v1.2) + * [Outlook Home Page](/techniques/T1137/004) (v1.2) + * [Outlook Rules](/techniques/T1137/005) (v1.2) * [Permission Groups Discovery](/techniques/T1069) (v2.6) - * [Cloud Groups](/techniques/T1069/003) (v1.5) - * [Domain Groups](/techniques/T1069/002) (v1.2) - * [Local Groups](/techniques/T1069/001) (v1.2) + * [Cloud Groups](/techniques/T1069/003) (v1.5) + * [Domain Groups](/techniques/T1069/002) (v1.2) + * [Local Groups](/techniques/T1069/001) (v1.2) * Phishing: [Spearphishing Attachment](/techniques/T1566/001) (v2.2) * Phishing: [Spearphishing Link](/techniques/T1566/002) (v2.7) * Phishing: [Spearphishing via Service](/techniques/T1566/003) (v2.0) @@ -646,49 +655,49 @@ * [Plist File Modification](/techniques/T1647) (v1.0) * [Query Registry](/techniques/T1012) (v1.3) * [Remote Service Session Hijacking](/techniques/T1563) (v1.1) - * [RDP Hijacking](/techniques/T1563/002) (v1.1) + * [RDP Hijacking](/techniques/T1563/002) (v1.1) * Remote Services: [Cloud Services](/techniques/T1021/007) (v1.1) * Remote Services: [Direct Cloud VM Connections](/techniques/T1021/008) (v1.0) * Remote Services: [Distributed Component Object Model](/techniques/T1021/003) (v1.3) * Remote Services: [Windows Remote Management](/techniques/T1021/006) (v1.2) * [Resource Hijacking](/techniques/T1496) (v2.0) - * [Bandwidth Hijacking](/techniques/T1496/002) (v1.0) - * [Cloud Service Hijacking](/techniques/T1496/004) (v1.0) - * [Compute Hijacking](/techniques/T1496/001) (v1.0) - * [SMS Pumping](/techniques/T1496/003) (v1.0) + * [Bandwidth Hijacking](/techniques/T1496/002) (v1.0) + * [Cloud Service Hijacking](/techniques/T1496/004) (v1.0) + * [Compute Hijacking](/techniques/T1496/001) (v1.0) + * [SMS Pumping](/techniques/T1496/003) (v1.0) * [Scheduled Transfer](/techniques/T1029) (v1.1) * [Screen Capture](/techniques/T1113) (v1.1) * [Search Closed Sources](/techniques/T1597) (v1.1) - * [Purchase Technical Data](/techniques/T1597/002) (v1.0) - * [Threat Intel Vendors](/techniques/T1597/001) (v1.0) + * [Purchase Technical Data](/techniques/T1597/002) (v1.0) + * [Threat Intel Vendors](/techniques/T1597/001) (v1.0) * [Search Open Technical Databases](/techniques/T1596) (v1.0) - * [CDNs](/techniques/T1596/004) (v1.0) - * [DNS/Passive DNS](/techniques/T1596/001) (v1.0) - * [Digital Certificates](/techniques/T1596/003) (v1.0) - * [Scan Databases](/techniques/T1596/005) (v1.0) - * [WHOIS](/techniques/T1596/002) (v1.0) + * [CDNs](/techniques/T1596/004) (v1.0) + * [DNS/Passive DNS](/techniques/T1596/001) (v1.0) + * [Digital Certificates](/techniques/T1596/003) (v1.0) + * [Scan Databases](/techniques/T1596/005) (v1.0) + * [WHOIS](/techniques/T1596/002) (v1.0) * [Search Open Websites/Domains](/techniques/T1593) (v1.1) - * [Code Repositories](/techniques/T1593/003) (v1.0) - * [Search Engines](/techniques/T1593/002) (v1.0) - * [Social Media](/techniques/T1593/001) (v1.0) + * [Code Repositories](/techniques/T1593/003) (v1.0) + * [Search Engines](/techniques/T1593/002) (v1.0) + * [Social Media](/techniques/T1593/001) (v1.0) * [Search Victim-Owned Websites](/techniques/T1594) (v1.1) * Server Software Component: [SQL Stored Procedures](/techniques/T1505/001) (v1.1) * Server Software Component: [Terminal Services DLL](/techniques/T1505/005) (v1.0) * Software Discovery: [Security Software Discovery](/techniques/T1518/001) (v1.5) * [Stage Capabilities](/techniques/T1608) (v1.2) - * [Drive-by Target](/techniques/T1608/004) (v1.3) - * [Install Digital Certificate](/techniques/T1608/003) (v1.1) - * [Link Target](/techniques/T1608/005) (v1.4) - * [SEO Poisoning](/techniques/T1608/006) (v1.1) - * [Upload Malware](/techniques/T1608/001) (v1.2) - * [Upload Tool](/techniques/T1608/002) (v1.2) + * [Drive-by Target](/techniques/T1608/004) (v1.3) + * [Install Digital Certificate](/techniques/T1608/003) (v1.1) + * [Link Target](/techniques/T1608/005) (v1.4) + * [SEO Poisoning](/techniques/T1608/006) (v1.1) + * [Upload Malware](/techniques/T1608/001) (v1.2) + * [Upload Tool](/techniques/T1608/002) (v1.2) * [Steal Web Session Cookie](/techniques/T1539) (v1.4) * [Steal or Forge Authentication Certificates](/techniques/T1649) (v1.2) * Steal or Forge Kerberos Tickets: [Ccache Files](/techniques/T1558/005) (v1.0) * [Supply Chain Compromise](/techniques/T1195) (v1.6) - * [Compromise Hardware Supply Chain](/techniques/T1195/003) (v1.1) - * [Compromise Software Dependencies and Development Tools](/techniques/T1195/001) (v1.2) - * [Compromise Software Supply Chain](/techniques/T1195/002) (v1.1) + * [Compromise Hardware Supply Chain](/techniques/T1195/003) (v1.1) + * [Compromise Software Dependencies and Development Tools](/techniques/T1195/001) (v1.2) + * [Compromise Software Supply Chain](/techniques/T1195/002) (v1.1) * System Binary Proxy Execution: [Electron Applications](/techniques/T1218/015) (v1.0) * System Binary Proxy Execution: [Mavinject](/techniques/T1218/013) (v2.0) * [System Location Discovery](/techniques/T1614) (v1.1) @@ -726,39 +735,39 @@ #### Patches * [Abuse Elevation Control Mechanism](/techniques/T1626) (v1.1) - * [Device Administrator Permissions](/techniques/T1626/001) (v1.1) + * [Device Administrator Permissions](/techniques/T1626/001) (v1.1) * [Access Notifications](/techniques/T1517) (v1.2) * [Account Access Removal](/techniques/T1640) (v1.1) * [Application Layer Protocol](/techniques/T1437) (v1.2) - * [Web Protocols](/techniques/T1437/001) (v1.0) + * [Web Protocols](/techniques/T1437/001) (v1.0) * [Archive Collected Data](/techniques/T1532) (v2.0) * [Audio Capture](/techniques/T1429) (v3.1) * [Boot or Logon Initialization Scripts](/techniques/T1398) (v2.1) * [Call Control](/techniques/T1616) (v1.2) * [Command and Scripting Interpreter](/techniques/T1623) (v1.2) - * [Unix Shell](/techniques/T1623/001) (v1.2) + * [Unix Shell](/techniques/T1623/001) (v1.2) * [Compromise Application Executable](/techniques/T1577) (v1.0) * [Compromise Client Software Binary](/techniques/T1645) (v1.1) * [Credentials from Password Store](/techniques/T1634) (v1.1) - * [Keychain](/techniques/T1634/001) (v1.1) + * [Keychain](/techniques/T1634/001) (v1.1) * [Data Encrypted for Impact](/techniques/T1471) (v3.2) * [Data Manipulation](/techniques/T1641) (v1.1) - * [Transmitted Data Manipulation](/techniques/T1641/001) (v1.1) + * [Transmitted Data Manipulation](/techniques/T1641/001) (v1.1) * [Data from Local System](/techniques/T1533) (v1.1) * [Download New Code at Runtime](/techniques/T1407) (v1.5) * [Drive-By Compromise](/techniques/T1456) (v2.2) * [Dynamic Resolution](/techniques/T1637) (v1.1) - * [Domain Generation Algorithms](/techniques/T1637/001) (v1.1) + * [Domain Generation Algorithms](/techniques/T1637/001) (v1.1) * [Encrypted Channel](/techniques/T1521) (v2.0) - * [Asymmetric Cryptography](/techniques/T1521/002) (v1.0) - * [Symmetric Cryptography](/techniques/T1521/001) (v1.0) + * [Asymmetric Cryptography](/techniques/T1521/002) (v1.0) + * [Symmetric Cryptography](/techniques/T1521/001) (v1.0) * [Endpoint Denial of Service](/techniques/T1642) (v1.1) * [Event Triggered Execution](/techniques/T1624) (v1.1) - * [Broadcast Receivers](/techniques/T1624/001) (v1.1) + * [Broadcast Receivers](/techniques/T1624/001) (v1.1) * [Execution Guardrails](/techniques/T1627) (v1.1) - * [Geofencing](/techniques/T1627/001) (v1.1) + * [Geofencing](/techniques/T1627/001) (v1.1) * [Exfiltration Over Alternative Protocol](/techniques/T1639) (v1.1) - * [Exfiltration Over Unencrypted Non-C2 Protocol](/techniques/T1639/001) (v1.1) + * [Exfiltration Over Unencrypted Non-C2 Protocol](/techniques/T1639/001) (v1.1) * [Exfiltration Over C2 Channel](/techniques/T1646) (v1.1) * [Exploitation for Privilege Escalation](/techniques/T1404) (v2.1) * [Exploitation of Remote Services](/techniques/T1428) (v1.2) @@ -766,43 +775,43 @@ * [Foreground Persistence](/techniques/T1541) (v2.1) * [Generate Traffic from Victim](/techniques/T1643) (v1.1) * [Hide Artifacts](/techniques/T1628) (v1.1) - * [User Evasion](/techniques/T1628/002) (v1.0) + * [User Evasion](/techniques/T1628/002) (v1.0) * [Hijack Execution Flow](/techniques/T1625) (v1.1) - * [System Runtime API Hijacking](/techniques/T1625/001) (v1.1) + * [System Runtime API Hijacking](/techniques/T1625/001) (v1.1) * [Hooking](/techniques/T1617) (v1.0) * [Impair Defenses](/techniques/T1629) (v1.1) - * [Device Lockout](/techniques/T1629/002) (v1.1) - * [Disable or Modify Tools](/techniques/T1629/003) (v1.1) + * [Device Lockout](/techniques/T1629/002) (v1.1) + * [Disable or Modify Tools](/techniques/T1629/003) (v1.1) * [Indicator Removal on Host](/techniques/T1630) (v1.1) - * [Disguise Root/Jailbreak Indicators](/techniques/T1630/003) (v1.1) - * [File Deletion](/techniques/T1630/002) (v1.1) - * [Uninstall Malicious Application](/techniques/T1630/001) (v1.1) + * [Disguise Root/Jailbreak Indicators](/techniques/T1630/003) (v1.1) + * [File Deletion](/techniques/T1630/002) (v1.1) + * [Uninstall Malicious Application](/techniques/T1630/001) (v1.1) * [Ingress Tool Transfer](/techniques/T1544) (v2.2) * [Input Capture](/techniques/T1417) (v2.3) - * [GUI Input Capture](/techniques/T1417/002) (v1.1) - * [Keylogging](/techniques/T1417/001) (v1.1) + * [GUI Input Capture](/techniques/T1417/002) (v1.1) + * [Keylogging](/techniques/T1417/001) (v1.1) * [Input Injection](/techniques/T1516) (v1.2) * [Location Tracking](/techniques/T1430) (v1.2) - * [Impersonate SS7 Nodes](/techniques/T1430/002) (v1.1) - * [Remote Device Management Services](/techniques/T1430/001) (v1.1) + * [Impersonate SS7 Nodes](/techniques/T1430/002) (v1.1) + * [Remote Device Management Services](/techniques/T1430/001) (v1.1) * [Masquerading](/techniques/T1655) (v1.0) - * [Match Legitimate Name or Location](/techniques/T1655/001) (v1.0) + * [Match Legitimate Name or Location](/techniques/T1655/001) (v1.0) * [Native API](/techniques/T1575) (v2.0) * [Network Denial of Service](/techniques/T1464) (v1.3) * [Network Service Scanning](/techniques/T1423) (v1.1) * [Non-Standard Port](/techniques/T1509) (v2.1) * [Obfuscated Files or Information](/techniques/T1406) (v3.1) - * [Software Packing](/techniques/T1406/002) (v1.1) - * [Steganography](/techniques/T1406/001) (v1.0) + * [Software Packing](/techniques/T1406/002) (v1.1) + * [Steganography](/techniques/T1406/001) (v1.0) * [Out of Band Data](/techniques/T1644) (v2.1) * [Process Discovery](/techniques/T1424) (v2.1) * [Process Injection](/techniques/T1631) (v1.1) - * [Ptrace System Calls](/techniques/T1631/001) (v1.1) + * [Ptrace System Calls](/techniques/T1631/001) (v1.1) * [Protected User Data](/techniques/T1636) (v1.1) - * [Calendar Entries](/techniques/T1636/001) (v1.1) - * [Call Log](/techniques/T1636/002) (v1.1) - * [Contact List](/techniques/T1636/003) (v1.1) - * [SMS Messages](/techniques/T1636/004) (v1.1) + * [Calendar Entries](/techniques/T1636/001) (v1.1) + * [Call Log](/techniques/T1636/002) (v1.1) + * [Contact List](/techniques/T1636/003) (v1.1) + * [SMS Messages](/techniques/T1636/004) (v1.1) * [Proxy Through Victim](/techniques/T1604) (v1.1) * [Remote Access Software](/techniques/T1663) (v1.0) * [Replication Through Removable Media](/techniques/T1458) (v2.1) @@ -810,24 +819,24 @@ * [Scheduled Task/Job](/techniques/T1603) (v1.0) * [Screen Capture](/techniques/T1513) (v1.3) * [Software Discovery](/techniques/T1418) (v2.1) - * [Security Software Discovery](/techniques/T1418/001) (v1.1) + * [Security Software Discovery](/techniques/T1418/001) (v1.1) * Steal Application Access Token: [URI Hijacking](/techniques/T1635/001) (v1.1) * [Stored Application Data](/techniques/T1409) (v3.1) * [Subvert Trust Controls](/techniques/T1632) (v1.1) - * [Code Signing Policy Modification](/techniques/T1632/001) (v1.1) + * [Code Signing Policy Modification](/techniques/T1632/001) (v1.1) * [Supply Chain Compromise](/techniques/T1474) (v2.1) - * [Compromise Hardware Supply Chain](/techniques/T1474/002) (v1.1) - * [Compromise Software Dependencies and Development Tools](/techniques/T1474/001) (v1.1) - * [Compromise Software Supply Chain](/techniques/T1474/003) (v1.1) + * [Compromise Hardware Supply Chain](/techniques/T1474/002) (v1.1) + * [Compromise Software Dependencies and Development Tools](/techniques/T1474/001) (v1.1) + * [Compromise Software Supply Chain](/techniques/T1474/003) (v1.1) * [System Information Discovery](/techniques/T1426) (v1.2) * [System Network Connections Discovery](/techniques/T1421) (v2.1) * [Video Capture](/techniques/T1512) (v2.1) * [Virtualization/Sandbox Evasion](/techniques/T1633) (v1.1) - * [System Checks](/techniques/T1633/001) (v1.1) + * [System Checks](/techniques/T1633/001) (v1.1) * [Web Service](/techniques/T1481) (v1.3) - * [Bidirectional Communication](/techniques/T1481/002) (v1.2) - * [Dead Drop Resolver](/techniques/T1481/001) (v1.2) - * [One-Way Communication](/techniques/T1481/003) (v1.2) + * [Bidirectional Communication](/techniques/T1481/002) (v1.2) + * [Dead Drop Resolver](/techniques/T1481/001) (v1.2) + * [One-Way Communication](/techniques/T1481/003) (v1.2) ### ICS From a5420042578450e0a243112ca9b2a5a54420119e Mon Sep 17 00:00:00 2001 From: Jared Ondricek Date: Wed, 22 Oct 2025 12:40:30 -0500 Subject: [PATCH 24/29] fix: remove deprecated x_mitre_data_source_ref field on data components --- mitreattack/stix20/custom_attack_objects.py | 1 - 1 file changed, 1 deletion(-) diff --git a/mitreattack/stix20/custom_attack_objects.py b/mitreattack/stix20/custom_attack_objects.py index 00147f7f..69fd5962 100644 --- a/mitreattack/stix20/custom_attack_objects.py +++ b/mitreattack/stix20/custom_attack_objects.py @@ -225,7 +225,6 @@ class DataSource(CustomStixObject, object): ("x_mitre_attack_spec_version", StringProperty()), ("x-mitre-deprecated", BooleanProperty(default=lambda: False)), # Data Component Properties - ("x_mitre_data_source_ref", ReferenceProperty(valid_types="x-mitre-data-source", spec_version="2.0")), ("x_mitre_log_sources", ListProperty(DictionaryProperty())), ], ) From bd6b6da289e065af97e3f409841044a15c1ed31d Mon Sep 17 00:00:00 2001 From: Evan Lucchesi Leon <189633144+elucchesileon@users.noreply.github.com> Date: Thu, 23 Oct 2025 08:50:51 -0400 Subject: [PATCH 25/29] fix: use stix v2.0 version of CustomObject, ExternalReference --- mitreattack/stix20/custom_attack_objects.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mitreattack/stix20/custom_attack_objects.py b/mitreattack/stix20/custom_attack_objects.py index 69fd5962..d8b43559 100644 --- a/mitreattack/stix20/custom_attack_objects.py +++ b/mitreattack/stix20/custom_attack_objects.py @@ -4,7 +4,6 @@ import stix2 import stix2.v20 -from stix2 import CustomObject, ExternalReference from stix2.properties import ( BooleanProperty, DictionaryProperty, @@ -15,6 +14,7 @@ TimestampProperty, TypeProperty, ) +from stix2.v20 import CustomObject, ExternalReference class CustomStixObject(object): From 52ae062cecf5836e882eef0e4f52be3e28b24ad9 Mon Sep 17 00:00:00 2001 From: Evan Lucchesi Leon <189633144+elucchesileon@users.noreply.github.com> Date: Thu, 23 Oct 2025 09:06:16 -0400 Subject: [PATCH 26/29] fix: update excel tests based on v18 changes --- tests/test_to_excel.py | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/tests/test_to_excel.py b/tests/test_to_excel.py index 5ea2fa6c..dfa2ea3c 100644 --- a/tests/test_to_excel.py +++ b/tests/test_to_excel.py @@ -37,11 +37,10 @@ def check_excel_files_exist(excel_folder: Path, domain: str): For "ics-attack", also checks for the existence of the assets file. """ assert (excel_folder / f"{domain}.xlsx").exists() - # TODO: add in check for assets for ICS after ATT&CK v14 is released if domain == "ics-attack": # Only ICS has Assets assert (excel_folder / f"{domain}-assets.xlsx").exists() - assert (excel_folder / f"{domain}-datasources.xlsx").exists() + assert (excel_folder / f"{domain}-datacomponents.xlsx").exists() assert (excel_folder / f"{domain}-campaigns.xlsx").exists() assert (excel_folder / f"{domain}-groups.xlsx").exists() assert (excel_folder / f"{domain}-matrices.xlsx").exists() @@ -50,6 +49,9 @@ def check_excel_files_exist(excel_folder: Path, domain: str): assert (excel_folder / f"{domain}-software.xlsx").exists() assert (excel_folder / f"{domain}-tactics.xlsx").exists() assert (excel_folder / f"{domain}-techniques.xlsx").exists() + # TODO: add in check for analytics/detection strategies after ATT&CK v18 is released + # assert (excel_folder / f"{domain}-analytics.xlsx").exists() + # assert (excel_folder / f"{domain}-detectionstrategies.xlsx").exists() def test_enterprise_latest(tmp_path: Path, memstore_enterprise_latest: stix2.MemoryStore): @@ -85,7 +87,7 @@ def test_ics_latest(tmp_path: Path, memstore_ics_latest: stix2.MemoryStore): check_excel_files_exist(excel_folder=excel_folder, domain=domain) -def test_enterprise_legacy(tmp_path: Path): +def test_enterprise_legacy_v9(tmp_path: Path): """Test enterprise v9.0 to excel spreadsheet functionality.""" logger.debug(f"{tmp_path=}") version = "v9.0" @@ -101,3 +103,22 @@ def test_enterprise_legacy(tmp_path: Path): assert (excel_folder / f"enterprise-attack-{version}-mitigations.xlsx").exists() assert (excel_folder / f"enterprise-attack-{version}-matrices.xlsx").exists() assert (excel_folder / f"enterprise-attack-{version}-groups.xlsx").exists() + + +def test_enterprise_legacy_v17(tmp_path: Path): + """Test enterprise v17.0 to excel spreadsheet functionality.""" + logger.debug(f"{tmp_path=}") + version = "v17.0" + + attackToExcel.export(domain="enterprise-attack", version=version, output_dir=str(tmp_path)) + + excel_folder = tmp_path / f"enterprise-attack-{version}" + assert (excel_folder / f"enterprise-attack-{version}.xlsx").exists() + assert (excel_folder / f"enterprise-attack-{version}-techniques.xlsx").exists() + assert (excel_folder / f"enterprise-attack-{version}-tactics.xlsx").exists() + assert (excel_folder / f"enterprise-attack-{version}-software.xlsx").exists() + assert (excel_folder / f"enterprise-attack-{version}-relationships.xlsx").exists() + assert (excel_folder / f"enterprise-attack-{version}-mitigations.xlsx").exists() + assert (excel_folder / f"enterprise-attack-{version}-matrices.xlsx").exists() + assert (excel_folder / f"enterprise-attack-{version}-groups.xlsx").exists() + assert (excel_folder / f"enterprise-attack-{version}-datasources.xlsx").exists() From dfd7d8da9e24aed06041d1fbbd0caa33df4f94ad Mon Sep 17 00:00:00 2001 From: Evan Lucchesi Leon <189633144+elucchesileon@users.noreply.github.com> Date: Thu, 23 Oct 2025 14:13:15 -0400 Subject: [PATCH 27/29] refactor: remove unnecessary references to x_mitre_data_sources --- .../get_datacomponents_detecting_technique.py | 22 ------------------- mitreattack/stix20/custom_attack_objects.py | 1 - tests/changelog/conftest.py | 9 ++------ .../changelog/core/test_missing_functions.py | 1 - 4 files changed, 2 insertions(+), 31 deletions(-) delete mode 100644 examples/get_datacomponents_detecting_technique.py diff --git a/examples/get_datacomponents_detecting_technique.py b/examples/get_datacomponents_detecting_technique.py deleted file mode 100644 index 1b4ddbd5..00000000 --- a/examples/get_datacomponents_detecting_technique.py +++ /dev/null @@ -1,22 +0,0 @@ -import os - -from mitreattack.stix20 import MitreAttackData - - -def main(): - stix_filepath = os.environ.get("STIX_BUNDLE", "enterprise-attack.json") - mitre_attack_data = MitreAttackData(stix_filepath=stix_filepath) - - # get data components detecting T1112 - technique_stix_id = "attack-pattern--57340c81-c025-4189-8fa0-fc7ede51bae4" - datacomponents_detects_t1112 = mitre_attack_data.get_datacomponents_detecting_technique(technique_stix_id) - - print(f"Data components detecting T1112 ({len(datacomponents_detects_t1112)}):") - for d in datacomponents_detects_t1112: - datacomponent = d["object"] - datasource = mitre_attack_data.get_object_by_stix_id(datacomponent.x_mitre_data_source_ref) - print(f"* {datasource.name}: {datacomponent.name} ({mitre_attack_data.get_attack_id(datasource.id)})") - - -if __name__ == "__main__": - main() diff --git a/mitreattack/stix20/custom_attack_objects.py b/mitreattack/stix20/custom_attack_objects.py index d8b43559..4ffd6861 100644 --- a/mitreattack/stix20/custom_attack_objects.py +++ b/mitreattack/stix20/custom_attack_objects.py @@ -233,7 +233,6 @@ class DataComponent(CustomStixObject, object): Custom Properties ----------------- - x_mitre_data_source_ref: str x_mitre_log_sources: list[object] """ diff --git a/tests/changelog/conftest.py b/tests/changelog/conftest.py index 7aee18a3..11344a44 100644 --- a/tests/changelog/conftest.py +++ b/tests/changelog/conftest.py @@ -340,9 +340,7 @@ def _add_campaign_fields(obj, attack_id, aliases): def _add_custom_mitre_fields(obj, attack_id, object_type): """Add fields for custom MITRE object types.""" # These objects have varying structures - add basic fields - if object_type == "x-mitre-data-component": - obj["x_mitre_data_source_ref"] = f"x-mitre-data-source--{uuid.uuid4()}" - elif object_type == "x-mitre-tactic": + if object_type == "x-mitre-tactic": obj["x_mitre_shortname"] = attack_id.lower() if attack_id else "test-tactic" def _generate_external_references(attack_id, object_type, is_subtechnique): @@ -1240,7 +1238,6 @@ def minimal_stix_bundles(mock_stix_object_factory, mock_relationship_factory): stix_type="x-mitre-data-component", obj_type="x-mitre-data-component", ) - old_datacomponent1["x_mitre_data_source_ref"] = old_datasource1["id"] old_datacomponent2 = mock_stix_object_factory( name="Data Component To Be Modified", @@ -1249,7 +1246,6 @@ def minimal_stix_bundles(mock_stix_object_factory, mock_relationship_factory): stix_type="x-mitre-data-component", obj_type="x-mitre-data-component", ) - old_datacomponent2["x_mitre_data_source_ref"] = old_datasource2["id"] # Assets (2) old_asset1 = mock_stix_object_factory( @@ -1293,7 +1289,7 @@ def minimal_stix_bundles(mock_stix_object_factory, mock_relationship_factory): new_campaign1 = old_campaign1.copy() # Unchanged new_mitigation1 = old_mitigation1.copy() # Unchanged new_datasource1 = old_datasource1.copy() # Unchanged - new_datacomponent1 = old_datacomponent1.copy() # Unchanged (includes x_mitre_data_source_ref) + new_datacomponent1 = old_datacomponent1.copy() # Unchanged new_asset1 = old_asset1.copy() # Unchanged # Modified objects (version changes) @@ -1313,7 +1309,6 @@ def minimal_stix_bundles(mock_stix_object_factory, mock_relationship_factory): new_datacomponent2_modified = old_datacomponent2.copy() new_datacomponent2_modified["x_mitre_version"] = "1.1" new_datacomponent2_modified["modified"] = "2025-01-15T12:00:00.000Z" - new_datacomponent2_modified["x_mitre_data_source_ref"] = new_datasource2_modified["id"] new_asset2_modified = old_asset2.copy() new_asset2_modified["x_mitre_version"] = "1.1" diff --git a/tests/changelog/core/test_missing_functions.py b/tests/changelog/core/test_missing_functions.py index 1dd20c25..3cfb613e 100644 --- a/tests/changelog/core/test_missing_functions.py +++ b/tests/changelog/core/test_missing_functions.py @@ -72,7 +72,6 @@ def test_get_relative_data_component_url_real_generation(self, mock_stix_object_ "x_mitre_version": "1.0", "created": "2023-01-01T00:00:00.000Z", "modified": "2023-01-01T00:00:00.000Z", - "x_mitre_data_source_ref": "x-mitre-data-source--test-id", } # Test real URL generation From d6f78eb4f7f370ff72464979745080e1ee07021c Mon Sep 17 00:00:00 2001 From: Jared Ondricek Date: Mon, 27 Oct 2025 12:47:02 -0500 Subject: [PATCH 28/29] feat: add table of contents to generated changelog --- mitreattack/diffStix/changelog_helper.py | 14 +- .../changelog/core/test_missing_functions.py | 6 +- .../changelog/formatting/test_html_output.py | 5 +- .../changelog-v16.1_to_v17.0/changelog.md | 145 +++++++++--------- 4 files changed, 93 insertions(+), 77 deletions(-) diff --git a/mitreattack/diffStix/changelog_helper.py b/mitreattack/diffStix/changelog_helper.py index 228957e0..17295259 100644 --- a/mitreattack/diffStix/changelog_helper.py +++ b/mitreattack/diffStix/changelog_helper.py @@ -1236,6 +1236,11 @@ def get_markdown_string(self) -> str: logger.info("Generating markdown output") content = "" + # Add contributors if requested by argument + if self.include_contributors: + content += self.get_contributor_section() + content += "\n" + # Add statistics section for the new version logger.info("Generating statistics section") stats_section = self.get_statistics_section(datastore_version="new") @@ -1245,6 +1250,9 @@ def get_markdown_string(self) -> str: key_content = self.get_md_key() content += f"{key_content}\n" + content += "## Table of Contents\n\n" + content += "[TOC]\n\n" + for object_type in self.types: domains = "" @@ -1279,10 +1287,6 @@ def get_markdown_string(self) -> str: if domains != "": content += f"## {self.attack_type_to_title[object_type]}\n\n{domains}" - # Add contributors if requested by argument - if self.include_contributors: - content += self.get_contributor_section() - return content def get_layers_dict(self): @@ -1782,7 +1786,7 @@ def markdown_to_html(outfile: str, content: str, diffStix: DiffStix): html_string = """
""" html_string += "" html_string += header - html_string += markdown.markdown(content) + html_string += markdown.markdown(content, extensions=['toc']) html_string += "
" with open(outfile, "w", encoding="utf-8") as outputfile: diff --git a/tests/changelog/core/test_missing_functions.py b/tests/changelog/core/test_missing_functions.py index 3cfb613e..ff057b59 100644 --- a/tests/changelog/core/test_missing_functions.py +++ b/tests/changelog/core/test_missing_functions.py @@ -107,7 +107,11 @@ def test_markdown_to_html_real_conversion(self, lightweight_diffstix, tmp_path): # Verify markdown was converted to HTML if "# " in markdown_content: - assert "

" in html_content or "

" in html_content # Headers should be converted + # when the python markdown Table of Contents plugin is enabled, it changes the

and

tags + # to include id attributes and maybe a style attribute (at least to

) so this assert statement + # looks a little funny, but is good enough + # https://python-markdown.github.io/extensions/toc/ + assert "Test Header

" in html_content assert "bold" in html_content assert "charset='utf-8'" in html_content + # it might be nice to add this back in, but when using the python markdown TOC extension, + # it modifies the

and

tags, giving them additional attributes, like id (and maybe style?) + # https://python-markdown.github.io/extensions/toc/ + # assert "

Test Header

" in html_content def test_write_detailed_html_basic( self, tmp_path, lightweight_diffstix, sample_deepdiff_data, minimal_stix_bundles diff --git a/tests/resources/changelog-v16.1_to_v17.0/changelog.md b/tests/resources/changelog-v16.1_to_v17.0/changelog.md index b285a89d..ec1a5b2a 100644 --- a/tests/resources/changelog-v16.1_to_v17.0/changelog.md +++ b/tests/resources/changelog-v16.1_to_v17.0/changelog.md @@ -1,3 +1,74 @@ +## Contributors to this release + +* Aaron Sullivan aka ZerkerEOD +* Adam Lichters +* Alden Schmidt +* Ale Houspanossian +* Alexey Kleymenov +* Alon Klayman, Hunters Security +* Amnon Kushnir, Sygnia +* Ben Smith, @cyberg3cko +* Caio Silva +* Cian Heasley +* Cristian Souza - Kaspersky GERT +* Cristóbal Martínez Martín +* David Hughes, BT Security +* Dhiraj Mishra (@RandomDhiraj) +* Dmitry Bestuzhev +* Dvir Sasson, Reco +* Eliraz Levi, Hunters Security +* Fabian Kammel +* Fernando Bacchin +* Flavio Costa, Cisco +* Frank Angiolelli +* Gabriel Currie +* Gerardo Santos +* Harikrishnan Muthu, Cyble +* Hiroki Nagahama, NEC Corporation +* Inna Danilevich, U.S. Bank +* Jaesang Oh, KC7 Foundation +* Janantha Marasinghe +* Jennifer Kim Roman +* Jiraput Thamsongkrah +* Joas Antonio dos Santos, @C0d3Cr4zy +* Joe Gumke, U.S. Bank +* Jun Hirata, NEC Corporation +* Kaung Zaw Hein +* Kevin Ward +* Kori Yoshihiro, NEC Corporation +* Kyaw Pyiyt Htet, @KyawPyiytHtet +* Liran Ravich, CardinalOps +* Lê Phương Nam, Group-IB +* Manikantan Srinivasan, NEC Corporation India +* Matt Anderson, @‌nosecurething, Huntress +* Matt Brenton, Zurich Global Information Security +* Matt Brenton, Zurich Insurance Group +* Menachem Goldstein +* Michael Davis @ ServiceNow Threat Intelligence +* MyungUk Han, ASEC +* Natthawut Saexu +* Nikita Rostovcev, Group-IB +* Oren Biderman, Sygnia +* Peter Oakes +* Pooja Natarajan, NEC Corporation India +* Raghvendra Mishra +* ReliaQuest +* RoseSecurity +* Rouven Bissinger (SySS GmbH) +* Ruben Groenewoud (@RFGroenewoud) +* Ryan Perez +* Sareena Karapoola, NEC Corporation India +* seungyoul.yoo@ahnlab.com +* Sharmine Low, Group-IB +* Shun Miyazaki, NEC Corporation +* Shwetank Murarka +* Sittikorn Sangrattanapitak +* Suraj Khetani (@r00treaver) +* Vicky Ray, RayvenX +* Vijay Lalwani +* Wietze Beukema @Wietze +* Yoshihiro Kori, NEC Corporation + ## Statistics This version of ATT&CK contains 877 Software, 170 Groups, and 50 Campaigns. @@ -19,6 +90,10 @@ Broken out by domain: * Object deprecations: ATT&CK objects which are deprecated and no longer in use, and not replaced. * Object deletions: ATT&CK objects which are no longer found in the STIX data. +## Table of Contents + +[TOC] + ## Techniques ### Enterprise @@ -2226,73 +2301,3 @@ Broken out by domain: * [Service Metadata](/datasources/DS0019/#Service%20Metadata) (v1.0) * [Software](/datasources/DS0039/#Software) (v1.0) -## Contributors to this release - -* Aaron Sullivan aka ZerkerEOD -* Adam Lichters -* Alden Schmidt -* Ale Houspanossian -* Alexey Kleymenov -* Alon Klayman, Hunters Security -* Amnon Kushnir, Sygnia -* Ben Smith, @cyberg3cko -* Caio Silva -* Cian Heasley -* Cristian Souza - Kaspersky GERT -* Cristóbal Martínez Martín -* David Hughes, BT Security -* Dhiraj Mishra (@RandomDhiraj) -* Dmitry Bestuzhev -* Dvir Sasson, Reco -* Eliraz Levi, Hunters Security -* Fabian Kammel -* Fernando Bacchin -* Flavio Costa, Cisco -* Frank Angiolelli -* Gabriel Currie -* Gerardo Santos -* Harikrishnan Muthu, Cyble -* Hiroki Nagahama, NEC Corporation -* Inna Danilevich, U.S. Bank -* Jaesang Oh, KC7 Foundation -* Janantha Marasinghe -* Jennifer Kim Roman -* Jiraput Thamsongkrah -* Joas Antonio dos Santos, @C0d3Cr4zy -* Joe Gumke, U.S. Bank -* Jun Hirata, NEC Corporation -* Kaung Zaw Hein -* Kevin Ward -* Kori Yoshihiro, NEC Corporation -* Kyaw Pyiyt Htet, @KyawPyiytHtet -* Liran Ravich, CardinalOps -* Lê Phương Nam, Group-IB -* Manikantan Srinivasan, NEC Corporation India -* Matt Anderson, @‌nosecurething, Huntress -* Matt Brenton, Zurich Global Information Security -* Matt Brenton, Zurich Insurance Group -* Menachem Goldstein -* Michael Davis @ ServiceNow Threat Intelligence -* MyungUk Han, ASEC -* Natthawut Saexu -* Nikita Rostovcev, Group-IB -* Oren Biderman, Sygnia -* Peter Oakes -* Pooja Natarajan, NEC Corporation India -* Raghvendra Mishra -* ReliaQuest -* RoseSecurity -* Rouven Bissinger (SySS GmbH) -* Ruben Groenewoud (@RFGroenewoud) -* Ryan Perez -* Sareena Karapoola, NEC Corporation India -* seungyoul.yoo@ahnlab.com -* Sharmine Low, Group-IB -* Shun Miyazaki, NEC Corporation -* Shwetank Murarka -* Sittikorn Sangrattanapitak -* Suraj Khetani (@r00treaver) -* Vicky Ray, RayvenX -* Vijay Lalwani -* Wietze Beukema @Wietze -* Yoshihiro Kori, NEC Corporation From 99089119efc69a90a5d7d96a8bd5ec4e9f6486d6 Mon Sep 17 00:00:00 2001 From: Jared Ondricek Date: Mon, 27 Oct 2025 15:11:08 -0500 Subject: [PATCH 29/29] chore: autoformat --- mitreattack/diffStix/changelog_helper.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mitreattack/diffStix/changelog_helper.py b/mitreattack/diffStix/changelog_helper.py index 17295259..cbbff41e 100644 --- a/mitreattack/diffStix/changelog_helper.py +++ b/mitreattack/diffStix/changelog_helper.py @@ -1786,7 +1786,7 @@ def markdown_to_html(outfile: str, content: str, diffStix: DiffStix): html_string = """
""" html_string += "" html_string += header - html_string += markdown.markdown(content, extensions=['toc']) + html_string += markdown.markdown(content, extensions=["toc"]) html_string += "
" with open(outfile, "w", encoding="utf-8") as outputfile: