From 97a1ec3bd56b25ed3ba77beb1835af69fbc94746 Mon Sep 17 00:00:00 2001 From: P4T12ICK Date: Fri, 28 Apr 2023 13:53:52 +0200 Subject: [PATCH 1/5] bug fix validation --- .../factory/new_content_factory.py | 2 +- .../domain/entities/detection_tags.py | 35 +++++++------------ .../builder/sigma_converter.py | 8 ++--- .../application/splunk_xss_via_view.yml | 6 ++-- ...supply_chain_attack_network_indicators.yml | 7 ++-- .../endpoint/suspicious_process_file_path.yml | 2 +- .../endpoint/windows_bootloader_inventory.yml | 3 ++ .../windows_impair_defenses_disable_hvci.yml | 8 +++++ .../windows_rdp_connection_successful.yml | 6 ++++ ...domains_using_pretrained_model_in_dsdl.yml | 2 +- ...ltiple_archive_files_http_post_traffic.yml | 2 +- .../plain_http_post_exfiltrated_data.yml | 2 +- detections/web/hunting_for_log4shell.yml | 3 ++ 13 files changed, 48 insertions(+), 38 deletions(-) diff --git a/bin/contentctl_project/contentctl_core/application/factory/new_content_factory.py b/bin/contentctl_project/contentctl_core/application/factory/new_content_factory.py index c9a3a4f102..b703bb76b0 100644 --- a/bin/contentctl_project/contentctl_core/application/factory/new_content_factory.py +++ b/bin/contentctl_project/contentctl_core/application/factory/new_content_factory.py @@ -51,7 +51,7 @@ class NewContentFactory(): self.output_dto.obj['tags']['asset_type'] = 'UPDATE asset_type' self.output_dto.obj['tags']['atomic_guid'] = ['UPDATE atomic_guid'] self.output_dto.obj['tags']['confidence'] = 'UPDATE value between 1-100' - self.output_dto.obj['tags']['drilldown_search'] = ['Add drilldown search'] + #self.output_dto.obj['tags']['drilldown_search'] = ['Add drilldown search'] self.output_dto.obj['tags']['impact'] = 'UPDATE value between 1-100' self.output_dto.obj['tags']['message'] = 'UPDATE message' self.output_dto.obj['tags']['mitre_attack_id'] = [x.strip() for x in answers['mitre_attack_ids'].split(',')] diff --git a/bin/contentctl_project/contentctl_core/domain/entities/detection_tags.py b/bin/contentctl_project/contentctl_core/domain/entities/detection_tags.py index fe97323c8f..703b809192 100644 --- a/bin/contentctl_project/contentctl_core/domain/entities/detection_tags.py +++ b/bin/contentctl_project/contentctl_core/domain/entities/detection_tags.py @@ -13,8 +13,6 @@ class DetectionTags(BaseModel): automated_detection_testing: str = None cis20: list = None confidence: str - context: list = None - dataset: list = None impact: int kill_chain_phases: list = None message: str @@ -22,7 +20,7 @@ class DetectionTags(BaseModel): nist: list = None observable: list product: list - required_fields: list = None + required_fields: list risk_score: int security_domain: str risk_severity: str = None @@ -81,13 +79,6 @@ class DetectionTags(BaseModel): else: return v - @validator('context') - def tags_context(cls, v, values): - context_list = SES_CONTEXT_MAPPING.keys() - for value in v: - if value not in context_list: - raise ValueError('context value not valid for ' + values["name"] + '. valid options are ' + str(context_list) ) - return v @validator('impact') def tags_impact(cls, v, values): @@ -112,19 +103,19 @@ class DetectionTags(BaseModel): raise ValueError('Mitre Attack ID are not following the pattern Txxxx: ' + values["name"]) return v - # @validator('observable') - # def tags_observable(cls,v,values): - # valid_roles = SES_OBSERVABLE_ROLE_MAPPING.keys() - # valid_types = SES_OBSERVABLE_TYPE_MAPPING.keys() + @validator('observable') + def tags_observable(cls,v,values): + valid_roles = SES_OBSERVABLE_ROLE_MAPPING.keys() + valid_types = SES_OBSERVABLE_TYPE_MAPPING.keys() - # for value in v: - # if value['type'] in valid_types: - # for role in value['role']: - # if role not in valid_roles: - # raise ValueError('Observable role ' + role + ' not valid for ' + values["name"] + '. valid options are ' + str(valid_roles)) - # else: - # raise ValueError('Observable type ' + value['type'] + ' not valid for ' + values["name"] + '. valid options are ' + str(valid_types)) - # return v + for value in v: + if value['type'] in valid_types: + for role in value['role']: + if role not in valid_roles: + raise ValueError('Observable role ' + role + ' not valid for ' + values["name"] + '. valid options are ' + str(valid_roles)) + else: + raise ValueError('Observable type ' + value['type'] + ' not valid for ' + values["name"] + '. valid options are ' + str(valid_types)) + return v @validator('product') def tags_product(cls, v, values): diff --git a/bin/contentctl_project/contentctl_infrastructure/builder/sigma_converter.py b/bin/contentctl_project/contentctl_infrastructure/builder/sigma_converter.py index c3ce1072ea..0ed326be9e 100644 --- a/bin/contentctl_project/contentctl_infrastructure/builder/sigma_converter.py +++ b/bin/contentctl_project/contentctl_infrastructure/builder/sigma_converter.py @@ -57,7 +57,7 @@ class SigmaConverter(): sys.exit(1) for detection_file in detection_files: - #try: + try: detection = self.read_detection(str(detection_file)) print("Converting detection: " + detection.name) data_source = self.load_data_source(input_dto.input_path, detection.data_source[0]) @@ -203,9 +203,9 @@ class SigmaConverter(): self.output_dto.detections.append(detection) - # except Exception as e: - # print(e) - # errors.append("ERROR: Converting detection " + detection.name) + except Exception as e: + print(e) + errors.append("ERROR: Converting detection " + detection.name) print() for error in errors: diff --git a/detections/application/splunk_xss_via_view.yml b/detections/application/splunk_xss_via_view.yml index 1ef8f0fcee..3cd6320c74 100644 --- a/detections/application/splunk_xss_via_view.yml +++ b/detections/application/splunk_xss_via_view.yml @@ -11,8 +11,8 @@ description: In Splunk Enterprise versions below 8.1.13, 8.2.10, and 9.0.4, a Vi This hunting search shows users action, application and role used for creating views related to this vulnerability. data_source: [] -search: index = _internal sourcetype IN ("splunk_web_service", "splunk_python") message="*loadParams*" - | `security_content_ctime(_time)` | table _time message fileName | `splunk_xss_via_view_filter` +search: 'index = _internal sourcetype IN ("splunk_web_service", "splunk_python") message="*loadParams*" + | `security_content_ctime(_time)` | table _time message fileName | `splunk_xss_via_view_filter`' how_to_implement: This data is collected by default in Splunk. Upon first enabling this rule, a number of errors may be observed. Those that are due to improperly formatted, but non-nefarious, XML views should be be remedied in the corresponding @@ -36,7 +36,7 @@ tags: - T1189 observable: - name: fileName - type: URL + type: URL String role: - Target product: diff --git a/detections/endpoint/3cx_supply_chain_attack_network_indicators.yml b/detections/endpoint/3cx_supply_chain_attack_network_indicators.yml index 651a91fe40..1cbbb051f3 100644 --- a/detections/endpoint/3cx_supply_chain_attack_network_indicators.yml +++ b/detections/endpoint/3cx_supply_chain_attack_network_indicators.yml @@ -7,14 +7,13 @@ type: TTP status: experimental data_source: [] description: The analytic provided below employs the Network_Resolution datamodel to detect domain indicators associated with the 3CX supply chain attack. By leveraging this query, you can efficiently conduct retrospective analysis of your data to uncover potential compromises. -search: - "| tstats `security_content_summariesonly` values(DNS.answer) as IPs min(_time) as firstTime from datamodel=Network_Resolution by DNS.src, DNS.query +search: '| tstats `security_content_summariesonly` values(DNS.answer) as IPs min(_time) as firstTime from datamodel=Network_Resolution by DNS.src, DNS.query | `drop_dm_object_name(DNS)` | `security_content_ctime(firstTime)` | `security_content_ctime(lastTime)` | lookup 3cx_ioc_domains domain as query OUTPUT Description isIOC | search isIOC=true - | `3cx_supply_chain_attack_network_indicators_filter`" + | `3cx_supply_chain_attack_network_indicators_filter`' how_to_implement: To successfully implement this search you need to be ingesting information into the `Network Resolution` datamodel in the `DNS` node. In addition, confirm the latest CIM App 4.20 or higher is installed and the latest TA''s are installed. known_false_positives: False positives will be present for accessing the 3cx[.]com website. Remove from the lookup as needed. references: @@ -40,7 +39,7 @@ tags: role: - Victim - name: query - type: URL Domain + type: URL String role: - Attacker product: diff --git a/detections/endpoint/suspicious_process_file_path.yml b/detections/endpoint/suspicious_process_file_path.yml index 6e6cdf7a01..c56f48c9ad 100644 --- a/detections/endpoint/suspicious_process_file_path.yml +++ b/detections/endpoint/suspicious_process_file_path.yml @@ -68,7 +68,7 @@ tags: role: - Victim - name: process_path - type: Location + type: Process Name role: - Attacker product: diff --git a/detections/endpoint/windows_bootloader_inventory.yml b/detections/endpoint/windows_bootloader_inventory.yml index a2b277fe1f..1f5058f4cd 100644 --- a/detections/endpoint/windows_bootloader_inventory.yml +++ b/detections/endpoint/windows_bootloader_inventory.yml @@ -36,5 +36,8 @@ tags: - Splunk Enterprise - Splunk Enterprise Security - Splunk Cloud + required_fields: + - _time + - _raw risk_score: 81 security_domain: endpoint \ No newline at end of file diff --git a/detections/endpoint/windows_impair_defenses_disable_hvci.yml b/detections/endpoint/windows_impair_defenses_disable_hvci.yml index 8e1854caf3..79d7d6a770 100644 --- a/detections/endpoint/windows_impair_defenses_disable_hvci.yml +++ b/detections/endpoint/windows_impair_defenses_disable_hvci.yml @@ -42,6 +42,14 @@ tags: - Splunk Enterprise - Splunk Enterprise Security - Splunk Cloud + required_fields: + - Registry.registry_path + - Registry.registry_value_data + - Registry.registry_value_name + - Registry.process_guid + - Registry.action + - Registry.user + - Registry.dest risk_score: 70 security_domain: endpoint tests: diff --git a/detections/endpoint/windows_rdp_connection_successful.yml b/detections/endpoint/windows_rdp_connection_successful.yml index a883ad9b02..24620bea14 100644 --- a/detections/endpoint/windows_rdp_connection_successful.yml +++ b/detections/endpoint/windows_rdp_connection_successful.yml @@ -40,6 +40,12 @@ tags: - Splunk Enterprise - Splunk Enterprise Security - Splunk Cloud + required_fields: + - EventCode + - ComputerName + - Source_Network_Address + - User + - Message risk_score: 25 security_domain: endpoint tests: diff --git a/detections/network/detect_dga_domains_using_pretrained_model_in_dsdl.yml b/detections/network/detect_dga_domains_using_pretrained_model_in_dsdl.yml index c6848429ff..1e5652c695 100644 --- a/detections/network/detect_dga_domains_using_pretrained_model_in_dsdl.yml +++ b/detections/network/detect_dga_domains_using_pretrained_model_in_dsdl.yml @@ -74,7 +74,7 @@ tags: - T1568.002 observable: - name: domain - type: URL + type: URL String role: - Attacker - name: src diff --git a/detections/network/multiple_archive_files_http_post_traffic.yml b/detections/network/multiple_archive_files_http_post_traffic.yml index e2683c2744..2cb708a2be 100644 --- a/detections/network/multiple_archive_files_http_post_traffic.yml +++ b/detections/network/multiple_archive_files_http_post_traffic.yml @@ -45,7 +45,7 @@ tags: - T1048 observable: - name: uri_path - type: URL + type: URL String role: - Attacker - name: form_data diff --git a/detections/network/plain_http_post_exfiltrated_data.yml b/detections/network/plain_http_post_exfiltrated_data.yml index 20753d905b..9ce625d44e 100644 --- a/detections/network/plain_http_post_exfiltrated_data.yml +++ b/detections/network/plain_http_post_exfiltrated_data.yml @@ -35,7 +35,7 @@ tags: - T1048 observable: - name: uri_path - type: URL + type: URL String role: - Attacker - name: form_data diff --git a/detections/web/hunting_for_log4shell.yml b/detections/web/hunting_for_log4shell.yml index f1843edb9c..7ce1936798 100644 --- a/detections/web/hunting_for_log4shell.yml +++ b/detections/web/hunting_for_log4shell.yml @@ -99,6 +99,9 @@ tags: - Splunk Enterprise - Splunk Enterprise Security - Splunk Cloud + required_fields: + - _time + - _raw risk_score: 40 security_domain: network tests: From 72792fc2a0d327121309bb9d99162469421517ed Mon Sep 17 00:00:00 2001 From: P4T12ICK Date: Fri, 28 Apr 2023 14:49:00 +0200 Subject: [PATCH 2/5] Update to detection tags validator --- .../domain/entities/detection_tags.py | 34 +++++++++++-------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/bin/contentctl_project/contentctl_core/domain/entities/detection_tags.py b/bin/contentctl_project/contentctl_core/domain/entities/detection_tags.py index 703b809192..16490246e8 100644 --- a/bin/contentctl_project/contentctl_core/domain/entities/detection_tags.py +++ b/bin/contentctl_project/contentctl_core/domain/entities/detection_tags.py @@ -1,6 +1,6 @@ import re -from pydantic import BaseModel, validator, ValidationError +from pydantic import BaseModel, validator, ValidationError, root_validator from bin.contentctl_project.contentctl_core.domain.entities.mitre_attack_enrichment import MitreAttackEnrichment from bin.contentctl_project.contentctl_core.domain.constants.constants import * @@ -103,20 +103,6 @@ class DetectionTags(BaseModel): raise ValueError('Mitre Attack ID are not following the pattern Txxxx: ' + values["name"]) return v - @validator('observable') - def tags_observable(cls,v,values): - valid_roles = SES_OBSERVABLE_ROLE_MAPPING.keys() - valid_types = SES_OBSERVABLE_TYPE_MAPPING.keys() - - for value in v: - if value['type'] in valid_types: - for role in value['role']: - if role not in valid_roles: - raise ValueError('Observable role ' + role + ' not valid for ' + values["name"] + '. valid options are ' + str(valid_roles)) - else: - raise ValueError('Observable type ' + value['type'] + ' not valid for ' + values["name"] + '. valid options are ' + str(valid_types)) - return v - @validator('product') def tags_product(cls, v, values): valid_products = [ @@ -137,3 +123,21 @@ class DetectionTags(BaseModel): f"\n Expected risk_score={calculated_risk_score}, found risk_score={int(v)}: {values['name']}") return v + @root_validator + def tags_observable(cls, values): + valid_roles = SES_OBSERVABLE_ROLE_MAPPING.keys() + valid_types = SES_OBSERVABLE_TYPE_MAPPING.keys() + + for value in values["observable"]: + if value['type'] in valid_types: + if 'Splunk Behavioral Analytics' in values["product"]: + continue + + if 'role' not in value: + raise ValueError('Observable role is missing for ' + values["name"]) + for role in value['role']: + if role not in valid_roles: + raise ValueError('Observable role ' + role + ' not valid for ' + values["name"] + '. valid options are ' + str(valid_roles)) + else: + raise ValueError('Observable type ' + value['type'] + ' not valid for ' + values["name"] + '. valid options are ' + str(valid_types)) + return values \ No newline at end of file From 600ceb89378660116bb556f97d29cf9c7994ea08 Mon Sep 17 00:00:00 2001 From: P4T12ICK Date: Mon, 1 May 2023 15:16:42 +0200 Subject: [PATCH 3/5] Add BA detection schema and validator --- spec/ba_detections.spec.json | 716 ++++++++++++++++++++++++++------ spec/ba_detections_validator.py | 46 ++ 2 files changed, 633 insertions(+), 129 deletions(-) create mode 100644 spec/ba_detections_validator.py diff --git a/spec/ba_detections.spec.json b/spec/ba_detections.spec.json index 884621de9f..803617f62c 100644 --- a/spec/ba_detections.spec.json +++ b/spec/ba_detections.spec.json @@ -2,42 +2,15 @@ "$id": "http://example.com/example.json", "$schema": "http://json-schema.org/draft-07/schema", "additionalProperties": true, - "description": "schema for detections", + "description": "schema for ba detections", "properties": { - "author": { - "$id": "#/properties/author", + "name": { + "$id": "#/properties/name", "default": "", - "description": "Author of the detection", "examples": [ - "Patrick Bareiss, Splunk" - ], - "type": "string" - }, - "date": { - "$id": "#/properties/date", - "default": "", - "description": "date of creation or modification, format yyyy-mm-dd", - "examples": [ - "2019-12-06" - ], - "type": "string" - }, - "description": { - "$id": "#/properties/description", - "default": "", - "description": "A detailed description of the detection", - "examples": [ - "dbgcore.dll is a specifc DLL for Windows core debugging. It is used to obtain a memory dump of a process. This search detects the usage of this DLL for creating a memory dump of LSASS process. Memory dumps of the LSASS process can be created with tools such as Windows Task Manager or procdump." - ], - "type": "string" - }, - "how_to_implement": { - "$id": "#/properties/how_to_implement", - "default": "", - "description": "information about how to implement. Only needed for non standard implementations.", - "examples": [ - "This search requires Sysmon Logs and a Sysmon configuration, which includes EventCode 10 for lsass.exe." + "Anomalous usage of Archive Tools" ], + "title": "Name of detection", "type": "string" }, "id": { @@ -49,24 +22,51 @@ ], "type": "string" }, + "version": { + "$id": "#/properties/version", + "default": 0, + "description": "version of detection, e.g. 1 or 2 ...", + "examples": [ + 1 + ], + "type": "integer" + }, + "description": { + "$id": "#/properties/description", + "default": "", + "description": "A detailed description of the detection", + "examples": [ + "The following detection identifies the usage of archive tools from the command line." + ], + "type": "string" + }, + "search": { + "$id": "#/properties/search", + "default": "", + "description": "The Splunk search for the detection", + "examples": [ + "| from read_ba_enriched_events()" + ], + "type": "string" + }, + "how_to_implement": { + "$id": "#/properties/how_to_implement", + "default": "", + "description": "information about how to implement.", + "examples": [ + "Ingest Windows Event Code 4688 with Command Line Logging enabled." + ], + "type": "string" + }, "known_false_positives": { "$id": "#/properties/knwon_false_positives", "default": "", "description": "known false postives", "examples": [ - "Administrators can create memory dumps for debugging purposes, but memory dumps of the LSASS process would be unusual." + "False positives can be ligitmate usage of archive tools from the command line." ], "type": "string" }, - "name": { - "$id": "#/properties/name", - "default": "", - "examples": [ - "Access LSASS Memory for Dump Creation" - ], - "title": "Name of detection", - "type": "string" - }, "references": { "$id": "#/properties/references", "additionalItems": true, @@ -74,30 +74,80 @@ "description": "A list of references for this detection", "examples": [ [ - "https://2017.zeronights.org/wp-content/uploads/materials/ZN17_Kheirkhabarov_Hunting_for_Credentials_Dumping_in_Windows_Environment.pdf" + "https://attack.mitre.org/techniques/T1560/001/" ] ], "items": { "$id": "#/properties/references/items", "default": "", - "description": "An explanation about the purpose of this instance.", + "description": "Link to reference", "examples": [ - "https://2017.zeronights.org/wp-content/uploads/materials/ZN17_Kheirkhabarov_Hunting_for_Credentials_Dumping_in_Windows_Environment.pdf" + "https://attack.mitre.org/techniques/T1560/001/" ], "title": "The Items Schema", "type": "string" }, "type": "array" }, - "search": { - "$id": "#/properties/search", + "runtime": { + "$id": "#/properties/runtime", "default": "", - "description": "The Splunk search for the detection", + "description": "runtime for BA detection", "examples": [ - "`sysmon` EventCode=10 TargetImage=*lsass.exe CallTrace=*dbgcore.dll* OR CallTrace=*dbghelp.dll* | stats count min(_time) as firstTime max(_time) as lastTime by Computer, TargetImage, TargetProcessId, SourceImage, SourceProcessId | rename Computer as dest | `security_content_ctime(firstTime)`| `security_content_ctime(lastTime)` | `access_lsass_memory_for_dump_creation_filter`" + "SPL2" ], + "items": { + "enum": [ + "DSP-SPL", + "SPL2", + "Spark" + ], + "type": "string" + }, "type": "string" }, + "detection_type": { + "$id": "#/properties/detection_type", + "default": "", + "description": "type of detection", + "examples": [ + "Rule" + ], + "items": { + "enum": [ + "Rule", + "ML" + ], + "type": "string" + }, + "type": "string" + }, + "job_params": { + "$id": "#/properties/job_params", + "additionalProperties": true, + "default": "", + "description": "job parameters", + "examples": [ + { + "entrypointClassName": "com.splunk.ssa.batch.poc.BatchEntryPoint", + "modelsJarFileName": "batch-models.jar" + } + ], + "type": "object" + }, + "model_params": { + "$id": "#/properties/model_params", + "additionalProperties": true, + "default": "", + "description": "model parameters", + "examples": [ + { + "modelClassName": "com.splunk.ssa.batch.poc.models.DeviceAccessRareModel", + "lookBackPeriodInDays": 30 + } + ], + "type": "object" + }, "tags": { "$id": "#/properties/tags", "additionalProperties": true, @@ -105,99 +155,507 @@ "description": "An array of key value pairs for tagging", "examples": [ { - "analytic_story": "credential_dumping", - "kill_chain_phases": "Action on Objectives", - "mitre_attack_id": "T1078.004", - "cis20": "CIS 13", - "nist": "DE.DP", - "security domain": "network", - "asset_type": "AWS Instance", - "risk_object": "user", - "risk_object_type": "network_artifacts", - "risk score": "60", - "custom_key": "custom_value" + "annotations": {"analytic_story": ["NOBELIUM Group"], "cis20": ["CIS 10"], "kill_chain_phases": ["Exploitation"], "mitre_attack_id": ["T1560.001", "T1560"], "nist": ["DE.AE"]}, + "ocsf_attributes": {"activity_id": 1, "category_uid": 2, "class_uid": 102001, "risk_level_id": 2, "risk_score": 42, "severity_id": 0, "rule": {"name": "Anomalous usage of Archive Tools", "uid": "63614a58-10e2-4c6c-ae81-ea1113681439", "type": "Streaming"}, "metadata": {"product": {"name": "Behavior Analytics", "vendor_name": "Splunk"}, "version": "1.0.0-rc.2"}, "type_uid": 10200101}, + "required_fields": ["process.user.name", "device.hostname"], + "risk_score": 42, + "security_domain": "endpoint", + "risk_severity": "low", + "research_site_url": "https://research.splunk.com/endpoint/63614a58-10e2-4c6c-ae81-ea1113681439/", + "event_schema": "ocsf", + "mappings": [{"ocsf": "process.user.name", "cim": "user"},{"ocsf": "device.hostname", "cim": "dest"}] } ], - "minItems": 1, "type": "object", - "uniqueItems": true - }, - "type": { - "$id": "#/properties/type", - "default": "", - "description": "type of detection", - "examples": [ - "Anomaly" + "uniqueItems": true, + "required": [ + "annotations", + "risk_score", + "security_domain", + "risk_severity", + "research_site_url", + "event_schema", + "mappings" ], - "items": { - "enum": [ - "TTP", - "Anomaly", - "Hunting", - "Baseline", - "Investigation", - "Correlation" - ], - "type": "string" - }, - "type": "string" - }, - "datamodel": { - "$id": "#/properties/datamodel", - "default": "", - "description": "datamodel used in the search", - "examples": [ - "Endpoint_Processes" - ], - "items": { - "enum": [ - "Alerts", - "Authentication", - "Certificates", - "Data Loss Prevention", - "Email", - "Endpoint_AccountManagement", - "Endpoint_Filesystem", - "Endpoint_Processes", - "Endpoint_Registry", - "Endpoint_ResourceAccess", - "Intrusion_Detection", - "Inventory_User", - "Malware_Attacks", - "Network_Traffic", - "Network_Sessions", - "Network_Resolution", - "Web", - "Web.Proxy" - ], - "type": "string" - }, - "type": "array" - }, - "version": { - "$id": "#/properties/version", - "default": 0, - "description": "version of detection, e.g. 1 or 2 ...", - "examples": [ - 2 - ], - "type": "integer" + "properties": { + "annotations": { + "$id": "#/properties/tags/annotations", + "additionalProperties": true, + "default": {}, + "description": "An array of key value pairs for annotations", + "examples": [ + { + "analytic_story": ["NOBELIUM Group"], + "cis20": ["CIS 10"], + "kill_chain_phases": ["Exploitation"], + "mitre_attack_id": ["T1560.001"], + "nist": ["DE.AE"] + } + ], + "type": "object", + "uniqueItems": true, + "required": [ + "analytic_story", + "cis20", + "kill_chain_phases", + "mitre_attack_id", + "nist" + ], + "properties": { + "analytic_story": { + "$id": "#/properties/tags/annotations/analytic_story", + "additionalItems": true, + "default": [], + "description": "A list of analytic stories for this detection", + "examples": [ + [ + "NOBELIUM Group" + ] + ], + "items": { + "$id": "#/properties/tags/annotations/analytic_story/items", + "default": "", + "description": "analytic story name", + "examples": [ + "NOBELIUM Group" + ], + "title": "The Items Schema", + "type": "string" + }, + "type": "array" + }, + "cis20": { + "$id": "#/properties/tags/annotations/cis20", + "additionalItems": true, + "default": [], + "description": "cis tags", + "examples": [ + ["CIS 10"] + ], + "items": { + "$id": "#/properties/tags/annotations/cis20/items", + "default": "", + "description": "cis tag", + "examples": [ + "CIS 10" + ], + "title": "The Items Schema", + "type": "string" + }, + "type": "array" + }, + "kill_chain_phases": { + "$id": "#/properties/tags/annotations/kill_chain_phases", + "additionalItems": true, + "default": [], + "description": "kill_chain_phases", + "examples": [ + ["Exploitation"] + ], + "items": { + "$id": "#/properties/tags/annotations/kill_chain_phases/items", + "default": "", + "description": "kill_chain_phase", + "examples": [ + "Exploitation" + ], + "title": "The Items Schema", + "type": "string" + }, + "type": "array" + }, + "mitre_attack_id": { + "$id": "#/properties/tags/annotations/mitre_attack_id", + "additionalItems": true, + "default": [], + "description": "mitre_attack_id", + "examples": [ + ["T1560.001", "T1560"] + ], + "items": { + "$id": "#/properties/tags/annotations/mitre_attack_id/items", + "default": "", + "description": "kill_chain_phase", + "examples": [ + "T1560.001" + ], + "title": "The Items Schema", + "type": "string" + }, + "type": "array" + }, + "nist": { + "$id": "#/properties/tags/annotations/nist", + "additionalItems": true, + "default": [], + "description": "nist array", + "examples": [ + ["DE.AE"] + ], + "items": { + "$id": "#/properties/tags/annotations/nist/items", + "default": "", + "description": "nist", + "examples": [ + "DE.AE" + ], + "title": "The Items Schema", + "type": "string" + }, + "type": "array" + } + } + }, + "ocsf_attributes": { + "$id": "#/properties/tags/ocsf_attributes", + "additionalProperties": true, + "default": {}, + "description": "An array of key value pairs for static ocsf attributes", + "examples": [ + { + "activity_id": 1, + "category_uid": 2, + "class_uid": 102001, + "risk_level_id": 2, + "risk_score": 42, + "severity_id": 0, + "rule": { + "name": "Anomalous usage of Archive Tools", + "uid": "63614a58-10e2-4c6c-ae81-ea1113681439", + "type": "Streaming" + }, + "metadata": { + "product": { + "name": "Behavior Analytics", + "vendor_name": "Splunk" + }, + "version": "1.0.0-rc.2" + }, + "type_uid": 10200101 + } + ], + "type": "object", + "uniqueItems": true, + "required": [ + "activity_id", + "category_uid", + "class_uid", + "risk_level_id", + "risk_score", + "severity_id", + "rule", + "metadata", + "type_uid" + ], + "properties": { + "activity_id": { + "$id": "#/properties/tags/ocsf_attributes/activity_id", + "default": 1, + "description": "activity_id", + "examples": [ + 1 + ], + "type": "integer" + }, + "category_uid": { + "$id": "#/properties/tags/ocsf_attributes/category_uid", + "default": 2, + "description": "category_uid", + "examples": [ + 2 + ], + "type": "integer" + }, + "class_uid": { + "$id": "#/properties/tags/ocsf_attributes/class_uid", + "default": 102001, + "description": "class_uid", + "examples": [ + 102001 + ], + "type": "integer" + }, + "risk_level_id": { + "$id": "#/properties/tags/ocsf_attributes/risk_level_id", + "default": 2, + "description": "risk_level_id", + "examples": [ + 2 + ], + "type": "integer" + }, + "risk_score": { + "$id": "#/properties/tags/ocsf_attributes/risk_score", + "default": 42, + "description": "risk_score", + "examples": [ + 42 + ], + "type": "integer" + }, + "severity_id": { + "$id": "#/properties/tags/ocsf_attributes/severity_id", + "default": 0, + "description": "severity_id", + "examples": [ + 0 + ], + "type": "integer" + }, + "rule": { + "$id": "#/properties/tags/ocsf_attributes/rule", + "additionalProperties": true, + "default": {}, + "description": "rule object", + "examples": [ + { + "name": "Anomalous usage of Archive Tools", + "uid": "63614a58-10e2-4c6c-ae81-ea1113681439", + "type": "Streaming" + } + ], + "type": "object", + "uniqueItems": true, + "required": [ + "name", + "uid" + ], + "properties": { + "name": { + "$id": "#/properties/tags/ocsf_attributes/rule/name", + "default": "", + "description": "rule name", + "examples": [ + "Anomalous usage of Archive Tools" + ], + "type": "string" + }, + "uid": { + "$id": "#/properties/tags/ocsf_attributes/rule/uid", + "default": "", + "description": "rule uid", + "examples": [ + "63614a58-10e2-4c6c-ae81-ea1113681439" + ], + "type": "string" + }, + "type": { + "$id": "#/properties/tags/ocsf_attributes/rule/type", + "default": "", + "description": "rule type", + "examples": [ + "Streaming" + ], + "type": "string" + } + } + }, + "metadata": { + "$id": "#/properties/tags/ocsf_attributes/metadata", + "additionalProperties": true, + "default": {}, + "description": "metadata object", + "examples": [ + { + "product": { + "name": "Behavior Analytics", + "vendor_name": "Splunk" + }, + "version": "1.0.0-rc.2" + } + ], + "type": "object", + "uniqueItems": true, + "required": [ + "product", + "version" + ], + "properties": { + "product": { + "$id": "#/properties/tags/ocsf_attributes/metadata/product", + "additionalProperties": true, + "default": {}, + "description": "product object", + "examples": [ + { + "name": "Behavior Analytics", + "vendor_name": "Splunk" + } + ], + "type": "object", + "uniqueItems": true, + "required": [ + "name", + "vendor_name" + ], + "properties": { + "name": { + "$id": "#/properties/tags/ocsf_attributes/metadata/product/name", + "default": "", + "description": "product name", + "examples": [ + "Behavior Analytics" + ], + "type": "string" + }, + "vendor_name": { + "$id": "#/properties/tags/ocsf_attributes/metadata/product/vendor_name", + "default": "", + "description": "vendor product name", + "examples": [ + "Splunk" + ], + "type": "string" + } + } + }, + "version": { + "$id": "#/properties/tags/ocsf_attributes/metadata/version", + "default": "", + "description": "ocsf schema version", + "examples": [ + "1.0.0-rc.2" + ], + "type": "string" + } + } + }, + "type_uid": { + "$id": "#/properties/tags/ocsf_attributes/type_uid", + "default": 10200101, + "description": "type_uid", + "examples": [ + 10200101 + ], + "type": "integer" + } + } + }, + "required_fields": { + "$id": "#/properties/tags/required_fields", + "additionalItems": true, + "default": [], + "description": "required_fields", + "examples": [ + ["process.user.name", "device.hostname"] + ], + "items": { + "$id": "#/properties/tags/required_fields/items", + "default": "", + "description": "required_fields name", + "examples": [ + "process.user.name" + ], + "title": "The Items Schema", + "type": "string" + }, + "type": "array" + }, + "risk_score": { + "$id": "#/properties/tags/risk_score", + "default": 50, + "description": "risk_score", + "examples": [ + 42 + ], + "type": "integer" + }, + "security_domain": { + "$id": "#/properties/tags/security_domain", + "default": "", + "description": "security_domain", + "examples": [ + "endpoint" + ], + "type": "string" + }, + "risk_severity": { + "$id": "#/properties/tags/risk_severity", + "default": "", + "description": "risk_severity", + "examples": [ + "low" + ], + "type": "string" + }, + "research_site_url": { + "$id": "#/properties/tags/research_site_url", + "default": "", + "description": "research_site_url", + "examples": [ + "https://research.splunk.com/endpoint/63614a58-10e2-4c6c-ae81-ea1113681439/" + ], + "type": "string" + }, + "event_schema": { + "$id": "#/properties/tags/event_schema", + "default": "", + "description": "event_schema", + "examples": [ + "ocsf" + ], + "type": "string" + }, + "mappings": { + "$id": "#/properties/tags/mappings", + "default": [], + "description": "mappings array", + "examples": [ + [{"ocsf": "process.user.name", "cim": "user"},{"ocsf": "device.hostname", "cim": "dest"}] + ], + "items": { + "$id": "#/properties/tags/mappings/items", + "default": {}, + "description": "mappings object", + "examples": [ + { + "ocsf": "process.user.name", + "cim": "user" + } + ], + "type": "object", + "uniqueItems": true, + "properties": { + "ocsf": { + "$id": "#/properties/tags/mappings/items/ocsf", + "default": "", + "description": "ocsf mapping", + "examples": [ + "process.user.name" + ], + "type": "string" + }, + "cim": { + "$id": "#/properties/tags/mappings/items/cim", + "default": "", + "description": "cim mapping", + "examples": [ + "user" + ], + "type": "string" + } + }, + "required": [ + "ocsf", + "cim" + ] + }, + "type": "array" + } + } } }, "required": [ "name", "id", "version", - "date", - "datamodel", "description", - "type", - "author", - "search", + "how_to_implement", "known_false_positives", + "references", "tags" ], - "title": "Detection Schema", + "title": "BA Detection Schema", "type": "object" - } +} \ No newline at end of file diff --git a/spec/ba_detections_validator.py b/spec/ba_detections_validator.py new file mode 100644 index 0000000000..d4875d47fa --- /dev/null +++ b/spec/ba_detections_validator.py @@ -0,0 +1,46 @@ +import json +import sys +from pathlib import Path +import yaml +from jsonschema import validate, ValidationError + +def read_yaml_file(file_path): + with open(file_path, 'r') as file: + return yaml.safe_load(file) + +def read_json_file(file_path): + with open(file_path, 'r') as file: + return json.load(file) + +def validate_json_against_schema(json_data, schema): + try: + validate(instance=json_data, schema=schema) + return True + except ValidationError as e: + print(f"Validation Error: {e}") + return False + +def main(yaml_file_path, json_schema_file_path): + yaml_data = read_yaml_file(yaml_file_path) + json_schema = read_json_file(json_schema_file_path) + + is_valid = validate_json_against_schema(yaml_data, json_schema) + + if is_valid: + print("The YAML file is valid according to the JSON schema.") + else: + print("The YAML file is not valid according to the JSON schema.") + +if __name__ == "__main__": + if len(sys.argv) != 3: + print("Usage: python ba_detections_validator.py ") + sys.exit(1) + + yaml_file_path = Path(sys.argv[1]) + json_schema_file_path = Path(sys.argv[2]) + + if not yaml_file_path.is_file() or not json_schema_file_path.is_file(): + print("Both input files must exist.") + sys.exit(1) + + main(yaml_file_path, json_schema_file_path) \ No newline at end of file From fdd6c6534a5f593401b6ccde4e444dd1b181eee5 Mon Sep 17 00:00:00 2001 From: P4T12ICK Date: Mon, 1 May 2023 16:26:51 +0200 Subject: [PATCH 4/5] update attackcti dependency --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 3ba80ab587..dd78740e25 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -attackcti==0.3.8 +attackcti==0.3.9 docker==6.0.0 GitPython==3.1.31 Jinja2==3.1.2 From 44b98b61c152c094a25affebc62df4261698e5e9 Mon Sep 17 00:00:00 2001 From: P4T12ICK Date: Wed, 3 May 2023 15:13:10 +0200 Subject: [PATCH 5/5] improved detections --- .../active_directory_lateral_movement_identified.yml | 9 +++++++++ ...t_lateral_movement_smbexec_commandline_parameters.yml | 8 ++++++++ ...t_lateral_movement_wmiexec_commandline_parameters.yml | 8 ++++++++ 3 files changed, 25 insertions(+) diff --git a/detections/endpoint/active_directory_lateral_movement_identified.yml b/detections/endpoint/active_directory_lateral_movement_identified.yml index aab3084d32..a591a4a73a 100644 --- a/detections/endpoint/active_directory_lateral_movement_identified.yml +++ b/detections/endpoint/active_directory_lateral_movement_identified.yml @@ -39,6 +39,15 @@ tags: - Splunk Enterprise - Splunk Enterprise Security - Splunk Cloud + required_fields: + - All_Risk.calculated_risk_score + - All_Risk.annotations.mitre_attack.mitre_tactic_id + - All_Risk.annotations.mitre_attack.mitre_technique_id + - All_Risk.tag + - All_Risk.analyticstories + - All_Risk.risk_object_type + - All_Risk.risk_object + - All_Risk.annotations.mitre_attack.mitre_tactic risk_score: 64 security_domain: endpoint tests: diff --git a/detections/endpoint/impacket_lateral_movement_smbexec_commandline_parameters.yml b/detections/endpoint/impacket_lateral_movement_smbexec_commandline_parameters.yml index edecf952ec..2a3406695b 100644 --- a/detections/endpoint/impacket_lateral_movement_smbexec_commandline_parameters.yml +++ b/detections/endpoint/impacket_lateral_movement_smbexec_commandline_parameters.yml @@ -55,6 +55,14 @@ tags: - Splunk Enterprise - Splunk Enterprise Security - Splunk Cloud + required_fields: + - Processes.process_name + - Processes.dest + - Processes.user + - Processes.parent_process_name + - Processes.process + - Processes.process_id + - Processes.parent_process_id risk_score: 63 security_domain: endpoint tests: diff --git a/detections/endpoint/impacket_lateral_movement_wmiexec_commandline_parameters.yml b/detections/endpoint/impacket_lateral_movement_wmiexec_commandline_parameters.yml index f104d8b402..cfce4e4ad0 100644 --- a/detections/endpoint/impacket_lateral_movement_wmiexec_commandline_parameters.yml +++ b/detections/endpoint/impacket_lateral_movement_wmiexec_commandline_parameters.yml @@ -62,6 +62,14 @@ tags: - Splunk Enterprise - Splunk Enterprise Security - Splunk Cloud + required_fields: + - Processes.process_name + - Processes.dest + - Processes.user + - Processes.parent_process_name + - Processes.process + - Processes.process_id + - Processes.parent_process_id risk_score: 63 security_domain: endpoint tests: