-
-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/)
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/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/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()
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()
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
deleted file mode 100644
index e07fc018..00000000
--- a/examples/get_datacomponents_detecting_technique.py
+++ /dev/null
@@ -1,19 +0,0 @@
-from mitreattack.stix20 import MitreAttackData
-
-
-def main():
- mitre_attack_data = MitreAttackData("enterprise-attack.json")
-
- # 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/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"
diff --git a/mitreattack/attackToExcel/attackToExcel.py b/mitreattack/attackToExcel/attackToExcel.py
index d03a61ac..29db7e4c 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
----------
@@ -108,6 +109,40 @@ 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
+
+
+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
@@ -146,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()
@@ -322,6 +357,16 @@ 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)
+ return
+
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 80eb5136..bf7290f6 100644
--- a/mitreattack/attackToExcel/stixToDf.py
+++ b/mitreattack/attackToExcel/stixToDf.py
@@ -259,11 +259,13 @@ 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
"""
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 +282,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:
@@ -290,7 +292,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 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:
row["type"] = "datasource"
@@ -309,7 +312,7 @@ def datasourcesToDf(src):
"collection layers",
"platforms",
"created",
- "modified",
+ "last modified",
"type",
"version",
"url",
@@ -332,6 +335,86 @@ 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.
+
+ :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)
+
+ 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")
+
+ else:
+ logger.warning("No analytics found - nothing to parse")
+
+ 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)
+
+ 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"),
+ }
+ if not citations.empty:
+ if "citations" in dataframes: # append to existing citations from references
+ dataframes["citations"] = citations.sort_values("reference")
+
+ else:
+ logger.warning("No detection strategies found - nothing to parse")
+
+ return dataframes
+
+
def softwareToDf(src):
"""Parse STIX software from the given data and return corresponding pandas dataframes.
@@ -892,6 +975,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",
@@ -905,6 +989,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)
@@ -973,7 +1058,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",
@@ -1015,6 +1106,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":
@@ -1060,6 +1152,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
diff --git a/mitreattack/diffStix/changelog_helper.py b/mitreattack/diffStix/changelog_helper.py
index 0b1364de..cbbff41e 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()
@@ -48,6 +49,61 @@ def __repr__(self):
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
+ assets: int
+ datasources: int
+ detectionstrategies: int
+ analytics: int
+ datacomponents: int
+
+ 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, "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
+ 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
class AttackChangesEncoder(json.JSONEncoder):
@@ -122,7 +178,6 @@ def __init__(
"datacomponents",
"detectionstrategies",
"analytics",
- "logsources",
]
self.use_mitre_cti = use_mitre_cti
self.verbose = verbose
@@ -144,7 +199,6 @@ def __init__(
"datacomponents": "Data Components",
"detectionstrategies": "Detection Strategies",
"analytics": "Analytics",
- "logsources": "Log Sources",
}
self.section_descriptions = {
@@ -495,14 +549,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 +578,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)
@@ -658,7 +729,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 = []
@@ -813,11 +883,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 +972,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 +1022,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 +1046,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)
@@ -973,6 +1058,134 @@ 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)
+ 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,
+ tactics=len(tactics),
+ techniques=len(techniques),
+ subtechniques=len(subtechniques),
+ groups=len(groups),
+ software=len(software),
+ campaigns=len(campaigns),
+ mitigations=len(mitigations),
+ assets=len(assets),
+ datasources=len(datasources),
+ detectionstrategies=len(detectionstrategies),
+ analytics=len(analytics),
+ datacomponents=len(datacomponents),
+ )
+
+ 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
+ output = "## Statistics\n\n"
+ output += (
+ 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"
+
+ 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 = ""
@@ -986,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"
@@ -1023,9 +1236,22 @@ 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")
+ content += stats_section
+
if self.show_key:
key_content = self.get_md_key()
- content = f"{key_content}\n\n"
+ content += f"{key_content}\n"
+
+ content += "## Table of Contents\n\n"
+ content += "[TOC]\n\n"
for object_type in self.types:
domains = ""
@@ -1061,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):
@@ -1273,6 +1495,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:
@@ -1548,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:
@@ -1683,16 +1921,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}
")
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.
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/mitreattack/stix20/MitreAttackData.py b/mitreattack/stix20/MitreAttackData.py
index 436b675c..1aef3f7a 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
###################################
@@ -912,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"]
@@ -949,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
@@ -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/__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 6609c1ec..4ffd6861 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):
@@ -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")
@@ -106,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"))),
],
@@ -139,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()),
],
@@ -184,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())),
@@ -218,8 +223,9 @@ 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())),
],
)
class DataComponent(CustomStixObject, object):
@@ -227,7 +233,7 @@ class DataComponent(CustomStixObject, object):
Custom Properties
-----------------
- x_mitre_data_source_ref: str
+ x_mitre_log_sources: list[object]
"""
pass
@@ -252,6 +258,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())),
@@ -268,3 +275,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(ReferenceProperty(valid_types="x-mitre-analytic", spec_version="2.0"))),
+ ],
+)
+class DetectionStrategy(CustomStixObject, object):
+ """Custom Detection Strategy object of type stix2.CustomObject.
+
+ Custom Properties
+ -----------------
+ x_mitre_analytic_refs: list[str]
+ """
+
+ pass
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_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/core/test_missing_functions.py b/tests/changelog/core/test_missing_functions.py
index 1dd20c25..ff057b59 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
@@ -108,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/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/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.
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": [
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..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,84 @@
+## 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.
+
+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,6 +90,9 @@
* 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
@@ -53,122 +137,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 +271,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 +296,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 +366,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 +437,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 +529,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 +560,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 +576,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 +626,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 +680,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 +730,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 +810,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 +850,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 +894,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
@@ -2217,73 +2301,3 @@
* [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
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"
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()