예제 #1
0
    def __init__(self, local_path=None):
        if local_path is not None and os.path.isdir(os.path.join(local_path, ENTERPRISE_ATTCK_LOCAL_DIR)) \
                                  and os.path.isdir(os.path.join(local_path, PRE_ATTCK_LOCAL_DIR)) \
                                  and os.path.isdir(os.path.join(local_path, MOBILE_ATTCK_LOCAL_DIR)):
            self.TC_ENTERPRISE_SOURCE = FileSystemSource(
                os.path.join(local_path, ENTERPRISE_ATTCK_LOCAL_DIR))
            self.TC_PRE_SOURCE = FileSystemSource(
                os.path.join(local_path, PRE_ATTCK_LOCAL_DIR))
            self.TC_MOBILE_SOURCE = FileSystemSource(
                os.path.join(local_path, MOBILE_ATTCK_LOCAL_DIR))
        else:
            ENTERPRISE_COLLECTION = Collection(ATTCK_STIX_COLLECTIONS +
                                               ENTERPRISE_ATTCK + "/")
            PRE_COLLECTION = Collection(ATTCK_STIX_COLLECTIONS + PRE_ATTCK +
                                        "/")
            MOBILE_COLLECTION = Collection(ATTCK_STIX_COLLECTIONS +
                                           MOBILE_ATTCK + "/")

            self.TC_ENTERPRISE_SOURCE = TAXIICollectionSource(
                ENTERPRISE_COLLECTION)
            self.TC_PRE_SOURCE = TAXIICollectionSource(PRE_COLLECTION)
            self.TC_MOBILE_SOURCE = TAXIICollectionSource(MOBILE_COLLECTION)

        self.COMPOSITE_DS = CompositeDataSource()
        self.COMPOSITE_DS.add_data_sources([
            self.TC_ENTERPRISE_SOURCE, self.TC_PRE_SOURCE,
            self.TC_MOBILE_SOURCE
        ])
def load_datasource(base=CTI_BASE):
    print("Loading CTI datasources map...")
    enterprise_attack_fs = FileSystemSource(
        os.path.join(base, "enterprise-attack"))
    mobile_attack_fs = FileSystemSource(os.path.join(base, "mobile-attack"))

    composite_ds = CompositeDataSource()
    composite_ds.add_data_sources([enterprise_attack_fs, mobile_attack_fs])
    return composite_ds
예제 #3
0
    def source(self):
        """
        Returns the data source object for Att&ck data.
        """
        if self._source:
            return self._source

        self._source = CompositeDataSource()
        self._source.add_data_sources(self._api_root.collections)

        return self._source
 def connect_server(self, url=None):
     """
     Allow user to specify what url to use
     :param url:
     :return:
     """
     server_url = MITRE_TAXII_URL if url is None else url
     self.attack_server = Server(server_url, proxies=self.proxies)
     api_root = self.attack_server.api_roots[0]
     # CompositeSource to query all the collections at once
     c_sources = [
         TAXIICollectionSource(collection)
         for collection in api_root.collections
     ]
     self.composite_ds = CompositeDataSource()
     self.composite_ds.add_data_sources(c_sources)
def get_map(base=CTI_BASE):
    from stix2 import FileSystemSource, CompositeDataSource, Filter

    print("Loading CTI attack-pattern map...")
    enterprise_attack_fs = FileSystemSource(
        os.path.join(base, "enterprise-attack"))
    mobile_attack_fs = FileSystemSource(os.path.join(base, "mobile-attack"))

    composite_ds = CompositeDataSource()
    composite_ds.add_data_sources([enterprise_attack_fs, mobile_attack_fs])

    filt = Filter('type', '=', 'attack-pattern')

    attack_map = {}
    for item in composite_ds.query(filt):
        name = item['name']

        if item['revoked']:
            print(
                f"[WARN] Ignored {name.upper()}: This attack-pattern has been revoked."
            )
            continue

        categories = [x['phase_name'] for x in item['kill_chain_phases']]
        desc = item['description']
        platforms = item['x_mitre_platforms']
        attack_id = None
        for er in item['external_references']:
            if er['source_name'] in [
                    "mitre-attack", "mobile-mitre-attack",
                    "mitre-mobile-attack"
            ]:
                attack_id = er['external_id']
        if attack_id:
            attack_map[attack_id] = {
                "name": name,
                "categories": categories,
                "description": desc,
                "platforms": platforms,
                "attack_id": attack_id
            }
            print(f"\tAdding {name.upper()} as ID: {attack_id}")
        else:
            print(f"[ERR] Ignored {name.upper()}: No attack ID found.")

    return attack_map
예제 #6
0
    def __init__(
            self,
            base_cti_path: Path = Path(__file__).parents[1] / "cti",
            log_path: Path = Path("~/riskmap.log").expanduser(),
    ) -> None:

        self.base_cti_path = base_cti_path
        self.log_path = log_path

        # Configure sources
        self.src = CompositeDataSource()
        self.src.add_data_source(
            FileSystemSource(base_cti_path / "enterprise-attack"))
        self.src.add_data_source(
            FileSystemSource(base_cti_path / "mobile-attack"))
        self.src.add_data_source(FileSystemSource(base_cti_path /
                                                  "ics-attack"))
        self.src.add_data_source(FileSystemSource(base_cti_path / "capec"))

        logger.remove()
        logger.add(sink=self.log_path, format="{message}")
예제 #7
0
 def __init__(self, cti_folder):
     self.cti_folder = cti_folder
     repo = Repo(cti_folder)
     origin = repo.remotes.origin
     try:
         origin.pull()
     except Exception as e:
         pass
     enterprise_attack_fs = FileSystemSource(cti_folder +
                                             "enterprise-attack")
     pre_attack_fs = FileSystemSource(cti_folder + "pre-attack")
     mobile_attack_fs = FileSystemSource(cti_folder + "mobile-attack")
     self.src = CompositeDataSource()
     self.src.add_data_sources(
         [enterprise_attack_fs, pre_attack_fs, mobile_attack_fs])
     # self.columns_list = {"techniques":['mitre_id', 'name', 'description', 'permissions_required', 'platforms', 'adversary-opsec', 'build-capabilities', 'collection', 'command-and-control', 'compromise', 'credential-access', 'defense-evasion', 'discovery', 'effects', 'establish-&-maintain-infrastructure', 'execution', 'exfiltration', 'impact', 'initial-access', 'lateral-movement', 'launch', 'network-effects', 'organizational-information-gathering', 'organizational-weakness-identification', 'people-information-gathering', 'people-weakness-identification', 'persistence', 'persona-development', 'priority-definition-direction', 'priority-definition-planning', 'privilege-escalation', 'remote-service-effects', 'stage-capabilities', 'target-selection', 'technical-information-gathering', 'technical-weakness-identification', 'test-capabilities','kill_chain_phases']}
     self.columns_list = {
         "techniques": [
             'mitre_id', 'tactics', 'name', 'permissions_required',
             'platforms'
         ]
     }
예제 #8
0
class attack_client(object):
    TC_ENTERPRISE_SOURCE = None
    TC_PRE_SOURCE = None
    TC_MOBILE_SOURCE = None
    COMPOSITE_DS = None

    def __init__(self, local_path=None):
        if local_path is not None and os.path.isdir(os.path.join(local_path, ENTERPRISE_ATTCK_LOCAL_DIR)) \
                                  and os.path.isdir(os.path.join(local_path, PRE_ATTCK_LOCAL_DIR)) \
                                  and os.path.isdir(os.path.join(local_path, MOBILE_ATTCK_LOCAL_DIR)):
            self.TC_ENTERPRISE_SOURCE = FileSystemSource(
                os.path.join(local_path, ENTERPRISE_ATTCK_LOCAL_DIR))
            self.TC_PRE_SOURCE = FileSystemSource(
                os.path.join(local_path, PRE_ATTCK_LOCAL_DIR))
            self.TC_MOBILE_SOURCE = FileSystemSource(
                os.path.join(local_path, MOBILE_ATTCK_LOCAL_DIR))
        else:
            ENTERPRISE_COLLECTION = Collection(ATTCK_STIX_COLLECTIONS +
                                               ENTERPRISE_ATTCK + "/")
            PRE_COLLECTION = Collection(ATTCK_STIX_COLLECTIONS + PRE_ATTCK +
                                        "/")
            MOBILE_COLLECTION = Collection(ATTCK_STIX_COLLECTIONS +
                                           MOBILE_ATTCK + "/")

            self.TC_ENTERPRISE_SOURCE = TAXIICollectionSource(
                ENTERPRISE_COLLECTION)
            self.TC_PRE_SOURCE = TAXIICollectionSource(PRE_COLLECTION)
            self.TC_MOBILE_SOURCE = TAXIICollectionSource(MOBILE_COLLECTION)

        self.COMPOSITE_DS = CompositeDataSource()
        self.COMPOSITE_DS.add_data_sources([
            self.TC_ENTERPRISE_SOURCE, self.TC_PRE_SOURCE,
            self.TC_MOBILE_SOURCE
        ])

    def translate_stix_objects(self, stix_objects):
        technique_stix_mapping = {
            "type": "type",
            "id": "id",
            "created_by_ref": "created_by_ref",
            "created": "created",
            "modified": "modified",
            "object_marking_refs": "object_marking_refs",
            "name": "technique",
            "description": "technique_description",
            "kill_chain_phases": "tactic",
            "x_mitre_detection": "technique_detection",
            "x_mitre_platforms": "platform",
            "x_mitre_data_sources": "data_sources",
            "x_mitre_defense_bypassed": "defense_bypassed",
            "x_mitre_permissions_required": "permissions_required",
            "x_mitre_effective_permissions": "effective_permissions",
            "x_mitre_system_requirements": "system_requirements",
            "x_mitre_network_requirements": "network_requirements",
            "x_mitre_remote_support": "remote_support",
            "x_mitre_contributors": "contributors",
            "x_mitre_detectable_by_common_defenses":
            "detectable_by_common_defenses",
            "x_mitre_detectable_by_common_defenses_explanation":
            "detectable_explanation",
            "x_mitre_difficulty_for_adversary": "difficulty_for_adversary",
            "x_mitre_difficulty_for_adversary_explanation":
            "difficulty_explanation",
            "x_mitre_tactic_type": "tactic_type",
            "x_mitre_impact_type": "impact_type",
            "external_references": "external_references"
        }
        mitigation_stix_mapping = {
            "type": "type",
            "id": "id",
            "created_by_ref": "created_by_ref",
            "created": "created",
            "modified": "modified",
            "name": "mitigation",
            "description": "mitigation_description",
            "external_references": "external_references",
            "x_mitre_old_attack_id": "old_mitigation_id"
        }
        group_stix_mapping = {
            "type": "type",
            "id": "id",
            "created_by_ref": "created_by_ref",
            "created": "created",
            "modified": "modified",
            "name": "group",
            "description": "group_description",
            "aliases": "group_aliases",
            "external_references": "external_references",
            "x_mitre_contributors": "contributors"
        }
        software_stix_mapping = {
            "type": "type",
            "id": "id",
            "created_by_ref": "created_by_ref",
            "created": "created",
            "modified": "modified",
            "name": "software",
            "description": "software_description",
            "labels": "software_labels",
            "x_mitre_aliases": "software_aliases",
            "x_mitre_platforms": "software_platform",
            "external_references": "external_references",
            "x_mitre_contributors": "contributors",
            "x_mitre_old_attack_id": "old_software_id"
        }
        relationship_stix_mapping = {
            "type": "type",
            "id": "id",
            "created_by_ref": "created_by_ref",
            "created": "created",
            "modified": "modified",
            "relationship_type": "relationship",
            "description": "relationship_description",
            "source_ref": "source_object",
            "target_ref": "target_object"
        }
        tactic_stix_mapping = {
            "type": "type",
            "id": "id",
            "created_by_ref": "created_by_ref",
            "created": "created",
            "modified": "modified",
            "object_marking_refs": "object_marking_refs",
            "name": "tactic",
            "description": "tactic_description",
            "x_mitre_shortname": "tactic_shortname",
            "external_references": "external_references"
        }
        matrix_stix_mapping = {
            "type": "type",
            "id": "id",
            "created_by_ref": "created_by_ref",
            "created": "created",
            "modified": "modified",
            "object_marking_refs": "object_marking_refs",
            "name": "matrix",
            "description": "matrix_description",
            "tactic_refs": "tactic_references",
            "external_references": "external_references"
        }
        identity_stix_mapping = {
            "type": "type",
            "id": "id",
            "created_by_ref": "created_by_ref",
            "created": "created",
            "definition_type": "marking_definition_type",
            "definition": "marking_definition"
        }
        marking_stix_mapping = {
            "type": "type",
            "id": "id",
            "created": "created",
            "modified": "modified",
            "object_marking_refs": "object_marking_refs",
            "name": "identity",
            "identity_class": "identity_class"
        }

        # ******** Helper Functions ********
        def handle_list(list_object, object_type):
            if object_type == "external_references":
                obj_dict['url'] = list_object[0]['url']
                obj_dict['matrix'] = list_object[0]['source_name']
                if obj_dict['type'] == 'attack-pattern':
                    for ref in list_object:
                        if ref['source_name'] == 'capec':
                            obj_dict['capec_id'] = ref['external_id']
                            obj_dict['capec_url'] = ref['url']
                    obj_dict['technique_id'] = list_object[0]['external_id']
                elif obj_dict['type'] == 'course-of-action':
                    obj_dict['mitigation_id'] = list_object[0]['external_id']
                elif obj_dict['type'] == 'group':
                    obj_dict['group_id'] = list_object[0]['external_id']
                elif obj_dict['type'] == 'software':
                    obj_dict['software_id'] = list_object[0]['external_id']
                elif obj_dict['type'] == 'tactic':
                    obj_dict['tactic_id'] = list_object[0]['external_id']
                elif obj_dict['type'] == 'matrix':
                    obj_dict['matrix_id'] = list_object[0]['external_id']
            elif object_type == "kill_chain_phases":
                tactic_list = list()
                for phase in list_object:
                    tactic_list.append(phase['phase_name'])
                obj_dict['tactic'] = tactic_list

        stix_objects_list = list()
        for obj in stix_objects:
            if isinstance(obj, dict):
                obj_dict = obj
            else:
                obj_dict = json.loads(
                    obj.serialize())  # From STIX to Python Dict
            dict_keys = list(obj_dict.keys())
            for key in dict_keys:
                if obj['type'] == "attack-pattern":
                    stix_mapping = technique_stix_mapping
                elif obj['type'] == "course-of-action":
                    stix_mapping = mitigation_stix_mapping
                elif obj['type'] == "intrusion-set":
                    stix_mapping = group_stix_mapping
                elif obj['type'] == "malware" or obj['type'] == "tool":
                    stix_mapping = software_stix_mapping
                elif obj['type'] == "relationship":
                    stix_mapping = relationship_stix_mapping
                elif obj['type'] == "x-mitre-tactic":
                    stix_mapping = tactic_stix_mapping
                elif obj['type'] == "x-mitre-matrix":
                    stix_mapping = matrix_stix_mapping
                elif obj['type'] == "identity":
                    stix_mapping = identity_stix_mapping
                elif obj['type'] == "marking-definition":
                    stix_mapping = marking_stix_mapping
                else:
                    exit

                if key in stix_mapping.keys():
                    if key == "external_references" or key == "kill_chain_phases":
                        handle_list(obj_dict[key], key)
                    else:
                        new_key = stix_mapping[key]
                        obj_dict[new_key] = obj_dict.pop(key)
            stix_objects_list.append(obj_dict)
        return stix_objects_list

    def remove_revoked(self, stix_objects, extract=False):
        handle_revoked = list()
        for obj in stix_objects:
            if 'revoked' in obj.keys() and obj['revoked'] == True:
                if extract:
                    handle_revoked.append(obj)
                else:
                    continue
            handle_revoked.append(obj)
        return handle_revoked

    # ******** Enterprise ATT&CK Technology Domain  *******
    def get_enterprise(self, stix_format=True):
        enterprise_filter_objects = {
            "techniques": Filter("type", "=", "attack-pattern"),
            "mitigations": Filter("type", "=", "course-of-action"),
            "groups": Filter("type", "=", "intrusion-set"),
            "malware": Filter("type", "=", "malware"),
            "tools": Filter("type", "=", "tool"),
            "relationships": Filter("type", "=", "relationship"),
            "tactics": Filter("type", "=", "x-mitre-tactic"),
            "matrix": Filter("type", "=", "x-mitre-matrix"),
            "identity": Filter("type", "=", "identity"),
            "marking-definition": Filter("type", "=", "marking-definition")
        }
        enterprise_stix_objects = {}
        for key in enterprise_filter_objects:
            enterprise_stix_objects[key] = (self.TC_ENTERPRISE_SOURCE.query(
                enterprise_filter_objects[key]))
            if not stix_format:
                enterprise_stix_objects[key] = self.translate_stix_objects(
                    enterprise_stix_objects[key])
        return enterprise_stix_objects

    def get_enterprise_techniques(self, stix_format=True):
        enterprise_techniques = self.TC_ENTERPRISE_SOURCE.query(
            Filter("type", "=", "attack-pattern"))
        if not stix_format:
            enterprise_techniques = self.translate_stix_objects(
                enterprise_techniques)
        return enterprise_techniques

    def get_enterprise_mitigations(self, stix_format=True):
        enterprise_mitigations = self.TC_ENTERPRISE_SOURCE.query(
            Filter("type", "=", "course-of-action"))
        if not stix_format:
            enterprise_mitigations = self.translate_stix_objects(
                enterprise_mitigations)
        return enterprise_mitigations

    def get_enterprise_groups(self, stix_format=True):
        enterprise_groups = self.TC_ENTERPRISE_SOURCE.query(
            Filter("type", "=", "intrusion-set"))
        if not stix_format:
            enterprise_groups = self.translate_stix_objects(enterprise_groups)
        return enterprise_groups

    def get_enterprise_malware(self, stix_format=True):
        enterprise_malware = self.TC_ENTERPRISE_SOURCE.query(
            Filter("type", "=", "malware"))
        if not stix_format:
            enterprise_malware = self.translate_stix_objects(
                enterprise_malware)
        return enterprise_malware

    def get_enterprise_tools(self, stix_format=True):
        enterprise_tools = self.TC_ENTERPRISE_SOURCE.query(
            Filter("type", "=", "tool"))
        if not stix_format:
            enterprise_tools = self.translate_stix_objects(enterprise_tools)
        return enterprise_tools

    def get_enterprise_relationships(self, stix_format=True):
        enterprise_relationships = self.TC_ENTERPRISE_SOURCE.query(
            Filter("type", "=", "relationship"))
        if not stix_format:
            enterprise_relationships = self.translate_stix_objects(
                enterprise_relationships)
        return enterprise_relationships

    def get_enterprise_tactics(self, stix_format=True):
        enterprise_tactics = self.TC_ENTERPRISE_SOURCE.query(
            Filter("type", "=", "x-mitre-tactic"))
        if not stix_format:
            enterprise_tactics = self.translate_stix_objects(
                enterprise_tactics)
        return enterprise_tactics

    # ******** Pre ATT&CK Domain  *******
    def get_pre(self, stix_format=True):
        pre_filter_objects = {
            "techniques": Filter("type", "=", "attack-pattern"),
            "groups": Filter("type", "=", "intrusion-set"),
            "relationships": Filter("type", "=", "relationship"),
            "tactics": Filter("type", "=", "x-mitre-tactic"),
            "matrix": Filter("type", "=", "x-mitre-matrix"),
            "identity": Filter("type", "=", "identity"),
            "marking-definition": Filter("type", "=", "marking-definition")
        }
        pre_stix_objects = {}
        for key in pre_filter_objects:
            pre_stix_objects[key] = self.TC_PRE_SOURCE.query(
                pre_filter_objects[key])
            if not stix_format:
                pre_stix_objects[key] = self.translate_stix_objects(
                    pre_stix_objects[key])
        return pre_stix_objects

    def get_pre_techniques(self, stix_format=True):
        pre_techniques = self.TC_PRE_SOURCE.query(
            Filter("type", "=", "attack-pattern"))
        if not stix_format:
            pre_techniques = self.translate_stix_objects(pre_techniques)
        return pre_techniques

    def get_pre_groups(self, stix_format=True):
        pre_groups = self.TC_PRE_SOURCE.query(
            Filter("type", "=", "intrusion-set"))
        if not stix_format:
            pre_groups = self.translate_stix_objects(pre_groups)
        return pre_groups

    def get_pre_relationships(self, stix_format=True):
        pre_relationships = self.TC_PRE_SOURCE.query(
            Filter("type", "=", "relationship"))
        if not stix_format:
            pre_relationships = self.translate_stix_objects(pre_relationships)
        return pre_relationships

    def get_pre_tactics(self, stix_format=True):
        pre_tactics = self.TC_PRE_SOURCE.query(
            Filter("type", "=", "x-mitre-tactic"))
        if not stix_format:
            pre_tactics = self.translate_stix_objects(pre_tactics)
        return pre_tactics

    # ******** Mobile ATT&CK Technology Domain  *******
    def get_mobile(self, stix_format=True):
        mobile_filter_objects = {
            "techniques": Filter("type", "=", "attack-pattern"),
            "mitigations": Filter("type", "=", "course-of-action"),
            "groups": Filter("type", "=", "intrusion-set"),
            "malware": Filter("type", "=", "malware"),
            "tools": Filter("type", "=", "tool"),
            "relationships": Filter("type", "=", "relationship"),
            "tactics": Filter("type", "=", "x-mitre-tactic"),
            "matrix": Filter("type", "=", "x-mitre-matrix"),
            "identity": Filter("type", "=", "identity"),
            "marking-definition": Filter("type", "=", "marking-definition")
        }
        mobile_stix_objects = {}
        for key in mobile_filter_objects:
            mobile_stix_objects[key] = self.TC_MOBILE_SOURCE.query(
                mobile_filter_objects[key])
            if not stix_format:
                mobile_stix_objects[key] = self.translate_stix_objects(
                    mobile_stix_objects[key])
        return mobile_stix_objects

    def get_mobile_techniques(self, stix_format=True):
        mobile_techniques = self.TC_MOBILE_SOURCE.query(
            Filter("type", "=", "attack-pattern"))
        if not stix_format:
            mobile_techniques = self.translate_stix_objects(mobile_techniques)
        return mobile_techniques

    def get_mobile_mitigations(self, stix_format=True):
        mobile_mitigations = self.TC_MOBILE_SOURCE.query(
            Filter("type", "=", "course-of-action"))
        if not stix_format:
            mobile_mitigations = self.translate_stix_objects(
                mobile_mitigations)
        return mobile_mitigations

    def get_mobile_groups(self, stix_format=True):
        mobile_groups = self.TC_MOBILE_SOURCE.query(
            Filter("type", "=", "intrusion-set"))
        if not stix_format:
            mobile_groups = self.translate_stix_objects(mobile_groups)
        return mobile_groups

    def get_mobile_malware(self, stix_format=True):
        mobile_malware = self.TC_MOBILE_SOURCE.query(
            Filter("type", "=", "malware"))
        if not stix_format:
            mobile_malware = self.translate_stix_objects(mobile_malware)
        return mobile_malware

    def get_mobile_tools(self, stix_format=True):
        mobile_tools = self.TC_MOBILE_SOURCE.query(Filter("type", "=", "tool"))
        if not stix_format:
            mobile_tools = self.translate_stix_objects(mobile_tools)
        return mobile_tools

    def get_mobile_relationships(self, stix_format=True):
        mobile_relationships = self.TC_MOBILE_SOURCE.query(
            Filter("type", "=", "relationship"))
        if not stix_format:
            mobile_relationships = self.translate_stix_objects(
                mobile_relationships)
        return mobile_relationships

    def get_mobile_tactics(self, stix_format=True):
        mobile_tactics = self.TC_MOBILE_SOURCE.query(
            Filter("type", "=", "x-mitre-tactic"))
        if not stix_format:
            mobile_tactics = self.translate_stix_objects(mobile_tactics)
        return mobile_tactics

    # ******** Get All Functions ********
    def get_stix_objects(self, stix_format=True):
        enterprise_objects = self.get_enterprise()
        pre_objects = self.get_pre()
        mobile_objects = self.get_mobile()
        for keypre in pre_objects.keys():
            for preobj in pre_objects[keypre]:
                if keypre in enterprise_objects.keys():
                    if preobj not in enterprise_objects[keypre]:
                        enterprise_objects[keypre].append(preobj)
        for keymob in mobile_objects.keys():
            for mobobj in mobile_objects[keymob]:
                if keymob in enterprise_objects.keys():
                    if mobobj not in enterprise_objects[keymob]:
                        enterprise_objects[keymob].append(mobobj)
        if not stix_format:
            for enterkey in enterprise_objects.keys():
                enterprise_objects[enterkey] = self.translate_stix_objects(
                    enterprise_objects[enterkey])
        return enterprise_objects

    def get_techniques(self, stix_format=True):
        all_techniques = self.COMPOSITE_DS.query(
            Filter("type", "=", "attack-pattern"))
        if not stix_format:
            all_techniques = self.translate_stix_objects(all_techniques)
        return all_techniques

    def get_groups(self, stix_format=True):
        all_groups = self.COMPOSITE_DS.query(
            Filter("type", "=", "intrusion-set"))
        if not stix_format:
            all_groups = self.translate_stix_objects(all_groups)
        return all_groups

    def get_mitigations(self, stix_format=True):
        enterprise_mitigations = self.get_enterprise_mitigations()
        mobile_mitigations = self.get_mobile_mitigations()
        for mm in mobile_mitigations:
            if mm not in enterprise_mitigations:
                enterprise_mitigations.append(mm)
        if not stix_format:
            enterprise_mitigations = self.translate_stix_objects(
                enterprise_mitigations)
        return enterprise_mitigations

    def get_software(self, stix_format=True):
        enterprise_malware = self.get_enterprise_malware()
        enterprise_tools = self.get_enterprise_tools()
        mobile_malware = self.get_mobile_malware()
        mobile_tools = self.get_mobile_tools()
        for mt in mobile_tools:
            if mt not in enterprise_tools:
                enterprise_tools.append(mt)
        for mmal in mobile_malware:
            if mmal not in enterprise_malware:
                enterprise_malware.append(mmal)
        all_software = enterprise_tools + enterprise_malware
        if not stix_format:
            all_software = self.translate_stix_objects(all_software)
        return all_software

    def get_relationships(self, stix_format=True):
        all_relationships = self.COMPOSITE_DS.query(
            Filter("type", "=", "relationship"))
        if not stix_format:
            all_relationships = self.translate_stix_objects(all_relationships)
        return all_relationships

    def get_tactics(self, stix_format=True):
        all_tactics = self.COMPOSITE_DS.query(
            Filter("type", "=", "x-mitre-tactic"))
        if not stix_format:
            all_tactics = self.translate_stix_objects(all_tactics)
        return all_tactics

    # ******** Custom Functions ********
    def get_technique_by_name(self, name, case=True, stix_format=True):
예제 #9
0
class MitreAttack:
    """
    Simple class that controls access to Mitre Att&ck datasets.
    """

    DEFAULT_SERVER = "https://cti-taxii.mitre.org/taxii/"

    def __init__(self):
        self._api_root = None
        self._server = None
        self._source = None
        self._frames = {}

    def _get_frame_from_collection(self, collection):
        """
        Returns a DataFrame with information from a Mitre Att&ck collection.
        """
        data = collection.get_objects()
        lines = []
        for item in data.get('objects', []):
            line = item
            external = item.get('external_references', [])
            for source in external:
                if not source.get("url",
                                  "").startswith("https://attack.mitre.org"):
                    continue
                line["mitre_source"] = source.get("source_name")
                line["mitre_id"] = source.get("external_id")
                url = source.get("url")
                url_items = url.split("/")
                line["mitre_collection"] = url_items[-2]
            lines.append(line)
        return pd.DataFrame(lines)

    @property
    def server(self):
        """
        Returns a copy of the Mitre server object.
        """
        if self._server:
            return self._server

        self._server = Server(self.DEFAULT_SERVER)
        self._api_root = self._server.api_roots[0]
        return self._server

    @property
    def collection_titles(self):
        """
        Returns a list of collection titles and ID that are available.
        """
        _ = self.server
        return [(c.title, c.id) for c in self._api_root.collections]

    @property
    def source(self):
        """
        Returns the data source object for Att&ck data.
        """
        if self._source:
            return self._source

        self._source = CompositeDataSource()
        self._source.add_data_sources(self._api_root.collections)

        return self._source

    def get_collection(self, collection_title):
        """
        Returns a DataFrame with the content of a particular collection.

        :param str collection_title: The tile or a substring of a collection
            entry in Mitre Att&ck framework. The first match of available
            collections will be used.
        :return: A pandas DataFrame with the content or an empty frame if the
            collection was not found.
        """
        _ = self.server
        for collection in self._api_root.collections:
            if collection_title.lower() not in collection.title.lower():
                continue

            title = collection.title
            if title not in self._frames:
                self._frames[title] = self._get_frame_from_collection(
                    collection)
            return self._frames[title]

        return pd.DataFrame()

    def get_technique(self, mitre_id, collection_title='Enterprise ATT&CK'):
        """
        Returns a pandas Series with the content of a single technique.

        :param str mitre_id: This is the corresponding Mitre Att&ck ID for the
            technique to look up.
        :param str collection_title: The title of the collection this
            particular technique exists in. By default uses the Enterprise
            collection.
        :return: A pandas Series with the information, or an empty series
            if not found.
        """
        titles = [x[0] for x in self.collection_titles]
        use_title = ""
        for title in titles:
            if collection_title.lower() in title.lower():
                use_title = title
                break
        if not use_title:
            raise ValueError("Collection Title %s not found", collection_title)

        if use_title not in self._frames:
            _ = self.get_collection(use_title)
        frame = self._frames.get(use_title)

        frame_slice = frame[frame.mitre_id == mitre_id.upper()]
        if not frame_slice.empty:
            return frame_slice.iloc[0].dropna()

        return pd.Series()
예제 #10
0
import re
import requests
from bs4 import BeautifulSoup

from stix2 import TAXIICollectionSource
from stix2 import Filter
from stix2 import CompositeDataSource
from taxii2client.v20 import Server

# globals
TAXII_SERVER = "https://cti-taxii.mitre.org/taxii/"
SUCCESS = (200, )
DATA_SOURCE = None
EXCLUDE_COLLECTIONS = ['PRE-ATT&CK']
CS = CompositeDataSource()


def execute(method, url, payload=None, user=None, password=None):
    """
    Execute rest api
    :param method:  http method
    :param url: rest endpoint
    :param payload: body of request
    :param user: username for auth
    :param password: password for auth
    :return:
    """
    headers = {'Content-Type': "text/html; charset=utf-8"}
    response = requests.request(method=method,
                                url=url,
                                auth=None,
class MitreAttackConnection(object):
    """
    Collection of methods for extracting data from MitreServer.
    Includes the logic of using multiple data sources.
    """
    def __init__(self, opts=None, function_opts=None):
        self.attack_server = None
        self.composite_ds = None
        self.proxies = RequestsCommon(opts, function_opts).get_proxies()

    def connect_server(self, url=None):
        """
        Allow user to specify what url to use
        :param url:
        :return:
        """
        server_url = MITRE_TAXII_URL if url is None else url
        self.attack_server = Server(server_url, proxies=self.proxies)
        api_root = self.attack_server.api_roots[0]
        # CompositeSource to query all the collections at once
        c_sources = [
            TAXIICollectionSource(collection)
            for collection in api_root.collections
        ]
        self.composite_ds = CompositeDataSource()
        self.composite_ds.add_data_sources(c_sources)

    def get_items(self, filters):
        """
        Get items using filters, convert them to dictionaries.
        Reference:
        https://github.com/mitre/cti/blob/master/USAGE.md
        :param filters: list of filter
        :return: list of dictionaries representing stix objects
        :rtype: list(dict)
        """
        if self.attack_server is None:
            self.connect_server()
        items = []
        for data_source in self.composite_ds.get_all_data_sources():
            try:
                ds_items = data_source.query(filters)
                updated_items = [
                    MitreAttackBase.object_to_dict(x) for x in ds_items
                ]
                for item in updated_items:
                    item["collection"] = data_source.collection.title
                items.extend(updated_items)
            except DataSourceError as e:
                # happens if data_source finds no elements with given filter
                pass
        return items

    def get_related_to(self, *args, **kwargs):
        """
        Facade for `related_to` of composite data source. Needed to abstract out DataSource from
        classes using AttackMitre.
        :return: objects with the provided relationships
        """
        if self.attack_server is None:
            self.connect_server()
        return self.composite_ds.related_to(*args, **kwargs)

    def lookup_item(self, item_name, type_name="attack-pattern"):
        """
        Look up items using item name
        :param item_name:
        :param collection_title:
        :param type_name:
        :return:
        """
        query_filter = Filter("type", "=", type_name)
        name_filter = Filter("name", "=", item_name)
        items = self.get_items([query_filter, name_filter])

        if not len(items):
            return None

        return items
예제 #12
0
class MitreParser:
    """This class wraps all the function for interacting with the MitreAtt&ck Repository"""
    def __init__(self, cti_folder):
        self.cti_folder = cti_folder
        repo = Repo(cti_folder)
        origin = repo.remotes.origin
        try:
            origin.pull()
        except Exception as e:
            pass
        enterprise_attack_fs = FileSystemSource(cti_folder +
                                                "enterprise-attack")
        pre_attack_fs = FileSystemSource(cti_folder + "pre-attack")
        mobile_attack_fs = FileSystemSource(cti_folder + "mobile-attack")
        self.src = CompositeDataSource()
        self.src.add_data_sources(
            [enterprise_attack_fs, pre_attack_fs, mobile_attack_fs])
        # self.columns_list = {"techniques":['mitre_id', 'name', 'description', 'permissions_required', 'platforms', 'adversary-opsec', 'build-capabilities', 'collection', 'command-and-control', 'compromise', 'credential-access', 'defense-evasion', 'discovery', 'effects', 'establish-&-maintain-infrastructure', 'execution', 'exfiltration', 'impact', 'initial-access', 'lateral-movement', 'launch', 'network-effects', 'organizational-information-gathering', 'organizational-weakness-identification', 'people-information-gathering', 'people-weakness-identification', 'persistence', 'persona-development', 'priority-definition-direction', 'priority-definition-planning', 'privilege-escalation', 'remote-service-effects', 'stage-capabilities', 'target-selection', 'technical-information-gathering', 'technical-weakness-identification', 'test-capabilities','kill_chain_phases']}
        self.columns_list = {
            "techniques": [
                'mitre_id', 'tactics', 'name', 'permissions_required',
                'platforms'
            ]
        }

    def get_technique_by_group(self, stix_id):
        relations = self.src.relationships(stix_id, 'uses', source_only=True)
        return self.src.query([
            Filter('type', '=', 'attack-pattern'),
            Filter('id', 'in', [r.target_ref for r in relations])
        ])

    def get_malware_by_group(self, stix_id):
        relations = self.src.relationships(stix_id, 'uses', source_only=True)
        query_malware = self.src.query([
            Filter('type', '=', 'malware'),
            Filter('id', 'in', [r.target_ref for r in relations])
        ])
        dict_malware = []
        for group in query_malware:
            string_report = group.serialize()
            dict_report = json.loads(string_report)
            dict_malware.append(dict_report)
        df_malware = pd.DataFrame(dict_malware)
        return df_malware

    def get_tool_by_group(self, stix_id):
        relations = self.src.relationships(stix_id, 'uses', source_only=True)
        query_tool = self.src.query([
            Filter('type', '=', 'tool'),
            Filter('id', 'in', [r.target_ref for r in relations])
        ])
        dict_tool = []
        for group in query_tool:
            string_report = group.serialize()
            dict_report = json.loads(string_report)
            dict_tool.append(dict_report)
        df_tool = pd.DataFrame(dict_tool)
        return df_tool

    def get_techniques_by_group(self, stix_id):
        group_uses = [
            r
            for r in self.src.relationships(stix_id, 'uses', source_only=True)
            if get_type_from_id(r.target_ref) in ['malware', 'tool']
        ]

        software_uses = self.src.query([
            Filter('type', '=', 'relationship'),
            Filter('relationship_type', '=', 'uses'),
            Filter('source_ref', 'in', [r.source_ref for r in group_uses])
        ])

        techniques_query = self.src.query([
            Filter('type', '=', 'attack-pattern'),
            Filter('id', 'in', [r.target_ref for r in software_uses])
        ])
        dict_techniques = []
        for current_technique in techniques_query:
            string_report = current_technique.serialize()
            dict_report = json.loads(string_report)
            dict_techniques.append(dict_report)
        techniques_df = pd.DataFrame(dict_techniques)
        if techniques_df.empty:
            return techniques_df
        techniques_df = techniques_df.fillna("")
        techniques_df["kill_chain_phases"] = techniques_df[
            "kill_chain_phases"].apply(lambda x: [
                y["phase_name"] for y in x if 'mitre' in y['kill_chain_name']
            ])
        techniques_df = techniques_df.rename(
            index=str,
            columns={
                "x_mitre_permissions_required": "permissions_required",
                "x_mitre_platforms": "platforms",
                "id": "mitre_id",
                "kill_chain_phases": "tactics"
            })
        column_set = set(techniques_df.columns.values)
        for i in self.columns_list["techniques"]:
            column_set.add(i)
        techniques_df = techniques_df.reindex(columns=list(column_set),
                                              fill_value="")
        return techniques_df[self.columns_list["techniques"]]

    def get_group_by_alias(self, alias):
        return self.src.query([
            Filter('type', '=', 'intrusion-set'),
            Filter('aliases', '=', alias)
        ])

    def get_all_groups(self):
        filt = Filter('type', '=', 'intrusion-set')
        groups = self.src.query([filt])
        dict_groups = []
        for group in groups:
            string_report = group.serialize()
            dict_report = json.loads(string_report)
            hash_report = hashlib.sha1(
                string_report.encode('utf-8')).hexdigest()
            dict_report["hash"] = hash_report
            dict_groups.append(dict_report)
        group_df = pd.DataFrame(dict_groups)
        group_df = group_df.fillna("")
        return group_df

    def get_all_techniques(self):
        technique_query = self.src.query(Filter('type', '=', 'attack-pattern'))
        dict_techniques = []
        for current_technique in technique_query:
            string_report = current_technique.serialize()
            dict_report = json.loads(string_report)
            dict_techniques.append(dict_report)
        techniques_df = pd.DataFrame(dict_techniques)
        techniques_df = techniques_df.fillna("")
        techniques_df["kill_chain_phases"] = techniques_df[
            "kill_chain_phases"].apply(lambda x: [
                y["phase_name"] for y in x if 'mitre' in y['kill_chain_name']
            ])
        techniques_df = techniques_df.rename(
            index=str,
            columns={
                "x_mitre_permissions_required": "permissions_required",
                "x_mitre_platforms": "platforms",
                "id": "mitre_id"
            })
        return techniques_df[self.columns_list["techniques"]]

    def get_all_tactics(self):
        tactic_query = self.src.query(Filter('type', '=', 'x-mitre-tactic'))
        tactics_df = pd.DataFrame(tactic_query)
        return tactics_df
예제 #13
0
class AttckMapper:
    """Mapper for ATT&CK Matrix IDs via STIX. Only file system access supported

    Args:
        base_cti_path: Base directory of CTI data.
    """
    def __init__(
            self,
            base_cti_path: Path = Path(__file__).parents[1] / "cti",
            log_path: Path = Path("~/riskmap.log").expanduser(),
    ) -> None:

        self.base_cti_path = base_cti_path
        self.log_path = log_path

        # Configure sources
        self.src = CompositeDataSource()
        self.src.add_data_source(
            FileSystemSource(base_cti_path / "enterprise-attack"))
        self.src.add_data_source(
            FileSystemSource(base_cti_path / "mobile-attack"))
        self.src.add_data_source(FileSystemSource(base_cti_path /
                                                  "ics-attack"))
        self.src.add_data_source(FileSystemSource(base_cti_path / "capec"))

        logger.remove()
        logger.add(sink=self.log_path, format="{message}")

    def lookup_by_attack_id(self, attack_id: str):
        return self.src.query([
            Filter("external_references.external_id", "=", attack_id),
            Filter("type", "in", ["attack-pattern", "course-of-action"]),
        ])

    def mapping(self,
                *ignore,
                enterprise: List = [],
                mobile: List = [],
                ics: List = []):
        """Maps enterprise, mobile, and ics IDs to a function as a dictionary."""
        if ignore:
            raise TypeError("Mapping arguments must be explicit")

        def decorator(func: Callable):
            @wraps(func)
            def add_attribute(*args, **kwargs):
                ids = {
                    "enterprise": enterprise,
                    "mobile": mobile,
                    "ics": ics,
                }
                try:
                    now = datetime.utcnow()
                    details = func(*args, **kwargs) or {}
                    logger.info(
                        json.dumps(
                            {
                                "command":
                                func.__name__,
                                "startTime":
                                now.strftime("%m/%d/%Y %H:%M:%S"),
                                "endTime":
                                datetime.utcnow().strftime(
                                    "%m/%d/%Y %H:%M:%S"),
                                "args":
                                args,
                                "kwargs":
                                kwargs,
                                "details":
                                details,
                                "mapping":
                                ids,
                            },
                            cls=CustomEncoder,
                        ))
                except Exception as e:
                    print(e)

            return add_attribute

        return decorator

    def get_map_info(self, map_object_name: str, command: Callable) -> List:
        """Lazy method to retrieve mapping of command to get details"""
        module = ast.parse(inspect.getsource(command))
        definition = []
        for node in ast.walk(module):
            if isinstance(node, ast.FunctionDef):
                for d in node.decorator_list:
                    if d.func.value.id == map_object_name:
                        for kw in d.keywords:
                            param, values = kw.arg, kw.value.elts
                            for v in values:
                                definition += self.lookup_by_attack_id(
                                    str(v.value))

                        break
                break
        return definition

    def describe(self, map_object_name: str, command: Callable) -> namedtuple:
        definition = self.get_map_info(map_object_name, command)

        references = []
        detections = []
        mitigations = []

        for pattern in definition:

            if pattern.type == "attack-pattern":
                if hasattr(pattern, "x_mitre_detection"):
                    detections.append(
                        (pattern.name, pattern.x_mitre_detection))
            elif pattern.type == "course-of-action":
                mitigations.append((pattern.name, pattern.description))

            for ref in pattern.external_references:
                if hasattr(ref, "external_id"):
                    if ref.external_id not in [r[0] for r in references]:
                        references.append([ref.external_id, ref.url])

        summarytable = PrettyTable(title="Summary", header=False)
        reftable = PrettyTable(title="References", header=False)
        detecttable = PrettyTable(title="Detections", header=False)
        mititable = PrettyTable(title="Mitigations", header=False)

        summarytable.add_row(["Name", command.__name__])
        summarytable.add_row(["Description", command.__doc__])
        reftable.add_rows(references)
        detecttable.add_rows([[d[0], "\n".join(wrap(d[1]))]
                              for d in detections])
        mititable.add_rows([[m[0], "\n".join(wrap(m[1]))]
                            for m in mitigations])

        summarytable.align = "l"
        reftable.align = "l"
        detecttable.align = "l"
        mititable.align = "l"
        return NamedTuple(
            "Description",
            [
                ("summary_table", PrettyTable),
                ("references_table", PrettyTable),
                ("detections_table", PrettyTable),
                ("mitigations_table", PrettyTable),
            ],
        )(summarytable, reftable, detecttable, mititable)