Skip to content

Commit

Permalink
Re-add TheHive alerter without any libraries
Browse files Browse the repository at this point in the history
  • Loading branch information
Qmando committed Apr 15, 2020
1 parent b45d767 commit 6a4ae2d
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 0 deletions.
1 change: 1 addition & 0 deletions docs/source/elastalert.rst
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 42,7 @@ Currently, we have support built in for these alert types:
- GoogleChat
- Debug
- Stomp
- TheHive

Additional rule types and alerts can be easily imported or written. (See :ref:`Writing rule types <writingrules>` and :ref:`Writing alerts <writingalerts>`)

Expand Down
45 changes: 45 additions & 0 deletions docs/source/ruletypes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2186,6 2186,51 @@ Required:

``linenotify_access_token``: The access token that you got from https://notify-bot.line.me/my/

theHive
~~~~~~

theHive alert type will send JSON request to theHive (Security Incident Response Platform) with TheHive4py API. Sent request will be stored like Hive Alert with description and observables.

Required:

``hive_connection``: The connection details as key:values. Required keys are ``hive_host``, ``hive_port`` and ``hive_apikey``.

``hive_alert_config``: Configuration options for the alert.

Optional:

``hive_proxies``: Proxy configuration.

``hive_observable_data_mapping``: If needed, matched data fields can be mapped to TheHive observable types using python string formatting.

Example usage::

alert: hivealerter

hive_connection:
hive_host: http://localhost
hive_port: <hive_port>
hive_apikey: <hive_apikey>
hive_proxies:
http: ''
https: ''

hive_alert_config:
title: 'Title' ## This will default to {rule[index]_rule[name]} if not provided
type: 'external'
source: 'elastalert'
description: '{match[field1]} {rule[name]} Sample description'
severity: 2
tags: ['tag1', 'tag2 {rule[name]}']
tlp: 3
status: 'New'
follow: True

hive_observable_data_mapping:
- domain: "{match[field1]}_{rule[name]}"
- domain: "{match[field]}"
- ip: "{match[ip_field]}"


Zabbix
~~~~~~~~~~~
Expand Down
70 changes: 70 additions & 0 deletions elastalert/alerts.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 4,7 @@
import json
import logging
import os
import re
import subprocess
import sys
import time
Expand Down Expand Up @@ -2104,3 2105,72 @@ def alert(self, matches):

def get_info(self):
return {"type": "linenotify", "linenotify_access_token": self.linenotify_access_token}


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 alert(self, matches):

connection_details = self.rule['hive_connection']

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.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]):
artifact = {'tlp': 2, 'tags': [], 'message': None, 'dataType': observable_type,
'data': match_data_key.format(**context)}
artifacts.append(artifact)
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],
'customFields': {},
'caseTemplate': None,
'title': '{rule[index]}_{rule[name]}'.format(**context),
'date': int(time.time()) * 1000
}
alert_config.update(self.rule.get('hive_alert_config', {}))

for alert_config_field, alert_config_value in alert_config.items():
if 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_body = json.dumps(alert_config, indent=4, sort_keys=True)
req = '{}:{}/api/alert'.format(connection_details['hive_host'], connection_details['hive_port'])
headers = {'Content-Type': 'application/json', 'Authorization': 'Bearer {}'.format(connection_details.get('hive_apikey', ''))}
proxies = connection_details.get('hive_proxies', {'http': '', 'https': ''})
verify = connection_details.get('hive_verify', False)
response = requests.post(req, headers=headers, data=alert_body, proxies=proxies, verify=verify)

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', '')
}
1 change: 1 addition & 0 deletions elastalert/loaders.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 77,7 @@ class RulesLoader(object):
'servicenow': alerts.ServiceNowAlerter,
'alerta': alerts.AlertaAlerter,
'post': alerts.HTTPPostAlerter,
'hivealerter': alerts.HiveAlerter
}

# A partial ordering of alert types. Relative order will be preserved in the resulting alerts list
Expand Down

0 comments on commit 6a4ae2d

Please sign in to comment.