Skip to content

Commit 47d8247

Browse files
authored
Merge pull request #202 from mitre-attack/detection_strategies_fix
Detection strategies fixes
2 parents 2a82ddf + 9908911 commit 47d8247

100 files changed

Lines changed: 1838 additions & 710 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

LICENSE.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@
186186
same "printed page" as the copyright notice for easier
187187
identification within third-party archives.
188188

189-
Copyright [yyyy] [name of copyright owner]
189+
Copyright [2025] [The MITRE Corporation]
190190

191191
Licensed under the Apache License, Version 2.0 (the "License");
192192
you may not use this file except in compliance with the License.

README.md

Lines changed: 3 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# mitreattack-python
22

3-
This repository contains a library of Python tools and utilities for working with ATT&CK data. For more information,
4-
see the [full documentation](https://mitreattack-python.readthedocs.io/) on ReadTheDocs.
3+
This repository contains a library of Python tools and utilities for working with ATT&CK data.
4+
For more information, see the [full documentation](https://mitreattack-python.readthedocs.io/) on ReadTheDocs.
55

66
## Install
77

@@ -11,26 +11,12 @@ To use this package, install the mitreattack-python library with [pip](https://p
1111
pip install mitreattack-python
1212
```
1313

14-
Note: the library requires [python3](https://www.python.org/).
15-
1614
## MitreAttackData Library
1715

18-
The ``MitreAttackData`` library is used to read in and work with MITRE ATT&CK STIX 2.0 content. This library provides
16+
The ``MitreAttackData`` library is used to read in and work with MITRE ATT&CK STIX 2.0 content. This library provides
1917
the ability to query the dataset for objects and their related objects. This is the main content of mitreattack-python;
2018
you can read more about other modules in this library under "Additional Modules".
2119

22-
## Additional Modules
23-
24-
More detailed information and examples about the specific usage of the additional modules in this package can be found in the individual README files for each module linked below.
25-
26-
| module | description | documentation |
27-
|:------------|:------------|:--------------|
28-
| [navlayers](https://github.com/mitre-attack/mitreattack-python/tree/main/mitreattack/navlayers) | A collection of utilities for working with [ATT&CK Navigator](https://github.com/mitre-attack/attack-navigator) layers. Provides the ability to import, export, and manipulate layers. Layers can be read in from the filesystem or python dictionaries, combined and edited, and then exported to excel or SVG images. | Further documentation can be found [here](https://github.com/mitre-attack/mitreattack-python/blob/main/mitreattack/navlayers/README.md).|
29-
| [attackToExcel](https://github.com/mitre-attack/mitreattack-python/tree/main/mitreattack/attackToExcel) | A collection of utilities for converting [ATT&CK STIX data](https://github.com/mitre/cti) to Excel spreadsheets. It also provides access to [Pandas](https://pandas.pydata.org/) DataFrames representing the dataset for use in data analysis. | Further documentation can be found [here](https://github.com/mitre-attack/mitreattack-python/blob/main/mitreattack/attackToExcel/README.md).|
30-
| [collections](https://github.com/mitre-attack/mitreattack-python/tree/main/mitreattack/collections) | A set of utilities for working with [ATT&CK Collections and Collection Indexes](https://github.com/center-for-threat-informed-defense/attack-workbench-frontend/blob/main/docs/collections.md). Provides functionalities for converting and summarizing data in collections and collection indexes, as well as generating a collection from a raw stix bundle input. | Further documentation can be found [here](https://github.com/mitre-attack/mitreattack-python/blob/main/mitreattack/collections/README.md).|
31-
| [diffStix](https://github.com/mitre-attack/mitreattack-python/tree/main/mitreattack/diffStix) | Create markdown, HTML, JSON and/or ATT&CK Navigator layers reporting on the changes between two versions of the STIX2 bundles representing the ATT&CK content. Run `diff_stix -h` for full usage instructions. | Further documentation can be found [here](https://github.com/mitre-attack/mitreattack-python/blob/main/mitreattack/diffStix/README.md).|
32-
33-
3420
## Related MITRE Work
3521

3622
### CTI
@@ -60,36 +46,7 @@ STIX is designed to improve many capabilities, such as collaborative threat anal
6046

6147
<https://oasis-open.github.io/cti-documentation/>
6248

63-
### ATT&CK scripts
64-
65-
One-off scripts and code examples you can use as inspiration for how to work with ATT&CK programmatically. Many of the functionalities found in the mitreattack-python package were originally posted on attack-scripts.
66-
67-
<https://github.com/mitre-attack/attack-scripts>
68-
69-
7049
## Contributing
7150

7251
To contribute to this project, either through a bug report, feature request, or merge request,
7352
please see the [Contributors Guide](https://github.com/mitre-attack/mitreattack-python/blob/main/docs/CONTRIBUTING.md).
74-
75-
## Notice
76-
77-
Copyright 2025 The MITRE Corporation
78-
79-
Approved for Public Release; Distribution Unlimited. Case Number 19-0486.
80-
81-
Licensed under the Apache License, Version 2.0 (the "License");
82-
you may not use this file except in compliance with the License.
83-
You may obtain a copy of the License at
84-
85-
<http://www.apache.org/licenses/LICENSE-2.0>
86-
87-
Unless required by applicable law or agreed to in writing, software
88-
distributed under the License is distributed on an "AS IS" BASIS,
89-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
90-
See the License for the specific language governing permissions and
91-
limitations under the License.
92-
93-
This project makes use of ATT&CK®
94-
95-
[ATT&CK Terms of Use](https://attack.mitre.org/resources/terms-of-use/)

examples/.env.example

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# These environment variables can be helpful when running scripts in the examples directory
2+
#
3+
# In order to use them, copy this file to .env and modify the values as needed
4+
# Two optional tools worth considering to automatically use the .env file are:
5+
# 1. `python-dotenv` python library: https://github.com/theskumar/python-dotenv
6+
# 2. `direnv` tool: https://direnv.net
7+
# Setting up these tools is out of scope for this example.
8+
#
9+
# if you have mitreattack-python installed, you can use the following command to download all STIX bundles:
10+
#
11+
# download_attack_stix --all
12+
#
13+
# the default download directory from the above command is "attack-releases"
14+
15+
STIX_BASE_DIR=attack-releases/stix-2.0/v17.1
16+
STIX_BUNDLE=attack-releases/stix-2.0/v17.1/enterprise-attack.json

examples/README.md

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
# Examples Directory
2+
3+
This directory contains example scripts demonstrating how to use the [`mitreattack-python`](https://github.com/mitre-attack/mitreattack-python)
4+
library to extract, analyze, and report on MITRE ATT&CK data.
5+
These scripts cover a variety of use cases, including querying STIX bundles, generating reports, and automating ATT&CK data analysis.
6+
7+
## Full Example Listing & Documentation
8+
9+
A complete, categorized list of example scripts, usage details, and direct links is maintained in the built documentation:
10+
11+
- [mitreattack-python Examples Documentation](https://mitreattack-python.readthedocs.io/en/latest/mitre_attack_data/examples.html)
12+
13+
## Setup
14+
15+
Many example scripts allow optional configuration via environment variables for paths to STIX bundles.
16+
If you want to set this up you can follow these instructions.
17+
18+
- Copy the provided [`examples/.env.example`](examples/.env.example:1) file to `.env`:
19+
20+
```sh
21+
cp .env.example .env
22+
```
23+
24+
- Edit `.env` to set the correct paths and variables for your environment.
25+
26+
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:
27+
28+
- [`python-dotenv`](https://pypi.org/project/python-dotenv/) (automatically loads `.env` in Python scripts)
29+
- [`direnv`](https://direnv.net/) (manages environment variables per directory)
30+
31+
Setting up these tools is out of scope for this README.
32+
33+
### Dependencies
34+
35+
- [`mitreattack-python`](https://github.com/mitre-attack/mitreattack-python)
36+
- Python 3.x
37+
- ATT&CK STIX bundles
38+
39+
### Downloading ATT&CK STIX Bundles
40+
41+
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`).
42+
You can download these bundles using the provided CLI command if you have mitreattack-python installed:
43+
44+
```sh
45+
download_attack_stix --all
46+
```
47+
48+
This will download all available ATT&CK releases in STIX format to the default directory (`attack-releases`).
49+
You can customize the download location and versions using additional options. For example:
50+
51+
- Download the latest release (default):
52+
53+
```sh
54+
download_attack_stix
55+
```
56+
57+
- Download specific versions:
58+
59+
```sh
60+
download_attack_stix -v 16.1 -v 17.1
61+
```
62+
63+
- Download all releases in both STIX formats:
64+
65+
```sh
66+
download_attack_stix --all --stix21
67+
```
68+
69+
## How to Run Scripts
70+
71+
- Run individual scripts with Python:
72+
73+
```sh
74+
python get_all_techniques.py
75+
```
76+
77+
## Contribution & Customization
78+
79+
Feel free to adapt these scripts for your own use cases. Contributions and improvements are welcome!

examples/analytic_extractor.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
# Prune an input string to remove any non-analytic text
1313
# This assumes that all analytics start the <h4> html block
14-
STRING_RE = "Analytic(\s|.)*"
14+
STRING_RE = r"Analytic(\s|.)*"
1515

1616

1717
def pruneString(in_string):

examples/attack-object-counter.py

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
"""Print comprehensive ATT&CK statistics across all domains."""
2+
3+
import os
4+
from dataclasses import dataclass
5+
6+
from mitreattack.stix20 import MitreAttackData
7+
8+
# Get STIX base directory from environment or use default
9+
STIX_BASE_DIR = os.environ.get("STIX_BASE_DIR", "attack-releases/stix-2.0/v17.1")
10+
11+
12+
@dataclass
13+
class DomainStatistics:
14+
"""Statistics for a single ATT&CK domain."""
15+
16+
name: str
17+
tactics: int
18+
techniques: int
19+
subtechniques: int
20+
groups: int
21+
software: int
22+
campaigns: int
23+
mitigations: int
24+
datasources: int
25+
assets: int = 0
26+
27+
def format_output(self) -> str:
28+
"""
29+
Format domain statistics as a string.
30+
31+
Returns
32+
-------
33+
str
34+
Formatted statistics string for display.
35+
"""
36+
# Define all possible statistics with their labels
37+
stats = [
38+
(self.tactics, "Tactics"),
39+
(self.techniques, "Techniques"),
40+
(self.subtechniques, "Sub-Techniques"),
41+
(self.groups, "Groups"),
42+
(self.software, "Pieces of Software"),
43+
(self.campaigns, "Campaigns"),
44+
(self.mitigations, "Mitigations"),
45+
(self.assets, "Assets"),
46+
(self.datasources, "Data Sources"),
47+
]
48+
49+
# Build parts list, only including items with count > 0
50+
parts = [f"{count} {label}" for count, label in stats if count > 0]
51+
52+
# Join all parts with proper formatting
53+
return f"- {self.name}: {', '.join(parts[:-1])}, and {parts[-1]}"
54+
55+
56+
def load_domain_data() -> dict[str, MitreAttackData]:
57+
"""
58+
Load STIX data for all ATT&CK domains.
59+
60+
Returns
61+
-------
62+
dict of str to MitreAttackData
63+
Mapping of domain names to loaded MitreAttackData objects.
64+
"""
65+
domains = {
66+
"enterprise": "enterprise-attack.json",
67+
"mobile": "mobile-attack.json",
68+
"ics": "ics-attack.json",
69+
}
70+
71+
return {
72+
domain: MitreAttackData(stix_filepath=os.path.join(STIX_BASE_DIR, filename))
73+
for domain, filename in domains.items()
74+
}
75+
76+
77+
def collect_domain_statistics(data: MitreAttackData, domain_name: str) -> DomainStatistics:
78+
"""
79+
Collect statistics for a single domain.
80+
81+
Parameters
82+
----------
83+
data : MitreAttackData
84+
The MitreAttackData object for the domain.
85+
domain_name : str
86+
Display name of the domain.
87+
88+
Returns
89+
-------
90+
DomainStatistics
91+
Statistics for the domain.
92+
"""
93+
# Get all object types, removing revoked and deprecated
94+
tactics = data.get_tactics(remove_revoked_deprecated=True)
95+
techniques = data.get_techniques(include_subtechniques=False, remove_revoked_deprecated=True)
96+
subtechniques = data.get_subtechniques(remove_revoked_deprecated=True)
97+
groups = data.get_groups(remove_revoked_deprecated=True)
98+
software = data.get_software(remove_revoked_deprecated=True)
99+
campaigns = data.get_campaigns(remove_revoked_deprecated=True)
100+
mitigations = data.get_mitigations(remove_revoked_deprecated=True)
101+
datasources = data.get_datasources(remove_revoked_deprecated=True)
102+
103+
# ICS domain has assets
104+
assets = 0
105+
if domain_name == "ICS":
106+
assets = len(data.get_assets(remove_revoked_deprecated=True))
107+
108+
return DomainStatistics(
109+
name=domain_name,
110+
tactics=len(tactics),
111+
techniques=len(techniques),
112+
subtechniques=len(subtechniques),
113+
groups=len(groups),
114+
software=len(software),
115+
campaigns=len(campaigns),
116+
mitigations=len(mitigations),
117+
datasources=len(datasources),
118+
assets=assets,
119+
)
120+
121+
122+
def collect_unique_object_counts(domain_data: dict[str, MitreAttackData]) -> dict[str, int]:
123+
"""
124+
Collect counts of unique objects across all domains.
125+
126+
Some objects (Software, Groups, Campaigns) may appear in multiple domains.
127+
This function counts unique objects to avoid double-counting.
128+
129+
Parameters
130+
----------
131+
domain_data : dict of str to MitreAttackData
132+
Mapping of domain names to MitreAttackData objects.
133+
134+
Returns
135+
-------
136+
dict of str to int
137+
Counts of unique software, groups, and campaigns.
138+
"""
139+
all_software_ids = set()
140+
all_groups_ids = set()
141+
all_campaigns_ids = set()
142+
143+
for data in domain_data.values():
144+
software = data.get_software(remove_revoked_deprecated=True)
145+
groups = data.get_groups(remove_revoked_deprecated=True)
146+
campaigns = data.get_campaigns(remove_revoked_deprecated=True)
147+
148+
all_software_ids.update(obj["id"] for obj in software)
149+
all_groups_ids.update(obj["id"] for obj in groups)
150+
all_campaigns_ids.update(obj["id"] for obj in campaigns)
151+
152+
return {
153+
"software": len(all_software_ids),
154+
"groups": len(all_groups_ids),
155+
"campaigns": len(all_campaigns_ids),
156+
}
157+
158+
159+
def main():
160+
"""Print ATT&CK statistics for all domains."""
161+
# Load data for all domains
162+
domain_data = load_domain_data()
163+
164+
# Collect unique object counts across all domains
165+
unique_counts = collect_unique_object_counts(domain_data)
166+
167+
# Collect statistics for each domain
168+
enterprise_stats = collect_domain_statistics(domain_data["enterprise"], "Enterprise")
169+
mobile_stats = collect_domain_statistics(domain_data["mobile"], "Mobile")
170+
ics_stats = collect_domain_statistics(domain_data["ics"], "ICS")
171+
172+
# Print summary output
173+
print(
174+
f"This version of ATT&CK contains {unique_counts['software']} Pieces of Software, "
175+
f"{unique_counts['groups']} Groups, and {unique_counts['campaigns']} Campaigns"
176+
)
177+
print("Broken out by domain:\n")
178+
179+
# Print domain statistics
180+
print(enterprise_stats.format_output())
181+
print(mobile_stats.format_output())
182+
print(ics_stats.format_output())
183+
184+
185+
if __name__ == "__main__":
186+
main()

0 commit comments

Comments
 (0)