| 13 | @dataclass |
| 14 | class ATTACKTag: |
| 15 | technique_id: str # e.g. "T1190" |
| 16 | sub_technique: str # e.g. "" or ".001" |
| 17 | tactic: str # e.g. "Initial Access" |
| 18 | tactic_id: str # e.g. "TA0001" |
| 19 | name: str # e.g. "Exploit Public-Facing Application" |
| 20 | description: str = "" |
| 21 | mitigations: list[str] = None # M-IDs |
| 22 | |
| 23 | def __post_init__(self): |
| 24 | if self.mitigations is None: |
| 25 | self.mitigations = [] |
| 26 | |
| 27 | @property |
| 28 | def full_id(self) -> str: |
| 29 | return f"{self.technique_id}{self.sub_technique}" |
| 30 | |
| 31 | def to_dict(self) -> dict: |
| 32 | return { |
| 33 | "technique_id": self.full_id, |
| 34 | "tactic": self.tactic, |
| 35 | "tactic_id": self.tactic_id, |
| 36 | "name": self.name, |
| 37 | "description": self.description, |
| 38 | "url": f"https://attack.mitre.org/techniques/{self.technique_id.replace('.', '/')}", |
| 39 | } |
| 40 | |
| 41 | |
| 42 | # ── Tactic reference ────────────────────────────────────────────────────────── |
| 43 | |