rosetta-ce 1.6.9__py3-none-any.whl → 1.7.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.
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 +528 -554
- {rosetta_ce-1.6.9.dist-info → rosetta_ce-1.7.1.dist-info}/METADATA +1 -1
- {rosetta_ce-1.6.9.dist-info → rosetta_ce-1.7.1.dist-info}/RECORD +7 -7
- {rosetta_ce-1.6.9.dist-info → rosetta_ce-1.7.1.dist-info}/WHEEL +1 -1
- {rosetta_ce-1.6.9.dist-info → rosetta_ce-1.7.1.dist-info}/LICENSE +0 -0
- {rosetta_ce-1.6.9.dist-info → rosetta_ce-1.7.1.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,606 @@ 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.
|
|
404
|
+
Generate fake syslog messages with per-message randomization.
|
|
506
405
|
|
|
507
406
|
Args:
|
|
508
|
-
count:
|
|
509
|
-
datetime_iso
|
|
510
|
-
|
|
511
|
-
|
|
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 /']
|
|
407
|
+
count (int): Number of syslog messages to generate.
|
|
408
|
+
datetime_iso (Optional[datetime]): Starting datetime for the messages.
|
|
409
|
+
observables (Optional[Observables]): Observables object with predefined values.
|
|
410
|
+
required_fields (Optional[str]): Comma-separated string of required fields.
|
|
525
411
|
|
|
412
|
+
Returns:
|
|
413
|
+
List[str]: A list of generated syslog messages.
|
|
526
414
|
"""
|
|
527
415
|
syslog_messages = []
|
|
528
|
-
faker =
|
|
416
|
+
faker = Events.faker
|
|
417
|
+
|
|
418
|
+
# Predefine default datetime if not provided
|
|
529
419
|
if datetime_iso is None:
|
|
530
420
|
datetime_iso = datetime.now() - timedelta(hours=1)
|
|
531
421
|
datetime_iso += timedelta(seconds=faker.random_int(min=0, max=3599))
|
|
532
|
-
if not required_fields:
|
|
533
|
-
required_fields = "pid,host,user,unix_process,unix_cmd"
|
|
534
|
-
for i in range(count):
|
|
535
|
-
datetime_iso += timedelta(seconds=1)
|
|
536
|
-
syslog_message = f"{datetime_iso.strftime('%Y-%m-%d %H:%M:%S')}"
|
|
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
|
|
545
422
|
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
"""
|
|
551
|
-
Generates fake CEF (Common Event Format) messages.
|
|
423
|
+
# Set default required fields
|
|
424
|
+
required_fields_list = required_fields.split(",") if required_fields else [
|
|
425
|
+
"pid", "host", "user", "unix_process", "unix_cmd"
|
|
426
|
+
]
|
|
552
427
|
|
|
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.
|
|
428
|
+
# Convert observables to a dictionary for easy access
|
|
429
|
+
observables_dict = vars(observables) if observables else {}
|
|
567
430
|
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
431
|
+
# Precompute constant fields (if any)
|
|
432
|
+
# For syslog, most fields may vary per message, so we may not have many constants
|
|
433
|
+
constant_fields = {}
|
|
434
|
+
|
|
435
|
+
# Generate syslog messages
|
|
436
|
+
for i in range(count):
|
|
437
|
+
# Update datetime for each log
|
|
438
|
+
current_time = (datetime_iso + timedelta(seconds=i + 1)).strftime('%b %d %H:%M:%S')
|
|
439
|
+
|
|
440
|
+
# Generate required fields per message
|
|
441
|
+
event_fields = {}
|
|
442
|
+
for field in required_fields_list:
|
|
443
|
+
value = None
|
|
444
|
+
if field in observables_dict and observables_dict[field]:
|
|
445
|
+
obs_value = observables_dict[field]
|
|
446
|
+
value = random.choice(obs_value) if isinstance(obs_value, list) else obs_value
|
|
447
|
+
else:
|
|
448
|
+
value = Events._set_field(field)
|
|
449
|
+
event_fields[field] = value
|
|
450
|
+
|
|
451
|
+
# Generate extra fields per message
|
|
452
|
+
extra_fields = []
|
|
453
|
+
for key, value in observables_dict.items():
|
|
454
|
+
if value and key not in required_fields_list:
|
|
455
|
+
val = random.choice(value) if isinstance(value, list) else value
|
|
456
|
+
extra_fields.append(str(val))
|
|
457
|
+
|
|
458
|
+
# Build the syslog message
|
|
459
|
+
syslog_message_parts = [f"{current_time}"]
|
|
460
|
+
|
|
461
|
+
# Insert required fields
|
|
462
|
+
syslog_message_parts.extend(str(event_fields[field]) for field in required_fields_list)
|
|
463
|
+
|
|
464
|
+
# Append additional observables not in required fields
|
|
465
|
+
syslog_message_parts.extend(extra_fields)
|
|
466
|
+
|
|
467
|
+
syslog_messages.append(" ".join(syslog_message_parts))
|
|
468
|
+
|
|
469
|
+
return syslog_messages
|
|
470
|
+
|
|
471
|
+
@classmethod
|
|
472
|
+
def cef(
|
|
473
|
+
cls,
|
|
474
|
+
count: int,
|
|
475
|
+
vendor: Optional[str] = None,
|
|
476
|
+
product: Optional[str] = None,
|
|
477
|
+
version: Optional[str] = None,
|
|
478
|
+
datetime_iso: Optional[datetime] = None,
|
|
479
|
+
observables: Optional['Observables'] = None,
|
|
480
|
+
required_fields: Optional[str] = None
|
|
481
|
+
) -> List[str]:
|
|
583
482
|
cef_messages = []
|
|
584
|
-
faker =
|
|
483
|
+
faker = Events.faker
|
|
585
484
|
vendor = vendor or faker.company()
|
|
485
|
+
product = product or faker.word()
|
|
586
486
|
version = version or faker.numerify("1.0.#")
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
"attachment_hash,spam_score,action"
|
|
597
|
-
else:
|
|
598
|
-
required_fields = "local_ip,local_port,remote_ip,remote_port,protocol,rule_id,action"
|
|
487
|
+
datetime_iso = datetime_iso or datetime.now() - timedelta(hours=1)
|
|
488
|
+
required_fields_list = required_fields.split(",") if required_fields else [
|
|
489
|
+
"local_ip", "local_port", "remote_ip", "remote_port", "protocol", "rule_id", "action"
|
|
490
|
+
]
|
|
491
|
+
|
|
492
|
+
# Convert observables to a dictionary for easy access
|
|
493
|
+
observables_dict = vars(observables) if observables else {}
|
|
494
|
+
|
|
495
|
+
# Generate events
|
|
599
496
|
for i in range(count):
|
|
600
|
-
datetime_iso
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
497
|
+
current_datetime = datetime_iso + timedelta(seconds=i)
|
|
498
|
+
log_id = faker.uuid4()
|
|
499
|
+
severity = 'low' # Or generate per message if needed
|
|
500
|
+
|
|
501
|
+
# Generate field values per message
|
|
502
|
+
event_fields = {}
|
|
503
|
+
for field in required_fields_list:
|
|
504
|
+
value = None
|
|
505
|
+
if field in observables_dict and observables_dict[field]:
|
|
506
|
+
obs_value = observables_dict[field]
|
|
507
|
+
if isinstance(obs_value, list):
|
|
508
|
+
value = random.choice(obs_value)
|
|
509
|
+
else:
|
|
510
|
+
value = obs_value
|
|
511
|
+
else:
|
|
512
|
+
value = Events._set_field(field)
|
|
513
|
+
event_fields[field] = value
|
|
514
|
+
|
|
515
|
+
# Generate extra fields per message
|
|
516
|
+
extra_fields = []
|
|
517
|
+
for key, value in observables_dict.items():
|
|
518
|
+
if value and key not in required_fields_list:
|
|
519
|
+
val = random.choice(value) if isinstance(value, list) else value
|
|
520
|
+
extra_fields.append(f"{key}={val}")
|
|
521
|
+
|
|
522
|
+
extra_fields_str = " " + " ".join(extra_fields) if extra_fields else ""
|
|
523
|
+
|
|
524
|
+
# Build the CEF message
|
|
525
|
+
cef_message = (
|
|
526
|
+
f"CEF:0|{vendor}|{product}|{version}|{log_id}|{current_datetime.strftime('%Y-%m-%dT%H:%M:%S.%fZ')}|{severity}|"
|
|
527
|
+
+ " ".join([f"{field}={event_fields[field]}" for field in required_fields_list])
|
|
528
|
+
)
|
|
529
|
+
cef_message += extra_fields_str
|
|
609
530
|
cef_messages.append(cef_message)
|
|
610
|
-
return cef_messages
|
|
611
531
|
|
|
532
|
+
return cef_messages
|
|
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 with per-message randomization.
|
|
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.#")
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
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
|
+
# Convert observables to a dictionary for easy access
|
|
561
|
+
observables_dict = vars(observables) if observables else {}
|
|
562
|
+
|
|
563
|
+
# Precompute constant fields
|
|
564
|
+
# Event ID and severity might change per event; move inside the loop if needed
|
|
565
|
+
constant_fields = {
|
|
566
|
+
'vendor': vendor,
|
|
567
|
+
'product': product,
|
|
568
|
+
'version': version,
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
# Generate messages
|
|
661
572
|
for i in range(count):
|
|
662
|
-
datetime_iso
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
573
|
+
current_datetime = (datetime_iso + timedelta(seconds=i)).strftime('%b %d %H:%M:%S')
|
|
574
|
+
|
|
575
|
+
# Generate per-message fields
|
|
576
|
+
# Event ID and severity could be variable
|
|
577
|
+
event_id = Events._set_field("event_id")
|
|
578
|
+
severity = Events._set_field("severity")
|
|
579
|
+
|
|
580
|
+
# Generate required fields per message
|
|
581
|
+
event_fields = {}
|
|
582
|
+
for field in required_fields_list:
|
|
583
|
+
value = None
|
|
584
|
+
if field in observables_dict and observables_dict[field]:
|
|
585
|
+
obs_value = observables_dict[field]
|
|
586
|
+
value = random.choice(obs_value) if isinstance(obs_value, list) else obs_value
|
|
587
|
+
else:
|
|
588
|
+
value = Events._set_field(field)
|
|
589
|
+
event_fields[field] = value
|
|
590
|
+
|
|
591
|
+
# Generate extra fields per message
|
|
592
|
+
extra_fields = []
|
|
593
|
+
for key, value in observables_dict.items():
|
|
594
|
+
if value and key not in required_fields_list:
|
|
595
|
+
val = random.choice(value) if isinstance(value, list) else value
|
|
596
|
+
extra_fields.append(f" {key}={val}")
|
|
597
|
+
|
|
598
|
+
# Build the LEEF message
|
|
599
|
+
leef_message = (
|
|
600
|
+
f"LEEF:1.0|{constant_fields['vendor']}|{constant_fields['product']}|{constant_fields['version']}|{event_id}|"
|
|
601
|
+
f"severity={severity} devTime={current_datetime}"
|
|
602
|
+
+ "".join(f" {field}={event_fields[field]}" for field in required_fields_list)
|
|
603
|
+
+ "".join(extra_fields)
|
|
604
|
+
)
|
|
605
|
+
|
|
671
606
|
leef_messages.append(leef_message)
|
|
607
|
+
|
|
672
608
|
return leef_messages
|
|
673
609
|
|
|
610
|
+
|
|
674
611
|
@classmethod
|
|
675
|
-
def winevent(
|
|
676
|
-
|
|
612
|
+
def winevent(
|
|
613
|
+
cls,
|
|
614
|
+
count: int,
|
|
615
|
+
datetime_iso: Optional[datetime] = None,
|
|
616
|
+
observables: Optional['Observables'] = None
|
|
617
|
+
) -> List[str]:
|
|
677
618
|
"""
|
|
678
|
-
Generates fake Windows Event Log messages.
|
|
619
|
+
Generates fake Windows Event Log messages with per-message randomization.
|
|
679
620
|
|
|
680
621
|
Args:
|
|
681
622
|
count (int): The number of fake messages to generate.
|
|
682
|
-
datetime_iso
|
|
683
|
-
observables: An observables object
|
|
623
|
+
datetime_iso (Optional[datetime]): The starting datetime for the messages.
|
|
624
|
+
observables (Optional[Observables]): An observables object with predefined values.
|
|
684
625
|
|
|
685
626
|
Returns:
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
Examples:
|
|
689
|
-
>>> Events.winevent(1)
|
|
690
|
-
['<Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">...</Event>', ...]
|
|
627
|
+
List[str]: A list of fake Windows Event Log messages.
|
|
691
628
|
"""
|
|
692
629
|
winevent_messages = []
|
|
693
|
-
faker =
|
|
630
|
+
faker = Events.faker
|
|
631
|
+
|
|
632
|
+
# Set starting datetime if not provided
|
|
694
633
|
if datetime_iso is None:
|
|
695
634
|
datetime_iso = datetime.now() - timedelta(hours=1)
|
|
696
635
|
datetime_iso += timedelta(seconds=faker.random_int(min=0, max=3599))
|
|
636
|
+
|
|
637
|
+
# Define required fields
|
|
638
|
+
required_fields_list = [
|
|
639
|
+
"process_id",
|
|
640
|
+
"new_process_id",
|
|
641
|
+
"thread_id",
|
|
642
|
+
"target_pid",
|
|
643
|
+
"subject_login_id",
|
|
644
|
+
"user_id",
|
|
645
|
+
"destination_login_id",
|
|
646
|
+
"privilege_list",
|
|
647
|
+
"win_process",
|
|
648
|
+
"src_host",
|
|
649
|
+
"user_name",
|
|
650
|
+
"cmd",
|
|
651
|
+
"source_network_address",
|
|
652
|
+
"local_port",
|
|
653
|
+
"transmitted_services",
|
|
654
|
+
"file_name",
|
|
655
|
+
"src_domain"
|
|
656
|
+
]
|
|
657
|
+
|
|
658
|
+
# Convert observables to a dictionary for easy access
|
|
659
|
+
observables_dict = vars(observables) if observables else {}
|
|
660
|
+
|
|
661
|
+
# Precompute constant fields (if any)
|
|
662
|
+
constant_fields = {
|
|
663
|
+
# Add any fields that are constant across events
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
# Generate events
|
|
697
667
|
for i in range(count):
|
|
698
|
-
|
|
668
|
+
# Update datetime for each event
|
|
669
|
+
current_datetime = datetime_iso + timedelta(seconds=i + 1)
|
|
670
|
+
system_time = current_datetime.strftime('%Y-%m-%d %H:%M:%S')
|
|
671
|
+
|
|
672
|
+
# Generate per-event fields
|
|
673
|
+
event_fields = {}
|
|
674
|
+
|
|
675
|
+
# Generate required fields per message
|
|
676
|
+
for field in required_fields_list:
|
|
677
|
+
value = None
|
|
678
|
+
if field in observables_dict and observables_dict[field]:
|
|
679
|
+
obs_value = observables_dict[field]
|
|
680
|
+
value = random.choice(obs_value) if isinstance(obs_value, list) else obs_value
|
|
681
|
+
else:
|
|
682
|
+
value = Events._set_field(field)
|
|
683
|
+
event_fields[field] = value
|
|
684
|
+
|
|
685
|
+
# Generate extra fields per message
|
|
686
|
+
for key, value in observables_dict.items():
|
|
687
|
+
if value and key not in required_fields_list:
|
|
688
|
+
val = random.choice(value) if isinstance(value, list) else value
|
|
689
|
+
event_fields[key] = val
|
|
690
|
+
|
|
691
|
+
# Generate per-event fields that are not in observables
|
|
699
692
|
guid = faker.uuid4()
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
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()
|
|
693
|
+
|
|
694
|
+
# Use event_id from observables if available
|
|
695
|
+
if 'event_id' in observables_dict and observables_dict['event_id']:
|
|
696
|
+
event_record_id = (
|
|
697
|
+
random.choice(observables_dict['event_id'])
|
|
698
|
+
if isinstance(observables_dict['event_id'], list)
|
|
699
|
+
else observables_dict['event_id']
|
|
700
|
+
)
|
|
701
|
+
else:
|
|
702
|
+
event_record_id = Events._set_field('event_id')
|
|
703
|
+
|
|
704
|
+
# Prepare event fields
|
|
705
|
+
event_fields.update({
|
|
706
|
+
'guid': guid,
|
|
707
|
+
'system_time': system_time,
|
|
708
|
+
'event_record_id': event_record_id,
|
|
709
|
+
})
|
|
710
|
+
|
|
711
|
+
# Combine with any constant fields
|
|
712
|
+
event_fields.update(constant_fields)
|
|
713
|
+
|
|
714
|
+
# Select a random event template
|
|
726
715
|
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)
|
|
716
|
+
|
|
717
|
+
# Format the event with all fields
|
|
718
|
+
win_event = unformatted_event.format(**event_fields)
|
|
719
|
+
|
|
736
720
|
winevent_messages.append(win_event)
|
|
737
|
-
return winevent_messages
|
|
738
721
|
|
|
722
|
+
return winevent_messages
|
|
723
|
+
|
|
739
724
|
@classmethod
|
|
740
|
-
def json(
|
|
741
|
-
|
|
742
|
-
|
|
725
|
+
def json(
|
|
726
|
+
cls,
|
|
727
|
+
count: int,
|
|
728
|
+
datetime_iso: Optional[datetime] = None,
|
|
729
|
+
vendor: Optional[str] = None,
|
|
730
|
+
product: Optional[str] = None,
|
|
731
|
+
version: Optional[str] = None,
|
|
732
|
+
observables: Optional['Observables'] = None,
|
|
733
|
+
required_fields: Optional[str] = None
|
|
734
|
+
) -> List[dict]:
|
|
743
735
|
"""
|
|
744
|
-
Generate fake JSON messages representing discovered vulnerabilities.
|
|
736
|
+
Generate fake JSON messages representing discovered vulnerabilities with per-message randomization.
|
|
745
737
|
|
|
746
738
|
Args:
|
|
747
|
-
count (int):
|
|
748
|
-
datetime_iso
|
|
749
|
-
vendor
|
|
750
|
-
product
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
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
|
|
739
|
+
count (int): Number of JSON messages to generate.
|
|
740
|
+
datetime_iso (Optional[datetime]): Starting datetime for the messages.
|
|
741
|
+
vendor (Optional[str]): Vendor name.
|
|
742
|
+
product (Optional[str]): Product name.
|
|
743
|
+
version (Optional[str]): Product version.
|
|
744
|
+
observables (Optional[Observables]): Observables object with predefined values.
|
|
745
|
+
required_fields (Optional[str]): Comma-separated string of required fields.
|
|
765
746
|
|
|
747
|
+
Returns:
|
|
748
|
+
List[dict]: A list of generated JSON messages.
|
|
766
749
|
"""
|
|
767
750
|
json_messages = []
|
|
768
|
-
faker =
|
|
751
|
+
faker = Events.faker
|
|
752
|
+
|
|
753
|
+
# Precompute vendor, product, and version details
|
|
769
754
|
vendor = vendor or faker.company()
|
|
755
|
+
product = product or "UnknownProduct"
|
|
770
756
|
version = version or faker.numerify("1.0.#")
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
757
|
+
|
|
758
|
+
# Set initial datetime
|
|
759
|
+
datetime_iso = datetime_iso or datetime.now() - timedelta(hours=1)
|
|
760
|
+
|
|
761
|
+
# Set required fields
|
|
762
|
+
if required_fields:
|
|
763
|
+
required_fields_list = required_fields.split(",")
|
|
764
|
+
else:
|
|
765
|
+
required_fields_list = (
|
|
766
|
+
["cve_id", "host", "file_hash"] if product == "VulnScanner" else ["user", "host"]
|
|
767
|
+
)
|
|
768
|
+
|
|
769
|
+
# Convert observables to a dictionary for easy access
|
|
770
|
+
observables_dict = vars(observables) if observables else {}
|
|
771
|
+
|
|
772
|
+
# Precompute constant fields
|
|
773
|
+
constant_fields = {
|
|
774
|
+
'vendor': vendor,
|
|
775
|
+
'product': product,
|
|
776
|
+
'version': version,
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
# Generate JSON events
|
|
779
780
|
for i in range(count):
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
'
|
|
781
|
+
# Adjust datetime for each message
|
|
782
|
+
current_datetime = datetime_iso + timedelta(seconds=i)
|
|
783
|
+
datetime_str = current_datetime.strftime("%Y-%m-%d %H:%M:%S")
|
|
784
|
+
|
|
785
|
+
# Generate variable fields per message
|
|
786
|
+
event_fields = {
|
|
787
|
+
'datetime_iso': datetime_str,
|
|
788
|
+
'severity': Events._set_field('severity'),
|
|
787
789
|
}
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
790
|
+
|
|
791
|
+
# Generate required fields per message
|
|
792
|
+
for field in required_fields_list:
|
|
793
|
+
value = None
|
|
794
|
+
if field in observables_dict and observables_dict[field]:
|
|
795
|
+
obs_value = observables_dict[field]
|
|
796
|
+
value = random.choice(obs_value) if isinstance(obs_value, list) else obs_value
|
|
797
|
+
else:
|
|
798
|
+
value = Events._set_field(field)
|
|
799
|
+
event_fields[field] = value
|
|
800
|
+
|
|
801
|
+
# Include additional observables not in required fields
|
|
802
|
+
for key, value in observables_dict.items():
|
|
803
|
+
if value and key not in required_fields_list:
|
|
804
|
+
val = random.choice(value) if isinstance(value, list) else value
|
|
805
|
+
event_fields[key] = val
|
|
806
|
+
|
|
807
|
+
# Combine all fields into the event
|
|
808
|
+
event = {**constant_fields, **event_fields}
|
|
809
|
+
|
|
810
|
+
# Append generated event to the list
|
|
794
811
|
json_messages.append(event)
|
|
812
|
+
|
|
795
813
|
return json_messages
|
|
796
814
|
|
|
797
815
|
@classmethod
|
|
798
816
|
def incidents(cls, count, fields: Optional[str] = None, datetime_iso: Optional[datetime] = None,
|
|
799
|
-
|
|
800
|
-
|
|
817
|
+
vendor: Optional[str] = None, product: Optional[str] = None, version: Optional[str] = None,
|
|
818
|
+
observables: Optional[Observables] = None, required_fields: Optional[str] = None) -> List[dict]:
|
|
801
819
|
"""
|
|
802
820
|
Generates a list of fake incident data.
|
|
803
821
|
|
|
804
822
|
Args:
|
|
805
823
|
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.
|
|
824
|
+
fields (str, optional): Comma-separated incident fields to include. If None, all fields are included.
|
|
825
|
+
vendor, product, version (Optional[str]): Details about the event source.
|
|
826
|
+
datetime_iso (Optional[datetime]): Base timestamp for the incidents.
|
|
827
|
+
observables (Optional[Observables]): Optional observables object to provide values.
|
|
828
|
+
required_fields (Optional[str]): Required fields for the events.
|
|
816
829
|
|
|
817
830
|
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
|
-
]
|
|
831
|
+
List[Dict]: A list of incident dictionaries.
|
|
836
832
|
"""
|
|
837
833
|
incidents = []
|
|
838
|
-
faker =
|
|
834
|
+
faker = Events.faker
|
|
835
|
+
datetime_iso = datetime_iso or datetime.now() - timedelta(hours=1)
|
|
836
|
+
|
|
837
|
+
# Generate analyst list if not provided in observables
|
|
838
|
+
incident_types = observables.incident_types if observables and observables.incident_types else INCIDENTS_TYPES
|
|
839
|
+
analysts = observables.analysts if observables and observables.analysts else [faker.unique.first_name() for _ in range(10)]
|
|
839
840
|
|
|
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)
|
|
841
|
+
incident_type_cycle = itertools.cycle(incident_types)
|
|
851
842
|
for i in range(count):
|
|
852
|
-
|
|
843
|
+
incident_id = i + 1 # Simplify unique ID generation
|
|
853
844
|
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)
|
|
845
|
+
incident_type = next(incident_type_cycle)
|
|
860
846
|
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
|
-
}
|
|
847
|
+
severity = Events._set_field('severity', observables) or faker.random_int(min=1, max=5)
|
|
848
|
+
description = Events._set_field('terms', observables) or faker.sentence(nb_words=10)
|
|
849
|
+
|
|
850
|
+
# Add base fields
|
|
851
|
+
incident = {}
|
|
852
|
+
field_list = fields.split(',') if fields else ['id', 'duration', 'type', 'analyst', 'severity', 'description', 'events']
|
|
853
|
+
if 'id' in field_list:
|
|
854
|
+
incident['id'] = incident_id
|
|
855
|
+
if 'duration' in field_list:
|
|
856
|
+
incident['duration'] = duration
|
|
857
|
+
if 'type' in field_list:
|
|
858
|
+
incident['type'] = incident_type
|
|
859
|
+
if 'analyst' in field_list:
|
|
860
|
+
incident['analyst'] = analyst
|
|
861
|
+
if 'severity' in field_list:
|
|
862
|
+
incident['severity'] = severity
|
|
863
|
+
if 'description' in field_list:
|
|
864
|
+
incident['description'] = description
|
|
865
|
+
|
|
866
|
+
# Generate associated events for each incident
|
|
867
|
+
if 'events' in field_list:
|
|
868
|
+
incident['events'] = [
|
|
869
|
+
{"event": cls.syslog(count=1, datetime_iso=datetime_iso, observables=observables, required_fields=required_fields)[0]},
|
|
870
|
+
{"event": cls.cef(count=1, datetime_iso=datetime_iso, vendor=vendor, product=product, version=version, observables=observables, required_fields=required_fields)[0]},
|
|
871
|
+
{"event": cls.leef(count=1, datetime_iso=datetime_iso, vendor=vendor, product=product, version=version, observables=observables, required_fields=required_fields)[0]},
|
|
872
|
+
{"event": cls.winevent(count=1, datetime_iso=datetime_iso, observables=observables)[0]},
|
|
873
|
+
{"event": cls.json(count=1, datetime_iso=datetime_iso, vendor=vendor, product=product, version=version, observables=observables, required_fields=required_fields)[0]}
|
|
874
|
+
]
|
|
875
|
+
|
|
903
876
|
incidents.append(incident)
|
|
877
|
+
|
|
904
878
|
return incidents
|