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
Metadata
Release files for attack-query 0.7.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| attack_query-0.7.0.tar.gz | 92.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| attack_query-0.7.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 141.4 kB
Release files / attack_query-0.7.0.tar.gz
| Download URL | attack_query-0.7.0.tar.gz |
|---|---|
| Size | 92.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
25f39e0c7c1481cb21ffc151e429ad67ed33d1400eee14e0a60422da95a24ecc
|
|
BLAKE2b-256 checksum How to use checksums |
dcfd1f9f2eda851028dc62ca1609f206999ff85f9806064019afaee88f6480bd
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is 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}
|
Release files / attack_query-0.7.0-py3-none-any.whl
| Download URL | attack_query-0.7.0-py3-none-any.whl |
|---|---|
| Size | 49.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
e78dd6fe16debc52112ebc2abc0889447b6014e2e9e1c2b241b384cb516ec690
|
|
BLAKE2b-256 checksum How to use checksums |
487051996fe119c1aeeef4f2778ad30afbec421bb8f2f8967942ad49489beb9c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is 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}
|