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
4 changes: 2 additions & 2 deletions .github/workflows/release-and-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ jobs:
id: release
uses: python-semantic-release/python-semantic-release@v10.5.3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
github_token: ${{ secrets.ATTACK_AUTOBOT_RELEASE_TOKEN }}
# NOTE: git_committer_name and git_committer_email are optional
# We omit them because, if set, they must be associated with the provided token
# and we don't really care to have a specific committer for automated releases.
Expand All @@ -92,7 +92,7 @@ jobs:
uses: python-semantic-release/publish-action@v10.5.3
if: steps.release.outputs.released == 'true'
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
github_token: ${{ secrets.ATTACK_AUTOBOT_RELEASE_TOKEN }}
tag: ${{ steps.release.outputs.tag }}

- name: Upload distribution artifacts
Expand Down
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 @@ def get_citations(objects):
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:
return []
return filter(lambda x: x == x, dataframe["mapping description"].tolist())


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 @@ def relationshipsToDf(src, relatedType=None):
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 @@ def _get_relationship_citations(object_dataframe, relationship_df):
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