# analyzing-threat-actor-ttps-with-mitre-navigator

Map advanced persistent threat (APT) group TTPs to the MITRE ATT&CK framework using the attackcti Python library to query STIX/TAXII data for group-technique associations, then generate ATT&CK Navigator layer files to visualize and compare defensive coverage against adversary profiles. Use when profiling an APT group's techniques, building Navigator coverage heatmaps, or assessing technique coverage gaps against a specific threat actor.

- **Kind:** skill
- **Source:** https://github.com/mukul975/Anthropic-Cybersecurity-Skills
- **Page:** https://forefy.com/skills/cc6e2615-cb30-47ba-96d6-3759edf6deae
- **API (JSON + files):** https://forefy.com/api/asr/cc6e2615-cb30-47ba-96d6-3759edf6deae

---

## LICENSE

```

```

## SKILL.md

---
name: analyzing-threat-actor-ttps-with-mitre-navigator
description: 'Map advanced persistent threat (APT) group TTPs to the MITRE ATT&CK framework using the attackcti Python library to query STIX/TAXII data for group-technique associations, then generate ATT&CK Navigator layer files to visualize and compare defensive coverage against adversary profiles. Use when profiling an APT group''s techniques, building Navigator coverage heatmaps, or assessing technique coverage gaps against a specific threat actor.

  '
domain: cybersecurity
subdomain: threat-intelligence
tags:
- mitre-attack
- navigator
- threat-intelligence
- apt
- ttp-mapping
- stix
- attackcti
version: '1.0'
author: mahipal
license: Apache-2.0
nist_ai_rmf:
- MEASURE-2.7
- MAP-5.1
- MANAGE-2.4
atlas_techniques:
- AML.T0070
- AML.T0066
- AML.T0082
d3fend_techniques:
- File Metadata Consistency Validation
- Application Protocol Command Analysis
- Identifier Analysis
- Content Format Conversion
- Message Analysis
nist_csf:
- ID.RA-01
- ID.RA-05
- DE.CM-01
- DE.AE-02
mitre_attack:
- T1566.001
- T1059.001
- T1071.001
- T1547.001
- T1053.005
---
# Analyzing Threat Actor TTPs with MITRE Navigator

## Overview

The MITRE ATT&CK Navigator is a web application for annotating and visualizing ATT&CK matrices.
Combined with the attackcti Python library (which queries ATT&CK STIX data via TAXII), analysts
can programmatically generate Navigator layer files mapping specific threat group TTPs, compare
multiple groups, and assess detection coverage gaps against known adversaries.


## When to Use

- When investigating security incidents that require analyzing threat actor ttps with mitre navigator
- When building detection rules or threat hunting queries for this domain
- When SOC analysts need structured procedures for this analysis type
- When validating security monitoring coverage for related attack techniques

## Prerequisites

- Python 3.8+ with attackcti and stix2 libraries installed
- MITRE ATT&CK Navigator (web UI or local instance)
- Understanding of STIX 2.1 objects and relationships

## Steps

1. Query ATT&CK STIX data for target threat group using attackcti
2. Extract techniques associated with the group via STIX relationships
3. Generate ATT&CK Navigator layer JSON with technique annotations
4. Overlay detection coverage to identify gaps
5. Export layer for team review and defensive planning

## Expected Output

```json
{
  "name": "APT29 TTPs",
  "domain": "enterprise-attack",
  "techniques": [
    {"techniqueID": "T1566.001", "score": 1, "comment": "Spearphishing Attachment"},
    {"techniqueID": "T1059.001", "score": 1, "comment": "PowerShell"}
  ]
}
```

## references

```

```

## references/api-reference.md

# Analyzing Threat Actor TTPs with MITRE Navigator — API Reference

## attackcti Python Library

| Method | Description |
|--------|-------------|
| `attack_client()` | Initialize STIX/TAXII client for ATT&CK data |
| `client.get_groups()` | Retrieve all threat groups from ATT&CK |
| `client.get_techniques()` | Retrieve all techniques from ATT&CK |
| `client.get_techniques_used_by_group(group)` | Get techniques linked to a specific group |
| `client.get_software()` | Retrieve all software/tools from ATT&CK |
| `client.get_software_used_by_group(group)` | Get software used by a specific group |
| `client.get_mitigations()` | Retrieve all mitigations from ATT&CK |
| `client.get_data_sources()` | Retrieve all data sources from ATT&CK |

## STIX 2.1 Group Object Fields

| Field | Description |
|-------|-------------|
| `id` | STIX object ID (e.g., `intrusion-set--abc123`) |
| `name` | Group name (e.g., APT29) |
| `aliases` | Alternative names for the group |
| `description` | Group description and background |
| `external_references` | List of references including ATT&CK ID |
| `created` | Object creation timestamp |
| `modified` | Last modification timestamp |

## STIX 2.1 Technique Object Fields

| Field | Description |
|-------|-------------|
| `name` | Technique name (e.g., Spearphishing Attachment) |
| `external_references[].external_id` | ATT&CK technique ID (e.g., T1566.001) |
| `x_mitre_platforms` | Target platforms (Windows, Linux, macOS) |
| `kill_chain_phases` | Associated tactics in the kill chain |
| `x_mitre_detection` | Detection guidance for the technique |
| `x_mitre_is_subtechnique` | Whether this is a sub-technique |

## ATT&CK Navigator Layer JSON Schema

| Field | Type | Description |
|-------|------|-------------|
| `name` | string | Layer display name |
| `versions.attack` | string | ATT&CK version (e.g., "15") |
| `versions.navigator` | string | Navigator version (e.g., "5.0") |
| `versions.layer` | string | Layer format version (e.g., "4.5") |
| `domain` | string | `enterprise-attack`, `mobile-attack`, or `ics-attack` |
| `techniques[].techniqueID` | string | ATT&CK technique ID |
| `techniques[].score` | integer | Numeric score for coloring (0-100) |
| `techniques[].color` | string | Hex color override (e.g., `#ff6666`) |
| `techniques[].comment` | string | Annotation text for the technique |
| `techniques[].enabled` | boolean | Whether technique cell is enabled |
| `gradient.colors` | array | Color gradient from min to max score |
| `gradient.minValue` | integer | Minimum score value |
| `gradient.maxValue` | integer | Maximum score value |
| `filters.platforms` | array | Platforms to display in the matrix |
| `legendItems[].label` | string | Legend entry label |
| `legendItems[].color` | string | Legend entry color |

## CLI Usage

```bash
# List all ATT&CK threat groups
python agent.py --list-groups

# Analyze a specific group
python agent.py --group "APT29"

# Generate Navigator layer file
python agent.py --group "APT29" --layer-output apt29_layer.json

# Compare multiple groups
python agent.py --compare "APT29" "APT28" "Lazarus Group"

# Save full report as JSON
python agent.py --group "APT29" --layer-output apt29.json --output report.json
```

## External References

- [ATT&CK Navigator GitHub](https://github.com/mitre-attack/attack-navigator)
- [attackcti Documentation](https://attackcti.readthedocs.io/)
- [MITRE ATT&CK Groups](https://attack.mitre.org/groups/)
- [STIX 2.1 Specification](https://docs.oasis-open.org/cti/stix/v2.1/stix-v2.1.html)

## scripts

```

```

## scripts/agent.py

```python
#!/usr/bin/env python3
"""MITRE ATT&CK Navigator layer generation and threat actor TTP mapping agent."""

import json
import sys
import argparse
from datetime import datetime

try:
    from attackcti import attack_client
except ImportError:
    print("Install: pip install attackcti")
    sys.exit(1)


def get_attack_client():
    """Initialize ATT&CK STIX/TAXII client."""
    return attack_client()


def list_threat_groups(client):
    """List all threat groups in ATT&CK."""
    groups = client.get_groups()
    results = []
    for g in groups:
        aliases = g.get("aliases", [])
        results.append({
            "name": g.get("name", ""),
            "id": g.get("external_references", [{}])[0].get("external_id", "")
                  if g.get("external_references") else "",
            "aliases": aliases,
            "description": g.get("description", "")[:200],
        })
    return sorted(results, key=lambda x: x["name"])


def get_group_techniques(client, group_name):
    """Get all techniques used by a specific threat group."""
    groups = client.get_groups()
    target_group = None
    for g in groups:
        if g.get("name", "").lower() == group_name.lower():
            target_group = g
            break
        aliases = [a.lower() for a in g.get("aliases", [])]
        if group_name.lower() in aliases:
            target_group = g
            break

    if not target_group:
        return {"error": f"Group '{group_name}' not found"}

    group_stix_id = target_group["id"]
    techniques = client.get_techniques_used_by_group(target_group)

    results = []
    for tech in techniques:
        ext_refs = tech.get("external_references", [])
        tech_id = ""
        url = ""
        for ref in ext_refs:
            if ref.get("source_name") == "mitre-attack":
                tech_id = ref.get("external_id", "")
                url = ref.get("url", "")
                break
        results.append({
            "technique_id": tech_id,
            "name": tech.get("name", ""),
            "description": tech.get("description", "")[:150],
            "url": url,
            "platforms": tech.get("x_mitre_platforms", []),
        })

    return {
        "group_name": target_group.get("name", ""),
        "group_id": target_group.get("external_references", [{}])[0].get("external_id", ""),
        "technique_count": len(results),
        "techniques": results,
    }


def generate_navigator_layer(group_data, color="#ff6666"):
    """Generate ATT&CK Navigator layer JSON from group technique data."""
    techniques = []
    for tech in group_data.get("techniques", []):
        tid = tech.get("technique_id", "")
        if not tid:
            continue
        techniques.append({
            "techniqueID": tid,
            "score": 1,
            "color": color,
            "comment": tech.get("name", ""),
            "enabled": True,
        })

    layer = {
        "name": f"{group_data.get('group_name', 'Unknown')} TTPs",
        "versions": {
            "attack": "15",
            "navigator": "5.0",
            "layer": "4.5",
        },
        "domain": "enterprise-attack",
        "description": f"Techniques used by {group_data.get('group_name', '')} "
                        f"({group_data.get('group_id', '')})",
        "filters": {"platforms": ["Windows", "Linux", "macOS", "Cloud"]},
        "sorting": 0,
        "layout": {"layout": "side", "showID": True, "showName": True},
        "hideDisabled": False,
        "techniques": techniques,
        "gradient": {
            "colors": ["#ffffff", color],
            "minValue": 0,
            "maxValue": 1,
        },
        "legendItems": [
            {"label": f"{group_data.get('group_name', '')} techniques", "color": color},
        ],
        "metadata": [],
        "showTacticRowBackground": True,
        "tacticRowBackground": "#dddddd",
    }
    return layer


def compare_groups(client, group_names):
    """Compare techniques across multiple threat groups."""
    all_techniques = {}
    group_techs = {}
    for name in group_names:
        data = get_group_techniques(client, name)
        if "error" in data:
            continue
        techs = {t["technique_id"] for t in data.get("techniques", [])}
        group_techs[data.get("group_name", name)] = techs
        for t in data.get("techniques", []):
            all_techniques[t["technique_id"]] = t["name"]

    shared = set.intersection(*group_techs.values()) if group_techs else set()
    unique_per_group = {}
    for name, techs in group_techs.items():
        unique_per_group[name] = techs - set.union(*(v for k, v in group_techs.items() if k != name))

    return {
        "groups_compared": list(group_techs.keys()),
        "total_unique_techniques": len(set.union(*group_techs.values())) if group_techs else 0,
        "shared_techniques": [{"id": t, "name": all_techniques.get(t, "")} for t in shared],
        "shared_count": len(shared),
        "unique_per_group": {k: len(v) for k, v in unique_per_group.items()},
    }


def run_audit(args):
    """Execute threat actor TTP mapping audit."""
    print(f"\n{'='*60}")
    print(f"  MITRE ATT&CK THREAT ACTOR TTP ANALYSIS")
    print(f"  Generated: {datetime.utcnow().isoformat()} UTC")
    print(f"{'='*60}\n")

    client = get_attack_client()
    report = {}

    if args.list_groups:
        groups = list_threat_groups(client)
        report["groups"] = groups
        print(f"--- THREAT GROUPS ({len(groups)}) ---")
        for g in groups[:30]:
            print(f"  {g['id']}: {g['name']}")

    if args.group:
        data = get_group_techniques(client, args.group)
        report["group_techniques"] = data
        print(f"--- {data.get('group_name','')} ({data.get('group_id','')}) ---")
        print(f"  Techniques: {data.get('technique_count', 0)}")
        for t in data.get("techniques", [])[:20]:
            print(f"  {t['technique_id']}: {t['name']}")

        if args.layer_output:
            layer = generate_navigator_layer(data)
            with open(args.layer_output, "w") as f:
                json.dump(layer, f, indent=2)
            report["layer_file"] = args.layer_output
            print(f"\n  Navigator layer saved to {args.layer_output}")

    if args.compare:
        comparison = compare_groups(client, args.compare)
        report["comparison"] = comparison
        print(f"\n--- GROUP COMPARISON ---")
        print(f"  Groups: {comparison['groups_compared']}")
        print(f"  Total unique techniques: {comparison['total_unique_techniques']}")
        print(f"  Shared: {comparison['shared_count']}")
        for t in comparison["shared_techniques"][:10]:
            print(f"    {t['id']}: {t['name']}")

    return report


def main():
    parser = argparse.ArgumentParser(description="MITRE ATT&CK TTP Mapping Agent")
    parser.add_argument("--group", help="Threat group name to analyze (e.g., APT29)")
    parser.add_argument("--list-groups", action="store_true", help="List all ATT&CK groups")
    parser.add_argument("--compare", nargs="+", help="Compare multiple groups")
    parser.add_argument("--layer-output", help="Save Navigator layer JSON to file")
    parser.add_argument("--output", help="Save report to JSON file")
    args = parser.parse_args()

    report = run_audit(args)
    if args.output:
        with open(args.output, "w") as f:
            json.dump(report, f, indent=2, default=str)
        print(f"\n[+] Report saved to {args.output}")


if __name__ == "__main__":
    main()
```

