contentctl 4.3.0__tar.gz → 4.3.1__tar.gz
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.
- {contentctl-4.3.0 → contentctl-4.3.1}/PKG-INFO +2 -2
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/actions/detection_testing/infrastructures/DetectionTestingInfrastructure.py +60 -24
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/objects/abstract_security_content_objects/detection_abstract.py +5 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/objects/constants.py +5 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/objects/observable.py +5 -3
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/templates/detections/endpoint/anomalous_usage_of_7zip.yml +2 -2
- {contentctl-4.3.0 → contentctl-4.3.1}/pyproject.toml +2 -2
- {contentctl-4.3.0 → contentctl-4.3.1}/LICENSE.md +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/README.md +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/__init__.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/actions/build.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/actions/deploy_acs.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/actions/detection_testing/DetectionTestingManager.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/actions/detection_testing/GitService.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/actions/detection_testing/generate_detection_coverage_badge.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/actions/detection_testing/infrastructures/DetectionTestingInfrastructureContainer.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/actions/detection_testing/infrastructures/DetectionTestingInfrastructureServer.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/actions/detection_testing/progress_bar.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/actions/detection_testing/views/DetectionTestingView.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/actions/detection_testing/views/DetectionTestingViewCLI.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/actions/detection_testing/views/DetectionTestingViewFile.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/actions/detection_testing/views/DetectionTestingViewWeb.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/actions/doc_gen.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/actions/initialize.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/actions/initialize_old.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/actions/inspect.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/actions/new_content.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/actions/release_notes.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/actions/reporting.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/actions/test.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/actions/validate.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/api.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/contentctl.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/enrichments/attack_enrichment.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/enrichments/cve_enrichment.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/enrichments/splunk_app_enrichment.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/helper/link_validator.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/helper/logger.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/helper/splunk_app.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/helper/utils.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/input/director.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/input/new_content_questions.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/input/yml_reader.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/objects/abstract_security_content_objects/security_content_object_abstract.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/objects/alert_action.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/objects/atomic.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/objects/base_test.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/objects/base_test_result.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/objects/baseline.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/objects/baseline_tags.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/objects/config.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/objects/correlation_search.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/objects/data_source.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/objects/deployment.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/objects/deployment_email.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/objects/deployment_notable.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/objects/deployment_phantom.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/objects/deployment_rba.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/objects/deployment_scheduling.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/objects/deployment_slack.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/objects/detection.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/objects/detection_tags.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/objects/enums.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/objects/errors.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/objects/event_source.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/objects/integration_test.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/objects/integration_test_result.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/objects/investigation.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/objects/investigation_tags.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/objects/lookup.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/objects/macro.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/objects/mitre_attack_enrichment.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/objects/notable_action.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/objects/notable_event.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/objects/playbook.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/objects/playbook_tags.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/objects/risk_analysis_action.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/objects/risk_event.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/objects/risk_object.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/objects/security_content_object.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/objects/ssa_detection.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/objects/ssa_detection_tags.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/objects/story.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/objects/story_tags.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/objects/test_group.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/objects/threat_object.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/objects/unit_test.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/objects/unit_test_attack_data.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/objects/unit_test_baseline.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/objects/unit_test_old.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/objects/unit_test_result.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/objects/unit_test_ssa.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/output/api_json_output.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/output/attack_nav_output.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/output/attack_nav_writer.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/output/conf_output.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/output/conf_writer.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/output/data_source_writer.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/output/detection_writer.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/output/doc_md_output.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/output/jinja_writer.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/output/json_writer.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/output/new_content_yml_output.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/output/svg_output.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/output/templates/analyticstories_detections.j2 +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/output/templates/analyticstories_investigations.j2 +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/output/templates/analyticstories_stories.j2 +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/output/templates/app.conf.j2 +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/output/templates/app.manifest.j2 +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/output/templates/collections.j2 +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/output/templates/content-version.j2 +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/output/templates/detection_count.j2 +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/output/templates/detection_coverage.j2 +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/output/templates/doc_detection_page.j2 +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/output/templates/doc_detections.j2 +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/output/templates/doc_navigation.j2 +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/output/templates/doc_navigation_pages.j2 +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/output/templates/doc_playbooks.j2 +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/output/templates/doc_playbooks_page.j2 +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/output/templates/doc_stories.j2 +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/output/templates/doc_story_page.j2 +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/output/templates/es_investigations_investigations.j2 +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/output/templates/es_investigations_stories.j2 +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/output/templates/finding_report.j2 +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/output/templates/header.j2 +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/output/templates/macros.j2 +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/output/templates/panel.j2 +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/output/templates/savedsearches_baselines.j2 +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/output/templates/savedsearches_detections.j2 +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/output/templates/savedsearches_investigations.j2 +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/output/templates/transforms.j2 +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/output/templates/workflow_actions.j2 +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/output/yml_output.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/output/yml_writer.py +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/templates/README.md +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/templates/app_default.yml +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/templates/app_template/README/essoc_story_detail.txt +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/templates/app_template/README/essoc_summary.txt +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/templates/app_template/README/essoc_usage_dashboard.txt +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/templates/app_template/README.md +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/templates/app_template/default/analytic_stories.conf +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/templates/app_template/default/app.conf +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/templates/app_template/default/commands.conf +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/templates/app_template/default/content-version.conf +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/templates/app_template/default/data/ui/nav/default.xml +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/templates/app_template/default/data/ui/views/escu_summary.xml +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/templates/app_template/default/data/ui/views/feedback.xml +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/templates/app_template/default/use_case_library.conf +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/templates/app_template/lookups/mitre_enrichment.csv +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/templates/app_template/metadata/default.meta +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/templates/app_template/static/appIcon.png +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/templates/app_template/static/appIconAlt.png +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/templates/app_template/static/appIconAlt_2x.png +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/templates/app_template/static/appIcon_2x.png +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/templates/data_sources/sysmon_eventid_1.yml +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/templates/datamodels_cim.conf +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/templates/datamodels_custom.conf +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/templates/deployments/escu_default_configuration_anomaly.yml +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/templates/deployments/escu_default_configuration_baseline.yml +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/templates/deployments/escu_default_configuration_correlation.yml +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/templates/deployments/escu_default_configuration_hunting.yml +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/templates/deployments/escu_default_configuration_ttp.yml +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/templates/detections/application/.gitkeep +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/templates/detections/cloud/.gitkeep +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/templates/detections/network/.gitkeep +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/templates/detections/web/.gitkeep +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/templates/macros/security_content_ctime.yml +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/templates/macros/security_content_summariesonly.yml +0 -0
- {contentctl-4.3.0 → contentctl-4.3.1}/contentctl/templates/stories/cobalt_strike.yml +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: contentctl
|
|
3
|
-
Version: 4.3.
|
|
3
|
+
Version: 4.3.1
|
|
4
4
|
Summary: Splunk Content Control Tool
|
|
5
5
|
License: Apache 2.0
|
|
6
6
|
Author: STRT
|
|
@@ -22,7 +22,7 @@ Requires-Dist: pygit2 (>=1.14.1,<2.0.0)
|
|
|
22
22
|
Requires-Dist: questionary (>=2.0.1,<3.0.0)
|
|
23
23
|
Requires-Dist: requests (>=2.32.2,<2.33.0)
|
|
24
24
|
Requires-Dist: semantic-version (>=2.10.0,<3.0.0)
|
|
25
|
-
Requires-Dist: setuptools (>=69.5.1,<
|
|
25
|
+
Requires-Dist: setuptools (>=69.5.1,<74.0.0)
|
|
26
26
|
Requires-Dist: splunk-sdk (>=2.0.1,<3.0.0)
|
|
27
27
|
Requires-Dist: tqdm (>=4.66.4,<5.0.0)
|
|
28
28
|
Requires-Dist: tyro (>=0.8.3,<0.9.0)
|
|
@@ -1060,7 +1060,9 @@ class DetectionTestingInfrastructure(BaseModel, abc.ABC):
|
|
|
1060
1060
|
results = JSONResultsReader(job.results(output_mode="json"))
|
|
1061
1061
|
|
|
1062
1062
|
# Consolidate a set of the distinct observable field names
|
|
1063
|
-
observable_fields_set = set([o.name for o in detection.tags.observable])
|
|
1063
|
+
observable_fields_set = set([o.name for o in detection.tags.observable]) # keeping this around for later
|
|
1064
|
+
risk_object_fields_set = set([o.name for o in detection.tags.observable if "Victim" in o.role ]) # just the "Risk Objects"
|
|
1065
|
+
threat_object_fields_set = set([o.name for o in detection.tags.observable if "Attacker" in o.role]) # just the "threat objects"
|
|
1064
1066
|
|
|
1065
1067
|
# Ensure the search had at least one result
|
|
1066
1068
|
if int(job.content.get("resultCount", "0")) > 0:
|
|
@@ -1068,7 +1070,10 @@ class DetectionTestingInfrastructure(BaseModel, abc.ABC):
|
|
|
1068
1070
|
test.result = UnitTestResult()
|
|
1069
1071
|
|
|
1070
1072
|
# Initialize the collection of fields that are empty that shouldn't be
|
|
1073
|
+
present_threat_objects: set[str] = set()
|
|
1071
1074
|
empty_fields: set[str] = set()
|
|
1075
|
+
|
|
1076
|
+
|
|
1072
1077
|
|
|
1073
1078
|
# Filter out any messages in the results
|
|
1074
1079
|
for result in results:
|
|
@@ -1077,30 +1082,50 @@ class DetectionTestingInfrastructure(BaseModel, abc.ABC):
|
|
|
1077
1082
|
|
|
1078
1083
|
# If not a message, it is a dict and we will process it
|
|
1079
1084
|
results_fields_set = set(result.keys())
|
|
1085
|
+
# Guard against first events (relevant later)
|
|
1080
1086
|
|
|
1081
|
-
# Identify any
|
|
1082
|
-
|
|
1083
|
-
if len(
|
|
1087
|
+
# Identify any risk object fields that are not available in the results
|
|
1088
|
+
missing_risk_objects = risk_object_fields_set - results_fields_set
|
|
1089
|
+
if len(missing_risk_objects) > 0:
|
|
1084
1090
|
# Report a failure in such cases
|
|
1085
|
-
e = Exception(f"The observable field(s) {
|
|
1091
|
+
e = Exception(f"The observable field(s) {missing_risk_objects} are missing in the detection results")
|
|
1086
1092
|
test.result.set_job_content(
|
|
1087
1093
|
job.content,
|
|
1088
1094
|
self.infrastructure,
|
|
1089
|
-
TestResultStatus.
|
|
1095
|
+
TestResultStatus.FAIL,
|
|
1090
1096
|
exception=e,
|
|
1091
1097
|
duration=time.time() - search_start_time,
|
|
1092
1098
|
)
|
|
1093
1099
|
|
|
1094
|
-
return
|
|
1100
|
+
return
|
|
1095
1101
|
|
|
1096
|
-
# If we find one or more fields that contain the string "null" then they were
|
|
1102
|
+
# If we find one or more risk object fields that contain the string "null" then they were
|
|
1097
1103
|
# not populated and we should throw an error. This can happen if there is a typo
|
|
1098
1104
|
# on a field. In this case, the field will appear but will not contain any values
|
|
1099
|
-
current_empty_fields = set()
|
|
1105
|
+
current_empty_fields: set[str] = set()
|
|
1106
|
+
|
|
1100
1107
|
for field in observable_fields_set:
|
|
1101
1108
|
if result.get(field, 'null') == 'null':
|
|
1102
|
-
|
|
1103
|
-
|
|
1109
|
+
if field in risk_object_fields_set:
|
|
1110
|
+
e = Exception(f"The risk object field {field} is missing in at least one result.")
|
|
1111
|
+
test.result.set_job_content(
|
|
1112
|
+
job.content,
|
|
1113
|
+
self.infrastructure,
|
|
1114
|
+
TestResultStatus.FAIL,
|
|
1115
|
+
exception=e,
|
|
1116
|
+
duration=time.time() - search_start_time,
|
|
1117
|
+
)
|
|
1118
|
+
return
|
|
1119
|
+
else:
|
|
1120
|
+
if field in threat_object_fields_set:
|
|
1121
|
+
current_empty_fields.add(field)
|
|
1122
|
+
else:
|
|
1123
|
+
if field in threat_object_fields_set:
|
|
1124
|
+
present_threat_objects.add(field)
|
|
1125
|
+
continue
|
|
1126
|
+
|
|
1127
|
+
|
|
1128
|
+
|
|
1104
1129
|
# If everything succeeded up until now, and no empty fields are found in the
|
|
1105
1130
|
# current result, then the search was a success
|
|
1106
1131
|
if len(current_empty_fields) == 0:
|
|
@@ -1114,21 +1139,32 @@ class DetectionTestingInfrastructure(BaseModel, abc.ABC):
|
|
|
1114
1139
|
|
|
1115
1140
|
else:
|
|
1116
1141
|
empty_fields = empty_fields.union(current_empty_fields)
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1142
|
+
|
|
1143
|
+
|
|
1144
|
+
missing_threat_objects = threat_object_fields_set - present_threat_objects
|
|
1145
|
+
# Report a failure if there were empty fields in a threat object in all results
|
|
1146
|
+
if len(missing_threat_objects) > 0:
|
|
1147
|
+
e = Exception(
|
|
1148
|
+
f"One or more required threat object fields {missing_threat_objects} contained 'null' values in all events. "
|
|
1149
|
+
"Is the data being parsed correctly or is there an error in the naming of a field?"
|
|
1122
1150
|
)
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1151
|
+
test.result.set_job_content(
|
|
1152
|
+
job.content,
|
|
1153
|
+
self.infrastructure,
|
|
1154
|
+
TestResultStatus.FAIL,
|
|
1155
|
+
exception=e,
|
|
1156
|
+
duration=time.time() - search_start_time,
|
|
1157
|
+
)
|
|
1158
|
+
return
|
|
1159
|
+
|
|
1130
1160
|
|
|
1131
|
-
|
|
1161
|
+
test.result.set_job_content(
|
|
1162
|
+
job.content,
|
|
1163
|
+
self.infrastructure,
|
|
1164
|
+
TestResultStatus.PASS,
|
|
1165
|
+
duration=time.time() - search_start_time,
|
|
1166
|
+
)
|
|
1167
|
+
return
|
|
1132
1168
|
|
|
1133
1169
|
else:
|
|
1134
1170
|
# Report a failure if there were no results at all
|
|
@@ -290,6 +290,11 @@ class Detection_Abstract(SecurityContentObject):
|
|
|
290
290
|
risk_object['threat_object_field'] = entity.name
|
|
291
291
|
risk_object['threat_object_type'] = "url"
|
|
292
292
|
risk_objects.append(risk_object)
|
|
293
|
+
|
|
294
|
+
elif 'Attacker' in entity.role:
|
|
295
|
+
risk_object['threat_object_field'] = entity.name
|
|
296
|
+
risk_object['threat_object_type'] = entity.type.lower()
|
|
297
|
+
risk_objects.append(risk_object)
|
|
293
298
|
|
|
294
299
|
else:
|
|
295
300
|
risk_object['risk_object_type'] = 'other'
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from pydantic import BaseModel, field_validator
|
|
2
|
-
from contentctl.objects.constants import SES_OBSERVABLE_TYPE_MAPPING,
|
|
2
|
+
from contentctl.objects.constants import SES_OBSERVABLE_TYPE_MAPPING, RBA_OBSERVABLE_ROLE_MAPPING
|
|
3
3
|
|
|
4
4
|
|
|
5
5
|
class Observable(BaseModel):
|
|
@@ -26,10 +26,12 @@ class Observable(BaseModel):
|
|
|
26
26
|
def check_roles(cls, v: list[str]):
|
|
27
27
|
if len(v) == 0:
|
|
28
28
|
raise ValueError("Error, at least 1 role must be listed for Observable.")
|
|
29
|
+
if len(v) > 1:
|
|
30
|
+
raise ValueError("Error, each Observable can only have one role.")
|
|
29
31
|
for role in v:
|
|
30
|
-
if role not in
|
|
32
|
+
if role not in RBA_OBSERVABLE_ROLE_MAPPING.keys():
|
|
31
33
|
raise ValueError(
|
|
32
34
|
f"Invalid role '{role}' provided for observable. Valid observable types are "
|
|
33
|
-
f"{
|
|
35
|
+
f"{RBA_OBSERVABLE_ROLE_MAPPING.keys()}"
|
|
34
36
|
)
|
|
35
37
|
return v
|
|
@@ -53,11 +53,11 @@ tags:
|
|
|
53
53
|
- name: parent_process_name
|
|
54
54
|
type: Process
|
|
55
55
|
role:
|
|
56
|
-
-
|
|
56
|
+
- Attacker
|
|
57
57
|
- name: process_name
|
|
58
58
|
type: Process
|
|
59
59
|
role:
|
|
60
|
-
-
|
|
60
|
+
- Attacker
|
|
61
61
|
product:
|
|
62
62
|
- Splunk Enterprise
|
|
63
63
|
- Splunk Enterprise Security
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "contentctl"
|
|
3
|
-
version = "4.3.
|
|
3
|
+
version = "4.3.1"
|
|
4
4
|
description = "Splunk Content Control Tool"
|
|
5
5
|
authors = ["STRT <research@splunk.com>"]
|
|
6
6
|
license = "Apache 2.0"
|
|
@@ -27,7 +27,7 @@ tqdm = "^4.66.4"
|
|
|
27
27
|
pygit2 = "^1.14.1"
|
|
28
28
|
tyro = "^0.8.3"
|
|
29
29
|
gitpython = "^3.1.43"
|
|
30
|
-
setuptools = ">=69.5.1,<
|
|
30
|
+
setuptools = ">=69.5.1,<74.0.0"
|
|
31
31
|
[tool.poetry.dev-dependencies]
|
|
32
32
|
|
|
33
33
|
[build-system]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{contentctl-4.3.0 → contentctl-4.3.1}/contentctl/output/templates/analyticstories_detections.j2
RENAMED
|
File without changes
|
{contentctl-4.3.0 → contentctl-4.3.1}/contentctl/output/templates/analyticstories_investigations.j2
RENAMED
|
File without changes
|
{contentctl-4.3.0 → contentctl-4.3.1}/contentctl/output/templates/analyticstories_stories.j2
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{contentctl-4.3.0 → contentctl-4.3.1}/contentctl/output/templates/es_investigations_stories.j2
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{contentctl-4.3.0 → contentctl-4.3.1}/contentctl/output/templates/savedsearches_baselines.j2
RENAMED
|
File without changes
|
{contentctl-4.3.0 → contentctl-4.3.1}/contentctl/output/templates/savedsearches_detections.j2
RENAMED
|
File without changes
|
{contentctl-4.3.0 → contentctl-4.3.1}/contentctl/output/templates/savedsearches_investigations.j2
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{contentctl-4.3.0 → contentctl-4.3.1}/contentctl/templates/app_template/README/essoc_summary.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{contentctl-4.3.0 → contentctl-4.3.1}/contentctl/templates/app_template/default/commands.conf
RENAMED
|
File without changes
|
{contentctl-4.3.0 → contentctl-4.3.1}/contentctl/templates/app_template/default/content-version.conf
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{contentctl-4.3.0 → contentctl-4.3.1}/contentctl/templates/app_template/lookups/mitre_enrichment.csv
RENAMED
|
File without changes
|
{contentctl-4.3.0 → contentctl-4.3.1}/contentctl/templates/app_template/metadata/default.meta
RENAMED
|
File without changes
|
|
File without changes
|
{contentctl-4.3.0 → contentctl-4.3.1}/contentctl/templates/app_template/static/appIconAlt.png
RENAMED
|
File without changes
|
{contentctl-4.3.0 → contentctl-4.3.1}/contentctl/templates/app_template/static/appIconAlt_2x.png
RENAMED
|
File without changes
|
{contentctl-4.3.0 → contentctl-4.3.1}/contentctl/templates/app_template/static/appIcon_2x.png
RENAMED
|
File without changes
|
{contentctl-4.3.0 → contentctl-4.3.1}/contentctl/templates/data_sources/sysmon_eventid_1.yml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{contentctl-4.3.0 → contentctl-4.3.1}/contentctl/templates/macros/security_content_ctime.yml
RENAMED
|
File without changes
|
{contentctl-4.3.0 → contentctl-4.3.1}/contentctl/templates/macros/security_content_summariesonly.yml
RENAMED
|
File without changes
|
|
File without changes
|