From 2784542cdbd9c1d5bcd18622f7579e277e02d55b Mon Sep 17 00:00:00 2001 From: Wes Lambert Date: Mon, 23 Sep 2019 22:39:43 +0000 Subject: [PATCH] update Elastalert config --- salt/elastalert/files/modules/so/thehive.py | 130 +++++++----------- salt/elastalert/files/rules/so/nids2hive.yaml | 4 +- 2 files changed, 55 insertions(+), 79 deletions(-) diff --git a/salt/elastalert/files/modules/so/thehive.py b/salt/elastalert/files/modules/so/thehive.py index d78a8d050..42b6f9e1d 100644 --- a/salt/elastalert/files/modules/so/thehive.py +++ b/salt/elastalert/files/modules/so/thehive.py @@ -1,108 +1,84 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals import uuid +import re from elastalert.alerts import Alerter from thehive4py.api import TheHiveApi from thehive4py.models import Alert, AlertArtifact, CustomFieldHelper - class TheHiveAlerter(Alerter): """ Use matched data to create alerts containing observables in an instance of TheHive + This is a modified version for use with Security Onion """ required_options = set(['hive_connection', 'hive_alert_config']) - def get_aggregation_summary_text(self, matches): - text = super(HiveAlerter, self).get_aggregation_summary_text(matches) - if text: - text = u'```\n{0}```\n'.format(text) - return text + def alert(self, matches): - def create_artifacts(self, match): - artifacts = [] - context = {'rule': self.rule, 'match': match} - 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 as e: - print('format string {} fail cause no key {} in {}'.format(e, match_data_key, context)) - return artifacts - - def create_alert_config(self, match): - context = {'rule': self.rule, 'match': match} - alert_config = { - 'artifacts': self.create_artifacts(match), - '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 (AttributeError, KeyError, IndexError): - formatted_list.append(element.format(**context)) - except (AttributeError, KeyError, IndexError): - formatted_list.append(element) - alert_config[alert_config_field] = formatted_list - - return alert_config - - def send_to_thehive(self, alert_config): connection_details = self.rule['hive_connection'] + api = TheHiveApi( - connection_details.get('hive_host', ''), + connection_details.get('hive_host'), 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) + for match in matches: + context = {'rule': self.rule, 'match': match} - if response.status_code != 201: - raise Exception('alert not successfully created in TheHive\n{}'.format(response.text)) - - def alert(self, matches): - if self.rule.get('hive_alert_config_type', 'custom') != 'classic': - for match in matches: - alert_config = self.create_alert_config(match) - self.send_to_thehive(alert_config) - else: - alert_config = self.create_alert_config(matches[0]) artifacts = [] - for match in matches: - artifacts += self.create_artifacts(match) - if 'related_events' in match: - for related_event in match['related_events']: - artifacts += self.create_artifacts(related_event) + for mapping in self.rule.get('hive_observable_data_mapping', []): + for observable_type, match_data_key in mapping.items(): + try: + match_data_keys = re.findall(r'\{match\[([^\]]*)\]', match_data_key) + rule_data_keys = re.findall(r'\{rule\[([^\]]*)\]', match_data_key) + data_keys = match_data_keys + rule_data_keys + context_keys = list(context['match'].keys()) + list(context['rule'].keys()) + if all([True if k in context_keys else False for k in data_keys]): + 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 - alert_config['title'] = self.create_title(matches) - alert_config['description'] = self.create_alert_body(matches) - self.send_to_thehive(alert_config) + 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.items(): + if alert_config_field == 'customFields': + custom_fields = CustomFieldHelper() + for cf_key, cf_value in alert_config_value.items(): + 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, str): + 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 (AttributeError, KeyError, IndexError): + 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 get_info(self): return { 'type': 'hivealerter', 'hive_host': self.rule.get('hive_connection', {}).get('hive_host', '') - } + } diff --git a/salt/elastalert/files/rules/so/nids2hive.yaml b/salt/elastalert/files/rules/so/nids2hive.yaml index ab0624e13..aa2287cca 100644 --- a/salt/elastalert/files/rules/so/nids2hive.yaml +++ b/salt/elastalert/files/rules/so/nids2hive.yaml @@ -23,7 +23,7 @@ filter: alert: modules.so.thehive.TheHiveAlerter hive_connection: - hive_host: {{hivehost}} + hive_host: https://{{hivehost}}/thehive/ hive_apikey: {{hivekey}} hive_proxies: @@ -31,7 +31,7 @@ hive_proxies: https: '' hive_alert_config: - title: '{rule[name]} -- {match[alert]}' + title: 'New Alert from Security Onion!' type: 'external' source: 'SecurityOnion' description: '{match[message]}'