From 5419bd6f088cce284b3a16854e2641b2379d3e01 Mon Sep 17 00:00:00 2001 From: Wes Lambert Date: Mon, 23 Sep 2019 14:43:14 +0000 Subject: [PATCH 1/2] update config for Elastalert --- salt/elastalert/files/modules/so/thehive.py | 108 ++++++++++++++++++ salt/elastalert/files/rules/so/nids2hive.yaml | 5 +- salt/elastalert/init.sls | 12 +- 3 files changed, 117 insertions(+), 8 deletions(-) create mode 100644 salt/elastalert/files/modules/so/thehive.py diff --git a/salt/elastalert/files/modules/so/thehive.py b/salt/elastalert/files/modules/so/thehive.py new file mode 100644 index 000000000..d78a8d050 --- /dev/null +++ b/salt/elastalert/files/modules/so/thehive.py @@ -0,0 +1,108 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals +import uuid + +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 + """ + + 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 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_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)) + + 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) + + 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): + + 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 1d4b4ee39..ab0624e13 100644 --- a/salt/elastalert/files/rules/so/nids2hive.yaml +++ b/salt/elastalert/files/rules/so/nids2hive.yaml @@ -1,9 +1,10 @@ +{% set es = salt['pillar.get']('static:masterip', '') %} {% set hivehost = salt['pillar.get']('static:masterip', '') %} {% set hivekey = salt['pillar.get']('static:hivekey', '') %} # hive.yaml # Elastalert rule to forward IDS alerts from Security Onion to a specified TheHive instance. # -es_host: elasticsearch +es_host: {{es}} es_port: 9200 name: TheHive - New IDS Alert! type: frequency @@ -19,7 +20,7 @@ filter: - term: event_type: "ids" -alert: elastalert.modules.so.hivealerter +alert: modules.so.thehive.TheHiveAlerter hive_connection: hive_host: {{hivehost}} diff --git a/salt/elastalert/init.sls b/salt/elastalert/init.sls index b17e657ca..8e8b32ae6 100644 --- a/salt/elastalert/init.sls +++ b/salt/elastalert/init.sls @@ -111,13 +111,13 @@ elastaconf: so-elastalertimage: cmd.run: - - name: docker pull --disable-content-trust=false soshybridhunter/so-elastalert:HH1.1.0 + - name: docker pull --disable-content-trust=false soshybridhunter/so-elastalert:HH1.1.1 so-elastalert: docker_container.running: - require: - so-elastalertimage - - image: soshybridhunter/so-elastalert:HH1.1.0 + - image: soshybridhunter/so-elastalert:HH1.1.1 - hostname: elastalert - name: so-elastalert - user: elastalert @@ -125,14 +125,14 @@ so-elastalert: - binds: - /opt/so/rules/elastalert:/etc/elastalert/rules/:ro - /opt/so/log/elastalert:/var/log/elastalert:rw - - /opt/so/conf/elastalert/modules:/opt/elastalert/elastalert/modules:ro + - /opt/so/conf/elastalert/modules/:/opt/elastalert/modules/:ro - /opt/so/conf/elastalert/elastalert_config.yaml:/etc/elastalert/conf/elastalert_config.yaml:ro - environment: - #- ELASTICSEARCH_HOST: {{ esip }} - #- ELASTICSEARCH_PORT: {{ esport }} + - ELASTICSEARCH_HOST: {{ esip }} + - ELASTICSEARCH_PORT: {{ esport }} - ELASTALERT_CONFIG: /etc/elastalert/conf/elastalert_config.yaml - ELASTALERT_SUPERVISOR_CONF: /etc/elastalert/conf/elastalert_supervisord.conf - #- RULES_DIRECTORY: /etc/elastalert/rules/ + - RULES_DIRECTORY: /etc/elastalert/rules/ - LOG_DIR: /var/log/elastalert {% endif %} From 965ee6f922f2085a2a1bc39027409270fac95338 Mon Sep 17 00:00:00 2001 From: Wes Lambert Date: Mon, 23 Sep 2019 14:43:54 +0000 Subject: [PATCH 2/2] remove duplicate alerter --- .../files/modules/so/hivealerter.py | 108 ------------------ 1 file changed, 108 deletions(-) delete mode 100644 salt/elastalert/files/modules/so/hivealerter.py diff --git a/salt/elastalert/files/modules/so/hivealerter.py b/salt/elastalert/files/modules/so/hivealerter.py deleted file mode 100644 index fbe4d6aac..000000000 --- a/salt/elastalert/files/modules/so/hivealerter.py +++ /dev/null @@ -1,108 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import unicode_literals -import uuid - -from elastalert.alerts import Alerter -from thehive4py.api import TheHiveApi -from thehive4py.models import Alert, AlertArtifact, CustomFieldHelper - - -class HiveAlerter(Alerter): - """ - Use matched data to create alerts containing observables in an instance of TheHive - """ - - 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 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_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)) - - 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) - - 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): - - return { - 'type': 'hivealerter', - 'hive_host': self.rule.get('hive_connection', {}).get('hive_host', '') - }