From 4c13ba2b25979a8e25bbd5af860ec0c176f5c02a Mon Sep 17 00:00:00 2001 From: patel-bhavin Date: Wed, 23 Mar 2022 11:23:17 -0700 Subject: [PATCH 1/5] added new option for BA new content --- .../factory/new_content_factory.py | 32 +++++++++++++++++-- .../factory/utils/new_content_questions.py | 13 ++++++++ .../adapter/obj_to_yml_adapter.py | 29 +++++++++++++---- 3 files changed, 65 insertions(+), 9 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 1613a0cb4f..526ec85f84 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 @@ -6,12 +6,14 @@ from dataclasses import dataclass from datetime import datetime from bin.contentctl_project.contentctl_core.domain.entities.enums.enums import SecurityContentType +from bin.contentctl_project.contentctl_core.domain.entities.enums.enums import SecurityContentProduct from bin.contentctl_project.contentctl_core.application.factory.utils.new_content_questions import NewContentQuestions @dataclass(frozen=True) class NewContentFactoryInputDto: type: SecurityContentType + type: SecurityContentProduct @dataclass(frozen=True) @@ -37,9 +39,27 @@ class NewContentFactory(): self.output_dto.obj['author'] = answers['detection_author'] self.output_dto.obj['type'] = answers['detection_type'] self.output_dto.obj['datamodel'] = answers['datamodels'] + if answers['detection_product'] == 'SSA': + answers['datamodels'] = [d.replace(' (SSA)', '') for d in answers['datamodels']] + self.output_dto.obj['datamodel'] = answers['datamodels'] + if answers['detection_product'] == 'ESCU': + self.output_dto.obj['datamodel'] = answers['datamodels'] self.output_dto.obj['description'] = 'UPDATE_DESCRIPTION' - file_name = self.output_dto.obj['name'].replace(' ', '_').replace('-','_').replace('.','_').replace('/','_').lower() - self.output_dto.obj['search'] = answers['detection_search'] + ' | `' + file_name + '_filter`' + # if answers['detection_product'] == 'ESCU': + # file_name = self.output_dto.obj['name'].replace(' ', '_').replace('-','_').replace('.','_').replace('/','_').lower() + # if answers['detection_product'] == 'SSA': + # file_name = "ssa___" + self.output_dto.obj['name'].replace(' ', '_').replace('-','_').replace('.','_').replace('/','_').lower() + # ssa_file_name = 'ssa___' + str(answers['detection_name'].replace(' ', '_').replace('-','_').replace('.','_').replace('/','_').lower()) + # file_name = self.output_dto.obj['name'].replace(' ', '_').replace('-','_').replace('.','_').replace('/','_').lower().join(('ssa___',answers['detection_name'])) + + # self.output_dto.obj['name'] = ssa_file + # file_name = self.output_dto.obj['name'].replace(' ', '_').replace('-','_').replace('.','_').replace('/','_').lower()) + # file_name = ssa_file + # print (ssa_file) + # file_name = 'ssa___' + str(self.output_dto.obj['name'].replace(' ', '_').replace('-','_').replace('.','_').replace('/','_').lower()) + + if answers['detection_product'] == 'ESCU': + self.output_dto.obj['search'] = answers['detection_search'] + ' | `' + file_name + '_filter`' self.output_dto.obj['how_to_implement'] = 'UPDATE_HOW_TO_IMPLEMENT' self.output_dto.obj['known_false_positives'] = 'UPDATE_KNOWN_FALSE_POSITIVES' self.output_dto.obj['references'] = ['REFERENCE'] @@ -56,11 +76,17 @@ class NewContentFactory(): self.output_dto.obj['tags']['mitre_attack_id'] = [x.strip() for x in answers['mitre_attack_ids'].split(',')] self.output_dto.obj['tags']['nist'] = ['DE.CM'] self.output_dto.obj['tags']['observable'] = [{'name': 'UPDATE', 'type': 'UPDATE', 'role': ['UPDATE']}] - self.output_dto.obj['tags']['product'] = ['Splunk Enterprise','Splunk Enterprise Security','Splunk Cloud'] + if answers['detection_product'] == 'SSA': + self.output_dto.obj['tags']['risk_severity'] = 'UPDATE: , , ' + if answers['detection_product'] == 'ESCU': + self.output_dto.obj['tags']['product'] = ['Splunk Enterprise','Splunk Enterprise Security','Splunk Cloud'] + if answers['detection_product'] == 'SSA': + self.output_dto.obj['tags']['product'] = ['Splunk Behavioral Analytics'] self.output_dto.obj['tags']['required_fields'] = ['UPDATE'] self.output_dto.obj['tags']['risk_score'] = 'UPDATE (impact * confidence)/100' self.output_dto.obj['tags']['security_domain'] = answers['security_domain'] self.output_dto.obj['source'] = answers['detection_kind'] + elif input_dto.type == SecurityContentType.stories: questions = NewContentQuestions.get_questions_story() diff --git a/bin/contentctl_project/contentctl_core/application/factory/utils/new_content_questions.py b/bin/contentctl_project/contentctl_core/application/factory/utils/new_content_questions.py index bb9d05e5b2..250d1327f5 100644 --- a/bin/contentctl_project/contentctl_core/application/factory/utils/new_content_questions.py +++ b/bin/contentctl_project/contentctl_core/application/factory/utils/new_content_questions.py @@ -5,6 +5,16 @@ class NewContentQuestions(): @classmethod def get_questions_detection(self) -> list: questions = [ + { + 'type': 'select', + 'message': 'what product is this for', + 'name': 'detection_product', + 'choices': [ + 'ESCU', + 'SSA' + ], + 'default': 'ESCU' + }, { 'type': 'select', 'message': 'what kind of detection is this', @@ -50,6 +60,7 @@ class NewContentQuestions(): 'name': 'datamodels', 'choices': [ 'Endpoint', + 'Endpoint_Processes (SSA)', 'Authentication', 'Change', 'Email', @@ -61,6 +72,7 @@ class NewContentQuestions(): 'Web', 'Risk' ], + 'default': 'Endpoint' }, { 'type': 'text', @@ -88,6 +100,7 @@ class NewContentQuestions(): 'Actions on Objectives', 'Denial of Service' ], + 'default': 'Exploitation' }, { 'type': 'select', diff --git a/bin/contentctl_project/contentctl_infrastructure/adapter/obj_to_yml_adapter.py b/bin/contentctl_project/contentctl_infrastructure/adapter/obj_to_yml_adapter.py index 361910bb34..dd7c61e845 100644 --- a/bin/contentctl_project/contentctl_infrastructure/adapter/obj_to_yml_adapter.py +++ b/bin/contentctl_project/contentctl_infrastructure/adapter/obj_to_yml_adapter.py @@ -85,13 +85,13 @@ class ObjToYmlAdapter(Adapter): def writeObjectNewContent(self, object: dict, type: SecurityContentType) -> None: if type == SecurityContentType.detections: - file_path = os.path.join(os.path.dirname(__file__), '../../../../detections', object['source'], self.convertNameToFileName(object['name'])) + file_path = os.path.join(os.path.dirname(__file__), '../../../../detections', object['source'], self.convertNameToFileName(object['name'],object['tags']['product'])) test_obj = {} test_obj['name'] = object['name'] + ' Unit Test' test_obj['tests'] = [ { 'name': object['name'], - 'file': object['source'] + '/' + self.convertNameToFileName(object['name']), + 'file': object['source'] + '/' + self.convertNameToFileName(object['name'],object['tags']['product']), 'pass_condition': '| stats count | where count > 0', 'earliest_time': '-24h', 'latest_time': 'now', @@ -105,23 +105,40 @@ class ObjToYmlAdapter(Adapter): ] } ] - file_path_test = os.path.join(os.path.dirname(__file__), '../../../../tests', object['source'], self.convertNameToFileName(object['name'])) + file_path_test = os.path.join(os.path.dirname(__file__), '../../../../tests', object['source'], self.convertNameToTestFileName(object['name'],object['tags']['product'])) YmlWriter.writeYmlFile(file_path_test, test_obj) object.pop('source') elif type == SecurityContentType.stories: - file_path = os.path.join(os.path.dirname(__file__), '../../../../stories', self.convertNameToFileName(object['name'])) + file_path = os.path.join(os.path.dirname(__file__), '../../../../stories', self.convertNameToFileName(object['name'],object['tags']['product'])) YmlWriter.writeYmlFile(file_path, object) - def convertNameToFileName(self, name: str): + def convertNameToFileName(self, name: str, product: list): file_name = name \ .replace(' ', '_') \ .replace('-','_') \ .replace('.','_') \ .replace('/','_') \ .lower() - file_name = file_name + '.yml' + if 'Splunk Behavioral Analytics' in product: + + file_name = 'ssa___' + file_name + '.yml' + else: + file_name = file_name + '.yml' + return file_name + + def convertNameToTestFileName(self, name: str, product: list): + file_name = name \ + .replace(' ', '_') \ + .replace('-','_') \ + .replace('.','_') \ + .replace('/','_') \ + .lower() + if 'Splunk Behavioral Analytics' in product: + file_name = 'ssa___' + file_name + '.test.yml' + else: + file_name = file_name + '.test.yml' return file_name From 750c585fd55bec9b3575970b590985184b1136b2 Mon Sep 17 00:00:00 2001 From: patel-bhavin Date: Wed, 23 Mar 2022 11:29:08 -0700 Subject: [PATCH 2/5] minor cleanup --- .../application/factory/new_content_factory.py | 16 ++-------------- 1 file changed, 2 insertions(+), 14 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 526ec85f84..8818c830cf 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 @@ -44,21 +44,9 @@ class NewContentFactory(): self.output_dto.obj['datamodel'] = answers['datamodels'] if answers['detection_product'] == 'ESCU': self.output_dto.obj['datamodel'] = answers['datamodels'] - self.output_dto.obj['description'] = 'UPDATE_DESCRIPTION' - # if answers['detection_product'] == 'ESCU': - # file_name = self.output_dto.obj['name'].replace(' ', '_').replace('-','_').replace('.','_').replace('/','_').lower() - # if answers['detection_product'] == 'SSA': - # file_name = "ssa___" + self.output_dto.obj['name'].replace(' ', '_').replace('-','_').replace('.','_').replace('/','_').lower() - # ssa_file_name = 'ssa___' + str(answers['detection_name'].replace(' ', '_').replace('-','_').replace('.','_').replace('/','_').lower()) - # file_name = self.output_dto.obj['name'].replace(' ', '_').replace('-','_').replace('.','_').replace('/','_').lower().join(('ssa___',answers['detection_name'])) - - # self.output_dto.obj['name'] = ssa_file - # file_name = self.output_dto.obj['name'].replace(' ', '_').replace('-','_').replace('.','_').replace('/','_').lower()) - # file_name = ssa_file - # print (ssa_file) - # file_name = 'ssa___' + str(self.output_dto.obj['name'].replace(' ', '_').replace('-','_').replace('.','_').replace('/','_').lower()) - + self.output_dto.obj['description'] = 'UPDATE_DESCRIPTION' if answers['detection_product'] == 'ESCU': + file_name = self.output_dto.obj['name'].replace(' ', '_').replace('-','_').replace('.','_').replace('/','_').lower() self.output_dto.obj['search'] = answers['detection_search'] + ' | `' + file_name + '_filter`' self.output_dto.obj['how_to_implement'] = 'UPDATE_HOW_TO_IMPLEMENT' self.output_dto.obj['known_false_positives'] = 'UPDATE_KNOWN_FALSE_POSITIVES' From 4321225a580774a9b172637b1fcd56063430a80e Mon Sep 17 00:00:00 2001 From: patel-bhavin Date: Wed, 23 Mar 2022 14:36:59 -0700 Subject: [PATCH 3/5] minor update --- .../contentctl_infrastructure/adapter/obj_to_yml_adapter.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/contentctl_project/contentctl_infrastructure/adapter/obj_to_yml_adapter.py b/bin/contentctl_project/contentctl_infrastructure/adapter/obj_to_yml_adapter.py index dd7c61e845..c48708b448 100644 --- a/bin/contentctl_project/contentctl_infrastructure/adapter/obj_to_yml_adapter.py +++ b/bin/contentctl_project/contentctl_infrastructure/adapter/obj_to_yml_adapter.py @@ -18,8 +18,8 @@ class ObjToYmlAdapter(Adapter): def writeObjects(self, objects: list, output_path: str, type: SecurityContentType = None) -> None: - for obj in objects: - file_name = "ssa___" + self.convertNameToFileName(obj.name) + for obj in objects: + file_name = "ssa___" + self.convertNameToFileName(obj.name, obj.tags) if self.isComplexBARule(obj.search): file_path = os.path.join(output_path, 'complex', file_name) else: From ed13f34bfaaeed2bc0424620761628f7176a574f Mon Sep 17 00:00:00 2001 From: patel-bhavin Date: Thu, 24 Mar 2022 14:28:52 -0700 Subject: [PATCH 4/5] added datamodels for SSA --- .../application/factory/utils/new_content_questions.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/bin/contentctl_project/contentctl_core/application/factory/utils/new_content_questions.py b/bin/contentctl_project/contentctl_core/application/factory/utils/new_content_questions.py index 250d1327f5..c8fd18d9ec 100644 --- a/bin/contentctl_project/contentctl_core/application/factory/utils/new_content_questions.py +++ b/bin/contentctl_project/contentctl_core/application/factory/utils/new_content_questions.py @@ -61,6 +61,11 @@ class NewContentQuestions(): 'choices': [ 'Endpoint', 'Endpoint_Processes (SSA)', + 'Endpoint_Registry (SSA)', + 'Endpoint_Filesystem (SSA)', + 'Endpoint_ResourceAccess (SSA)', + 'Endpoint_AccountManagement (SSA)', + 'Intrusion_Detection (SSA)', 'Authentication', 'Change', 'Email', From f87c0062c41430fad6aded9e01aaf00e17c71491 Mon Sep 17 00:00:00 2001 From: Bhavin Patel Date: Mon, 28 Mar 2022 09:55:27 -0700 Subject: [PATCH 5/5] Update new_content_factory.py --- .../contentctl_core/application/factory/new_content_factory.py | 1 - 1 file changed, 1 deletion(-) 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 8818c830cf..bad3a9ce53 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 @@ -1,7 +1,6 @@ import os import uuid import questionary - from dataclasses import dataclass from datetime import datetime