Пример #1
0
def create_thehive_alerts(config, alerts):
    """
    :param config: TheHive config
    :type config: dict
    :param alerts: List of alerts
    :type alerts: list
    :return: create TH alert
    """

    thapi = TheHiveApi(config.get('url', None), config.get('key'),
                       config.get('password', None), config.get('proxies'))
    for a in alerts:
        thapi.create_alert(a)
Пример #2
0
def send_thehive_message(rule, message, asset, description):
    print("send_thehive_message:", rule, message, asset, description)
    thehive_url = Setting.objects.get(key="alerts.endpoint.thehive.url")
    thehive_apikey = Setting.objects.get(key="alerts.endpoint.thehive.apikey")
    alert_message = "[Alert][Rule={}]{}".format(rule.title, message)

    api = TheHiveApi(thehive_url.value, thehive_apikey.value)
    sourceRef = str(uuid.uuid4())[0:6]
    rule_severity = 0
    if rule.severity == "Low":
        rule_severity = 1
    elif rule.severity == "Medium":
        rule_severity = 2
    elif rule.severity == "High":
        rule_severity = 3

    tlp = 0
    if asset.criticity == "low":
        tlp = 1
    elif asset.criticity == "medium":
        tlp = 2
    elif asset.criticity == "high":
        tlp = 3

    if asset:
        artifacts = [AlertArtifact(dataType=asset.type, data=asset.value)]
        try:
            alert = Alert(
                        title=alert_message,
                        tlp=tlp,
                        severity=rule_severity,
                        tags=['src:PatrOwl'],
                        description=description,
                        type='external',
                        source='patrowl',
                        sourceRef=sourceRef,
                        artifacts=artifacts)

            response = api.create_alert(alert)

            if response.status_code == 201:
                alert_id = response.json()['id']
                # todo: track theHive alerts
                Event.objects.create(
                    message="[Rule][send_thehive_message()] "
                    "Alert sent to TheHive with message '{}' (alert id: {})".format(message, alert_id),
                    type="DEBUG", severity="DEBUG"
                )
            else:
                Event.objects.create(
                    message="[Rule][send_thehive_message()] Unable to send "
                    "alert to TheHive with message ='{}'".format(message),
                    type="ERROR", severity="ERROR"
                )
        except Exception:
            Event.objects.create(
                message="[Rule][send_thehive_message()] Unable to send alert "
                "to TheHive with message ='{}'".format(message),
                type="ERROR", severity="ERROR")
Пример #3
0
    def alert(self, matches):

        connection_details = self.rule['hive_connection']

        api = TheHiveApi(
            '{hive_host}:{hive_port}'.format(**connection_details),
            connection_details.get('hive_apikey',''),
            proxies=connection_details.get('hive_proxies', {'http': '', 'https': ''}),
            cert=connection_details.get('hive_verify', False))

        for match in matches:
            context = {'rule': self.rule, 'match': match}

            artifacts = []
            for mapping in self.rule.get('hive_observable_data_mapping', []):
                for observable_type, match_data_key in mapping.iteritems():
                    try:
                        match_data_keys = re.findall(r'\{match\[([^\]]*)\]', match_data_key)
                        if all([True for k in match_data_keys if k in context['match']]):
                            artifacts.append(AlertArtifact(dataType=observable_type, data=match_data_key.format(**context)))
                    except KeyError:
                        raise KeyError('\nformat string\n{}\nmatch data\n{}'.format(match_data_key, context))

            alert_config = {
                'artifacts': artifacts,
                'sourceRef': str(uuid.uuid4())[0:6],
                'title': '{rule[name]}'.format(**context)
            }
            alert_config.update(self.rule.get('hive_alert_config', {}))

            for alert_config_field, alert_config_value in alert_config.iteritems():
                if alert_config_field == 'customFields':
                    custom_fields = CustomFieldHelper()
                    for cf_key, cf_value in alert_config_value.iteritems():
                        try:
                            func = getattr(custom_fields, 'add_{}'.format(cf_value['type']))
                        except AttributeError:
                            raise Exception('unsupported custom field type {}'.format(cf_value['type']))
                        value = cf_value['value'].format(**context)
                        func(cf_key, value)
                    alert_config[alert_config_field] = custom_fields.build()
                elif isinstance(alert_config_value, basestring):
                    alert_config[alert_config_field] = alert_config_value.format(**context)
                elif isinstance(alert_config_value, (list, tuple)):
                    formatted_list = []
                    for element in alert_config_value:
                        try:
                            formatted_list.append(element.format(**context))
                        except:
                            formatted_list.append(element)
                    alert_config[alert_config_field] = formatted_list

            alert = Alert(**alert_config)

            response = api.create_alert(alert)

            if response.status_code != 201:
                raise Exception('alert not successfully created in TheHive\n{}'.format(response.text))
    def send_to_thehive(self, alert_config):
        connection_details = self.rule['hive_connection']
        api = TheHiveApi(
            '{hive_host}:{hive_port}'.format(**connection_details),
            connection_details.get('hive_apikey', ''),
            proxies=connection_details.get('hive_proxies', {'http': '', 'https': ''}),
            cert=connection_details.get('hive_verify', False))

        alert = Alert(**alert_config)
        response = api.create_alert(alert)

        if response.status_code != 201:
            raise Exception('alert not successfully created in TheHive\n{}'.format(response.text))
Пример #5
0
def sendHiveAlert(title, tlp, tags, description, sourceRef, artifact_string):

  hive_url = parser.get('hive', 'hive_url')
  hive_key = parser.get('hive', 'hive_key')
  hive_verifycert = parser.get('hive', 'hive_verifycert')
  tlp = int(parser.get('hive', 'hive_tlp'))

  # Check if verifying cert
  if 'False' in hive_verifycert:
        hiveapi = TheHiveApi(hive_url, hive_key, cert=False)
  else:
        hiveapi = TheHiveApi(hive_url, hive_key, cert=True)

  newtags = tags.strip('][').replace("'","").split(', ')

  artifacts = json.loads(artifact_string)

  #print(newtags)
  # Build alert
  hivealert = Alert(
     title= title,
     tlp=tlp,
     tags=newtags,
     description=description,
     type='external',
     source='SecurityOnion',
     sourceRef=sourceRef,
     artifacts=artifacts
  )

  # Send it off
  response = hiveapi.create_alert(hivealert)
  if response.status_code == 201:
              print(json.dumps(response.json(), indent=4, sort_keys=True))
              print('')
              id = response.json()['id']

              # If running standalone / eval tell ES that we sent the alert
              #es_type = 'doc'
              #es_index = index
              #es_headers = {'Content-Type' : 'application/json'}
              #es_data = '{"script" : {"source": "ctx._source.tags.add(params.tag)","lang": "painless","params" : {"tag" : "Sent to TheHive"}}}'
              #update_es_event = requests.post(es_url + '/' + es_index + '/' + es_type + '/' + esid +  '/_update', headers=es_headers, data=es_data)
              #print(update_es_event.content)

  else:
              print('ko: {}/{}'.format(response.status_code, response.text))
              sys.exit(0)

  # Redirect to TheHive instance
  return redirect(hive_url + '/index.html#!/alert/list')
Пример #6
0
def create_thehive_alerts(config, alerts):
    """
    :param config: TheHive config
    :type config: dict
    :param alerts: List of alerts
    :type alerts: list
    :return: create TH alert
    """

    thapi = TheHiveApi(config.get('url', None), config.get('key'),
                       config.get('password', None), config.get('proxies'))

    response = thapi.create_alert(alerts)
    if response.status_code == 201:
        print(json.dumps(response.json(), indent=4, sort_keys=True))
    else:
        print('ko: {}/{}'.format(response.status_code, response.text))
Пример #7
0
def prepare_alert(subject, indicatorlevel, emailbody, alerttype, tag):

    hive_address = ''.join(settings.stored_hive_address[0])
    hive_api = ''.join(settings.stored_api_key[0])

    #Define the connection to thehive installation (including the generated API key).
    api = TheHiveApi(hive_address, hive_api, None, {'http': '', 'https': ''})

    # Prepare the sample Alert

    print("Preparing the alert for", alerttype)
    sourceRef = str(uuid.uuid4())[0:6]
    alert = Alert(title=subject,
                  tlp=indicatorlevel,
                  tags=[tag],
                  description=emailbody,
                  type=alerttype,
                  source='instance1',
                  sourceRef=sourceRef,
                  artifacts="")

    # Create the Alert
    print('Create Alert')
    print('-----------------------------')
    id = None
    response = api.create_alert(alert)
    if response.status_code == 201:
        print("Alert created sucessfully!")
        #    		print(json.dumps(response.json(), indent=4, sort_keys=True))
        #    		print('')
        id = response.json()['id']
    else:
        print("Unable to create alert")
        #   		print('ko: {}/{}'.format(response.status_code, response.text))
        sys.exit(0)

# Get all the details of the created alert
    print('Get created alert {}'.format(id))
    print('-----------------------------')
    response = api.get_alert(id)
    if response.status_code == requests.codes.ok:
        #    		print(json.dumps(response.json(), indent=4, sort_keys=True))
        print('')
    else:
        print("Error retreiving the alert!")
        print('ko: {}/{}'.format(response.status_code, response.text))
    def alert(self, matches):

        connection_details = self.rule['hive_connection']
        api = TheHiveApi(
            '{hive_host}:{hive_port}'.format(**connection_details),
            '{hive_username}'.format(**connection_details),
            '{hive_password}'.format(**connection_details),
            connection_details.get('hive_proxies', {'http': '', 'https': ''}))

        for match in matches:
            context = {'rule': self.rule, 'match': match}

            artifacts = []
            for mapping in self.rule.get('hive_observable_data_mapping', []):
                for observable_type, match_data_key in mapping.iteritems():
                    try:
                        artifacts.append(AlertArtifact(dataType=observable_type, data=match_data_key.format(**context)))
                    except KeyError:
                        raise KeyError('\nformat string\n{}\nmatch data\n{}'.format(match_data_key, context))

            alert_config = {
                'artifacts': artifacts,
                'sourceRef': str(uuid.uuid4())[0:6],
                'title': '{rule[index]}_{rule[name]}'.format(**context)
            }
            alert_config.update(self.rule.get('hive_alert_config', {}))

            for alert_config_field, alert_config_value in alert_config.iteritems():
                if isinstance(alert_config_value, basestring):
                    alert_config[alert_config_field] = alert_config_value.format(**context)
                elif isinstance(alert_config_value, (list, tuple)):
                    formatted_list = []
                    for element in alert_config_value:
                        try:
                            formatted_list.append(element.format(**context))
                        except:
                            formatted_list.append(element)
                    alert_config[alert_config_field] = formatted_list

            alert = Alert(**alert_config)

            response = api.create_alert(alert)

            if response.status_code != 201:
                raise Exception('alert not successfully created in TheHive\n{}'.format(response.text))
Пример #9
0
def create_th_alerts(config, alerts):
    """
    :param config: TheHive config
    :type config: dict
    :param alerts: List of alerts
    :type alerts: list
    :return: create TH alert
    """
    thapi = TheHiveApi(config.get('url', None),
                       config.get('key'),
                       config.get('password', None),
                       config.get('proxies'))
    for a in alerts:
        response = thapi.create_alert(a)
        logging.debug('API TheHive - status code: {}'.format(
            response.status_code))
        if response.status_code > 299:
            logging.debug('API TheHive - raw error output: {}'.format(
                response.raw.read()))
Пример #10
0
def create_alert():

    # Get request JSON
    content = request.get_json()

    # Configure logging
    logging.basicConfig(
        filename=app.config['LOG_FILE'],
        filemode='a',
        format='%(asctime)s - graylog2thehive - %(levelname)s - %(message)s',
        level=logging.INFO)
    logging.info(json.dumps(content))

    # Configure API
    api = TheHiveApi(app.config['HIVE_URL'], app.config['API_KEY'])

    # Configure artifacts
    artifacts = []

    # Configure tags
    tags = ['graylog']

    # Build description body and tags list
    description = 'Alert Condition: \n' + content['check_result'][
        'triggered_condition']['title'] + '\n\nMatching messages:\n\n'
    tags = ['graylog']
    for message in content['check_result']['matching_messages']:

        description = description + "\n\n---\n\n**Source:** " + message[
            'source'] + "\n\n**Log URL:** " + app.config[
                'GRAYLOG_URL'] + "/messages/" + message[
                    'index'] + "/" + message['id'] + "\n\n"

        message_flattened = flatten_dict(message)
        for key in message_flattened.keys():
            if key != "message" and key != "source":
                description = description + "\n**" + key + ":** " + json.dumps(
                    message_flattened[key], ensure_ascii=False) + "\n"

            # Use any IPs, hashes, URLs, filenames, etc here in place of src_ip and dst_ip to include them as artifacts/observables in your alert
            if key == "cmd_url2":
                artifacts.append(
                    AlertArtifact(dataType='url',
                                  tags=[key],
                                  data=message_flattened[key]))
            if key == "dest_ip":
                artifacts.append(
                    AlertArtifact(dataType='ip',
                                  tags=[key],
                                  data=message_flattened[key]))
            if key == "MD5" or key == "SHA256":
                artifacts.append(
                    AlertArtifact(dataType='hash',
                                  tags=[key],
                                  data=message_flattened[key]))
        description = description + '\n\n**Raw Message:** \n\n```\n' + json.dumps(
            message) + '\n```\n---\n'

    # Prepare alert
    sourceRef = str(uuid.uuid4())[0:6]
    alert = Alert(title="Graylog Alert: " + content['stream']['title'] +
                  " - " + content['check_result']['result_description'],
                  tlp=2,
                  tags=tags,
                  description=content['check_result']['result_description'],
                  type='external',
                  source='graylog',
                  artifacts=artifacts,
                  sourceRef=sourceRef)

    # Create the alert
    print('Create Alert')
    print('-----------------------------')
    id = None
    response = api.create_alert(alert)
    if response.status_code == 201:
        logging.info(json.dumps(response.json(), indent=4, sort_keys=True))
        print(json.dumps(response.json(), indent=4, sort_keys=True))
        print('')
        id = response.json()['id']
    else:
        print('ko: {}/{}'.format(response.status_code, response.text))
        sys.exit(0)

    return content['check_result']['result_description']
Пример #11
0
def createGRRFlow(esid, flow_name):
    search = getHits(esid)

    tlp = int(parser.get('hive', 'hive_tlp'))

    # Check if verifying cert
    if 'False' in hive_verifycert:
        hiveapi = TheHiveApi(hive_url, hive_key, cert=False)
    else:
        hiveapi = TheHiveApi(hive_url, hive_key, cert=True)

    grr_url = parser.get('grr', 'grr_url')
    grr_user = parser.get('grr', 'grr_user')
    grr_pass = parser.get('grr', 'grr_pass')
    grrapi = api.InitHttp(api_endpoint=grr_url, auth=(grr_user, grr_pass))

    base64string = '%s:%s' % (grr_user, grr_pass)
    base64string = base64.b64encode(bytes(base64string, "utf-8"))
    authheader = "Basic %s" % base64string
    index_response = requests.get(grr_url,
                                  auth=HTTPBasicAuth(grr_user, grr_pass))
    csrf_token = index_response.cookies.get("csrftoken")
    headers = {
        "Authorization": authheader,
        "x-csrftoken": csrf_token,
        "x-requested-with": "XMLHttpRequest"
    }
    cookies = {"csrftoken": csrf_token}

    for result in search['hits']['hits']:
        result = result['_source']
        message = result['message']
        description = str(message)
        info = description

        if 'source_ip' in result:
            source_ip = result['source_ip']

        if 'destination_ip' in result:
            destination_ip = result['destination_ip']

        for ip in source_ip, destination_ip:
            search_result = grrapi.SearchClients(ip)
            grr_result = {}
            client_id = ''
            for client in search_result:
                # Get client id
                client_id = client.client_id
                client_last_seen_at = client.data.last_seen_at
                grr_result[client_id] = client_last_seen_at
                #flow_name = "ListProcesses"
                if client_id is None:
                    pass

                # Process flow and get flow id
                flow_id = listProcessFlow(client_id, grr_url, headers, cookies,
                                          grr_user, grr_pass)

                # Get status
                status = checkFlowStatus(client_id, grr_url, flow_id, headers,
                                         cookies, grr_user, grr_pass)

                # Keep checking to see if complete
                while status != "terminated":
                    time.sleep(15)
                    print(
                        "Flow not yet completed..watiing 15 secs before attempting to check status again..."
                    )
                    status = checkFlowStatus(client_id, grr_url, flow_id,
                                             headers, cookies, grr_user,
                                             grr_pass)

                # If terminated, run the download
                if status == "terminated":
                    downloadFlowResults(client_id, grr_url, flow_id, headers,
                                        cookies, grr_user, grr_pass)
                #print("Done!")

                # Run flow via API client
                #flow_obj = grrapi.Client(client_id)
                #flow_obj.CreateFlow(name=flow_name)
                title = "Test Alert with GRR Flow"
                description = str(message)
                sourceRef = str(uuid.uuid4())[0:6]
                tags = ["SecurityOnion", "GRR"]
                artifacts = []
                id = None
                filepath = "/tmp/soctopus/" + client_id + ".zip"
                artifacts.append(
                    AlertArtifact(dataType='file', data=str(filepath)))

                # Build alert
                hivealert = Alert(title=title,
                                  tlp=tlp,
                                  tags=tags,
                                  description=description,
                                  type='external',
                                  source='SecurityOnion',
                                  sourceRef=sourceRef,
                                  artifacts=artifacts)

                # Send it off
                response = hiveapi.create_alert(hivealert)

            if client_id:
                # Redirect to GRR instance
                return redirect(grr_url + '/#/clients/' + client_id + '/flows')
            else:
                return "No matches found for source or destination ip"
Пример #12
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']
                    fd, path = tempfile.mkstemp(prefix=slugify(filename) + "_")
                    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

    if config['thehiveAuthMethod'] == 'APIKey':
        api = TheHiveApi(config['thehiveURL'], config['thehiveAPIKey'], None, {
            'http': '',
            'https': ''
        })
    else:
        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:
Пример #13
0
def submitTheHive(message):
    '''Create a new case in TheHive based on the email'''

    # Decode email
    msg = email.message_from_bytes(message)
    decode = email.header.decode_header(msg['From'])[0]
    fromField = str(decode[0])
    decode = email.header.decode_header(msg['Subject'])[0]
    subjectField = str(decode[0])
    if args.verbose:
        print("[INFO] From: %s Subject: %s" % (fromField, subjectField))
    attachments = []
    body = ''
    for part in msg.walk():
        if part.get_content_type() == "text/plain":
            body = part.get_payload(decode=True).decode()
        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']:
                    print("[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']
                    fd, path = tempfile.mkstemp(prefix=slugify(filename) + "_")
                    try:
                        with os.fdopen(fd, 'w+b') as tmp:
                            tmp.write(part.get_payload(decode=1))
                        attachments.append(path)
                    except OSError as e:
                        print("[ERROR] Cannot dump attachment to %s: %s" %
                              (path, e.errno))

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

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

        # Create the Alert
        id = None
        response = api.create_alert(alert)
        if response.status_code == 201:
            if args.verbose:
                print('[INFO] Created alert %s' % response.json()['sourceRef'])
        else:
            print('[ERROR] Cannot create alert: %s (%s)' %
                  (response.status_code, response.text))
            sys.exit(0)

    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()

        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']
            if args.verbose:
                print('[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='Created by imap2thehive.py')
                    response = api.create_case_observable(newID, observable)
                    if response.status_code == 201:
                        if args.verbose:
                            print('[INFO] Added observable %s to case ID %s' %
                                  (path, newID))
                            os.unlink(path)
                    else:
                        print('[ERROR] Cannot add observable: %s - %s (%s)' %
                              (path, response.status_code, response.text))
                        sys.exit(0)
        else:
            print('[ERROR] Cannot create case: %s (%s)' %
                  (response.status_code, response.text))
            sys.exit(0)
    return
Пример #14
0
class TheHive(AppBase):
    """
    An example of a Walkoff App.
    Inherit from the AppBase class to have Redis, logging, and console logging set up behind the scenes.
    """

    __version__ = "1.0.0"
    app_name = "thehive"

    def __init__(self, redis, logger, console_logger=None):
        """
        Each app should have this __init__ to set up Redis and logging.
        :param redis:
        :param logger:
        :param console_logger:
        """
        super().__init__(redis, logger, console_logger)

    # async def run_analyzer(self, apikey, url, title_query):
    #    self.thehive = TheHiveApi(url, apikey, cert=False)

    #    response = self.thehive.find_cases(query=String("title:'%s'" % title_query), range='all', sort=[])
    #    return response.text

    async def search_cases(self, apikey, url, title_query):
        self.thehive = TheHiveApi(url, apikey, cert=False)

        response = self.thehive.find_cases(query=ContainsString(
            "title", title_query),
                                           range="all",
                                           sort=[])
        return response.text

    async def search_query(self, apikey, url, search_for, custom_query):
        self.thehive = TheHiveApi(url, apikey, cert=False)

        try:
            query = json.loads(custom_query)
        except:
            raise IOError("Invalid JSON payload received.")

        if search_for == "alert":
            response = self.thehive.find_alerts(query=query,
                                                range="all",
                                                sort=[])
        else:
            response = self.thehive.find_cases(query=query,
                                               range="all",
                                               sort=[])

        if response.status_code == 200:
            return response.text
        else:
            raise IOError(response.text)

    async def add_observable(self, apikey, url, case_id, data, datatype, tags):
        self.thehive = TheHiveApi(url, apikey, cert=False)

        if tags:
            if ", " in tags:
                tags = tags.split(", ")
            elif "," in tags:
                tags = tags.split(",")
            else:
                tags = [tags]
        else:
            tags = []

        item = thehive4py.models.CaseObservable(
            dataType=datatype,
            data=data,
            tlp=1,
            ioc=False,
            sighted=False,
            tags=["Shuffle"],
            message="Created by shuffle",
        )

        return self.thehive.create_case_observable(case_id, item).text

    async def search_alerts(self,
                            apikey,
                            url,
                            title_query,
                            search_range="0-25"):
        self.thehive = TheHiveApi(url, apikey, cert=False)

        # Could be "all" too
        if search_range == "":
            search_range = "0-25"

        response = self.thehive.find_alerts(query=ContainsString(
            "title", title_query),
                                            range=search_range,
                                            sort=[])
        return response.text

    async def create_case(self,
                          apikey,
                          url,
                          title,
                          description="",
                          tlp=1,
                          severity=1,
                          tags=""):
        self.thehive = TheHiveApi(url, apikey, cert=False)
        if tags:
            if ", " in tags:
                tags = tags.split(", ")
            elif "," in tags:
                tags = tags.split(",")
            else:
                tags = [tags]
        else:
            tags = []

        # Wutface fix
        if not tlp:
            tlp = 1
        if not severity:
            severity = 1

        if isinstance(tlp, str):
            if not tlp.isdigit():
                return "TLP needs to be a number from 0-2, not %s" % tlp
            tlp = int(tlp)
        if isinstance(severity, str):
            if not severity.isdigit():
                return "Severity needs to be a number from 0-2, not %s" % tlp

            severity = int(severity)

        if tlp > 3 or tlp < 0:
            return "TLP needs to be a number from 0-3, not %d" % tlp
        if severity > 2 or severity < 0:
            return "Severity needs to be a number from 0-2, not %d" % tlp

        case = thehive4py.models.Case(
            title=title,
            tlp=tlp,
            severity=severity,
            tags=tags,
            description=description,
        )

        try:
            ret = self.thehive.create_case(case)
            return ret.text
        except requests.exceptions.ConnectionError as e:
            return "ConnectionError: %s" % e

    async def create_alert(
        self,
        apikey,
        url,
        type,
        source,
        sourceref,
        title,
        description="",
        tlp=1,
        severity=1,
        tags="",
    ):
        self.thehive = TheHiveApi(url, apikey, cert=False)
        if tags:
            if ", " in tags:
                tags = tags.split(", ")
            elif "," in tags:
                tags = tags.split(",")
            else:
                tags = [tags]
        else:
            tags = []

        # Wutface fix
        if not tlp:
            tlp = 1
        if not severity:
            severity = 1

        if isinstance(tlp, str):
            if not tlp.isdigit():
                return "TLP needs to be a number from 0-3, not %s" % tlp

            tlp = int(tlp)
        if isinstance(severity, str):
            if not severity.isdigit():
                return "Severity needs to be a number from 1-3, not %s" % severity

            severity = int(severity)

        if tlp > 3 or tlp < 0:
            return "TLP needs to be a number from 0-3, not %d" % tlp
        if severity > 3 or severity < 1:
            return "Severity needs to be a number from 1-3, not %d" % severity

        alert = thehive4py.models.Alert(
            title=title,
            tlp=tlp,
            severity=severity,
            tags=tags,
            description=description,
            type=type,
            source=source,
            sourceRef=sourceref,
        )

        try:
            ret = self.thehive.create_alert(alert)
            return ret.text
        except requests.exceptions.ConnectionError as e:
            return "ConnectionError: %s" % e

    async def create_alert_artifact(self,
                                    apikey,
                                    url,
                                    alert_id,
                                    dataType,
                                    data,
                                    message=None,
                                    tlp="2",
                                    ioc="False",
                                    sighted="False",
                                    ignoreSimilarity="False",
                                    tags=None):
        self.thehive = TheHiveApi(url, apikey, cert=False, version=4)

        if tlp:
            tlp = int(tlp)
        else:
            tlp = 2

        ioc = ioc.lower().strip() == "true"
        sighted = sighted.lower().strip() == "true"
        ignoreSimilarity = ignoreSimilarity.lower().strip() == "true"

        if tags:
            tags = [x.strip() for x in tags.split(",")]
        else:
            tags = []

        alert_artifact = thehive4py.models.AlertArtifact(
            dataType=dataType,
            data=data,
            message=message,
            tlp=tlp,
            ioc=ioc,
            sighted=sighted,
            ignoreSimilarity=ignoreSimilarity,
            tags=tags)

        try:
            ret = self.thehive.create_alert_artifact(alert_id, alert_artifact)
        except requests.exceptions.ConnectionError as e:
            return "ConnectionError: %s" % e
        if ret.status_code > 299:
            raise ConnectionError(ret.text)

        return ret.text

    # Gets an item based on input. E.g. field_type = Alert
    async def get_item(self, apikey, url, field_type, cur_id):
        self.thehive = TheHiveApi(url, apikey, cert=False)

        newstr = ""
        ret = ""
        if field_type.lower() == "alert":
            ret = self.thehive.get_alert(cur_id + "?similarity=1")
        elif field_type.lower() == "case":
            ret = self.thehive.get_case(cur_id)
        elif field_type.lower() == "case_observables":
            ret = self.thehive.get_case_observables(cur_id)
        elif field_type.lower() == "case_task":
            ret = self.thehive.get_case_task(cur_id)
        elif field_type.lower() == "case_tasks":
            ret = self.thehive.get_case_tasks(cur_id)
        elif field_type.lower() == "case_template":
            ret = self.thehive.get_case_tasks(cur_id)
        elif field_type.lower() == "linked_cases":
            ret = self.thehive.get_linked_cases(cur_id)
        elif field_type.lower() == "task_log":
            ret = self.thehive.get_task_log(cur_id)
        elif field_type.lower() == "task_logs":
            ret = self.thehive.get_task_logs(cur_id)
        else:
            return (
                "%s is not implemented. See https://github.com/frikky/shuffle-apps for more info."
                % field_type)

        return ret.text

    async def close_alert(self, apikey, url, alert_id):
        self.thehive = TheHiveApi(url, apikey, cert=False)
        return self.thehive.mark_alert_as_read(alert_id).text

    async def reopen_alert(self, apikey, url, alert_id):
        self.thehive = TheHiveApi(url, apikey, cert=False)
        return self.thehive.mark_alert_as_unread(alert_id).text

    async def create_case_from_alert(self,
                                     apikey,
                                     url,
                                     alert_id,
                                     case_template=None):
        self.thehive = TheHiveApi(url, apikey, cert=False)
        response = self.thehive.promote_alert_to_case(
            alert_id=alert_id, case_template=case_template)
        return response.text

    async def merge_alert_into_case(self, apikey, url, alert_id, case_id):
        self.thehive = TheHiveApi(url, apikey, cert=False)
        req = url + f"/api/alert/{alert_id}/merge/{case_id}"
        ret = requests.post(req, auth=self.thehive.auth)
        return ret.text

    # Not sure what the data should be
    async def update_field(self, apikey, url, field_type, cur_id, field, data):
        # This is kinda silly but..
        if field_type.lower() == "alert":
            newdata = {}

            if data.startswith("%s"):
                ticket = self.thehive.get_alert(cur_id)
                if ticket.status_code != 200:
                    pass

                newdata[field] = "%s%s" % (ticket.json()[field], data[2:])
            else:
                newdata[field] = data

            # Bleh
            url = "%s/api/alert/%s" % (url, cur_id)
            if field == "status":
                if data == "New" or data == "Updated":
                    url = "%s/markAsUnread" % url
                elif data == "Ignored":
                    url = "%s/markAsRead" % url

                ret = requests.post(
                    url,
                    headers={
                        "Content-Type": "application/json",
                        "Authorization": "Bearer %s" % apikey,
                    },
                )
            else:
                ret = requests.patch(
                    url,
                    headers={
                        "Content-Type": "application/json",
                        "Authorization": "Bearer %s" % apikey,
                    },
                    json=newdata,
                )

            return str(ret.status_code)
        else:
            return (
                "%s is not implemented. See https://github.com/frikky/walkoff-integrations for more info."
                % field_type)

    # https://github.com/TheHive-Project/TheHiveDocs/tree/master/api/connectors/cortex
    async def run_analyzer(self, apikey, url, cortex_id, analyzer_id,
                           artifact_id):
        self.thehive = TheHiveApi(url, apikey, cert=False)
        return self.thehive.run_analyzer(cortex_id, artifact_id,
                                         analyzer_id).text

    # Creates a task log in TheHive with file
    async def create_task_log(self,
                              apikey,
                              url,
                              task_id,
                              message,
                              filedata={}):
        if filedata["success"] == False:
            return "No file to upload. Skipping message."

        headers = {
            "Authorization": "Bearer %s" % apikey,
        }

        files = {}
        if len(filedata["data"]) > 0:
            files = {
                "attachment": (filedata["filename"], filedata["data"]),
            }

        data = {"_json": """{"message": "%s"}""" % message}
        response = requests.post(
            "%s/api/case/task/%s/log" % (url, task_id),
            headers=headers,
            files=files,
            data=data,
        )
        return response.text

    # Creates an observable as a file in a case
    async def create_case_file_observable(self, apikey, url, case_id, tags,
                                          filedata):
        if filedata["success"] == False:
            return "No file to upload. Skipping message."

        headers = {
            "Authorization": "Bearer %s" % apikey,
        }

        if tags:
            if ", " in tags:
                tags = tags.split(", ")
            elif "," in tags:
                tags = tags.split(",")
            else:
                tags = [tags]

        files = {}
        if len(filedata["data"]) > 0:
            files = {
                "attachment": (filedata["filename"], filedata["data"]),
            }

        outerarray = {"dataType": "file", "tags": tags}
        data = {"_json": """%s""" % json.dumps(outerarray)}
        response = requests.post(
            "%s/api/case/%s/artifact" % (url, case_id),
            headers=headers,
            files=files,
            data=data,
        )
        return response.text
Пример #15
0
def create_alert():

    # Get request data
    body = request.form.get('body-plain')
    headers = request.form.get('message-headers')
    subject = request.form.get('subject')
    sender = request.form.get('sender')
    recipient = request.form.get('recipient')

    # Configure logging
    logging.basicConfig(filename=app.config['LOG_FILE'], filemode='a', format='%(asctime)s - mailgun2thehive - %(levelname)s - %(message)s', level=logging.INFO)
    logging.info(json.dumps(subject))

    # Configure API
    api = TheHiveApi(app.config['HIVE_URL'], app.config['API_KEY'])

    # Configure artifacts
    artifacts = []

    # Get attachments, if any
    for key in request.files:
        file = request.files[key]
        logging.info(key)

        file.save(key)
        artifacts.append(AlertArtifact(dataType='file', tags=[key], data=key))

    # Tags list
    tags=['mailgun']

    # Prepare alert
    sourceRef = str(uuid.uuid4())[0:6]
    alert = Alert(title="Mailgun - " + sender + " - " + subject,
                  tlp=2,
                  tags=tags,
                  description="**Email body:**\n\n"+body+"\n\n**Message Headers:**\n\n"+headers,
                  type='external',
                  source='mailgun',
                  artifacts=artifacts,
                  sourceRef=sourceRef)

    # Create the alert
    print('Create Alert')
    print('-----------------------------')
    id = None
    response = api.create_alert(alert)
    if response.status_code == 201:
        logging.info(json.dumps(response.json(), indent=4, sort_keys=True))
        print(json.dumps(response.json(), indent=4, sort_keys=True))
        print('')
        id = response.json()['id']
    else:
        print('ko: {}/{}'.format(response.status_code, response.text))
        sys.exit(0)

    # Delete attachments, if any
    for key in request.files:
        os.remove(key)

    # Return
    return "Hive Alert Created"
Пример #16
0
def send_thehive_message(rule, message, asset, description):
    mess = "[Rule] Rule '{}' TheHive alert creation (asset={})".format(
        rule, asset)
    Event.objects.create(message=mess, type="CREATE", severity="DEBUG")
    AuditLog.objects.create(message=mess,
                            scope='rule',
                            type='rule_send_thehive',
                            request_context=inspect.stack())

    thehive_apikey = Setting.objects.get(key="alerts.endpoint.thehive.apikey")
    thehive_url = Setting.objects.get(key="alerts.endpoint.thehive.url")
    thehive_user = Setting.objects.get(key="alerts.endpoint.thehive.user")
    alert_message = "[Alert][Rule={}]{}".format(rule.title, message)

    api = TheHiveApi(thehive_url.value, thehive_apikey.value)
    sourceRef = str(uuid.uuid4())[0:6]
    # Severity 1 is the lower severity for TheHive
    rule_severity = 1
    if rule.severity == "Medium":
        rule_severity = 2
    elif rule.severity in ["High", "Critical"]:
        rule_severity = 3

    tlp = 0
    if asset.criticity == "low":
        tlp = 1
    elif asset.criticity == "medium":
        tlp = 2
    elif asset.criticity == "high":
        tlp = 3

    if asset:
        artifacts = [THAlertArtifact(dataType=asset.type, data=asset.value)]
        try:
            alert = THAlert(title=alert_message,
                            tlp=tlp,
                            severity=rule_severity,
                            tags=['src:PatrOwl'],
                            description=description,
                            type='external',
                            source=thehive_user.value,
                            sourceRef=sourceRef,
                            artifacts=artifacts)

            response = api.create_alert(alert)

            if response.status_code == 201:
                alert_id = response.json()['id']
                # todo: track theHive alerts
                Event.objects.create(
                    message="[Rule][send_thehive_message()] "
                    "Alert sent to TheHive with message '{}' (alert id: {})".
                    format(message, alert_id),
                    type="DEBUG",
                    severity="DEBUG")
            else:
                return_value = ""
                if "errors" in json.loads(response.text):
                    # Limit length to 40 characters
                    return_value = json.loads(
                        response.text)["errors"][0]["message"][:40]
                Event.objects.create(
                    message="[Rule][send_thehive_message()] Unable to send "
                    "alert to TheHive (status_code={}, return_value='{}')".
                    format(response.status_code, return_value),
                    type="ERROR",
                    severity="ERROR")
        except Exception as e:
            Event.objects.create(
                message="[Rule][send_thehive_message()] Unable to send alert "
                "to TheHive with (error={}, message ='{}')".format(e, message),
                type="ERROR",
                severity="ERROR")
Пример #17
0
def submitTheHive(emailFilePath):

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

    global log

    mailName, mailType = os.path.splitext(emailFilePath)

    if mailType == ".msg":
        fromField, subjectField, observables, body, attachments = readMsg(emailFilePath)
    elif mailType == ".eml":
        fromField, subjectField, observables, body, attachments = readEml(emailFilePath)

    # 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['thehiveApiKey'])

    # 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:
Пример #18
0
def submitTheHive(message):
    '''
    Create a new case in TheHive based on the email
    Return 'TRUE' is successfully processed otherwise 'FALSE'
    '''

    # Decode email
    msg = email.message_from_bytes(message)  # gets full content of the email
    decode = email.header.decode_header(msg['From'])[0]
    fromField = str(decode[0])
    decode = email.header.decode_header(msg['Subject'])[0]
    subjectField = str(decode[0])
    if args.verbose:
        print("[INFO] From: %s Subject: %s" % (fromField, subjectField))
    attachments = []
    observables = []
    body = ''
    bodyMessage = ''
    for part in msg.walk():
        if part.get_content_type() == "text/plain":
            body = part.get_payload(decode=True).decode()
            bodyMessage += body
            observables = searchObservables(
                body, observables
            )  # searches the body of the email for supplied observables
        elif part.get_content_type(
        ) == "text/html":  # if email is html based will search throuh html source code
            if args.verbose:
                print("[INFO] Searching for observable in HTML code")
            html = part.get_payload(decode=True).decode()
            observables = searchObservables(html, observables)
        elif part.get_content_type(
        ) == "application/vnd.ms-excel":  #ONLY WORKS FOR .CSV
            body = part.get_payload(decode=True).decode('UTF-8')
            observables = searchObservables(body, 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']:
                    print("[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']
                    fd, path = tempfile.mkstemp(prefix=slugify(filename) + "_")
                    try:
                        with os.fdopen(fd, 'w+b') as tmp:
                            tmp.write(part.get_payload(decode=1))
                        attachments.append(path)
                    except OSError as e:
                        print("[ERROR] Cannot dump attachment to %s: %s" %
                              (path, e.errno))
                        return False

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

    # if '[ALERT]' in subjectField:
    if re.match(config['alertKeywords'], subjectField, flags=0):
        #
        # Add observables found in the mail body
        #
        artifacts = []
        if config['thehiveObservables'] and len(observables) > 0:
            print("t1")
            for o in observables:
                print("t2")
                artifacts.append(
                    AlertArtifact(dataType=o['type'], data=o['value']))

        #
        # Prepare tags - add alert keywords found to the list of tags
        #
        tags = 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']
            ),  #setting it blank since custom template allows default color, set it back to tlp = int for conf value
            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:
            if args.verbose:
                print('[INFO] Created alert %s' % response.json()['sourceRef'])
        else:
            print('[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

        m = 1
        if m == 1:
            templates = []
            for task in config['caseTemplates']:
                templates.append(task)
            temptouse = config['caseTemplate']
            descrip = re.compile('-"(.+)"')
            name = re.compile('(.+)-"')
            for x in templates:
                z = descrip.search(x)
                tempVar = name.search(x)
                searchVar = z.group(1)
                tempVar = tempVar.group(1)

                if searchVar in subjectField:
                    print(
                        x
                    )  #if 2 template names in subject, take the latest defined
                    temptouse = tempVar
                    print("TEMPLATE", temptouse)
            if body:
                testerVar = False
                print("body")
                try:
                    albert = re.compile('Albert Incident #: (\d+)')
                    m = albert.search(body)
                    albertId = m.group(1)
                    print(albertId)
                    customFields = CustomFieldHelper() \
                        .add_string('from', fromField) \
                        .add_string('attachment', str(attachments)) \
                        .add_string('albertId', albertId) \
                        .build()
                    print(customFields)
                except:
                    print("albert id doesnt exist")

                if "Update" in subjectField:  #update code
                    testerVar = True
                    print("UPDATE")
                    #INTIAL
                    try:
                        findBodyInfo = re.compile('---((?:.+[\r\n]+)+)---')
                    except:
                        print(
                            "Unable to update, unable to find two '---'s, exiting.."
                        )
                        sys.exit(0)
                    m = findBodyInfo.search(body)
                    bigGroup = m.group(1)
                    caseId = parseBody("Case Id", bigGroup)
                    print("caseid", caseId)
                    try:
                        caseId = int(caseId)

                    except:
                        print("invalid case id")
                    updateACase(caseId, bigGroup, fromField, attachments)

                    id = None
                    if testerVar == True:
                        print("g")
                        sys.exit(0)
                #end update code

                caseTags = []
                for tag in config['caseTags']:
                    descripFound = descrip.search(tag)
                    nameFound = name.search(tag)
                    descripFound = descripFound.group(1)
                    nameFound = nameFound.group(1)
                    if descripFound == 'always':
                        caseTags.append(nameFound)
                    elif descripFound in bodyMessage:
                        caseTags.append(nameFound)

            try:

                #
                # 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 = 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,
                    tlp=int(
                        config['alertTLP']
                    ),  #setting it blank since custom template allows default color, set it back to tlp = int for conf value
                    tags=caseTags,
                    description=body,
                    type='external',
                    source=fromField,
                    sourceRef=sourceRef,
                    customFields=customFields,
                    severity=None,
                    artifacts=artifacts)

            except FileExistsError:
                print(
                    "Error with creating alert, wrong template name or tags?")
        else:
            print("")
        # Create the alert
        response = api.create_alert(alert)
        print("Alert being created..")
        if response.status_code == 201:
            newID = response.json()['id']
            if args.verbose:
                print('[INFO] Created alert %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:
                        if args.verbose:
                            print('[INFO] Added observable %s to case ID %s' %
                                  (path, newID))
                            os.unlink(path)
                    else:
                        print('[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=caseTags,  #switched to custom tags
                        message='Found in the email body')
                    response = api.create_case_observable(newID, observable)
                    if response.status_code == 201:
                        if args.verbose:
                            print(
                                '[INFO] Added observable %s: %s to case ID %s'
                                % (o['type'], o['value'], newID))
                    else:
                        print(
                            '[WARNING] Cannot add observable %s: %s - %s (%s)'
                            % (o['type'], o['value'], response.status_code,
                               response.text))
        else:
            print('[ERROR] Cannot create case: %s (%s)' %
                  (response.status_code, response.text))
            return False
    return True
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()
Пример #20
0
class TheHiveRequests:

    def __init__(self, config, ReportConfig):
        #Define the main logger
        self.logger = logging.getLogger("QTHI")
        self.config = config
        #Load config for reports
        self.ReportConfig = ReportConfig

        #Timestamp
        self.current_time = int(round(time.time() * 1000))
        
        #Assign The Hive API class
        self.thapi = TheHiveApi(self.config.get('url', None),
                           self.config.get('key'),
                           self.config.get('password', None),
                           self.config.get('proxies'),
                           self.config.get('verify'))

    #Allow stringed output when needed
    def __repr__(self, alert):
        return str(alert.__dict__)

    #Function to prepare an alert object that is required to perform Alert based action within The Hive	
    def prepare_alert(self, content, alert_type):
        """
        convert a QRadar alert into a TheHive alert

        :param content: QRadar Alert
        :type content: dict
        :return: Thehive alert
        :rtype: thehive4py.models Alerts
        """
        
        #Defined tags that should be present in the alert
        case_tags = ["src:QRadar"]
                               
        ''' CHANGE NOT DONE ''' 
        ''' Added APR and RESPC alert type. Still needs a case template and argument adjustment (severity, source etc). Importing the Alert function arguments from config file
        Please do not forget the change on line 290'''
        if alert_type in ["lse", "apr", "respc"]:
            
            case_tags.append(alert_type)
            #Build alert as object defined in TheHive4Py models
            alert = Alert(title=content.get("title"),
                          tlp=2,
                          tags=case_tags,
                          severity=int(content.get('severity', self.ReportConfig[alert_type]['severity'])),
                          description=content.get('description'),
                          type='{} report'.format(alert_type.upper()),
                          source='QRadar',
                          caseTemplate=self.ReportConfig[alert_type]['case_template'],
                          sourceRef="qrpt-{}-{}".format(alert_type, str(self.current_time)))

            self.logger.info("Alert built for {}".format(self.ReportConfig[alert_type]['description']))
            self.logger.debug(str(alert))
            
        return alert

    #Function to check if the alert that has been created contains new/different data in comparison to the alert that is present
    def check_if_updated(self, current_a, new_a):
        for item in sorted(new_a):
            #Skip values that are not required for the compare
            if item is "date":
                continue
            #Artifacts require special attention
            if item is "artifacts":
                #If the array is of different size an update is required
                if not len(current_a[item]) == len(new_a[item]):
                    self.logger.info("Length mismatch detected: old length:%s, new length: %s" % (len(current_a[item]),len(new_a[item])))
                    return True
                
                #loop through the newly created alert array to extract the artifacts and add them so a separate variable
                for i in range(len(new_a[item])):
                    vars_current_artifacts = current_a[item][i]
                    vars_new_artifacts = vars(new_a[item][i])
                    
                    #For each artifact loop through the attributes to check for differences
                    for attribute in vars_new_artifacts:
                        if vars_current_artifacts[attribute] != vars_new_artifacts[attribute]:
                            self.logger.debug("Change detected for %s, new value: %s" % (vars_current_artifacts[attribute],vars_new_artifacts[attribute]))
                            self.logger.debug("old: %s, new: %s" % (vars_current_artifacts,vars_new_artifacts))
                            return True
                continue
                
            if item is "tags":
                #loop through the newly created alert array to extract the tags and add them so a separate variable
                for i in range(len(new_a[item])):
                    i = int(i)
                    vars_current_tags = current_a[item][i]
                    vars_new_tags = new_a[item][i]
                
                    #For each tag loop through the new attributes to check for missing tags. The chances are zero to none that a tag will be removed, so this check is skipped
                    for tag in vars_new_tags:
                        if not tag in vars_current_tags:
                            self.logger.debug("Change detected for %s, new value: %s" % (vars_current_tags,str(tag)))
                            return True
                continue
             
            #Match other items of the new alert to the current alert (string based)
            if str(current_a[item]) != str(new_a[item]):
                self.logger.debug("Change detected for %s, new value: %s" % (item,str(new_a[item])))
                return True
        return False

    #Function to actually create a new alert in The Hive    
    def create_th_alerts(self, alerts, alert_type):
        """
        :param alerts: List of alerts
        :type alerts: list
        :return: create TH alert
        """
        
        # CHANGE        
        if alert_type in ["lse", "apr", "respc"]:
            #Loop through all alerts to be created
            for alert in alerts:
                self.logger.info("Creating alert {} for {} report".format(self.current_time, alert_type.upper()))
                response = self.thapi.create_alert(alert)
       
        #Create a default action for standard alerts    
        else:
            self.logger.info("Creating default alert")
            alert = alerts
            response = self.thapi.create_alert(alert)
        
        #Check output to handle errors
        self.logger.debug('API TheHive - status code: {}'.format(
            response.status_code))
        if response.status_code > 299:
            self.logger.error('API TheHive - raw error output: {}'.format(
                response.raw.read()))
        else:
            self.logger.debug('Posted alert %s' % self.__repr__(alert))
Пример #21
0
class TheHive(AppBase):
    """
    An example of a Walkoff App.
    Inherit from the AppBase class to have Redis, logging, and console logging set up behind the scenes.
    """
    __version__ = "1.0.0"
    app_name = "thehive"

    def __init__(self, redis, logger, console_logger=None):
        """
        Each app should have this __init__ to set up Redis and logging.
        :param redis:
        :param logger:
        :param console_logger:
        """
        super().__init__(redis, logger, console_logger)

    #async def run_analyzer(self, apikey, url, title_query):
    #    self.thehive = TheHiveApi(url, apikey)

    #    response = self.thehive.find_cases(query=String("title:'%s'" % title_query), range='all', sort=[])
    #    return response.text


    async def search_cases(self, apikey, url, title_query):
        self.thehive = TheHiveApi(url, apikey)

        response = self.thehive.find_cases(query=String("title:'%s'" % title_query), range='all', sort=[])
        return response.text

    async def add_observable(self, apikey, url, case_id, data, datatype, tags):
        self.thehive = TheHiveApi(url, apikey)

        if tags:
            if ", " in tags:
                tags = tags.split(", ")
            elif "," in tags:
                tags = tags.split(",")
            else:
                tags = []
        else:
            tags = []

        item = thehive4py.models.CaseObservable(
            dataType=datatype,
            data=data,
            tlp=1,
            ioc=False,
            sighted=False,
            tags=["Shuffle"],
            message="Created by shuffle",
        )

        return self.thehive.create_case_observable(case_id, item).text

    async def search_alerts(self, apikey, url, title_query, search_range="0-25"):
        self.thehive = TheHiveApi(url, apikey)

        # Could be "all" too
        if search_range == "":
            search_range = "0-25"

        response = self.thehive.find_alerts(query=String("title:'%s'" % title_query), range=search_range, sort=[])
        return response.text

    async def create_case(self, apikey, url, title, description="", tlp=1, severity=1, tags=""):
        self.thehive = TheHiveApi(url, apikey)
        if tags:
            if ", " in tags:
                tags = tags.split(", ")
            elif "," in tags:
                tags = tags.split(",")
            else:
                tags = []
        else:
            tags = []

        # Wutface fix
        if not tlp:
            tlp = 1
        if not severity:
            severity = 1

        if isinstance(tlp, str):
            if not tlp.isdigit():
                return "TLP needs to be a number from 0-2, not %s" % tlp
            tlp = int(tlp)
        if isinstance(severity, str):
            if not severity.isdigit():
                return "Severity needs to be a number from 0-2, not %s" % tlp

            severity = int(severity)

        if tlp > 3 or tlp < 0:
            return "TLP needs to be a number from 0-3, not %d" % tlp
        if severity > 2 or severity < 0:
            return "Severity needs to be a number from 0-2, not %d" % tlp

        case = thehive4py.models.Case(
            title=title,
            tlp=tlp,
            severity=severity,
            tags=tags,
            description=description,
        )

        try:
            ret = self.thehive.create_case(case)
            return ret.text
        except requests.exceptions.ConnectionError as e:
            return "ConnectionError: %s" % e

    async def create_alert(self, apikey, url, type, source, sourceref, title, description="", tlp=1, severity=1, tags=""):
        self.thehive = TheHiveApi(url, apikey)
        if tags:
            if ", " in tags:
                tags = tags.split(", ")
            elif "," in tags:
                tags = tags.split(",")
            else:
                tags = []
        else:
            tags = []

        # Wutface fix
        if not tlp:
            tlp = 1
        if not severity:
            severity = 1

        if isinstance(tlp, str):
            if not tlp.isdigit():
                return "TLP needs to be a number from 0-2, not %s" % tlp
            tlp = int(tlp)
        if isinstance(severity, str):
            if not severity.isdigit():
                return "Severity needs to be a number from 0-2, not %s" % tlp

            severity = int(severity)

        if tlp > 2 or tlp < 0:
            return "TLP needs to be a number from 0-2, not %d" % tlp
        if severity > 2 or severity < 0:
            return "Severity needs to be a number from 0-2, not %d" % tlp

        alert = thehive4py.models.Alert(
            title=title,
            tlp=tlp,
            severity=severity,
            tags=tags,
            description=description,
            type=type,
            source=source,
            sourceRef=sourceref,
        )

        try:
            ret = self.thehive.create_alert(alert)
            return ret.text
        except requests.exceptions.ConnectionError as e:
            return "ConnectionError: %s" % e

    # Gets an item based on input. E.g. field_type = Alert
    async def get_item(self, apikey, url, field_type, cur_id): 
        self.thehive = TheHiveApi(url, apikey)

        newstr = ""
        ret = ""
        if field_type.lower() == "alert":
            ret = self.thehive.get_alert(cur_id + "?similarity=1") 
        elif field_type.lower() == "case":
            ret = self.thehive.get_case(cur_id)
        elif field_type.lower() == "case_observables":
            ret = self.thehive.get_case_observables(cur_id)
        elif field_type.lower() == "case_task":
            ret = self.thehive.get_case_task(cur_id)
        elif field_type.lower() == "case_tasks":
            ret = self.thehive.get_case_tasks(cur_id)
        elif field_type.lower() == "case_template":
            ret = self.thehive.get_case_tasks(cur_id)
        elif field_type.lower() == "linked_cases":
            ret = self.thehive.get_linked_cases(cur_id)
        elif field_type.lower() == "task_log":
            ret = self.thehive.get_task_log(cur_id)
        elif field_type.lower() == "task_logs":
            ret = self.thehive.get_task_logs(cur_id)
        else:
            return "%s is not implemented. See https://github.com/frikky/shuffle-apps for more info." % field_type

        return ret.text

    async def close_alert(self, apikey, url, alert_id):
        self.thehive = TheHiveApi(url, apikey)
        return self.thehive.mark_alert_as_read(alert_id).text

    async def reopen_alert(self, apikey, url, alert_id):
        self.thehive = TheHiveApi(url, apikey)
        return self.thehive.mark_alert_as_unread(alert_id).text

    async def create_case_from_alert(self, apikey, url, alert_id, case_template=None):
        self.thehive = TheHiveApi(url, apikey)
        response = self.thehive.promote_alert_to_case(alert_id=alert_id, case_template=case_template)
        return response.text

    async def merge_alert_into_case(self, apikey, url, alert_id, case_id):
        self.thehive = TheHiveApi(url, apikey)
        req = url + f"/api/alert/{alert_id}/merge/{case_id}"
        ret = requests.post(req, auth=self.thehive.auth)
        return ret.text

    # Not sure what the data should be
    async def update_field(self, apikey, url, field_type, cur_id, field, data):
        # This is kinda silly but..
        if field_type.lower() == "alert":
            newdata = {}

            if data.startswith("%s"): 
                ticket = self.thehive.get_alert(cur_id)
                if ticket.status_code != 200:
                    pass 
            
                newdata[field] = "%s%s" % (ticket.json()[field], data[2:])
            else:
                newdata[field] = data

            # Bleh
            url = "%s/api/alert/%s" % (url, cur_id)
            if field == "status":
                if data == "New" or data == "Updated":
                    url = "%s/markAsUnread" % url
                elif data == "Ignored": 
                    url = "%s/markAsRead" % url

                ret = requests.post(
                    url,
                    headers={
                        'Content-Type': 'application/json',
                        'Authorization': 'Bearer %s' % apikey
                    }
                )
            else:
                ret = requests.patch(
                    url,
                    headers={
                        'Content-Type': 'application/json',
                        'Authorization': 'Bearer %s' % apikey
                    }, 
                    json=newdata,
                )

            return str(ret.status_code)
        else:
            return "%s is not implemented. See https://github.com/frikky/walkoff-integrations for more info." % field_type

    # https://github.com/TheHive-Project/TheHiveDocs/tree/master/api/connectors/cortex
    async def run_analyzer(self, apikey, url, cortex_id, analyzer_id, artifact_id):
        self.thehive = TheHiveApi(url, apikey)
        return self.thehive.run_analyzer(cortex_id, artifact_id, analyzer_id).text
Пример #22
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
Пример #23
0
def create_alert():

    # Get request data
    content = request.get_json()

    # Configure logging
    logging.basicConfig(filename=app.config['LOG_FILE'], filemode='a',
                        format='%(asctime)s - canaries2thehive - %(levelname)s - %(message)s',
                        level=logging.INFO)
    logging.info(json.dumps(content))

    # Configure artifacts
    artifacts = []
    artifacts.append(AlertArtifact(dataType='ip',
                                   tags=[],
                                   data=content['CanaryIP']))
    artifacts.append(AlertArtifact(dataType='ip',
                                   tags=[],
                                   data=content['SourceIP']))
    artifacts.append(AlertArtifact(dataType='fqdn',
                                   tags=[],
                                   data=content['CanaryName']))

    # Tags list
    tags = ['canary']

    # Parse fields and create description
    description = ""
    alert_flattened = flatten_dict(content)
    for key in alert_flattened.keys():
        if (alert_flattened[key] != ""):
            description = description+"\n**"+key+":** "+json.dumps(alert_flattened[key])+"\n"

    # Prepare alert
    sourceRef = str(uuid.uuid4())[0:6]
    alert = Alert(title="Canary Triggered - %s by %s on %s (%s)" % (content["Description"], content["SourceIP"], content["CanaryName"], content["CanaryIP"]),
                  tlp=2,
                  tags=tags,
                  description=description,
                  type='external',
                  source='canary',
                  artifacts=artifacts,
                  sourceRef=sourceRef)

    # Get API keys
    with open(app.root_path + '/keys.json', 'r') as file:
        keys_file = file.read()
    keys = json.loads(keys_file)

    # Loop through organisations in TheHive
    for org, key in keys.items():

        # Configure API
        logging.info(app.config['HIVE_URL'])
        api = TheHiveApi(app.config['HIVE_URL'], key)

        # Create the alert
        logging.info('Create Alert')
        logging.info('-----------------------------')
        id = None
        response = api.create_alert(alert)
        if response.status_code == 201:
            logging.info(json.dumps(response.json(), indent=4, sort_keys=True))
            id = response.json()['id']
        else:
            logging.info('ko: {}/{}'.format(response.status_code,
                                            response.text))
            sys.exit(0)

    # Return
    return "Hive Alerts Created"
Пример #24
0
# Prepare the sample Alert
sourceRef = str(uuid.uuid4())[0:6]
alert = Alert(title='<CUSTOMIZE THE TITLE>',
              tlp=2,
              tags=['<add tag here>'],
              description='<add some description>',
              type='notification',
              source='Email Server',
              sourceRef=sourceRef,
              artifacts=artifacts)

# Create the Alert
print('Create Alert')
print('-----------------------------')
id = None
response = api.create_alert(alert)
if response.status_code == 201:
    print(json.dumps(response.json(), indent=4, sort_keys=True))
    print('')
    id = response.json()['id']
else:
    print('ko: {}/{}'.format(response.status_code, response.text))
    sys.exit(0)


# Get all the details of the created alert
print('Get created alert {}'.format(id))
print('-----------------------------')
response = api.get_alert(id)
if response.status_code == requests.codes.ok:
    print(json.dumps(response.json(), indent=4, sort_keys=True))
Пример #25
0
class TheHive(AppBase):
    """
    An example of a Walkoff App.
    Inherit from the AppBase class to have Redis, logging, and console logging set up behind the scenes.
    """

    __version__ = "1.1.0"
    app_name = "thehive"

    def __init__(self, redis, logger, console_logger=None):
        """
        Each app should have this __init__ to set up Redis and logging.
        :param redis:
        :param logger:
        :param console_logger:
        """
        super().__init__(redis, logger, console_logger)

    # async def run_analyzer(self, apikey, url, title_query):
    #    self.thehive = TheHiveApi(url, apikey, cert=False)

    #    response = self.thehive.find_cases(query=String("title:'%s'" % title_query), range='all', sort=[])
    #    return response.text

    def __connect_thehive(self, url, apikey, organisation):
        if organisation:
            self.thehive = TheHiveApi(url,
                                      apikey,
                                      cert=False,
                                      organisation=organisation)
        else:
            self.thehive = TheHiveApi(url, apikey, cert=False)

    async def search_case_title(self, apikey, url, organisation, title_query):
        self.__connect_thehive(url, apikey, organisation)

        response = self.thehive.find_cases(query=ContainsString(
            "title", title_query),
                                           range="all",
                                           sort=[])

        return response.text

    async def custom_search(self,
                            apikey,
                            url,
                            organisation,
                            search_for,
                            custom_query,
                            range="all"):
        self.__connect_thehive(url, apikey, organisation)

        try:
            custom_query = json.loads(custom_query)
        except:
            # raise IOError("Invalid JSON payload received.")
            pass

        if search_for == "alert":
            response = self.thehive.find_alerts(query=custom_query,
                                                range="all",
                                                sort=[])
        else:
            response = self.thehive.find_cases(query=custom_query,
                                               range="all",
                                               sort=[])

        if (response.status_code == 200 or response.status_code == 201
                or response.status_code == 202):
            return response.text
        else:
            raise IOError(response.text)

    async def add_case_artifact(
        self,
        apikey,
        url,
        organisation,
        case_id,
        data,
        datatype,
        tags=None,
        tlp=None,
        ioc=None,
        sighted=None,
        description="",
    ):
        self.__connect_thehive(url, apikey, organisation)

        tlp = int(tlp) if tlp else 2
        ioc = True if ioc.lower() == "true" else False
        sighted = True if sighted.lower() == "true" else False
        if not description:
            description = "Created by shuffle"

        tags = (tags.split(", ")
                if ", " in tags else tags.split(",") if "," in tags else [])

        item = thehive4py.models.CaseObservable(
            dataType=datatype,
            data=data,
            tlp=tlp,
            ioc=ioc,
            sighted=sighted,
            tags=tags,
            message=description,
        )

        return self.thehive.create_case_observable(case_id, item).text

    async def search_alert_title(self,
                                 apikey,
                                 url,
                                 organisation,
                                 title_query,
                                 search_range="0-25"):
        self.__connect_thehive(url, apikey, organisation)

        # Could be "all" too
        if search_range == "":
            search_range = "0-25"

        response = self.thehive.find_alerts(query=ContainsString(
            "title", title_query),
                                            range=search_range,
                                            sort=[])

        return response.text

    async def create_case(
        self,
        apikey,
        url,
        organisation,
        template,
        title,
        description="",
        tlp=1,
        severity=1,
        tags="",
    ):
        self.__connect_thehive(url, apikey, organisation)
        if tags:
            if ", " in tags:
                tags = tags.split(", ")
            elif "," in tags:
                tags = tags.split(",")
            else:
                tags = [tags]
        else:
            tags = []

        # Wutface fix
        if not tlp:
            tlp = 1
        if not severity:
            severity = 1

        if isinstance(tlp, str):
            if not tlp.isdigit():
                return "TLP needs to be a number from 0-2, not %s" % tlp
            tlp = int(tlp)
        if isinstance(severity, str):
            if not severity.isdigit():
                return "Severity needs to be a number from 0-2, not %s" % tlp

            severity = int(severity)

        if tlp > 3 or tlp < 0:
            return "TLP needs to be a number from 0-3, not %d" % tlp
        if severity > 2 or severity < 0:
            return "Severity needs to be a number from 0-2, not %d" % tlp

        Casetemplate = template if template else None

        case = thehive4py.models.Case(
            title=title,
            tlp=tlp,
            severity=severity,
            tags=tags,
            description=description,
            template=Casetemplate,
        )

        try:
            ret = self.thehive.create_case(case)
            return ret.text
        except requests.exceptions.ConnectionError as e:
            return "ConnectionError: %s" % e

    async def create_alert(
        self,
        apikey,
        url,
        organisation,
        type,
        source,
        sourceref,
        title,
        description="",
        tlp=1,
        severity=1,
        tags="",
        artifacts="",
    ):
        self.__connect_thehive(url, apikey, organisation)
        if tags:
            if ", " in tags:
                tags = tags.split(", ")
            elif "," in tags:
                tags = tags.split(",")
            else:
                tags = [tags]
        else:
            tags = []

        # Wutface fix
        if not tlp:
            tlp = 1
        if not severity:
            severity = 1

        if isinstance(tlp, str):
            if not tlp.isdigit():
                return "TLP needs to be a number from 0-3, not %s" % tlp

            tlp = int(tlp)
        if isinstance(severity, str):
            if not severity.isdigit():
                return "Severity needs to be a number from 1-3, not %s" % severity

            severity = int(severity)

        if tlp > 3 or tlp < 0:
            return "TLP needs to be a number from 0-3, not %d" % tlp
        if severity > 3 or severity < 1:
            return "Severity needs to be a number from 1-3, not %d" % severity

        all_artifacts = []
        if artifacts != "":
            # print("ARTIFACTS: %s" % artifacts)
            if isinstance(artifacts, str):
                # print("ITS A STRING!")
                try:
                    artifacts = json.loads(artifacts)
                except:
                    print("[ERROR] Error in parsing artifacts!")

            # print("ART HERE: %s" % artifacts)
            # print("ART: %s" % type(artifacts))
            if isinstance(artifacts, list):
                print("ITS A LIST!")
                for item in artifacts:
                    print("ITEM: %s" % item)
                    try:
                        artifact = thehive4py.models.AlertArtifact(
                            dataType=item["data_type"],
                            data=item["data"],
                        )

                        try:
                            artifact["message"] = item["message"]
                        except:
                            pass

                        if item["data_type"] == "ip":
                            try:
                                if item["is_private_ip"]:
                                    message += " IP is private."
                            except:
                                pass

                        all_artifacts.append(artifact)
                    except KeyError as e:
                        print("Error in artifacts: %s" % e)

        alert = thehive4py.models.Alert(
            title=title,
            tlp=tlp,
            severity=severity,
            tags=tags,
            description=description,
            type=type,
            source=source,
            sourceRef=sourceref,
            artifacts=all_artifacts,
        )

        try:
            ret = self.thehive.create_alert(alert)
            return ret.text
        except requests.exceptions.ConnectionError as e:
            return "ConnectionError: %s" % e

    async def create_alert_artifact(
        self,
        apikey,
        url,
        organisation,
        alert_id,
        dataType,
        data,
        message=None,
        tlp="2",
        ioc="False",
        sighted="False",
        ignoreSimilarity="False",
        tags=None,
    ):
        self.__connect_thehive(url, apikey, organisation, version=4)

        if tlp:
            tlp = int(tlp)
        else:
            tlp = 2

        ioc = ioc.lower().strip() == "true"
        sighted = sighted.lower().strip() == "true"
        ignoreSimilarity = ignoreSimilarity.lower().strip() == "true"

        if tags:
            tags = [x.strip() for x in tags.split(",")]
        else:
            tags = []

        alert_artifact = thehive4py.models.AlertArtifact(
            dataType=dataType,
            data=data,
            message=message,
            tlp=tlp,
            ioc=ioc,
            sighted=sighted,
            ignoreSimilarity=ignoreSimilarity,
            tags=tags,
        )

        try:
            ret = self.thehive.create_alert_artifact(alert_id, alert_artifact)
        except requests.exceptions.ConnectionError as e:
            return "ConnectionError: %s" % e

        if ret.status_code > 299:
            raise ConnectionError(ret.text)

        return ret.text

    # Gets an item based on input. E.g. field_type = Alert
    async def get_item(self, apikey, url, organisation, field_type, cur_id):
        self.__connect_thehive(url, apikey, organisation)

        newstr = ""
        ret = ""
        if field_type.lower() == "alert":
            ret = self.thehive.get_alert(cur_id + "?similarity=1")
        elif field_type.lower() == "case":
            ret = self.thehive.get_case(cur_id)
        elif field_type.lower() == "case_observables":
            ret = self.thehive.get_case_observables(cur_id)
        elif field_type.lower() == "case_task":
            ret = self.thehive.get_case_task(cur_id)
        elif field_type.lower() == "case_tasks":
            ret = self.thehive.get_case_tasks(cur_id)
        elif field_type.lower() == "case_template":
            ret = self.thehive.get_case_tasks(cur_id)
        elif field_type.lower() == "linked_cases":
            ret = self.thehive.get_linked_cases(cur_id)
        elif field_type.lower() == "task_log":
            ret = self.thehive.get_task_log(cur_id)
        elif field_type.lower() == "task_logs":
            ret = self.thehive.get_task_logs(cur_id)
        else:
            return (
                "%s is not implemented. See https://github.com/frikky/shuffle-apps for more info."
                % field_type)

        return ret.text

    async def close_alert(self, apikey, url, organisation, alert_id):
        self.__connect_thehive(url, apikey, organisation)
        return self.thehive.mark_alert_as_read(alert_id).text

    async def reopen_alert(self, apikey, url, organisation, alert_id):
        self.__connect_thehive(url, apikey, organisation)
        return self.thehive.mark_alert_as_unread(alert_id).text

    async def create_case_from_alert(self,
                                     apikey,
                                     url,
                                     organisation,
                                     alert_id,
                                     case_template=None):
        self.__connect_thehive(url, apikey, organisation)
        response = self.thehive.promote_alert_to_case(
            alert_id=alert_id, case_template=case_template)
        return response.text

    async def merge_alert_into_case(self, apikey, url, organisation, alert_id,
                                    case_id):
        self.__connect_thehive(url, apikey, organisation)
        req = url + f"/api/alert/{alert_id}/merge/{case_id}"
        ret = requests.post(req, auth=self.thehive.auth)
        return ret.text

    # Not sure what the data should be
    async def update_field(self, apikey, url, organisation, field_type, cur_id,
                           field, data):
        # This is kinda silly but..
        if field_type.lower() == "alert":
            newdata = {}

            if data.startswith("%s"):
                ticket = self.thehive.get_alert(cur_id)
                if ticket.status_code != 200:
                    pass

                newdata[field] = "%s%s" % (ticket.json()[field], data[2:])
            else:
                newdata[field] = data

            # Bleh
            url = "%s/api/alert/%s" % (url, cur_id)
            if field == "status":
                if data == "New" or data == "Updated":
                    url = "%s/markAsUnread" % url
                elif data == "Ignored":
                    url = "%s/markAsRead" % url

                ret = requests.post(
                    url,
                    headers={
                        "Content-Type": "application/json",
                        "Authorization": "Bearer %s" % apikey,
                    },
                )
            else:
                ret = requests.patch(
                    url,
                    headers={
                        "Content-Type": "application/json",
                        "Authorization": "Bearer %s" % apikey,
                    },
                    json=newdata,
                )

            return str(ret.status_code)
        else:
            return (
                "%s is not implemented. See https://github.com/frikky/walkoff-integrations for more info."
                % field_type)

    # https://github.com/TheHive-Project/TheHiveDocs/tree/master/api/connectors/cortex
    async def delete_alert_artifact(self, apikey, url, organisation,
                                    artifact_id):
        self.__connect_thehive(url, apikey, organisation, version=4)
        return self.thehive.delete_alert_artifact(artifact_id).text

    # https://github.com/TheHive-Project/TheHiveDocs/tree/master/api/connectors/cortex
    async def run_analyzer(self, apikey, url, organisation, cortex_id,
                           analyzer_id, artifact_id):
        self.__connect_thehive(url, apikey, organisation)
        return self.thehive.run_analyzer(cortex_id, artifact_id,
                                         analyzer_id).text

    # Creates a task log in TheHive with file
    async def create_task_log(self,
                              apikey,
                              url,
                              organisation,
                              task_id,
                              message,
                              filedata={}):
        if filedata["success"] == False:
            return "No file to upload. Skipping message."

        headers = {
            "Authorization": "Bearer %s" % apikey,
        }

        files = {}
        if len(filedata["data"]) > 0:
            files = {
                "attachment": (filedata["filename"], filedata["data"]),
            }

        data = {"_json": """{"message": "%s"}""" % message}
        response = requests.post(
            "%s/api/case/task/%s/log" % (url, task_id),
            headers=headers,
            files=files,
            data=data,
        )
        return response.text

    # Creates an observable as a file in a case
    async def create_case_file_observable(self, apikey, url, organisation,
                                          case_id, tags, filedata):
        if filedata["success"] == False:
            return "No file to upload. Skipping message."

        headers = {
            "Authorization": "Bearer %s" % apikey,
        }

        if tags:
            if ", " in tags:
                tags = tags.split(", ")
            elif "," in tags:
                tags = tags.split(",")
            else:
                tags = [tags]

        files = {}
        if len(filedata["data"]) > 0:
            files = {
                "attachment": (filedata["filename"], filedata["data"]),
            }

        outerarray = {"dataType": "file", "tags": tags}
        data = {"_json": """%s""" % json.dumps(outerarray)}
        response = requests.post(
            "%s/api/case/%s/artifact" % (url, case_id),
            headers=headers,
            files=files,
            data=data,
            verify=False,
        )
        return response.text

    # Get all artifacts of a given case
    async def get_case_artifacts(
        self,
        apikey,
        url,
        organisation,
        case_id,
        dataType,
    ):
        self.__connect_thehive(url, apikey, organisation)

        query = And(Eq("dataType", dataType)) if dataType else {}

        # Call the API
        response = self.thehive.get_case_observables(
            case_id, query=query, sort=["-startDate", "+ioc"], range="all")

        # Display the result
        if response.status_code == 200:
            # Get response data
            list = response.json()

            # Display response data
            return (json.dumps(list, indent=4, sort_keys=True)
                    if list else json.dumps(
                        {
                            "status": 200,
                            "message": "No observable results"
                        },
                        indent=4,
                        sort_keys=True,
                    ))
        else:
            return f"Failure: {response.status_code}/{response.text}"

    async def close_case(
        self,
        apikey,
        url,
        organisation,
        id,
        resolution_status="",
        impact_status="",
        summary="",
    ):

        self.__connect_thehive(url, apikey, organisation)
        case = self.thehive.case(id)
        case.status = "Resolved"
        case.summary = summary
        case.resolutionStatus = resolution_status
        case.impactStatus = impact_status

        result = self.thehive.update_case(
            case,
            fields=[
                "status",
                "summary",
                "resolutionStatus",
                "impactStatus",
            ],
        )

        return json.dumps(result.json(), indent=4, sort_keys=True)

    # Update TheHive Case
    async def update_case(
        self,
        apikey,
        url,
        organisation,
        id,
        title="",
        description="",
        severity=None,
        owner="",
        flag=None,
        tlp=None,
        pap=None,
        tags="",
        status="",
        custom_fields=None,
        custom_json=None,
    ):
        self.__connect_thehive(url, apikey, organisation)

        # Get current case data and update fields if new data exists
        case = self.thehive.get_case(id).json()
        print(case)

        case_title = title if title else case["title"]
        case_description = description if description else case["description"]
        case_severity = int(severity) if severity else case["severity"]
        case_owner = owner if owner else case["owner"]
        case_flag = ((False if flag.lower() == "false" else True)
                     if flag else case["flag"])
        case_tlp = int(tlp) if tlp else case["tlp"]
        case_pap = int(pap) if pap else case["pap"]
        case_tags = tags.split(",") if tags else case["tags"]
        case_tags = tags.split(",") if tags else case["tags"]

        case_status = status if status else case["status"]
        case_customFields = case["customFields"]

        # Prepare the customfields
        customfields = CustomFieldHelper()
        if case_customFields:
            for key, value in case_customFields.items():
                if list(value)[0] == "integer":
                    customfields.add_integer(key, list(value.items())[0][1])
                elif list(value)[0] == "string":
                    customfields.add_string(key, list(value.items())[0][1])
                elif list(value)[0] == "boolean":
                    customfields.add_boolean(key, list(value.items())[0][1])
                elif list(value)[0] == "float":
                    customfields.add_float(key, list(value.items())[0][1])
                else:
                    print(
                        f'The value type "{value}" of the field {key} is not suported by the function.'
                    )

        custom_fields = json.loads(custom_fields) if custom_fields else {}
        for key, value in custom_fields.items():
            if type(value) == int:
                customfields.add_integer(key, value)
            elif type(value) == str:
                customfields.add_string(key, value)
            elif type(value) == bool:
                customfields.add_boolean(key, value)
            elif type(value) == float:
                customfields.add_float(key, value)
            else:
                print(
                    f'The value type "{value}" of the field {key} is not suported by the function.'
                )

        customfields = customfields.build()

        custom_json = json.loads(custom_json) if custom_json else {}

        # Prepare the fields to be updated
        case = Case(
            id=id,
            title=case_title,
            description=case_description,
            severity=case_severity,
            owner=case_owner,
            flag=case_flag,
            tlp=case_tlp,
            pap=case_pap,
            tags=case_tags,
            status=case_status,
            customFields=customfields,
            json=custom_json,
        )

        # resolutionStatus=case_resolutionStatus,

        result = self.thehive.update_case(
            case,
            fields=[
                "title",
                "description",
                "severity",
                "owner",
                "flag",
                "tlp",
                "pap",
                "tags",
                "customFields",
                "status",
            ],
        )

        return json.dumps(result.json(), indent=4, sort_keys=True)

    # Get TheHive Organisations
    async def get_organisations(
        self,
        apikey,
        url,
        organisation,
    ):
        headers = {
            "Authorization": f"Bearer {apikey}",
            "Content-Type": "application/json",
        }

        response = requests.get(
            f"{url}/api/organisation",
            headers=headers,
            verify=False,
        )

        return response.text

    # Create TheHive Organisation
    async def create_organisation(
        self,
        apikey,
        url,
        organisation,
        name,
        description,
    ):
        headers = {
            "Authorization": f"Bearer {apikey}",
            "Content-Type": "application/json",
        }

        data = {"name": f"{name}", "description": f"{description}"}

        response = requests.post(
            f"{url}/api/organisation",
            headers=headers,
            json=data,
            verify=False,
        )

        return response.text

    # Create User in TheHive
    async def create_user(
        self,
        apikey,
        url,
        organisation,
        login,
        name,
        profile,
    ):
        headers = {
            "Authorization": f"Bearer {apikey}",
            "Content-Type": "application/json",
        }

        data = {
            "login": f"{login}",
            "name": f"{name}",
            "profile": f"{profile}",
            "organisation": f"{organisation}",
        }

        response = requests.post(
            f"{url}/api/v1/user",
            headers=headers,
            json=data,
            verify=False,
        )

        return response.text
Пример #26
0
def submitTheHive(message):
    '''Create a new case in TheHive based on the email'''

    # Decode email
    msg = email.message_from_bytes(message)
    decode = email.header.decode_header(msg['From'])[0]
    fromField = str(decode[0])
    decode = email.header.decode_header(msg['Subject'])[0]
    subjectField = str(decode[0])
    if args.verbose:
        print("[INFO] From: %s Subject: %s" % (fromField, subjectField))
    attachments = []
    body = ''
    for part in msg.walk():
        if part.get_content_type() == "text/plain":
            body = part.get_payload(decode=True).decode()
        else:
            filename = part.get_filename()
            if filename:
                print("[INFO] Found attachment: %s" % filename)
                attachments.append(filename)

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

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

        # Create the Alert
        id = None
        response = api.create_alert(alert)
        if response.status_code == 201:
            if args.verbose:
                print('[INFO] Created alert %s' % response.json()['sourceRef'])
        else:
            print('[ERROR] Cannot create alert: %s (%s)' %
                  (response.status_code, response.text))
            sys.exit(0)

    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()

        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:
            if args.verbose:
                print('[INFO] Created case %s' % response.json()['caseId'])
        else:
            print('[ERROR] Cannot create case: %s (%s)' %
                  (response.status_code, response.text))
            sys.exit(0)
    return