예제 #1
0
    def _mitre_groups_technique_intersection_function(self, event, *args,
                                                      **kwargs):
        """Function: For given Techniques return the Groups that are know to use all of them."""
        try:
            # Get the wf_instance_id of the workflow this Function was called in
            wf_instance_id = event.message["workflow_instance"][
                "workflow_instance_id"]

            # Get the function parameters:
            mitre_technique_name = kwargs.get("mitre_technique_name")  # text
            mitre_technique_id = kwargs.get("mitre_technique_id")  # text

            log = logging.getLogger(__name__)
            log.info("mitre_technique_name: %s", mitre_technique_name)
            log.info("mitre_technique_id: %s", mitre_technique_id)

            result_payload = ResultPayload(
                "fn_mitre_integration",
                mitre_technique_name=mitre_technique_name,
                mitre_technique_id=mitre_technique_id)

            if not mitre_technique_id and not mitre_technique_name:
                raise ValueError(
                    "At least one of the inputs(mitre_technique_name or mitre_technique_id) "
                    "should be provided.")

            yield StatusMessage("Getting technique information...")

            mitre_conn = mitre_attack.MitreAttackConnection()

            techniques = mitre_attack_utils.get_multiple_techniques(
                mitre_conn,
                mitre_technique_ids=mitre_technique_id,
                mitre_technique_names=mitre_technique_name)

            intersection_query = ",".join([t.id for t in techniques])

            yield StatusMessage("Getting group intersection information...")
            groups = mitre_attack.MitreAttackGroup.get_by_technique_intersection(
                mitre_conn, techniques)

            if len(groups) == 0:
                yield StatusMessage(
                    "No groups were found using all of the given techniques. Done"
                )
            else:
                yield StatusMessage("Done. Returning results.")

            # Storing the techniques specified to query this group
            for group in groups:
                group.technique_id = intersection_query

            groups = [x.dict_form()
                      for x in groups]  # prepare the data for viewing

            results = {"mitre_groups": groups}
            # Produce a FunctionResult with the results
            yield FunctionResult(result_payload.done(True, results))
        except Exception as e:
            yield FunctionError(e)
    def _mitre_groups_using_technique_function(self, event, *args, **kwargs):
        """Function: Get a list of groups that are using the given technique(s)."""
        try:
            mitre_technique_name = kwargs.get("mitre_technique_name")  # text
            mitre_technique_id = kwargs.get("mitre_technique_id")  # text

            log = logging.getLogger(__name__)
            log.info("mitre_technique_name: %s", mitre_technique_name)
            log.info("mitre_technique_id: %s", mitre_technique_id)

            result_payload = ResultPayload(
                "fn_mitre_integration",
                mitre_technique_name=mitre_technique_name,
                mitre_technique_id=mitre_technique_id)

            if not mitre_technique_id and not mitre_technique_name:
                raise ValueError(
                    "At least one of the inputs(mitre_technique_name or mitre_technique_id) "
                    "should be provided.")

            yield StatusMessage("Getting technique information...")

            mitre_conn = mitre_attack.MitreAttackConnection(
                self.opts, self.options)

            techniques = mitre_attack_utils.get_multiple_techniques(
                mitre_conn,
                mitre_technique_ids=mitre_technique_id,
                mitre_technique_names=mitre_technique_name)

            yield StatusMessage("Getting group information...")
            groups = []
            for technique in techniques:
                groups.extend(
                    mitre_attack.MitreAttackGroup.get_by_technique(
                        mitre_conn, technique))

            if len(groups) == 0:
                yield StatusMessage(
                    "No groups were found using any of the given techniques. Done."
                )
            else:
                yield StatusMessage("Done. Returning results.")

            groups = [x.dict_form()
                      for x in groups]  # prepare the data for viewing

            results = {"mitre_groups": groups}
            # Produce a FunctionResult with the results
            yield FunctionResult(result_payload.done(True, results))
        except Exception as e:
            log.exception(str(e))
            yield FunctionError()
    def _mitre_technique_information_function(self, event, *args, **kwargs):
        """Function: Get ATT&CK information about MITRE ATT&CK technique"""
        try:
            # Get the function parameters:
            mitre_technique_name = kwargs.get("mitre_technique_name")  # text
            mitre_technique_id = kwargs.get("mitre_technique_id")  # text
            mitre_technique_mitigation_only = kwargs.get("mitre_technique_mitigation_only")  # boolean

            log = logging.getLogger(__name__)
            log.info("mitre_technique_name: %s", mitre_technique_name)
            log.info("mitre_technique_id: %s", mitre_technique_id)
            log.info("mitre_technique_mitigation_only: %s", mitre_technique_mitigation_only)

            if not mitre_technique_name and not mitre_technique_id:
                raise ValueError("Neither name nor id is provided for getting technique information.")

            result_payload = ResultPayload("fn_mitre_integration", mitre_technique_name=mitre_technique_name,
                                           mitre_technique_id=mitre_technique_id,
                                           mitre_technique_mitigation_only=mitre_technique_mitigation_only)
            yield StatusMessage("starting...")
            yield StatusMessage("querying MITRE STIX TAXII server. It might take several minutes...")

            mitre_conn = mitre_attack.MitreAttackConnection()
            techniques = mitre_attack.MitreAttackTechnique.get(mitre_conn, name=mitre_technique_name,
                                                               id=mitre_technique_id)

            if not techniques:
                raise ValueError(
                    "Technique with name/id {}/{} can't be found".format(mitre_technique_name, mitre_technique_id))

            techs = []
            for technique in techniques:
                tactics = technique.get_tactic(mitre_conn)
                tech_dict = technique.dict_form()
                tech_dict.update(
                    {
                        "tactic": ",".join(x.name for x in tactics) if tactics else None,  # there should be 1 tactic per technique
                        "mitre_mitigations": [x.dict_form() for x in technique.get_mitigations(mitre_conn)]
                    }
                )
                techs.append(tech_dict)

            yield StatusMessage("done...")

            results = {
                "mitre_techniques": techs
            }
            # Produce a FunctionResult with the results
            yield FunctionResult(result_payload.done(True, results))
        except Exception as e:
            log.exception(str(e))
            yield FunctionError()
def selftest_function(opts):
    """
    Placeholder for selftest function. An example use would be to test package api connectivity.
    Suggested return values are be unimplemented, success, or failure.
    """
    options = opts.get("fn_mitre_integration", {})
    mitre_conn = mitre_attack.MitreAttackConnection()
    try:
        mitre_conn.connect_server()
    except Exception:
        return {"state": "failure"}

    if mitre_conn.composite_ds is not None:
        return {"state": "success"}

    return {"state": "failure"}
    def _mitre_techniques_software_function(self, event, *args, **kwargs):
        """Function: Gets a list of software used by each of the techniques queried.
For each, it will create a row in the corresponding data table for MITRE software."""
        try:
            # Get the function parameters:
            mitre_technique_name = kwargs.get("mitre_technique_name")  # text
            mitre_technique_id = kwargs.get("mitre_technique_id")  # text

            log = logging.getLogger(__name__)
            log.info("mitre_technique_name: %s", mitre_technique_name)
            log.info("mitre_technique_id: %s", mitre_technique_id)

            result_payload = ResultPayload("fn_mitre_integration", mitre_technique_name=mitre_technique_name,
                                           mitre_technique_id=mitre_technique_id)

            if not mitre_technique_id and not mitre_technique_name:
                raise ValueError("At least one of the inputs(mitre_technique_name or mitre_technique_id) "
                                 "should be provided.")

            yield StatusMessage("starting...")
            yield StatusMessage("Getting technique information...")

            mitre_conn = mitre_attack.MitreAttackConnection(self.opts, self.options)

            if mitre_technique_id is not None:
                # Try id first, because it's less ambiguous
                technique_ids = mitre_technique_id.split(',')
                techniques = []
                for t_id in technique_ids:
                    technique = mitre_attack.MitreAttackTechnique.get_by_id(mitre_conn, t_id)
                    if not technique:
                        raise ValueError("Technique with id {} doesn't exist".format(t_id))
                    techniques.extend(technique)
            else:
                # It's possible for multiple tactics to have the same name
                # And we want to make sure that all of them are processed in that case
                technique_names = mitre_technique_name.split(',')
                techniques = []
                for name in technique_names:
                    technique = mitre_attack.MitreAttackTechnique.get_by_name(mitre_conn, name)
                    if not technique:
                        raise ValueError("Techniques with name {} don't exist".format(name))
                    techniques.extend(technique)

            yield StatusMessage("Getting software information...")
            software = []
            for technique in techniques:
                software.extend(mitre_attack.MitreAttackSoftware.get_by_technique(mitre_conn, technique))

            if len(software) == 0:
                yield StatusMessage("No software was found for the given techniques. Done.")
            else:
                yield StatusMessage("Done. Returning results.")

            software = [x.dict_form() for x in software]  # prepare the data for viewing
            results = {
                "mitre_software": software
            }
            # Produce a FunctionResult with the results
            yield FunctionResult(result_payload.done(True, results))
        except Exception as e:
            log.exception(str(e))
            yield FunctionError()