def checkRA(self, stage): if self.rp_rule.get(stage): for rule in self.rp_rule.get(stage): try: rtask = REACTutils.read_yaml_file(self.inputRA + rule + ".yml") except OSError: print("Response Action %s not existing\n" % rule) continue self.task_prefix = int(self.task_prefix) self.task_prefix += 1 task = THC.TheHiveTask(order=self.task_order) self.task_order += 1 task.title = str(self.task_prefix) + " | "\ + rtask.get('id')\ + ": "\ + REACTutils.normalize_react_title(rtask.get('title'),REACTConfig.get('titlefmtrules')) if rtask.get('stage'): task.group = REACTutils.normalize_rs_name( rtask.get('stage')) else: task.group = 'Unknown stage' task.description = str(rtask.get('workflow')) if rtask.get('owner'): task.owner = str(rtask.get('owner')) self.case.tasks.append(task.return_dictionary())
def convertRPToTemplate(self, file_input, output_file): self.rp_rule = REACTutils.read_yaml_file(file_input) self.case = THC.TheHiveCase() self.case.name = self.rp_rule.get('id')\ + ": "\ + REACTutils.normalize_react_title(self.rp_rule.get('title'),REACTConfig.get('titlefmtrules')) self.case.description = str(self.rp_rule.get('description')) + \ '\n\nWorkflow:\n\n' + str(self.rp_rule.get('workflow')) try: self.case.tags += self.rp_rule.get('tags') except TypeError: pass self.case.tlp = self.checkTLP(self.rp_rule.get('tlp')) self.case.pap = self.checkPAP(self.rp_rule.get('pap')) if self.args.prefix: self.case.prefix = self.args.prefix self.task_prefix = 0.0 self.task_order = 0 stages = [ 'preparation', 'identification', 'containment', 'eradication', 'recovery', 'lessons_learned' ] for stage in stages: if stage in self.rp_rule.keys(): self.checkRA(stage) try: with open(output_file, 'w') as f: f.write(self.case.json()) except OSError: print("ERROR: No such directory %s" % os.path.dirname(os.path.abspath(output_file)))
UpdateAttackMapping() ReactPopulateMarkdown(auto=args.auto, ra=args.responseactions, rp=args.responseplaybook, rs=args.responsestage, init=args.init) GenerateMkdocs() GenerateSTIX() GenerateNavigator() elif args.mkdocs: GenerateMkdocs() elif args.stix: GenerateSTIX() elif args.navigator: GenerateNavigator() elif args.thehive: UpdateAttackMapping() REACTConfig = REACTutils.read_yaml_file("config.yml") REACTConfig2 = REACTutils.read_yaml_file("scripts/config.default.yml") #print("HINT: Make sure proper directories are " + # "configured in the scripts/config.yml") if REACTConfig.get( 'response_playbooks_dir', REACTConfig2.get('response_playbooks_dir')) and \ REACTConfig.get( 'response_actions_dir', REACTConfig2.get('response_actions_dir')) and \ REACTConfig.get( 'thehive_templates_dir', REACTConfig2.get('thehive_templates_dir')): RPTheHive( inputRP=REACTConfig.get(
def parse_into_fields(self, yaml_file): """Description""" self.ra_parsed_file = REACTutils.read_yaml_file(yaml_file)
def render_template(self, template_type): """Description template_type: - "markdown" - "confluence" """ if template_type not in ["markdown", "confluence"]: raise Exception("Bad template_type. Available values:" + " [\"markdown\", \"confluence\"]]") # Get proper template if template_type == "markdown": template = env.get_template( 'markdown_responseplaybook_template.md.j2') self.rp_parsed_file.update({ 'title': REACTutils.normalize_react_title( self.rp_parsed_file.get('title')) }) # MITRE ATT&CK Tactics and Techniques tactic = [] tactic_re = re.compile(r'attack\.\w\D+$') technique = [] technique_re = re.compile(r'attack\.t\d{4}(\.\d{3})?$') # AM!TT Tactics and Techniques amitt_tactic = [] amitt_tactic_re = re.compile(r'amitt\.\w\D+$') amitt_technique = [] amitt_technique_re = re.compile(r'amitt\.t\d{1,5}$') other_tags = [] for tag in self.rp_parsed_file.get('tags'): if tactic_re.match(tag): tactic.append(ta_mapping.get(tag)) elif technique_re.match(tag): te = tag.upper()[7:] technique.append((te_mapping.get(te), te)) elif amitt_tactic_re.match(tag): amitt_tactic.append(amitt_tactic_mapping.get(tag)) elif amitt_technique_re.match(tag): te = tag.upper()[6:] amitt_technique.append( (amitt_technique_mapping.get(te), te)) else: other_tags.append(tag) # Add MITRE ATT&CK Tactics and Techniques to J2 self.rp_parsed_file.update({'tactics': tactic}) self.rp_parsed_file.update({'techniques': technique}) # Add AM!TT Tactics and Techniques to J2 self.rp_parsed_file.update({'amitt_tactics': amitt_tactic}) self.rp_parsed_file.update({'amitt_techniques': amitt_technique}) self.rp_parsed_file.update({'other_tags': other_tags}) preparation = [] identification = [] containment = [] eradication = [] recovery = [] lessons_learned = [] detect = [] deny = [] disrupt = [] degrade = [] deceive = [] destroy = [] deter = [] stages = [('preparation', preparation), ('identification', identification), ('containment', containment), ('eradication', eradication), ('recovery', recovery), ('lessons_learned', lessons_learned), ('detect', detect), ('deny', deny), ('disrupt', disrupt), ('degrade', degrade), ('deceive', deceive), ('destroy', destroy), ('deter', deter)] # grab workflow per action in each IR stages # error handling for playbooks with empty stages for stage_name, stage_list in stages: try: for task in self.rp_parsed_file.get(stage_name): action = REACTutils.read_yaml_file( REACTConfig.get('response_actions_dir') + '/' + task + '.yml') action_title = action.get('id')\ + ": "\ + REACTutils.normalize_react_title(action.get('title')) stage_list.append( (action_title, task, action.get('description'), action.get('workflow'))) except TypeError: pass elif template_type == "confluence": template = env.get_template( 'confluence_responseplaybook_template.html.j2') new_title = self.rp_parsed_file.get('id')\ + ": "\ + REACTutils.normalize_react_title(self.rp_parsed_file.get('title')) self.rp_parsed_file.update({'title': new_title}) self.rp_parsed_file.update({ 'confluence_viewpage_url': REACTConfig.get('confluence_viewpage_url') }) # MITRE ATT&CK Tactics and Techniques tactic = [] tactic_re = re.compile(r'attack\.\w\D+$') technique = [] technique_re = re.compile(r'attack\.t\d{4}(\.\d{3})?$') # AM!TT Tactics and Techniques amitt_tactic = [] amitt_tactic_re = re.compile(r'amitt\.\w\D+$') amitt_technique = [] amitt_technique_re = re.compile(r'amitt\.t\d{1,5}$') other_tags = [] for tag in self.rp_parsed_file.get('tags'): if tactic_re.match(tag): tactic.append(ta_mapping.get(tag)) elif technique_re.match(tag): te = tag.upper()[7:] technique.append((te_mapping.get(te), te)) elif amitt_tactic_re.match(tag): amitt_tactic.append(amitt_tactic_mapping.get(tag)) elif amitt_technique_re.match(tag): te = tag.upper()[6:] amitt_technique.append( (amitt_technique_mapping.get(te), te)) else: other_tags.append(tag) # Add MITRE ATT&CK Tactics and Techniques to J2 self.rp_parsed_file.update({'tactics': tactic}) self.rp_parsed_file.update({'techniques': technique}) # Add AM!TT Tactics and Techniques to J2 self.rp_parsed_file.update({'amitt_tactics': amitt_tactic}) self.rp_parsed_file.update({'amitt_techniques': amitt_technique}) self.rp_parsed_file.update({'other_tags': other_tags}) # get links to response action preparation = [] identification = [] containment = [] eradication = [] recovery = [] lessons_learned = [] detect = [] deny = [] disrupt = [] degrade = [] deceive = [] destroy = [] deter = [] stages = [('preparation', preparation), ('identification', identification), ('containment', containment), ('eradication', eradication), ('recovery', recovery), ('lessons_learned', lessons_learned), ('detect', detect), ('deny', deny), ('disrupt', disrupt), ('degrade', degrade), ('deceive', deceive), ('destroy', destroy), ('deter', deter)] for stage_name, stage_list in stages: try: for task in self.rp_parsed_file.get(stage_name): action = REACTutils.read_yaml_file( REACTConfig.get('response_actions_dir') + '/' + task + '.yml') action_title = action.get('id')\ + ": "\ + REACTutils.normalize_react_title(action.get('title')) if self.apipath and self.auth and self.space: stage_list.append( (action_title, str( REACTutils.confluence_get_page_id( self.apipath, self.auth, self.space, action_title)))) else: stage_list.append((action_title, "")) except TypeError: pass # change stages name to more pretty format stages = [(stage_name.replace('_', ' ').capitalize(), stage_list) for stage_name, stage_list in stages] self.rp_parsed_file.update({'stages_with_id': stages}) # get descriptions for response actions preparation = [] identification = [] containment = [] eradication = [] recovery = [] lessons_learned = [] detect = [] deny = [] disrupt = [] degrade = [] deceive = [] destroy = [] deter = [] stages = [('preparation', preparation), ('identification', identification), ('containment', containment), ('eradication', eradication), ('recovery', recovery), ('lessons_learned', lessons_learned), ('detect', detect), ('deny', deny), ('disrupt', disrupt), ('degrade', degrade), ('deceive', deceive), ('destroy', destroy), ('deter', deter)] # grab workflow per action in each IR stages # error handling for playbooks with empty stages for stage_name, stage_list in stages: try: for task in self.rp_parsed_file.get(stage_name): action = REACTutils.read_yaml_file( REACTConfig.get('response_actions_dir') + '/' + task + '.yml') stage_list.append((action.get('description'), action.get('workflow'))) except TypeError: pass # # POST: Common for both Markdown and Confluence templates # # change stages name to more pretty format stages = [(stage_name.replace('_', ' ').capitalize(), stage_list) for stage_name, stage_list in stages] self.rp_parsed_file.update({'stages': stages}) self.rp_parsed_file.update( {'description': self.rp_parsed_file.get('description').strip()}) # Render self.content = template.render(self.rp_parsed_file)