From 70b8a4ee3dafc96cf088bf5402e4f14ef7ec33a3 Mon Sep 17 00:00:00 2001 From: Florian GAULTIER Date: Mon, 27 May 2019 21:54:17 +0200 Subject: [PATCH 1/4] Rewrite part of thehivealerter --- elastalert/alerts.py | 118 +++++++++++++++++++++++++------------------ 1 file changed, 69 insertions(+), 49 deletions(-) diff --git a/elastalert/alerts.py b/elastalert/alerts.py index f5ca22070..635550533 100644 --- a/elastalert/alerts.py +++ b/elastalert/alerts.py @@ -2118,8 +2118,57 @@ class HiveAlerter(Alerter): required_options = set(['hive_connection', 'hive_alert_config']) - def alert(self, matches): + 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 create_artifacts(self, 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(**{'rule': self.rule, 'match': match}))) + except KeyError: + raise KeyError('\nformat string\n{}\nmatch data\n{}'.format(match_data_key, {'rule': self.rule, 'match': match})) + 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[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 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) + 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( @@ -2128,56 +2177,27 @@ def alert(self, matches): 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} + 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 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 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, - '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)) + for match in matches: + artifacts += self.create_artifacts(match) + + 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) def get_info(self): From f926dee367c341a74dcb07dfe5013bb6fed1af91 Mon Sep 17 00:00:00 2001 From: Florian GAULTIER Date: Mon, 27 May 2019 22:47:14 +0200 Subject: [PATCH 2/4] Comply with flake8 --- elastalert/alerts.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/elastalert/alerts.py b/elastalert/alerts.py index 635550533..cb0dc654e 100644 --- a/elastalert/alerts.py +++ b/elastalert/alerts.py @@ -4,7 +4,6 @@ import json import logging import os -import re import subprocess import sys import time @@ -2126,12 +2125,13 @@ def get_aggregation_summary_text(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(**{'rule': self.rule, 'match': 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, {'rule': self.rule, 'match': match})) + raise KeyError('\nformat string\n{}\nmatch data\n{}'.format(match_data_key, context)) return artifacts def create_alert_config(self, match): From 116ed6dfc7591d7b8ba1c940320ebc31a2da6131 Mon Sep 17 00:00:00 2001 From: Florian GAULTIER Date: Tue, 28 May 2019 21:39:06 +0200 Subject: [PATCH 3/4] Add related_events to artifcats --- elastalert/alerts.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/elastalert/alerts.py b/elastalert/alerts.py index cb0dc654e..cbc342c76 100644 --- a/elastalert/alerts.py +++ b/elastalert/alerts.py @@ -2193,6 +2193,9 @@ def alert(self, matches): 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) alert_config['artifacts'] = artifacts alert_config['title'] = self.create_title(matches) From 68b0a75ea50423ec46bbb3f707ef6be6d7dcc906 Mon Sep 17 00:00:00 2001 From: Florian GAULTIER Date: Wed, 23 Oct 2019 14:46:25 +0200 Subject: [PATCH 4/4] iteritems to items --- elastalert/alerts.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/elastalert/alerts.py b/elastalert/alerts.py index cbc342c76..f1fab28a2 100644 --- a/elastalert/alerts.py +++ b/elastalert/alerts.py @@ -2127,7 +2127,7 @@ 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(): + for observable_type, match_data_key in mapping.items(): try: artifacts.append(AlertArtifact(dataType=observable_type, data=match_data_key.format(**context))) except KeyError: @@ -2144,10 +2144,10 @@ def create_alert_config(self, match): alert_config.update(self.rule.get('hive_alert_config', {})) - for alert_config_field, alert_config_value in alert_config.iteritems(): + 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.iteritems(): + for cf_key, cf_value in alert_config_value.items(): try: func = getattr(custom_fields, 'add_{}'.format(cf_value['type'])) except AttributeError: