mirror of
https://github.com/mandiant/capa.git
synced 2025-12-12 15:49:46 -08:00
linter: refactor att&ck linter and add attck json data
This commit is contained in:
@@ -1,27 +1,23 @@
|
||||
import json
|
||||
from os.path import dirname
|
||||
|
||||
import requests
|
||||
from stix2 import Filter, MemoryStore, AttackPattern
|
||||
|
||||
|
||||
class StixExtractor:
|
||||
def __init__(self, url):
|
||||
stix_json = requests.get(url).json()
|
||||
url = ""
|
||||
|
||||
def __init__(self):
|
||||
if self.url == "":
|
||||
raise ValueError(f"URL not specified in class {self.__class__.__name__}")
|
||||
|
||||
stix_json = requests.get(self.url).json()
|
||||
self._memory_store = MemoryStore(stix_data=stix_json["objects"])
|
||||
|
||||
def _process_attack_patterns(self, attack_patterns):
|
||||
return attack_patterns
|
||||
|
||||
def _get_attack_patterns(self):
|
||||
results = self._memory_store.query([Filter("type", "=", "attack-pattern")])
|
||||
return self._process_attack_patterns(results)
|
||||
|
||||
|
||||
class AttckStixExtractor(StixExtractor):
|
||||
def _process_attack_patterns(self, stix_objects) -> list[AttackPattern]:
|
||||
@staticmethod
|
||||
def _remove_deprecated_objetcs(stix_objects) -> list[AttackPattern]:
|
||||
"""Remove any revoked or deprecated objects from queries made to the data source"""
|
||||
# Note we use .get() because the property may not be present in the JSON data. The default is False
|
||||
# if the property is not set.
|
||||
return list(
|
||||
filter(
|
||||
lambda x: x.get("x_mitre_deprecated", False) is False and x.get("revoked", False) is False,
|
||||
@@ -29,50 +25,59 @@ class AttckStixExtractor(StixExtractor):
|
||||
)
|
||||
)
|
||||
|
||||
def _get_tactics(self):
|
||||
# Only one matrix -> enterprise att&ck
|
||||
matrix = self._memory_store.query(
|
||||
[
|
||||
Filter("type", "=", "x-mitre-matrix"),
|
||||
]
|
||||
)[0]
|
||||
return [self._memory_store.get(tid) for tid in matrix["tactic_refs"]]
|
||||
|
||||
def _get_techniques_from_tactic(self, tactic):
|
||||
return self._memory_store.query(
|
||||
[
|
||||
Filter("type", "=", "attack-pattern"),
|
||||
Filter("kill_chain_phases.phase_name", "=", tactic["x_mitre_shortname"]),
|
||||
Filter(
|
||||
"kill_chain_phases.kill_chain_name", "=", "mitre-attack"
|
||||
), # kill chain name for enterprise att&ck
|
||||
]
|
||||
class AttckStixExtractor(StixExtractor):
|
||||
url = "https://raw.githubusercontent.com/mitre-attack/attack-stix-data/master/enterprise-attack/enterprise-attack.json"
|
||||
|
||||
def _get_tactics(self) -> list[dict]:
|
||||
# Only one matrix for enterprise att&ck framework
|
||||
matrix = self._remove_deprecated_objetcs(
|
||||
self._memory_store.query(
|
||||
[
|
||||
Filter("type", "=", "x-mitre-matrix"),
|
||||
]
|
||||
)
|
||||
)[0]
|
||||
return list(map(self._memory_store.get, matrix["tactic_refs"]))
|
||||
|
||||
def _get_techniques_from_tactic(self, tactic: str) -> list[AttackPattern]:
|
||||
techniques = self._remove_deprecated_objetcs(
|
||||
self._memory_store.query(
|
||||
[
|
||||
Filter("type", "=", "attack-pattern"),
|
||||
Filter("kill_chain_phases.phase_name", "=", tactic),
|
||||
Filter( # kill chain name for enterprise att&ck
|
||||
"kill_chain_phases.kill_chain_name", "=", "mitre-attack"
|
||||
),
|
||||
]
|
||||
)
|
||||
)
|
||||
return techniques
|
||||
|
||||
def _get_parent_technique_from_subtechnique(self, subtechnique):
|
||||
tid = subtechnique["external_references"][0]["external_id"].split(".")[0]
|
||||
return self._memory_store.query(
|
||||
[
|
||||
Filter("type", "=", "attack-pattern"),
|
||||
Filter("external_references.external_id", "=", tid),
|
||||
]
|
||||
def _get_parent_technique_from_subtechnique(self, technique: AttackPattern) -> AttackPattern:
|
||||
sub_id = technique["external_references"][0]["external_id"].split(".")[0]
|
||||
parent_technique = self._remove_deprecated_objetcs(
|
||||
self._memory_store.query(
|
||||
[
|
||||
Filter("type", "=", "attack-pattern"),
|
||||
Filter("external_references.external_id", "=", sub_id),
|
||||
]
|
||||
)
|
||||
)[0]
|
||||
return parent_technique
|
||||
|
||||
def run(self):
|
||||
result = {}
|
||||
tactics = self._get_tactics()
|
||||
for tactic in tactics:
|
||||
result[tactic["name"]] = {}
|
||||
techniques = self._get_techniques_from_tactic(tactic)
|
||||
for technique in techniques:
|
||||
def run(self) -> dict[str, dict[str, str]]:
|
||||
data: dict[str, dict[str, str]] = {}
|
||||
for tactic in self._get_tactics():
|
||||
data[tactic["name"]] = {}
|
||||
for technique in self._get_techniques_from_tactic(tactic["x_mitre_shortname"]):
|
||||
tid = technique["external_references"][0]["external_id"]
|
||||
if technique["x_mitre_is_subtechnique"]:
|
||||
parent_technique = self._get_parent_technique_from_subtechnique(technique)
|
||||
result[tactic["name"]][f"{parent_technique['name']}::{technique['name']}"] = technique[
|
||||
"external_references"
|
||||
][0]["external_id"]
|
||||
data[tactic["name"]][tid] = f"{parent_technique['name']}::{technique['name']}"
|
||||
else:
|
||||
result[tactic["name"]][technique["name"]] = technique["external_references"][0]["external_id"]
|
||||
return result
|
||||
data[tactic["name"]][tid] = technique["name"]
|
||||
return data
|
||||
|
||||
|
||||
class MbcStixExtractor(StixExtractor):
|
||||
@@ -80,11 +85,9 @@ class MbcStixExtractor(StixExtractor):
|
||||
|
||||
|
||||
def main():
|
||||
s = AttckStixExtractor(
|
||||
"https://raw.githubusercontent.com/mitre-attack/attack-stix-data/master/enterprise-attack/enterprise-attack.json"
|
||||
)
|
||||
s = AttckStixExtractor()
|
||||
r = s.run()
|
||||
with open("attack.json", "w") as jf:
|
||||
with open(f"{dirname(__file__)}/linter-data.json", "w") as jf:
|
||||
json.dump(r, jf, indent=2)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user