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 anin_top25flag (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-89with 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-787rank-1 outranks a count-1CWE-502rank-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.