Пример #1
0
def submitTheHive(message):

    '''
    Create a new case in TheHive based on the email
    Return 'TRUE' is successfully processed otherwise 'FALSE'
    '''

    global log

    # Decode email
    msg = email.message_from_bytes(message)
    decode = email.header.decode_header(msg['From'])[0]
    if decode[1] is not None:
        fromField = decode[0].decode(decode[1])
    else:
        fromField = str(decode[0])
    decode = email.header.decode_header(msg['Subject'])[0]
    if decode[1] is not None:
        subjectField = decode[0].decode(decode[1])
    else:
        subjectField = str(decode[0])
    log.info("From: %s Subject: %s" % (fromField, subjectField))

    attachments = []
    observables = []

    # Extract SMTP headers and search for observables
    parser = HeaderParser()
    headers = parser.parsestr(msg.as_string())
    headers_string = ''
    i = 0
    while  i < len(headers.keys()):
        headers_string = headers_string + headers.keys()[i] + ': ' + headers.values()[i] + '\n'
        i+=1
    # Temporary disabled
    # observables = searchObservables(headers_string, observables)

    body = ''
    for part in msg.walk():
        if part.get_content_type() == "text/plain":
            try:
                body = part.get_payload(decode=True).decode()
            except UnicodeDecodeError:
                body = part.get_payload(decode=True).decode('ISO-8859-1')
            observables.extend(searchObservables(body, observables))
        elif part.get_content_type() == "text/html":
            try:
                html = part.get_payload(decode=True).decode()
            except UnicodeDecodeError:
                html = part.get_payload(decode=True).decode('ISO-8859-1')
            observables.extend(searchObservables(html, observables))
        else:
            # Extract MIME parts
            filename = part.get_filename()
            mimetype = part.get_content_type()
            if filename and mimetype:
                if mimetype in config['caseFiles'] or not config['caseFiles']:
                    log.info("Found attachment: %s (%s)" % (filename, mimetype))
                    # Decode the attachment and save it in a temporary file
                    charset = part.get_content_charset()
                    if charset is None:
                        charset = chardet.detect(bytes(part))['encoding']
                    # Get filename extension to not break TheHive analysers (see Github #11)
                    fname, fextension = os.path.splitext(filename)
                    fd, path = tempfile.mkstemp(prefix=slugify(fname) + "_", suffix=fextension)
                    try:
                        with os.fdopen(fd, 'w+b') as tmp:
                            tmp.write(part.get_payload(decode=1))
                        attachments.append(path)
                    except OSerror as e:
                        log.error("Cannot dump attachment to %s: %s" % (path,e.errno))
                        return False

    # Cleanup observables (remove duplicates)
    new_observables = []
    for o in observables:
        if not {'type': o['type'], 'value': o['value'] } in new_observables:
            # Is the observable whitelisted?
            if isWhitelisted(o['value']):
                log.debug('Skipping whitelisted observable: %s' % o['value'])
            else:
                new_observables.append({ 'type': o['type'], 'value': o['value'] })
                log.debug('Found observable %s: %s' % (o['type'], o['value']))
        else:
            log.info('Ignoring duplicate observable: %s' % o['value'])
    log.info("Removed duplicate observables: %d -> %d" % (len(observables), len(new_observables)))
    observables = new_observables

    api = TheHiveApi(config['thehiveURL'], config['thehiveUser'], config['thehivePassword'], {'http': '', 'https': ''})

    # Search for interesting keywords in subjectField:
    log.debug("Searching for %s in '%s'" % (config['alertKeywords'], subjectField))
    if re.match(config['alertKeywords'], subjectField, flags=0):
        #
        # Add observables found in the mail body
        #
        artifacts = []
        if config['thehiveObservables'] and len(observables) > 0:
            for o in observables:
                artifacts.append(AlertArtifact(dataType=o['type'], data=o['value']))

        #
        # Prepare tags - add alert keywords found to the list of tags
        #
        tags = list(config['alertTags'])
        match = re.findall(config['alertKeywords'], subjectField)
        for m in match:
            tags.append(m)

        #
        # Prepare the alert
        #
        sourceRef = str(uuid.uuid4())[0:6]
        alert = Alert(title=subjectField.replace('[ALERT]', ''),
                      tlp         = int(config['alertTLP']),
                      tags        = tags,
                      description = body,
                      type        = 'external',
                      source      = fromField,
                      sourceRef   = sourceRef,
                      artifacts   = artifacts)

        # Create the Alert
        id = None
        response = api.create_alert(alert)
        if response.status_code == 201:
            log.info('Created alert %s' % response.json()['sourceRef'])
        else:
            log.error('Cannot create alert: %s (%s)' % (response.status_code, response.text))
            return False

    else:
        # Prepare the sample case
        tasks = []
        for task in config['caseTasks']:
             tasks.append(CaseTask(title=task))

        # Prepare the custom fields
        customFields = CustomFieldHelper()\
            .add_string('from', fromField)\
            .add_string('attachment', str(attachments))\
            .build()

        # If a case template is specified, use it instead of the tasks
        if len(config['caseTemplate']) > 0:
            case = Case(title=subjectField,
                        tlp          = int(config['caseTLP']), 
                        flag         = False,
                        tags         = config['caseTags'],
                        description  = body,
                        template     = config['caseTemplate'],
                        customFields = customFields)
        else:
            case = Case(title        = subjectField,
                        tlp          = int(config['caseTLP']), 
                        flag         = False,
                        tags         = config['caseTags'],
                        description  = body,
                        tasks        = tasks,
                        customFields = customFields)

        # Create the case
        id = None
        response = api.create_case(case)
        if response.status_code == 201:
            newID = response.json()['id']
            log.info('Created case %s' % response.json()['caseId'])
            if len(attachments) > 0:
                for path in attachments:
                    observable = CaseObservable(dataType='file',
                        data    = [path],
                        tlp     = int(config['caseTLP']),
                        ioc     = False,
                        tags    = config['caseTags'],
                        message = 'Found as email attachment'
                        )
                    response = api.create_case_observable(newID, observable)
                    if response.status_code == 201:
                        log.info('Added observable %s to case ID %s' % (path, newID))
                        os.unlink(path)
                    else:
                        log.warning('Cannot add observable: %s - %s (%s)' % (path, response.status_code, response.text))
            #
            # Add observables found in the mail body
            #
            if config['thehiveObservables'] and len(observables) > 0:
                for o in observables:
                    observable = CaseObservable(
                        dataType = o['type'],
                        data     = o['value'],
                        tlp      = int(config['caseTLP']),
                        ioc      = False,
                        tags     = config['caseTags'],
                        message  = 'Found in the email body'
                        )
                    response = api.create_case_observable(newID, observable)
                    if response.status_code == 201:
                        log.info('Added observable %s: %s to case ID %s' % (o['type'], o['value'], newID))
                    else:
                         log.warning('Cannot add observable %s: %s - %s (%s)' % (o['type'], o['value'], response.status_code, response.text))
        else:
            log.error('Cannot create case: %s (%s)' % (response.status_code, response.text))
            return False
    return True
Пример #2
0
                 flag=True)
    ]

    #Build TheHive Case with custom fields
    thehive_case = Case(title=offense_desc,
                        tlp=tlp,
                        flag=True,
                        tags=['offense', 'qradar', offense_type_name],
                        description=build_desc,
                        customFields=custom_fields.fields,
                        tasks=tasks)

    print('-------Posting Case with initial values--------')
    case_id = None
    try:
        resp = hive_api.create_case(thehive_case)
        if resp.status_code == 201:
            case_id = resp.json()['id']
            case_num = resp.json()['caseId']
            qr.post_offense_note(offense_id, offense_note.format(case_num))
            sl.insert_record(
                case_table, 'id, case_id, status',
                '"{}","{}","{}"'.format(offense_id, case_id, 'Open'))
            #sl.new_case_record(offense_id, case_id, 'Open')
            logger.info('Case created. Case Id:{} - Case Num:{}'.format(
                case_id, case_num))
    except Exception as err:
        logger.error('Error at case creation.:{}'.format(err))
        sys.exit(1)

    if case_id:
class HiveManagement:
    def __init__(
        self,
        config_file='C:\\automation-hunting\\the-hive\\conf\\thehive-provider.yaml'
    ):

        self.hive_url = None
        self.api_key = None
        self.alert_tags = None
        self.source = None
        self.alert_type = None
        self.case_tags = None
        self.ioc_tags = None

        if not self.get_config_data(config_file):
            raise Exception('Invalid Configuration File')

        self.api = TheHiveApi(self.hive_url, self.api_key)

    def get_config_data(self, yaml_file):
        with open(yaml_file, 'r') as ymlfile:
            cfg = yaml.load(ymlfile, Loader=yaml.FullLoader)

        valid = False
        if self.validate_cfg_yml(cfg):
            self.hive_url = cfg['hive']['hive_url']
            self.api_key = cfg['hive']['api_key']
            self.alert_tags = cfg['hive']['alert_tags']
            self.source = cfg['hive']['source']
            self.alert_type = cfg['hive']['alert_type']
            self.case_tags = cfg['hive']['case_tags']
            self.ioc_tags = cfg['hive']['ioc_tags']
            valid = True
        return valid

    @staticmethod
    def validate_cfg_yml(cfg):
        if 'hive' not in cfg:
            print('Not main')
            return False
        else:
            if 'hive_url' not in cfg['hive'] or 'api_key' not in cfg['hive']:
                return False
        return True

    def create_alarm(self,
                     title,
                     source_ref=None,
                     description='N/A',
                     alert_type='external',
                     source='LogRhythm',
                     iocs=None,
                     additional_fields=None,
                     additional_tags=None,
                     tlp=TLP.AMBER,
                     pap=PAP.AMBER,
                     severity=HiveSeverity.MEDIUM):

        if source_ref is None:
            source_ref = str(uuid.uuid4())[0:6]

        alert_tags = self.alert_tags.copy()
        if additional_tags is not None:
            for additional_tag in additional_tags:
                alert_tags.append(additional_tag)

        custom_fields_helper = CustomFieldHelper()
        if additional_fields is not None:
            for field in additional_fields:
                custom_fields_helper.add_string(field['name'], field['value'])
        custom_fields = custom_fields_helper.build()

        artifacts = list()
        if iocs is not None:
            for ioc in iocs:
                artifacts.append(
                    AlertArtifact(dataType=ioc['type'].value,
                                  data=ioc['value']))

        hive_alert = Alert(title=title,
                           tlp=tlp.value,
                           tags=alert_tags,
                           description=description,
                           type=alert_type,
                           source=source,
                           sourceRef=source_ref,
                           pap=pap.value,
                           artifacts=artifacts,
                           customFields=custom_fields,
                           severity=severity.value)

        response = self.api.create_alert(hive_alert)
        if response.status_code == 201:
            print('Alerta Creada Exitosamente')
            print(json.dumps(response.json(), indent=4, sort_keys=True))
        else:
            print('Error')
            print(response.text)

        return response.json()

    def create_case(self,
                    title,
                    tasks=None,
                    tlp=TLP.AMBER,
                    pap=PAP.AMBER,
                    severity=HiveSeverity.MEDIUM,
                    additional_fields=None,
                    additional_tags=None,
                    flag=False,
                    description='N/A'):

        case_tags = self.case_tags.copy()
        if additional_tags is not None:
            for additional_tag in additional_tags:
                case_tags.append(additional_tag)

        custom_fields_helper = CustomFieldHelper()
        if additional_fields is not None:
            for field in additional_fields:
                custom_fields_helper.add_string(field['name'], field['value'])
        custom_fields = custom_fields_helper.build()

        new_tasks = list()
        if tasks is not None:
            for task in tasks:
                new_tasks.append(CaseTask(title=task))

        hive_case = Case(title=title,
                         tlp=tlp.value,
                         pap=pap.value,
                         description=description,
                         tags=case_tags,
                         severity=severity.value,
                         flag=flag,
                         customFields=custom_fields,
                         tasks=new_tasks)

        response = self.api.create_case(hive_case)
        if response.status_code == 201:
            print('Caso Creada Exitosamente')
            print(json.dumps(response.json(), indent=4, sort_keys=True))
        else:
            print('Error')
            print(response.text)

        return response.json()

    def create_case_observable(self,
                               data_type: HiveDataType,
                               value: list,
                               tlp=TLP.AMBER,
                               ioc=True,
                               additional_tags=None,
                               description='LogRhythm IoC'):

        ioc_tags = self.ioc_tags.copy()
        if additional_tags is not None:
            for additional_tag in additional_tags:
                ioc_tags.append(additional_tag)

        hive_observable = CaseObservable(data_type=data_type.value,
                                         data=value,
                                         tlp=tlp.value,
                                         ioc=ioc,
                                         tags=ioc_tags,
                                         message=description)

        return hive_observable

    def add_observable_to_case(self, case_id, observable: CaseObservable):
        response = self.api.create_case_observable(case_id, observable)
        if response.status_code == 201:
            print('Observable successfully added to the case')
            print(json.dumps(response.json(), indent=4, sort_keys=True))
        else:
            print('Error')
            print(response.text)

    def search_case(self,
                    title=None,
                    tlp: TLP = None,
                    pap: PAP = None,
                    severity: HiveSeverity = None,
                    or_operator=False):
        if title is None and tlp is None and pap is None and severity is None:
            print('Can\'t search without a filter')
            return None

        operators = list()
        if title is not None:
            operators.append(String('title: ' + urllib.parse.quote(title)))
        if tlp is not None:
            operators.append(Gte('tlp', tlp.value))
        if pap is not None:
            operators.append(Gte('pap', pap.value))
        if severity is not None:
            operators.append(Gte('severity', severity.value))

        if len(operators) == 1:
            query = operators[0]
        else:
            if or_operator:
                query = Or(operators)
            else:
                query = And(operators)

        response = self.api.find_cases(query=query, range='all', sort=[])
        if response.status_code == 200:
            print('Busqueda correcta')
            print(json.dumps(response.json(), indent=4, sort_keys=True))
        else:
            print('Error')
            print(response.text)

        return response.json()

    def promote_alert(self, alert_id):
        response = self.api.promote_alert_to_case(alert_id)
        if response.status_code == 201:
            print('Correct Promotion')
            print(json.dumps(response.json(), indent=4, sort_keys=True))
        else:
            print('Error')
            print(response.text)

        return response.json()