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_add_get_remove_filter(collection): ds = stix2.TAXIICollectionSource(collection) # First 3 filters are valid, remaining properties are erroneous in some way valid_filters = [ Filter('type', '=', 'malware'), Filter('id', '!=', 'stix object id'), Filter('labels', 'in', ["heartbleed", "malicious-activity"]), ] assert len(ds.filters) == 0 ds.filters.add(valid_filters[0]) assert len(ds.filters) == 1 # Addin the same filter again will have no effect since `filters` acts # like a set ds.filters.add(valid_filters[0]) assert len(ds.filters) == 1 ds.filters.add(valid_filters[1]) assert len(ds.filters) == 2 ds.filters.add(valid_filters[2]) assert len(ds.filters) == 3 assert valid_filters == [f for f in ds.filters] # remove ds.filters.remove(valid_filters[0]) assert len(ds.filters) == 2 ds.filters.add(valid_filters)
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 test_can_read_error(collection_no_rw_access): """create a TAXIICOllectionSource with a taxii2client.Collection instance that does not have read access, check ValueError exception is raised""" with pytest.raises(DataSourceError) as excinfo: stix2.TAXIICollectionSource(collection_no_rw_access) assert "Collection object provided does not have read access" in str(excinfo.value)
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 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 build_taxii_source(collection_name): """Downloads latest Enterprise or Mobile ATT&CK content from MITRE TAXII Server.""" # Establish TAXII2 Collection instance for Enterprise ATT&CK collection collection_map = { "enterprise_attack": "95ecc380-afe9-11e4-9b6c-751b66dd541e", "mobile_attack": "2f669986-b40b-4423-b720-4396ca6a462b" } collection_url = "https://cti-taxii.mitre.org/stix/collections/" + collection_map[ collection_name] + "/" collection = taxii2client.Collection(collection_url) taxii_ds = stix2.TAXIICollectionSource(collection) # Create an in-memory source (to prevent multiple web requests) return stix2.MemorySource(stix_data=taxii_ds.query())
def test_parse_taxii_filters(collection): query = [ Filter("added_after", "=", "2016-02-01T00:00:01.000Z"), Filter("id", "=", "taxii stix object ID"), Filter("type", "=", "taxii stix object ID"), Filter("version", "=", "first"), Filter("created_by_ref", "=", "Bane"), ] taxii_filters_expected = [ Filter("added_after", "=", "2016-02-01T00:00:01.000Z"), Filter("id", "=", "taxii stix object ID"), Filter("type", "=", "taxii stix object ID"), Filter("version", "=", "first"), ] ds = stix2.TAXIICollectionSource(collection) taxii_filters = ds._parse_taxii_filters(query) assert taxii_filters == taxii_filters_expected
def test_get_404(): """a TAXIICollectionSource.get() call that receives an HTTP 404 response code from the taxii2client should be be returned as None. TAXII spec states that a TAXII server can return a 404 for nonexistent resources or lack of access. Decided that None is acceptable reponse to imply that state of the TAXII endpoint. """ class TAXIICollection404(): can_read = True def get_object(self, id, version=None): resp = Response() resp.status_code = 404 resp.raise_for_status() ds = stix2.TAXIICollectionSource(TAXIICollection404()) # this will raise 404 from mock TAXII Client but TAXIICollectionStore # should handle gracefully and return None stix_obj = ds.get("indicator--1") assert stix_obj is None
def test_get_stix2_object(collection): tc_sink = stix2.TAXIICollectionSource(collection) objects = tc_sink.get("indicator--00000000-0000-4000-8000-000000000001") assert objects
def test_get_object_not_found(collection): tc_source = stix2.TAXIICollectionSource(collection) result = tc_source.get("indicator--00000000-0000-4000-8000-000000000005") assert result is None
def test_ds_taxii(collection): ds = stix2.TAXIICollectionSource(collection) assert ds.collection is not None
def customQuery(self, query, instance, reconnect=True): mydf = None status = "" str_err = "" out_res_df = pd.DataFrame() inst = self.instances[instance] qlist = self.formatQuery(query) qfilter = self.retQueryFilter(qlist) try: if self.opts['taxii_group_collections'][0] == 1: searcher = stix2.CompositeDataSource() searcher.add_data_sources([ stix2.TAXIICollectionSource(c) for c in inst['taxii_collections'] ]) tres = searcher.query(qfilter) for r in tres: try: tdf = pd.json_normalize(json.loads(r.serialize())) if len(tdf) > 0: out_res_df = pd.concat([out_res_df, tdf], ignore_index=True) except Exceptions as e: if self.debug: print("Error grouped: %s" % e) else: for c in inst['taxii_collections']: c_title = c.title c_id = c.id searcher = stix2.CompositeDataSource() searcher.add_data_sources([stix2.TAXIICollectionSource(c)]) tres = searcher.query(qfilter) for r in tres: try: tdf = pd.json_normalize(json.loads(r.serialize())) if len(tdf) > 0: tdf['collection_name'] = c_title tdf['collection_id'] = c_id out_res_df = pd.concat([out_res_df, tdf], ignore_index=True) except Exception as e: if self.debug: print("Error ungrouped: %s" % e) if len(out_res_df) == 0: mydf = None str_err = "Success - No Results" elif len(out_res_df) > 0: mydf = out_res_df str_err = "Success" except Exception as e: mydf = None str_err = str(e) if str_err.find("Success") >= 0: pass elif str_err.find("Session is not logged in") >= 0: # Need to fix this # Try to rerun query if reconnect == True: self.disconnect(instance) self.connect(instance) m, s = self.customQuery(query, instance, False) mydf = m status = s else: mydf = None status = "Failure - Session not logged in and reconnect failed" else: status = "Failure - query_error: " + str_err return mydf, status