Programmatic queries on MITRE ATT&CK threat actor techniques with natural language support
Project description
attack-query
Programmatic queries on MITRE ATT&CK threat actor techniques with natural language support.
Features
- Cross-matrix support: Query Enterprise, Mobile, or ICS ATT&CK matrices
- Natural language queries:
"techniques used by APT28 or APT29 but not APT33" - Set operations: Union (
or), intersection (and), difference (but not), complement (NOT used by) - Tactics queries: Query which tactics a group uses (derived from techniques)
- Sub-technique support: Query parent/child technique relationships (T1566.001)
- Group alias resolution: Use aliases like "Fancy Bear" instead of "APT28"
- Software/Tool queries: Query malware and tools used by groups or implementing techniques
- Mitigation queries: Find countermeasures for techniques or see what a mitigation covers
- Data source queries: Explore detection data sources and data components for detection coverage
- Campaign queries: Explore ATT&CK campaigns, attributed groups, and techniques used
- Timeline queries: Filter campaigns and techniques by year or date range
- Version selection: Query specific ATT&CK versions (e.g., v12.0, v15.1)
- Similarity scoring: Find groups with similar technique profiles (Jaccard, Overlap, Cosine)
- Smart mode: LLM-assisted query parsing for ambiguous queries (optional)
- Fuzzy matching: Helpful suggestions when you make typos
- Navigator export: Generate ATT&CK Navigator layer files
- Heatmap generation: Visualize technique overlap across groups
- Offline support: Cache data locally for offline use
- Type-safe: Full type annotations with strict mypy checking
Installation
Using UV (recommended)
# Install from source
uv pip install git+https://github.com/swoodeng/attack-query.git
# Or clone and install in development mode
git clone https://github.com/swoodeng/attack-query.git
cd attack-query
uv pip install -e ".[dev]"
Using pip
pip install git+https://github.com/swoodeng/attack-query.git
Quick Start
Command Line
# Union: techniques used by ANY of the groups
attack-query "techniques used by APT28 or APT29"
# Intersection: techniques used by ALL groups
attack-query "techniques used by APT28 and APT29"
attack-query "techniques employed by APT28, APT29, and APT33" # Alternative phrasing
# Difference: exclude techniques from certain groups
attack-query "techniques used by APT28 or APT29 but not APT33"
attack-query "techniques used by APT28 but not by APT29" # "but not by" also works
# Verbose output (includes tactics)
attack-query "techniques used by APT28" -v
# Complement: techniques NOT used by a group
attack-query "techniques NOT used by APT28"
# Sub-technique queries
attack-query "sub-techniques of T1566"
attack-query "parent of T1566.001"
# Group alias resolution
attack-query "who is Fancy Bear"
attack-query "aliases of APT28"
# Software/Tool queries
attack-query "software used by APT28"
attack-query "groups using Mimikatz"
attack-query "techniques for Cobalt Strike"
attack-query "software using T1566"
attack-query "software info Mimikatz"
# Mixed software + group queries
attack-query "techniques used by Mimikatz but not APT29" # Software minus group
attack-query "techniques used by software Mimikatz and group APT28" # Explicit qualifiers
attack-query "techniques used by both Cobalt Strike and APT28" # Intersection
# Tactics queries
attack-query "tactics used by APT28" # Tactics from group's techniques
attack-query "tactics used by APT28 and APT29" # Tactics shared by both groups
attack-query "tactics used by APT28 or APT29" # Tactics from either group
attack-query "tactics not used by APT28" # Tactics NOT used by a group
# Mitigation queries
attack-query "mitigations for T1566"
attack-query "how to mitigate T1566"
attack-query "techniques mitigated by M1031"
attack-query "mitigation info M1017"
# Data source queries
attack-query "data sources"
attack-query "data source info Process"
attack-query "data components"
attack-query "data component info Process Creation"
attack-query "techniques detectable by Process Creation"
# Campaign queries
attack-query "campaigns" # List all campaigns
attack-query "campaigns by APT28" # Campaigns attributed to a group
attack-query "techniques in C0027" # Techniques used in a campaign
attack-query "campaign info C0027" # Campaign details
# Timeline queries
attack-query "campaigns in 2023" # Campaigns active in a year
attack-query "campaigns between 2022 and 2024" # Campaigns in date range
attack-query "techniques used in 2023" # Techniques from campaigns in year
# Similarity scoring
attack-query "groups similar to APT28" # Find groups with similar TTPs
attack-query "similarity APT28 APT29" # Detailed metrics between two groups
attack-query "groups like APT28 threshold 0.5" # With minimum similarity score
attack-query "groups similar to APT28 using cosine" # Different similarity metric
# Export formats
attack-query "techniques used by APT28" --format csv # CSV output
attack-query "techniques used by APT28" --format md # Markdown table
attack-query "techniques used by APT28" --format layer # Navigator layer JSON
attack-query "techniques used by APT28" --json # JSON output
# Use a specific ATT&CK version
attack-query --version 12.0 "techniques used by APT28"
# Use a different matrix (Mobile or ICS)
attack-query --matrix mobile "techniques used by APT28"
attack-query --matrix ics "techniques used by ALLANITE"
# List available versions
attack-query --list-versions
# Interactive mode
attack-query
Python API
from attack_query import ATTACKDataStore, ATTACKQueryEngine, Matrix
# Load latest ATT&CK data (Enterprise matrix by default)
store = ATTACKDataStore()
store.load()
# Or load a specific version
store = ATTACKDataStore(version="12.0")
store.load()
# Or load a different matrix (Mobile or ICS)
store = ATTACKDataStore(matrix=Matrix.MOBILE)
store.load()
store = ATTACKDataStore(matrix="ics") # Also accepts string
store.load()
# Create query engine
engine = ATTACKQueryEngine(store)
# Get techniques used by a group
apt28_techniques = engine.get_group_techniques("APT28")
# Set operations
shared = engine.techniques_intersection(["APT28", "APT29"])
unique_to_apt28_29 = engine.techniques_difference(
include_groups=["APT28", "APT29"],
exclude_groups=["APT33"]
)
# Compare groups
comparison = engine.compare_groups("APT28", "APT29")
print(f"Jaccard similarity: {comparison['jaccard_similarity']:.1%}")
# Export to Navigator
layer = engine.export_navigator_layer(
unique_to_apt28_29,
name="Unique to APT28/29"
)
Natural Language Parser
from attack_query import ATTACKDataStore, ATTACKQueryEngine, NLQueryParser
store = ATTACKDataStore()
store.load()
engine = ATTACKQueryEngine(store)
parser = NLQueryParser(engine)
# Parse and execute natural language queries
# 'or' = union, 'and' = intersection, 'but not' = difference
results = parser.parse_and_execute(
"techniques used by APT28 or APT29 but not APT33"
)
# Access results
for technique in results["techniques"]:
print(f"{technique['id']}: {technique['name']}")
Supported Query Patterns
| Pattern | Example | Set Operation |
|---|---|---|
| Single group | techniques used by APT28 |
— |
| Union (ANY) | techniques used by APT28 or APT29 |
A ∪ B |
| Intersection (ALL) | techniques used by APT28 and APT29 |
A ∩ B |
| Comma-list with and | techniques employed by APT28, APT29, and APT33 |
A ∩ B ∩ C |
| Union with exclusion | techniques used by APT28 or APT29 but not APT33 |
(A ∪ B) − C |
| Intersection with exclusion | techniques used by APT28 and APT29 but not APT33 |
(A ∩ B) − C |
| Complement | techniques NOT used by APT28 |
Ā (all − A) |
| Sub-techniques | sub-techniques of T1566 |
— |
| Parent technique | parent of T1566.001 |
— |
| Group alias lookup | who is Fancy Bear |
— |
| List aliases | aliases of APT28 |
— |
| Tactic filter | techniques used by APT28 for initial access |
— |
| Tactics by group | tactics used by APT28 |
— |
| Tactics intersection | tactics used by APT28 and APT29 |
A ∩ B |
| Tactics union | tactics used by APT28 or APT29 |
A ∪ B |
| Tactics complement | tactics not used by APT28 |
Ā (all − A) |
| Reverse lookup | groups using T1566 |
x ∈ A |
| Comparison | compare APT28 and APT29 |
Shows ∩, A−B, B−A |
| Software by group | software used by APT28 |
— |
| Groups by software | groups using Mimikatz |
— |
| Techniques by software | techniques for Cobalt Strike |
— |
| Software by technique | software using T1566 |
— |
| Software info | software info Mimikatz |
— |
| Mixed: software + group | techniques used by Mimikatz but not APT29 |
S − G |
| Mixed: explicit qualifiers | techniques used by software X and group Y |
S ∩ G |
| Mixed: both keyword | techniques used by both Cobalt Strike and APT28 |
S ∩ G |
| Mitigations for technique | mitigations for T1566 |
— |
| Techniques by mitigation | techniques mitigated by M1031 |
— |
| Mitigation info | mitigation info M1017 |
— |
| List data sources | data sources |
— |
| Data source info | data source info Process |
— |
| List data components | data components |
— |
| Data component info | data component info Process Creation |
— |
| Techniques by data component | techniques detectable by Process Creation |
— |
| List campaigns | campaigns |
— |
| Campaigns by group | campaigns by APT28 |
— |
| Techniques in campaign | techniques in C0027 |
— |
| Campaign info | campaign info C0027 |
— |
| Campaigns in year | campaigns in 2023 |
— |
| Campaigns in range | campaigns between 2022 and 2024 |
— |
| Techniques in year | techniques used in 2023 |
— |
| Techniques in range | techniques between 2022 and 2024 |
— |
| Group techniques in year | techniques used by APT28 in 2023 |
Campaign-based |
| Group techniques in range | techniques used by APT28 between 2022 and 2024 |
Campaign-based |
| Similar groups | groups similar to APT28 |
— |
| Group similarity | similarity APT28 APT29 |
Jaccard, Overlap, Cosine |
| Similarity with threshold | groups like APT28 threshold 0.5 |
— |
| Similarity with metric | groups similar to APT28 using cosine |
— |
| Export to CSV | --format csv |
— |
| Export to Markdown | --format md |
— |
| Export to Navigator | --format layer |
— |
Matrix Selection
The tool supports all three ATT&CK matrices:
| Matrix | Flag | Description |
|---|---|---|
| Enterprise | --matrix enterprise (default) |
Techniques for Windows, Linux, macOS, Cloud, etc. |
| Mobile | --matrix mobile |
Techniques for Android and iOS |
| ICS | --matrix ics |
Techniques for Industrial Control Systems |
# Query Mobile ATT&CK (default is Enterprise)
attack-query --matrix mobile "techniques used by APT28"
# Query ICS ATT&CK
attack-query --matrix ics "techniques used by ALLANITE"
# Combine with version selection
attack-query --matrix mobile --version 12.0 "groups"
Version Selection
The tool supports specific ATT&CK versions for reproducibility:
# List available versions
attack-query --list-versions
# Use ATT&CK v12.0 (October 2022)
attack-query --version 12.0 "techniques used by APT28"
Caching Behavior
| Data Type | Cache Duration | Example Location |
|---|---|---|
| Specific version | Permanent (immutable) | ~/.cache/attack/enterprise-attack-12.0.json |
| Latest version | 7 days | ~/.cache/attack/mobile-attack-latest.json |
Each matrix is cached separately, so you can work with Enterprise and Mobile data without re-downloading.
Smart Mode (LLM-Assisted)
Enable smart mode for LLM-assisted query parsing. Useful for ambiguous or non-standard queries.
Installation
# Install with smart mode dependencies
pip install attack-query[smart]
Usage
# Use smart mode with default model (ollama:llama3.2)
attack-query --smart "what attacks does fancy bear do"
# Specify a different model
attack-query --smart --model ollama:mistral "show me APT28 tools"
attack-query --smart --model openai:gpt-4o-mini "phishing techniques by russian groups"
Configuration
# Environment variables
export ATTACK_QUERY_COMPLETION_MODEL=ollama:llama3.2 # Default model
export OLLAMA_BASE_URL=http://localhost:11434 # Ollama endpoint
export OPENAI_API_KEY=sk-... # For OpenAI models
Supported Providers
| Provider | Model Examples | Notes |
|---|---|---|
ollama |
llama3.2, mistral, codellama |
Local, requires Ollama running |
openai |
gpt-4o-mini, gpt-4o |
Cloud, requires API key |
Fuzzy Matching
Even without smart mode, attack-query provides fuzzy matching suggestions when queries fail:
$ attack-query "techniques used by APT27"
❌ Error: Could not parse query
Did you mean:
• 'APT27' → 'APT28'
Try pattern: techniques used by {GROUP}
Temporal Group Queries
Query techniques used by a group during a specific time period:
# Techniques used by APT28 in 2023 (based on campaign data)
attack-query "techniques used by APT28 in 2023"
# Techniques used by APT28 between 2022 and 2024
attack-query "techniques used by APT28 between 2022 and 2024"
How it works: These queries approximate temporal group activity by cross-referencing:
- Campaigns attributed to the group
- Campaign date ranges (first_seen/last_seen)
- Techniques used in those campaigns
⚠️ Note: Results only include techniques documented in campaigns, not all techniques attributed to the group. ATT&CK does not timestamp individual group-technique relationships.
Limitations
Direct group-technique timestamps: ATT&CK data does not include timestamps for when a specific group used a specific technique. The temporal group queries above provide an approximation based on campaign data.
Export Formats
Export query results in different formats:
Command Line
# CSV format for spreadsheets
attack-query "techniques used by APT28" --format csv > apt28.csv
# Markdown format for documentation
attack-query "techniques used by APT28" --format md > apt28.md
# Navigator layer for visualization
attack-query "techniques used by APT28" --format layer > apt28_layer.json
# JSON format for scripting
attack-query "techniques used by APT28" --json > apt28.json
# CSV with descriptions (verbose mode)
attack-query "techniques used by APT28" --format csv -v > apt28_full.csv
Interactive Mode
query> techniques used by APT28
query> export csv results.csv # Export to CSV
query> export md results.md # Export to Markdown
query> export layer.json # Export to Navigator layer
Navigator Layer Export
Export query results as ATT&CK Navigator layer files:
from attack_query import ATTACKDataStore, ATTACKQueryEngine
import json
store = ATTACKDataStore()
store.load()
engine = ATTACKQueryEngine(store)
# Get techniques
techniques = engine.techniques_difference(["APT28", "APT29"], ["APT33"])
# Export as Navigator layer
layer = engine.export_navigator_layer(
techniques,
name="APT28/29 Unique Techniques",
description="Techniques used by APT28 or APT29 but not APT33",
color="#ff6666"
)
# Save to file
with open("layer.json", "w") as f:
json.dump(layer, f, indent=2)
Then import the layer at https://mitre-attack.github.io/attack-navigator/
Development
Setup
git clone https://github.com/swoodeng/attack-query.git
cd attack-query
uv venv
source .venv/bin/activate # or `.venv\Scripts\activate` on Windows
uv pip install -e ".[dev]"
Running Tests
pytest
pytest --cov=attack_query # with coverage
Code Quality
ruff check src tests # linting
ruff format src tests # formatting
mypy src # type checking
Data Source
This tool uses the official MITRE ATT&CK STIX data from: https://github.com/mitre-attack/attack-stix-data
License
MIT License - see LICENSE for details.
Related Projects
- mitreattack-python - Official MITRE library
- ATT&CK Navigator - Web-based visualization
- attackcti - TAXII client for ATT&CK
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file attack_query-0.7.0.tar.gz.
File metadata
- Download URL: attack_query-0.7.0.tar.gz
- Upload date:
- Size: 92.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.24 {"installer":{"name":"uv","version":"0.9.24","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
25f39e0c7c1481cb21ffc151e429ad67ed33d1400eee14e0a60422da95a24ecc
|
|
| MD5 |
9f8b72ed807c7a5b8000333982d68635
|
|
| BLAKE2b-256 |
dcfd1f9f2eda851028dc62ca1609f206999ff85f9806064019afaee88f6480bd
|
File details
Details for the file attack_query-0.7.0-py3-none-any.whl.
File metadata
- Download URL: attack_query-0.7.0-py3-none-any.whl
- Upload date:
- Size: 49.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.9.24 {"installer":{"name":"uv","version":"0.9.24","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e78dd6fe16debc52112ebc2abc0889447b6014e2e9e1c2b241b384cb516ec690
|
|
| MD5 |
399359c723d8ca64e0cae3d1fff49427
|
|
| BLAKE2b-256 |
487051996fe119c1aeeef4f2778ad30afbec421bb8f2f8967942ad49489beb9c
|