|
4 | 4 | import json
|
5 | 5 | import logging
|
6 | 6 | import os
|
| 7 | +import re |
7 | 8 | import subprocess
|
8 | 9 | import sys
|
9 | 10 | import time
|
@@ -2104,3 +2105,72 @@ def alert(self, matches):
|
2104 | 2105 |
|
2105 | 2106 | def get_info(self):
|
2106 | 2107 | return {"type": "linenotify", "linenotify_access_token": self.linenotify_access_token}
|
| 2108 | + |
| 2109 | + |
| 2110 | +class HiveAlerter(Alerter): |
| 2111 | + """ |
| 2112 | + Use matched data to create alerts containing observables in an instance of TheHive |
| 2113 | + """ |
| 2114 | + |
| 2115 | + required_options = set(['hive_connection', 'hive_alert_config']) |
| 2116 | + |
| 2117 | + def alert(self, matches): |
| 2118 | + |
| 2119 | + connection_details = self.rule['hive_connection'] |
| 2120 | + |
| 2121 | + for match in matches: |
| 2122 | + context = {'rule': self.rule, 'match': match} |
| 2123 | + |
| 2124 | + artifacts = [] |
| 2125 | + for mapping in self.rule.get('hive_observable_data_mapping', []): |
| 2126 | + for observable_type, match_data_key in mapping.items(): |
| 2127 | + try: |
| 2128 | + match_data_keys = re.findall(r'\{match\[([^\]]*)\]', match_data_key) |
| 2129 | + rule_data_keys = re.findall(r'\{rule\[([^\]]*)\]', match_data_key) |
| 2130 | + data_keys = match_data_keys + rule_data_keys |
| 2131 | + context_keys = list(context['match'].keys()) + list(context['rule'].keys()) |
| 2132 | + if all([True if k in context_keys else False for k in data_keys]): |
| 2133 | + artifact = {'tlp': 2, 'tags': [], 'message': None, 'dataType': observable_type, |
| 2134 | + 'data': match_data_key.format(**context)} |
| 2135 | + artifacts.append(artifact) |
| 2136 | + except KeyError: |
| 2137 | + raise KeyError('\nformat string\n{}\nmatch data\n{}'.format(match_data_key, context)) |
| 2138 | + |
| 2139 | + alert_config = { |
| 2140 | + 'artifacts': artifacts, |
| 2141 | + 'sourceRef': str(uuid.uuid4())[0:6], |
| 2142 | + 'customFields': {}, |
| 2143 | + 'caseTemplate': None, |
| 2144 | + 'title': '{rule[index]}_{rule[name]}'.format(**context), |
| 2145 | + 'date': int(time.time()) * 1000 |
| 2146 | + } |
| 2147 | + alert_config.update(self.rule.get('hive_alert_config', {})) |
| 2148 | + |
| 2149 | + for alert_config_field, alert_config_value in alert_config.items(): |
| 2150 | + if isinstance(alert_config_value, str): |
| 2151 | + alert_config[alert_config_field] = alert_config_value.format(**context) |
| 2152 | + elif isinstance(alert_config_value, (list, tuple)): |
| 2153 | + formatted_list = [] |
| 2154 | + for element in alert_config_value: |
| 2155 | + try: |
| 2156 | + formatted_list.append(element.format(**context)) |
| 2157 | + except (AttributeError, KeyError, IndexError): |
| 2158 | + formatted_list.append(element) |
| 2159 | + alert_config[alert_config_field] = formatted_list |
| 2160 | + |
| 2161 | + alert_body = json.dumps(alert_config, indent=4, sort_keys=True) |
| 2162 | + req = '{}:{}/api/alert'.format(connection_details['hive_host'], connection_details['hive_port']) |
| 2163 | + headers = {'Content-Type': 'application/json', 'Authorization': 'Bearer {}'.format(connection_details.get('hive_apikey', ''))} |
| 2164 | + proxies = connection_details.get('hive_proxies', {'http': '', 'https': ''}) |
| 2165 | + verify = connection_details.get('hive_verify', False) |
| 2166 | + response = requests.post(req, headers=headers, data=alert_body, proxies=proxies, verify=verify) |
| 2167 | + |
| 2168 | + if response.status_code != 201: |
| 2169 | + raise Exception('alert not successfully created in TheHive\n{}'.format(response.text)) |
| 2170 | + |
| 2171 | + def get_info(self): |
| 2172 | + |
| 2173 | + return { |
| 2174 | + 'type': 'hivealerter', |
| 2175 | + 'hive_host': self.rule.get('hive_connection', {}).get('hive_host', '') |
| 2176 | + } |
0 commit comments