Skip to content

Commit

Permalink
Merge branch 'master' into feature/assets
Browse files Browse the repository at this point in the history
  • Loading branch information
clemiller committed Aug 10, 2023
2 parents 2e75633 + ed3f579 commit fb82858
Show file tree
Hide file tree
Showing 8 changed files with 47 additions and 17 deletions.
22 changes: 16 additions & 6 deletions mitreattack/attackToExcel/stixToDf.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ def parseBaseStix(sdo):
if sdo["external_references"][0]["source_name"] in MITRE_ATTACK_ID_SOURCE_NAMES:
row["ID"] = sdo["external_references"][0]["external_id"]
url = sdo["external_references"][0]["url"]
if "id" in sdo: # required for workbench collection import
if "id" in sdo: # required for workbench collection import
row["STIX ID"] = sdo["id"]
if "name" in sdo:
row["name"] = sdo["name"]
Expand All @@ -124,7 +124,7 @@ def parseBaseStix(sdo):
row["created"] = format_date(sdo["created"])
if "modified" in sdo:
row["last modified"] = format_date(sdo["modified"])
if "x_mitre_domains" in sdo: # required for workbench collection import
if "x_mitre_domains" in sdo: # required for workbench collection import
row["domain"] = ",".join(sdo["x_mitre_domains"])
if "x_mitre_version" in sdo:
row["version"] = sdo["x_mitre_version"]
Expand Down Expand Up @@ -171,7 +171,7 @@ def techniquesToDf(src, domain):

# sub-technique properties
if "kill_chain_phases" not in technique:
attack_id = technique['external_references'][0]['external_id']
attack_id = technique["external_references"][0]["external_id"]
logger.error(f"Skipping {attack_id} [{technique['id']}] because it does't have kill chain phases")
continue
tactic_shortnames = []
Expand Down Expand Up @@ -929,7 +929,7 @@ def add_side(label, sdo):
row[f"{label} name"] = sdo["name"]
if "id" in sdo:
# "source ref" or "target ref"
row[f"{label} ref"] = sdo ["id"]
row[f"{label} ref"] = sdo["id"]
# "source type" or "target type"
row[f"{label} type"] = stixToAttackTerm[sdo["type"]]

Expand All @@ -948,10 +948,20 @@ def add_side(label, sdo):

citations = get_citations(relationships)
relationships = pd.DataFrame(relationship_rows).sort_values(
["mapping type", "source type", "target type", "source name", "target name", "source ref", "target ref", "created", "last modified"]
[
"mapping type",
"source type",
"target type",
"source name",
"target name",
"source ref",
"target ref",
"created",
"last modified",
]
)

# return all relationships and citations
# return all relationships and citations
if not relatedType:
dataframes = {
"relationships": relationships,
Expand Down
12 changes: 12 additions & 0 deletions mitreattack/stix20/MitreAttackData.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ def __init__(self, stix_filepath: str):
if not isinstance(stix_filepath, str):
raise TypeError(f"Argument stix_filepath must be of type str, not {type(stix_filepath)}")

self.stix_filepath = stix_filepath

self.src = MemoryStore()
self.src.load_from_file(stix_filepath)

Expand Down Expand Up @@ -321,6 +323,9 @@ def get_objects_by_type(self, stix_type: str, remove_revoked_deprecated=False) -
if remove_revoked_deprecated:
objects = self.remove_revoked_deprecated(objects)

if not objects:
return []

# since ATT&CK has custom objects, we need to reconstruct the query results
return [StixObjectFactory(o) for o in objects]

Expand Down Expand Up @@ -539,6 +544,10 @@ def get_object_by_stix_id(self, stix_id: str) -> object:
the STIX Domain Object specified by the STIX ID
"""
object = self.src.get(stix_id)

if not object:
raise ValueError(f"{stix_id} not found in {self.stix_filepath}")

return StixObjectFactory(object)

def get_object_by_attack_id(self, attack_id: str, stix_type: str) -> object:
Expand Down Expand Up @@ -605,6 +614,9 @@ def get_objects_by_name(self, name: str, stix_type: str) -> list:
filter = [Filter("type", "=", stix_type), Filter("name", "=", name)]
objects = self.src.query(filter)

if not objects:
return []

# since ATT&CK has custom objects, we need to reconstruct the query results
return [StixObjectFactory(o) for o in objects]

Expand Down
6 changes: 4 additions & 2 deletions mitreattack/stix20/custom_attack_objects.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,10 @@ def StixObjectFactory(data: dict) -> object:
"x-mitre-data-component": DataComponent,
}

if "type" in data and data["type"] in stix_type_to_custom_class:
return stix_type_to_custom_class[data["type"]](**data, allow_custom=True)
stix_type = data.get("type")

if data and stix_type in stix_type_to_custom_class:
return stix_type_to_custom_class[stix_type](**data, allow_custom=True)
return data


Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ profile = "black"
line-length = 120
ignore = [
"E501", # line-too-long
"D100", # Missing docstring in public module
"D105", # undocumented-magic-method
]
# On top of the defaults (E, F), enable pydocstyle (D) and isort (I).
Expand Down
4 changes: 2 additions & 2 deletions requirements-dev.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
black>=22.3.0
check-wheel-contents
colour>=0.1.5
deepdiff==6.3.0
deepdiff==6.3.1
drawsvg==2.1.1
flake8>=5.0.4
flake8-docstrings>=1.6.0
Expand All @@ -18,7 +18,7 @@ pytest-cov>=3.0.0
python-dateutil
Pillow>=7.1.2
requests>=2.21.0
rich==13.4.1
rich==13.5.2
ruff>=0.0.275
stix2>=3.0.1
stix2-elevator>=4.0.1
Expand Down
3 changes: 1 addition & 2 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@
from pathlib import Path

import pytest
from stix2 import MemoryStore
from loguru import logger

from resources.testing_data import example_layer_v3_all, example_layer_v43_dict
from stix2 import MemoryStore

from mitreattack.download_stix import download_domains
from mitreattack.navlayers import Layer
Expand Down
9 changes: 7 additions & 2 deletions tests/test_collections.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import json
import os

from resources.testing_data import collection, index

Expand All @@ -21,10 +22,14 @@ def test_collection_to_index():

def test_stix_to_collection():
"""Test converting stix bundle file to a collection"""
with open("resources/ics-bundle.json", "r") as fio:
dir = os.path.dirname(__file__)
ics_bundle_collection = os.path.join(dir, "resources", "ics-bundle.json")
enterprise_bundle_collection = os.path.join(dir, "resources", "enterprise-bundle.json")

with open(ics_bundle_collection, "r") as fio:
v20 = json.load(fio)

with open("resources/enterprise-bundle.json", "r") as fio:
with open(enterprise_bundle_collection, "r") as fio:
v21 = json.load(fio)

STIXToCollection.stix_to_collection(v20, name="v20_test", version="9.0", description="testing")
Expand Down
7 changes: 4 additions & 3 deletions tests/test_layers.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import json
import os
from pathlib import Path

import pytest
from stix2 import MemoryStore

from resources import testing_data
from stix2 import MemoryStore

from mitreattack.navlayers import (
Layer,
Expand Down Expand Up @@ -37,7 +37,8 @@ def test_depreciated_tactics_export(tmp_path: Path, memstore_enterprise_latest:
def test_colormap_export(tmp_path: Path, memstore_enterprise_latest: MemoryStore):
"""Test exporting a layer with a gradiant of scores"""
lay = Layer()
lay.from_file("resources/heatmap_example.json")
dir = os.path.dirname(__file__)
lay.from_file(os.path.join(dir, "resources", "heatmap_example.json"))
xlsx_output = tmp_path / "layer.xlsx"
svg_output = tmp_path / "layer.svg"

Expand Down

0 comments on commit fb82858

Please sign in to comment.