Merge pull request #100 from weslambert/elastalert

more updates to Elastalert config
This commit is contained in:
Mike Reeves
2019-09-23 20:42:27 -04:00
committed by GitHub
2 changed files with 55 additions and 79 deletions

View File

@@ -1,108 +1,84 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from __future__ import unicode_literals from __future__ import unicode_literals
import uuid import uuid
import re
from elastalert.alerts import Alerter from elastalert.alerts import Alerter
from thehive4py.api import TheHiveApi from thehive4py.api import TheHiveApi
from thehive4py.models import Alert, AlertArtifact, CustomFieldHelper from thehive4py.models import Alert, AlertArtifact, CustomFieldHelper
class TheHiveAlerter(Alerter): class TheHiveAlerter(Alerter):
""" """
Use matched data to create alerts containing observables in an instance of TheHive 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']) required_options = set(['hive_connection', 'hive_alert_config'])
def get_aggregation_summary_text(self, matches): def alert(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'] connection_details = self.rule['hive_connection']
api = TheHiveApi( api = TheHiveApi(
connection_details.get('hive_host', ''), connection_details.get('hive_host'),
connection_details.get('hive_apikey', ''), connection_details.get('hive_apikey', ''),
proxies=connection_details.get('hive_proxies', {'http': '', 'https': ''}), proxies=connection_details.get('hive_proxies', {'http': '', 'https': ''}),
cert=connection_details.get('hive_verify', False)) cert=connection_details.get('hive_verify', False))
alert = Alert(**alert_config) for match in matches:
response = api.create_alert(alert) 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 = [] artifacts = []
for match in matches: for mapping in self.rule.get('hive_observable_data_mapping', []):
artifacts += self.create_artifacts(match) for observable_type, match_data_key in mapping.items():
if 'related_events' in match: try:
for related_event in match['related_events']: match_data_keys = re.findall(r'\{match\[([^\]]*)\]', match_data_key)
artifacts += self.create_artifacts(related_event) 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 = {
alert_config['title'] = self.create_title(matches) 'artifacts': artifacts,
alert_config['description'] = self.create_alert_body(matches) 'sourceRef': str(uuid.uuid4())[0:6],
self.send_to_thehive(alert_config) '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): def get_info(self):
return { return {
'type': 'hivealerter', 'type': 'hivealerter',
'hive_host': self.rule.get('hive_connection', {}).get('hive_host', '') 'hive_host': self.rule.get('hive_connection', {}).get('hive_host', '')
} }

View File

@@ -23,7 +23,7 @@ filter:
alert: modules.so.thehive.TheHiveAlerter alert: modules.so.thehive.TheHiveAlerter
hive_connection: hive_connection:
hive_host: {{hivehost}} hive_host: https://{{hivehost}}/thehive/
hive_apikey: {{hivekey}} hive_apikey: {{hivekey}}
hive_proxies: hive_proxies:
@@ -31,7 +31,7 @@ hive_proxies:
https: '' https: ''
hive_alert_config: hive_alert_config:
title: '{rule[name]} -- {match[alert]}' title: 'New Alert from Security Onion!'
type: 'external' type: 'external'
source: 'SecurityOnion' source: 'SecurityOnion'
description: '{match[message]}' description: '{match[message]}'