def set_indicator(self, indicator: stix2.Indicator): if indicator: self.indicator = indicator self.buffer.name = f'Opinions: {self.indicator.name} ({self.indicator.id})' self.buffer.clearBuffer() opinions = self.store.query([ stix2.Filter('type', '=', 'opinion'), stix2.Filter('object_refs', 'contains', self.indicator.id), ]) opinions.sort(key=lambda opinion: opinion.created, reverse=True) for opinion in opinions: opinion: stix2.Opinion creator = self.store.creator_of(opinion) opinion_text = opinion.opinion.replace('-', ' ').title() evaluated_at = opinion.created.strftime('%Y-%m-%d %H:%M:%S') indent = ' ' explanation = indent + '\n'.join( indent + line for line in opinion.explanation.splitlines()) self.buffer.buffer([ f'# {creator.name} ({creator.identity_class.title()})', f' Opinion on effectiveness: {opinion_text}', f' Evaluated at: {evaluated_at}', f'', f'{explanation}', f'', f'', ], scroll_end=False)
def test_environment_functions(): env = stix2.Environment(stix2.ObjectFactory(created_by_ref=IDENTITY_ID), stix2.MemoryStore()) # Create a STIX object ind = env.create(stix2.Indicator, id=INDICATOR_ID, **INDICATOR_KWARGS) assert ind.created_by_ref == IDENTITY_ID # Add objects to datastore ind2 = ind.new_version(labels=['benign']) env.add([ind, ind2]) # Get both versions of the object resp = env.all_versions(INDICATOR_ID) assert len(resp) == 1 # should be 2, but MemoryStore only keeps 1 version of objects # Get just the most recent version of the object resp = env.get(INDICATOR_ID) assert resp['labels'][0] == 'benign' # Search on something other than id query = [stix2.Filter('type', '=', 'vulnerability')] resp = env.query(query) assert len(resp) == 0 # See different results after adding filters to the environment env.add_filters([stix2.Filter('type', '=', 'indicator'), stix2.Filter('created_by_ref', '=', IDENTITY_ID)]) env.add_filter(stix2.Filter('labels', '=', 'benign')) # should be 'malicious-activity' resp = env.get(INDICATOR_ID) assert resp['labels'][0] == 'benign' # should be 'malicious-activity'
def get_examples(tech_stix_id, src): """Given a technique stix id, return a list of examples with their external references. """ examples = [] ext_refs = [] for r in src.relationships(tech_stix_id, 'uses', target_only=True): if stix2.utils.get_type_from_id( r.source_ref) in ['intrusion-set', 'tool', 'malware']: curr_refs = None attack_id = None if 'external_references' in r: curr_refs = r.external_references example = src.query([ stix2.Filter('id', '=', r.source_ref), stix2.Filter('revoked', '=', False) ])[0] attack_id = buildhelpers.get_attack_id(example) examples.append({ 'name': example.name, 'id': attack_id, 'description': r.description, 'ext_refs': curr_refs }) examples = sorted(examples, key=lambda k: k['name'].lower()) for example in examples: if example['ext_refs']: ext_refs += example['ext_refs'] return examples, ext_refs
def get_all_techniques(src, source_name): """Filters data source by attack-pattern which extracts all ATT&CK Techniques""" filters = [ stix2.Filter("type", "=", "attack-pattern"), stix2.Filter("external_references.source_name", "=", source_name), ] results = src.query(filters) return remove_deprecated(results)
def filter_by_type_and_id(src, object_type, object_id, source_name): """Filters data source by id and type""" filters = [ stix2.Filter("type", "=", object_type), stix2.Filter("id", "=", object_id), stix2.Filter("external_references.source_name", "=", source_name), ] results = src.query(filters) return remove_deprecated(results)
def get_techniques(src): """Reads the STIX and returns a list of all techniques in the STIX""" tech_list = src.query([ stix2.Filter('type', '=', 'attack-pattern'), stix2.Filter('revoked', '=', False) ]) tech_list = sorted(tech_list, key=lambda k: k['name'].lower()) return tech_list
def test_optimize_types6(): filters = [ stix2.Filter("type", "!=", "foo"), stix2.Filter("type", "!=", "bar"), ] auth_types, auth_ids = _find_search_optimizations(filters) assert auth_types.auth_type == AuthSet.BLACK assert auth_types.values == {"foo", "bar"} assert auth_ids.auth_type == AuthSet.BLACK assert len(auth_ids.values) == 0
def test_optimize_types4(): filters = [ stix2.Filter("type", "in", ["A", "B", "C"]), stix2.Filter("type", "in", ["D", "E", "F"]), ] auth_types, auth_ids = _find_search_optimizations(filters) assert auth_types.auth_type == AuthSet.WHITE assert len(auth_types.values) == 0 assert auth_ids.auth_type == AuthSet.BLACK assert len(auth_ids.values) == 0
def test_optimize_types_ids3(): filters = [ stix2.Filter("type", "in", ["foo", "bar"]), stix2.Filter("id", "!=", "bar--00000000-0000-0000-0000-000000000000"), ] auth_types, auth_ids = _find_search_optimizations(filters) assert auth_types.auth_type == AuthSet.WHITE assert auth_types.values == {"foo", "bar"} assert auth_ids.auth_type == AuthSet.BLACK assert auth_ids.values == {"bar--00000000-0000-0000-0000-000000000000"}
def get_mitigation_list(src): """Reads the STIX and returns a list of all mitigations in the STIX""" mitigations = src.query([ stix2.Filter('type', '=', 'course-of-action'), stix2.Filter('revoked', '=', False) ]) #Filter out deprecated objects for mitigation pages mitigations = [x for x in mitigations if not hasattr(x, 'x_mitre_deprecated') or x.x_mitre_deprecated == False] return sorted(mitigations, key=lambda k: k['name'].lower())
def test_optimize_types_ids2(): filters = [ stix2.Filter("type", "=", "foo"), stix2.Filter("id", "=", "bar--00000000-0000-0000-0000-000000000000"), ] auth_types, auth_ids = _find_search_optimizations(filters) assert auth_types.auth_type == AuthSet.WHITE assert len(auth_types.values) == 0 assert auth_ids.auth_type == AuthSet.WHITE assert len(auth_ids.values) == 0
def retrieve_collection(collection_id): # Initialize dictionary to hold Enterprise ATT&CK content attack = {} # Establish TAXII2 Collection instance for Enterprise ATT&CK collection collection_url = STIX_URL + "/stix/collections/{}/".format(collection_id) collection = taxii2client.Collection(collection_url, verify=False) #,proxies=PROXIES) # Supply the collection to TAXIICollection tc_source = stix2.TAXIICollectionSource(collection) # Create filters to retrieve content from Enterprise ATT&CK based on type taxii_filters = { "techniques": stix2.Filter("type", "=", "attack-pattern"), "mitigations": stix2.Filter("type", "=", "course-of-action"), "groups": stix2.Filter("type", "=", "intrusion-set"), "malware": stix2.Filter("type", "=", "malware"), "tools": stix2.Filter("type", "=", "tool"), "relationships": stix2.Filter("type", "=", "relationship"), "tactic": stix2.Filter("type", "=", "x-mitre-tactic"), "matrix": stix2.Filter("type", "=", "x-mitre-matrix") } # Retrieve all Enterprise ATT&CK content for field in taxii_filters: attack[field] = tc_source.query(taxii_filters[field]) return attack
def test_filesystem_source_backward_compatible(fs_source): # this specific object is outside an "ID" directory; make sure we can get # it. modified = datetime.datetime(2018, 11, 16, 22, 54, 20, 390000, pytz.utc) results = fs_source.query([ stix2.Filter("type", "=", "malware"), stix2.Filter("id", "=", "malware--6b616fc1-1505-48e3-8b2c-0d19337bff38"), stix2.Filter("modified", "=", modified), ]) assert len(results) == 1 result = results[0] assert result.type == "malware" assert result.id == "malware--6b616fc1-1505-48e3-8b2c-0d19337bff38" assert result.modified == modified assert result.malware_types == ["version four"]
def test_get_object_found(collection): tc_source = stix2.TAXIICollectionSource(collection) result = tc_source.query([ stix2.Filter("id", "=", "indicator--00000000-0000-4000-8000-000000000001"), ]) assert result
def filter_for_term_relationships(src, relationship_type, object_id, target=True): """Filters data source by type, relationship_type and source or target""" filters = [ stix2.Filter("type", "=", "relationship"), stix2.Filter("relationship_type", "=", relationship_type), ] if target: filters.append(stix2.Filter("target_ref", "=", object_id)) else: filters.append(stix2.Filter("source_ref", "=", object_id)) results = src.query(filters) return remove_deprecated(results)
def main(): collection = Collection( "http://127.0.0.1:5000/trustgroup1/collections/52892447-4d7e-4f70-b94d-d7f22742ff63/", user="******", password="******") # instantiate TAXII data source taxii = stix2.TAXIICollectionSource(collection) # get (url watch indicator) indicator_fw = taxii.get("indicator--d81f86b9-975b-bc0b-775e-810c5ad45a4f") print("\n\n-------Queried for Indicator - got:") print(indicator_fw.serialize(indent=4)) # all versions (url watch indicator - currently two) indicator_fw_versions = taxii.all_versions( "indicator--d81f86b9-975b-bc0b-775e-810c5ad45a4f") print("\n\n------Queried for indicator (all_versions()) - got:") for indicator in indicator_fw_versions: print(indicator.serialize(indent=4)) # add TAXII filter (ie filter should be passed to TAXII) query_filter = stix2.Filter("type", "in", "malware") # query() - but with filter attached. There are no malware objects in this collection malwares = taxii.query(query=query_filter) print( "\n\n\n--------Queried for Malware string (with above filter attached) - got:" ) for malware in malwares: print(malware.serialize(indent=4)) if not malwares: print(malwares)
def generate(): """parse the STIX on MITRE/CTI and return a layer dict with techniques with randomized scores""" # import the STIX data from MITRE/CTI stix = requests.get("https://raw.githubusercontent.com/mitre/cti/master/enterprise-attack/enterprise-attack.json").json() ms = stix2.MemoryStore(stix_data=stix["objects"]) # get all techniques in STIX techniques = ms.query([ stix2.Filter("type", "=", "attack-pattern") ]) # parse techniques into layer format techniques_list = [] for technique in techniques: # skip deprecated and revoked if ("x_mitre_deprecated" in technique and technique["x_mitre_deprecated"]) or ("revoked" in technique and technique["revoked"]): continue techniqueID = technique["external_references"][0]["external_id"] # get the attackID techniques_list.append({ "techniqueID": techniqueID, "score": random.randint(1,100) # random score }) # return the techniques in a layer dict return { "name": "heatmap example", "version": "3.0", "sorting": 3, # descending order of score "description": "An example layer where all techniques have a randomized score", "domain": "mitre-enterprise", "techniques": techniques_list, }
def get_technique_id_domain_map(ms): """Create map from technique_id to domain""" tech_list = {} for domain in site_config.domains: curr_list = ms[domain].query([ stix2.Filter('type', '=', 'attack-pattern'), stix2.Filter('revoked', '=', False) ]) for val in curr_list: technique_id = buildhelpers.get_attack_id(val) if technique_id: tech_list[technique_id] = domain return tech_list
def main(): collection = Collection( "http://127.0.0.1:5000/trustgroup1/collections/91a7b528-80eb-42ed-a74d-c6fbd5a26116/", user="******", password="******", ) # instantiate TAXII data source taxii = stix2.TAXIICollectionSource(collection) # get (url watch indicator) indicator_fw = taxii.get("indicator--6770298f-0fd8-471a-ab8c-1c658a46574e") print("\n\n-------Queried for Indicator - got:") print(indicator_fw.serialize(indent=4)) # all versions (url watch indicator - currently two) indicator_fw_versions = taxii.all_versions( "indicator--6770298f-0fd8-471a-ab8c-1c658a46574e") print("\n\n------Queried for indicator (all_versions()) - got:") for indicator in indicator_fw_versions: print(indicator.serialize(indent=4)) # add TAXII filter (ie filter should be passed to TAXII) query_filter = stix2.Filter("type", "in", "malware") # query() - but with filter attached. There are no malware objects in this collection malwares = taxii.query(query=query_filter) print( "\n\n\n--------Queried for Malware string (with above filter attached) - got:" ) for malware in malwares: print(malware.serialize(indent=4)) if not malwares: print(malwares)
def test_filesystem_source_sco(fs_source): results = fs_source.query([stix2.Filter("type", "=", "directory")]) assert len(results) == 1 result = results[0] assert result["type"] == "directory" assert result["id"] == "directory--572827aa-e0cd-44fd-afd5-a717a7585f39" assert result["path"] == "/performance/Democrat.gif"
def get_matrices(src): """Reads the STIX and returns a list of all matrices in the STIX""" matrices = src.query([ stix2.Filter('type', '=', 'x-mitre-matrix'), ]) return matrices
def test_filesystem_source_query_single(fs_source): # query2 is_2 = fs_source.query([stix2.Filter("external_references.external_id", '=', "T1027")]) assert len(is_2) == 1 is_2 = is_2[0] assert is_2.id == "attack-pattern--b3d682b6-98f2-4fb0-aa3b-b4df007ca70a" assert is_2.type == "attack-pattern"
def get_revoked_by(stix_id, src): """Given a stix_id, return an object that revokes it, if no object is found, return None """ relations = src.relationships(stix_id, 'revoked-by', source_only=True) revoked_by = src.query([ stix2.Filter('id', 'in', [r.target_ref for r in relations]), stix2.Filter('revoked', '=', False) ]) if revoked_by: try: revoked_by = revoked_by[0] except IndexError: print("Malformed STIX content detected") print(stix_id) revoked_by = revoked_by[0] return revoked_by
def get_tactic_list(src, matrix_id=None): """Reads the STIX and returns a list of all tactics in the STIX""" tactics = [] matrix = src.query([ stix2.Filter('type', '=', 'x-mitre-matrix'), ]) if matrix_id: for curr_matrix in matrix: if curr_matrix['id'] == matrix_id: for tactic_id in curr_matrix['tactic_refs']: tactics.append(src.query([stix2.Filter('id', '=', tactic_id)])[0]) else: for i in range(len(matrix)): for tactic_id in matrix[i]['tactic_refs']: tactics.append(src.query([stix2.Filter('id', '=', tactic_id)])[0]) return tactics
def test_filesystem_store_query(fs_store): # query() tools = fs_store.query([stix2.Filter("tool_types", "in", "tool")]) assert len(tools) == 2 assert "tool--242f3da3-4425-4d11-8f5c-b842886da966" in [ tool.id for tool in tools ] assert "tool--03342581-f790-4f03-ba41-e82e67392e23" in [ tool.id for tool in tools ]
def test_filesystem_store_query_single_filter(fs_store): query = stix2.Filter("labels", "in", "tool") tools = fs_store.query(query) assert len(tools) == 2 assert "tool--242f3da3-4425-4d11-8f5c-b842886da966" in [ tool.id for tool in tools ] assert "tool--03342581-f790-4f03-ba41-e82e67392e23" in [ tool.id for tool in tools ]
def test_filesystem_source_query_multiple(fs_source): # query intrusion_sets = fs_source.query([stix2.Filter("type", '=', "intrusion-set")]) assert len(intrusion_sets) == 2 assert "intrusion-set--a653431d-6a5e-4600-8ad3-609b5af57064" in [is_.id for is_ in intrusion_sets] assert "intrusion-set--f3bdec95-3d62-42d9-a840-29630f6cdc1a" in [is_.id for is_ in intrusion_sets] is_1 = [is_ for is_ in intrusion_sets if is_.id == "intrusion-set--f3bdec95-3d62-42d9-a840-29630f6cdc1a"][0] assert "DragonOK" in is_1.aliases assert len(is_1.external_references) == 4
def test_optimize_types_ids6(): filters = [ stix2.Filter("id", "=", "A--00000000-0000-0000-0000-000000000000"), ] auth_types, auth_ids = _find_search_optimizations(filters) assert auth_types.auth_type == AuthSet.WHITE assert auth_types.values == {"A"} assert auth_ids.auth_type == AuthSet.WHITE assert auth_ids.values == {"A--00000000-0000-0000-0000-000000000000"}
def test_optimize_types_ids5(): filters = [ stix2.Filter("type", "in", ["A", "B", "C"]), stix2.Filter("type", "!=", "C"), stix2.Filter( "id", "in", [ "B--00000000-0000-0000-0000-000000000000", "C--00000000-0000-0000-0000-000000000000", "D--00000000-0000-0000-0000-000000000000", ], ), stix2.Filter("id", "!=", "D--00000000-0000-0000-0000-000000000000"), ] auth_types, auth_ids = _find_search_optimizations(filters) assert auth_types.auth_type == AuthSet.WHITE assert auth_types.values == {"B"} assert auth_ids.auth_type == AuthSet.WHITE assert auth_ids.values == {"B--00000000-0000-0000-0000-000000000000"}
def __init__(self, name=None, parentApp=None, framed=None, help=None, color='FORMDEFAULT', widget_list=None, cycle_widgets=False, *args, store: stix2.MemoryStore, **keywords): indicators = store.query([stix2.Filter('type', '=', 'indicator')]) self._provided_indicators = tuple(indicators) super().__init__(name, parentApp, framed, help, color, widget_list, cycle_widgets, *args, **keywords)