Exemplo n.º 1
0
class Automation():
    def __init__(self, webhook, cfg):
        logger.info('Initiating MISPautomation')
        self.TheHiveConnector = TheHiveConnector(cfg)
        if self.cfg.getboolean('Cortex', 'enabled'):
            self.CortexConnector = CortexConnector(cfg)
        self.webhook = webhook
        self.report_action = report_action
        self.qr_config = {}
        for key, value in cfg.items('QRadar'):
            self.qr_config[key] = value

    def parse_hooks(self):
        """
        Check for new MISP Alert containing supported IOC to search automatically
        """

        if self.webhook.isNewMispAlert():
            logger.info(
                'Alert {} has been tagged as MISP and is just created'.format(
                    self.webhook.data['rootId']))

            #Check alert for supported ioc types
            supported_iocs = False
            for artifact in self.webhook.data['object']['artifacts']:
                if artifact['dataType'] in self.qr_config[
                        'supported_datatypes']:
                    supported_iocs = True

            #Promote alert to case if there are support ioc types
            if supported_iocs:
                alert_id = self.webhook.data['rootId']
                casetemplate = "MISP Event"

                logger.info('Alert {} contains IOCs that are supported'.format(
                    alert_id))

                response = self.TheHiveConnector.createCaseFromAlert(
                    alert_id, casetemplate)

                self.report_action = 'createCase'
        """
        Add timestamps to keep track of the search activity per case (we do not want to keep searching forever)
        """
        #Perform automated Analyzer runs for supported observables in a case that has been created from a MISP alert
        if self.webhook.isNewMispCase():
            logger.info(
                'Case {} has been tagged as MISP and is just created'.format(
                    self.webhook.data['rootId']))

            #Retrieve caseid
            caseid = self.webhook.data['object']['id']

            #Add customFields firstSearched and lastSearched
            #Create a Case object? Or whatever it is
            case = Case()

            #Add the case id to the object
            case.id = caseid

            #Debug output
            logger.info('Updating case %s' % case.id)

            #Define which fields need to get updated
            fields = ['customFields']

            #Retrieve all required attributes from the alert and add them as custom fields to the case
            current_time = int(round(time.time() * 1000))
            customFields = CustomFieldHelper()\
                .add_date('firstSearched', current_time)\
                .add_date('lastSearched', current_time)\
                .build()

            #Add custom fields to the case object
            case.customFields = customFields

            #Update the case
            self.TheHiveConnector.updateCase(case, fields)
            self.report_action = 'updateCase'
        """
        Start the analyzers automatically for MISP observables that are supported and update the case with a new timestamp
        """
        #Automatically run Analyzers for newly created MISP cases where supported IOC's are present
        if self.webhook.isNewMispArtifact():
            logger.info(
                'Case artifact is tagged with "MISP-extern". Checking if observable is of a supported type'
            )

            #Retrieve caseid
            caseid = self.webhook.data['rootId']

            #Retrieve case data
            case_data = self.TheHiveConnector.getCase(caseid)

            #List all supported ioc's for the case
            observable = self.webhook.data['object']

            #When supported, start a cortex analyzer for it
            if observable['dataType'] in self.qr_config['supported_datatypes']:
                supported_observable = observable['_id']

                #Trigger a search for the supported ioc
                logger.info('Launching analyzers for observable: {}'.format(
                    observable['_id']))
                response = self.CortexConnector.runAnalyzer(
                    "Cortex-intern", supported_observable,
                    "IBMQRadar_Search_Manual_0_1")

                #Add customFields firstSearched and lastSearched
                #Create a Case object
                case = Case()

                #Add the case id to the object
                case.id = caseid

                #Debug output
                logger.info('Updating case %s' % case.id)

                #Define which fields need to get updated
                fields = ['customFields']

                #Retrieve all required attributes from the alert and add them as custom fields to the case
                current_time = int(round(time.time() * 1000))
                customFields = CustomFieldHelper()\
                    .add_date('firstSearched', case_data['customFields']['firstSearched']['date'])\
                    .add_date('lastSearched', current_time)\
                    .build()

                #Add custom fields to the case object
                case.customFields = customFields

                #Update the case
                self.TheHiveConnector.updateCase(case, fields)
                self.report_action = 'updateCase'
        """
        Automatically create a task for a found IOC
        """
        #If the Job result contains a successful search with minimum of 1 hit, create a task to investigate the results
        if self.webhook.isCaseArtifactJob() and self.webhook.isSuccess(
        ) and self.webhook.isMisp():
            #Case ID
            caseid = self.webhook.data['rootId']
            #Load Case information
            case_data = self.TheHiveConnector.getCase(caseid)

            logger.info(
                'Job {} is part of a case that has been tagged as MISP case and has just finished'
                .format(self.webhook.data['object']['cortexJobId']))

            #Check if the result count higher than 0
            if int(
                    float(self.webhook.data['object']['report']['summary']
                          ['taxonomies'][0]['value'])) > 0:
                logger.info(
                    'Job {} contains hits, checking if a task is already present for this observable'
                    .format(self.webhook.data['object']['cortexJobId']))
                #Retrieve case task information
                response = self.TheHiveConnector.getCaseTasks(caseid)
                case_tasks = response.json()

                #Load CaseTask template
                casetask = CaseTask()

                #Observable + Link
                observable = self.webhook.data['object']['artifactId']
                observable_link = TheHive.get(
                    'url'
                ) + "/index.html#!/case/" + caseid + "/observables/" + self.webhook.data[
                    'object']['artifactId']

                #Task name
                casetask.title = "Investigate found IOC with id: {}".format(
                    observable)

                #Date
                date_found = time.strftime("%d-%m-%Y %H:%M")

                case_task_found = False
                for case_task in case_tasks:

                    #Check if task is present for investigating the new results
                    if casetask.title == case_task['title']:
                        case_task_found = True

                if not case_task_found:
                    logger.info(
                        'No task found, creating task for observable found in job {}'
                        .format(self.webhook.data['object']['cortexJobId']))
                    #Add description
                    casetask.description = "The following ioc is hit in the environment. Investigate the results and act accordingly:\n\n"
                    casetask.description = casetask.description + "{} is seen on {}\n".format(
                        observable_link, date_found)

                    #Check if case is closed
                    if case_data['status'] == "Resolved":
                        #Create a Case object? Or whatever it is
                        case = Case()

                        #Add the case id to the object
                        case.id = caseid

                        logger.info('Updating case %s' % case.id)

                        #Define which fields need to get updated
                        fields = ['status']

                        #Reopen the case
                        case.status = "Open"

                        #Update the case
                        self.TheHiveConnector.updateCase(case, fields)

                    #Add the case task
                    self.TheHiveConnector.createTask(caseid, casetask)
                    self.report_action = 'createTask'

        return self.report_action
Exemplo n.º 2
0
class Automators(Main):
    def __init__(self, cfg, use_case_config):
        self.logger = logging.getLogger(__name__)
        self.logger.info('Initiating The Hive Automator')

        self.cfg = cfg
        self.TheHiveConnector = TheHiveConnector(cfg)
        if self.cfg.getboolean('Cortex', 'enabled'):
            self.CortexConnector = CortexConnector(cfg)

        #Read mail config
        self.mailsettings = self.cfg.get('TheHive', 'mail')

    '''
    Can be used to check if there is a match between tags and the provided list.
    Useful for checking if there is a customer tag (having a list of customers) present where only one can match.
    '''

    def MatchValueAgainstTags(self, tags, list):
        for tag in tags:
            if tag in list:
                return tag

    def craftUcTask(self, title, description):
        self.logger.debug('%s.craftUcTask starts', __name__)

        self.uc_task = CaseTask(title=title, description=description)

        return self.uc_task

    def createBasicTask(self, action_config, webhook):
        #Only continue if the right webhook is triggered
        if webhook.isImportedAlert():
            pass
        else:
            return False

        #Perform actions for the CreateBasicTask action
        self.case_id = webhook.data['object']['case']
        self.title = action_config['title']
        self.description = action_config['description']

        self.logger.info('Found basic task to create: %s' % self.title)

        #Create Task
        self.uc_task = self.craftUcTask(self.title, self.description)
        self.uc_task_id = self.TheHiveConnector.createTask(
            self.case_id, self.uc_task)

        return True

    def createMailTask(self, action_config, webhook):
        #Only continue if the right webhook is triggered
        if webhook.isImportedAlert():
            pass
        else:
            return False

        self.tags = webhook.data['object']['tags']
        self.case_id = webhook.data['object']['case']
        if self.cfg.getboolean('Automation',
                               'enable_customer_list',
                               fallback=False):
            self.customer_id = self.MatchValueAgainstTags(
                self.tags, self.customers)
            self.logger.info('Found customer %s, retrieving recipient' %
                             self.customer_id)
        else:
            self.customer_id = None
        self.notification_type = "email"
        self.title = action_config['title']
        self.description = self.renderTemplate(action_config['long_template'],
                                               self.tags,
                                               webhook,
                                               self.notification_type,
                                               customer_id=self.customer_id,
                                               mail_settings=self.mailsettings)

        self.logger.info('Found mail task to create: %s' % self.title)

        #Create Task
        self.ucTask = self.craftUcTask(self.title, self.description)
        self.ucTaskId = self.TheHiveConnector.createTask(
            self.case_id, self.ucTask)
        if 'auto_send_mail' in action_config and action_config[
                'auto_send_mail'] and not self.stopsend:
            self.logger.info('Sending mail for task with id: %s' %
                             self.ucTaskId)
            self.TheHiveConnector.runResponder(
                'case_task', self.ucTaskId,
                self.use_case_config['configuration']['mail']['responder_id'])

    def runAnalyzer(self, action_config, webhook):
        #Automatically run Analyzers for newly created cases where supported IOC's are present
        if webhook.isNewArtifact():
            self.logger.debug(
                'Case artifact found. Checking if observable is of a supported type to automatically fire the analyzer'
            )

            #Retrieve caseid
            self.caseid = webhook.data['rootId']

            #List all supported ioc's for the case
            self.observable = webhook.data['object']

            #When supported, start a cortex analyzer for it
            if self.observable['dataType'] in action_config['datatypes']:
                self.supported_observable = self.observable['_id']

                #Blacklist IP addresses, make sure the blacklist is present
                if self.observable[
                        'dataType'] == "ip" and 'blacklist' in action_config and 'ip' in action_config[
                            'blacklist']:
                    for entry in action_config['blacklist']['ip']:
                        #Initial values
                        match = False
                        observable_ip = ipaddress.ip_address(
                            self.observable['data'])

                        #Match ip with CIDR syntax
                        if entry[-3:] == "/32":
                            bl_entry = ipaddress.ip_address(entry[:-3])
                            match = observable_ip == bl_entry
                        #Match ip without CIDR syntax
                        elif "/" not in entry:
                            bl_entry = ipaddress.ip_address(entry)
                            match = observable_ip == bl_entry
                        #Capture actual network entries
                        else:
                            bl_entry = ipaddress.ip_network(entry,
                                                            strict=False)
                            match = observable_ip in bl_entry

                        #If matched add it to new entries to use outside of the loop
                        if match:
                            self.logger.debug(
                                "Observable {} has matched {} of blacklist. Ignoring..."
                                .format(self.observable['data'], entry))
                            return

                #Trigger a search for the supported ioc
                self.logger.debug(
                    'Launching analyzers for observable: {}'.format(
                        self.observable['_id']))
                self.TheHiveConnector.runAnalyzer(
                    action_config['cortex_instance'],
                    self.supported_observable, action_config['analyzer'])

    def closeCaseForTaxonomyInAnalyzerResults(self, action_config, webhook):
        #If the Job result contains a successful search with minimum of 1 hit, create a task to investigate the results
        if webhook.isCaseArtifactJob() and webhook.isSuccess():
            #Case ID
            self.caseid = webhook.data['rootId']
            #Load Case information
            self.case_data = self.TheHiveConnector.getCase(self.caseid)

            self.logger.debug('Job {} has just finished'.format(
                webhook.data['object']['cortexJobId']))

            #Check if the result count higher than 0
            if webhook.data['object']['report']['summary']['taxonomies'][0][
                    'level'] in action_config["taxonomy_level"]:
                self.logger.info(
                    'Job {} has configured taxonomy level, checking if a task is already present for this observable'
                    .format(webhook.data['object']['cortexJobId']))
                #Check if task is present for investigating the new results
                if self.case_data['status'] != "Resolved":
                    self.logger.info(
                        'Case is not yet closed, closing case for {} now...'.
                        format(webhook.data['object']['cortexJobId']))
                    #Close the case
                    self.TheHiveConnector.closeCase(self.caseid)

        self.report_action = 'closeCase'

        return self.report_action

    def createTaskForTaxonomyinAnalyzerResults(self, action_config, webhook):
        #If the Job result contains a successful search with minimum of 1 hit, create a task to investigate the results
        if webhook.isCaseArtifactJob() and webhook.isSuccess():
            #Case ID
            self.caseid = webhook.data['rootId']
            #Load Case information
            self.case_data = self.TheHiveConnector.getCase(self.caseid)

            self.logger.debug('Job {} has just finished'.format(
                webhook.data['object']['cortexJobId']))

            #Check if the result count higher than 0
            if webhook.data['object']['report']['summary']['taxonomies'][0][
                    'level'] in action_config["taxonomy_level"]:
                self.logger.info(
                    'Job {} has configured taxonomy level, checking if a task is already present for this observable'
                    .format(webhook.data['object']['cortexJobId']))
                #Retrieve case task information
                self.response = self.TheHiveConnector.getCaseTasks(self.caseid)
                self.case_tasks = self.response.json()

                #Load CaseTask template
                self.casetask = CaseTask()

                #Observable + Link
                self.observable = webhook.data['object']['artifactId']
                self.observable_link = self.cfg.get(
                    'Automation', 'hive_url', fallback="https://localhost"
                ) + "/index.html#!/case/" + self.caseid + "/observables/" + webhook.data[
                    'object']['artifactId']

                #Task name
                self.casetask.title = "{} {}".format(action_config['title'],
                                                     self.observable)

                #Date
                self.date_found = time.strftime("%d-%m-%Y %H:%M")

                self.case_task_found = False
                for case_task in self.case_tasks:

                    #Check if task is present for investigating the new results
                    if self.casetask.title == case_task['title']:
                        self.case_task_found = True

                if not self.case_task_found:
                    self.logger.info(
                        'No task found, creating task for observable found in job {}'
                        .format(webhook.data['object']['cortexJobId']))
                    #Add description
                    self.casetask.description = action_config['description']
                    self.casetask.description = self.casetask.description + "\n\n {} is seen on {}\n".format(
                        self.observable_link, self.date_found)

                    #Check if case is closed
                    if self.case_data['status'] == "Resolved":
                        #Create a Case object
                        case = Case()

                        #Add the case id to the object
                        case.id = self.caseid

                        self.logger.info('Updating case %s' % case.id)

                        #Define which fields need to get updated
                        fields = ['status']

                        #Reopen the case
                        case.status = "Open"

                        #Update the case
                        self.TheHiveConnector.updateCase(case, fields)

                    #Add the case task
                    self.TheHiveConnector.createTask(self.caseid,
                                                     self.casetask)

                self.report_action = 'createTask'
                return self.report_action