contentctl 3.6.0__py3-none-any.whl → 4.0.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (142) hide show
  1. contentctl/actions/build.py +89 -0
  2. contentctl/actions/detection_testing/DetectionTestingManager.py +48 -49
  3. contentctl/actions/detection_testing/GitService.py +148 -230
  4. contentctl/actions/detection_testing/infrastructures/DetectionTestingInfrastructure.py +14 -24
  5. contentctl/actions/detection_testing/infrastructures/DetectionTestingInfrastructureContainer.py +43 -17
  6. contentctl/actions/detection_testing/views/DetectionTestingView.py +3 -2
  7. contentctl/actions/detection_testing/views/DetectionTestingViewFile.py +0 -8
  8. contentctl/actions/doc_gen.py +1 -1
  9. contentctl/actions/initialize.py +28 -65
  10. contentctl/actions/inspect.py +260 -0
  11. contentctl/actions/new_content.py +106 -13
  12. contentctl/actions/release_notes.py +168 -144
  13. contentctl/actions/reporting.py +24 -13
  14. contentctl/actions/test.py +39 -20
  15. contentctl/actions/validate.py +25 -48
  16. contentctl/contentctl.py +196 -754
  17. contentctl/enrichments/attack_enrichment.py +69 -19
  18. contentctl/enrichments/cve_enrichment.py +28 -13
  19. contentctl/helper/link_validator.py +24 -26
  20. contentctl/helper/utils.py +7 -3
  21. contentctl/input/director.py +139 -201
  22. contentctl/input/new_content_questions.py +63 -61
  23. contentctl/input/sigma_converter.py +1 -2
  24. contentctl/input/ssa_detection_builder.py +16 -7
  25. contentctl/input/yml_reader.py +4 -3
  26. contentctl/objects/abstract_security_content_objects/detection_abstract.py +487 -154
  27. contentctl/objects/abstract_security_content_objects/security_content_object_abstract.py +155 -51
  28. contentctl/objects/alert_action.py +40 -0
  29. contentctl/objects/atomic.py +212 -0
  30. contentctl/objects/baseline.py +44 -43
  31. contentctl/objects/baseline_tags.py +69 -20
  32. contentctl/objects/config.py +857 -125
  33. contentctl/objects/constants.py +0 -1
  34. contentctl/objects/correlation_search.py +1 -1
  35. contentctl/objects/data_source.py +2 -4
  36. contentctl/objects/deployment.py +61 -21
  37. contentctl/objects/deployment_email.py +2 -2
  38. contentctl/objects/deployment_notable.py +4 -4
  39. contentctl/objects/deployment_phantom.py +2 -2
  40. contentctl/objects/deployment_rba.py +3 -4
  41. contentctl/objects/deployment_scheduling.py +2 -3
  42. contentctl/objects/deployment_slack.py +2 -2
  43. contentctl/objects/detection.py +1 -5
  44. contentctl/objects/detection_tags.py +210 -119
  45. contentctl/objects/enums.py +312 -24
  46. contentctl/objects/integration_test.py +1 -1
  47. contentctl/objects/integration_test_result.py +0 -2
  48. contentctl/objects/investigation.py +62 -53
  49. contentctl/objects/investigation_tags.py +30 -6
  50. contentctl/objects/lookup.py +80 -31
  51. contentctl/objects/macro.py +29 -45
  52. contentctl/objects/mitre_attack_enrichment.py +29 -5
  53. contentctl/objects/observable.py +3 -7
  54. contentctl/objects/playbook.py +60 -30
  55. contentctl/objects/playbook_tags.py +45 -8
  56. contentctl/objects/security_content_object.py +1 -5
  57. contentctl/objects/ssa_detection.py +8 -4
  58. contentctl/objects/ssa_detection_tags.py +19 -26
  59. contentctl/objects/story.py +142 -44
  60. contentctl/objects/story_tags.py +46 -33
  61. contentctl/objects/unit_test.py +7 -2
  62. contentctl/objects/unit_test_attack_data.py +10 -19
  63. contentctl/objects/unit_test_baseline.py +1 -1
  64. contentctl/objects/unit_test_old.py +4 -3
  65. contentctl/objects/unit_test_result.py +5 -3
  66. contentctl/objects/unit_test_ssa.py +31 -0
  67. contentctl/output/api_json_output.py +202 -130
  68. contentctl/output/attack_nav_output.py +20 -9
  69. contentctl/output/attack_nav_writer.py +3 -3
  70. contentctl/output/ba_yml_output.py +3 -3
  71. contentctl/output/conf_output.py +125 -391
  72. contentctl/output/conf_writer.py +169 -31
  73. contentctl/output/jinja_writer.py +2 -2
  74. contentctl/output/json_writer.py +17 -5
  75. contentctl/output/new_content_yml_output.py +8 -7
  76. contentctl/output/svg_output.py +17 -27
  77. contentctl/output/templates/analyticstories_detections.j2 +8 -4
  78. contentctl/output/templates/analyticstories_investigations.j2 +1 -1
  79. contentctl/output/templates/analyticstories_stories.j2 +6 -6
  80. contentctl/output/templates/app.conf.j2 +2 -2
  81. contentctl/output/templates/app.manifest.j2 +2 -2
  82. contentctl/output/templates/detection_coverage.j2 +6 -8
  83. contentctl/output/templates/doc_detection_page.j2 +2 -2
  84. contentctl/output/templates/doc_detections.j2 +2 -2
  85. contentctl/output/templates/doc_stories.j2 +1 -1
  86. contentctl/output/templates/es_investigations_investigations.j2 +1 -1
  87. contentctl/output/templates/es_investigations_stories.j2 +1 -1
  88. contentctl/output/templates/header.j2 +2 -1
  89. contentctl/output/templates/macros.j2 +6 -10
  90. contentctl/output/templates/savedsearches_baselines.j2 +5 -5
  91. contentctl/output/templates/savedsearches_detections.j2 +36 -33
  92. contentctl/output/templates/savedsearches_investigations.j2 +4 -4
  93. contentctl/output/templates/transforms.j2 +4 -4
  94. contentctl/output/yml_writer.py +2 -2
  95. contentctl/templates/app_template/README.md +7 -0
  96. contentctl/{output/templates/splunk_app → templates/app_template}/default/data/ui/nav/default.xml +1 -0
  97. contentctl/templates/app_template/lookups/mitre_enrichment.csv +638 -0
  98. contentctl/templates/deployments/{00_default_anomaly.yml → escu_default_configuration_anomaly.yml} +1 -2
  99. contentctl/templates/deployments/{00_default_baseline.yml → escu_default_configuration_baseline.yml} +1 -2
  100. contentctl/templates/deployments/{00_default_correlation.yml → escu_default_configuration_correlation.yml} +2 -2
  101. contentctl/templates/deployments/{00_default_hunting.yml → escu_default_configuration_hunting.yml} +2 -2
  102. contentctl/templates/deployments/{00_default_ttp.yml → escu_default_configuration_ttp.yml} +1 -2
  103. contentctl/templates/detections/anomalous_usage_of_7zip.yml +0 -1
  104. contentctl/templates/stories/cobalt_strike.yml +0 -1
  105. {contentctl-3.6.0.dist-info → contentctl-4.0.2.dist-info}/METADATA +36 -15
  106. contentctl-4.0.2.dist-info/RECORD +168 -0
  107. contentctl/actions/detection_testing/DataManipulation.py +0 -149
  108. contentctl/actions/generate.py +0 -91
  109. contentctl/helper/config_handler.py +0 -75
  110. contentctl/input/baseline_builder.py +0 -66
  111. contentctl/input/basic_builder.py +0 -58
  112. contentctl/input/detection_builder.py +0 -370
  113. contentctl/input/investigation_builder.py +0 -42
  114. contentctl/input/new_content_generator.py +0 -95
  115. contentctl/input/playbook_builder.py +0 -68
  116. contentctl/input/story_builder.py +0 -106
  117. contentctl/objects/app.py +0 -214
  118. contentctl/objects/repo_config.py +0 -163
  119. contentctl/objects/test_config.py +0 -630
  120. contentctl/output/templates/macros_detections.j2 +0 -7
  121. contentctl/output/templates/splunk_app/README.md +0 -7
  122. contentctl-3.6.0.dist-info/RECORD +0 -176
  123. /contentctl/{output/templates/splunk_app → templates/app_template}/README/essoc_story_detail.txt +0 -0
  124. /contentctl/{output/templates/splunk_app → templates/app_template}/README/essoc_summary.txt +0 -0
  125. /contentctl/{output/templates/splunk_app → templates/app_template}/README/essoc_usage_dashboard.txt +0 -0
  126. /contentctl/{output/templates/splunk_app → templates/app_template}/default/analytic_stories.conf +0 -0
  127. /contentctl/{output/templates/splunk_app → templates/app_template}/default/app.conf +0 -0
  128. /contentctl/{output/templates/splunk_app → templates/app_template}/default/commands.conf +0 -0
  129. /contentctl/{output/templates/splunk_app → templates/app_template}/default/content-version.conf +0 -0
  130. /contentctl/{output/templates/splunk_app → templates/app_template}/default/data/ui/views/escu_summary.xml +0 -0
  131. /contentctl/{output/templates/splunk_app → templates/app_template}/default/data/ui/views/feedback.xml +0 -0
  132. /contentctl/{output/templates/splunk_app → templates/app_template}/default/distsearch.conf +0 -0
  133. /contentctl/{output/templates/splunk_app → templates/app_template}/default/usage_searches.conf +0 -0
  134. /contentctl/{output/templates/splunk_app → templates/app_template}/default/use_case_library.conf +0 -0
  135. /contentctl/{output/templates/splunk_app → templates/app_template}/metadata/default.meta +0 -0
  136. /contentctl/{output/templates/splunk_app → templates/app_template}/static/appIcon.png +0 -0
  137. /contentctl/{output/templates/splunk_app → templates/app_template}/static/appIconAlt.png +0 -0
  138. /contentctl/{output/templates/splunk_app → templates/app_template}/static/appIconAlt_2x.png +0 -0
  139. /contentctl/{output/templates/splunk_app → templates/app_template}/static/appIcon_2x.png +0 -0
  140. {contentctl-3.6.0.dist-info → contentctl-4.0.2.dist-info}/LICENSE.md +0 -0
  141. {contentctl-3.6.0.dist-info → contentctl-4.0.2.dist-info}/WHEEL +0 -0
  142. {contentctl-3.6.0.dist-info → contentctl-4.0.2.dist-info}/entry_points.txt +0 -0
@@ -6,22 +6,22 @@
6
6
  action.escu = 0
7
7
  action.escu.enabled = 1
8
8
  {% if detection.status == "deprecated" %}
9
- description = **WARNING**, this detection has been marked **DEPRECATED** by the Splunk Threat Research Team. This means that it will no longer be maintained or supported. If you have any questions feel free to email us at: research@splunk.com. {{ detection.description }}
9
+ description = **WARNING**, this detection has been marked **DEPRECATED** by the Splunk Threat Research Team. This means that it will no longer be maintained or supported. If you have any questions feel free to email us at: research@splunk.com. {{ detection.description | escapeNewlines() }}
10
10
  {% elif detection.status == "experimental" %}
11
- description = **WARNING**, this detection is marked **EXPERIMENTAL** by the Splunk Threat Research Team. This means that the detection has been manually tested but we do not have the associated attack data to perform automated testing or cannot share this attack dataset due to its sensitive nature. If you have any questions feel free to email us at: research@splunk.com. {{ detection.description }}
11
+ description = **WARNING**, this detection is marked **EXPERIMENTAL** by the Splunk Threat Research Team. This means that the detection has been manually tested but we do not have the associated attack data to perform automated testing or cannot share this attack dataset due to its sensitive nature. If you have any questions feel free to email us at: research@splunk.com. {{ detection.description | escapeNewlines() }}
12
12
  {% else %}
13
- description = {{ detection.description }}
13
+ description = {{ detection.description | escapeNewlines() }}
14
14
  {% endif %}
15
15
  action.escu.mappings = {{ detection.mappings | tojson }}
16
16
  action.escu.data_models = {{ detection.datamodel | tojson }}
17
- action.escu.eli5 = {{ detection.description }}
18
- {% if detection.how_to_implement is defined %}
19
- action.escu.how_to_implement = {{ detection.how_to_implement }}
17
+ action.escu.eli5 = {{ detection.description | escapeNewlines() }}
18
+ {% if detection.how_to_implement %}
19
+ action.escu.how_to_implement = {{ detection.how_to_implement | escapeNewlines() }}
20
20
  {% else %}
21
21
  action.escu.how_to_implement = none
22
22
  {% endif %}
23
- {% if detection.known_false_positives is defined %}
24
- action.escu.known_false_positives = {{ detection.known_false_positives }}
23
+ {% if detection.known_false_positives %}
24
+ action.escu.known_false_positives = {{ detection.known_false_positives | escapeNewlines() }}
25
25
  {% else %}
26
26
  action.escu.known_false_positives = None
27
27
  {% endif %}
@@ -33,16 +33,19 @@ action.escu.search_type = detection
33
33
  {% if detection.tags.product is defined %}
34
34
  action.escu.product = {{ detection.tags.product | tojson }}
35
35
  {% endif %}
36
- {% if detection.providing_technologies is defined %}
36
+ {% if detection.tags.atomic_guid %}
37
+ action.escu.atomic_red_team_guids = {{ detection.tags.getAtomicGuidStringArray() | tojson }}
38
+ {% endif %}
39
+ {% if detection.providing_technologies | length > 0 %}
37
40
  action.escu.providing_technologies = {{ detection.providing_technologies | tojson }}
38
41
  {% else %}
39
- action.escu.providing_technologies = []
42
+ action.escu.providing_technologies = null
40
43
  {% endif %}
41
- {% if detection.tags.analytic_story is defined %}
42
- action.escu.analytic_story = {{ detection.tags.analytic_story | tojson }}
43
- {% if detection.deployment.rba.enabled is defined %}
44
+ {% if detection.tags.analytic_story %}
45
+ action.escu.analytic_story = {{ objectListToNameList(detection.tags.analytic_story) | tojson }}
46
+ {% if detection.deployment.alert_action.rba.enabled%}
44
47
  action.risk = 1
45
- action.risk.param._risk_message = {{ detection.tags.message }}
48
+ action.risk.param._risk_message = {{ detection.tags.message | escapeNewlines() }}
46
49
  action.risk.param._risk = {{ detection.risk | tojson }}
47
50
  action.risk.param._risk_score = 0
48
51
  action.risk.param.verbose = 0
@@ -69,34 +72,34 @@ action.correlationsearch.metadata = {{ detection.getMetadata() | tojson }}
69
72
  schedule_window = {{ detection.deployment.scheduling.schedule_window }}
70
73
  {% endif %}
71
74
  {% if detection.deployment is defined %}
72
- {% if detection.deployment.notable.rule_title is defined %}
75
+ {% if detection.deployment.alert_action.notable %}
73
76
  action.notable = 1
74
- {% if detection.nes_fields is defined %}
77
+ {% if detection.nes_fields %}
75
78
  action.notable.param.nes_fields = {{ detection.nes_fields }}
76
79
  {% endif %}
77
- action.notable.param.rule_description = {{ detection.deployment.notable.rule_description | custom_jinja2_enrichment_filter(detection) }}
78
- action.notable.param.rule_title = {% if detection.type | lower == "correlation" %}RBA: {{ detection.deployment.notable.rule_title | custom_jinja2_enrichment_filter(detection) }}{% else %}{{ detection.deployment.notable.rule_title | custom_jinja2_enrichment_filter(detection) }}{% endif +%}
79
- action.notable.param.security_domain = {{ detection.tags.security_domain }}
80
+ action.notable.param.rule_description = {{ detection.deployment.alert_action.notable.rule_description | custom_jinja2_enrichment_filter(detection) | escapeNewlines()}}
81
+ action.notable.param.rule_title = {% if detection.type | lower == "correlation" %}RBA: {{ detection.deployment.alert_action.notable.rule_title | custom_jinja2_enrichment_filter(detection) }}{% else %}{{ detection.deployment.alert_action.notable.rule_title | custom_jinja2_enrichment_filter(detection) }}{% endif +%}
82
+ action.notable.param.security_domain = {{ detection.tags.security_domain.value }}
80
83
  action.notable.param.severity = high
81
84
  {% endif %}
82
- {% if detection.deployment.email.to is defined %}
83
- action.email.subject.alert = {{ detection.deployment.email.subject | custom_jinja2_enrichment_filter(detection) }}
84
- action.email.to = {{ detection.deployment.email.to }}
85
- action.email.message.alert = {{ detection.deployment.email.message | custom_jinja2_enrichment_filter(detection) }}
85
+ {% if detection.deployment.alert_action.email %}
86
+ action.email.subject.alert = {{ detection.deployment.alert_action.email.subject | custom_jinja2_enrichment_filter(detection) | escapeNewlines() }}
87
+ action.email.to = {{ detection.deployment.alert_action.email.to }}
88
+ action.email.message.alert = {{ detection.deployment.alert_action.email.message | custom_jinja2_enrichment_filter(detection) | escapeNewlines() }}
86
89
  action.email.useNSSubject = 1
87
90
  {% endif %}
88
- {% if detection.deployment.slack.channel is defined %}
91
+ {% if detection.deployment.alert_action.slack %}
89
92
  action.slack = 1
90
- action.slack.param.channel = {{ detection.deployment.slack.channel | custom_jinja2_enrichment_filter(detection) }}
91
- action.slack.param.message = {{ detection.deployment.slack.message | custom_jinja2_enrichment_filter(detection) }}
93
+ action.slack.param.channel = {{ detection.deployment.alert_action.slack.channel | custom_jinja2_enrichment_filter(detection) | escapeNewlines() }}
94
+ action.slack.param.message = {{ detection.deployment.alert_action.slack.message | custom_jinja2_enrichment_filter(detection) | escapeNewlines() }}
92
95
  {% endif %}
93
- {% if detection.deployment.phantom.phantom_server is defined %}
96
+ {% if detection.deployment.alert_action.phantom%}
94
97
  action.sendtophantom = 1
95
- action.sendtophantom.param._cam_workers = {{ detection.deployment.phantom.cam_workers | custom_jinja2_enrichment_filter(detection) }}
96
- action.sendtophantom.param.label = {{ detection.deployment.phantom.label | custom_jinja2_enrichment_filter(detection) }}
97
- action.sendtophantom.param.phantom_server = {{ detection.deployment.phantom.phantom_server | custom_jinja2_enrichment_filter(detection) }}
98
- action.sendtophantom.param.sensitivity = {{ detection.deployment.phantom.sensitivity | custom_jinja2_enrichment_filter(detection) }}
99
- action.sendtophantom.param.severity = {{ detection.deployment.phantom.severity | custom_jinja2_enrichment_filter(detection) }}
98
+ action.sendtophantom.param._cam_workers = {{ detection.deployment.alert_action.phantom.cam_workers | custom_jinja2_enrichment_filter(detection) }}
99
+ action.sendtophantom.param.label = {{ detection.deployment.alert_action.phantom.label | custom_jinja2_enrichment_filter(detection) }}
100
+ action.sendtophantom.param.phantom_server = {{ detection.deployment.alert_action.phantom.phantom_server | custom_jinja2_enrichment_filter(detection) }}
101
+ action.sendtophantom.param.sensitivity = {{ detection.deployment.alert_action.phantom.sensitivity | custom_jinja2_enrichment_filter(detection) }}
102
+ action.sendtophantom.param.severity = {{ detection.deployment.alert_action.phantom.severity | custom_jinja2_enrichment_filter(detection) }}
100
103
  {% endif %}
101
104
  {% endif %}
102
105
  alert.digest_mode = 1
@@ -112,7 +115,7 @@ relation = greater than
112
115
  quantity = 0
113
116
  realtime_schedule = 0
114
117
  is_visible = false
115
- search = {{ detection.search }}
118
+ search = {{ detection.search | escapeNewlines() }}
116
119
 
117
120
  {% endif %}
118
121
  {% endfor %}
@@ -10,11 +10,11 @@ action.escu = 0
10
10
  action.escu.enabled = 1
11
11
  action.escu.search_type = investigative
12
12
  action.escu.full_search_name = {{APP_NAME}} - {{ detection.name }} - Response Task
13
- description = {{ detection.description }}
13
+ description = {{ detection.description | escapeNewlines() }}
14
14
  action.escu.creation_date = {{ detection.date }}
15
15
  action.escu.modification_date = {{ detection.date }}
16
16
  {% if detection.tags.analytic_story is defined %}
17
- action.escu.analytic_story = {{ detection.tags.analytic_story | tojson }}
17
+ action.escu.analytic_story = {{ objectListToNameList(detection.tags.analytic_story) | tojson }}
18
18
  {% else %}
19
19
  action.escu.analytic_story = []
20
20
  {% endif %}
@@ -22,13 +22,13 @@ action.escu.earliest_time_offset = 3600
22
22
  action.escu.latest_time_offset = 86400
23
23
  action.escu.providing_technologies = []
24
24
  action.escu.data_models = {{ detection.datamodel | tojson }}
25
- action.escu.eli5 = {{ detection.description }}
25
+ action.escu.eli5 = {{ detection.description | escapeNewlines() }}
26
26
  action.escu.how_to_implement = none
27
27
  action.escu.known_false_positives = None at this time
28
28
  disabled = true
29
29
  schedule_window = auto
30
30
  is_visible = false
31
- search = {{ detection.search }}
31
+ search = {{ detection.search | escapeNewlines() }}
32
32
 
33
33
  {% endif %}
34
34
  {% endif %}
@@ -2,19 +2,19 @@
2
2
  {% for lookup in objects %}
3
3
  [{{ lookup.name }}]
4
4
  {% if lookup.filename is defined and lookup.filename != None %}
5
- filename = {{ lookup.filename }}
5
+ filename = {{ lookup.filename.name }}
6
6
  {% else %}
7
7
  collection = {{ lookup.collection }}
8
8
  external_type = kvstore
9
9
  {% endif %}
10
10
  {% if lookup.default_match is defined and lookup.default_match != None %}
11
- default_match = {{ lookup.default_match }}
11
+ default_match = {{ lookup.default_match | lower }}
12
12
  {% endif %}
13
13
  {% if lookup.case_sensitive_match is defined and lookup.case_sensitive_match != None %}
14
- case_sensitive_match = {{ lookup.case_sensitive_match }}
14
+ case_sensitive_match = {{ lookup.case_sensitive_match | lower }}
15
15
  {% endif %}
16
16
  {% if lookup.description is defined and lookup.description != None %}
17
- # description = {{ lookup.description }}
17
+ # description = {{ lookup.description | escapeNewlines() }}
18
18
  {% endif %}
19
19
  {% if lookup.match_type is defined and lookup.match_type != None %}
20
20
  match_type = {{ lookup.match_type }}
@@ -1,11 +1,11 @@
1
1
 
2
2
  import yaml
3
-
3
+ from typing import Any
4
4
 
5
5
  class YmlWriter:
6
6
 
7
7
  @staticmethod
8
- def writeYmlFile(file_path : str, obj : dict) -> None:
8
+ def writeYmlFile(file_path : str, obj : dict[Any,Any]) -> None:
9
9
 
10
10
  with open(file_path, 'w') as outfile:
11
11
  yaml.safe_dump(obj, outfile, default_flow_style=False, sort_keys=False)
@@ -0,0 +1,7 @@
1
+ # Content Pack built with contentctl
2
+
3
+ This application was built using the open source [contentctl](https://github.com/splunk/contentctl) tool published by the Splunk Threat Research Team (STRT).
4
+
5
+ For questions about the tool, please see the repo or contact STRT at research@splunk.com
6
+
7
+ Feel free to update this file to include your own valuable README information.
@@ -2,5 +2,6 @@
2
2
  <view name="escu_summary" default="true"/>
3
3
  <view name="feedback"/>
4
4
  <view name="search"/>
5
+ <view name="dashboards"/>
5
6
  <a href="http://docs.splunk.com/Documentation/ESSOC">Docs</a>
6
7
  </nav>