intelmq-extensions 1.8.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- intelmq_extensions/__init__.py +0 -0
- intelmq_extensions/bots/__init__.py +0 -0
- intelmq_extensions/bots/collectors/blackkite/__init__.py +0 -0
- intelmq_extensions/bots/collectors/blackkite/_client.py +167 -0
- intelmq_extensions/bots/collectors/blackkite/collector.py +182 -0
- intelmq_extensions/bots/collectors/disp/__init__.py +0 -0
- intelmq_extensions/bots/collectors/disp/_client.py +121 -0
- intelmq_extensions/bots/collectors/disp/collector.py +104 -0
- intelmq_extensions/bots/collectors/xmpp/__init__.py +0 -0
- intelmq_extensions/bots/collectors/xmpp/collector.py +210 -0
- intelmq_extensions/bots/experts/__init__.py +0 -0
- intelmq_extensions/bots/experts/certat_contact_intern/__init__.py +0 -0
- intelmq_extensions/bots/experts/certat_contact_intern/expert.py +139 -0
- intelmq_extensions/bots/experts/copy_extra/__init__.py +0 -0
- intelmq_extensions/bots/experts/copy_extra/expert.py +27 -0
- intelmq_extensions/bots/experts/event_group_splitter/__init__.py +0 -0
- intelmq_extensions/bots/experts/event_group_splitter/expert.py +117 -0
- intelmq_extensions/bots/experts/event_splitter/__init__.py +0 -0
- intelmq_extensions/bots/experts/event_splitter/expert.py +41 -0
- intelmq_extensions/bots/experts/squelcher/__init__.py +0 -0
- intelmq_extensions/bots/experts/squelcher/expert.py +316 -0
- intelmq_extensions/bots/experts/vulnerability_lookup/__init__.py +0 -0
- intelmq_extensions/bots/experts/vulnerability_lookup/expert.py +136 -0
- intelmq_extensions/bots/outputs/__init__.py +0 -0
- intelmq_extensions/bots/outputs/mattermost/__init__.py +0 -0
- intelmq_extensions/bots/outputs/mattermost/output.py +113 -0
- intelmq_extensions/bots/outputs/to_logs/__init__.py +0 -0
- intelmq_extensions/bots/outputs/to_logs/output.py +12 -0
- intelmq_extensions/bots/outputs/xmpp/__init__.py +0 -0
- intelmq_extensions/bots/outputs/xmpp/output.py +180 -0
- intelmq_extensions/bots/parsers/__init__.py +0 -0
- intelmq_extensions/bots/parsers/blackkite/__init__.py +0 -0
- intelmq_extensions/bots/parsers/blackkite/_transformers.py +202 -0
- intelmq_extensions/bots/parsers/blackkite/parser.py +65 -0
- intelmq_extensions/bots/parsers/disp/__init__.py +0 -0
- intelmq_extensions/bots/parsers/disp/parser.py +125 -0
- intelmq_extensions/bots/parsers/malwaredomains/__init__.py +0 -0
- intelmq_extensions/bots/parsers/malwaredomains/parser.py +63 -0
- intelmq_extensions/cli/__init__.py +0 -0
- intelmq_extensions/cli/create_reports.py +161 -0
- intelmq_extensions/cli/intelmqcli.py +657 -0
- intelmq_extensions/cli/lib.py +670 -0
- intelmq_extensions/cli/utils.py +12 -0
- intelmq_extensions/etc/harmonization.conf +434 -0
- intelmq_extensions/etc/squelcher.conf +52 -0
- intelmq_extensions/lib/__init__.py +0 -0
- intelmq_extensions/lib/api_helpers.py +105 -0
- intelmq_extensions/lib/blackkite.py +29 -0
- intelmq_extensions/tests/__init__.py +0 -0
- intelmq_extensions/tests/base.py +336 -0
- intelmq_extensions/tests/bots/__init__.py +0 -0
- intelmq_extensions/tests/bots/collectors/__init__.py +0 -0
- intelmq_extensions/tests/bots/collectors/blackkite/__init__.py +0 -0
- intelmq_extensions/tests/bots/collectors/blackkite/base.py +45 -0
- intelmq_extensions/tests/bots/collectors/blackkite/test_client.py +154 -0
- intelmq_extensions/tests/bots/collectors/blackkite/test_collector.py +287 -0
- intelmq_extensions/tests/bots/collectors/disp/__init__.py +0 -0
- intelmq_extensions/tests/bots/collectors/disp/base.py +147 -0
- intelmq_extensions/tests/bots/collectors/disp/test_client.py +134 -0
- intelmq_extensions/tests/bots/collectors/disp/test_collector.py +137 -0
- intelmq_extensions/tests/bots/collectors/xmpp/__init__.py +0 -0
- intelmq_extensions/tests/bots/collectors/xmpp/test_collector.py +10 -0
- intelmq_extensions/tests/bots/experts/__init__.py +0 -0
- intelmq_extensions/tests/bots/experts/certat_contact_intern/__init__.py +0 -0
- intelmq_extensions/tests/bots/experts/certat_contact_intern/test_expert.py +176 -0
- intelmq_extensions/tests/bots/experts/copy_extra/__init__.py +0 -0
- intelmq_extensions/tests/bots/experts/copy_extra/test_expert.py +42 -0
- intelmq_extensions/tests/bots/experts/event_group_splitter/__init__.py +0 -0
- intelmq_extensions/tests/bots/experts/event_group_splitter/test_expert.py +302 -0
- intelmq_extensions/tests/bots/experts/event_splitter/__init__.py +0 -0
- intelmq_extensions/tests/bots/experts/event_splitter/test_expert.py +101 -0
- intelmq_extensions/tests/bots/experts/squelcher/__init__.py +0 -0
- intelmq_extensions/tests/bots/experts/squelcher/test_expert.py +548 -0
- intelmq_extensions/tests/bots/experts/vulnerability_lookup/__init__.py +0 -0
- intelmq_extensions/tests/bots/experts/vulnerability_lookup/test_expert.py +203 -0
- intelmq_extensions/tests/bots/outputs/__init__.py +0 -0
- intelmq_extensions/tests/bots/outputs/mattermost/__init__.py +0 -0
- intelmq_extensions/tests/bots/outputs/mattermost/test_output.py +138 -0
- intelmq_extensions/tests/bots/outputs/xmpp/__init__.py +0 -0
- intelmq_extensions/tests/bots/outputs/xmpp/test_output.py +10 -0
- intelmq_extensions/tests/bots/parsers/__init__.py +0 -0
- intelmq_extensions/tests/bots/parsers/blackkite/__init__.py +0 -0
- intelmq_extensions/tests/bots/parsers/blackkite/data.py +69 -0
- intelmq_extensions/tests/bots/parsers/blackkite/test_parser.py +197 -0
- intelmq_extensions/tests/bots/parsers/disp/__init__.py +0 -0
- intelmq_extensions/tests/bots/parsers/disp/test_parser.py +282 -0
- intelmq_extensions/tests/bots/parsers/malwaredomains/__init__.py +0 -0
- intelmq_extensions/tests/bots/parsers/malwaredomains/test_parser.py +62 -0
- intelmq_extensions/tests/cli/__init__.py +0 -0
- intelmq_extensions/tests/cli/test_create_reports.py +97 -0
- intelmq_extensions/tests/cli/test_intelmqcli.py +158 -0
- intelmq_extensions/tests/lib/__init__.py +0 -0
- intelmq_extensions/tests/lib/base.py +81 -0
- intelmq_extensions/tests/lib/test_api_helpers.py +126 -0
- intelmq_extensions-1.8.1.dist-info/METADATA +60 -0
- intelmq_extensions-1.8.1.dist-info/RECORD +100 -0
- intelmq_extensions-1.8.1.dist-info/WHEEL +5 -0
- intelmq_extensions-1.8.1.dist-info/entry_points.txt +33 -0
- intelmq_extensions-1.8.1.dist-info/licenses/LICENSE +661 -0
- intelmq_extensions-1.8.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"""Testing events splitter
|
|
2
|
+
|
|
3
|
+
SPDX-FileCopyrightText: 2023 CERT.at GmbH <https://cert.at/>
|
|
4
|
+
SPDX-License-Identifier: AGPL-3.0-or-later
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import unittest
|
|
8
|
+
|
|
9
|
+
from intelmq_extensions.bots.experts.event_splitter.expert import EventSplitterExpertBot
|
|
10
|
+
|
|
11
|
+
from ....base import BotTestCase
|
|
12
|
+
|
|
13
|
+
INPUT = {
|
|
14
|
+
"__type": "Event",
|
|
15
|
+
"classification.identifier": "zeus",
|
|
16
|
+
"classification.type": "infected-system",
|
|
17
|
+
"notify": False,
|
|
18
|
+
"source.asn": 1,
|
|
19
|
+
"source.ip": "192.0.2.1",
|
|
20
|
+
"feed.name": "Example Feed",
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class TestEventSplitterExpertBot(BotTestCase, unittest.TestCase):
|
|
25
|
+
@classmethod
|
|
26
|
+
def set_bot(cls):
|
|
27
|
+
cls.bot_reference = EventSplitterExpertBot
|
|
28
|
+
cls.sysconfig = {
|
|
29
|
+
"look_in": "extra.tag",
|
|
30
|
+
"copy_to": ["classification.identifier", "extra.vulnerabilities"],
|
|
31
|
+
"regex": r"(cve-\d\d\d\d-[\d]+)",
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
def test_no_tags_sent_original_message(self):
|
|
35
|
+
self.input_message = INPUT
|
|
36
|
+
|
|
37
|
+
self.run_bot()
|
|
38
|
+
|
|
39
|
+
self.assertOutputQueueLen(1)
|
|
40
|
+
self.assertMessageEqual(0, INPUT)
|
|
41
|
+
|
|
42
|
+
def test_no_matched_tags_sent_original_message(self):
|
|
43
|
+
message = {**INPUT, "extra.tag": "some,different,tags"}
|
|
44
|
+
self.input_message = message
|
|
45
|
+
|
|
46
|
+
self.run_bot()
|
|
47
|
+
|
|
48
|
+
self.assertOutputQueueLen(1)
|
|
49
|
+
self.assertMessageEqual(0, message)
|
|
50
|
+
|
|
51
|
+
def test_only_one_matched_apply_copy_to(self):
|
|
52
|
+
message = {**INPUT, "extra.tag": "cve-2023-00000"}
|
|
53
|
+
self.input_message = message
|
|
54
|
+
|
|
55
|
+
self.run_bot()
|
|
56
|
+
|
|
57
|
+
self.assertOutputQueueLen(1)
|
|
58
|
+
self.assertMessageEqual(
|
|
59
|
+
0,
|
|
60
|
+
{
|
|
61
|
+
**message,
|
|
62
|
+
"classification.identifier": "cve-2023-00000",
|
|
63
|
+
"extra.vulnerabilities": "cve-2023-00000",
|
|
64
|
+
},
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
def test_multiple_matched_tags(self):
|
|
68
|
+
message = {
|
|
69
|
+
**INPUT,
|
|
70
|
+
"extra.tag": "cve-2023-00000,other,cve-2023-00001,some,tag,cve-2023-00002",
|
|
71
|
+
}
|
|
72
|
+
self.input_message = message
|
|
73
|
+
|
|
74
|
+
self.run_bot()
|
|
75
|
+
|
|
76
|
+
self.assertOutputQueueLen(3)
|
|
77
|
+
self.assertMessageEqual(
|
|
78
|
+
0,
|
|
79
|
+
{
|
|
80
|
+
**message,
|
|
81
|
+
"classification.identifier": "cve-2023-00000",
|
|
82
|
+
"extra.vulnerabilities": "cve-2023-00000",
|
|
83
|
+
},
|
|
84
|
+
)
|
|
85
|
+
self.assertMessageEqual(
|
|
86
|
+
1,
|
|
87
|
+
{
|
|
88
|
+
**message,
|
|
89
|
+
"classification.identifier": "cve-2023-00001",
|
|
90
|
+
"extra.vulnerabilities": "cve-2023-00001",
|
|
91
|
+
},
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
self.assertMessageEqual(
|
|
95
|
+
2,
|
|
96
|
+
{
|
|
97
|
+
**message,
|
|
98
|
+
"classification.identifier": "cve-2023-00002",
|
|
99
|
+
"extra.vulnerabilities": "cve-2023-00002",
|
|
100
|
+
},
|
|
101
|
+
)
|
|
File without changes
|
|
@@ -0,0 +1,548 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
from __future__ import unicode_literals
|
|
3
|
+
|
|
4
|
+
import json
|
|
5
|
+
import os
|
|
6
|
+
import os.path
|
|
7
|
+
import unittest
|
|
8
|
+
from copy import deepcopy
|
|
9
|
+
from unittest import mock
|
|
10
|
+
|
|
11
|
+
import intelmq.lib.test as test
|
|
12
|
+
import pkg_resources
|
|
13
|
+
|
|
14
|
+
from intelmq_extensions.bots.experts.squelcher.expert import SquelcherExpertBot
|
|
15
|
+
|
|
16
|
+
from ....base import POSTGRES_CONFIG, BotTestCase
|
|
17
|
+
|
|
18
|
+
INPUT1 = {
|
|
19
|
+
"__type": "Event",
|
|
20
|
+
"classification.identifier": "zeus",
|
|
21
|
+
"classification.type": "infected-system",
|
|
22
|
+
"notify": False,
|
|
23
|
+
"source.asn": 1,
|
|
24
|
+
"source.ip": "192.0.2.1",
|
|
25
|
+
"feed.name": "Example Feed",
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
INPUT2 = INPUT1.copy()
|
|
29
|
+
INPUT2["classification.identifier"] = "https"
|
|
30
|
+
INPUT2["classification.type"] = "vulnerable-system"
|
|
31
|
+
OUTPUT2 = INPUT2.copy()
|
|
32
|
+
OUTPUT2["notify"] = True
|
|
33
|
+
|
|
34
|
+
INPUT3 = INPUT1.copy()
|
|
35
|
+
INPUT3["classification.identifier"] = "https"
|
|
36
|
+
INPUT3["classification.type"] = "vulnerable-system"
|
|
37
|
+
INPUT3["source.ip"] = "192.0.2.4"
|
|
38
|
+
|
|
39
|
+
INPUT4 = INPUT3.copy()
|
|
40
|
+
INPUT4["classification.identifier"] = "openresolver"
|
|
41
|
+
INPUT4["notify"] = True
|
|
42
|
+
|
|
43
|
+
INPUT5 = INPUT4.copy()
|
|
44
|
+
INPUT5["source.ip"] = "198.51.100.5"
|
|
45
|
+
OUTPUT5 = INPUT5.copy()
|
|
46
|
+
OUTPUT5["notify"] = False
|
|
47
|
+
|
|
48
|
+
INPUT6 = INPUT4.copy()
|
|
49
|
+
INPUT6["source.ip"] = "198.51.100.45"
|
|
50
|
+
OUTPUT6 = INPUT6.copy()
|
|
51
|
+
OUTPUT6["notify"] = False
|
|
52
|
+
|
|
53
|
+
INPUT7 = INPUT1.copy()
|
|
54
|
+
INPUT7["notify"] = True
|
|
55
|
+
INPUT7["source.fqdn"] = "example.com"
|
|
56
|
+
del INPUT7["source.ip"]
|
|
57
|
+
OUTPUT7 = INPUT7.copy()
|
|
58
|
+
|
|
59
|
+
INPUT8 = INPUT1.copy()
|
|
60
|
+
del INPUT8["notify"]
|
|
61
|
+
del INPUT8["source.asn"]
|
|
62
|
+
OUTPUT8 = INPUT8.copy()
|
|
63
|
+
OUTPUT8["notify"] = False
|
|
64
|
+
|
|
65
|
+
INPUT_INFINITE = {
|
|
66
|
+
"__type": "Event",
|
|
67
|
+
"classification.identifier": "zeus",
|
|
68
|
+
"classification.type": "infected-system",
|
|
69
|
+
"source.asn": 12312,
|
|
70
|
+
"source.ip": "192.0.2.1",
|
|
71
|
+
}
|
|
72
|
+
OUTPUT_INFINITE = INPUT_INFINITE.copy()
|
|
73
|
+
OUTPUT_INFINITE["notify"] = False
|
|
74
|
+
|
|
75
|
+
INPUT_RANGE = {
|
|
76
|
+
"__type": "Event",
|
|
77
|
+
"classification.identifier": "zeus",
|
|
78
|
+
"classification.type": "infected-system",
|
|
79
|
+
"source.asn": 789,
|
|
80
|
+
"source.ip": "10.0.0.10",
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
INPUT9 = INPUT1.copy()
|
|
84
|
+
INPUT9["extra.additionalmetadata"] = ["foobar"]
|
|
85
|
+
|
|
86
|
+
INPUT10 = INPUT1.copy()
|
|
87
|
+
INPUT10["notify"] = True
|
|
88
|
+
|
|
89
|
+
INPUT11 = INPUT1.copy()
|
|
90
|
+
INPUT11["extra.malware.variants"] = ["foo", "bar"]
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
# TODO: move test case to the use the test DB helper
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
@test.skip_database()
|
|
97
|
+
@test.skip_exotic()
|
|
98
|
+
class TestSquelcherExpertBot(BotTestCase, unittest.TestCase):
|
|
99
|
+
"""
|
|
100
|
+
A TestCase for SquelcherExpertBot.
|
|
101
|
+
"""
|
|
102
|
+
|
|
103
|
+
@classmethod
|
|
104
|
+
def set_bot(cls):
|
|
105
|
+
cls.bot_reference = SquelcherExpertBot
|
|
106
|
+
cls.default_input_message = INPUT1
|
|
107
|
+
if not os.environ.get("INTELMQ_TEST_DATABASES"):
|
|
108
|
+
return
|
|
109
|
+
cls.sysconfig = {
|
|
110
|
+
"configuration_path": pkg_resources.resource_filename(
|
|
111
|
+
"intelmq_extensions", "etc/squelcher.conf"
|
|
112
|
+
),
|
|
113
|
+
"overwrite": True,
|
|
114
|
+
"sending_time_interval": "2 years",
|
|
115
|
+
"table": cls.TEST_EVENTS_TABLE,
|
|
116
|
+
"logging_level": "DEBUG",
|
|
117
|
+
}
|
|
118
|
+
cls.sysconfig.update(POSTGRES_CONFIG)
|
|
119
|
+
cls.con = cls.connect_database(POSTGRES_CONFIG)
|
|
120
|
+
cls.con.autocommit = True
|
|
121
|
+
cls.cur = cls.con.cursor()
|
|
122
|
+
cls.truncate(cls)
|
|
123
|
+
|
|
124
|
+
def truncate(self):
|
|
125
|
+
self.cur.execute("TRUNCATE TABLE {}".format(self.sysconfig["table"]))
|
|
126
|
+
|
|
127
|
+
def insert(
|
|
128
|
+
self,
|
|
129
|
+
classification_identifier,
|
|
130
|
+
classification_type,
|
|
131
|
+
notify,
|
|
132
|
+
source_asn,
|
|
133
|
+
source_ip,
|
|
134
|
+
time_source,
|
|
135
|
+
sent_at=None,
|
|
136
|
+
report_id=None,
|
|
137
|
+
feed_name="Example Feed",
|
|
138
|
+
extra=None,
|
|
139
|
+
):
|
|
140
|
+
if sent_at is not None:
|
|
141
|
+
append = "LOCALTIMESTAMP + INTERVAL %s second"
|
|
142
|
+
else:
|
|
143
|
+
append = "%s"
|
|
144
|
+
query = """
|
|
145
|
+
INSERT INTO {table}(
|
|
146
|
+
"classification.identifier", "classification.type", notify, "source.asn",
|
|
147
|
+
"source.ip", "time.source", "rtir_report_id", "sent_at", "feed.name", "extra"
|
|
148
|
+
) VALUES (%s, %s, %s, %s, %s,
|
|
149
|
+
LOCALTIMESTAMP + INTERVAL %s second, %s,
|
|
150
|
+
{append}, %s, %s)
|
|
151
|
+
""".format(table=self.sysconfig["table"], append=append)
|
|
152
|
+
self.cur.execute(
|
|
153
|
+
query,
|
|
154
|
+
(
|
|
155
|
+
classification_identifier,
|
|
156
|
+
classification_type,
|
|
157
|
+
notify,
|
|
158
|
+
source_asn,
|
|
159
|
+
source_ip,
|
|
160
|
+
time_source,
|
|
161
|
+
report_id,
|
|
162
|
+
sent_at,
|
|
163
|
+
feed_name,
|
|
164
|
+
json.dumps(extra or dict()),
|
|
165
|
+
),
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
def test_ttl_1(self):
|
|
169
|
+
"event exists in db -> squelch"
|
|
170
|
+
self.insert("zeus", "infected-system", True, 1, "192.0.2.1", "0")
|
|
171
|
+
self.input_message = INPUT1
|
|
172
|
+
self.run_bot()
|
|
173
|
+
self.truncate()
|
|
174
|
+
self.assertLogMatches("Found TTL 604800 for", levelname="DEBUG")
|
|
175
|
+
self.assertMessageEqual(0, INPUT1)
|
|
176
|
+
|
|
177
|
+
def test_ttl_2(self):
|
|
178
|
+
"event in db is too old -> notify"
|
|
179
|
+
self.insert("https", "vulnerable-system", True, 1, "192.0.2.1", "- 01:45")
|
|
180
|
+
self.input_message = INPUT2
|
|
181
|
+
self.run_bot()
|
|
182
|
+
self.truncate()
|
|
183
|
+
self.assertLogMatches("Found TTL 3600 for", levelname="DEBUG")
|
|
184
|
+
self.assertMessageEqual(0, OUTPUT2)
|
|
185
|
+
|
|
186
|
+
def test_ttl_2h_squelch(self):
|
|
187
|
+
"event is in db -> squelch"
|
|
188
|
+
self.insert("https", "vulnerable-system", True, 1, "192.0.2.4", "- 01:45")
|
|
189
|
+
self.input_message = INPUT3
|
|
190
|
+
self.run_bot()
|
|
191
|
+
self.truncate()
|
|
192
|
+
self.assertLogMatches("Found TTL 7200 for", levelname="DEBUG")
|
|
193
|
+
self.assertMessageEqual(0, INPUT3)
|
|
194
|
+
|
|
195
|
+
def test_network_match(self):
|
|
196
|
+
"""event is in db without notify -> notify
|
|
197
|
+
find ttl based on network test"""
|
|
198
|
+
self.insert(
|
|
199
|
+
"openresolver", "vulnerable-system", False, 1, "198.51.100.5", "- 20:00"
|
|
200
|
+
)
|
|
201
|
+
self.input_message = INPUT5
|
|
202
|
+
self.run_bot()
|
|
203
|
+
self.truncate()
|
|
204
|
+
self.assertLogMatches("Found TTL 115200 for", levelname="DEBUG")
|
|
205
|
+
self.assertMessageEqual(0, INPUT5)
|
|
206
|
+
|
|
207
|
+
def test_network_match3(self):
|
|
208
|
+
"""event is in db -> squelch
|
|
209
|
+
find ttl based on network test"""
|
|
210
|
+
self.insert(
|
|
211
|
+
"openresolver",
|
|
212
|
+
"vulnerable-system",
|
|
213
|
+
True,
|
|
214
|
+
1,
|
|
215
|
+
"198.51.100.5",
|
|
216
|
+
"- 25:00",
|
|
217
|
+
"- 25:00",
|
|
218
|
+
)
|
|
219
|
+
self.input_message = INPUT5
|
|
220
|
+
self.run_bot()
|
|
221
|
+
self.truncate()
|
|
222
|
+
self.assertLogMatches("Found TTL 115200 for", levelname="DEBUG")
|
|
223
|
+
self.assertMessageEqual(0, OUTPUT5)
|
|
224
|
+
|
|
225
|
+
def test_address_match1(self):
|
|
226
|
+
"event in db is too old -> notify"
|
|
227
|
+
self.insert(
|
|
228
|
+
"openresolver",
|
|
229
|
+
"vulnerable-system",
|
|
230
|
+
True,
|
|
231
|
+
1,
|
|
232
|
+
"198.51.100.45",
|
|
233
|
+
"- 25:00",
|
|
234
|
+
"- 25:00",
|
|
235
|
+
)
|
|
236
|
+
self.input_message = INPUT6
|
|
237
|
+
self.run_bot()
|
|
238
|
+
self.truncate()
|
|
239
|
+
self.assertLogMatches("Found TTL 86400 for", levelname="DEBUG")
|
|
240
|
+
self.assertMessageEqual(0, INPUT6)
|
|
241
|
+
|
|
242
|
+
def test_address_match2(self):
|
|
243
|
+
"event is in db -> squelch"
|
|
244
|
+
self.insert(
|
|
245
|
+
"openresolver",
|
|
246
|
+
"vulnerable-system",
|
|
247
|
+
True,
|
|
248
|
+
1,
|
|
249
|
+
"198.51.100.45",
|
|
250
|
+
"- 20:00",
|
|
251
|
+
"- 20:00",
|
|
252
|
+
)
|
|
253
|
+
self.input_message = INPUT6
|
|
254
|
+
self.run_bot()
|
|
255
|
+
self.truncate()
|
|
256
|
+
self.assertLogMatches("Found TTL 86400 for", levelname="DEBUG")
|
|
257
|
+
self.assertMessageEqual(0, OUTPUT6)
|
|
258
|
+
|
|
259
|
+
def test_ttl_other_ident(self):
|
|
260
|
+
"other event in db -> notify"
|
|
261
|
+
self.insert(
|
|
262
|
+
"https", "vulnerable-system", True, 1, "198.51.100.5", "- 01:45", "- 01:45"
|
|
263
|
+
)
|
|
264
|
+
self.input_message = INPUT4
|
|
265
|
+
self.run_bot()
|
|
266
|
+
self.truncate()
|
|
267
|
+
self.assertLogMatches("Found TTL 7200 for", levelname="DEBUG")
|
|
268
|
+
self.assertMessageEqual(0, INPUT4)
|
|
269
|
+
|
|
270
|
+
def test_use_ttl_from_event(self):
|
|
271
|
+
"Honour TTL from the event"
|
|
272
|
+
input_msg = INPUT4.copy()
|
|
273
|
+
input_msg["source.ip"] = "82.82.82.82"
|
|
274
|
+
|
|
275
|
+
# Default TTL
|
|
276
|
+
self.input_message = input_msg
|
|
277
|
+
self.run_bot()
|
|
278
|
+
self.truncate()
|
|
279
|
+
self.assertLogMatches("Found TTL 604800 for", levelname="DEBUG")
|
|
280
|
+
self.assertMessageEqual(0, input_msg)
|
|
281
|
+
|
|
282
|
+
# Pre-defined TTL
|
|
283
|
+
input_msg["extra.ttl"] = 10
|
|
284
|
+
self.input_message = input_msg
|
|
285
|
+
self.run_bot()
|
|
286
|
+
self.truncate()
|
|
287
|
+
self.assertLogMatches("Found TTL 10 for", levelname="DEBUG")
|
|
288
|
+
self.assertMessageEqual(0, input_msg)
|
|
289
|
+
|
|
290
|
+
def test_domain(self):
|
|
291
|
+
"only domain -> notify true"
|
|
292
|
+
self.input_message = INPUT7
|
|
293
|
+
self.run_bot()
|
|
294
|
+
self.truncate()
|
|
295
|
+
self.assertNotRegexpMatchesLog("Found TTL")
|
|
296
|
+
self.assertMessageEqual(0, OUTPUT7)
|
|
297
|
+
|
|
298
|
+
def test_missing_asn(self):
|
|
299
|
+
"no asn -> notify false"
|
|
300
|
+
self.input_message = INPUT8
|
|
301
|
+
self.run_bot()
|
|
302
|
+
self.truncate()
|
|
303
|
+
self.assertNotRegexpMatchesLog("Found TTL")
|
|
304
|
+
self.assertMessageEqual(0, OUTPUT8)
|
|
305
|
+
|
|
306
|
+
def test_domain_when_non_ip_filter(self):
|
|
307
|
+
"only domain, but filtering without IP allowed -> process"
|
|
308
|
+
self.input_message = INPUT7
|
|
309
|
+
self.run_bot(parameters={"filter_ip_only": False, "source_fields": "feed.name"})
|
|
310
|
+
self.truncate()
|
|
311
|
+
self.assertRegexpMatchesLog("Found TTL 604800") # default ttl
|
|
312
|
+
self.assertMessageEqual(0, OUTPUT7)
|
|
313
|
+
|
|
314
|
+
def test_missing_asn_when_non_ip_filter(self):
|
|
315
|
+
"no asn, but filtering without IP allowed -> process"
|
|
316
|
+
self.input_message = INPUT8
|
|
317
|
+
self.run_bot(parameters={"filter_ip_only": False, "source_fields": "feed.name"})
|
|
318
|
+
self.truncate()
|
|
319
|
+
self.assertRegexpMatchesLog("Found TTL 604800") # default ttl
|
|
320
|
+
output = OUTPUT8.copy()
|
|
321
|
+
output["notify"] = True
|
|
322
|
+
self.assertMessageEqual(0, output)
|
|
323
|
+
|
|
324
|
+
def test_infinite(self):
|
|
325
|
+
"never notify with ttl -1"
|
|
326
|
+
self.input_message = INPUT_INFINITE
|
|
327
|
+
self.run_bot()
|
|
328
|
+
self.truncate()
|
|
329
|
+
self.assertLogMatches("Found TTL -1 for", levelname="DEBUG")
|
|
330
|
+
self.assertMessageEqual(0, OUTPUT_INFINITE)
|
|
331
|
+
|
|
332
|
+
def test_iprange(self):
|
|
333
|
+
"test if mechanism checking IP ranges"
|
|
334
|
+
self.input_message = INPUT_RANGE
|
|
335
|
+
self.run_bot()
|
|
336
|
+
self.truncate()
|
|
337
|
+
self.assertLogMatches("Found TTL 72643 for", levelname="DEBUG")
|
|
338
|
+
|
|
339
|
+
def test_unsent_notify(self):
|
|
340
|
+
"""event exists, but is older than 1 day and has not been sent -> notify"""
|
|
341
|
+
self.insert(
|
|
342
|
+
"openresolver",
|
|
343
|
+
"vulnerable-system",
|
|
344
|
+
True,
|
|
345
|
+
1,
|
|
346
|
+
"198.51.100.5",
|
|
347
|
+
str(-25 * 3600),
|
|
348
|
+
)
|
|
349
|
+
self.sysconfig["sending_time_interval"] = "1 day"
|
|
350
|
+
self.input_message = INPUT5
|
|
351
|
+
self.run_bot()
|
|
352
|
+
self.sysconfig["sending_time_interval"] = "2 days"
|
|
353
|
+
self.truncate()
|
|
354
|
+
self.assertLogMatches("Found TTL 115200 for", levelname="DEBUG")
|
|
355
|
+
self.assertMessageEqual(0, INPUT5)
|
|
356
|
+
|
|
357
|
+
def test_unsent_squelch(self):
|
|
358
|
+
"""event exists, is younger than 2 days and has not been sent -> squelch"""
|
|
359
|
+
self.insert(
|
|
360
|
+
"openresolver", "vulnerable-system", True, 1, "198.51.100.5", "- 86400"
|
|
361
|
+
)
|
|
362
|
+
self.input_message = INPUT5
|
|
363
|
+
self.run_bot()
|
|
364
|
+
self.truncate()
|
|
365
|
+
self.assertLogMatches("Found TTL 115200 for", levelname="DEBUG")
|
|
366
|
+
self.assertMessageEqual(0, OUTPUT5)
|
|
367
|
+
|
|
368
|
+
def test_extra_list(self):
|
|
369
|
+
"""lists in extra data is handled."""
|
|
370
|
+
self.insert("zeus", "infected-system", True, 1, "192.0.2.1", "0")
|
|
371
|
+
self.input_message = INPUT9
|
|
372
|
+
self.run_bot()
|
|
373
|
+
self.truncate()
|
|
374
|
+
self.assertMessageEqual(0, INPUT9)
|
|
375
|
+
|
|
376
|
+
def test_overwrite_false(self):
|
|
377
|
+
"""check if notify is not overwritten if not allowed."""
|
|
378
|
+
self.input_message = INPUT10
|
|
379
|
+
self.sysconfig["overwrite"] = False
|
|
380
|
+
self.run_bot()
|
|
381
|
+
self.sysconfig["overwrite"] = True
|
|
382
|
+
self.assertLogMatches(
|
|
383
|
+
"Notify field present and not allowed to overwrite, skipping.",
|
|
384
|
+
levelname="DEBUG",
|
|
385
|
+
)
|
|
386
|
+
self.assertMessageEqual(0, INPUT10)
|
|
387
|
+
|
|
388
|
+
def test_hashable(self):
|
|
389
|
+
self.input_message = INPUT11
|
|
390
|
+
self.run_bot(
|
|
391
|
+
parameters={
|
|
392
|
+
"configuration_path": os.path.join(
|
|
393
|
+
os.path.dirname(__file__), "unhashable.config"
|
|
394
|
+
)
|
|
395
|
+
}
|
|
396
|
+
)
|
|
397
|
+
self.assertLogMatches("Found TTL 123 for", levelname="DEBUG")
|
|
398
|
+
|
|
399
|
+
def test_open_report_ttl_squelch(self):
|
|
400
|
+
"event with report exists in db -> squelch"
|
|
401
|
+
self.insert("zeus", "infected-system", True, 1, "192.0.2.1", "0", report_id="1")
|
|
402
|
+
self.input_message = INPUT1
|
|
403
|
+
self.run_bot(parameters={"query": "open_report"})
|
|
404
|
+
self.truncate()
|
|
405
|
+
self.assertLogMatches("Found TTL 604800 for", levelname="DEBUG")
|
|
406
|
+
self.assertMessageEqual(0, INPUT1)
|
|
407
|
+
|
|
408
|
+
def test_open_report_ttl_too_old(self):
|
|
409
|
+
"event in db is too old -> notify"
|
|
410
|
+
self.insert(
|
|
411
|
+
"https", "vulnerable-system", True, 1, "192.0.2.1", "- 01:45", report_id="1"
|
|
412
|
+
)
|
|
413
|
+
self.input_message = INPUT2
|
|
414
|
+
self.run_bot(parameters={"query": "open_report"})
|
|
415
|
+
self.truncate()
|
|
416
|
+
self.assertLogMatches("Found TTL 3600 for", levelname="DEBUG")
|
|
417
|
+
self.assertMessageEqual(0, OUTPUT2)
|
|
418
|
+
|
|
419
|
+
def test_custom_sources_ttl_too_old(self):
|
|
420
|
+
"event in db is too old, matched using custom field -> notify"
|
|
421
|
+
# different IP
|
|
422
|
+
self.insert("https", "vulnerable-system", True, 1, "0.0.0.0", "- 01:45")
|
|
423
|
+
self.input_message = INPUT2
|
|
424
|
+
self.run_bot(parameters={"source_fields": "feed.name,source.asn"})
|
|
425
|
+
self.truncate()
|
|
426
|
+
self.assertLogMatches("Found TTL 3600 for", levelname="DEBUG")
|
|
427
|
+
self.assertMessageEqual(0, OUTPUT2)
|
|
428
|
+
|
|
429
|
+
def test_custom_sources_ttl_squelch(self):
|
|
430
|
+
"event with report exists in db -> squelch"
|
|
431
|
+
self.insert("zeus", "infected-system", True, 1, "0.0.0.0", "0")
|
|
432
|
+
self.input_message = INPUT1
|
|
433
|
+
self.run_bot(parameters={"source_fields": "feed.name,source.asn"})
|
|
434
|
+
self.truncate()
|
|
435
|
+
self.assertLogMatches("Found TTL 604800 for", levelname="DEBUG")
|
|
436
|
+
self.assertMessageEqual(0, INPUT1)
|
|
437
|
+
|
|
438
|
+
def test_custom_sources_json_squelch(self):
|
|
439
|
+
"event with report exists in db -> squelch"
|
|
440
|
+
self.insert(
|
|
441
|
+
"zeus",
|
|
442
|
+
"infected-system",
|
|
443
|
+
True,
|
|
444
|
+
1,
|
|
445
|
+
"0.0.0.0",
|
|
446
|
+
"0",
|
|
447
|
+
extra={"ident": "something"},
|
|
448
|
+
)
|
|
449
|
+
message = INPUT1.copy()
|
|
450
|
+
message["extra.ident"] = "something"
|
|
451
|
+
self.input_message = deepcopy(message)
|
|
452
|
+
self.run_bot(parameters={"source_fields": "extra.ident"})
|
|
453
|
+
self.truncate()
|
|
454
|
+
self.assertLogMatches("Found TTL 604800 for", levelname="DEBUG")
|
|
455
|
+
self.assertMessageEqual(0, message)
|
|
456
|
+
|
|
457
|
+
def test_custom_sources_all_need_match(self):
|
|
458
|
+
"all custom source fields need to match to squelch"
|
|
459
|
+
self.insert("zeus", "infected-system", True, 2, "0.0.0.0", "0")
|
|
460
|
+
self.insert(
|
|
461
|
+
"zeus", "infected-system", True, 1, "0.0.0.0", "0", feed_name="Another"
|
|
462
|
+
)
|
|
463
|
+
self.input_message = INPUT1
|
|
464
|
+
self.run_bot(parameters={"source_fields": "feed.name,source.asn"})
|
|
465
|
+
self.truncate()
|
|
466
|
+
self.assertLogMatches("Found TTL 604800 for", levelname="DEBUG")
|
|
467
|
+
output = INPUT1.copy()
|
|
468
|
+
output["notify"] = True
|
|
469
|
+
self.assertMessageEqual(0, output)
|
|
470
|
+
|
|
471
|
+
def test_when_source_field_is_null(self):
|
|
472
|
+
"Squelcher should compare against null values"
|
|
473
|
+
self.insert("zeus", "infected-system", True, 2, "0.0.0.0", "0", report_id=None)
|
|
474
|
+
self.input_message = INPUT1
|
|
475
|
+
|
|
476
|
+
self.run_bot(parameters={"source_fields": "feed.name,rtir_report_id"})
|
|
477
|
+
self.truncate()
|
|
478
|
+
self.assertLogMatches("Found TTL 604800 for", levelname="DEBUG")
|
|
479
|
+
|
|
480
|
+
# Notify: False - the same feed name and both events has lack of report id
|
|
481
|
+
self.assertMessageEqual(0, INPUT1)
|
|
482
|
+
|
|
483
|
+
def test_when_json_source_field_is_null(self):
|
|
484
|
+
self.insert("zeus", "infected-system", True, 2, "0.0.0.0", "0")
|
|
485
|
+
self.input_message = INPUT1
|
|
486
|
+
|
|
487
|
+
self.run_bot(parameters={"source_fields": "feed.name,extra.something"})
|
|
488
|
+
self.truncate()
|
|
489
|
+
self.assertLogMatches("Found TTL 604800 for", levelname="DEBUG")
|
|
490
|
+
|
|
491
|
+
# Notify: False - the same feed name and both events has lack of extra.something
|
|
492
|
+
self.assertMessageEqual(0, INPUT1)
|
|
493
|
+
|
|
494
|
+
def test_static_bot_check_method(self, *args, **kwargs):
|
|
495
|
+
with mock.patch(
|
|
496
|
+
"intelmq.lib.utils.load_configuration", new=test.mocked_config()
|
|
497
|
+
):
|
|
498
|
+
super().test_static_bot_check_method()
|
|
499
|
+
|
|
500
|
+
@classmethod
|
|
501
|
+
def tearDownClass(cls):
|
|
502
|
+
if not os.environ.get("INTELMQ_TEST_DATABASES"):
|
|
503
|
+
return
|
|
504
|
+
cls.truncate(cls)
|
|
505
|
+
cls.cur.close()
|
|
506
|
+
cls.con.close()
|
|
507
|
+
|
|
508
|
+
|
|
509
|
+
class TestSquelcherExpertBotHelper(unittest.TestCase):
|
|
510
|
+
def test_convert_config_list(self):
|
|
511
|
+
self.config = [
|
|
512
|
+
[
|
|
513
|
+
{"extra.malware.variants": ["foo", "bar"]},
|
|
514
|
+
{"ttl": 10},
|
|
515
|
+
]
|
|
516
|
+
]
|
|
517
|
+
SquelcherExpertBot.convert_config(self)
|
|
518
|
+
self.assertEqual(
|
|
519
|
+
self.config,
|
|
520
|
+
[
|
|
521
|
+
[
|
|
522
|
+
{"extra.malware.variants": ("foo", "bar")},
|
|
523
|
+
{"ttl": 10},
|
|
524
|
+
]
|
|
525
|
+
],
|
|
526
|
+
)
|
|
527
|
+
|
|
528
|
+
def test_convert_config_dict(self):
|
|
529
|
+
self.config = [
|
|
530
|
+
[
|
|
531
|
+
{"extra.malware.variants": {"foo": "bar"}},
|
|
532
|
+
{"ttl": 10},
|
|
533
|
+
]
|
|
534
|
+
]
|
|
535
|
+
SquelcherExpertBot.convert_config(self)
|
|
536
|
+
self.assertEqual(
|
|
537
|
+
self.config,
|
|
538
|
+
[
|
|
539
|
+
[
|
|
540
|
+
{"extra.malware.variants": (("foo", "bar"),)},
|
|
541
|
+
{"ttl": 10},
|
|
542
|
+
]
|
|
543
|
+
],
|
|
544
|
+
)
|
|
545
|
+
|
|
546
|
+
|
|
547
|
+
if __name__ == "__main__":
|
|
548
|
+
unittest.main()
|
|
File without changes
|