Skip to content

Commit 439dd63

Browse files
authored
fix: handle missing relationship descriptions in attackToExcel (#226)
1 parent c480e3e commit 439dd63

2 files changed

Lines changed: 83 additions & 3 deletions

File tree

mitreattack/attackToExcel/stixToDf.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,13 @@ def get_citations(objects):
7272
return pd.DataFrame(citations).drop_duplicates(subset="reference", ignore_index=True)
7373

7474

75+
def _get_mapping_descriptions(dataframe):
76+
"""Return non-null mapping descriptions from a relationship dataframe."""
77+
if "mapping description" not in dataframe.columns:
78+
return []
79+
return filter(lambda x: x == x, dataframe["mapping description"].tolist())
80+
81+
7582
def parseBaseStix(sdo):
7683
"""Given an SDO, return a dict of field names:values that are common across all ATT&CK STIX types."""
7784
row = {}
@@ -1311,8 +1318,7 @@ def relationshipsToDf(src, relatedType=None):
13111318
usedCitations = set()
13121319
for dfname in dataframes:
13131320
df = dataframes[dfname]
1314-
# filter out missing descriptions which for whatever reason
1315-
for description in filter(lambda x: x == x, df["mapping description"].tolist()):
1321+
for description in _get_mapping_descriptions(df):
13161322
# in pandas don't equal themselves
13171323
[usedCitations.add(x) for x in re.findall(r"\(Citation: (.*?)\)", description)]
13181324

@@ -1342,7 +1348,7 @@ def _get_relationship_citations(object_dataframe, relationship_df):
13421348
mask = relationship_df[z].values == y
13431349
filtered = relationship_df[z].loc[mask]
13441350
temp = set()
1345-
for description in filter(lambda x: x == x, filtered["mapping description"].tolist()):
1351+
for description in _get_mapping_descriptions(filtered):
13461352
[temp.add(x) for x in re.findall(r"\(Citation: (.*?)\)", description)]
13471353
subset.append(",".join([f"(Citation: {z})" for z in temp]))
13481354
if not new_citations:

tests/test_stix_to_df.py

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,77 @@ def test_techniques_to_df_handles_missing_tactic_definition(monkeypatch):
4343

4444
assert len(techniques_df) == 1
4545
assert techniques_df.iloc[0]["tactics"] == "Defense Evasion"
46+
47+
48+
def test_techniques_to_df_handles_targets_relationship_without_description():
49+
"""TechniquesToDf should tolerate asset targets relationships with no description."""
50+
mem_store = stix2.MemoryStore(
51+
stix_data=[
52+
{
53+
"type": "attack-pattern",
54+
"spec_version": "2.1",
55+
"id": "attack-pattern--11111111-1111-4111-8111-111111111111",
56+
"created": "2020-01-01T00:00:00.000Z",
57+
"modified": "2020-01-01T00:00:00.000Z",
58+
"name": "Test Technique",
59+
"description": "Test technique",
60+
"kill_chain_phases": [
61+
{
62+
"kill_chain_name": "mitre-attack",
63+
"phase_name": "inhibit-response-function",
64+
}
65+
],
66+
"external_references": [
67+
{
68+
"source_name": "mitre-attack",
69+
"external_id": "T0001",
70+
"url": "https://example.com/technique",
71+
}
72+
],
73+
"x_mitre_domains": ["ics-attack"],
74+
},
75+
{
76+
"type": "x-mitre-asset",
77+
"spec_version": "2.1",
78+
"id": "x-mitre-asset--22222222-2222-4222-8222-222222222222",
79+
"created": "2020-01-01T00:00:00.000Z",
80+
"modified": "2020-01-01T00:00:00.000Z",
81+
"name": "Test Asset",
82+
"description": "Test asset",
83+
"external_references": [
84+
{
85+
"source_name": "mitre-attack",
86+
"external_id": "A0001",
87+
"url": "https://example.com/asset",
88+
}
89+
],
90+
"x_mitre_domains": ["ics-attack"],
91+
},
92+
{
93+
"type": "relationship",
94+
"spec_version": "2.1",
95+
"id": "relationship--33333333-3333-4333-8333-333333333333",
96+
"created": "2020-01-01T00:00:00.000Z",
97+
"modified": "2020-01-01T00:00:00.000Z",
98+
"relationship_type": "targets",
99+
"source_ref": "attack-pattern--11111111-1111-4111-8111-111111111111",
100+
"target_ref": "x-mitre-asset--22222222-2222-4222-8222-222222222222",
101+
"external_references": [
102+
{
103+
"source_name": "Test Reference",
104+
"description": "Test citation",
105+
"url": "https://example.com/reference",
106+
}
107+
],
108+
},
109+
]
110+
)
111+
112+
dataframes = stixToDf.techniquesToDf(mem_store, "ics-attack")
113+
114+
assert "targeted assets" in dataframes
115+
assert len(dataframes["targeted assets"]) == 1
116+
assert dataframes["targeted assets"].iloc[0]["target name"] == "Test Asset"
117+
assert dataframes["techniques"].iloc[0]["relationship citations"] == ""
118+
if "citations" in dataframes:
119+
assert dataframes["citations"].empty

0 commit comments

Comments
 (0)