diff --git a/bin/jinja2_templates/baseline.j2 b/bin/jinja2_templates/baseline.j2 deleted file mode 100644 index 3c48684ff2..0000000000 --- a/bin/jinja2_templates/baseline.j2 +++ /dev/null @@ -1,27 +0,0 @@ -name: {{name}} -id: {{uuid}} -version: 1 -date: '{{date}}' -author: {{author}} -type: {{type}} -datamodel: -{% for datamodel in datamodels -%} - - {{datamodel}} -{% endfor -%} -description: {{description}} -search: '{{search}}' -how_to_implement: {{how_to_implement}} -known_false_positives: {{known_false_positives}} -references: -{% for reference in references -%} - - {{reference}} -{% endfor -%} -tags: - analytic_story: - - {{analytic_story_name}} - detections: - - {{detection_name}} - product: - {% for product in products -%} - - {{product}} - {% endfor -%} diff --git a/bin/jinja2_templates/story.j2 b/bin/jinja2_templates/story.j2 index be09c2f78f..94d419c14f 100644 --- a/bin/jinja2_templates/story.j2 +++ b/bin/jinja2_templates/story.j2 @@ -3,7 +3,6 @@ id: {{uuid}} version: 1 date: '{{date}}' author: {{author}} -type: {{type}} description: {{description}} narrative: {{narrative}} references: diff --git a/bin/newcontent.py b/bin/newcontent.py index 1192bcf690..736e0ada0b 100644 --- a/bin/newcontent.py +++ b/bin/newcontent.py @@ -64,13 +64,26 @@ def detection_wizard(security_content_path,type,TEMPLATE_PATH): 'name': 'detection_type', 'choices': [ { - 'name': 'batch' + 'name': 'TTP' }, { - 'name': 'streaming' + 'name': 'Anomaly' }, + { + 'name': 'Hunting' + }, + { + 'name': 'Baseline' + }, + { + 'name': 'Investigation' + }, + { + 'name': 'Correlation' + } + ], - 'default': 'batch' + 'default': 'TTP' }, { # get provider @@ -82,18 +95,12 @@ def detection_wizard(security_content_path,type,TEMPLATE_PATH): 'name': 'Endpoint', 'checked': True }, - { - 'name': 'Network_Traffic' - }, { 'name': 'Authentication' }, { 'name': 'Change' }, - { - 'name': 'Change_Analysis' - }, { 'name': 'Email' }, @@ -115,6 +122,9 @@ def detection_wizard(security_content_path,type,TEMPLATE_PATH): { 'name': 'Web' }, + { + 'name': 'Risk' + }, ], }, { @@ -203,12 +213,10 @@ def detection_wizard(security_content_path,type,TEMPLATE_PATH): j2_env = Environment(loader=FileSystemLoader(TEMPLATE_PATH), trim_blocks=True, autoescape=True) + answers['products'] = ['Splunk Enterprise','Splunk Enterprise Security','Splunk Cloud'] + answers['references'] = [] - if answers['detection_type'] == 'batch': - answers['products'] = ['Splunk Enterprise','Splunk Enterprise Security','Splunk Cloud'] - elif answers['detection_type'] == 'streaming': - answers['products'] = ['Splunk Behavioral Analytics'] - + # grab some vars for the test detection_kind = answers['detection_kind'] @@ -220,8 +228,8 @@ def detection_wizard(security_content_path,type,TEMPLATE_PATH): output_path = path.join(security_content_path, 'detections/' + detection_kind + '/' + detection_file_name + '.yml') output = template.render(uuid=uuid.uuid1(), date=date.today().strftime('%Y-%m-%d'), author=answers['detection_author'], name=answers['detection_name'], - description='|\n\tUPDATE_DESCRIPTION\n\tWHAT IS THIS?\n\tWHAT DOES IT LOOK LIKE?\n\tHOW DO YOU TRIAGE IT?', how_to_implement='UPDATE_HOW_TO_IMPLEMENT', known_false_positives='UPDATE_KNOWN_FALSE_POSITIVES', - references='',datamodels=answers['datamodels'], + description='\n\tUPDATE_DESCRIPTION\n\tWHAT IS THIS?\n\tWHAT DOES IT LOOK LIKE?\n\tHOW DO YOU TRIAGE IT?', how_to_implement='UPDATE_HOW_TO_IMPLEMENT', known_false_positives='UPDATE_KNOWN_FALSE_POSITIVES', + references=' ',datamodels=answers['datamodels'], search= answers['detection_search'] + ' | `' + detection_file_name + '_filter`', type=answers['detection_type'], analytic_story_name='UPDATE_STORY_NAME', mitre_attack_id=mitre_attack_id, kill_chain_phases=answers['kill_chain_phases'], dataset_url='UPDATE_DATASET_URL', @@ -270,7 +278,7 @@ def detection_wizard(security_content_path,type,TEMPLATE_PATH): output_path = path.join(security_content_path, 'tests/' + detection_kind + '/' + test_name) output = template.render(name=detection_name + ' Unit Test', detection_name=detection_name, - detection_path='detections/' + detection_kind + '/' + detection_file_name + '.yml', pass_condition=answers['pass_condition'], + detection_path= detection_kind + '/' + detection_file_name + '.yml', pass_condition=answers['pass_condition'], earliest_time=answers['earliest_time'], latest_time=answers['latest_time'], file_name='UPDATE_FILE_NAME', splunk_source='UPDATE_SPLUNK_SOURCE',splunk_sourcetype='UPDATE_SPLUNK_SOURCETYPE',dataset_url='UPDATE_DATASET_URL') with open(output_path, 'w', encoding="utf-8") as f: @@ -302,20 +310,6 @@ def story_wizard(security_content_path,type, TEMPLATE_PATH): 'message': 'enter author name', 'name': 'story_author', }, - { - 'type': 'list', - 'message': 'select a story type', - 'name': 'story_type', - 'choices': [ - { - 'name': 'batch' - }, - { - 'name': 'streaming' - }, - ], - 'default': 'batch' - }, { 'type': 'checkbox', 'message': 'select a category', @@ -382,19 +376,17 @@ def story_wizard(security_content_path,type, TEMPLATE_PATH): answers = prompt(questions) j2_env = Environment(loader=FileSystemLoader(TEMPLATE_PATH), trim_blocks=True, autoescape=True) - if answers['story_type'] == 'batch': - answers['products'] = ['Splunk Enterprise','Splunk Enterprise Security','Splunk Cloud'] - elif answers['story_type'] == 'streaming': - answers['products'] = ['Splunk Behavioral Analytics'] + template = j2_env.get_template('story.j2') + answers['products'] = ['Splunk Enterprise','Splunk Enterprise Security','Splunk Cloud'] + answers['references'] = [] story_name = answers['story_name'] story_file_name = story_name.replace(' ', '_').replace('-','_').replace('.','_').replace('/','_').lower() output_path = path.join(security_content_path, 'stories/' + story_file_name + '.yml') output = template.render(uuid=uuid.uuid1(), date=date.today().strftime('%Y-%m-%d'), author=answers['story_author'], name=answers['story_name'], description='UPDATE_DESCRIPTION', - narrative='UPDATE_NARRATIVE', references=['https://www.destroyallsoftware.com/talks/wat'], - type=answers['story_type'], analytic_story_name=answers['story_name'], + narrative='UPDATE_NARRATIVE', references=['https://www.destroyallsoftware.com/talks/wat'],analytic_story_name=answers['story_name'], categories=answers['category'], usecase=answers['usecase'], products=answers['products']) with open(output_path, 'w', encoding="utf-8") as f: f.write(output) @@ -419,7 +411,7 @@ def create_example(security_content_path,type, TEMPLATE_PATH): known_false_positives='UPDATE_KNOWN_FALSE_POSITIVES', references=['https://html5zombo.com/'], datamodels=['Endpoint'], search='| UPDATE_SPL | `' + getpass.getuser() + '_' + type + '_filter`', - type='batch', analytic_story_name=' UPDATE_STORY_NAME', mitre_attack_id = 'T1003.01', + type='TTP', analytic_story_name=' UPDATE_STORY_NAME', mitre_attack_id = 'T1003.01', kill_chain_phases=['Exploitation'], dataset_url='UPDATE_DATASET_URL', products=['Splunk Enterprise','Splunk Enterprise Security','Splunk Cloud']) with open(output_path, 'w', encoding="utf-8") as f: @@ -448,36 +440,15 @@ def create_example(security_content_path,type, TEMPLATE_PATH): author='UPDATE_AUTHOR', name=getpass.getuser().capitalize() + ' ' + type.capitalize(), description='UPDATE_DESCRIPTION', narrative='UPDATE_NARRATIVE', - references=['https://www.destroyallsoftware.com/talks/wat'], - type='batch', analytic_story_name=getpass.getuser().capitalize() + ' ' + type.capitalize(), + references=['https://www.destroyallsoftware.com/talks/wat'], analytic_story_name=getpass.getuser().capitalize() + ' ' + type.capitalize(), categories=['Adversary Tactics'], usecase='Advanced Threat Detection', products=['Splunk Enterprise','Splunk Enterprise Security','Splunk Cloud']) with open(output_path, 'w', encoding="utf-8") as f: f.write(output) print("contentctl wrote a example story to: {0}".format(output_path)) - elif type == 'baseline': - # write a baseline example - template = j2_env.get_template('baseline.j2') - baseline_name = getpass.getuser() + '_' + type + '.yml.example' - output_path = path.join(security_content_path, 'baselines/' + baseline_name) - output = template.render(uuid=uuid.uuid1(), date=date.today().strftime('%Y-%m-%d'), - author='UPDATE_AUTHOR', name=getpass.getuser().capitalize() + ' ' + type.capitalize(), - description='UPDATE_DESCRIPTION', - how_to_implement='UPDATE_HOW_TO_IMPLENT', - known_false_positives='UPDATE_KNOWN_FALSE_POSITIVES', - references=['https://html5zombo.com/'], - datamodels=['Endpoint'], search='| UPDATE_SPL', - type='batch', analytic_story_name='UPDATE_STORY_NAME', - detection_name = 'UPDATE_DETECTION_NAME', dataset_url='UPDATE_DATASET_URL', - products=['Splunk Enterprise','Splunk Enterprise Security','Splunk Cloud']) - with open(output_path, 'w', encoding="utf-8") as f: - f.write(output) - print("contentctl wrote a example baseline to: {0}".format(output_path)) - - def new(security_content_path, VERBOSE, type, example_only): - valid_content_objects = ['detection','story', 'baseline'] + valid_content_objects = ['detection','story'] if type not in valid_content_objects: print("ERROR: content type: {0} is not valid, please use: {1}".format(type, str(valid_content_objects))) sys.exit(1)