rosetta-ce 1.6.8__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/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
- if observable_type == ObservableType.IP and known == ObservableKnown.GOOD:
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
- if observable_type == ObservableType.URL and known == ObservableKnown.BAD:
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
- if observable_type == ObservableType.URL and known == ObservableKnown.GOOD:
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
- if observable_type == ObservableType.SHA256 and known == ObservableKnown.BAD:
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
- if observable_type == ObservableType.SHA256 and known == ObservableKnown.GOOD:
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
- if observable_type == ObservableType.CVE:
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
- if observable_type == ObservableType.TERMS:
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,612 +273,573 @@ class Observables:
272
273
 
273
274
  class Events:
274
275
 
275
- @staticmethod
276
- def _create_faker():
277
- """
278
- Returns:
279
- Faker instance.
280
- """
281
- return Faker()
276
+ faker = Faker()
277
+ field_timings = {}
282
278
 
283
279
  @staticmethod
284
- def _create_generator():
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 == "severity":
323
- field_value = random.choice(observables.severity) if observables and observables.severity \
324
- else random.choice(SEVERITIES)
325
- if field == "local_ip":
326
- field_value = random.choice(observables.local_ip) if observables and observables.local_ip \
327
- else faker.ipv4()
328
- if field == "local_port":
329
- field_value = faker.random_int(min=1024, max=65535)
330
- if field == "remote_ip":
331
- field_value = random.choice(observables.remote_ip) if observables and observables.remote_ip \
332
- else Observables.generator(observable_type=ObservableType.IP, known=ObservableKnown.BAD, count=1)[0]
333
- if field == "local_ip_v6":
334
- field_value = random.choice(observables.local_ip_v6) if observables and observables.local_ip_v6 \
335
- else faker.ipv6()
336
- if field == "remote_ip_v6":
337
- field_value = random.choice(observables.remote_ip_v6) if observables and observables.remote_ip_v6 \
338
- else faker.ipv6()
339
- if field == "remote_port":
340
- field_value = random.choice(observables.remote_port) if observables and observables.remote_port \
341
- else faker.random_int(min=1024, max=65535)
342
- if field == "dst_url":
343
- field_value = random.choice(observables.url) if observables and observables.url \
344
- else Observables.generator(observable_type=ObservableType.URL, known=ObservableKnown.BAD, count=1)
345
- if field == "inbound_bytes":
346
- field_value = random.choice(observables.inbound_bytes) if observables and observables.inbound_bytes \
347
- else faker.random_int(min=10, max=1073741824)
348
- if field == "outbound_bytes":
349
- field_value = random.choice(observables.outbound_bytes) if observables and observables.outbound_bytes \
350
- else faker.random_int(min=10, max=1073741824)
351
- if field == "app":
352
- field_value = random.choice(observables.app) if observables and observables.app \
353
- else faker.sentence(nb_words=2)
354
- if field == "os":
355
- field_value = random.choice(observables.os) if observables and observables.os \
356
- else random.choice(OS_LIST)
357
- if field == "protocol":
358
- field_value = random.choice(observables.protocol) if observables and observables.protocol \
359
- else random.choice(PROTOCOLS)
360
- if field == "rule_id":
361
- field_value = random.choice(observables.event_id) if observables and observables.event_id \
362
- else faker.random_int(min=1, max=200)
363
- if field == "action":
364
- field_value = random.choice(observables.action) if observables and observables.action \
365
- else random.choice(ACTIONS)
366
- if field == "src_domain":
367
- field_value = random.choice(observables.src_domain) if observables and observables.src_domain \
368
- else faker.domain_name()
369
- if field == "dst_domain":
370
- field_value = random.choice(observables.dst_domain) if observables and observables.dst_domain \
371
- else faker.domain_name()
372
- if field == "sender_email":
373
- field_value = random.choice(observables.sender_email) if observables and observables.sender_email \
374
- else faker.email()
375
- if field == "recipient_email":
376
- field_value = random.choice(observables.recipient_email) if observables and observables.recipient_email \
377
- else faker.email()
378
- if field == "email_subject":
379
- field_value = random.choice(observables.email_subject) if observables and observables.email_subject \
380
- else faker.sentence(nb_words=6)
381
- if field == "email_body":
382
- field_value = random.choice(observables.email_body) if observables and observables.email_body else \
383
- faker.sentence(nb_words=50)
384
- if field == "attachment_hash":
385
- field_value = random.choice(observables.file_hash) if observables and observables.file_hash \
386
- else Observables.generator(observable_type=ObservableType.SHA256, known=ObservableKnown.BAD,
387
- count=1)
388
- if field == "spam_score":
389
- field_value = faker.random_int(min=1, max=5)
390
- if field == "method":
391
- field_value = random.choice(observables.technique).get('mechanism') if observables and \
392
- observables.technique else random.choice(TECHNIQUES).get('mechanism')
393
- if field == "url":
394
- field_value = random.choice(observables.technique).get('indicator') if observables and \
395
- observables.technique else random.choice(TECHNIQUES).get('indicator')
396
- if field == "user_agent":
397
- field_value = faker.user_agent()
398
- if field == "referer":
399
- field_value = random.choice(observables.url) if observables and observables.url \
400
- else Observables.generator(observable_type=ObservableType.URL, known=ObservableKnown.BAD, count=1)
401
- if field == "response_code":
402
- field_value = random.choice(observables.error_code) if observables and observables.error_code \
403
- else random.choice(ERROR_CODE)
404
- if field == "response_size":
405
- field_value = faker.random_int(min=100, max=10000)
406
- if field == "attack_type":
407
- field_value = random.choice(observables.technique).get('technique') if observables and \
408
- observables.technique else random.choice(TECHNIQUES).get('technique')
409
- if field == "cookies":
410
- field_value = f"{faker.word()}={faker.uuid4()}"
411
- if field == "guid":
412
- field_value = faker.uuid4()
413
- if field == "transmitted_services":
414
- field_value = faker.sentence(nb_words=5)
415
- if field == "process_id":
416
- field_value = faker.random_int()
417
- if field == "new_process_id":
418
- field_value = faker.random_int()
419
- if field == "thread_id":
420
- field_value = faker.random_int()
421
- if field == "target_pid":
422
- field_value = faker.random_int()
423
- if field == "subject_login_id":
424
- field_value = faker.random_int()
425
- if field == "win_user_id":
426
- field_value = "S-1-" + str(faker.random_int())
427
- if field == "destination_login_id":
428
- field_value = faker.random_int()
429
- if field == "privilege_list":
430
- field_value = faker.sentence(nb_words=5)
431
- if field == "event_record_id":
432
- field_value = random.choice(observables.event_id) if observables and observables.event_id \
433
- else faker.random.randint(1, 999)
434
- if field == "win_process":
435
- field_value = random.choice(observables.win_process) if observables and observables.win_process \
436
- else random.choice(WIN_PROCESSES)
437
- if field == "win_cmd":
438
- field_value = random.choice(observables.win_cmd) if observables and observables.win_cmd \
439
- else random.choice(WINDOWS_CMD)
440
- if field == "win_child_process":
441
- field_value = random.choice(observables.win_child_process) if \
442
- observables and observables.win_child_process else random.choice(WIN_PROCESSES)
443
- if field == "source_network_address":
444
- field_value = random.choice(observables.local_ip) if observables and observables.local_ip \
445
- else faker.ipv4_private()
446
- if field == "file_name":
447
- field_value = random.choice(observables.file_name) if observables and observables.file_name \
448
- else faker.file_name()
449
- if field == "cve":
450
- field_value = random.choice(observables.cve) if observables and observables.cve \
451
- else Observables.generator(observable_type=ObservableType.CVE, count=1)
452
- if field == "file_hash":
453
- field_value = random.choice(observables.file_hash) if observables and observables.file_hash \
454
- else Observables.generator(observable_type=ObservableType.SHA256, known=ObservableKnown.BAD,
455
- count=1)
456
- if field == "incident_types":
457
- field_value = random.choice(observables.incident_types) if observables and observables.incident_types \
458
- else INCIDENTS_TYPES
459
- if field == "analysts":
460
- field_value = random.choice(observables.analysts) if observables and observables.analysts \
461
- else [faker.unique.first_name() for _ in range(10)]
462
- if field == "duration":
463
- field_value = random.randint(1, 5)
464
- if field == "log_id":
465
- field_value = faker.uuid4()
466
- if field == "alert_name":
467
- field_value = random.choice(observables.alert_name) if observables and observables.alert_name \
468
- else faker.sentence(nb_words=4)
469
- if field == "query_type":
470
- field_value = random.choice(observables.query_type) if \
471
- observables and observables.query_type else random.choice(QUERY_TYPE)
472
- if field == "database_name":
473
- field_value = random.choice(observables.database_name) if \
474
- observables and observables.database_name else random.choice(DATABASE_NAME)
475
- if field == "query":
476
- field_value = random.choice(observables.query) if \
477
- observables and observables.query else random.choice(QUERY)
478
- return field_value
479
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
+
480
395
  @classmethod
481
- def syslog(cls, count: int, datetime_iso: Optional[datetime] = None, observables: Optional[Observables] = None,
482
- required_fields: Optional[str] = None) -> List[str]:
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]:
483
403
  """
484
- Generate fake syslog messages.
485
-
486
- Args:
487
- count: The number of syslog messages to generate.
488
- datetime_iso: Optional. The starting datetime_iso for the syslog messages. If not provided, a random time during
489
- the past hour from now will be used.
490
- observables: Optional. An observables object. If not provided, random objservable will be generated
491
- and used.
492
- required_fields: Optional. A list of fields that are required to present in the generated data, whether from
493
- observables or randomely.
494
- Returns:
495
- A list of syslog messages.
496
-
497
- Examples:
498
- >>> Events.syslog(5)
499
- ['Jan 01 05:32:48 myhostname sudo[1023]: username : COMMAND ; cat /etc/shadow',
500
- 'Jan 01 05:17:59 myhostname sudo[2019]: username : COMMAND ; find / -name \'*.log\' -exec rm -f {} \\;',
501
- 'Jan 01 05:46:16 myhostname sudo[3132]: username : COMMAND ; dd if=/dev/zero of=/dev/sda',
502
- 'Jan 01 05:08:08 myhostname sudo[4111]: username : COMMAND ; chmod -R 777 /',
503
- 'Jan 01 05:59:41 myhostname sudo[5195]: username : COMMAND ; chown -R nobody:nogroup /']
504
-
404
+ Generate fake syslog messages with optimizations for efficiency.
505
405
  """
506
406
  syslog_messages = []
507
- faker = cls._create_faker()
407
+ faker = Events.faker
408
+
409
+ # Predefine default datetime if not provided
508
410
  if datetime_iso is None:
509
411
  datetime_iso = datetime.now() - timedelta(hours=1)
510
412
  datetime_iso += timedelta(seconds=faker.random_int(min=0, max=3599))
511
- if not required_fields:
512
- required_fields = "pid,host,user,unix_process,unix_cmd"
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
513
447
  for i in range(count):
514
- datetime_iso += timedelta(seconds=1)
515
- syslog_message = f"{datetime_iso.strftime('%Y-%m-%d %H:%M:%S')}"
516
- for field in required_fields.split(","):
517
- syslog_message += f" {cls.set_field(field, observables)}"
518
- if observables:
519
- for observable, observable_value in vars(observables).items():
520
- if observable_value and observable not in required_fields.split(","):
521
- syslog_message += f" {random.choice(observable_value)}"
522
- syslog_messages.append(syslog_message)
523
- return syslog_messages
448
+ # Update datetime for each log
449
+ current_time = (datetime_iso + timedelta(seconds=i + 1)).strftime('%b %d %H:%M:%S')
524
450
 
525
- @classmethod
526
- def cef(cls, count: int, vendor: Optional[str] = None, product: Optional[str] = None,
527
- version: Optional[str] = None, datetime_iso: Optional[datetime] = None,
528
- observables: Optional[Observables] = None, required_fields: Optional[str] = None) -> List[str]:
529
- """
530
- Generates fake CEF (Common Event Format) messages.
451
+ # Build the syslog message efficiently
452
+ syslog_message_parts = [f"{current_time}"]
531
453
 
532
- Args:
533
- count: The number of CEF messages to generate.
534
- datetime_iso: Optional. The starting datetime_iso for the syslog messages. If not provided, a random time during.
535
- vendor: Optional. The vendor.
536
- product: Optional. The product value options include:
537
- - Firewall
538
- - EmailGW
539
- version: Optional. The version.
540
- observables: Optional. An observables object. If not provided, random objservable will be generated
541
- and used.
542
- required_fields: Optional. A list of fields that are required to present in the generated data, whether from
543
- observables or randomely.
544
- Returns:
545
- 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)
546
456
 
547
- Raises:
548
- None.
549
-
550
- Example Usage:
551
- >>> Events.cef(3)
552
- ['CEF:0|Acme|Firewall|1.0.0|ddab6607-1c35-4e81-a54a-99b1c9b77e49|Firewall ALLOW UDP traffic
553
- from example.com:61434 to 23.216.45.109:47983|1|src=example.com spt=61434 dst=23.216.45.109
554
- dpt=47983 proto=UDP act=ALLOW',
555
- 'CEF:0|Acme|Firewall|1.0.0|25b41f8f-8a63-4162-a69c-cb43f8c8e49f|Firewall DENY TCP traffic
556
- from example.com:11460 to 184.72.194.90:3087|8|src=example.com spt=11460 dst=184.72.194.90
557
- dpt=3087 proto=TCP act=DENY',
558
- 'CEF:0|Acme|Firewall|1.0.0|a3faedaa-5109-4849-b9ec-1ad6c5f8a5ec|Firewall ALLOW TCP traffic
559
- from example.com:25068 to 81.171.9.216:6157|2|src=example.com spt=25068 dst=81.171.9.216
560
- dpt=6157 proto=TCP act=ALLOW']
561
- """
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]:
562
475
  cef_messages = []
563
- faker = cls._create_faker()
476
+ faker = Events.faker
564
477
  vendor = vendor or faker.company()
478
+ product = product or faker.word()
565
479
  version = version or faker.numerify("1.0.#")
566
- if datetime_iso is None:
567
- datetime_iso = datetime.now() - timedelta(hours=1)
568
- datetime_iso += timedelta(seconds=faker.random_int(min=0, max=3599))
569
- if not required_fields:
570
- if product == "Firewall":
571
- required_fields = "local_ip,local_port,remote_ip,remote_port,dst_url,inbound_bytes," \
572
- "outbound_bytes,protocol,rule_id,action"
573
- elif product == "EmailGW":
574
- required_fields = "local_ip,src_domain,sender_email,recipient_email,email_subject,email_body," \
575
- "attachment_hash,spam_score,action"
576
- else:
577
- required_fields = "local_ip,local_port,remote_ip,remote_port,protocol,rule_id,action"
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
578
519
  for i in range(count):
579
- datetime_iso += timedelta(seconds=1)
580
- cef_message = f"CEF:0|{vendor}|{product}|{version}|{cls.set_field('log_id', observables)}|{datetime_iso}" \
581
- f"|{cls.set_field('severity', observables)}|"
582
- for field in required_fields.split(","):
583
- cef_message += f" {field}={cls.set_field(field, observables)}"
584
- if observables:
585
- for observable, observable_value in vars(observables).items():
586
- if observable_value and observable not in required_fields.split(","):
587
- cef_message += f" {observable}={random.choice(observable_value)}"
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
588
530
  cef_messages.append(cef_message)
531
+
589
532
  return cef_messages
590
-
533
+
591
534
  @classmethod
592
- def leef(cls, count, datetime_iso: Optional[datetime] = None, vendor: Optional[str] = None,
593
- product: Optional[str] = None, version: Optional[str] = None,
594
- observables: Optional[Observables] = None, required_fields: Optional[str] = None) -> List[str]:
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]:
595
545
  """
596
- Generates fake LEEF (Log Event Extended Format) messages.
597
-
598
- Parameters:
599
- count (int): The number of LEEF messages to generate.
600
- datetime_iso: Optional. The starting datetime_iso for the syslog messages. If not provided, a random time during.
601
- vendor: Optional. The vendor.
602
- product: Optional. The product.
603
- version: Optional. The version.
604
- observables: An observables object. If not provided, random objservable will be generated and used.
605
- required_fields: Optional. A list of fields that are required to present in the generated data, whether from
606
- observables or randomely.
607
-
608
- Returns:
609
- A list of generated LEEF messages.
610
-
611
- Example:
612
- To generate 10 fake LEEF messages:
613
- ```
614
- >>> messages = Events.leef(count=2)
615
- >>> print(messages)
616
- ['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
617
- dst=mycomputer spt=60918 dpt=443 request=https://example.com/?q=<script>alert("xss")</script>
618
- method=GET proto=HTTP/1.1 status=200 request_size=5119 response_size=6472
619
- user_agent=Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko)
620
- Chrome/93.0.4577.63 Safari/537.36',
621
- '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
622
- dst=mycomputer spt=57251 dpt=443 request=https://example.com/admin.php?sessionid=12345 method=POST
623
- proto=HTTP/1.1 status=404 request_size=1216 response_size=9729 user_agent=Mozilla/5.0
624
- (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.
625
547
  """
626
548
  leef_messages = []
627
- faker = cls._create_faker()
549
+ faker = Events.faker
628
550
  vendor = vendor or faker.company()
551
+ product = product or faker.word()
629
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
630
561
  event_id = faker.random_int(min=101, max=501)
631
- if datetime_iso is None:
632
- datetime_iso = datetime.now() - timedelta(hours=1)
633
- datetime_iso += timedelta(seconds=faker.random_int(min=0, max=3599))
634
- if not required_fields:
635
- if product == "WAF":
636
- required_fields = "local_ip,local_port,host,method,url,protocol," \
637
- "user_agent,referer,response_code,response_size,rule_id,action,attack_type,cookies"
638
- else:
639
- required_fields = "local_ip,local_port,host,url,protocol,response_code,action"
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
640
597
  for i in range(count):
641
- datetime_iso += timedelta(seconds=1)
642
- leef_message = f"LEEF:1.0|{vendor}|{product}|{version}|{event_id}|" \
643
- f"severity={cls.set_field('severity', observables)} devtime={datetime_iso}"
644
- for field in required_fields.split(","):
645
- leef_message += f" {field}={cls.set_field(field, observables)}"
646
- if observables:
647
- for observable, observable_value in vars(observables).items():
648
- if observable_value and observable not in required_fields.split(","):
649
- 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)
650
601
  leef_messages.append(leef_message)
651
- return leef_messages
652
602
 
603
+ return leef_messages
604
+
653
605
  @classmethod
654
- def winevent(cls, count, datetime_iso: Optional[datetime] = None, observables: Optional[Observables] = None) -> \
655
- List[str]:
606
+ def winevent(
607
+ cls,
608
+ count: int,
609
+ datetime_iso: Optional[datetime] = None,
610
+ observables: Optional['Observables'] = None
611
+ ) -> List[str]:
656
612
  """
657
- Generates fake Windows Event Log messages.
613
+ Generates optimized fake Windows Event Log messages using set_field.
658
614
 
659
615
  Args:
660
616
  count (int): The number of fake messages to generate.
661
- datetime_iso: Optional. The starting datetime_iso for the syslog messages. If not provided, a random time during
662
- observables: An observables object. If not provided, random objservable will be generated and used.
617
+ datetime_iso (Optional[datetime]): The starting datetime for the messages.
618
+ observables (Optional[Observables]): An observables object with predefined values.
663
619
 
664
620
  Returns:
665
- list: A list of fake Windows Event Log messages.
666
-
667
- Examples:
668
- >>> Events.winevent(1)
669
- ['<Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">...</Event>', ...]
621
+ List[str]: A list of fake Windows Event Log messages.
670
622
  """
671
623
  winevent_messages = []
672
- faker = cls._create_faker()
624
+ faker = Events.faker
625
+
626
+ # Set starting datetime if not provided
673
627
  if datetime_iso is None:
674
628
  datetime_iso = datetime.now() - timedelta(hours=1)
675
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
676
674
  for i in range(count):
677
- datetime_iso += timedelta(seconds=1)
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
678
680
  guid = faker.uuid4()
679
- local_port = faker.random_int(min=1024, max=65535)
680
- transmitted_services = faker.sentence(nb_words=5)
681
- system_time = datetime_iso
682
- process_id = faker.random_int()
683
- new_process_id = faker.random_int()
684
- thread_id = faker.random_int()
685
- target_pid = faker.random_int()
686
- domain_name = faker.domain_name()
687
- subject_login_id = faker.random_int()
688
- user_id = "S-1-" + str(faker.random_int())
689
- destination_login_id = faker.random_int()
690
- privilege_list = faker.sentence(nb_words=5)
691
- event_record_id = random.choice(observables.event_id) if observables and observables.event_id \
692
- else faker.random.randint(1, 999)
693
- process_name = random.choice(observables.win_process) if observables and observables.win_process \
694
- else random.choice(WIN_PROCESSES)
695
- host = random.choice(observables.src_host) if observables and observables.src_host \
696
- else faker.hostname()
697
- user_name = random.choice(observables.user) if observables and observables.user \
698
- else faker.user_name()
699
- cmd = random.choice(observables.win_cmd) if observables and observables.win_cmd \
700
- else random.choice(WINDOWS_CMD)
701
- source_network_address = random.choice(observables.local_ip) if observables and observables.local_ip \
702
- else faker.ipv4_private()
703
- file_name = random.choice(observables.file_name) if observables and observables.file_name \
704
- 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
705
699
  unformatted_event = random.choice(WIN_EVENTS)
706
- win_event = unformatted_event.format(guid=guid, system_time=system_time, event_record_id=event_record_id,
707
- process_id=process_id, process_name=process_name,
708
- new_process_id=new_process_id, thread_id=thread_id,
709
- target_pid=target_pid, host=host, user_id=user_id, user_name=user_name,
710
- domain_name=domain_name, subject_login_id=subject_login_id,
711
- privilege_list=privilege_list, cmd=cmd,
712
- destination_login_id=destination_login_id,
713
- source_network_address=source_network_address, local_port=local_port,
714
- 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
+
715
704
  winevent_messages.append(win_event)
705
+
716
706
  return winevent_messages
717
707
 
718
708
  @classmethod
719
- def json(cls, count, datetime_iso: Optional[datetime] = None, vendor: Optional[str] = None,
720
- product: Optional[str] = None, version: Optional[str] = None, observables: Optional[Observables] = None,
721
- required_fields: Optional[str] = None) -> List[dict]:
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]:
722
719
  """
723
- Generate fake JSON messages representing discovered vulnerabilities.
724
-
725
- Args:
726
- count (int): The number of JSON messages to generate.
727
- datetime_iso: Optional. The starting datetime_iso for the syslog messages. If not provided, a random time during.
728
- vendor: Optional. The vendor.
729
- product: Optional. The product value options include:
730
- - VulnScanner
731
- version: Optional. The version.
732
- observables: An observables object. If not provided, random objservable will be generated and used.
733
- required_fields: Optional. A list of fields that are required to present in the generated data, whether from
734
- observables or randomely.
735
- Returns:
736
- List[Dict[str, Union[str, int]]]: A list of dictionaries representing the generated JSON messages.
737
-
738
- Example:
739
- >>> fake_messages = json(5)
740
- >>> len(fake_messages)
741
- 5
742
- >>> isinstance(fake_messages[0], dict)
743
- True
744
-
720
+ Generate optimized fake JSON messages representing discovered vulnerabilities.
745
721
  """
746
722
  json_messages = []
747
- faker = cls._create_faker()
723
+ faker = Events.faker
724
+
725
+ # Precompute vendor, product, and version details
748
726
  vendor = vendor or faker.company()
727
+ product = product or "UnknownProduct"
749
728
  version = version or faker.numerify("1.0.#")
750
- if datetime_iso is None:
751
- datetime_iso = datetime.now() - timedelta(hours=1)
752
- datetime_iso += timedelta(seconds=faker.random_int(min=0, max=3599))
753
- if not required_fields:
754
- if product == "VulnScanner":
755
- required_fields = "cve_id,host,file_hash"
756
- else:
757
- required_fields = "user,host"
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
758
762
  for i in range(count):
759
- datetime_iso += timedelta(seconds=1)
763
+ # Adjust datetime for each message
764
+ current_datetime = datetime_iso + timedelta(seconds=i)
765
+
766
+ # Initialize event with static fields
760
767
  event = {
761
768
  'vendor': vendor,
762
769
  'product': product,
763
770
  'version': version,
764
- 'datetime_iso': str(datetime_iso),
765
- 'severity': cls.set_field("severity", observables)
771
+ 'datetime_iso': current_datetime.strftime("%Y-%m-%d %H:%M:%S"),
772
+ 'severity': severity,
773
+ **common_fields,
774
+ **extra_fields
766
775
  }
767
- for field in required_fields.split(","):
768
- event[field] = cls.set_field(field, observables)
769
- if observables:
770
- for observable, observable_value in vars(observables).items():
771
- if observable_value and observable not in required_fields.split(","):
772
- event[observable] = random.choice(observable_value)
776
+
777
+ # Append generated event to the list
773
778
  json_messages.append(event)
779
+
774
780
  return json_messages
775
781
 
776
782
  @classmethod
777
783
  def incidents(cls, count, fields: Optional[str] = None, datetime_iso: Optional[datetime] = None,
778
- vendor: Optional[str] = None, product: Optional[str] = None, version: Optional[str] = None,
779
- observables: Optional[Observables] = None, required_fields: Optional[str] = None) -> List[dict]:
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]:
780
786
  """
781
787
  Generates a list of fake incident data.
782
788
 
783
789
  Args:
784
790
  count (int): The number of incidents to generate.
785
- fields (str, optional): A comma-separated list of incident fields to include in the output. If None,
786
- all fields will be included. Valid options are: 'id', 'duration', 'type', 'analyst', 'severity',
787
- 'description', 'events'.
788
- vendor: Optional. The vendor.
789
- product: Optional. The product.
790
- version: Optional. The version.
791
- datetime_iso: Optional. The starting datetime_iso for the syslog messages. If not provided, a random time during
792
- observables: An observables object. If not provided, random objservable will be generated and used.
793
- required_fields: Optional. A list of fields that are required to present in the generated data, whether from
794
- 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.
795
796
 
796
797
  Returns:
797
- List[Dict]: A list of incident dictionaries. Each dictionary contains the following fields:
798
- - 'id' (int): A unique identifier for the incident.
799
- - 'type' (str): The type of incident.
800
- - 'duration' (int): The duration of the incident in hours.
801
- - 'analyst' (str): The name of the analyst assigned to the incident.
802
- - 'severity' (str, optional): The severity of the incident. Only included if 'severity' is specified
803
- in the 'fields' argument.
804
- - 'description' (str, optional): A brief description of the incident. Only included if 'description' is
805
- specified in the 'fields' argument.
806
- - 'events' (List[Dict], optional): A list of event dictionaries associated with the incident.
807
-
808
- Example:
809
- >>> incidents(count=3, fields='id,type,severity')
810
- [
811
- {'id': 1, 'type': 'Lateral Movement', 'severity': 'Critical'},
812
- {'id': 2, 'type': 'Access Violation', 'severity': 'High'},
813
- {'id': 3, 'type': 'Account Compromised', 'severity': 'Low'}
814
- ]
798
+ List[Dict]: A list of incident dictionaries.
815
799
  """
816
800
  incidents = []
817
- faker = cls._create_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)]
818
807
 
819
- incident_ids = set()
820
-
821
- incident_types = observables.incident_types if observables and observables.incident_types \
822
- else INCIDENTS_TYPES
823
- analysts = observables.analysts if observables and observables.analysts \
824
- else [faker.unique.first_name() for _ in range(10)]
825
- analyst_incident_map = {}
826
- for analyst in analysts:
827
- mapped_incident_type = incident_types.pop(0)
828
- analyst_incident_map[analyst] = mapped_incident_type
829
- incident_types.append(mapped_incident_type)
808
+ incident_type_cycle = itertools.cycle(incident_types)
830
809
  for i in range(count):
831
- incident = {}
810
+ incident_id = i + 1 # Simplify unique ID generation
832
811
  duration = random.randint(1, 5)
833
- while True:
834
- incident_id = random.randint(1, count)
835
- if incident_id not in incident_ids:
836
- incident_ids.add(incident_id)
837
- break
838
- incident_type = random.choice(incident_types)
812
+ incident_type = next(incident_type_cycle)
839
813
  analyst = random.choice(analysts)
840
- severity = random.choice(observables.severity) if observables and observables.severity \
841
- else faker.random_int(min=1, max=5)
842
- description = random.choice(observables.terms) if observables and observables.terms \
843
- else Observables.generator(observable_type=ObservableType.TERMS, known=ObservableKnown.BAD, count=1000)
844
- if analyst in analyst_incident_map and random.randint(1, 100) == 2:
845
- incident_type = analyst_incident_map[analyst]
846
- duration = random.randint(1, 2)
847
- if fields:
848
- field_list = fields.split(',')
849
- if 'id' in field_list:
850
- incident['id'] = incident_id
851
- if 'duration' in field_list:
852
- incident['duration'] = duration
853
- if 'type' in field_list:
854
- incident['type'] = incident_type
855
- if 'analyst' in field_list:
856
- incident['analyst'] = analyst
857
- if 'severity' in field_list:
858
- incident['severity'] = severity
859
- if 'description' in field_list:
860
- incident_description = faker.paragraph(nb_sentences=1, ext_word_list=description)
861
- incident['description'] = incident_description
862
- if 'events' in field_list:
863
- incident['events'] = [
864
- {"event": cls.syslog(count=1, datetime_iso=datetime_iso, observables=observables,
865
- required_fields=required_fields)[0]},
866
- {"event": cls.cef(count=1, datetime_iso=datetime_iso, vendor=vendor, product=product, version=version
867
- , observables=observables, required_fields=required_fields)[0]},
868
- {"event": cls.leef(count=1, datetime_iso=datetime_iso, vendor=vendor, product=product,
869
- version=version, observables=observables, required_fields=required_fields)[0]},
870
- {"event": cls.winevent(count=1, datetime_iso=datetime_iso, observables=observables)[0]},
871
- {"event": cls.json(count=1, datetime_iso=datetime_iso, vendor=vendor, product=product,
872
- version=version, observables=observables,
873
- required_fields=required_fields)[0]}
874
- ]
875
- else:
876
- incident = {
877
- "id": incident_id,
878
- "type": incident_type,
879
- "duration": duration,
880
- "analyst": analyst
881
- }
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
+
882
843
  incidents.append(incident)
844
+
883
845
  return incidents