rosetta-ce 1.6.9__py3-none-any.whl → 1.7.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of rosetta-ce might be problematic. Click here for more details.

rosetta/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,633 +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 == "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(cls, count: int, datetime_iso: Optional[datetime] = None, observables: Optional[Observables] = None,
503
- 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]:
504
403
  """
505
- Generate fake syslog messages.
506
-
507
- Args:
508
- count: The number of syslog messages to generate.
509
- datetime_iso: Optional. The starting datetime_iso for the syslog messages. If not provided, a random time during
510
- the past hour from now will be used.
511
- observables: Optional. An observables object. If not provided, random objservable will be generated
512
- and used.
513
- required_fields: Optional. A list of fields that are required to present in the generated data, whether from
514
- observables or randomely.
515
- Returns:
516
- A list of syslog messages.
517
-
518
- Examples:
519
- >>> Events.syslog(5)
520
- ['Jan 01 05:32:48 myhostname sudo[1023]: username : COMMAND ; cat /etc/shadow',
521
- 'Jan 01 05:17:59 myhostname sudo[2019]: username : COMMAND ; find / -name \'*.log\' -exec rm -f {} \\;',
522
- 'Jan 01 05:46:16 myhostname sudo[3132]: username : COMMAND ; dd if=/dev/zero of=/dev/sda',
523
- 'Jan 01 05:08:08 myhostname sudo[4111]: username : COMMAND ; chmod -R 777 /',
524
- 'Jan 01 05:59:41 myhostname sudo[5195]: username : COMMAND ; chown -R nobody:nogroup /']
525
-
404
+ Generate fake syslog messages with optimizations for efficiency.
526
405
  """
527
406
  syslog_messages = []
528
- faker = cls._create_faker()
407
+ faker = Events.faker
408
+
409
+ # Predefine default datetime if not provided
529
410
  if datetime_iso is None:
530
411
  datetime_iso = datetime.now() - timedelta(hours=1)
531
412
  datetime_iso += timedelta(seconds=faker.random_int(min=0, max=3599))
532
- if not required_fields:
533
- 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
534
447
  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
448
+ # Update datetime for each log
449
+ current_time = (datetime_iso + timedelta(seconds=i + 1)).strftime('%b %d %H:%M:%S')
545
450
 
546
- @classmethod
547
- def cef(cls, count: int, vendor: Optional[str] = None, product: Optional[str] = None,
548
- version: Optional[str] = None, datetime_iso: Optional[datetime] = None,
549
- observables: Optional[Observables] = None, required_fields: Optional[str] = None) -> List[str]:
550
- """
551
- Generates fake CEF (Common Event Format) messages.
451
+ # Build the syslog message efficiently
452
+ syslog_message_parts = [f"{current_time}"]
552
453
 
553
- Args:
554
- count: The number of CEF messages to generate.
555
- datetime_iso: Optional. The starting datetime_iso for the syslog messages. If not provided, a random time during.
556
- vendor: Optional. The vendor.
557
- product: Optional. The product value options include:
558
- - Firewall
559
- - EmailGW
560
- version: Optional. The version.
561
- observables: Optional. An observables object. If not provided, random objservable will be generated
562
- and used.
563
- required_fields: Optional. A list of fields that are required to present in the generated data, whether from
564
- observables or randomely.
565
- Returns:
566
- A list of fake CEF messages in string format.
454
+ # Insert required fields
455
+ syslog_message_parts.extend(str(common_fields[field]) for field in required_fields_list)
567
456
 
568
- Raises:
569
- None.
570
-
571
- Example Usage:
572
- >>> Events.cef(3)
573
- ['CEF:0|Acme|Firewall|1.0.0|ddab6607-1c35-4e81-a54a-99b1c9b77e49|Firewall ALLOW UDP traffic
574
- from example.com:61434 to 23.216.45.109:47983|1|src=example.com spt=61434 dst=23.216.45.109
575
- dpt=47983 proto=UDP act=ALLOW',
576
- 'CEF:0|Acme|Firewall|1.0.0|25b41f8f-8a63-4162-a69c-cb43f8c8e49f|Firewall DENY TCP traffic
577
- from example.com:11460 to 184.72.194.90:3087|8|src=example.com spt=11460 dst=184.72.194.90
578
- dpt=3087 proto=TCP act=DENY',
579
- 'CEF:0|Acme|Firewall|1.0.0|a3faedaa-5109-4849-b9ec-1ad6c5f8a5ec|Firewall ALLOW TCP traffic
580
- from example.com:25068 to 81.171.9.216:6157|2|src=example.com spt=25068 dst=81.171.9.216
581
- dpt=6157 proto=TCP act=ALLOW']
582
- """
457
+ # Append additional observables not in required fields
458
+ syslog_message_parts.extend(extra_fields)
459
+
460
+ syslog_messages.append(" ".join(syslog_message_parts))
461
+
462
+ return syslog_messages
463
+
464
+ @classmethod
465
+ def cef(
466
+ cls,
467
+ count: int,
468
+ vendor: Optional[str] = None,
469
+ product: Optional[str] = None,
470
+ version: Optional[str] = None,
471
+ datetime_iso: Optional[datetime] = None,
472
+ observables: Optional['Observables'] = None,
473
+ required_fields: Optional[str] = None
474
+ ) -> List[str]:
583
475
  cef_messages = []
584
- faker = cls._create_faker()
476
+ faker = Events.faker
585
477
  vendor = vendor or faker.company()
478
+ product = product or faker.word()
586
479
  version = version or faker.numerify("1.0.#")
587
- if datetime_iso is None:
588
- datetime_iso = datetime.now() - timedelta(hours=1)
589
- datetime_iso += timedelta(seconds=faker.random_int(min=0, max=3599))
590
- if not required_fields:
591
- if product == "Firewall":
592
- required_fields = "local_ip,local_port,remote_ip,remote_port,dst_url,inbound_bytes," \
593
- "outbound_bytes,protocol,rule_id,action"
594
- elif product == "EmailGW":
595
- required_fields = "local_ip,src_domain,sender_email,recipient_email,email_subject,email_body," \
596
- "attachment_hash,spam_score,action"
597
- else:
598
- 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
599
519
  for i in range(count):
600
- datetime_iso += timedelta(seconds=1)
601
- cef_message = f"CEF:0|{vendor}|{product}|{version}|{cls.set_field('log_id', observables)}|{datetime_iso}" \
602
- f"|{cls.set_field('severity', observables)}|"
603
- for field in required_fields.split(","):
604
- cef_message += f" {field}={cls.set_field(field, observables)}"
605
- if observables:
606
- for observable, observable_value in vars(observables).items():
607
- if observable_value and observable not in required_fields.split(","):
608
- 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
609
530
  cef_messages.append(cef_message)
531
+
610
532
  return cef_messages
611
-
533
+
612
534
  @classmethod
613
- def leef(cls, count, datetime_iso: Optional[datetime] = None, vendor: Optional[str] = None,
614
- product: Optional[str] = None, version: Optional[str] = None,
615
- 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]:
616
545
  """
617
- Generates fake LEEF (Log Event Extended Format) messages.
618
-
619
- Parameters:
620
- count (int): The number of LEEF messages to generate.
621
- datetime_iso: Optional. The starting datetime_iso for the syslog messages. If not provided, a random time during.
622
- vendor: Optional. The vendor.
623
- product: Optional. The product.
624
- version: Optional. The version.
625
- observables: An observables object. If not provided, random objservable will be generated and used.
626
- required_fields: Optional. A list of fields that are required to present in the generated data, whether from
627
- observables or randomely.
628
-
629
- Returns:
630
- A list of generated LEEF messages.
631
-
632
- Example:
633
- To generate 10 fake LEEF messages:
634
- ```
635
- >>> messages = Events.leef(count=2)
636
- >>> print(messages)
637
- ['LEEF:1.0|Leef|Payment Portal|1.0|192.168.0.1|mycomputer|08:00:27:da:2e:2e|08:00:27:da:2e:2f|src=10.0.0.1
638
- dst=mycomputer spt=60918 dpt=443 request=https://example.com/?q=<script>alert("xss")</script>
639
- method=GET proto=HTTP/1.1 status=200 request_size=5119 response_size=6472
640
- user_agent=Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko)
641
- Chrome/93.0.4577.63 Safari/537.36',
642
- 'LEEF:1.0|Leef|Payment Portal|1.0|192.168.0.1|mycomputer|08:00:27:da:2e:2e|08:00:27:da:2e:2f|src=10.0.0.2
643
- dst=mycomputer spt=57251 dpt=443 request=https://example.com/admin.php?sessionid=12345 method=POST
644
- proto=HTTP/1.1 status=404 request_size=1216 response_size=9729 user_agent=Mozilla/5.0
645
- (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3']
546
+ Generates optimized fake LEEF (Log Event Extended Format) messages.
646
547
  """
647
548
  leef_messages = []
648
- faker = cls._create_faker()
549
+ faker = Events.faker
649
550
  vendor = vendor or faker.company()
551
+ product = product or faker.word()
650
552
  version = version or faker.numerify("1.0.#")
553
+
554
+ # Set starting datetime and default fields if necessary
555
+ datetime_iso = datetime_iso or datetime.now() - timedelta(hours=1)
556
+ required_fields_list = required_fields.split(",") if required_fields else [
557
+ "local_ip", "local_port", "host", "url", "protocol", "response_code", "action"
558
+ ]
559
+
560
+ # Precompute event_id and severity
651
561
  event_id = faker.random_int(min=101, max=501)
652
- if datetime_iso is None:
653
- datetime_iso = datetime.now() - timedelta(hours=1)
654
- datetime_iso += timedelta(seconds=faker.random_int(min=0, max=3599))
655
- if not required_fields:
656
- if product == "WAF":
657
- required_fields = "local_ip,local_port,host,method,url,protocol," \
658
- "user_agent,referer,response_code,response_size,rule_id,action,attack_type,cookies"
659
- else:
660
- 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
661
597
  for i in range(count):
662
- datetime_iso += timedelta(seconds=1)
663
- leef_message = f"LEEF:1.0|{vendor}|{product}|{version}|{event_id}|" \
664
- f"severity={cls.set_field('severity', observables)} devtime={datetime_iso}"
665
- for field in required_fields.split(","):
666
- leef_message += f" {field}={cls.set_field(field, observables)}"
667
- if observables:
668
- for observable, observable_value in vars(observables).items():
669
- if observable_value and observable not in required_fields.split(","):
670
- leef_message += f" {observable}={random.choice(observable_value)}"
598
+ current_datetime = (datetime_iso + timedelta(seconds=i)).strftime('%b %d %H:%M:%S')
599
+
600
+ leef_message = leef_template.format(current_datetime=current_datetime)
671
601
  leef_messages.append(leef_message)
672
- return leef_messages
673
602
 
603
+ return leef_messages
604
+
674
605
  @classmethod
675
- def winevent(cls, count, datetime_iso: Optional[datetime] = None, observables: Optional[Observables] = None) -> \
676
- List[str]:
606
+ def winevent(
607
+ cls,
608
+ count: int,
609
+ datetime_iso: Optional[datetime] = None,
610
+ observables: Optional['Observables'] = None
611
+ ) -> List[str]:
677
612
  """
678
- Generates fake Windows Event Log messages.
613
+ Generates optimized fake Windows Event Log messages using set_field.
679
614
 
680
615
  Args:
681
616
  count (int): The number of fake messages to generate.
682
- datetime_iso: Optional. The starting datetime_iso for the syslog messages. If not provided, a random time during
683
- 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.
684
619
 
685
620
  Returns:
686
- list: A list of fake Windows Event Log messages.
687
-
688
- Examples:
689
- >>> Events.winevent(1)
690
- ['<Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">...</Event>', ...]
621
+ List[str]: A list of fake Windows Event Log messages.
691
622
  """
692
623
  winevent_messages = []
693
- faker = cls._create_faker()
624
+ faker = Events.faker
625
+
626
+ # Set starting datetime if not provided
694
627
  if datetime_iso is None:
695
628
  datetime_iso = datetime.now() - timedelta(hours=1)
696
629
  datetime_iso += timedelta(seconds=faker.random_int(min=0, max=3599))
630
+
631
+ # Define required fields
632
+ required_fields_list = [
633
+ "process_id",
634
+ "new_process_id",
635
+ "thread_id",
636
+ "target_pid",
637
+ "subject_login_id",
638
+ "user_id",
639
+ "destination_login_id",
640
+ "privilege_list",
641
+ "win_process",
642
+ "src_host",
643
+ "user_name",
644
+ "cmd",
645
+ "source_network_address",
646
+ "local_port",
647
+ "transmitted_services",
648
+ "file_name",
649
+ "src_domain"
650
+ ]
651
+
652
+ # Precompute common fields using set_field
653
+ common_fields = {}
654
+ for field in required_fields_list:
655
+ value = None
656
+ if observables and hasattr(observables, field):
657
+ obs_value = getattr(observables, field)
658
+ if obs_value:
659
+ value = random.choice(obs_value) if isinstance(obs_value, list) else obs_value
660
+ if value is None:
661
+ value = Events._set_field(field)
662
+ common_fields[field] = value
663
+
664
+ # Preprocess extra observables not in required fields
665
+ extra_fields = {}
666
+ if observables:
667
+ observables_dict = vars(observables)
668
+ for key, value in observables_dict.items():
669
+ if value and key not in required_fields_list:
670
+ val = random.choice(value) if isinstance(value, list) else value
671
+ extra_fields[key] = val
672
+
673
+ # Generate events
697
674
  for i in range(count):
698
- 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
699
680
  guid = faker.uuid4()
700
- local_port = faker.random_int(min=1024, max=65535)
701
- transmitted_services = faker.sentence(nb_words=5)
702
- system_time = datetime_iso
703
- process_id = faker.random_int()
704
- new_process_id = faker.random_int()
705
- thread_id = faker.random_int()
706
- target_pid = faker.random_int()
707
- domain_name = faker.domain_name()
708
- subject_login_id = faker.random_int()
709
- user_id = "S-1-" + str(faker.random_int())
710
- destination_login_id = faker.random_int()
711
- privilege_list = faker.sentence(nb_words=5)
712
- event_record_id = random.choice(observables.event_id) if observables and observables.event_id \
713
- else faker.random.randint(1, 999)
714
- process_name = random.choice(observables.win_process) if observables and observables.win_process \
715
- else random.choice(WIN_PROCESSES)
716
- host = random.choice(observables.src_host) if observables and observables.src_host \
717
- else faker.hostname()
718
- user_name = random.choice(observables.user) if observables and observables.user \
719
- else faker.user_name()
720
- cmd = random.choice(observables.win_cmd) if observables and observables.win_cmd \
721
- else random.choice(WINDOWS_CMD)
722
- source_network_address = random.choice(observables.local_ip) if observables and observables.local_ip \
723
- else faker.ipv4_private()
724
- file_name = random.choice(observables.file_name) if observables and observables.file_name \
725
- else faker.file_name()
681
+
682
+ # Use event_id from observables if available
683
+ event_record_id = None
684
+ if observables and hasattr(observables, 'event_id') and observables.event_id:
685
+ event_record_id = random.choice(observables.event_id)
686
+ else:
687
+ event_record_id = Events._set_field('event_id')
688
+
689
+ # Prepare event fields
690
+ event_fields = {
691
+ 'guid': guid,
692
+ 'system_time': system_time,
693
+ 'event_record_id': event_record_id,
694
+ **common_fields,
695
+ **extra_fields
696
+ }
697
+
698
+ # Select a random event template
726
699
  unformatted_event = random.choice(WIN_EVENTS)
727
- win_event = unformatted_event.format(guid=guid, system_time=system_time, event_record_id=event_record_id,
728
- process_id=process_id, process_name=process_name,
729
- new_process_id=new_process_id, thread_id=thread_id,
730
- target_pid=target_pid, host=host, user_id=user_id, user_name=user_name,
731
- domain_name=domain_name, subject_login_id=subject_login_id,
732
- privilege_list=privilege_list, cmd=cmd,
733
- destination_login_id=destination_login_id,
734
- source_network_address=source_network_address, local_port=local_port,
735
- transmitted_services=transmitted_services, file_name=file_name)
700
+
701
+ # Format the event with all fields
702
+ win_event = unformatted_event.format(**event_fields)
703
+
736
704
  winevent_messages.append(win_event)
705
+
737
706
  return winevent_messages
738
707
 
739
708
  @classmethod
740
- def json(cls, count, datetime_iso: Optional[datetime] = None, vendor: Optional[str] = None,
741
- product: Optional[str] = None, version: Optional[str] = None, observables: Optional[Observables] = None,
742
- 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]:
743
719
  """
744
- Generate fake JSON messages representing discovered vulnerabilities.
745
-
746
- Args:
747
- count (int): The number of JSON messages to generate.
748
- datetime_iso: Optional. The starting datetime_iso for the syslog messages. If not provided, a random time during.
749
- vendor: Optional. The vendor.
750
- product: Optional. The product value options include:
751
- - VulnScanner
752
- version: Optional. The version.
753
- observables: An observables object. If not provided, random objservable will be generated and used.
754
- required_fields: Optional. A list of fields that are required to present in the generated data, whether from
755
- observables or randomely.
756
- Returns:
757
- List[Dict[str, Union[str, int]]]: A list of dictionaries representing the generated JSON messages.
758
-
759
- Example:
760
- >>> fake_messages = json(5)
761
- >>> len(fake_messages)
762
- 5
763
- >>> isinstance(fake_messages[0], dict)
764
- True
765
-
720
+ Generate optimized fake JSON messages representing discovered vulnerabilities.
766
721
  """
767
722
  json_messages = []
768
- faker = cls._create_faker()
723
+ faker = Events.faker
724
+
725
+ # Precompute vendor, product, and version details
769
726
  vendor = vendor or faker.company()
727
+ product = product or "UnknownProduct"
770
728
  version = version or faker.numerify("1.0.#")
771
- if datetime_iso is None:
772
- datetime_iso = datetime.now() - timedelta(hours=1)
773
- datetime_iso += timedelta(seconds=faker.random_int(min=0, max=3599))
774
- if not required_fields:
775
- if product == "VulnScanner":
776
- required_fields = "cve_id,host,file_hash"
777
- else:
778
- 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
779
762
  for i in range(count):
780
- 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
781
767
  event = {
782
768
  'vendor': vendor,
783
769
  'product': product,
784
770
  'version': version,
785
- 'datetime_iso': str(datetime_iso),
786
- '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
787
775
  }
788
- for field in required_fields.split(","):
789
- event[field] = cls.set_field(field, observables)
790
- if observables:
791
- for observable, observable_value in vars(observables).items():
792
- if observable_value and observable not in required_fields.split(","):
793
- event[observable] = random.choice(observable_value)
776
+
777
+ # Append generated event to the list
794
778
  json_messages.append(event)
779
+
795
780
  return json_messages
796
781
 
797
782
  @classmethod
798
783
  def incidents(cls, count, fields: Optional[str] = None, datetime_iso: Optional[datetime] = None,
799
- vendor: Optional[str] = None, product: Optional[str] = None, version: Optional[str] = None,
800
- 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]:
801
786
  """
802
787
  Generates a list of fake incident data.
803
788
 
804
789
  Args:
805
790
  count (int): The number of incidents to generate.
806
- fields (str, optional): A comma-separated list of incident fields to include in the output. If None,
807
- all fields will be included. Valid options are: 'id', 'duration', 'type', 'analyst', 'severity',
808
- 'description', 'events'.
809
- vendor: Optional. The vendor.
810
- product: Optional. The product.
811
- version: Optional. The version.
812
- datetime_iso: Optional. The starting datetime_iso for the syslog messages. If not provided, a random time during
813
- observables: An observables object. If not provided, random objservable will be generated and used.
814
- required_fields: Optional. A list of fields that are required to present in the generated data, whether from
815
- observables or randomely.
791
+ fields (str, optional): Comma-separated incident fields to include. If None, all fields are included.
792
+ vendor, product, version (Optional[str]): Details about the event source.
793
+ datetime_iso (Optional[datetime]): Base timestamp for the incidents.
794
+ observables (Optional[Observables]): Optional observables object to provide values.
795
+ required_fields (Optional[str]): Required fields for the events.
816
796
 
817
797
  Returns:
818
- List[Dict]: A list of incident dictionaries. Each dictionary contains the following fields:
819
- - 'id' (int): A unique identifier for the incident.
820
- - 'type' (str): The type of incident.
821
- - 'duration' (int): The duration of the incident in hours.
822
- - 'analyst' (str): The name of the analyst assigned to the incident.
823
- - 'severity' (str, optional): The severity of the incident. Only included if 'severity' is specified
824
- in the 'fields' argument.
825
- - 'description' (str, optional): A brief description of the incident. Only included if 'description' is
826
- specified in the 'fields' argument.
827
- - 'events' (List[Dict], optional): A list of event dictionaries associated with the incident.
828
-
829
- Example:
830
- >>> incidents(count=3, fields='id,type,severity')
831
- [
832
- {'id': 1, 'type': 'Lateral Movement', 'severity': 'Critical'},
833
- {'id': 2, 'type': 'Access Violation', 'severity': 'High'},
834
- {'id': 3, 'type': 'Account Compromised', 'severity': 'Low'}
835
- ]
798
+ List[Dict]: A list of incident dictionaries.
836
799
  """
837
800
  incidents = []
838
- faker = 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)]
839
807
 
840
- incident_ids = set()
841
-
842
- incident_types = observables.incident_types if observables and observables.incident_types \
843
- else INCIDENTS_TYPES
844
- analysts = observables.analysts if observables and observables.analysts \
845
- else [faker.unique.first_name() for _ in range(10)]
846
- analyst_incident_map = {}
847
- for analyst in analysts:
848
- mapped_incident_type = incident_types.pop(0)
849
- analyst_incident_map[analyst] = mapped_incident_type
850
- incident_types.append(mapped_incident_type)
808
+ incident_type_cycle = itertools.cycle(incident_types)
851
809
  for i in range(count):
852
- incident = {}
810
+ incident_id = i + 1 # Simplify unique ID generation
853
811
  duration = random.randint(1, 5)
854
- while True:
855
- incident_id = random.randint(1, count)
856
- if incident_id not in incident_ids:
857
- incident_ids.add(incident_id)
858
- break
859
- incident_type = random.choice(incident_types)
812
+ incident_type = next(incident_type_cycle)
860
813
  analyst = random.choice(analysts)
861
- severity = random.choice(observables.severity) if observables and observables.severity \
862
- else faker.random_int(min=1, max=5)
863
- description = random.choice(observables.terms) if observables and observables.terms \
864
- else Observables.generator(observable_type=ObservableType.TERMS, known=ObservableKnown.BAD, count=1000)
865
- if analyst in analyst_incident_map and random.randint(1, 100) == 2:
866
- incident_type = analyst_incident_map[analyst]
867
- duration = random.randint(1, 2)
868
- if fields:
869
- field_list = fields.split(',')
870
- if 'id' in field_list:
871
- incident['id'] = incident_id
872
- if 'duration' in field_list:
873
- incident['duration'] = duration
874
- if 'type' in field_list:
875
- incident['type'] = incident_type
876
- if 'analyst' in field_list:
877
- incident['analyst'] = analyst
878
- if 'severity' in field_list:
879
- incident['severity'] = severity
880
- if 'description' in field_list:
881
- incident_description = faker.paragraph(nb_sentences=1, ext_word_list=description)
882
- incident['description'] = incident_description
883
- if 'events' in field_list:
884
- incident['events'] = [
885
- {"event": cls.syslog(count=1, datetime_iso=datetime_iso, observables=observables,
886
- required_fields=required_fields)[0]},
887
- {"event": cls.cef(count=1, datetime_iso=datetime_iso, vendor=vendor, product=product, version=version
888
- , observables=observables, required_fields=required_fields)[0]},
889
- {"event": cls.leef(count=1, datetime_iso=datetime_iso, vendor=vendor, product=product,
890
- version=version, observables=observables, required_fields=required_fields)[0]},
891
- {"event": cls.winevent(count=1, datetime_iso=datetime_iso, observables=observables)[0]},
892
- {"event": cls.json(count=1, datetime_iso=datetime_iso, vendor=vendor, product=product,
893
- version=version, observables=observables,
894
- required_fields=required_fields)[0]}
895
- ]
896
- else:
897
- incident = {
898
- "id": incident_id,
899
- "type": incident_type,
900
- "duration": duration,
901
- "analyst": analyst
902
- }
814
+ severity = Events._set_field('severity', observables) or faker.random_int(min=1, max=5)
815
+ description = Events._set_field('terms', observables) or faker.sentence(nb_words=10)
816
+
817
+ # Add base fields
818
+ incident = {}
819
+ field_list = fields.split(',') if fields else ['id', 'duration', 'type', 'analyst', 'severity', 'description', 'events']
820
+ if 'id' in field_list:
821
+ incident['id'] = incident_id
822
+ if 'duration' in field_list:
823
+ incident['duration'] = duration
824
+ if 'type' in field_list:
825
+ incident['type'] = incident_type
826
+ if 'analyst' in field_list:
827
+ incident['analyst'] = analyst
828
+ if 'severity' in field_list:
829
+ incident['severity'] = severity
830
+ if 'description' in field_list:
831
+ incident['description'] = description
832
+
833
+ # Generate associated events for each incident
834
+ if 'events' in field_list:
835
+ incident['events'] = [
836
+ {"event": cls.syslog(count=1, datetime_iso=datetime_iso, observables=observables, required_fields=required_fields)[0]},
837
+ {"event": cls.cef(count=1, datetime_iso=datetime_iso, vendor=vendor, product=product, version=version, observables=observables, required_fields=required_fields)[0]},
838
+ {"event": cls.leef(count=1, datetime_iso=datetime_iso, vendor=vendor, product=product, version=version, observables=observables, required_fields=required_fields)[0]},
839
+ {"event": cls.winevent(count=1, datetime_iso=datetime_iso, observables=observables)[0]},
840
+ {"event": cls.json(count=1, datetime_iso=datetime_iso, vendor=vendor, product=product, version=version, observables=observables, required_fields=required_fields)[0]}
841
+ ]
842
+
903
843
  incidents.append(incident)
844
+
904
845
  return incidents