예제 #1
0
 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)
예제 #2
0
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
예제 #3
0
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)
예제 #4
0
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
예제 #5
0
    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()
예제 #7
0
    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!!')
예제 #9
0
 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)
예제 #10
0
    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
예제 #11
0
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)
예제 #12
0
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
    ]
예제 #13
0
    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()
예제 #14
0
파일: afactory.py 프로젝트: mitre/CICAT
    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
예제 #15
0
    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()
예제 #16
0
    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
예제 #17
0
    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()
예제 #18
0
    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)
예제 #20
0
        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,
예제 #21
0
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()
예제 #22
0
 def __init__(self):
     self.__c = attack_client()
     self.__intrusion_set = {}
예제 #23
0
 def __init__(self):
     self._client = attack_client()
예제 #24
0
 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
예제 #25
0
# 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',
예제 #26
0
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
예제 #27
0
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
예제 #28
0
 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())