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.
Files changed (100) hide show
  1. intelmq_extensions/__init__.py +0 -0
  2. intelmq_extensions/bots/__init__.py +0 -0
  3. intelmq_extensions/bots/collectors/blackkite/__init__.py +0 -0
  4. intelmq_extensions/bots/collectors/blackkite/_client.py +167 -0
  5. intelmq_extensions/bots/collectors/blackkite/collector.py +182 -0
  6. intelmq_extensions/bots/collectors/disp/__init__.py +0 -0
  7. intelmq_extensions/bots/collectors/disp/_client.py +121 -0
  8. intelmq_extensions/bots/collectors/disp/collector.py +104 -0
  9. intelmq_extensions/bots/collectors/xmpp/__init__.py +0 -0
  10. intelmq_extensions/bots/collectors/xmpp/collector.py +210 -0
  11. intelmq_extensions/bots/experts/__init__.py +0 -0
  12. intelmq_extensions/bots/experts/certat_contact_intern/__init__.py +0 -0
  13. intelmq_extensions/bots/experts/certat_contact_intern/expert.py +139 -0
  14. intelmq_extensions/bots/experts/copy_extra/__init__.py +0 -0
  15. intelmq_extensions/bots/experts/copy_extra/expert.py +27 -0
  16. intelmq_extensions/bots/experts/event_group_splitter/__init__.py +0 -0
  17. intelmq_extensions/bots/experts/event_group_splitter/expert.py +117 -0
  18. intelmq_extensions/bots/experts/event_splitter/__init__.py +0 -0
  19. intelmq_extensions/bots/experts/event_splitter/expert.py +41 -0
  20. intelmq_extensions/bots/experts/squelcher/__init__.py +0 -0
  21. intelmq_extensions/bots/experts/squelcher/expert.py +316 -0
  22. intelmq_extensions/bots/experts/vulnerability_lookup/__init__.py +0 -0
  23. intelmq_extensions/bots/experts/vulnerability_lookup/expert.py +136 -0
  24. intelmq_extensions/bots/outputs/__init__.py +0 -0
  25. intelmq_extensions/bots/outputs/mattermost/__init__.py +0 -0
  26. intelmq_extensions/bots/outputs/mattermost/output.py +113 -0
  27. intelmq_extensions/bots/outputs/to_logs/__init__.py +0 -0
  28. intelmq_extensions/bots/outputs/to_logs/output.py +12 -0
  29. intelmq_extensions/bots/outputs/xmpp/__init__.py +0 -0
  30. intelmq_extensions/bots/outputs/xmpp/output.py +180 -0
  31. intelmq_extensions/bots/parsers/__init__.py +0 -0
  32. intelmq_extensions/bots/parsers/blackkite/__init__.py +0 -0
  33. intelmq_extensions/bots/parsers/blackkite/_transformers.py +202 -0
  34. intelmq_extensions/bots/parsers/blackkite/parser.py +65 -0
  35. intelmq_extensions/bots/parsers/disp/__init__.py +0 -0
  36. intelmq_extensions/bots/parsers/disp/parser.py +125 -0
  37. intelmq_extensions/bots/parsers/malwaredomains/__init__.py +0 -0
  38. intelmq_extensions/bots/parsers/malwaredomains/parser.py +63 -0
  39. intelmq_extensions/cli/__init__.py +0 -0
  40. intelmq_extensions/cli/create_reports.py +161 -0
  41. intelmq_extensions/cli/intelmqcli.py +657 -0
  42. intelmq_extensions/cli/lib.py +670 -0
  43. intelmq_extensions/cli/utils.py +12 -0
  44. intelmq_extensions/etc/harmonization.conf +434 -0
  45. intelmq_extensions/etc/squelcher.conf +52 -0
  46. intelmq_extensions/lib/__init__.py +0 -0
  47. intelmq_extensions/lib/api_helpers.py +105 -0
  48. intelmq_extensions/lib/blackkite.py +29 -0
  49. intelmq_extensions/tests/__init__.py +0 -0
  50. intelmq_extensions/tests/base.py +336 -0
  51. intelmq_extensions/tests/bots/__init__.py +0 -0
  52. intelmq_extensions/tests/bots/collectors/__init__.py +0 -0
  53. intelmq_extensions/tests/bots/collectors/blackkite/__init__.py +0 -0
  54. intelmq_extensions/tests/bots/collectors/blackkite/base.py +45 -0
  55. intelmq_extensions/tests/bots/collectors/blackkite/test_client.py +154 -0
  56. intelmq_extensions/tests/bots/collectors/blackkite/test_collector.py +287 -0
  57. intelmq_extensions/tests/bots/collectors/disp/__init__.py +0 -0
  58. intelmq_extensions/tests/bots/collectors/disp/base.py +147 -0
  59. intelmq_extensions/tests/bots/collectors/disp/test_client.py +134 -0
  60. intelmq_extensions/tests/bots/collectors/disp/test_collector.py +137 -0
  61. intelmq_extensions/tests/bots/collectors/xmpp/__init__.py +0 -0
  62. intelmq_extensions/tests/bots/collectors/xmpp/test_collector.py +10 -0
  63. intelmq_extensions/tests/bots/experts/__init__.py +0 -0
  64. intelmq_extensions/tests/bots/experts/certat_contact_intern/__init__.py +0 -0
  65. intelmq_extensions/tests/bots/experts/certat_contact_intern/test_expert.py +176 -0
  66. intelmq_extensions/tests/bots/experts/copy_extra/__init__.py +0 -0
  67. intelmq_extensions/tests/bots/experts/copy_extra/test_expert.py +42 -0
  68. intelmq_extensions/tests/bots/experts/event_group_splitter/__init__.py +0 -0
  69. intelmq_extensions/tests/bots/experts/event_group_splitter/test_expert.py +302 -0
  70. intelmq_extensions/tests/bots/experts/event_splitter/__init__.py +0 -0
  71. intelmq_extensions/tests/bots/experts/event_splitter/test_expert.py +101 -0
  72. intelmq_extensions/tests/bots/experts/squelcher/__init__.py +0 -0
  73. intelmq_extensions/tests/bots/experts/squelcher/test_expert.py +548 -0
  74. intelmq_extensions/tests/bots/experts/vulnerability_lookup/__init__.py +0 -0
  75. intelmq_extensions/tests/bots/experts/vulnerability_lookup/test_expert.py +203 -0
  76. intelmq_extensions/tests/bots/outputs/__init__.py +0 -0
  77. intelmq_extensions/tests/bots/outputs/mattermost/__init__.py +0 -0
  78. intelmq_extensions/tests/bots/outputs/mattermost/test_output.py +138 -0
  79. intelmq_extensions/tests/bots/outputs/xmpp/__init__.py +0 -0
  80. intelmq_extensions/tests/bots/outputs/xmpp/test_output.py +10 -0
  81. intelmq_extensions/tests/bots/parsers/__init__.py +0 -0
  82. intelmq_extensions/tests/bots/parsers/blackkite/__init__.py +0 -0
  83. intelmq_extensions/tests/bots/parsers/blackkite/data.py +69 -0
  84. intelmq_extensions/tests/bots/parsers/blackkite/test_parser.py +197 -0
  85. intelmq_extensions/tests/bots/parsers/disp/__init__.py +0 -0
  86. intelmq_extensions/tests/bots/parsers/disp/test_parser.py +282 -0
  87. intelmq_extensions/tests/bots/parsers/malwaredomains/__init__.py +0 -0
  88. intelmq_extensions/tests/bots/parsers/malwaredomains/test_parser.py +62 -0
  89. intelmq_extensions/tests/cli/__init__.py +0 -0
  90. intelmq_extensions/tests/cli/test_create_reports.py +97 -0
  91. intelmq_extensions/tests/cli/test_intelmqcli.py +158 -0
  92. intelmq_extensions/tests/lib/__init__.py +0 -0
  93. intelmq_extensions/tests/lib/base.py +81 -0
  94. intelmq_extensions/tests/lib/test_api_helpers.py +126 -0
  95. intelmq_extensions-1.8.1.dist-info/METADATA +60 -0
  96. intelmq_extensions-1.8.1.dist-info/RECORD +100 -0
  97. intelmq_extensions-1.8.1.dist-info/WHEEL +5 -0
  98. intelmq_extensions-1.8.1.dist-info/entry_points.txt +33 -0
  99. intelmq_extensions-1.8.1.dist-info/licenses/LICENSE +661 -0
  100. 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
+ )
@@ -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()