def __init__(self): self.mitre = attack_client() self.attack_cti_techniques = self.mitre.get_enterprise_techniques() self.attack_cti_techniques = self.mitre.remove_revoked(self.attack_cti_techniques) self.attack_cti_techniques = self.remove_deprecated(self.attack_cti_techniques) self.attack_cti_software = self.mitre.get_software() self.attack_cti_software = self.remove_deprecated(self.attack_cti_software)
def load_attack_data(data_type): """ Load the cached ATT&CK data from disk, if not expired (data file on disk is older then EXPIRE_TIME seconds). :param data_type: the desired data type, see DATATYPE_XX constants. :return: MITRE ATT&CK data object """ if os.path.exists("cache/" + data_type): with open("cache/" + data_type, 'rb') as f: cached = pickle.load(f) write_time = cached[1] if not (dt.now() - write_time).total_seconds() >= EXPIRE_TIME: return cached[0] from attackcti import attack_client mitre = attack_client() json_data = None if data_type == DATATYPE_TECH_BY_GROUP: json_data = mitre.get_techniques_used_by_group() elif data_type == DATATYPE_ALL_TECH: json_data = mitre.get_all_techniques() elif data_type == DATATYPE_ALL_GROUPS: json_data = mitre.get_all_groups() elif data_type == DATATYPE_ALL_SOFTWARE: json_data = mitre.get_all_software() elif data_type == DATATYPE_TECH_BY_SOFTWARE: json_data = mitre.get_techniques_used_by_software() elif data_type == DATATYPE_SOFTWARE_BY_GROUP: json_data = mitre.get_software_used_by_group() save_attack_data(json_data, "cache/" + data_type) return json_data
def generate_mitre_lookup(OUTPUT_PATH): csv_mitre_rows = [["mitre_id", "technique", "tactics", "groups"]] lift = attack_client() all_enterprise = lift.get_enterprise(stix_format=False) enterprise_relationships = lift.get_enterprise_relationships() enterprise_groups = lift.get_enterprise_groups() for technique in all_enterprise['techniques']: apt_groups = [] for relationship in enterprise_relationships: if (relationship['target_ref'] == technique['id'] ) and relationship['source_ref'].startswith('intrusion-set'): for group in enterprise_groups: if relationship['source_ref'] == group['id']: apt_groups.append(group['name']) if not ('revoked' in technique): if len(apt_groups) == 0: apt_groups.append('no') csv_mitre_rows.append([ technique['technique_id'], technique['technique'], '|'.join(technique['tactic']).replace('-', ' ').title(), '|'.join(apt_groups) ]) with open(path.join(OUTPUT_PATH, 'lookups/mitre_enrichment.csv'), 'w', newline='', encoding="utf-8") as file: writer = csv.writer(file) writer.writerows(csv_mitre_rows)
def get_techniques(): lift = attack_client() all_enterprise = lift.get_enterprise(stix_format=False) data_sources_dict = {} techniques_dict = {} for technique in all_enterprise['techniques']: technique_id = technique['technique_id'] technique_name = technique['technique'] technique_obj = ATechnique(technique_id, technique_name) if 'tactic' in technique: for tactic in technique['tactic']: technique_obj.add_tactic(tactic) else: technique_obj.add_tactic(UNSPECIFIED_TACTIC) if 'data_sources' in technique: for data_source in technique['data_sources']: technique_obj.add_data_source(data_source) if data_source not in data_sources_dict: data_sources_dict[data_source] = data_source assert technique_id not in techniques_dict techniques_dict[technique_id] = technique_obj return techniques_dict, data_sources_dict
def __init__(self, ds_scores): """Pull ATT&CK data from MITRE API""" print('[*] Pulling ATT&CK data') cli = attack_client() attack = cli.get_enterprise(stix_format=False) self.techniques = cli.remove_revoked(attack['techniques']) self.ds_scores = ds_scores
def __init__(self, mapping_filename): """ Constructor of the MitreMapping class :param mapping_filename: filename reference for the Excel file which holds the datasource mapping and query mapping. """ self.mapping_filename = mapping_filename self.mitre = attack_client() self._get_all_mitre_info()
def get_attack_tactics(self): try: tactics_payload = [] client = attack_client() tactics = client.get_tactics() except: traceback.print_exc(file=sys.stdout) print("[!] Error connecting obtaining tactics from Att&ck's API !") sys.exit()
def get_attck_from_stix(matrix='enterprise'): if (matrix.lower() == 'enterprise'): # Instantiating attack_client class lift = attack_client() # Getting techniques for windows platform - enterprise matrix attck = lift.get_enterprise_techniques(stix_format=False) # Removing revoked techniques attck = lift.remove_revoked(attck) return attck else: sys.exit('ERROR: Only Enterprise available!!')
def __init__(self): try: self.mitre = attack_client() except exceptions.ConnectionError: print("[!] Cannot connect to MITRE's CTI TAXII server") quit() self.attack_cti_techniques = self.mitre.get_enterprise_techniques() self.attack_cti_techniques = self.mitre.remove_revoked(self.attack_cti_techniques) self.attack_cti_techniques = self.mitre.remove_deprecated(self.attack_cti_techniques) self.attack_cti_software = self.mitre.get_software() self.attack_cti_software = self.mitre.remove_deprecated(self.attack_cti_software)
def do(self): phrases = TextBlob(self.event_text).noun_phrases tagging = [] lift = attack_client() all_mobile = lift.get_mobile() for t in all_mobile['techniques']: for phrase in phrases: if phrase in t['name'].lower(): tagging = ((t['name'], t['description'])) return tagging
def load_cti(): LOGGER.info('[-] Initiaing ATT&CK CTI client...') client = attack_client() LOGGER.info('[-] Loading data...') enterprise_groups = client.get_enterprise_groups() enterprise_techniques = client.get_enterprise_techniques() enterprise_relationships = client.get_enterprise_relationships() LOGGER.info('[-] OK!') return EnterpriseCTI(enterprise_groups, enterprise_techniques, enterprise_relationships)
def get_mitre_data(): """ Generate tags from live TAXI service to get up-to-date data """ # Get ATT&CK information lift = attack_client() # Techniques MITRE_TECHNIQUES = [] MITRE_TECHNIQUE_NAMES = [] MITRE_PHASE_NAMES = set() MITRE_TOOLS = [] MITRE_GROUPS = [] # Techniques enterprise_techniques = lift.get_enterprise_techniques() for t in enterprise_techniques: MITRE_TECHNIQUE_NAMES.append(t['name'].lower().replace(' ', '_').replace( '-', '_')) for r in t.external_references: if 'external_id' in r: MITRE_TECHNIQUES.append(r['external_id'].lower()) if 'kill_chain_phases' in t: for kc in t['kill_chain_phases']: if 'phase_name' in kc: MITRE_PHASE_NAMES.add(kc['phase_name'].replace('-', '_')) # Tools / Malware enterprise_tools = lift.get_enterprise_tools() for t in enterprise_tools: for r in t.external_references: if 'external_id' in r: MITRE_TOOLS.append(r['external_id'].lower()) enterprise_malware = lift.get_enterprise_malware() for m in enterprise_malware: for r in m.external_references: if 'external_id' in r: MITRE_TOOLS.append(r['external_id'].lower()) # Groups enterprise_groups = lift.get_enterprise_groups() for g in enterprise_groups: for r in g.external_references: if 'external_id' in r: MITRE_GROUPS.append(r['external_id'].lower()) # Debugging print("MITRE ATT&CK LIST LENGTHS: %d %d %d %d %d" % (len(MITRE_TECHNIQUES), len(MITRE_TECHNIQUE_NAMES), len(list(MITRE_PHASE_NAMES)), len(MITRE_GROUPS), len(MITRE_TOOLS))) # Combine all IDs to a big tag list return [ "attack." + item for item in MITRE_TECHNIQUES + MITRE_TECHNIQUE_NAMES + list(MITRE_PHASE_NAMES) + MITRE_GROUPS + MITRE_TOOLS ]
def __init__(self): try: self.mitre = attack_client() except (exceptions.ConnectionError, datastore.DataSourceError): print("[!] Cannot connect to MITRE's CTI TAXII server") quit() self.attack_cti_techniques_enterprise = self.mitre.get_enterprise_techniques( ) self.attack_cti_techniques_ics = self.mitre.get_ics_techniques() self.data_source_dict_enterprise = self._create_data_source_dict( MATRIX_ENTERPRISE) self.attack_cti_software = self.mitre.get_software()
def __init__(self, loadOPT, fname, trace): if trace: print('ATT&CK factory constructed..') self.trace = trace self.fname = fname self.loadFromSpreadsheet = False if loadOPT == 'JSON': if self.trace: print('Opening local json dataset') with open( os.path.normpath( os.path.join(os.path.dirname(__file__), '..', 'data', 'ATK', 'attack.json'))) as data_file: self.all_attack = json.load(data_file) elif loadOPT == 'STIX': if self.trace: print('Connecting to STIX/TAXII service') try: from attackcti import attack_client self.lift = attack_client() self.all_attack = self.lift.get_all_stix_objects() except: print('Cannot connect to STIX/TAXII service: ') print( 'Most likely cause: application cannot reach the Internet') raise elif loadOPT == 'SPREAD': if self.trace: print('Loading data from spreadsheet', self.fname) self.loadFromSpreadsheet = True else: if self.trace: print('WARNING! ATTACK factory: Unsupported load option:', loadOPT) self.ttps = [] self.groups = None #self.all_attack['groups'] self.malwares = None #self.all_attack['malware'] self.mitigations = None #self.all_attack['mitigations'] self.techniques = None #self.all_attack['techniques'] self.tools = None #self.all_attack['tools'] self.relationships = None #self.all_attack['relationships'] self.groupprofiles = None
def get_attack_datasources(self): try: datasource_payload = [] client = attack_client() datasources = client.get_data_sources() for datasource in datasources: dict = {'name': datasource} datasource_payload.append(dict) return datasource_payload except: traceback.print_exc(file=sys.stdout) print( "[!] Error connecting obtaining datasources from Att&ck's API !" ) sys.exit()
def get_attack_techniques(self): try: print("[*] Obtaining ATT&CK's techniques...") client = attack_client() all_enterprise = client.get_enterprise() techniques = [] for technique in all_enterprise['techniques']: techniques.append(json.loads(technique.serialize())) print("[!] Done!") return techniques except: traceback.print_exc(file=sys.stdout) print("[!] Error connecting to Att&ck's API !") return
def get_attack_tactics(self): try: tactics_payload = [] client = attack_client() enterprise_tactics = client.get_enterprise() tactics = [ tactic['name'].lower().replace(" ", "-") for tactic in enterprise_tactics['tactics'] ] for tactic in tactics: tactics_payload.append({"name": tactic}) return tactics_payload except: traceback.print_exc(file=sys.stdout) print("[!] Error connecting obtaining tactics from Att&ck's API !") sys.exit()
def get_attack_techniques(self): # Deprecated, keeping just in case try: print("[*] Obtaining ATT&CK's techniques...") client = attack_client() all_enterprise = client.get_enterprise() techniques = [] for technique in all_enterprise['techniques']: tech = json.loads(technique.serialize()) # avoid bringing in the revoked techniques if not 'revoked' in tech.keys(): techniques.append(tech) print("[!] Done!") return techniques except: traceback.print_exc(file=sys.stdout) print("[!] Error connecting to Att&ck's API !") return
def main(): logging.basicConfig(level=logging.INFO, format='%(asctime)s %(levelname)-8s %(message)s', datefmt='%Y-%m-%d %H:%M:%S') parser = argparse.ArgumentParser(description='Generate a jupyter notebook for each technique in the MITRE ATT&CK framework', add_help=True) parser.add_argument('--output-dir', '-o', default='notebooks', help='Directory to output notebooks in') parser.add_argument('--no-sigma', action='store_true', help='Do not include mapping to sigma rules') args = parser.parse_args() lift = attack_client() logging.info('Fetching MITRE ATT&CK enterprise techniques') all_techniques = lift.get_enterprise_techniques(stix_format=False) all_techniques_no_revoked = lift.remove_revoked(all_techniques) logging.info(f'{len(all_techniques_no_revoked)} techniques found') sigma_clone_url = 'https://github.com/Neo23x0/sigma.git' sigma_git_dir = 'sigma_clone' if args.no_sigma: mitre_sigma_mapping = {} else: logging.info(f'Cloning sigma repository using {sigma_clone_url}') subprocess.run(f'git clone {sigma_clone_url} {sigma_git_dir}', shell=True) logging.info('Creating mapping of sigma rules to mitre techniques') mitre_sigma_mapping = create_mitre_sigma_mapping(sigma_git_dir) logging.info(f'Cleaning up cloned directory {sigma_git_dir}') shutil.rmtree(Path(sigma_git_dir)) # Load markdown template template_loader = jinja2.FileSystemLoader(searchpath="./") template_env = jinja2.Environment(loader=template_loader) ads_template = template_env.get_template('ads_template.md') generate_notebooks(all_techniques_no_revoked, ads_template, args.output_dir, mitre_sigma_mapping)
cachefilename = params[1].lower() try: with open( os.path.normpath( os.path.join(os.path.dirname(__file__), '..', 'data', 'ATK', cachefilename))) as data_file: attack_data = json.load(data_file) print('ATT&CK cache loaded.') except FileNotFoundError: print('ATT&CK cache', cachefilename, 'not found. Refreshing from STIX/TAXII service.') ac = attack_client() attack_data = ac.get_all_stix_objects() if not (attack_data): print('No ATT&CK data retrieved from STIX//TAXII service.') exit try: with open((os.path.normpath( os.path.join(os.path.dirname(__file__), '..', 'data', 'ATK', cachefilename))), mode="w+") as outfile: json.dump(attack_data, outfile) print('ATT&CK cache', cachefilename,
from attackcti import attack_client import pandas as pd from pandas import json_normalize # Do not truncate Pandas output pd.set_option('display.max_colwidth', None) import requests import yaml ### Getting ATT&CK enterprise techniques for Windows platform * Getting all Windows techniques lift = attack_client() windowsTechniques = lift.get_techniques_by_platform('Windows',stix_format=False) windowsTechniques = lift.remove_revoked(windowsTechniques) windowsTechniques = json_normalize(windowsTechniques) windowsTechniques = windowsTechniques[['tactic','technique_id','technique','data_sources']] windowsTechniques.head() * Splitting data_sources windowsTechniques = windowsTechniques['data_sources'].apply(pd.Series)\ .merge(windowsTechniques, left_index = True, right_index = True)\ .drop(["data_sources"], axis = 1)\ .melt(id_vars = ['tactic','technique_id','technique'], value_name = "data_sources")\ .drop("variable", axis = 1)\ .dropna(subset=['data_sources']) windowsTechniques.head()
def __init__(self): self.__c = attack_client() self.__intrusion_set = {}
def __init__(self): self._client = attack_client()
def __init__(self): self.attack_client = attack_client() # We use only Enterprise ATT&CK matrix. self.attack_client.COMPOSITE_DS = self.attack_client.TC_ENTERPRISE_SOURCE
# Author: Jose Rodriguez (@Cyb3rPandaH) # License: GPL-3.0 # Reference: # https://github.com/Cyb3rWard0g/ATTACK-Python-Client # https://stackoverflow.com/questions/27263805/pandas-when-cell-contents-are-lists-create-a-row-for-each-element-in-the-list/27266225?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa # https://stackoverflow.com/questions/19913659/pandas-conditional-creation-of-a-series-dataframe-column?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa # http://pandas.pydata.org/pandas-docs/version/0.22/generated/pandas.Series.str.contains.html # https://chrisalbon.com/python/data_wrangling/pandas_dropping_column_and_rows/ from pandas import * from pandas.io.json import json_normalize from pandas import Series,DataFrame from attackcti import attack_client mitre = attack_client() db = mitre.get_all_attack() # Removes '\n' inside of a list element of the 'system_requirements' property db_fixed = db for sr in db_fixed: if 'system_requirements' in sr: if sr['system_requirements']: for idx, item in enumerate(sr['system_requirements']): sr['system_requirements'][idx] = sr['system_requirements'][idx].replace('\n',' ') df = json_normalize(db_fixed) df = df[[ 'matrix','tactic','technique','technique_id','technique_description', 'mitigation','mitigation_description','group','group_id','group_aliases',
def load_attack_data(data_type): """ By default the ATT&CK data is loaded from the online TAXII server or from the local cache directory. The local cache directory will be used if the file is not expired (data file on disk is older then EXPIRE_TIME seconds). When the local_stix_path option is given, the ATT&CK data will be loaded from the given path of a local STIX repository. :param data_type: the desired data type, see DATATYPE_XX constants. :return: MITRE ATT&CK data object (STIX or custom schema) """ from attackcti import attack_client if local_stix_path is not None: if local_stix_path is not None and os.path.isdir(os.path.join(local_stix_path, 'enterprise-attack')) \ and os.path.isdir(os.path.join(local_stix_path, 'ics-attack')) \ and os.path.isdir(os.path.join(local_stix_path, 'mobile-attack')): mitre = attack_client(local_path=local_stix_path) else: print('[!] Not a valid local STIX path: ' + local_stix_path) quit() else: if os.path.exists("cache/" + data_type): with open("cache/" + data_type, 'rb') as f: cached = pickle.load(f) write_time = cached[1] if not (dt.now() - write_time).total_seconds() >= EXPIRE_TIME: # the first item in the list contains the ATT&CK data return cached[0] try: mitre = attack_client() except (exceptions.ConnectionError, datastore.DataSourceError): print("[!] Cannot connect to MITRE's CTI TAXII server") quit() attack_data = None if data_type == DATA_TYPE_STIX_ALL_RELATIONSHIPS: attack_data = mitre.get_relationships() elif data_type == DATA_TYPE_STIX_ALL_TECH_ENTERPRISE: stix_attack_data = mitre.get_enterprise_techniques() attack_data = _convert_stix_techniques_to_dict(stix_attack_data) elif data_type == DATA_TYPE_STIX_ALL_TECH_ICS: stix_attack_data = mitre.get_ics_techniques() attack_data = _convert_stix_techniques_to_dict(stix_attack_data) elif data_type == DATA_TYPE_CUSTOM_TECH_BY_GROUP: # First we need to know which technique references (STIX Object type 'attack-pattern') we have for all # groups. This results in a dict: {group_id: Gxxxx, technique_ref/attack-pattern_ref: ...} groups = load_attack_data(DATA_TYPE_STIX_ALL_GROUPS) relationships = load_attack_data(DATA_TYPE_STIX_ALL_RELATIONSHIPS) all_groups_relationships = [] for g in groups: for r in relationships: if g['id'] == r['source_ref'] and r['relationship_type'] == 'uses' and \ r['target_ref'].startswith('attack-pattern--'): # much more information on the group can be added. Only the minimal required data is now added. all_groups_relationships.append( { 'group_id': get_attack_id(g), 'name': g['name'], 'aliases': g.get('aliases', None), 'technique_ref': r['target_ref'] }) # Now we start resolving this part of the dict created above: 'technique_ref/attack-pattern_ref'. # and we add some more data to the final result. all_group_use = [] techniques = load_attack_data(DATA_TYPE_STIX_ALL_TECH) for gr in all_groups_relationships: for t in techniques: if t['id'] == gr['technique_ref']: all_group_use.append( { 'group_id': gr['group_id'], 'name': gr['name'], 'aliases': gr['aliases'], 'technique_id': get_attack_id(t), 'x_mitre_platforms': t.get('x_mitre_platforms', None), 'matrix': t['external_references'][0]['source_name'] }) attack_data = all_group_use elif data_type == DATA_TYPE_STIX_ALL_TECH: stix_attack_data = mitre.get_techniques() attack_data = _convert_stix_techniques_to_dict(stix_attack_data) elif data_type == DATA_TYPE_STIX_ALL_GROUPS: stix_attack_data = mitre.get_groups() attack_data = _convert_stix_groups_to_dict(stix_attack_data) elif data_type == DATA_TYPE_STIX_ALL_SOFTWARE: attack_data = mitre.get_software() elif data_type == DATA_TYPE_CUSTOM_TECH_BY_SOFTWARE: # First we need to know which technique references (STIX Object type 'attack-pattern') we have for all software # This results in a dict: {software_id: Sxxxx, technique_ref/attack-pattern_ref: ...} software = load_attack_data(DATA_TYPE_STIX_ALL_SOFTWARE) relationships = load_attack_data(DATA_TYPE_STIX_ALL_RELATIONSHIPS) all_software_relationships = [] for s in software: for r in relationships: if s['id'] == r['source_ref'] and r['relationship_type'] == 'uses' and \ r['target_ref'].startswith('attack-pattern--'): # much more information (e.g. description, aliases, platform) on the software can be added to the # dict if necessary. Only the minimal required data is now added. all_software_relationships.append({'software_id': get_attack_id(s), 'technique_ref': r['target_ref']}) # Now we start resolving this part of the dict created above: 'technique_ref/attack-pattern_ref' techniques = load_attack_data(DATA_TYPE_STIX_ALL_TECH) all_software_use = [] for sr in all_software_relationships: for t in techniques: if t['id'] == sr['technique_ref']: # much more information on the technique can be added to the dict. Only the minimal required data # is now added (i.e. resolving the technique ref to an actual ATT&CK ID) all_software_use.append({'software_id': sr['software_id'], 'technique_id': get_attack_id(t)}) attack_data = all_software_use elif data_type == DATA_TYPE_CUSTOM_SOFTWARE_BY_GROUP: # First we need to know which software references (STIX Object type 'malware' or 'tool') we have for all # groups. This results in a dict: {group_id: Gxxxx, software_ref/malware-tool_ref: ...} groups = load_attack_data(DATA_TYPE_STIX_ALL_GROUPS) relationships = load_attack_data(DATA_TYPE_STIX_ALL_RELATIONSHIPS) all_groups_relationships = [] for g in groups: for r in relationships: if g['id'] == r['source_ref'] and r['relationship_type'] == 'uses' and \ (r['target_ref'].startswith('tool--') or r['target_ref'].startswith('malware--')): # much more information on the group can be added. Only the minimal required data is now added. all_groups_relationships.append( { 'group_id': get_attack_id(g), 'name': g['name'], 'aliases': g.get('aliases', None), 'software_ref': r['target_ref'] }) # Now we start resolving this part of the dict created above: 'software_ref/malware-tool_ref'. # and we add some more data to the final result. all_group_use = [] software = load_attack_data(DATA_TYPE_STIX_ALL_SOFTWARE) for gr in all_groups_relationships: for s in software: if s['id'] == gr['software_ref']: all_group_use.append( { 'group_id': gr['group_id'], 'name': gr['name'], 'aliases': gr['aliases'], 'software_id': get_attack_id(s), 'x_mitre_platforms': s.get('x_mitre_platforms', None), 'matrix': s['external_references'][0]['source_name'] }) attack_data = all_group_use elif data_type == DATA_TYPE_STIX_ALL_ENTERPRISE_MITIGATIONS: attack_data = mitre.get_enterprise_mitigations() attack_data = mitre.remove_revoked_deprecated(attack_data) elif data_type == DATA_TYPE_STIX_ALL_MOBILE_MITIGATIONS: attack_data = mitre.get_mobile_mitigations() attack_data = mitre.remove_revoked_deprecated(attack_data) elif data_type == DATA_TYPE_STIX_ALL_ICS_MITIGATIONS: attack_data = mitre.get_ics_mitigations() attack_data = mitre.remove_revoked_deprecated(attack_data) # Only use cache when using online TAXII server: if local_stix_path is None: _save_attack_data(attack_data, "cache/" + data_type) return attack_data
def load_attack_data(data_type): """ Load the cached ATT&CK data from disk, if not expired (data file on disk is older then EXPIRE_TIME seconds). :param data_type: the desired data type, see DATATYPE_XX constants. :return: MITRE ATT&CK data object (STIX or custom schema) """ if os.path.exists("cache/" + data_type): with open("cache/" + data_type, 'rb') as f: cached = pickle.load(f) write_time = cached[1] if not (dt.now() - write_time).total_seconds() >= EXPIRE_TIME: # the first item in the list contains the ATT&CK data return cached[0] from attackcti import attack_client mitre = attack_client() attack_data = None if data_type == DATA_TYPE_STIX_ALL_RELATIONSHIPS: attack_data = mitre.get_all_relationships() if data_type == DATA_TYPE_STIX_ALL_TECH_ENTERPRISE: attack_data = mitre.get_all_enterprise_techniques() if data_type == DATA_TYPE_CUSTOM_TECH_BY_GROUP: # First we need to know which technique references (STIX Object type 'attack-pattern') we have for all # groups. This results in a dict: {group_id: Gxxxx, technique_ref/attack-pattern_ref: ...} groups = load_attack_data(DATA_TYPE_STIX_ALL_GROUPS) relationships = load_attack_data(DATA_TYPE_STIX_ALL_RELATIONSHIPS) all_groups_relationships = [] for g in groups: for r in relationships: if g['id'] == r['source_ref'] and r['relationship_type'] == 'uses' and \ r['target_ref'].startswith('attack-pattern--'): # much more information on the group can be added. Only the minimal required data is now added. all_groups_relationships.append({ 'group_id': get_attack_id(g), 'name': g['name'], 'aliases': try_get_key(g, 'aliases'), 'technique_ref': r['target_ref'] }) # Now we start resolving this part of the dict created above: 'technique_ref/attack-pattern_ref'. # and we add some more data to the final result. all_group_use = [] techniques = load_attack_data(DATA_TYPE_STIX_ALL_TECH) for gr in all_groups_relationships: for t in techniques: if t['id'] == gr['technique_ref']: all_group_use.append({ 'group_id': gr['group_id'], 'name': gr['name'], 'aliases': gr['aliases'], 'technique_id': get_attack_id(t), 'x_mitre_platforms': try_get_key(t, 'x_mitre_platforms'), 'matrix': t['external_references'][0]['source_name'] }) attack_data = all_group_use elif data_type == DATA_TYPE_STIX_ALL_TECH: attack_data = mitre.get_all_techniques() elif data_type == DATA_TYPE_STIX_ALL_GROUPS: attack_data = mitre.get_all_groups() elif data_type == DATA_TYPE_STIX_ALL_SOFTWARE: attack_data = mitre.get_all_software() elif data_type == DATA_TYPE_CUSTOM_TECH_BY_SOFTWARE: # First we need to know which technique references (STIX Object type 'attack-pattern') we have for all software # This results in a dict: {software_id: Sxxxx, technique_ref/attack-pattern_ref: ...} software = load_attack_data(DATA_TYPE_STIX_ALL_SOFTWARE) relationships = load_attack_data(DATA_TYPE_STIX_ALL_RELATIONSHIPS) all_software_relationships = [] for s in software: for r in relationships: if s['id'] == r['source_ref'] and r['relationship_type'] == 'uses' and \ r['target_ref'].startswith('attack-pattern--'): # much more information (e.g. description, aliases, platform) on the software can be added to the # dict if necessary. Only the minimal required data is now added. all_software_relationships.append({ 'software_id': get_attack_id(s), 'technique_ref': r['target_ref'] }) # Now we start resolving this part of the dict created above: 'technique_ref/attack-pattern_ref' techniques = load_attack_data(DATA_TYPE_STIX_ALL_TECH) all_software_use = [] for sr in all_software_relationships: for t in techniques: if t['id'] == sr['technique_ref']: # much more information on the technique can be added to the dict. Only the minimal required data # is now added (i.e. resolving the technique ref to an actual ATT&CK ID) all_software_use.append({ 'software_id': sr['software_id'], 'technique_id': get_attack_id(t) }) attack_data = all_software_use elif data_type == DATA_TYPE_CUSTOM_SOFTWARE_BY_GROUP: # First we need to know which software references (STIX Object type 'malware' or 'tool') we have for all # groups. This results in a dict: {group_id: Gxxxx, software_ref/malware-tool_ref: ...} groups = load_attack_data(DATA_TYPE_STIX_ALL_GROUPS) relationships = load_attack_data(DATA_TYPE_STIX_ALL_RELATIONSHIPS) all_groups_relationships = [] for g in groups: for r in relationships: if g['id'] == r['source_ref'] and r['relationship_type'] == 'uses' and \ (r['target_ref'].startswith('tool--') or r['target_ref'].startswith('malware--')): # much more information on the group can be added. Only the minimal required data is now added. all_groups_relationships.append({ 'group_id': get_attack_id(g), 'name': g['name'], 'aliases': try_get_key(g, 'aliases'), 'software_ref': r['target_ref'] }) # Now we start resolving this part of the dict created above: 'software_ref/malware-tool_ref'. # and we add some more data to the final result. all_group_use = [] software = load_attack_data(DATA_TYPE_STIX_ALL_SOFTWARE) for gr in all_groups_relationships: for s in software: if s['id'] == gr['software_ref']: all_group_use.append({ 'group_id': gr['group_id'], 'name': gr['name'], 'aliases': gr['aliases'], 'software_id': get_attack_id(s), 'x_mitre_platforms': try_get_key(s, 'x_mitre_platforms'), 'matrix': s['external_references'][0]['source_name'] }) attack_data = all_group_use save_attack_data(attack_data, "cache/" + data_type) return attack_data
def __init__(self): self.client = attack_client() # self.R=lift.get_relationships() # self.T=lift.get_techniques() self.G = self.client.remove_revoked(self.client.get_groups())