Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions mitreattack/attackToExcel/stixToDf.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,13 @@
return pd.DataFrame(citations).drop_duplicates(subset="reference", ignore_index=True)


def _get_mapping_descriptions(dataframe):
"""Return non-null mapping descriptions from a relationship dataframe."""
if "mapping description" not in dataframe.columns:

Check failure on line 77 in mitreattack/attackToExcel/stixToDf.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Define a constant instead of duplicating this literal "mapping description" 3 times.

See more on https://sonarcloud.io/project/issues?id=mitre-attack_mitreattack-python&issues=AZ2Zx4uO3GBU49Wbj57y&open=AZ2Zx4uO3GBU49Wbj57y&pullRequest=226
return []
return filter(lambda x: x == x, dataframe["mapping description"].tolist())

Check warning on line 79 in mitreattack/attackToExcel/stixToDf.py

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Correct one of the identical sub-expressions on both sides of operator "==".

See more on https://sonarcloud.io/project/issues?id=mitre-attack_mitreattack-python&issues=AZ2Zx4uO3GBU49Wbj57z&open=AZ2Zx4uO3GBU49Wbj57z&pullRequest=226


def parseBaseStix(sdo):
"""Given an SDO, return a dict of field names:values that are common across all ATT&CK STIX types."""
row = {}
Expand Down Expand Up @@ -1311,8 +1318,7 @@
usedCitations = set()
for dfname in dataframes:
df = dataframes[dfname]
# filter out missing descriptions which for whatever reason
for description in filter(lambda x: x == x, df["mapping description"].tolist()):
for description in _get_mapping_descriptions(df):
# in pandas don't equal themselves
[usedCitations.add(x) for x in re.findall(r"\(Citation: (.*?)\)", description)]

Expand Down Expand Up @@ -1342,7 +1348,7 @@
mask = relationship_df[z].values == y
filtered = relationship_df[z].loc[mask]
temp = set()
for description in filter(lambda x: x == x, filtered["mapping description"].tolist()):
for description in _get_mapping_descriptions(filtered):
[temp.add(x) for x in re.findall(r"\(Citation: (.*?)\)", description)]
subset.append(",".join([f"(Citation: {z})" for z in temp]))
if not new_citations:
Expand Down
74 changes: 74 additions & 0 deletions tests/test_stix_to_df.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,77 @@ def test_techniques_to_df_handles_missing_tactic_definition(monkeypatch):

assert len(techniques_df) == 1
assert techniques_df.iloc[0]["tactics"] == "Defense Evasion"


def test_techniques_to_df_handles_targets_relationship_without_description():
"""TechniquesToDf should tolerate asset targets relationships with no description."""
mem_store = stix2.MemoryStore(
stix_data=[
{
"type": "attack-pattern",
"spec_version": "2.1",
"id": "attack-pattern--11111111-1111-4111-8111-111111111111",
"created": "2020-01-01T00:00:00.000Z",
"modified": "2020-01-01T00:00:00.000Z",
"name": "Test Technique",
"description": "Test technique",
"kill_chain_phases": [
{
"kill_chain_name": "mitre-attack",
"phase_name": "inhibit-response-function",
}
],
"external_references": [
{
"source_name": "mitre-attack",
"external_id": "T0001",
"url": "https://example.com/technique",
}
],
"x_mitre_domains": ["ics-attack"],
},
{
"type": "x-mitre-asset",
"spec_version": "2.1",
"id": "x-mitre-asset--22222222-2222-4222-8222-222222222222",
"created": "2020-01-01T00:00:00.000Z",
"modified": "2020-01-01T00:00:00.000Z",
"name": "Test Asset",
"description": "Test asset",
"external_references": [
{
"source_name": "mitre-attack",
"external_id": "A0001",
"url": "https://example.com/asset",
}
],
"x_mitre_domains": ["ics-attack"],
},
{
"type": "relationship",
"spec_version": "2.1",
"id": "relationship--33333333-3333-4333-8333-333333333333",
"created": "2020-01-01T00:00:00.000Z",
"modified": "2020-01-01T00:00:00.000Z",
"relationship_type": "targets",
"source_ref": "attack-pattern--11111111-1111-4111-8111-111111111111",
"target_ref": "x-mitre-asset--22222222-2222-4222-8222-222222222222",
"external_references": [
{
"source_name": "Test Reference",
"description": "Test citation",
"url": "https://example.com/reference",
}
],
},
]
)

dataframes = stixToDf.techniquesToDf(mem_store, "ics-attack")

assert "targeted assets" in dataframes
assert len(dataframes["targeted assets"]) == 1
assert dataframes["targeted assets"].iloc[0]["target name"] == "Test Asset"
assert dataframes["techniques"].iloc[0]["relationship citations"] == ""
if "citations" in dataframes:
assert dataframes["citations"].empty
Loading