attack-query 0.7.0
Programmatic queries on MITRE ATT&CK threat actor techniques with natural language support
License: MIT
Requires Python: >=3.10
Keywords: apt, attack, cybersecurity, mitre, threat-intelligence, ttps

# attack-query

[![PyPI version](https://img.shields.io/pypi/v/attack-query.svg)](https://pypi.org/project/attack-query/)
[![PyPI downloads](https://img.shields.io/pypi/dm/attack-query.svg)](https://pypi.org/project/attack-query/)
[![Python 3.10+](https://img.shields.io/pypi/pyversions/attack-query.svg)](https://pypi.org/project/attack-query/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![Ruff](https://img.shields.io/badge/code%20style-ruff-000000.svg)](https://github.com/astral-sh/ruff)

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)

```bash
# 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

```bash
pip install git+https://github.com/swoodeng/attack-query.git
```

## Quick Start

### Command Line

```bash
# 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

```python
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

```python
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 |

```bash
# 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:

```bash
# 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

```bash
# Install with smart mode dependencies
pip install attack-query[smart]
```

### Usage

```bash
# 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

```bash
# 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:

```bash
# 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:
1. Campaigns attributed to the group
2. Campaign date ranges (first_seen/last_seen)
3. 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

```bash
# 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:

```python
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

```bash
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

```bash
pytest
pytest --cov=attack_query  # with coverage
```

### Code Quality

```bash
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](LICENSE) for details.

## Related Projects

- [mitreattack-python](https://github.com/mitre-attack/mitreattack-python) - Official MITRE library
- [ATT&CK Navigator](https://github.com/mitre-attack/attack-navigator) - Web-based visualization
- [attackcti](https://github.com/OTRF/ATTACK-Python-Client) - TAXII client for ATT&CK