rosetta-ce 1.6.9__py3-none-any.whl → 1.7.0__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.
Potentially problematic release.
This version of rosetta-ce might be problematic. Click here for more details.
- rosetta/constants/systems.py +33 -29
- rosetta/rfaker.py +495 -554
- {rosetta_ce-1.6.9.dist-info → rosetta_ce-1.7.0.dist-info}/METADATA +1 -1
- {rosetta_ce-1.6.9.dist-info → rosetta_ce-1.7.0.dist-info}/RECORD +7 -7
- {rosetta_ce-1.6.9.dist-info → rosetta_ce-1.7.0.dist-info}/WHEEL +1 -1
- {rosetta_ce-1.6.9.dist-info → rosetta_ce-1.7.0.dist-info}/LICENSE +0 -0
- {rosetta_ce-1.6.9.dist-info → rosetta_ce-1.7.0.dist-info}/top_level.txt +0 -0
rosetta/rfaker.py
CHANGED
|
@@ -2,9 +2,10 @@ import random
|
|
|
2
2
|
import requests
|
|
3
3
|
import warnings
|
|
4
4
|
import ipaddress
|
|
5
|
-
import json
|
|
6
5
|
import csv
|
|
7
6
|
import hashlib
|
|
7
|
+
import itertools
|
|
8
|
+
import time
|
|
8
9
|
from enum import Enum
|
|
9
10
|
from functools import reduce
|
|
10
11
|
from faker import Faker
|
|
@@ -180,7 +181,7 @@ class Observables:
|
|
|
180
181
|
warnings.warn(f"No source of a bad ip , generating a random IP.")
|
|
181
182
|
for i in range(count):
|
|
182
183
|
gen_observables.append(faker.ipv4())
|
|
183
|
-
|
|
184
|
+
elif observable_type == ObservableType.IP and known == ObservableKnown.GOOD:
|
|
184
185
|
for source in GOOD_IP_SOURCES:
|
|
185
186
|
try:
|
|
186
187
|
gen_observables = cls._get_observables_from_source(source)[:count]
|
|
@@ -192,7 +193,7 @@ class Observables:
|
|
|
192
193
|
warnings.warn(f"No source of a good ip , generating a random IP.")
|
|
193
194
|
for i in range(count):
|
|
194
195
|
gen_observables.append(faker.ipv4())
|
|
195
|
-
|
|
196
|
+
elif observable_type == ObservableType.URL and known == ObservableKnown.BAD:
|
|
196
197
|
for source in BAD_URL_SOURCES:
|
|
197
198
|
try:
|
|
198
199
|
gen_observables = cls._get_observables_from_source(source)[:count]
|
|
@@ -204,7 +205,7 @@ class Observables:
|
|
|
204
205
|
warnings.warn(f"No source of a bad url , generating a random url.")
|
|
205
206
|
for i in range(count):
|
|
206
207
|
gen_observables.append(faker.url())
|
|
207
|
-
|
|
208
|
+
elif observable_type == ObservableType.URL and known == ObservableKnown.GOOD:
|
|
208
209
|
for source in GOOD_URL_SOURCES:
|
|
209
210
|
try:
|
|
210
211
|
gen_observables = cls._get_observables_from_source(source)[:count]
|
|
@@ -216,7 +217,7 @@ class Observables:
|
|
|
216
217
|
warnings.warn(f"No source of a good url , generating a random url.")
|
|
217
218
|
for i in range(count):
|
|
218
219
|
gen_observables.append(faker.url())
|
|
219
|
-
|
|
220
|
+
elif observable_type == ObservableType.SHA256 and known == ObservableKnown.BAD:
|
|
220
221
|
for source in BAD_SHA256_SOURCES:
|
|
221
222
|
try:
|
|
222
223
|
gen_observables = cls._get_observables_from_source(source)[:count]
|
|
@@ -229,7 +230,7 @@ class Observables:
|
|
|
229
230
|
for i in range(count):
|
|
230
231
|
random_string = faker.text(max_nb_chars=50)
|
|
231
232
|
gen_observables.append(hashlib.sha256(random_string.encode()).hexdigest())
|
|
232
|
-
|
|
233
|
+
elif observable_type == ObservableType.SHA256 and known == ObservableKnown.GOOD:
|
|
233
234
|
for source in GOOD_SHA256_SOURCES:
|
|
234
235
|
try:
|
|
235
236
|
gen_observables = cls._get_observables_from_source(source)[:count]
|
|
@@ -242,7 +243,7 @@ class Observables:
|
|
|
242
243
|
for i in range(count):
|
|
243
244
|
random_string = faker.text(max_nb_chars=50)
|
|
244
245
|
gen_observables.append(hashlib.sha256(random_string.encode()).hexdigest())
|
|
245
|
-
|
|
246
|
+
elif observable_type == ObservableType.CVE:
|
|
246
247
|
for source in CVE_SOURCES:
|
|
247
248
|
try:
|
|
248
249
|
gen_observables = cls._get_observables_from_source(source)[:count]
|
|
@@ -255,7 +256,7 @@ class Observables:
|
|
|
255
256
|
for i in range(count):
|
|
256
257
|
fake_cve = "CVE-" + faker.numerify(text="####-####")
|
|
257
258
|
gen_observables.append(fake_cve)
|
|
258
|
-
|
|
259
|
+
elif observable_type == ObservableType.TERMS:
|
|
259
260
|
for source in TERMS_SOURCES:
|
|
260
261
|
try:
|
|
261
262
|
gen_observables = cls._get_observables_from_source(source)[:count]
|
|
@@ -272,633 +273,573 @@ class Observables:
|
|
|
272
273
|
|
|
273
274
|
class Events:
|
|
274
275
|
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
"""
|
|
278
|
-
Returns:
|
|
279
|
-
Faker instance.
|
|
280
|
-
"""
|
|
281
|
-
return Faker()
|
|
276
|
+
faker = Faker()
|
|
277
|
+
field_timings = {}
|
|
282
278
|
|
|
283
279
|
@staticmethod
|
|
284
|
-
def
|
|
285
|
-
"""
|
|
286
|
-
Returns:
|
|
287
|
-
Faker instance.
|
|
288
|
-
"""
|
|
289
|
-
return Observables()
|
|
290
|
-
|
|
291
|
-
@classmethod
|
|
292
|
-
def set_field(cls, field, observables: Optional[Observables] = None):
|
|
280
|
+
def _set_field(field):
|
|
293
281
|
"""
|
|
294
282
|
Returns:
|
|
295
283
|
Field value.
|
|
296
284
|
"""
|
|
297
|
-
field_value = None
|
|
298
|
-
faker = cls._create_faker()
|
|
299
|
-
if field == "pid":
|
|
300
|
-
field_value = faker.random_int(min=1000, max=65535)
|
|
301
|
-
if field == "src_host":
|
|
302
|
-
field_value = random.choice(observables.src_host) if observables and observables.src_host \
|
|
303
|
-
else faker.hostname()
|
|
304
|
-
if field == "dst_host":
|
|
305
|
-
field_value = random.choice(observables.dst_host) if observables and observables.dst_host \
|
|
306
|
-
else faker.hostname()
|
|
307
|
-
if field == "user":
|
|
308
|
-
field_value = random.choice(observables.user) if observables and observables.user \
|
|
309
|
-
else faker.user_name()
|
|
310
|
-
if field == "unix_process":
|
|
311
|
-
field_value = random.choice(observables.unix_process) if observables and observables.unix_process \
|
|
312
|
-
else "sudo"
|
|
313
|
-
if field == "unix_child_process":
|
|
314
|
-
field_value = random.choice(observables.unix_child_process) if observables and \
|
|
315
|
-
observables.unix_child_process else "sudo"
|
|
316
|
-
if field == "unix_cmd":
|
|
317
|
-
field_value = random.choice(observables.unix_cmd) if observables and observables.unix_cmd \
|
|
318
|
-
else random.choice(UNIX_CMD)
|
|
319
|
-
if field == "technique":
|
|
320
|
-
field_value = random.choice(observables.technique) if observables and observables.technique \
|
|
321
|
-
else random.choice(ATTACK_TECHNIQUES)
|
|
322
|
-
if field == "entry_type":
|
|
323
|
-
field_value = random.choice(observables.entry_type) if observables and observables.entry_type \
|
|
324
|
-
else faker.sentence(nb_words=2)
|
|
325
|
-
if field == "sensor":
|
|
326
|
-
field_value = random.choice(observables.sensor) if observables and observables.sensor \
|
|
327
|
-
else faker.sentence(nb_words=1)
|
|
328
|
-
if field == "event_id":
|
|
329
|
-
field_value = random.choice(observables.event_id) if observables and observables.event_id \
|
|
330
|
-
else faker.random_int(min=10, max=1073741824)
|
|
331
|
-
if field == "error_code":
|
|
332
|
-
field_value = random.choice(observables.error_code) if observables and observables.error_code \
|
|
333
|
-
else faker.random_int(min=1000, max=5000)
|
|
334
|
-
if field == "terms":
|
|
335
|
-
field_value = random.choice(observables.terms) if observables and observables.terms \
|
|
336
|
-
else faker.sentence(nb_words=10)
|
|
337
|
-
if field == "alert_types":
|
|
338
|
-
field_value = random.choice(observables.alert_types) if observables and observables.alert_types \
|
|
339
|
-
else faker.sentence(nb_words=1)
|
|
340
|
-
if field == "action_status":
|
|
341
|
-
field_value = random.choice(observables.action_status) if observables and observables.action_status \
|
|
342
|
-
else random.choice(ACTIONS)
|
|
343
|
-
if field == "severity":
|
|
344
|
-
field_value = random.choice(observables.severity) if observables and observables.severity \
|
|
345
|
-
else random.choice(SEVERITIES)
|
|
346
|
-
if field == "local_ip":
|
|
347
|
-
field_value = random.choice(observables.local_ip) if observables and observables.local_ip \
|
|
348
|
-
else faker.ipv4()
|
|
349
|
-
if field == "local_port":
|
|
350
|
-
field_value = faker.random_int(min=1024, max=65535)
|
|
351
|
-
if field == "remote_ip":
|
|
352
|
-
field_value = random.choice(observables.remote_ip) if observables and observables.remote_ip \
|
|
353
|
-
else Observables.generator(observable_type=ObservableType.IP, known=ObservableKnown.BAD, count=1)[0]
|
|
354
|
-
if field == "local_ip_v6":
|
|
355
|
-
field_value = random.choice(observables.local_ip_v6) if observables and observables.local_ip_v6 \
|
|
356
|
-
else faker.ipv6()
|
|
357
|
-
if field == "remote_ip_v6":
|
|
358
|
-
field_value = random.choice(observables.remote_ip_v6) if observables and observables.remote_ip_v6 \
|
|
359
|
-
else faker.ipv6()
|
|
360
|
-
if field == "remote_port":
|
|
361
|
-
field_value = random.choice(observables.remote_port) if observables and observables.remote_port \
|
|
362
|
-
else faker.random_int(min=1024, max=65535)
|
|
363
|
-
if field == "dst_url":
|
|
364
|
-
field_value = random.choice(observables.url) if observables and observables.url \
|
|
365
|
-
else Observables.generator(observable_type=ObservableType.URL, known=ObservableKnown.BAD, count=1)
|
|
366
|
-
if field == "inbound_bytes":
|
|
367
|
-
field_value = random.choice(observables.inbound_bytes) if observables and observables.inbound_bytes \
|
|
368
|
-
else faker.random_int(min=10, max=1073741824)
|
|
369
|
-
if field == "outbound_bytes":
|
|
370
|
-
field_value = random.choice(observables.outbound_bytes) if observables and observables.outbound_bytes \
|
|
371
|
-
else faker.random_int(min=10, max=1073741824)
|
|
372
|
-
if field == "app":
|
|
373
|
-
field_value = random.choice(observables.app) if observables and observables.app \
|
|
374
|
-
else faker.sentence(nb_words=2)
|
|
375
|
-
if field == "os":
|
|
376
|
-
field_value = random.choice(observables.os) if observables and observables.os \
|
|
377
|
-
else random.choice(OS_LIST)
|
|
378
|
-
if field == "protocol":
|
|
379
|
-
field_value = random.choice(observables.protocol) if observables and observables.protocol \
|
|
380
|
-
else random.choice(PROTOCOLS)
|
|
381
|
-
if field == "rule_id":
|
|
382
|
-
field_value = random.choice(observables.event_id) if observables and observables.event_id \
|
|
383
|
-
else faker.random_int(min=1, max=200)
|
|
384
|
-
if field == "action":
|
|
385
|
-
field_value = random.choice(observables.action) if observables and observables.action \
|
|
386
|
-
else random.choice(ACTIONS)
|
|
387
|
-
if field == "src_domain":
|
|
388
|
-
field_value = random.choice(observables.src_domain) if observables and observables.src_domain \
|
|
389
|
-
else faker.domain_name()
|
|
390
|
-
if field == "dst_domain":
|
|
391
|
-
field_value = random.choice(observables.dst_domain) if observables and observables.dst_domain \
|
|
392
|
-
else faker.domain_name()
|
|
393
|
-
if field == "sender_email":
|
|
394
|
-
field_value = random.choice(observables.sender_email) if observables and observables.sender_email \
|
|
395
|
-
else faker.email()
|
|
396
|
-
if field == "recipient_email":
|
|
397
|
-
field_value = random.choice(observables.recipient_email) if observables and observables.recipient_email \
|
|
398
|
-
else faker.email()
|
|
399
|
-
if field == "email_subject":
|
|
400
|
-
field_value = random.choice(observables.email_subject) if observables and observables.email_subject \
|
|
401
|
-
else faker.sentence(nb_words=6)
|
|
402
|
-
if field == "email_body":
|
|
403
|
-
field_value = random.choice(observables.email_body) if observables and observables.email_body else \
|
|
404
|
-
faker.sentence(nb_words=50)
|
|
405
|
-
if field == "attachment_hash":
|
|
406
|
-
field_value = random.choice(observables.file_hash) if observables and observables.file_hash \
|
|
407
|
-
else Observables.generator(observable_type=ObservableType.SHA256, known=ObservableKnown.BAD,
|
|
408
|
-
count=1)
|
|
409
|
-
if field == "spam_score":
|
|
410
|
-
field_value = faker.random_int(min=1, max=5)
|
|
411
|
-
if field == "method":
|
|
412
|
-
field_value = random.choice(observables.technique).get('mechanism') if observables and \
|
|
413
|
-
observables.technique else random.choice(TECHNIQUES).get('mechanism')
|
|
414
|
-
if field == "url":
|
|
415
|
-
field_value = random.choice(observables.technique).get('indicator') if observables and \
|
|
416
|
-
observables.technique else random.choice(TECHNIQUES).get('indicator')
|
|
417
|
-
if field == "user_agent":
|
|
418
|
-
field_value = faker.user_agent()
|
|
419
|
-
if field == "referer":
|
|
420
|
-
field_value = random.choice(observables.url) if observables and observables.url \
|
|
421
|
-
else Observables.generator(observable_type=ObservableType.URL, known=ObservableKnown.BAD, count=1)
|
|
422
|
-
if field == "response_code":
|
|
423
|
-
field_value = random.choice(observables.error_code) if observables and observables.error_code \
|
|
424
|
-
else random.choice(ERROR_CODE)
|
|
425
|
-
if field == "response_size":
|
|
426
|
-
field_value = faker.random_int(min=100, max=10000)
|
|
427
|
-
if field == "attack_type":
|
|
428
|
-
field_value = random.choice(observables.technique).get('technique') if observables and \
|
|
429
|
-
observables.technique else random.choice(TECHNIQUES).get('technique')
|
|
430
|
-
if field == "cookies":
|
|
431
|
-
field_value = f"{faker.word()}={faker.uuid4()}"
|
|
432
|
-
if field == "guid":
|
|
433
|
-
field_value = faker.uuid4()
|
|
434
|
-
if field == "transmitted_services":
|
|
435
|
-
field_value = faker.sentence(nb_words=5)
|
|
436
|
-
if field == "process_id":
|
|
437
|
-
field_value = faker.random_int()
|
|
438
|
-
if field == "new_process_id":
|
|
439
|
-
field_value = faker.random_int()
|
|
440
|
-
if field == "thread_id":
|
|
441
|
-
field_value = faker.random_int()
|
|
442
|
-
if field == "target_pid":
|
|
443
|
-
field_value = faker.random_int()
|
|
444
|
-
if field == "subject_login_id":
|
|
445
|
-
field_value = faker.random_int()
|
|
446
|
-
if field == "win_user_id":
|
|
447
|
-
field_value = "S-1-" + str(faker.random_int())
|
|
448
|
-
if field == "destination_login_id":
|
|
449
|
-
field_value = faker.random_int()
|
|
450
|
-
if field == "privilege_list":
|
|
451
|
-
field_value = faker.sentence(nb_words=5)
|
|
452
|
-
if field == "event_record_id":
|
|
453
|
-
field_value = random.choice(observables.event_id) if observables and observables.event_id \
|
|
454
|
-
else faker.random.randint(1, 999)
|
|
455
|
-
if field == "win_process":
|
|
456
|
-
field_value = random.choice(observables.win_process) if observables and observables.win_process \
|
|
457
|
-
else random.choice(WIN_PROCESSES)
|
|
458
|
-
if field == "win_cmd":
|
|
459
|
-
field_value = random.choice(observables.win_cmd) if observables and observables.win_cmd \
|
|
460
|
-
else random.choice(WINDOWS_CMD)
|
|
461
|
-
if field == "win_child_process":
|
|
462
|
-
field_value = random.choice(observables.win_child_process) if \
|
|
463
|
-
observables and observables.win_child_process else random.choice(WIN_PROCESSES)
|
|
464
|
-
if field == "source_network_address":
|
|
465
|
-
field_value = random.choice(observables.local_ip) if observables and observables.local_ip \
|
|
466
|
-
else faker.ipv4_private()
|
|
467
|
-
if field == "file_name":
|
|
468
|
-
field_value = random.choice(observables.file_name) if observables and observables.file_name \
|
|
469
|
-
else faker.file_name()
|
|
470
|
-
if field == "cve":
|
|
471
|
-
field_value = random.choice(observables.cve) if observables and observables.cve \
|
|
472
|
-
else Observables.generator(observable_type=ObservableType.CVE, count=1)
|
|
473
|
-
if field == "file_hash":
|
|
474
|
-
field_value = random.choice(observables.file_hash) if observables and observables.file_hash \
|
|
475
|
-
else Observables.generator(observable_type=ObservableType.SHA256, known=ObservableKnown.BAD,
|
|
476
|
-
count=1)
|
|
477
|
-
if field == "incident_types":
|
|
478
|
-
field_value = random.choice(observables.incident_types) if observables and observables.incident_types \
|
|
479
|
-
else INCIDENTS_TYPES
|
|
480
|
-
if field == "analysts":
|
|
481
|
-
field_value = random.choice(observables.analysts) if observables and observables.analysts \
|
|
482
|
-
else [faker.unique.first_name() for _ in range(10)]
|
|
483
|
-
if field == "duration":
|
|
484
|
-
field_value = random.randint(1, 5)
|
|
485
|
-
if field == "log_id":
|
|
486
|
-
field_value = faker.uuid4()
|
|
487
|
-
if field == "alert_name":
|
|
488
|
-
field_value = random.choice(observables.alert_name) if observables and observables.alert_name \
|
|
489
|
-
else faker.sentence(nb_words=4)
|
|
490
|
-
if field == "query_type":
|
|
491
|
-
field_value = random.choice(observables.query_type) if \
|
|
492
|
-
observables and observables.query_type else random.choice(QUERY_TYPE)
|
|
493
|
-
if field == "database_name":
|
|
494
|
-
field_value = random.choice(observables.database_name) if \
|
|
495
|
-
observables and observables.database_name else random.choice(DATABASE_NAME)
|
|
496
|
-
if field == "query":
|
|
497
|
-
field_value = random.choice(observables.query) if \
|
|
498
|
-
observables and observables.query else random.choice(QUERY)
|
|
499
|
-
return field_value
|
|
500
285
|
|
|
286
|
+
faker = Events.faker
|
|
287
|
+
|
|
288
|
+
# Define default generators for each field
|
|
289
|
+
default_generators = {
|
|
290
|
+
"pid": lambda: faker.random_int(min=1000, max=65535),
|
|
291
|
+
"src_host": faker.hostname,
|
|
292
|
+
"dst_host": faker.hostname,
|
|
293
|
+
"user": faker.user_name,
|
|
294
|
+
"unix_process": lambda: "sudo",
|
|
295
|
+
"unix_child_process": lambda: "sudo",
|
|
296
|
+
"unix_cmd": lambda: random.choice(UNIX_CMD),
|
|
297
|
+
"technique": lambda: random.choice(ATTACK_TECHNIQUES),
|
|
298
|
+
"entry_type": lambda: faker.sentence(nb_words=2),
|
|
299
|
+
"sensor": lambda: faker.sentence(nb_words=1),
|
|
300
|
+
"event_id": lambda: faker.random_int(min=10, max=1073741824),
|
|
301
|
+
"error_code": lambda: faker.random_int(min=1000, max=5000),
|
|
302
|
+
"terms": lambda: faker.sentence(nb_words=10),
|
|
303
|
+
"alert_types": lambda: faker.sentence(nb_words=1),
|
|
304
|
+
"action_status": lambda: random.choice(ACTIONS),
|
|
305
|
+
"severity": lambda: random.choice(SEVERITIES),
|
|
306
|
+
"local_ip": faker.ipv4,
|
|
307
|
+
"local_port": lambda: faker.random_int(min=1024, max=65535),
|
|
308
|
+
"remote_ip": lambda: Observables.generator(
|
|
309
|
+
observable_type=ObservableType.IP,
|
|
310
|
+
known=ObservableKnown.BAD,
|
|
311
|
+
count=1
|
|
312
|
+
)[0],
|
|
313
|
+
"local_ip_v6": faker.ipv6,
|
|
314
|
+
"remote_ip_v6": faker.ipv6,
|
|
315
|
+
"remote_port": lambda: faker.random_int(min=1024, max=65535),
|
|
316
|
+
"dst_url": lambda: Observables.generator(
|
|
317
|
+
observable_type=ObservableType.URL,
|
|
318
|
+
known=ObservableKnown.BAD,
|
|
319
|
+
count=1
|
|
320
|
+
)[0],
|
|
321
|
+
"inbound_bytes": lambda: faker.random_int(min=10, max=1073741824),
|
|
322
|
+
"outbound_bytes": lambda: faker.random_int(min=10, max=1073741824),
|
|
323
|
+
"app": lambda: faker.sentence(nb_words=2),
|
|
324
|
+
"os": lambda: random.choice(OS_LIST),
|
|
325
|
+
"protocol": lambda: random.choice(PROTOCOLS),
|
|
326
|
+
"rule_id": lambda: faker.random_int(min=1, max=200),
|
|
327
|
+
"action": lambda: random.choice(ACTIONS),
|
|
328
|
+
"src_domain": faker.domain_name,
|
|
329
|
+
"dst_domain": faker.domain_name,
|
|
330
|
+
"sender_email": faker.email,
|
|
331
|
+
"recipient_email": faker.email,
|
|
332
|
+
"email_subject": lambda: faker.sentence(nb_words=6),
|
|
333
|
+
"email_body": lambda: faker.sentence(nb_words=50),
|
|
334
|
+
"attachment_hash": lambda: Observables.generator(
|
|
335
|
+
observable_type=ObservableType.SHA256,
|
|
336
|
+
known=ObservableKnown.BAD,
|
|
337
|
+
count=1
|
|
338
|
+
)[0],
|
|
339
|
+
"spam_score": lambda: faker.random_int(min=1, max=5),
|
|
340
|
+
"method": lambda: random.choice(TECHNIQUES).get('mechanism'),
|
|
341
|
+
"url": lambda: random.choice(TECHNIQUES).get('indicator'),
|
|
342
|
+
"user_agent": faker.user_agent,
|
|
343
|
+
"referer": lambda: Observables.generator(
|
|
344
|
+
observable_type=ObservableType.URL,
|
|
345
|
+
known=ObservableKnown.BAD,
|
|
346
|
+
count=1
|
|
347
|
+
)[0],
|
|
348
|
+
"response_code": lambda: random.choice(ERROR_CODE),
|
|
349
|
+
"response_size": lambda: faker.random_int(min=100, max=10000),
|
|
350
|
+
"attack_type": lambda: random.choice(TECHNIQUES).get('technique'),
|
|
351
|
+
"cookies": lambda: f"{faker.word()}={faker.uuid4()}",
|
|
352
|
+
"guid": faker.uuid4,
|
|
353
|
+
"transmitted_services": lambda: faker.sentence(nb_words=5),
|
|
354
|
+
"process_id": faker.random_int,
|
|
355
|
+
"new_process_id": faker.random_int,
|
|
356
|
+
"thread_id": faker.random_int,
|
|
357
|
+
"target_pid": faker.random_int,
|
|
358
|
+
"subject_login_id": faker.random_int,
|
|
359
|
+
"win_user_id": lambda: "S-1-" + str(faker.random_int()),
|
|
360
|
+
"destination_login_id": faker.random_int,
|
|
361
|
+
"privilege_list": lambda: faker.sentence(nb_words=5),
|
|
362
|
+
"event_record_id": lambda: faker.random_int(min=1, max=999),
|
|
363
|
+
"win_process": lambda: random.choice(WIN_PROCESSES),
|
|
364
|
+
"win_cmd": lambda: random.choice(WINDOWS_CMD),
|
|
365
|
+
"win_child_process": lambda: random.choice(WIN_PROCESSES),
|
|
366
|
+
"source_network_address": faker.ipv4_private,
|
|
367
|
+
"file_name": faker.file_name,
|
|
368
|
+
"cve": lambda: Observables.generator(
|
|
369
|
+
observable_type=ObservableType.CVE,
|
|
370
|
+
count=1
|
|
371
|
+
)[0],
|
|
372
|
+
"file_hash": lambda: Observables.generator(
|
|
373
|
+
observable_type=ObservableType.SHA256,
|
|
374
|
+
known=ObservableKnown.BAD,
|
|
375
|
+
count=1
|
|
376
|
+
)[0],
|
|
377
|
+
"incident_types": lambda: random.choice(INCIDENTS_TYPES),
|
|
378
|
+
"analysts": lambda: [faker.unique.first_name() for _ in range(10)],
|
|
379
|
+
"duration": lambda: random.randint(1, 5),
|
|
380
|
+
"log_id": faker.uuid4,
|
|
381
|
+
"alert_name": lambda: faker.sentence(nb_words=4),
|
|
382
|
+
"query_type": lambda: random.choice(QUERY_TYPE),
|
|
383
|
+
"database_name": lambda: random.choice(DATABASE_NAME),
|
|
384
|
+
"query": lambda: random.choice(QUERY),
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
if field in default_generators:
|
|
388
|
+
generator = default_generators[field]
|
|
389
|
+
field_value = generator() if callable(generator) else generator()
|
|
390
|
+
else:
|
|
391
|
+
field_value = faker.word()
|
|
392
|
+
|
|
393
|
+
return field_value
|
|
394
|
+
|
|
501
395
|
@classmethod
|
|
502
|
-
def syslog(
|
|
503
|
-
|
|
396
|
+
def syslog(
|
|
397
|
+
cls,
|
|
398
|
+
count: int,
|
|
399
|
+
datetime_iso: Optional[datetime] = None,
|
|
400
|
+
observables: Optional['Observables'] = None,
|
|
401
|
+
required_fields: Optional[str] = None
|
|
402
|
+
) -> List[str]:
|
|
504
403
|
"""
|
|
505
|
-
Generate fake syslog messages.
|
|
506
|
-
|
|
507
|
-
Args:
|
|
508
|
-
count: The number of syslog messages to generate.
|
|
509
|
-
datetime_iso: Optional. The starting datetime_iso for the syslog messages. If not provided, a random time during
|
|
510
|
-
the past hour from now will be used.
|
|
511
|
-
observables: Optional. An observables object. If not provided, random objservable will be generated
|
|
512
|
-
and used.
|
|
513
|
-
required_fields: Optional. A list of fields that are required to present in the generated data, whether from
|
|
514
|
-
observables or randomely.
|
|
515
|
-
Returns:
|
|
516
|
-
A list of syslog messages.
|
|
517
|
-
|
|
518
|
-
Examples:
|
|
519
|
-
>>> Events.syslog(5)
|
|
520
|
-
['Jan 01 05:32:48 myhostname sudo[1023]: username : COMMAND ; cat /etc/shadow',
|
|
521
|
-
'Jan 01 05:17:59 myhostname sudo[2019]: username : COMMAND ; find / -name \'*.log\' -exec rm -f {} \\;',
|
|
522
|
-
'Jan 01 05:46:16 myhostname sudo[3132]: username : COMMAND ; dd if=/dev/zero of=/dev/sda',
|
|
523
|
-
'Jan 01 05:08:08 myhostname sudo[4111]: username : COMMAND ; chmod -R 777 /',
|
|
524
|
-
'Jan 01 05:59:41 myhostname sudo[5195]: username : COMMAND ; chown -R nobody:nogroup /']
|
|
525
|
-
|
|
404
|
+
Generate fake syslog messages with optimizations for efficiency.
|
|
526
405
|
"""
|
|
527
406
|
syslog_messages = []
|
|
528
|
-
faker =
|
|
407
|
+
faker = Events.faker
|
|
408
|
+
|
|
409
|
+
# Predefine default datetime if not provided
|
|
529
410
|
if datetime_iso is None:
|
|
530
411
|
datetime_iso = datetime.now() - timedelta(hours=1)
|
|
531
412
|
datetime_iso += timedelta(seconds=faker.random_int(min=0, max=3599))
|
|
532
|
-
|
|
533
|
-
|
|
413
|
+
|
|
414
|
+
# Set default required fields
|
|
415
|
+
required_fields_list = required_fields.split(",") if required_fields else [
|
|
416
|
+
"pid", "host", "user", "unix_process", "unix_cmd"
|
|
417
|
+
]
|
|
418
|
+
|
|
419
|
+
# Precompute static values for required fields
|
|
420
|
+
common_fields = {}
|
|
421
|
+
for field in required_fields_list:
|
|
422
|
+
value = None
|
|
423
|
+
if observables and hasattr(observables, field):
|
|
424
|
+
obs_value = getattr(observables, field)
|
|
425
|
+
if obs_value:
|
|
426
|
+
if isinstance(obs_value, list):
|
|
427
|
+
value = random.choice(obs_value)
|
|
428
|
+
else:
|
|
429
|
+
value = obs_value
|
|
430
|
+
if value is None:
|
|
431
|
+
value = Events._set_field(field)
|
|
432
|
+
common_fields[field] = value
|
|
433
|
+
|
|
434
|
+
# Preprocess observables
|
|
435
|
+
extra_fields = []
|
|
436
|
+
if observables:
|
|
437
|
+
observables_dict = vars(observables)
|
|
438
|
+
for key, value in observables_dict.items():
|
|
439
|
+
if value and key not in required_fields_list:
|
|
440
|
+
if isinstance(value, list):
|
|
441
|
+
val = random.choice(value)
|
|
442
|
+
else:
|
|
443
|
+
val = value
|
|
444
|
+
extra_fields.append(str(val))
|
|
445
|
+
|
|
446
|
+
# Generate all syslog messages
|
|
534
447
|
for i in range(count):
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
for field in required_fields.split(","):
|
|
538
|
-
syslog_message += f" {cls.set_field(field, observables)}"
|
|
539
|
-
if observables:
|
|
540
|
-
for observable, observable_value in vars(observables).items():
|
|
541
|
-
if observable_value and observable not in required_fields.split(","):
|
|
542
|
-
syslog_message += f" {random.choice(observable_value)}"
|
|
543
|
-
syslog_messages.append(syslog_message)
|
|
544
|
-
return syslog_messages
|
|
448
|
+
# Update datetime for each log
|
|
449
|
+
current_time = (datetime_iso + timedelta(seconds=i + 1)).strftime('%b %d %H:%M:%S')
|
|
545
450
|
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
version: Optional[str] = None, datetime_iso: Optional[datetime] = None,
|
|
549
|
-
observables: Optional[Observables] = None, required_fields: Optional[str] = None) -> List[str]:
|
|
550
|
-
"""
|
|
551
|
-
Generates fake CEF (Common Event Format) messages.
|
|
451
|
+
# Build the syslog message efficiently
|
|
452
|
+
syslog_message_parts = [f"{current_time}"]
|
|
552
453
|
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
datetime_iso: Optional. The starting datetime_iso for the syslog messages. If not provided, a random time during.
|
|
556
|
-
vendor: Optional. The vendor.
|
|
557
|
-
product: Optional. The product value options include:
|
|
558
|
-
- Firewall
|
|
559
|
-
- EmailGW
|
|
560
|
-
version: Optional. The version.
|
|
561
|
-
observables: Optional. An observables object. If not provided, random objservable will be generated
|
|
562
|
-
and used.
|
|
563
|
-
required_fields: Optional. A list of fields that are required to present in the generated data, whether from
|
|
564
|
-
observables or randomely.
|
|
565
|
-
Returns:
|
|
566
|
-
A list of fake CEF messages in string format.
|
|
454
|
+
# Insert required fields
|
|
455
|
+
syslog_message_parts.extend(str(common_fields[field]) for field in required_fields_list)
|
|
567
456
|
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
457
|
+
# Append additional observables not in required fields
|
|
458
|
+
syslog_message_parts.extend(extra_fields)
|
|
459
|
+
|
|
460
|
+
syslog_messages.append(" ".join(syslog_message_parts))
|
|
461
|
+
|
|
462
|
+
return syslog_messages
|
|
463
|
+
|
|
464
|
+
@classmethod
|
|
465
|
+
def cef(
|
|
466
|
+
cls,
|
|
467
|
+
count: int,
|
|
468
|
+
vendor: Optional[str] = None,
|
|
469
|
+
product: Optional[str] = None,
|
|
470
|
+
version: Optional[str] = None,
|
|
471
|
+
datetime_iso: Optional[datetime] = None,
|
|
472
|
+
observables: Optional['Observables'] = None,
|
|
473
|
+
required_fields: Optional[str] = None
|
|
474
|
+
) -> List[str]:
|
|
583
475
|
cef_messages = []
|
|
584
|
-
faker =
|
|
476
|
+
faker = Events.faker
|
|
585
477
|
vendor = vendor or faker.company()
|
|
478
|
+
product = product or faker.word()
|
|
586
479
|
version = version or faker.numerify("1.0.#")
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
480
|
+
datetime_iso = datetime_iso or datetime.now() - timedelta(hours=1)
|
|
481
|
+
required_fields_list = required_fields.split(",") if required_fields else [
|
|
482
|
+
"local_ip", "local_port", "remote_ip", "remote_port", "protocol", "rule_id", "action"
|
|
483
|
+
]
|
|
484
|
+
|
|
485
|
+
common_fields = {}
|
|
486
|
+
for field in required_fields_list:
|
|
487
|
+
value = None
|
|
488
|
+
if observables and hasattr(observables, field):
|
|
489
|
+
obs_value = getattr(observables, field)
|
|
490
|
+
if obs_value:
|
|
491
|
+
if isinstance(obs_value, list):
|
|
492
|
+
value = random.choice(obs_value)
|
|
493
|
+
else:
|
|
494
|
+
value = obs_value
|
|
495
|
+
if value is None:
|
|
496
|
+
value = Events._set_field(field)
|
|
497
|
+
common_fields[field] = value
|
|
498
|
+
|
|
499
|
+
|
|
500
|
+
# Preprocess observables
|
|
501
|
+
extra_fields_str = ""
|
|
502
|
+
if observables:
|
|
503
|
+
observables_dict = vars(observables)
|
|
504
|
+
extra_fields = [
|
|
505
|
+
f"{key}={random.choice(value)}"
|
|
506
|
+
for key, value in observables_dict.items()
|
|
507
|
+
if value and key not in required_fields_list
|
|
508
|
+
]
|
|
509
|
+
if extra_fields:
|
|
510
|
+
extra_fields_str = " " + " ".join(extra_fields)
|
|
511
|
+
|
|
512
|
+
# Pre-compile the CEF message template
|
|
513
|
+
cef_template = (
|
|
514
|
+
f"CEF:0|{vendor}|{product}|{version}|{{log_id}}|{{current_datetime}}|{{severity}}|"
|
|
515
|
+
+ " ".join([f"{field}={common_fields[field]}" for field in required_fields_list])
|
|
516
|
+
)
|
|
517
|
+
|
|
518
|
+
# Generate events
|
|
599
519
|
for i in range(count):
|
|
600
|
-
datetime_iso
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
520
|
+
current_datetime = datetime_iso + timedelta(seconds=i)
|
|
521
|
+
log_id = faker.uuid4()
|
|
522
|
+
severity = common_fields.get('severity') or 'low'
|
|
523
|
+
|
|
524
|
+
cef_message = cef_template.format(
|
|
525
|
+
log_id=log_id,
|
|
526
|
+
current_datetime=current_datetime.strftime('%Y-%m-%dT%H:%M:%S.%fZ'),
|
|
527
|
+
severity=severity
|
|
528
|
+
)
|
|
529
|
+
cef_message += extra_fields_str
|
|
609
530
|
cef_messages.append(cef_message)
|
|
531
|
+
|
|
610
532
|
return cef_messages
|
|
611
|
-
|
|
533
|
+
|
|
612
534
|
@classmethod
|
|
613
|
-
def leef(
|
|
614
|
-
|
|
615
|
-
|
|
535
|
+
def leef(
|
|
536
|
+
cls,
|
|
537
|
+
count: int,
|
|
538
|
+
datetime_iso: Optional[datetime] = None,
|
|
539
|
+
vendor: Optional[str] = None,
|
|
540
|
+
product: Optional[str] = None,
|
|
541
|
+
version: Optional[str] = None,
|
|
542
|
+
observables: Optional['Observables'] = None,
|
|
543
|
+
required_fields: Optional[str] = None
|
|
544
|
+
) -> List[str]:
|
|
616
545
|
"""
|
|
617
|
-
Generates fake LEEF (Log Event Extended Format) messages.
|
|
618
|
-
|
|
619
|
-
Parameters:
|
|
620
|
-
count (int): The number of LEEF messages to generate.
|
|
621
|
-
datetime_iso: Optional. The starting datetime_iso for the syslog messages. If not provided, a random time during.
|
|
622
|
-
vendor: Optional. The vendor.
|
|
623
|
-
product: Optional. The product.
|
|
624
|
-
version: Optional. The version.
|
|
625
|
-
observables: An observables object. If not provided, random objservable will be generated and used.
|
|
626
|
-
required_fields: Optional. A list of fields that are required to present in the generated data, whether from
|
|
627
|
-
observables or randomely.
|
|
628
|
-
|
|
629
|
-
Returns:
|
|
630
|
-
A list of generated LEEF messages.
|
|
631
|
-
|
|
632
|
-
Example:
|
|
633
|
-
To generate 10 fake LEEF messages:
|
|
634
|
-
```
|
|
635
|
-
>>> messages = Events.leef(count=2)
|
|
636
|
-
>>> print(messages)
|
|
637
|
-
['LEEF:1.0|Leef|Payment Portal|1.0|192.168.0.1|mycomputer|08:00:27:da:2e:2e|08:00:27:da:2e:2f|src=10.0.0.1
|
|
638
|
-
dst=mycomputer spt=60918 dpt=443 request=https://example.com/?q=<script>alert("xss")</script>
|
|
639
|
-
method=GET proto=HTTP/1.1 status=200 request_size=5119 response_size=6472
|
|
640
|
-
user_agent=Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko)
|
|
641
|
-
Chrome/93.0.4577.63 Safari/537.36',
|
|
642
|
-
'LEEF:1.0|Leef|Payment Portal|1.0|192.168.0.1|mycomputer|08:00:27:da:2e:2e|08:00:27:da:2e:2f|src=10.0.0.2
|
|
643
|
-
dst=mycomputer spt=57251 dpt=443 request=https://example.com/admin.php?sessionid=12345 method=POST
|
|
644
|
-
proto=HTTP/1.1 status=404 request_size=1216 response_size=9729 user_agent=Mozilla/5.0
|
|
645
|
-
(Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3']
|
|
546
|
+
Generates optimized fake LEEF (Log Event Extended Format) messages.
|
|
646
547
|
"""
|
|
647
548
|
leef_messages = []
|
|
648
|
-
faker =
|
|
549
|
+
faker = Events.faker
|
|
649
550
|
vendor = vendor or faker.company()
|
|
551
|
+
product = product or faker.word()
|
|
650
552
|
version = version or faker.numerify("1.0.#")
|
|
553
|
+
|
|
554
|
+
# Set starting datetime and default fields if necessary
|
|
555
|
+
datetime_iso = datetime_iso or datetime.now() - timedelta(hours=1)
|
|
556
|
+
required_fields_list = required_fields.split(",") if required_fields else [
|
|
557
|
+
"local_ip", "local_port", "host", "url", "protocol", "response_code", "action"
|
|
558
|
+
]
|
|
559
|
+
|
|
560
|
+
# Precompute event_id and severity
|
|
651
561
|
event_id = faker.random_int(min=101, max=501)
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
562
|
+
severity = Events._set_field("severity")
|
|
563
|
+
|
|
564
|
+
# Precompute common fields
|
|
565
|
+
common_fields = {}
|
|
566
|
+
for field in required_fields_list:
|
|
567
|
+
value = None
|
|
568
|
+
if observables and hasattr(observables, field):
|
|
569
|
+
obs_value = getattr(observables, field)
|
|
570
|
+
if obs_value:
|
|
571
|
+
if isinstance(obs_value, list):
|
|
572
|
+
value = random.choice(obs_value)
|
|
573
|
+
else:
|
|
574
|
+
value = obs_value
|
|
575
|
+
if value is None:
|
|
576
|
+
value = Events._set_field(field)
|
|
577
|
+
common_fields[field] = value
|
|
578
|
+
|
|
579
|
+
# Preprocess extra observables
|
|
580
|
+
extra_fields = []
|
|
581
|
+
if observables:
|
|
582
|
+
observables_dict = vars(observables)
|
|
583
|
+
for key, value in observables_dict.items():
|
|
584
|
+
if value and key not in required_fields_list:
|
|
585
|
+
val = random.choice(value) if isinstance(value, list) else value
|
|
586
|
+
extra_fields.append(f" {key}={val}")
|
|
587
|
+
|
|
588
|
+
# Pre-compile the LEEF message template
|
|
589
|
+
leef_template = (
|
|
590
|
+
f"LEEF:1.0|{vendor}|{product}|{version}|{event_id}|"
|
|
591
|
+
f"severity={severity} devTime={{current_datetime}}"
|
|
592
|
+
+ "".join(f" {field}={common_fields[field]}" for field in required_fields_list)
|
|
593
|
+
+ "".join(extra_fields)
|
|
594
|
+
)
|
|
595
|
+
|
|
596
|
+
# Generate messages
|
|
661
597
|
for i in range(count):
|
|
662
|
-
datetime_iso
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
for field in required_fields.split(","):
|
|
666
|
-
leef_message += f" {field}={cls.set_field(field, observables)}"
|
|
667
|
-
if observables:
|
|
668
|
-
for observable, observable_value in vars(observables).items():
|
|
669
|
-
if observable_value and observable not in required_fields.split(","):
|
|
670
|
-
leef_message += f" {observable}={random.choice(observable_value)}"
|
|
598
|
+
current_datetime = (datetime_iso + timedelta(seconds=i)).strftime('%b %d %H:%M:%S')
|
|
599
|
+
|
|
600
|
+
leef_message = leef_template.format(current_datetime=current_datetime)
|
|
671
601
|
leef_messages.append(leef_message)
|
|
672
|
-
return leef_messages
|
|
673
602
|
|
|
603
|
+
return leef_messages
|
|
604
|
+
|
|
674
605
|
@classmethod
|
|
675
|
-
def winevent(
|
|
676
|
-
|
|
606
|
+
def winevent(
|
|
607
|
+
cls,
|
|
608
|
+
count: int,
|
|
609
|
+
datetime_iso: Optional[datetime] = None,
|
|
610
|
+
observables: Optional['Observables'] = None
|
|
611
|
+
) -> List[str]:
|
|
677
612
|
"""
|
|
678
|
-
Generates fake Windows Event Log messages.
|
|
613
|
+
Generates optimized fake Windows Event Log messages using set_field.
|
|
679
614
|
|
|
680
615
|
Args:
|
|
681
616
|
count (int): The number of fake messages to generate.
|
|
682
|
-
datetime_iso
|
|
683
|
-
observables: An observables object
|
|
617
|
+
datetime_iso (Optional[datetime]): The starting datetime for the messages.
|
|
618
|
+
observables (Optional[Observables]): An observables object with predefined values.
|
|
684
619
|
|
|
685
620
|
Returns:
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
Examples:
|
|
689
|
-
>>> Events.winevent(1)
|
|
690
|
-
['<Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">...</Event>', ...]
|
|
621
|
+
List[str]: A list of fake Windows Event Log messages.
|
|
691
622
|
"""
|
|
692
623
|
winevent_messages = []
|
|
693
|
-
faker =
|
|
624
|
+
faker = Events.faker
|
|
625
|
+
|
|
626
|
+
# Set starting datetime if not provided
|
|
694
627
|
if datetime_iso is None:
|
|
695
628
|
datetime_iso = datetime.now() - timedelta(hours=1)
|
|
696
629
|
datetime_iso += timedelta(seconds=faker.random_int(min=0, max=3599))
|
|
630
|
+
|
|
631
|
+
# Define required fields
|
|
632
|
+
required_fields_list = [
|
|
633
|
+
"process_id",
|
|
634
|
+
"new_process_id",
|
|
635
|
+
"thread_id",
|
|
636
|
+
"target_pid",
|
|
637
|
+
"subject_login_id",
|
|
638
|
+
"user_id",
|
|
639
|
+
"destination_login_id",
|
|
640
|
+
"privilege_list",
|
|
641
|
+
"win_process",
|
|
642
|
+
"src_host",
|
|
643
|
+
"user_name",
|
|
644
|
+
"cmd",
|
|
645
|
+
"source_network_address",
|
|
646
|
+
"local_port",
|
|
647
|
+
"transmitted_services",
|
|
648
|
+
"file_name",
|
|
649
|
+
"src_domain"
|
|
650
|
+
]
|
|
651
|
+
|
|
652
|
+
# Precompute common fields using set_field
|
|
653
|
+
common_fields = {}
|
|
654
|
+
for field in required_fields_list:
|
|
655
|
+
value = None
|
|
656
|
+
if observables and hasattr(observables, field):
|
|
657
|
+
obs_value = getattr(observables, field)
|
|
658
|
+
if obs_value:
|
|
659
|
+
value = random.choice(obs_value) if isinstance(obs_value, list) else obs_value
|
|
660
|
+
if value is None:
|
|
661
|
+
value = Events._set_field(field)
|
|
662
|
+
common_fields[field] = value
|
|
663
|
+
|
|
664
|
+
# Preprocess extra observables not in required fields
|
|
665
|
+
extra_fields = {}
|
|
666
|
+
if observables:
|
|
667
|
+
observables_dict = vars(observables)
|
|
668
|
+
for key, value in observables_dict.items():
|
|
669
|
+
if value and key not in required_fields_list:
|
|
670
|
+
val = random.choice(value) if isinstance(value, list) else value
|
|
671
|
+
extra_fields[key] = val
|
|
672
|
+
|
|
673
|
+
# Generate events
|
|
697
674
|
for i in range(count):
|
|
698
|
-
|
|
675
|
+
# Update datetime for each event
|
|
676
|
+
current_datetime = datetime_iso + timedelta(seconds=i + 1)
|
|
677
|
+
system_time = current_datetime.strftime('%Y-%m-%d %H:%M:%S')
|
|
678
|
+
|
|
679
|
+
# Generate per-event fields
|
|
699
680
|
guid = faker.uuid4()
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
user_name = random.choice(observables.user) if observables and observables.user \
|
|
719
|
-
else faker.user_name()
|
|
720
|
-
cmd = random.choice(observables.win_cmd) if observables and observables.win_cmd \
|
|
721
|
-
else random.choice(WINDOWS_CMD)
|
|
722
|
-
source_network_address = random.choice(observables.local_ip) if observables and observables.local_ip \
|
|
723
|
-
else faker.ipv4_private()
|
|
724
|
-
file_name = random.choice(observables.file_name) if observables and observables.file_name \
|
|
725
|
-
else faker.file_name()
|
|
681
|
+
|
|
682
|
+
# Use event_id from observables if available
|
|
683
|
+
event_record_id = None
|
|
684
|
+
if observables and hasattr(observables, 'event_id') and observables.event_id:
|
|
685
|
+
event_record_id = random.choice(observables.event_id)
|
|
686
|
+
else:
|
|
687
|
+
event_record_id = Events._set_field('event_id')
|
|
688
|
+
|
|
689
|
+
# Prepare event fields
|
|
690
|
+
event_fields = {
|
|
691
|
+
'guid': guid,
|
|
692
|
+
'system_time': system_time,
|
|
693
|
+
'event_record_id': event_record_id,
|
|
694
|
+
**common_fields,
|
|
695
|
+
**extra_fields
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
# Select a random event template
|
|
726
699
|
unformatted_event = random.choice(WIN_EVENTS)
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
domain_name=domain_name, subject_login_id=subject_login_id,
|
|
732
|
-
privilege_list=privilege_list, cmd=cmd,
|
|
733
|
-
destination_login_id=destination_login_id,
|
|
734
|
-
source_network_address=source_network_address, local_port=local_port,
|
|
735
|
-
transmitted_services=transmitted_services, file_name=file_name)
|
|
700
|
+
|
|
701
|
+
# Format the event with all fields
|
|
702
|
+
win_event = unformatted_event.format(**event_fields)
|
|
703
|
+
|
|
736
704
|
winevent_messages.append(win_event)
|
|
705
|
+
|
|
737
706
|
return winevent_messages
|
|
738
707
|
|
|
739
708
|
@classmethod
|
|
740
|
-
def json(
|
|
741
|
-
|
|
742
|
-
|
|
709
|
+
def json(
|
|
710
|
+
cls,
|
|
711
|
+
count: int,
|
|
712
|
+
datetime_iso: Optional[datetime] = None,
|
|
713
|
+
vendor: Optional[str] = None,
|
|
714
|
+
product: Optional[str] = None,
|
|
715
|
+
version: Optional[str] = None,
|
|
716
|
+
observables: Optional['Observables'] = None,
|
|
717
|
+
required_fields: Optional[str] = None
|
|
718
|
+
) -> List[dict]:
|
|
743
719
|
"""
|
|
744
|
-
Generate fake JSON messages representing discovered vulnerabilities.
|
|
745
|
-
|
|
746
|
-
Args:
|
|
747
|
-
count (int): The number of JSON messages to generate.
|
|
748
|
-
datetime_iso: Optional. The starting datetime_iso for the syslog messages. If not provided, a random time during.
|
|
749
|
-
vendor: Optional. The vendor.
|
|
750
|
-
product: Optional. The product value options include:
|
|
751
|
-
- VulnScanner
|
|
752
|
-
version: Optional. The version.
|
|
753
|
-
observables: An observables object. If not provided, random objservable will be generated and used.
|
|
754
|
-
required_fields: Optional. A list of fields that are required to present in the generated data, whether from
|
|
755
|
-
observables or randomely.
|
|
756
|
-
Returns:
|
|
757
|
-
List[Dict[str, Union[str, int]]]: A list of dictionaries representing the generated JSON messages.
|
|
758
|
-
|
|
759
|
-
Example:
|
|
760
|
-
>>> fake_messages = json(5)
|
|
761
|
-
>>> len(fake_messages)
|
|
762
|
-
5
|
|
763
|
-
>>> isinstance(fake_messages[0], dict)
|
|
764
|
-
True
|
|
765
|
-
|
|
720
|
+
Generate optimized fake JSON messages representing discovered vulnerabilities.
|
|
766
721
|
"""
|
|
767
722
|
json_messages = []
|
|
768
|
-
faker =
|
|
723
|
+
faker = Events.faker
|
|
724
|
+
|
|
725
|
+
# Precompute vendor, product, and version details
|
|
769
726
|
vendor = vendor or faker.company()
|
|
727
|
+
product = product or "UnknownProduct"
|
|
770
728
|
version = version or faker.numerify("1.0.#")
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
if
|
|
775
|
-
if product == "VulnScanner"
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
729
|
+
|
|
730
|
+
# Set initial datetime and precompute required fields if not provided
|
|
731
|
+
datetime_iso = datetime_iso or datetime.now() - timedelta(hours=1)
|
|
732
|
+
required_fields_list = required_fields.split(",") if required_fields else (
|
|
733
|
+
["cve_id", "host", "file_hash"] if product == "VulnScanner" else ["user", "host"]
|
|
734
|
+
)
|
|
735
|
+
|
|
736
|
+
# Precompute static fields
|
|
737
|
+
severity = Events._set_field("severity")
|
|
738
|
+
common_fields = {}
|
|
739
|
+
for field in required_fields_list:
|
|
740
|
+
value = None
|
|
741
|
+
if observables and hasattr(observables, field):
|
|
742
|
+
obs_value = getattr(observables, field)
|
|
743
|
+
if obs_value:
|
|
744
|
+
if isinstance(obs_value, list):
|
|
745
|
+
value = random.choice(obs_value)
|
|
746
|
+
else:
|
|
747
|
+
value = obs_value
|
|
748
|
+
if value is None:
|
|
749
|
+
value = Events._set_field(field)
|
|
750
|
+
common_fields[field] = value
|
|
751
|
+
|
|
752
|
+
# Preprocess additional observables not in required_fields
|
|
753
|
+
extra_fields = {}
|
|
754
|
+
if observables:
|
|
755
|
+
observables_dict = vars(observables)
|
|
756
|
+
for key, value in observables_dict.items():
|
|
757
|
+
if value and key not in required_fields_list:
|
|
758
|
+
val = random.choice(value) if isinstance(value, list) else value
|
|
759
|
+
extra_fields[key] = val
|
|
760
|
+
|
|
761
|
+
# Loop to generate JSON events
|
|
779
762
|
for i in range(count):
|
|
780
|
-
|
|
763
|
+
# Adjust datetime for each message
|
|
764
|
+
current_datetime = datetime_iso + timedelta(seconds=i)
|
|
765
|
+
|
|
766
|
+
# Initialize event with static fields
|
|
781
767
|
event = {
|
|
782
768
|
'vendor': vendor,
|
|
783
769
|
'product': product,
|
|
784
770
|
'version': version,
|
|
785
|
-
'datetime_iso':
|
|
786
|
-
'severity':
|
|
771
|
+
'datetime_iso': current_datetime.strftime("%Y-%m-%d %H:%M:%S"),
|
|
772
|
+
'severity': severity,
|
|
773
|
+
**common_fields,
|
|
774
|
+
**extra_fields
|
|
787
775
|
}
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
if observables:
|
|
791
|
-
for observable, observable_value in vars(observables).items():
|
|
792
|
-
if observable_value and observable not in required_fields.split(","):
|
|
793
|
-
event[observable] = random.choice(observable_value)
|
|
776
|
+
|
|
777
|
+
# Append generated event to the list
|
|
794
778
|
json_messages.append(event)
|
|
779
|
+
|
|
795
780
|
return json_messages
|
|
796
781
|
|
|
797
782
|
@classmethod
|
|
798
783
|
def incidents(cls, count, fields: Optional[str] = None, datetime_iso: Optional[datetime] = None,
|
|
799
|
-
|
|
800
|
-
|
|
784
|
+
vendor: Optional[str] = None, product: Optional[str] = None, version: Optional[str] = None,
|
|
785
|
+
observables: Optional[Observables] = None, required_fields: Optional[str] = None) -> List[dict]:
|
|
801
786
|
"""
|
|
802
787
|
Generates a list of fake incident data.
|
|
803
788
|
|
|
804
789
|
Args:
|
|
805
790
|
count (int): The number of incidents to generate.
|
|
806
|
-
fields (str, optional):
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
version: Optional. The version.
|
|
812
|
-
datetime_iso: Optional. The starting datetime_iso for the syslog messages. If not provided, a random time during
|
|
813
|
-
observables: An observables object. If not provided, random objservable will be generated and used.
|
|
814
|
-
required_fields: Optional. A list of fields that are required to present in the generated data, whether from
|
|
815
|
-
observables or randomely.
|
|
791
|
+
fields (str, optional): Comma-separated incident fields to include. If None, all fields are included.
|
|
792
|
+
vendor, product, version (Optional[str]): Details about the event source.
|
|
793
|
+
datetime_iso (Optional[datetime]): Base timestamp for the incidents.
|
|
794
|
+
observables (Optional[Observables]): Optional observables object to provide values.
|
|
795
|
+
required_fields (Optional[str]): Required fields for the events.
|
|
816
796
|
|
|
817
797
|
Returns:
|
|
818
|
-
List[Dict]: A list of incident dictionaries.
|
|
819
|
-
- 'id' (int): A unique identifier for the incident.
|
|
820
|
-
- 'type' (str): The type of incident.
|
|
821
|
-
- 'duration' (int): The duration of the incident in hours.
|
|
822
|
-
- 'analyst' (str): The name of the analyst assigned to the incident.
|
|
823
|
-
- 'severity' (str, optional): The severity of the incident. Only included if 'severity' is specified
|
|
824
|
-
in the 'fields' argument.
|
|
825
|
-
- 'description' (str, optional): A brief description of the incident. Only included if 'description' is
|
|
826
|
-
specified in the 'fields' argument.
|
|
827
|
-
- 'events' (List[Dict], optional): A list of event dictionaries associated with the incident.
|
|
828
|
-
|
|
829
|
-
Example:
|
|
830
|
-
>>> incidents(count=3, fields='id,type,severity')
|
|
831
|
-
[
|
|
832
|
-
{'id': 1, 'type': 'Lateral Movement', 'severity': 'Critical'},
|
|
833
|
-
{'id': 2, 'type': 'Access Violation', 'severity': 'High'},
|
|
834
|
-
{'id': 3, 'type': 'Account Compromised', 'severity': 'Low'}
|
|
835
|
-
]
|
|
798
|
+
List[Dict]: A list of incident dictionaries.
|
|
836
799
|
"""
|
|
837
800
|
incidents = []
|
|
838
|
-
faker =
|
|
801
|
+
faker = Events.faker
|
|
802
|
+
datetime_iso = datetime_iso or datetime.now() - timedelta(hours=1)
|
|
803
|
+
|
|
804
|
+
# Generate analyst list if not provided in observables
|
|
805
|
+
incident_types = observables.incident_types if observables and observables.incident_types else INCIDENTS_TYPES
|
|
806
|
+
analysts = observables.analysts if observables and observables.analysts else [faker.unique.first_name() for _ in range(10)]
|
|
839
807
|
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
incident_types = observables.incident_types if observables and observables.incident_types \
|
|
843
|
-
else INCIDENTS_TYPES
|
|
844
|
-
analysts = observables.analysts if observables and observables.analysts \
|
|
845
|
-
else [faker.unique.first_name() for _ in range(10)]
|
|
846
|
-
analyst_incident_map = {}
|
|
847
|
-
for analyst in analysts:
|
|
848
|
-
mapped_incident_type = incident_types.pop(0)
|
|
849
|
-
analyst_incident_map[analyst] = mapped_incident_type
|
|
850
|
-
incident_types.append(mapped_incident_type)
|
|
808
|
+
incident_type_cycle = itertools.cycle(incident_types)
|
|
851
809
|
for i in range(count):
|
|
852
|
-
|
|
810
|
+
incident_id = i + 1 # Simplify unique ID generation
|
|
853
811
|
duration = random.randint(1, 5)
|
|
854
|
-
|
|
855
|
-
incident_id = random.randint(1, count)
|
|
856
|
-
if incident_id not in incident_ids:
|
|
857
|
-
incident_ids.add(incident_id)
|
|
858
|
-
break
|
|
859
|
-
incident_type = random.choice(incident_types)
|
|
812
|
+
incident_type = next(incident_type_cycle)
|
|
860
813
|
analyst = random.choice(analysts)
|
|
861
|
-
severity =
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
version=version, observables=observables, required_fields=required_fields)[0]},
|
|
891
|
-
{"event": cls.winevent(count=1, datetime_iso=datetime_iso, observables=observables)[0]},
|
|
892
|
-
{"event": cls.json(count=1, datetime_iso=datetime_iso, vendor=vendor, product=product,
|
|
893
|
-
version=version, observables=observables,
|
|
894
|
-
required_fields=required_fields)[0]}
|
|
895
|
-
]
|
|
896
|
-
else:
|
|
897
|
-
incident = {
|
|
898
|
-
"id": incident_id,
|
|
899
|
-
"type": incident_type,
|
|
900
|
-
"duration": duration,
|
|
901
|
-
"analyst": analyst
|
|
902
|
-
}
|
|
814
|
+
severity = Events._set_field('severity', observables) or faker.random_int(min=1, max=5)
|
|
815
|
+
description = Events._set_field('terms', observables) or faker.sentence(nb_words=10)
|
|
816
|
+
|
|
817
|
+
# Add base fields
|
|
818
|
+
incident = {}
|
|
819
|
+
field_list = fields.split(',') if fields else ['id', 'duration', 'type', 'analyst', 'severity', 'description', 'events']
|
|
820
|
+
if 'id' in field_list:
|
|
821
|
+
incident['id'] = incident_id
|
|
822
|
+
if 'duration' in field_list:
|
|
823
|
+
incident['duration'] = duration
|
|
824
|
+
if 'type' in field_list:
|
|
825
|
+
incident['type'] = incident_type
|
|
826
|
+
if 'analyst' in field_list:
|
|
827
|
+
incident['analyst'] = analyst
|
|
828
|
+
if 'severity' in field_list:
|
|
829
|
+
incident['severity'] = severity
|
|
830
|
+
if 'description' in field_list:
|
|
831
|
+
incident['description'] = description
|
|
832
|
+
|
|
833
|
+
# Generate associated events for each incident
|
|
834
|
+
if 'events' in field_list:
|
|
835
|
+
incident['events'] = [
|
|
836
|
+
{"event": cls.syslog(count=1, datetime_iso=datetime_iso, observables=observables, required_fields=required_fields)[0]},
|
|
837
|
+
{"event": cls.cef(count=1, datetime_iso=datetime_iso, vendor=vendor, product=product, version=version, observables=observables, required_fields=required_fields)[0]},
|
|
838
|
+
{"event": cls.leef(count=1, datetime_iso=datetime_iso, vendor=vendor, product=product, version=version, observables=observables, required_fields=required_fields)[0]},
|
|
839
|
+
{"event": cls.winevent(count=1, datetime_iso=datetime_iso, observables=observables)[0]},
|
|
840
|
+
{"event": cls.json(count=1, datetime_iso=datetime_iso, vendor=vendor, product=product, version=version, observables=observables, required_fields=required_fields)[0]}
|
|
841
|
+
]
|
|
842
|
+
|
|
903
843
|
incidents.append(incident)
|
|
844
|
+
|
|
904
845
|
return incidents
|