Skip to content

enhancement: ship MITRE ATT&CK technique→tactic map #324

Description

@Daren9m

Gap

data/frameworks/mitre-attack.json declares the 14 ATT&CK tactics (scoring.tactics: TA0001 Initial Access, TA0002 Execution, …). But ATT&CK controlIds are technique IDs (T1078, T1078.001) which do not encode the tactic — a technique→tactic lookup is required to group findings by tactic.

Today this map is missing from CheckID. M365-Assess maintains a partial copy at src/M365-Assess/controls/mitre-technique-map.json (~100 entries), but data/registry.json references 152 unique parent techniques and 477 unique technique IDs. So even the downstream copy is incomplete, and any other consumer (Az-Assess, future projects) has to either reinvent the map or live without tactic grouping.

This is a schema-independent fix — it doesn't require the spike (#317) to land. The technique→tactic map is data, not taxonomy structure.

Deliverables

1. Data file: data/mitre-technique-map.json

{
  "$schema": "../mitre-technique-map.schema.json",
  "version": "ATT&CK v15.1",
  "generatedAt": "2026-04-27",
  "source": "https://github.com/mitre/cti enterprise-attack.json",
  "map": {
    "T1078":      ["TA0001", "TA0003", "TA0004", "TA0005"],
    "T1078.001":  ["TA0001", "TA0003", "TA0004", "TA0005"],
    "T1190":      ["TA0001"],
    ...
  }
}

Notes on shape:

  • Many-to-many: techniques can map to multiple tactics (T1078 "Valid Accounts" is in 4 tactics). Values must be arrays.
  • Coverage: at minimum all 152 parent techniques + 477 sub-techniques referenced in data/registry.json. Better: the full ATT&CK Enterprise matrix (~600+ techniques) so registry growth doesn't hit gaps.
  • Versioned: capture the ATT&CK release the map was generated from, so consumers can detect drift.

2. Schema: data/mitre-technique-map.schema.json

JSON-Schema mirroring the frameworks.schema.json pattern, validating shape and tactic-code enum (TA0001–TA0043).

3. Generator: scripts/Build-MitreTechniqueMap.py

Pulls the latest ATT&CK STIX bundle from https://github.com/mitre/cti (or its CDN), extracts attack-pattern objects, builds the technique_id → [tactic_id] map. Wired into the existing scripts/ pipeline alongside Build-CisM365Crosswalk.py etc. Output is deterministic so diffs are reviewable.

4. Registry validation

Pester test confirms every mitre-attack controlId in data/registry.json resolves to at least one tactic via the map. Fails CI if registry references a technique not in the map.

Migration of M365-Assess's downstream copy

Once shipped here:

  1. M365-Assess imports/syncs data/mitre-technique-map.json (mirroring how it already syncs data/frameworks/*.json).
  2. M365-Assess deletes src/M365-Assess/controls/mitre-technique-map.json (the partial downstream copy) in a follow-up PR.
  3. The M365-Assess Export-FrameworkCatalog.ps1 reads from the synced location.
  4. M365-Assess's React FrameworkQuilt (PR #843) gains a attack-tactic-lookup extractor that uses this map to render the tactic breakdown row.

Acceptance criteria

  • data/mitre-technique-map.json covers all 152 parent + 477 sub-technique IDs in current data/registry.json
  • data/mitre-technique-map.schema.json validates shape; CI gate fails on schema violation
  • scripts/Build-MitreTechniqueMap.py regenerates deterministically from upstream STIX
  • Pester test confirms registry coverage (no orphan techniques)
  • data/frameworks/mitre-attack.json references the map file (TBD by spike spike: multi-axis taxonomy schema for frameworks #317 whether via axes[].extract.lookup or a sibling lookupTable field)
  • README / docs/architecture.md updated to mention the map in the data inventory

Notes

  • displayOrder of tactics in mitre-attack.json already reflects kill-chain order (Reconnaissance → Resource Development → … → Impact). The map should preserve that ordering when consumers iterate.
  • ATT&CK ICS and Mobile matrices are out of scope — Enterprise only.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestupstreamIntegration with upstream data sources (SecFrame)

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions