From a3b2d73e49edc5b3299d2f3ad12619c6467c8dcb Mon Sep 17 00:00:00 2001 From: ITER Date: Fri, 20 May 2022 17:15:56 +0200 Subject: [PATCH 01/14] add an optionnal field description_args, in the thehive alerter, to allow the use of match and rule fields in the description for the alert in thehive, based on the model of alert_text and alert_text_args' --- elastalert/alerters/thehive.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/elastalert/alerters/thehive.py b/elastalert/alerters/thehive.py index e7dbf9a3..1792faa6 100644 --- a/elastalert/alerters/thehive.py +++ b/elastalert/alerters/thehive.py @@ -72,6 +72,23 @@ def load_tags(self, tag_names: list, match: dict): return tag_values + def load_description(self, description_raw, match: dict): + missing = self.rule.get('description_missing_value', '') + if 'description_args' in self.rule.get('hive_alert_config'): + description_args = self.rule['hive_alert_config'].get('description_args') + description_values=[] + for arg in description_args: + description_values.append(self.lookup_field(match, arg, arg)) + for i, text_value in enumerate(description_values): + if text_value is None: + description_value = self.rule.get(description_args[i]) + if description_value: + description_values[i] = description_value + description_values = [missing if val is None else val for val in description_values] + description_raw = description_raw.format(*description_values) + return description_raw + else: + return description_raw def alert(self, matches): # Build TheHive alert object, starting with some defaults, updating with any # user-specified config From 36c8d71543fd9db1a1c994d8fd6ec23be7059638 Mon Sep 17 00:00:00 2001 From: ITER Date: Fri, 20 May 2022 17:19:44 +0200 Subject: [PATCH 02/14] add an optionnal field description_args, in the thehive alerter, to allow the use of match and rule fields in the description for the alert in thehive, based on the model of alert_text and alert_text_args' --- elastalert/alerters/thehive.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/elastalert/alerters/thehive.py b/elastalert/alerters/thehive.py index 1792faa6..c1b72e5e 100644 --- a/elastalert/alerters/thehive.py +++ b/elastalert/alerters/thehive.py @@ -102,7 +102,7 @@ def alert(self, matches): 'title': self.create_title(matches), } alert_config.update(self.rule.get('hive_alert_config', {})) - + alert_config['description']=self.load_description(alert_config['description'], matches[0]) # Iterate through each match found, populating the alert tags and observables as required tags = set() artifacts = [] From 252c6bd3b912bffb1540c86cad4a2b1f8cb2c09c Mon Sep 17 00:00:00 2001 From: luffynextgen <34096485+luffynextgen@users.noreply.github.com> Date: Fri, 20 May 2022 17:33:22 +0200 Subject: [PATCH 03/14] update hivealerter add documentation for description_args field in the hive --- docs/source/ruletypes.rst | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/source/ruletypes.rst b/docs/source/ruletypes.rst index 0dd88823..2451fd99 100644 --- a/docs/source/ruletypes.rst +++ b/docs/source/ruletypes.rst @@ -3232,6 +3232,8 @@ the observable value is also the same, including the behaviour for aggregated al ``hive_verify``: Whether or not to enable SSL certificate validation. Defaults to False. +``description_args``: can be used to call rule and match fileds in the description of the alert in TheHive + Example usage:: alert: hivealerter @@ -3253,7 +3255,8 @@ Example usage:: severity: 2 status: 'New' source: 'elastalert' - description: 'Sample description' + description_args: [ name, description] + description: '{0} : {1}' tags: ['tag1', 'tag2'] title: 'Title' tlp: 3 From efc4c0658dba972b8a7637c8458ce0a9701e06a3 Mon Sep 17 00:00:00 2001 From: luffynextgen <34096485+luffynextgen@users.noreply.github.com> Date: Fri, 20 May 2022 17:35:52 +0200 Subject: [PATCH 04/14] update hivealerter Add the possibility to use rule and match fileds in the description of TheHive alert --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 12b668f3..5b6581c8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ ## Other changes - Upgrade stomp 8.0.0 to 8.0.1 - [#832](https://github.com/jertel/elastalert2/pull/832) - @jertel - Add support for Kibana 8.2 for Kibana Discover, Upgrade Pytest 7.1.1 to 7.1.2, Upgrade pylint 2.13.5 to 2.13.8, Upgrade Jinja2 3.1.1 to 3.1.2 - [#840](https://github.com/jertel/elastalert2/pull/840) - @nsano-rururu +- Add the possibility to use rule and match fileds in the description of TheHive alert # 2.5.0 From e9f8f5ec709d08a0f54ecfcbda2bb663644f9a0f Mon Sep 17 00:00:00 2001 From: ITER Date: Mon, 23 May 2022 14:54:51 +0200 Subject: [PATCH 05/14] add unit test for theHive alert description --- elastalert/alerters/thehive.py | 2 +- tests/alerters/unitTestDescription_TheHive.py | 183 ++++++++++++++++++ tests/thehive_description_test.py | 5 + 3 files changed, 189 insertions(+), 1 deletion(-) create mode 100644 tests/alerters/unitTestDescription_TheHive.py create mode 100644 tests/thehive_description_test.py diff --git a/elastalert/alerters/thehive.py b/elastalert/alerters/thehive.py index c1b72e5e..3624eac6 100644 --- a/elastalert/alerters/thehive.py +++ b/elastalert/alerters/thehive.py @@ -73,7 +73,7 @@ def load_tags(self, tag_names: list, match: dict): return tag_values def load_description(self, description_raw, match: dict): - missing = self.rule.get('description_missing_value', '') + missing = self.rule['hive_alert_config'].get('description_missing_value', '') if 'description_args' in self.rule.get('hive_alert_config'): description_args = self.rule['hive_alert_config'].get('description_args') description_values=[] diff --git a/tests/alerters/unitTestDescription_TheHive.py b/tests/alerters/unitTestDescription_TheHive.py new file mode 100644 index 00000000..f94e1e9e --- /dev/null +++ b/tests/alerters/unitTestDescription_TheHive.py @@ -0,0 +1,183 @@ +import json +import logging + +from unittest import mock +import pytest +from requests import RequestException + +from elastalert.util import EAException +from elastalert.loaders import FileRulesLoader +from elastalert.alerters.thehive import HiveAlerter + +#### Test when description is not submitted under hive_alert_config +def test_load_description_1(): + rule = {'alert': [], + 'alert_text': '', + 'alert_text_type': 'alert_text_only', + 'description': 'test', + 'hive_alert_config': {'customFields': [{'name': 'test', + 'type': 'string', + 'value': 2}], + 'follow': True, + 'severity': 2, + 'source': 'elastalert', + 'status': 'New', + 'tags': ['test.port'], + 'tlp': 3, + 'type': 'external'}, + 'hive_connection': {'hive_apikey': '', + 'hive_host': 'https://localhost', + 'hive_port': 9000}, + 'hive_observable_data_mapping': [{'ip': 'test.ip', 'autonomous-system': 'test.as_number'}], + 'name': 'test-thehive', + 'tags': ['a', 'b'], + 'type': 'any'} + + rules_loader = FileRulesLoader({}) + rules_loader.load_modules(rule) + alert = HiveAlerter(rule) + match = { + "test": { + "ip": "127.0.0.1", + "port": 9876, + "as_number": 1234 + }, + "@timestamp": "2021-05-09T14:43:30", + } + + actual = alert.load_description(alert.create_alert_body(match), match) + expected=alert.create_alert_body(match) + assert actual == expected + +#### Test when description is submitted under hive_alert_config but description_args is not +def test_load_description_2(): + rule = {'alert': [], + 'alert_text': '', + 'alert_text_type': 'alert_text_only', + 'description': 'test', + 'hive_alert_config': {'customFields': [{'name': 'test', + 'type': 'string', + 'value': 2}], + 'follow': True, + 'severity': 2, + 'source': 'elastalert', + 'description': 'TheHive description test', + 'status': 'New', + 'tags': ['test.port'], + 'tlp': 3, + 'type': 'external'}, + 'hive_connection': {'hive_apikey': '', + 'hive_host': 'https://localhost', + 'hive_port': 9000}, + 'hive_observable_data_mapping': [{'ip': 'test.ip', 'autonomous-system': 'test.as_number'}], + 'name': 'test-thehive', + 'tags': ['a', 'b'], + 'type': 'any'} + + rules_loader = FileRulesLoader({}) + rules_loader.load_modules(rule) + alert = HiveAlerter(rule) + match = { + "test": { + "ip": "127.0.0.1", + "port": 9876, + "as_number": 1234 + }, + "@timestamp": "2021-05-09T14:43:30", + } + actual = alert.load_description(rule['hive_alert_config']['description'], match) + expected = rule['hive_alert_config']['description'] + assert actual == expected + + +### Test with description_missing_value + +def test_load_description_3(): + rule = {'alert': [], + 'alert_text': '', + 'alert_text_type': 'alert_text_only', + 'title': 'Unit test', + 'description': 'test', + 'hive_alert_config': {'customFields': [{'name': 'test', + 'type': 'string', + 'value': 2}], + 'follow': True, + 'severity': 2, + 'source': 'elastalert', + 'description_missing_value': '', + 'description_args': [ 'title', 'test.ip', 'host' ], + 'description': '{0} from host:{2} to {1}', + 'status': 'New', + 'tags': ['test.port'], + 'tlp': 3, + 'type': 'external'}, + 'hive_connection': {'hive_apikey': '', + 'hive_host': 'https://localhost', + 'hive_port': 9000}, + 'hive_observable_data_mapping': [{'ip': 'test.ip', 'autonomous-system': 'test.as_number'}], + 'name': 'test-thehive', + 'tags': ['a', 'b'], + 'type': 'any'} + + rules_loader = FileRulesLoader({}) + rules_loader.load_modules(rule) + alert = HiveAlerter(rule) + match = { + "test": { + "ip": "127.0.0.1", + "port": 9876, + "as_number": 1234 + }, + "@timestamp": "2021-05-09T14:43:30", + } + actual = alert.load_description(rule['hive_alert_config']['description'], match) + expected = "Unit test from host: to 127.0.0.1" + assert actual == expected + + +### Test without description_missing_value, missing values a replaced by a default value +def test_load_description_4(): + rule = {'alert': [], + 'alert_text': '', + 'alert_text_type': 'alert_text_only', + 'title': 'Unit test', + 'description': 'test', + 'hive_alert_config': {'customFields': [{'name': 'test', + 'type': 'string', + 'value': 2}], + 'follow': True, + 'severity': 2, + 'source': 'elastalert', + 'description_args': [ 'title', 'test.ip', 'host' ], + 'description': '{0} from host:{2} to {1}', + 'status': 'New', + 'tags': ['test.port'], + 'tlp': 3, + 'type': 'external'}, + 'hive_connection': {'hive_apikey': '', + 'hive_host': 'https://localhost', + 'hive_port': 9000}, + 'hive_observable_data_mapping': [{'ip': 'test.ip', 'autonomous-system': 'test.as_number'}], + 'name': 'test-thehive', + 'tags': ['a', 'b'], + 'type': 'any'} + + rules_loader = FileRulesLoader({}) + rules_loader.load_modules(rule) + alert = HiveAlerter(rule) + match = { + "test": { + "ip": "127.0.0.1", + "port": 9876, + "as_number": 1234 + }, + "@timestamp": "2021-05-09T14:43:30", + } + actual = alert.load_description(rule['hive_alert_config']['description'], match) + expected = "Unit test from host: to 127.0.0.1" + assert actual == expected + +test_load_description_1() +test_load_description_2() +test_load_description_3() +test_load_description_4() diff --git a/tests/thehive_description_test.py b/tests/thehive_description_test.py new file mode 100644 index 00000000..1b61dc88 --- /dev/null +++ b/tests/thehive_description_test.py @@ -0,0 +1,5 @@ +# -*- coding: utf-8 -*- +from datetime import timedelta +import pytest + +from elastalert.kibana_discover import load_description From b62493add880d91cd3800f2777b1b4987e27995b Mon Sep 17 00:00:00 2001 From: ITER Date: Mon, 23 May 2022 14:56:49 +0200 Subject: [PATCH 06/14] add unit test for theHive alert description --- tests/thehive_description_test.py | 5 ----- tests/{alerters => }/thehive_test.py | 0 2 files changed, 5 deletions(-) delete mode 100644 tests/thehive_description_test.py rename tests/{alerters => }/thehive_test.py (100%) diff --git a/tests/thehive_description_test.py b/tests/thehive_description_test.py deleted file mode 100644 index 1b61dc88..00000000 --- a/tests/thehive_description_test.py +++ /dev/null @@ -1,5 +0,0 @@ -# -*- coding: utf-8 -*- -from datetime import timedelta -import pytest - -from elastalert.kibana_discover import load_description diff --git a/tests/alerters/thehive_test.py b/tests/thehive_test.py similarity index 100% rename from tests/alerters/thehive_test.py rename to tests/thehive_test.py From 77bf90d670ac71a29f00d015e18a476c4e5f5806 Mon Sep 17 00:00:00 2001 From: ITER Date: Mon, 23 May 2022 15:04:48 +0200 Subject: [PATCH 07/14] update documentation and changelog --- CHANGELOG.md | 2 +- docs/source/ruletypes.rst | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5b6581c8..e7fbaf9f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,7 @@ ## Other changes - Upgrade stomp 8.0.0 to 8.0.1 - [#832](https://github.com/jertel/elastalert2/pull/832) - @jertel - Add support for Kibana 8.2 for Kibana Discover, Upgrade Pytest 7.1.1 to 7.1.2, Upgrade pylint 2.13.5 to 2.13.8, Upgrade Jinja2 3.1.1 to 3.1.2 - [#840](https://github.com/jertel/elastalert2/pull/840) - @nsano-rururu -- Add the possibility to use rule and match fileds in the description of TheHive alert +- Add the possibility to use rule and match fields in the description of TheHive alerts - [#855](https://github.com/jertel/elastalert2/pull/855) - @luffynextgen # 2.5.0 diff --git a/docs/source/ruletypes.rst b/docs/source/ruletypes.rst index 2451fd99..2a2aa13c 100644 --- a/docs/source/ruletypes.rst +++ b/docs/source/ruletypes.rst @@ -3233,6 +3233,7 @@ the observable value is also the same, including the behaviour for aggregated al ``hive_verify``: Whether or not to enable SSL certificate validation. Defaults to False. ``description_args``: can be used to call rule and match fileds in the description of the alert in TheHive +``description_missing_value``: Text to replace any match field not found when formating the ``description``. Defaults to ````. Example usage:: From 0e66a4f037aaf1d2b01c3f5a7cc49774baebc270 Mon Sep 17 00:00:00 2001 From: ITER Date: Mon, 23 May 2022 15:07:49 +0200 Subject: [PATCH 08/14] move unitTestDescription_TheHive.py to tests/ --- tests/{alerters => }/unitTestDescription_TheHive.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/{alerters => }/unitTestDescription_TheHive.py (100%) diff --git a/tests/alerters/unitTestDescription_TheHive.py b/tests/unitTestDescription_TheHive.py similarity index 100% rename from tests/alerters/unitTestDescription_TheHive.py rename to tests/unitTestDescription_TheHive.py From 89dfa988ffab3c4c97e62b07f7a2de08109ce0ed Mon Sep 17 00:00:00 2001 From: ITER Date: Mon, 23 May 2022 16:26:39 +0200 Subject: [PATCH 09/14] move back thehive_test to test/alerters and add the unit test for the hive description in thehive_test.py --- tests/{ => alerters}/thehive_test.py | 167 ++++++++++++++++++++++++ tests/unitTestDescription_TheHive.py | 183 --------------------------- 2 files changed, 167 insertions(+), 183 deletions(-) rename tests/{ => alerters}/thehive_test.py (61%) delete mode 100644 tests/unitTestDescription_TheHive.py diff --git a/tests/thehive_test.py b/tests/alerters/thehive_test.py similarity index 61% rename from tests/thehive_test.py rename to tests/alerters/thehive_test.py index e954588d..1ddd3027 100644 --- a/tests/thehive_test.py +++ b/tests/alerters/thehive_test.py @@ -304,3 +304,170 @@ def test_load_tags(tags, expect): } actual = alert.load_tags(tags, match) assert expect == actual + +def test_load_description_1(): + rule = {'alert': [], + 'alert_text': '', + 'alert_text_type': 'alert_text_only', + 'description': 'test', + 'hive_alert_config': {'customFields': [{'name': 'test', + 'type': 'string', + 'value': 2}], + 'follow': True, + 'severity': 2, + 'source': 'elastalert', + 'status': 'New', + 'tags': ['test.port'], + 'tlp': 3, + 'type': 'external'}, + 'hive_connection': {'hive_apikey': '', + 'hive_host': 'https://localhost', + 'hive_port': 9000}, + 'hive_observable_data_mapping': [{'ip': 'test.ip', 'autonomous-system': 'test.as_number'}], + 'name': 'test-thehive', + 'tags': ['a', 'b'], + 'type': 'any'} + + rules_loader = FileRulesLoader({}) + rules_loader.load_modules(rule) + alert = HiveAlerter(rule) + match = { + "test": { + "ip": "127.0.0.1", + "port": 9876, + "as_number": 1234 + }, + "@timestamp": "2021-05-09T14:43:30", + } + + actual = alert.load_description(alert.create_alert_body(match), match) + expected=alert.create_alert_body(match) + assert actual == expected + +#### Test when description is submitted under hive_alert_config but description_args is not +def test_load_description_2(): + rule = {'alert': [], + 'alert_text': '', + 'alert_text_type': 'alert_text_only', + 'description': 'test', + 'hive_alert_config': {'customFields': [{'name': 'test', + 'type': 'string', + 'value': 2}], + 'follow': True, + 'severity': 2, + 'source': 'elastalert', + 'description': 'TheHive description test', + 'status': 'New', + 'tags': ['test.port'], + 'tlp': 3, + 'type': 'external'}, + 'hive_connection': {'hive_apikey': '', + 'hive_host': 'https://localhost', + 'hive_port': 9000}, + 'hive_observable_data_mapping': [{'ip': 'test.ip', 'autonomous-system': 'test.as_number'}], + 'name': 'test-thehive', + 'tags': ['a', 'b'], + 'type': 'any'} + + rules_loader = FileRulesLoader({}) + rules_loader.load_modules(rule) + alert = HiveAlerter(rule) + match = { + "test": { + "ip": "127.0.0.1", + "port": 9876, + "as_number": 1234 + }, + "@timestamp": "2021-05-09T14:43:30", + } + actual = alert.load_description(rule['hive_alert_config']['description'], match) + expected = rule['hive_alert_config']['description'] + assert actual == expected + + +### Test with description_missing_value + +def test_load_description_3(): + rule = {'alert': [], + 'alert_text': '', + 'alert_text_type': 'alert_text_only', + 'title': 'Unit test', + 'description': 'test', + 'hive_alert_config': {'customFields': [{'name': 'test', + 'type': 'string', + 'value': 2}], + 'follow': True, + 'severity': 2, + 'source': 'elastalert', + 'description_missing_value': '', + 'description_args': [ 'title', 'test.ip', 'host' ], + 'description': '{0} from host:{2} to {1}', + 'status': 'New', + 'tags': ['test.port'], + 'tlp': 3, + 'type': 'external'}, + 'hive_connection': {'hive_apikey': '', + 'hive_host': 'https://localhost', + 'hive_port': 9000}, + 'hive_observable_data_mapping': [{'ip': 'test.ip', 'autonomous-system': 'test.as_number'}], + 'name': 'test-thehive', + 'tags': ['a', 'b'], + 'type': 'any'} + + rules_loader = FileRulesLoader({}) + rules_loader.load_modules(rule) + alert = HiveAlerter(rule) + match = { + "test": { + "ip": "127.0.0.1", + "port": 9876, + "as_number": 1234 + }, + "@timestamp": "2021-05-09T14:43:30", + } + actual = alert.load_description(rule['hive_alert_config']['description'], match) + expected = "Unit test from host: to 127.0.0.1" + assert actual == expected + + +### Test without description_missing_value, missing values a replaced by a default value +def test_load_description_4(): + rule = {'alert': [], + 'alert_text': '', + 'alert_text_type': 'alert_text_only', + 'title': 'Unit test', + 'description': 'test', + 'hive_alert_config': {'customFields': [{'name': 'test', + 'type': 'string', + 'value': 2}], + 'follow': True, + 'severity': 2, + 'source': 'elastalert', + 'description_args': [ 'title', 'test.ip', 'host' ], + 'description': '{0} from host:{2} to {1}', + 'status': 'New', + 'tags': ['test.port'], + 'tlp': 3, + 'type': 'external'}, + 'hive_connection': {'hive_apikey': '', + 'hive_host': 'https://localhost', + 'hive_port': 9000}, + 'hive_observable_data_mapping': [{'ip': 'test.ip', 'autonomous-system': 'test.as_number'}], + 'name': 'test-thehive', + 'tags': ['a', 'b'], + 'type': 'any'} + + rules_loader = FileRulesLoader({}) + rules_loader.load_modules(rule) + alert = HiveAlerter(rule) + match = { + "test": { + "ip": "127.0.0.1", + "port": 9876, + "as_number": 1234 + }, + "@timestamp": "2021-05-09T14:43:30", + } + actual = alert.load_description(rule['hive_alert_config']['description'], match) + expected = "Unit test from host: to 127.0.0.1" + assert actual == expected \ No newline at end of file diff --git a/tests/unitTestDescription_TheHive.py b/tests/unitTestDescription_TheHive.py deleted file mode 100644 index f94e1e9e..00000000 --- a/tests/unitTestDescription_TheHive.py +++ /dev/null @@ -1,183 +0,0 @@ -import json -import logging - -from unittest import mock -import pytest -from requests import RequestException - -from elastalert.util import EAException -from elastalert.loaders import FileRulesLoader -from elastalert.alerters.thehive import HiveAlerter - -#### Test when description is not submitted under hive_alert_config -def test_load_description_1(): - rule = {'alert': [], - 'alert_text': '', - 'alert_text_type': 'alert_text_only', - 'description': 'test', - 'hive_alert_config': {'customFields': [{'name': 'test', - 'type': 'string', - 'value': 2}], - 'follow': True, - 'severity': 2, - 'source': 'elastalert', - 'status': 'New', - 'tags': ['test.port'], - 'tlp': 3, - 'type': 'external'}, - 'hive_connection': {'hive_apikey': '', - 'hive_host': 'https://localhost', - 'hive_port': 9000}, - 'hive_observable_data_mapping': [{'ip': 'test.ip', 'autonomous-system': 'test.as_number'}], - 'name': 'test-thehive', - 'tags': ['a', 'b'], - 'type': 'any'} - - rules_loader = FileRulesLoader({}) - rules_loader.load_modules(rule) - alert = HiveAlerter(rule) - match = { - "test": { - "ip": "127.0.0.1", - "port": 9876, - "as_number": 1234 - }, - "@timestamp": "2021-05-09T14:43:30", - } - - actual = alert.load_description(alert.create_alert_body(match), match) - expected=alert.create_alert_body(match) - assert actual == expected - -#### Test when description is submitted under hive_alert_config but description_args is not -def test_load_description_2(): - rule = {'alert': [], - 'alert_text': '', - 'alert_text_type': 'alert_text_only', - 'description': 'test', - 'hive_alert_config': {'customFields': [{'name': 'test', - 'type': 'string', - 'value': 2}], - 'follow': True, - 'severity': 2, - 'source': 'elastalert', - 'description': 'TheHive description test', - 'status': 'New', - 'tags': ['test.port'], - 'tlp': 3, - 'type': 'external'}, - 'hive_connection': {'hive_apikey': '', - 'hive_host': 'https://localhost', - 'hive_port': 9000}, - 'hive_observable_data_mapping': [{'ip': 'test.ip', 'autonomous-system': 'test.as_number'}], - 'name': 'test-thehive', - 'tags': ['a', 'b'], - 'type': 'any'} - - rules_loader = FileRulesLoader({}) - rules_loader.load_modules(rule) - alert = HiveAlerter(rule) - match = { - "test": { - "ip": "127.0.0.1", - "port": 9876, - "as_number": 1234 - }, - "@timestamp": "2021-05-09T14:43:30", - } - actual = alert.load_description(rule['hive_alert_config']['description'], match) - expected = rule['hive_alert_config']['description'] - assert actual == expected - - -### Test with description_missing_value - -def test_load_description_3(): - rule = {'alert': [], - 'alert_text': '', - 'alert_text_type': 'alert_text_only', - 'title': 'Unit test', - 'description': 'test', - 'hive_alert_config': {'customFields': [{'name': 'test', - 'type': 'string', - 'value': 2}], - 'follow': True, - 'severity': 2, - 'source': 'elastalert', - 'description_missing_value': '', - 'description_args': [ 'title', 'test.ip', 'host' ], - 'description': '{0} from host:{2} to {1}', - 'status': 'New', - 'tags': ['test.port'], - 'tlp': 3, - 'type': 'external'}, - 'hive_connection': {'hive_apikey': '', - 'hive_host': 'https://localhost', - 'hive_port': 9000}, - 'hive_observable_data_mapping': [{'ip': 'test.ip', 'autonomous-system': 'test.as_number'}], - 'name': 'test-thehive', - 'tags': ['a', 'b'], - 'type': 'any'} - - rules_loader = FileRulesLoader({}) - rules_loader.load_modules(rule) - alert = HiveAlerter(rule) - match = { - "test": { - "ip": "127.0.0.1", - "port": 9876, - "as_number": 1234 - }, - "@timestamp": "2021-05-09T14:43:30", - } - actual = alert.load_description(rule['hive_alert_config']['description'], match) - expected = "Unit test from host: to 127.0.0.1" - assert actual == expected - - -### Test without description_missing_value, missing values a replaced by a default value -def test_load_description_4(): - rule = {'alert': [], - 'alert_text': '', - 'alert_text_type': 'alert_text_only', - 'title': 'Unit test', - 'description': 'test', - 'hive_alert_config': {'customFields': [{'name': 'test', - 'type': 'string', - 'value': 2}], - 'follow': True, - 'severity': 2, - 'source': 'elastalert', - 'description_args': [ 'title', 'test.ip', 'host' ], - 'description': '{0} from host:{2} to {1}', - 'status': 'New', - 'tags': ['test.port'], - 'tlp': 3, - 'type': 'external'}, - 'hive_connection': {'hive_apikey': '', - 'hive_host': 'https://localhost', - 'hive_port': 9000}, - 'hive_observable_data_mapping': [{'ip': 'test.ip', 'autonomous-system': 'test.as_number'}], - 'name': 'test-thehive', - 'tags': ['a', 'b'], - 'type': 'any'} - - rules_loader = FileRulesLoader({}) - rules_loader.load_modules(rule) - alert = HiveAlerter(rule) - match = { - "test": { - "ip": "127.0.0.1", - "port": 9876, - "as_number": 1234 - }, - "@timestamp": "2021-05-09T14:43:30", - } - actual = alert.load_description(rule['hive_alert_config']['description'], match) - expected = "Unit test from host: to 127.0.0.1" - assert actual == expected - -test_load_description_1() -test_load_description_2() -test_load_description_3() -test_load_description_4() From e117ef7115193ed5558a469ed2c6eb7e53f633ad Mon Sep 17 00:00:00 2001 From: ITER Date: Mon, 23 May 2022 16:56:32 +0200 Subject: [PATCH 10/14] rename unit test functions --- tests/alerters/thehive_test.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/alerters/thehive_test.py b/tests/alerters/thehive_test.py index 1ddd3027..54a25aaa 100644 --- a/tests/alerters/thehive_test.py +++ b/tests/alerters/thehive_test.py @@ -305,7 +305,7 @@ def test_load_tags(tags, expect): actual = alert.load_tags(tags, match) assert expect == actual -def test_load_description_1(): +def test_load_description_default(): rule = {'alert': [], 'alert_text': '', 'alert_text_type': 'alert_text_only', @@ -345,7 +345,7 @@ def test_load_description_1(): assert actual == expected #### Test when description is submitted under hive_alert_config but description_args is not -def test_load_description_2(): +def test_load_description_no_args(): rule = {'alert': [], 'alert_text': '', 'alert_text_type': 'alert_text_only', @@ -387,7 +387,7 @@ def test_load_description_2(): ### Test with description_missing_value -def test_load_description_3(): +def test_load_description_args(): rule = {'alert': [], 'alert_text': '', 'alert_text_type': 'alert_text_only', @@ -431,7 +431,7 @@ def test_load_description_3(): ### Test without description_missing_value, missing values a replaced by a default value -def test_load_description_4(): +def test_load_description_missing_value_default(): rule = {'alert': [], 'alert_text': '', 'alert_text_type': 'alert_text_only', From 258273681e902f5f47713d348ad82bda4e95fa0e Mon Sep 17 00:00:00 2001 From: ITER Date: Mon, 23 May 2022 17:25:24 +0200 Subject: [PATCH 11/14] add empty list check for matches variable, before calling the load functions to populate the alert fields --- elastalert/alerters/thehive.py | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/elastalert/alerters/thehive.py b/elastalert/alerters/thehive.py index 3624eac6..d9e02bf8 100644 --- a/elastalert/alerters/thehive.py +++ b/elastalert/alerters/thehive.py @@ -102,19 +102,21 @@ def alert(self, matches): 'title': self.create_title(matches), } alert_config.update(self.rule.get('hive_alert_config', {})) - alert_config['description']=self.load_description(alert_config['description'], matches[0]) - # Iterate through each match found, populating the alert tags and observables as required - tags = set() - artifacts = [] - for match in matches: - artifacts = artifacts + self.load_observable_artifacts(match) - tags.update(self.load_tags(alert_config['tags'], match)) - - alert_config['artifacts'] = artifacts - alert_config['tags'] = list(tags) - - # Populate the customFields - alert_config['customFields'] = self.load_custom_fields(alert_config['customFields'], + if not matches: + #Populate description field + alert_config['description']=self.load_description(alert_config['description'], matches[0]) + # Iterate through each match found, populating the alert tags and observables as required + tags = set() + artifacts = [] + for match in matches: + artifacts = artifacts + self.load_observable_artifacts(match) + tags.update(self.load_tags(alert_config['tags'], match)) + + alert_config['artifacts'] = artifacts + alert_config['tags'] = list(tags) + + # Populate the customFields + alert_config['customFields'] = self.load_custom_fields(alert_config['customFields'], matches[0]) # POST the alert to TheHive From 1c8a5a187baa511e4e3ec24ea0735a70d9f2fcc4 Mon Sep 17 00:00:00 2001 From: ITER Date: Mon, 23 May 2022 17:58:51 +0200 Subject: [PATCH 12/14] change enpty check list to only keep custom fields and description under it --- elastalert/alerters/thehive.py | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/elastalert/alerters/thehive.py b/elastalert/alerters/thehive.py index d9e02bf8..2787d59a 100644 --- a/elastalert/alerters/thehive.py +++ b/elastalert/alerters/thehive.py @@ -102,20 +102,21 @@ def alert(self, matches): 'title': self.create_title(matches), } alert_config.update(self.rule.get('hive_alert_config', {})) - if not matches: - #Populate description field - alert_config['description']=self.load_description(alert_config['description'], matches[0]) - # Iterate through each match found, populating the alert tags and observables as required - tags = set() - artifacts = [] - for match in matches: - artifacts = artifacts + self.load_observable_artifacts(match) - tags.update(self.load_tags(alert_config['tags'], match)) + + # Iterate through each match found, populating the alert tags and observables as required + tags = set() + artifacts = [] + for match in matches: + artifacts = artifacts + self.load_observable_artifacts(match) + tags.update(self.load_tags(alert_config['tags'], match)) - alert_config['artifacts'] = artifacts - alert_config['tags'] = list(tags) + alert_config['artifacts'] = artifacts + alert_config['tags'] = list(tags) # Populate the customFields + if len(matches) > 0: + #Populate description field + alert_config['description']=self.load_description(alert_config['description'], matches[0]) alert_config['customFields'] = self.load_custom_fields(alert_config['customFields'], matches[0]) From de157ff65eb04fe177838bac804d844299fefd60 Mon Sep 17 00:00:00 2001 From: ITER Date: Tue, 24 May 2022 09:16:39 +0200 Subject: [PATCH 13/14] replace dedfault value by missing argument in description lookup field --- elastalert/alerters/thehive.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/elastalert/alerters/thehive.py b/elastalert/alerters/thehive.py index 2787d59a..e50ad201 100644 --- a/elastalert/alerters/thehive.py +++ b/elastalert/alerters/thehive.py @@ -78,7 +78,7 @@ def load_description(self, description_raw, match: dict): description_args = self.rule['hive_alert_config'].get('description_args') description_values=[] for arg in description_args: - description_values.append(self.lookup_field(match, arg, arg)) + description_values.append(self.lookup_field(match, arg, missing)) for i, text_value in enumerate(description_values): if text_value is None: description_value = self.rule.get(description_args[i]) From 1085436dd512d64142b1f4e43a8fbea174e1f1e4 Mon Sep 17 00:00:00 2001 From: ITER Date: Tue, 24 May 2022 14:17:16 +0200 Subject: [PATCH 14/14] correction of lint problem --- tests/alerters/thehive_test.py | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/tests/alerters/thehive_test.py b/tests/alerters/thehive_test.py index 54a25aaa..7bd1dc89 100644 --- a/tests/alerters/thehive_test.py +++ b/tests/alerters/thehive_test.py @@ -305,6 +305,7 @@ def test_load_tags(tags, expect): actual = alert.load_tags(tags, match) assert expect == actual + def test_load_description_default(): rule = {'alert': [], 'alert_text': '', @@ -327,7 +328,7 @@ def test_load_description_default(): 'name': 'test-thehive', 'tags': ['a', 'b'], 'type': 'any'} - + rules_loader = FileRulesLoader({}) rules_loader.load_modules(rule) alert = HiveAlerter(rule) @@ -341,10 +342,11 @@ def test_load_description_default(): } actual = alert.load_description(alert.create_alert_body(match), match) - expected=alert.create_alert_body(match) + expected = alert.create_alert_body(match) assert actual == expected -#### Test when description is submitted under hive_alert_config but description_args is not + +# Test when description is submitted under hive_alert_config but description_args is not def test_load_description_no_args(): rule = {'alert': [], 'alert_text': '', @@ -368,7 +370,7 @@ def test_load_description_no_args(): 'name': 'test-thehive', 'tags': ['a', 'b'], 'type': 'any'} - + rules_loader = FileRulesLoader({}) rules_loader.load_modules(rule) alert = HiveAlerter(rule) @@ -385,7 +387,7 @@ def test_load_description_no_args(): assert actual == expected -### Test with description_missing_value +# Test with description_missing_value def test_load_description_args(): rule = {'alert': [], @@ -400,7 +402,7 @@ def test_load_description_args(): 'severity': 2, 'source': 'elastalert', 'description_missing_value': '', - 'description_args': [ 'title', 'test.ip', 'host' ], + 'description_args': ['title', 'test.ip', 'host'], 'description': '{0} from host:{2} to {1}', 'status': 'New', 'tags': ['test.port'], @@ -413,7 +415,7 @@ def test_load_description_args(): 'name': 'test-thehive', 'tags': ['a', 'b'], 'type': 'any'} - + rules_loader = FileRulesLoader({}) rules_loader.load_modules(rule) alert = HiveAlerter(rule) @@ -430,7 +432,7 @@ def test_load_description_args(): assert actual == expected -### Test without description_missing_value, missing values a replaced by a default value +# Test without description_missing_value, missing values a replaced by a default value def test_load_description_missing_value_default(): rule = {'alert': [], 'alert_text': '', @@ -443,7 +445,7 @@ def test_load_description_missing_value_default(): 'follow': True, 'severity': 2, 'source': 'elastalert', - 'description_args': [ 'title', 'test.ip', 'host' ], + 'description_args': ['title', 'test.ip', 'host'], 'description': '{0} from host:{2} to {1}', 'status': 'New', 'tags': ['test.port'], @@ -456,7 +458,7 @@ def test_load_description_missing_value_default(): 'name': 'test-thehive', 'tags': ['a', 'b'], 'type': 'any'} - + rules_loader = FileRulesLoader({}) rules_loader.load_modules(rule) alert = HiveAlerter(rule) @@ -470,4 +472,4 @@ def test_load_description_missing_value_default(): } actual = alert.load_description(rule['hive_alert_config']['description'], match) expected = "Unit test from host: to 127.0.0.1" - assert actual == expected \ No newline at end of file + assert actual == expected