npx skills add mukul975/Anthropic-Cybersecurity-SkillsMITRE ATT&CK
NIST CSF 2.0
MITRE ATLAS
MITRE D3FEND
When to Use
Use this skill when:
- Generating an ATT&CK coverage heatmap to show which techniques your detection stack addresses
- Tagging existing SIEM use cases or Sigma rules with ATT&CK technique IDs for structured reporting
- Aligning your security program roadmap to specific adversary groups known to target your sector
Do not use this skill for real-time incident triage — ATT&CK mapping is an analytical activity best performed post-detection or during threat hunting planning.
Prerequisites
- Access to MITRE ATT&CK knowledge base (https://attack.mitre.org) or local ATT&CK STIX data bundle
- ATT&CK Navigator web app or local installation (https://mitre-attack.github.io/attack-navigator/)
- Inventory of existing detection rules (Sigma, Splunk, Sentinel KQL) to assess current coverage
- ATT&CK Python library:
pip install mitreattack-python
Workflow
Step 1: Obtain Current ATT&CK Data
Download the latest ATT&CK STIX bundle for the relevant matrix (Enterprise, Mobile, ICS):
curl -o enterprise-attack.json \
https://raw.githubusercontent.com/mitre/cti/master/enterprise-attack/enterprise-attack.jsonUse the mitreattack-python library to query techniques programmatically:
from mitreattack.stix20 import MitreAttackData
mitre = MitreAttackData("enterprise-attack.json")
techniques = mitre.get_techniques(remove_revoked_deprecated=True)
for t in techniques[:5]:
print(t["external_references"][0]["external_id"], t["name"])Step 2: Map Existing Detections to Techniques
For each SIEM rule or Sigma file, assign ATT&CK technique IDs. Sigma rules support native ATT&CK tagging:
tags:
- attack.execution
- attack.t1059.001 # PowerShell
- attack.t1059.003 # Windows Command ShellCreate a coverage matrix: list each technique ID and mark as: Detected (alert fires), Logged (data present but no alert), Blind (no data source).
Step 3: Prioritize Coverage Gaps Using Threat Intelligence
Cross-reference coverage gaps with adversary groups targeting your sector. Use ATT&CK Groups data:
groups = mitre.get_groups()
apt29 = mitre.get_object_by_attack_id("G0016", "groups")
apt29_techniques = mitre.get_techniques_used_by_group(apt29)
for t in apt29_techniques:
print(t["object"]["external_references"][0]["external_id"])Prioritize adding detection for techniques used by high-priority threat groups where your coverage is blind.
Step 4: Build Navigator Heatmap
Export coverage scores as ATT&CK Navigator JSON layer:
import json
layer = {
"name": "SOC Detection Coverage Q1 2025",
"versions": {"attack": "14", "navigator": "4.9", "layer": "4.5"},
"domain": "enterprise-attack",
"techniques": [
{"techniqueID": "T1059.001", "score": 100, "comment": "Splunk rule: PS_Encoded_Command"},
{"techniqueID": "T1071.001", "score": 50, "comment": "Logged only, no alert"},
{"techniqueID": "T1055", "score": 0, "comment": "No coverage — blind spot"}
],
"gradient": {"colors": ["#ff6666", "#ffe766", "#8ec843"], "minValue": 0, "maxValue": 100}
}
with open("coverage_layer.json", "w") as f:
json.dump(layer, f)Import layer into ATT&CK Navigator (https://mitre-attack.github.io/attack-navigator/) for visualization.
Step 5: Generate Executive Coverage Report
Summarize coverage by tactic category (Initial Access, Execution, Persistence, etc.) with counts and percentages. Provide a risk-ranked list of top 10 blind-spot techniques based on adversary group usage frequency. Recommend data source additions (e.g., "Enable PowerShell Script Block Logging to address 12 Execution sub-technique gaps").
Key Concepts
| Term | Definition |
|---|---|
| ATT&CK Technique | Specific adversary method identified by T-number (e.g., T1059 = Command and Scripting Interpreter) |
| Sub-technique | More granular variant of a technique (e.g., T1059.001 = PowerShell, T1059.003 = Windows Command Shell) |
| Tactic | Adversary goal category in ATT&CK: Initial Access, Execution, Persistence, Privilege Escalation, Defense Evasion, Credential Access, Discovery, Lateral Movement, Collection, C&C, Exfiltration, Impact |
| Data Source | ATT&CK v10+ component identifying telemetry required to detect a technique (e.g., Process Creation, Network Traffic) |
| Coverage Score | Numeric (0–100) representing detection completeness for a technique: 0=blind, 50=logged only, 100=alerted |
| MITRE D3FEND | Defensive countermeasure ontology complementing ATT&CK — maps defensive techniques to attack techniques they mitigate |
Tools & Systems
- ATT&CK Navigator: Browser-based heatmap visualization tool for layering coverage scores and annotations on the ATT&CK matrix
- mitreattack-python: Official MITRE Python library for programmatic access to ATT&CK STIX data (techniques, groups, software, mitigations)
- Atomic Red Team: MITRE-aligned test library providing atomic test cases to validate detection for each technique
- Sigma: Detection rule format with ATT&CK tagging support; translatable to Splunk, Sentinel, QRadar, Elastic
- ATT&CK Workbench: Self-hosted ATT&CK knowledge base for organizations maintaining custom technique extensions
Common Pitfalls
- Over-claiming coverage: Logging a data source (e.g., process creation events) does not mean the associated technique is detected — a rule must actually fire on malicious patterns.
- Mapping at tactic level only: Tagging a rule as "attack.execution" without a specific technique ID prevents granular gap analysis.
- Ignoring sub-techniques: Many adversaries use specific sub-techniques. Coverage of T1059 (parent) doesn't imply coverage of T1059.005 (Visual Basic).
- Static mapping without updates: ATT&CK releases major versions annually. Coverage maps go stale as techniques are added, revised, or deprecated.
- Not mapping to adversary groups: Generic coverage maps don't distinguish between techniques used by APTs targeting your sector vs. commodity malware.
References and resources
Everything below is rendered for inspection. Script files are read-only and never run.
References 1
api-reference.md2.6 KB
API Reference: Mapping MITRE ATT&CK Techniques
mitreattack-python Library
| Method | Description |
|---|---|
MitreAttackData(stix_filepath=path) |
Load ATT&CK STIX 2.0 data bundle from file |
get_techniques(remove_revoked_deprecated=False) |
Returns list[AttackPattern] STIX objects |
get_groups(remove_revoked_deprecated=False) |
Returns list[IntrusionSet] STIX objects |
get_techniques_used_by_group(group_stix_id) |
Returns list[dict] with t["object"] as AttackPattern |
get_attack_id(stix_id=id) |
Resolve STIX ID to ATT&CK ID (e.g., T1059) |
get_mitigations(remove_revoked_deprecated=False) |
Returns list[CourseOfAction] |
get_software(remove_revoked_deprecated=False) |
Returns list[Malware or Tool] |
ATT&CK Navigator API (Layer Format)
| Field | Type | Description |
|---|---|---|
techniques[].techniqueID |
string | ATT&CK technique ID (e.g., T1059) |
techniques[].score |
number | Coverage score (0=gap, 1=detected) |
techniques[].color |
string | Hex color for heatmap visualization |
domain |
string | ATT&CK domain: enterprise-attack, mobile-attack, ics-attack |
MITRE ATT&CK TAXII Server
| Endpoint | Description |
|---|---|
cti-taxii.mitre.org/stix/collections/ |
List available STIX collections |
cti-taxii.mitre.org/stix/collections/{id}/objects/ |
Download STIX objects |
Sigma Rules (Detection Engineering)
| Field | Description |
|---|---|
tags |
ATT&CK mapping (e.g., attack.t1059.001) |
logsource.product |
Target log source (windows, linux, aws) |
detection |
Search logic with conditions |
Key Libraries
- mitreattack-python (
pip install mitreattack-python): Official MITRE ATT&CK Python library - stix2: Parse and create STIX 2.1 objects
- taxii2-client: Download ATT&CK data from TAXII server
- pySigma: Parse and convert Sigma detection rules
Configuration
| Variable | Description |
|---|---|
ATTACK_STIX_PATH |
Path to local enterprise-attack.json STIX bundle |
NAVIGATOR_URL |
ATT&CK Navigator instance URL |
Data Sources
| Source | URL | Description |
|---|---|---|
| ATT&CK STIX | github.com/mitre/cti |
Official STIX bundles |
| ATT&CK Navigator | github.com/mitre-attack/attack-navigator |
Layer visualization tool |
| Sigma Rules | github.com/SigmaHQ/sigma |
Community detection rules |
References
Scripts 1
agent.py7.6 KB
#!/usr/bin/env python3
"""
MITRE ATT&CK Technique Mapping Agent
Maps detection rules and security alerts to ATT&CK techniques using
the mitreattack-python library. Generates coverage heatmaps and identifies gaps.
"""
import json
import os
import sys
from datetime import datetime, timezone
from mitreattack.stix20 import MitreAttackData
def load_attack_data(stix_path: str = None) -> MitreAttackData:
"""Load MITRE ATT&CK STIX data bundle."""
if stix_path and os.path.exists(stix_path):
return MitreAttackData(stix_filepath=stix_path)
return MitreAttackData(stix_filepath="enterprise-attack.json")
def get_all_techniques(attack_data: MitreAttackData) -> list[dict]:
"""Retrieve all Enterprise ATT&CK techniques with metadata.
Returns list[AttackPattern] (STIX objects supporting dict-like access).
"""
techniques = attack_data.get_techniques(remove_revoked_deprecated=True)
result = []
for tech in techniques:
# Use get_attack_id() to resolve STIX ID -> ATT&CK ID (e.g. T1059)
tech_id = attack_data.get_attack_id(stix_id=tech.id) or ""
platforms = tech.get("x_mitre_platforms", [])
tactics = []
for phase in tech.get("kill_chain_phases", []):
if phase.get("kill_chain_name") == "mitre-attack":
tactics.append(phase.get("phase_name", ""))
result.append({
"id": tech_id,
"name": tech.name,
"tactics": tactics,
"platforms": platforms,
"is_subtechnique": tech.get("x_mitre_is_subtechnique", False),
})
return sorted(result, key=lambda x: x["id"])
def get_techniques_by_group(attack_data: MitreAttackData, group_name: str) -> list[str]:
"""Get techniques used by a specific threat group.
Groups are IntrusionSet STIX objects; techniques retrieved via relationship query.
"""
groups = attack_data.get_groups(remove_revoked_deprecated=True)
target_group = None
for group in groups:
if group.name.lower() == group_name.lower():
target_group = group
break
for alias in group.get("aliases", []):
if alias.lower() == group_name.lower():
target_group = group
break
if not target_group:
return []
# get_techniques_used_by_group returns list of RelationshipEntry dicts
# Each entry has t["object"] = AttackPattern STIX object
techniques = attack_data.get_techniques_used_by_group(target_group.id)
tech_ids = []
for t in techniques:
technique = t["object"]
attack_id = attack_data.get_attack_id(stix_id=technique.id)
if attack_id:
tech_ids.append(attack_id)
return sorted(tech_ids)
def load_detection_rules(rules_file: str) -> list[dict]:
"""Load detection rules with ATT&CK technique tags."""
if os.path.exists(rules_file):
with open(rules_file, "r") as f:
return json.load(f)
return []
def calculate_coverage(all_techniques: list[dict], detected_technique_ids: set) -> dict:
"""Calculate ATT&CK coverage statistics by tactic."""
tactic_coverage = {}
for tech in all_techniques:
if tech["is_subtechnique"]:
continue
for tactic in tech["tactics"]:
if tactic not in tactic_coverage:
tactic_coverage[tactic] = {"total": 0, "covered": 0, "uncovered_techniques": []}
tactic_coverage[tactic]["total"] += 1
if tech["id"] in detected_technique_ids:
tactic_coverage[tactic]["covered"] += 1
else:
tactic_coverage[tactic]["uncovered_techniques"].append(tech["id"])
for tactic, data in tactic_coverage.items():
data["coverage_pct"] = round(data["covered"] / max(data["total"], 1) * 100, 1)
total_techniques = len([t for t in all_techniques if not t["is_subtechnique"]])
covered = len(detected_technique_ids & {t["id"] for t in all_techniques if not t["is_subtechnique"]})
return {
"overall_coverage_pct": round(covered / max(total_techniques, 1) * 100, 1),
"total_techniques": total_techniques,
"covered_techniques": covered,
"by_tactic": tactic_coverage,
}
def generate_navigator_layer(techniques: list[dict], detected_ids: set, layer_name: str) -> dict:
"""Generate ATT&CK Navigator JSON layer for visualization."""
tech_entries = []
for tech in techniques:
score = 1 if tech["id"] in detected_ids else 0
color = "#31a354" if score == 1 else ""
tech_entries.append({
"techniqueID": tech["id"],
"score": score,
"color": color,
"enabled": True,
})
return {
"name": layer_name,
"versions": {"attack": "14", "navigator": "4.9.1", "layer": "4.5"},
"domain": "enterprise-attack",
"description": f"Detection coverage layer generated {datetime.now(timezone.utc).strftime('%Y-%m-%d')}",
"gradient": {"colors": ["#ff6666", "#31a354"], "minValue": 0, "maxValue": 1},
"techniques": tech_entries,
}
def identify_priority_gaps(coverage: dict, group_techniques: list[str]) -> list[dict]:
"""Identify high-priority coverage gaps based on threat group activity."""
gaps = []
all_uncovered = set()
for tactic, data in coverage["by_tactic"].items():
all_uncovered.update(data["uncovered_techniques"])
for tech_id in group_techniques:
if tech_id in all_uncovered:
gaps.append({"technique_id": tech_id, "reason": "Used by target threat group, no detection"})
return gaps
def generate_report(coverage: dict, gaps: list, group_name: str) -> str:
"""Generate ATT&CK mapping report."""
lines = [
"MITRE ATT&CK DETECTION COVERAGE REPORT",
"=" * 50,
f"Report Date: {datetime.now(timezone.utc).strftime('%Y-%m-%d %H:%M UTC')}",
"",
f"Overall Coverage: {coverage['overall_coverage_pct']}%",
f" Techniques Covered: {coverage['covered_techniques']}/{coverage['total_techniques']}",
"",
"COVERAGE BY TACTIC:",
]
for tactic, data in sorted(coverage["by_tactic"].items()):
bar = "#" * int(data["coverage_pct"] / 5) + "." * (20 - int(data["coverage_pct"] / 5))
lines.append(f" {tactic:35s} [{bar}] {data['coverage_pct']}%")
if gaps:
lines.extend(["", f"PRIORITY GAPS (Threat Group: {group_name}):", "-" * 40])
for gap in gaps[:15]:
lines.append(f" [GAP] {gap['technique_id']} - {gap['reason']}")
return "\n".join(lines)
if __name__ == "__main__":
stix_path = sys.argv[1] if len(sys.argv) > 1 else "enterprise-attack.json"
rules_file = sys.argv[2] if len(sys.argv) > 2 else "detection_rules.json"
group_name = sys.argv[3] if len(sys.argv) > 3 else "APT29"
print("[*] Loading MITRE ATT&CK data...")
attack_data = load_attack_data(stix_path)
all_techniques = get_all_techniques(attack_data)
print(f"[*] Loaded {len(all_techniques)} techniques")
rules = load_detection_rules(rules_file)
detected_ids = set()
for rule in rules:
detected_ids.update(rule.get("attack_ids", []))
coverage = calculate_coverage(all_techniques, detected_ids)
group_techs = get_techniques_by_group(attack_data, group_name)
gaps = identify_priority_gaps(coverage, group_techs)
report = generate_report(coverage, gaps, group_name)
print(report)
layer = generate_navigator_layer(all_techniques, detected_ids, "Detection Coverage")
with open("attack_navigator_layer.json", "w") as f:
json.dump(layer, f, indent=2)
print(f"\n[*] Navigator layer saved to attack_navigator_layer.json")