Lab 03 — Weakness Taxonomy Mapper (CWE / CAPEC / ATT&CK)

Frameworks: MITRE CWE, CAPEC, ATT&CK, CWE Top 25, OWASP categories. Kind: taxonomy. Builds toward: Phase 08 (variants), Phase 09 (ATT&CK coverage).

The problem (and the threat model)

A scanner hands you thousands of instances with tool-specific labels ("SQLi in /login (sqlmap)," "tainted query in OrdersController"). Reasoning at that altitude is hopeless and brittle — it's the "searching only for known indicators" failure. The "threat" is drowning in instances and missing the class: ten findings that are all one CWE-89 SQL-injection class, and a whole ATT&CK technique you have no detection for. The control is a taxonomy mapper: normalize raw findings to MITRE CWE classes, enrich each with its CAPEC attack pattern, ATT&CK technique, OWASP category, and CWE Top 25 rank, then diff the implicated ATT&CK techniques against your detections to find coverage gaps.

raw finding ─► CWE class (the weakness, language-agnostic)
                 ├─ CAPEC  (the attack pattern)
                 ├─ ATT&CK (the adversary technique → what a detection targets)
                 ├─ OWASP  (the web risk category)
                 └─ Top 25 (how dangerous the class is)

The same CWE-89 describes a Rails find_by_sql, a Python f-string in cursor.execute, a Java Statement, and a Node template literal — which is exactly why the class is the useful unit.

What you build (lab.py)

  • normalize(findings) — collapse raw findings to {cwe: instance_count} (dedup by class).
  • enrich(cwe) — the CAPEC / ATT&CK / OWASP / Top-25 context for a class, with an in_top25 flag (UNKNOWN for unmapped CWEs).
  • class_priority(findings) — rank classes by prevalence, then Top-25 danger, then id.
  • attack_coverage(findings, detections){implicated, covered, gaps} ATT&CK techniques: the detection-engineering view (Phase 09's pyramid of pain — invest at the technique level).

Attack / failure cases the tests cover

  • Dedup by class: three SQLi instances collapse to one CWE-89 with count 3.
  • Enrichment: known class → CAPEC/ATT&CK/OWASP/Top-25; unknown CWE → UNKNOWN, in_top25=False.
  • Prioritization: ranked by instance count, then Top-25 rank (a count-1 CWE-787 rank-1 outranks a count-1 CWE-502 rank-16), unranked classes last.
  • Coverage gap: an implicated ATT&CK technique with no detection is reported as a gap.
  • Unmapped CWE implicates no technique (no phantom coverage).
  • Determinism: stable, sorted outputs.

Run

pip install -r requirements.txt
LAB_MODULE=solution pytest -q
pytest -q

Hardening / extensions

  • Load the real CWE→ATT&CK mappings from MITRE / the Center for Threat-Informed Defense (CTID), rather than the small teaching table here.
  • Add CWE abstraction relationships (Pillar → Class → Base → Variant) so a Variant rolls up to its Base class for variant analysis (Phase 08 Chapter 10).
  • Join with Lab 01: enrich each finding with its CVE/CVSS/EPSS/KEV and produce a single class-and-risk-ranked remediation plan.
  • Emit an ATT&CK Navigator layer JSON for the coverage gaps (Phase 09).

Interview / resume

"Built a weakness-taxonomy mapper that normalizes noisy scanner output to MITRE CWE classes and maps each to its CAPEC pattern, ATT&CK technique, OWASP category, and CWE Top 25 rank — then computes ATT&CK detection-coverage gaps. The point: reason about weakness classes and adversary behaviors, not instances and indicators, so fixes and detections survive the attacker changing one byte."

Limitations: a representative taxonomy slice with defensible (not authoritative) CWE→ATT&CK assignments; single-technique-per-class; no CWE abstraction hierarchy.