def data_needed(self, dn_path): """Desc""" print("[*] Populating Data Needed...") if dn_path: dn_list = glob.glob(dn_path + '*.yml') else: dn_dir = ATCconfig.get('data_needed_dir') dn_list = glob.glob(dn_dir + '/*.yml') for dn_file in dn_list: try: dn = DataNeeded(dn_file, apipath=self.apipath, auth=self.auth, space=self.space) dn.render_template("confluence") confluence_data = { "title": dn.dn_fields["title"], "spacekey": self.space, "parentid": str(ATCutils.confluence_get_page_id( self.apipath, self.auth, self.space, "Data Needed")), "confluencecontent": dn.content, } res = ATCutils.push_to_confluence(confluence_data, self.apipath, self.auth) if res == 'Page updated': print("==> updated page: DN '" + dn.dn_fields['title'] + "'") # print("Done: ", dn.dn_fields['title']) except Exception as err: print(dn_file + " failed") print("Err message: %s" % err) print('-' * 60) traceback.print_exc(file=sys.stdout) print('-' * 60) print("[+] Data Needed populated!")
def mitigation_policy(self, mp_path): """Populate Mitigation Policies""" print("[*] Populating Mitigation Policies...") if mp_path: mp_list = glob.glob(mp_path + '*.yml') else: mp_dir = ATCconfig.get('mitigation_policies_directory') mp_list = glob.glob(mp_dir + '/*.yml') for mp_file in mp_list: try: mp = MitigationPolicy(mp_file, apipath=self.apipath, auth=self.auth, space=self.space) mp.render_template("confluence") confluence_data = { "title": mp.mp_parsed_file["title"], "spacekey": self.space, "parentid": str(ATCutils.confluence_get_page_id( self.apipath, self.auth, self.space, "Mitigation Policies")), "confluencecontent": mp.content, } res = ATCutils.push_to_confluence(confluence_data, self.apipath, self.auth) if res == 'Page updated': print("==> updated page: MP '" + mp.mp_parsed_file['title'] + "'") except Exception as err: print(mp_file + " failed") print("Err message: %s" % err) print('-' * 60) traceback.print_exc(file=sys.stdout) print('-' * 60) print("[+] Mitigation Policies populated!")
def hardening_policy(self, hp_path): """Populate Hardening Policies""" print("[*] Populating Hardening Policies...") if hp_path: hp_list = glob.glob(hp_path + '*.yml') else: hp_dir = ATCconfig.get('hardening_policies_directory') hp_list = glob.glob(hp_dir + '/*.yml') for hp_file in hp_list: try: hp = HardeningPolicy(hp_file) hp.render_template("confluence") confluence_data = { "title": hp.hp_parsed_file["title"], "spacekey": self.space, "parentid": str(ATCutils.confluence_get_page_id( self.apipath, self.auth, self.space, "Hardening Policies")), "confluencecontent": hp.content, } res = ATCutils.push_to_confluence(confluence_data, self.apipath, self.auth) if res == 'Page updated': print("==> updated page: HP '" + hp.hp_parsed_file['title'] + "'") except Exception as err: print(hp_file + " failed") print("Err message: %s" % err) print('-' * 60) traceback.print_exc(file=sys.stdout) print('-' * 60) print("[+] Hardening Policies populated!")
def logging_policy(self, lp_path): """Desc""" print("[*] Populating Logging Policies...") if lp_path: lp_list = glob.glob(lp_path + '*.yml') else: lp_dir = ATCconfig.get('logging_policies_dir') lp_list = glob.glob(lp_dir + '/*.yml') for lp_file in lp_list: try: lp = LoggingPolicy(lp_file) lp.render_template("confluence") confluence_data = { "title": lp.fields["title"], "spacekey": self.space, "parentid": str(ATCutils.confluence_get_page_id( self.apipath, self.auth, self.space, "Logging Policies")), "confluencecontent": lp.content, } res = ATCutils.push_to_confluence(confluence_data, self.apipath, self.auth) if res == 'Page updated': print("==> updated page: LP '" + lp.fields['title'] + "'") # print("Done: ", lp.fields['title']) except Exception as err: print(lp_file + " failed") print("Err message: %s" % err) print('-' * 60) traceback.print_exc(file=sys.stdout) print('-' * 60) print("[+] Logging Policies populated!")
def render_template(self, template_type): """Description template_type: - "confluence" """ if template_type not in ["confluence"]: raise Exception("Bad template_type. Available value:" + " \"confluence\"]") # Get proper template template = env.get_template( 'confluence_responseaction_template.html.j2') new_title = self.ra_parsed_file.get('id')\ + ": "\ + ATCutils.normalize_react_title(self.ra_parsed_file.get('title')) self.ra_parsed_file.update({'title': new_title}) self.ra_parsed_file.update({ 'confluence_viewpage_url': ATCconfig.get('confluence_viewpage_url') }) ## ## Add link to a stage ## stage = self.ra_parsed_file.get('stage') rs_list = [] for rs_id, rs_name in rs_mapping.items(): if ATCutils.normalize_rs_name(stage) == rs_name: if self.apipath and self.auth and self.space: rs_confluence_page_id = str( ATCutils.confluence_get_page_id( self.apipath, self.auth, self.space, rs_name)) rs_list.append((rs_id, rs_name, rs_confluence_page_id)) else: rs_confluence_page_id = "" rs_list.append((rs_id, rs_name, rs_confluence_page_id)) break self.ra_parsed_file.update({'stage': rs_list}) # Category self.ra_parsed_file.update({ 'category': ATCutils.get_ra_category(self.ra_parsed_file.get('id')) }) self.ra_parsed_file.update( {'description': self.ra_parsed_file.get('description').strip()}) self.ra_parsed_file.update( {'workflow': self.ra_parsed_file.get('workflow')}) self.content = template.render(self.ra_parsed_file)
def detection_rule(self, dr_path): """Desc""" print("Populating Detection Rules..") if dr_path: dr_list = glob.glob(dr_path + '*.yml') else: dr_dirs = ATCconfig.get('detection_rules_directories') # check if config provides multiple directories for detection rules if isinstance(dr_dirs, list): dr_list = [] for directory in dr_dirs: dr_list += glob.glob(directory + '/*.yml') elif isinstance(dr_dirs, str): dr_list = glob.glob(dr_dirs + '/*.yml') for dr_file in dr_list: try: dr = DetectionRule(dr_file, apipath=self.apipath, auth=self.auth, space=self.space) dr.render_template("confluence") confluence_data = { "title": dr.fields['title'], "spacekey": self.space, "parentid": str( ATCutils.confluence_get_page_id( self.apipath, self.auth, self.space, "Detection Rules")), "confluencecontent": dr.content, } res = ATCutils.push_to_confluence(confluence_data, self.apipath, self.auth) if res == 'Page updated': print("==> updated page: DR '" + dr.fields['title'] + "' (" + dr_file + ")") # print("Done: ", dr.fields['title']) except Exception as err: print(dr_file + " failed") print("Err message: %s" % err) print('-' * 60) traceback.print_exc(file=sys.stdout) print('-' * 60) print("Detection Rules populated!")
def main(): dr_dirs = ATCconfig.get('detection_rules_directories') dr_list = [] for path in dr_dirs: dr_list.append(ATCutils.load_yamls(path)) # flat dr_list dr_list = [dr for drs_from_path in dr_list for dr in drs_from_path] list_of_customers = get_customers() for customer in list_of_customers: rules = find_rules_per_customer(customer, dr_list) techniques = get_techniques(rules) tab_name = {"name": customer.get('customer_name')} NAVIGATOR_TEMPLATE.update(tab_name) NAVIGATOR_TEMPLATE['techniques'] = techniques filename = 'atc_attack_navigator_profile_' + \ customer.get('title') + '.json' exported_analytics_directory = \ ATCconfig.get('exported_analytics_directory') + \ "/attack_navigator_profiles" with open(exported_analytics_directory + '/' + filename, 'w') as fp: json.dump(NAVIGATOR_TEMPLATE, fp) print(f'[+] Created {filename}')
def triggers(self, tg_path): """Populate triggers""" if self.art_dir and self.atc_dir: r = ATCutils.populate_tg_markdown(art_dir=self.art_dir, atc_dir=self.atc_dir) elif self.art_dir: r = ATCutils.populate_tg_markdown(art_dir=self.art_dir) elif self.atc_dir: r = ATCutils.populate_tg_markdown(atc_dir=self.atc_dir) else: r = ATCutils.populate_tg_markdown() return r
def response_playbook(self, rp_path): """Nothing here yet""" print("Populating Response Playbooks..") if rp_path: rp_list = glob.glob(rp_path + '*.yml') else: rp_dir = ATCconfig.get('response_playbooks_dir') rp_list = glob.glob(rp_dir + '/*.yml') for rp_file in rp_list: try: rp = ResponsePlaybook(rp_file, apipath=self.apipath, auth=self.auth, space=self.space) rp.render_template("confluence") base = os.path.basename(rp_file) confluence_data = { "title": rp.rp_parsed_file['title'], "spacekey": self.space, "parentid": str( ATCutils.confluence_get_page_id( self.apipath, self.auth, self.space, "Response Playbooks")), "confluencecontent": rp.content, } res = ATCutils.push_to_confluence(confluence_data, self.apipath, self.auth) if res == 'Page updated': print("==> updated page: RP '" + base + "'") # print("Done: ", rp.rp_parsed_file['title']) except Exception as err: print(rp_file + " failed") print("Err message: %s" % err) print('-' * 60) traceback.print_exc(file=sys.stdout) print('-' * 60) print("Response Playbooks populated!")
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\"]") # Point to the templates directory env = Environment(loader=FileSystemLoader('templates')) # Get proper template if template_type == "markdown": template = env.get_template( 'markdown_responseaction_template.md.j2') self.ra_parsed_file.update({ 'description': self.ra_parsed_file.get('description').strip() }) elif template_type == "confluence": template = env.get_template( 'confluence_responseaction_template.html.j2') self.ra_parsed_file.update({ 'confluence_viewpage_url': ATCconfig.get('confluence_viewpage_url') }) linked_ra = self.ra_parsed_file.get("linked_ra") if linked_ra: linked_ra_with_id = [] for ra in linked_ra: if self.apipath and self.auth and self.space: linked_ra_id = str( ATCutils.confluence_get_page_id( self.apipath, self.auth, self.space, ra)) else: linked_ra_id = "" ra = (ra, linked_ra_id) linked_ra_with_id.append(ra) self.ra_parsed_file.update({'linkedra': linked_ra_with_id}) self.ra_parsed_file.update({ 'description': self.ra_parsed_file.get('description').strip() }) self.ra_parsed_file.update( {'workflow': self.ra_parsed_file.get('workflow') + ' \n\n.'}) self.content = template.render(self.ra_parsed_file)
def enrichment(self, en_path): """Nothing here yet""" print("Populating Enrichments..") if en_path: en_list = glob.glob(en_path + '*.yml') else: en_dir = ATCconfig.get('enrichments_directory') en_list = glob.glob(en_dir + '/*.yml') for en_file in en_list: try: en = Enrichment(en_file, apipath=self.apipath, auth=self.auth, space=self.space) en.render_template("confluence") confluence_data = { "title": en.en_parsed_file['title'], "spacekey": self.space, "parentid": str( ATCutils.confluence_get_page_id( self.apipath, self.auth, self.space, "Enrichments")), "confluencecontent": en.content, } res = ATCutils.push_to_confluence(confluence_data, self.apipath, self.auth) if res == 'Page updated': print("==> updated page: EN '" + en.en_parsed_file['title'] + "'") # print("Done: ", en.en_parsed_file['title']) except Exception as err: print(en_file + " failed") print("Err message: %s" % err) print('-' * 60) traceback.print_exc(file=sys.stdout) print('-' * 60) print("Enrichments populated!")
def save_markdown_file(self, atc_dir='../Atomic_Threat_Coverage/'): """Write content (md template filled with data) to a file""" base = os.path.basename(self.yaml_file) title = os.path.splitext(base)[0] file_path = atc_dir + self.parent_title + "/" + \ title + ".md" return ATCutils.write_file(file_path, self.content)
def customer(self, cu_path): """Nothing here yet""" print("Populating Customers..") if cu_path: cu_list = glob.glob(cu_path + '*.yml') else: cu_dir = ATCconfig.get('customers_directory') cu_list = glob.glob(cu_dir + '/*.yml') for cu_file in cu_list: try: cu = Customer(cu_file, apipath=self.apipath, auth=self.auth, space=self.space) cu.render_template("confluence") confluence_data = { "title": cu.customer_name, "spacekey": self.space, "parentid": str( ATCutils.confluence_get_page_id( self.apipath, self.auth, self.space, "Customers")), "confluencecontent": cu.content, } res = ATCutils.push_to_confluence(confluence_data, self.apipath, self.auth) if res == 'Page updated': print("==> updated page: CU '" + cu.customer_name + "'") # print("Done: ", cu.title) except Exception as err: print(cu_file + " failed") print("Err message: %s" % err) print('-' * 60) traceback.print_exc(file=sys.stdout) print('-' * 60) print("Customers populated!")
def load_yamls(path): yamls = [join(path, f) for f in listdir(path) if isfile( join(path, f)) if f.endswith('.yaml') or f.endswith('.yml')] result = [] for yaml in yamls: try: result.append(ATCutils.read_yaml_file(yaml)) except ScannerError: raise ScannerError('yaml is bad! %s' % yaml) return result, yamls
def save_markdown_file(self, atc_dir='../' + ATCconfig.get('md_name_of_root_directory') + '/'): """Write content (md template filled with data) to a file""" base = os.path.basename(self.yaml_file) title = os.path.splitext(base)[0] file_path = atc_dir + self.parent_title + "/" + \ title + ".md" # Should return True return ATCutils.write_file(file_path, self.content)
def triggers(self, tg_path): """Populate Triggers""" print("Populating Triggers..") if self.art_dir and self.atc_dir: r = ATCutils.populate_tg_markdown(art_dir=self.art_dir, atc_dir=self.atc_dir) elif self.art_dir: r = ATCutils.populate_tg_markdown(art_dir=self.art_dir) elif self.atc_dir: r = ATCutils.populate_tg_markdown(atc_dir=self.atc_dir) else: r = ATCutils.populate_tg_markdown() print("Triggers populated!") return r
def response_action(self, ra_path): """Nothing here yet""" print("Populating Response Actions..") if ra_path: ra_list = glob.glob(ra_path + '*.yml') else: ra_list = glob.glob('../response_actions/*.yml') for ra_file in ra_list: try: ra = ResponseAction(ra_file, apipath=self.apipath, auth=self.auth, space=self.space) ra.render_template("confluence") confluence_data = { "title": ra.ra_parsed_file['title'], "spacekey": self.space, "parentid": str( ATCutils.confluence_get_page_id( self.apipath, self.auth, self.space, "Response Actions")), "confluencecontent": ra.content, } ATCutils.push_to_confluence(confluence_data, self.apipath, self.auth) # print("Done: ", ra.ra_parsed_file['title']) except Exception as err: print(ra_file + " failed") print("Err message: %s" % err) print('-' * 60) traceback.print_exc(file=sys.stdout) print('-' * 60) print("Response Actions populated!")
def detection_rule(self, dr_path): """Desc""" print("Populating Detection Rules..") if dr_path: dr_list = glob.glob(dr_path + '*.yml') else: dr_list = glob.glob( ATCconfig.get('detection_rules_directory') + '/*.yml') for dr_file in dr_list: try: dr = DetectionRule(dr_file, apipath=self.apipath, auth=self.auth, space=self.space) dr.render_template("confluence") confluence_data = { "title": dr.fields['title'], "spacekey": self.space, "parentid": str( ATCutils.confluence_get_page_id( self.apipath, self.auth, self.space, "Detection Rules")), "confluencecontent": dr.content, } ATCutils.push_to_confluence(confluence_data, self.apipath, self.auth) print("Done: ", dr.fields['title']) except Exception as err: print(dr_file + " failed") print("Err message: %s" % err) print('-' * 60) traceback.print_exc(file=sys.stdout) print('-' * 60) print("Detection Rules populated!")
def triggers(self, tg_path): """Populate Triggers""" print("Populating Triggers..") if tg_path: tg_list = glob.glob(tg_path + '*.yml') else: tg_list = glob.glob( ATCconfig.get("triggers_directory") + '/T*/*.yaml') for tg_file in tg_list: try: tg = Triggers(tg_file) tg.render_template("confluence") title = tg.fields["attack_technique"] + ": " + \ te_mapping.get(tg.fields["attack_technique"]) confluence_data = { "title": title, "spacekey": self.space, "parentid": str( ATCutils.confluence_get_page_id( self.apipath, self.auth, self.space, "Triggers")), "confluencecontent": tg.content, } res = ATCutils.push_to_confluence(confluence_data, self.apipath, self.auth) if res == 'Page updated': print("==> updated page: TR '" + title + "'") # print("Done: ", tg.fields["attack_technique"]) except Exception as err: print(tg_file + " failed") print("Err message: %s" % err) print('-' * 60) traceback.print_exc(file=sys.stdout) print('-' * 60) print("Triggers populated!")
def create_markdown_dirs(): config = ATCutils.load_config('config.yml') base_dir = Path( config.get('md_name_of_root_directory', '../Atomic_Threat_Coverage')) target_dir_list = [ 'Detection_Rules', 'Logging_Policies', 'Data_Needed', 'Triggers', 'Response_Actions', 'Response_Playbooks', 'Enrichments', 'Customers' ] for item in target_dir_list: (base_dir / item).mkdir(parents=True, exist_ok=True)
def parse_into_fields(self): """Description""" # self.fields contains parsed fields obtained from yaml file self.cu_fields = ATCutils.read_yaml_file(self.yaml_file) """Fill the fields with values. Put None if key not found""" self.title = self.cu_fields.get('title') self.customer_name = self.cu_fields.get('customer_name') self.description = self.cu_fields.get('description') self.data_needed = self.cu_fields.get('dataneeded') self.logging_policies = self.cu_fields.get('loggingpolicy') self.detection_rules = self.cu_fields.get('detectionrule')
def mitigation_system(self, ms_path): """Populate Mitigation Systems""" print("Populating Mitigation Systems..") if ms_path: ms_list = glob.glob(ms_path + '*.yml') else: ms_dir = ATCconfig.get('mitigation_systems_directory') ms_list = glob.glob(ms_dir + '/*.yml') for ms_file in ms_list: try: ms = MitigationSystem(ms_file) ms.render_template("confluence") confluence_data = { "title": ms.ms_parsed_file["title"], "spacekey": self.space, "parentid": str( ATCutils.confluence_get_page_id( self.apipath, self.auth, self.space, "Mitigation Systems")), "confluencecontent": ms.content, } ATCutils.push_to_confluence(confluence_data, self.apipath, self.auth) except Exception as err: print(ms_file + " failed") print("Err message: %s" % err) print('-' * 60) traceback.print_exc(file=sys.stdout) print('-' * 60) print("Mitigation Systems populated!")
def checkRA(self, stage): if self.rp_rule.get(stage): for rule in self.rp_rule.get(stage): try: rtask = ATCutils.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) + " | " + \ str(rtask.get('title')) task.group = rtask.get('stage', 'Unknown stage') task.description = str(rtask.get('workflow')) self.case.tasks.append(task.return_dictionary()) if rtask.get('linked_ra'): self.task_prefix = float(self.task_prefix) for linked_ra in rtask.get('linked_ra'): try: rtask = ATCutils.read_yaml_file(self.inputRA + linked_ra + ".yml") except OSError: print("Response Action %s not existing\n" % rule) continue task = THC.TheHiveTask(order=self.task_order) self.task_order += 1 self.task_prefix += 0.1 task.title = str(round(self.task_prefix, 1)) + \ " | " + str(rtask.get('title')) task.title = str(round(self.task_prefix, 1)) + " | "\ + str(rtask.get("title")) task.group = rtask.get('stage', 'Unknown stage') task.description = str(rtask.get('workflow')) self.case.tasks.append(task.return_dictionary())
def parse_into_fields(self, yaml_file): """Description""" # self.dn_fields contains parsed fields obtained from yaml file self.dn_fields = ATCutils.read_yaml_file(yaml_file) """Fill the fields with values. Put None if key not found""" self.title = self.dn_fields.get("title") self.description = self.dn_fields.get("description") self.loggingpolicy = self.dn_fields.get("loggingpolicy") self.platform = self.dn_fields.get("platform") self.type = self.dn_fields.get("type") self.channel = self.dn_fields.get("channel") self.provider = self.dn_fields.get("provider") self.fields = self.dn_fields.get("fields") self.sample = self.dn_fields.get("sample")
def main(): dr_dirs = ATCconfig.get('detection_rules_directories') dr_list = [] for path in dr_dirs: dr_list.append(ATCutils.load_yamls(path)) # flat dr_list dr_list = [dr for drs_from_path in dr_list for dr in drs_from_path] techniques = get_techniques(dr_list) NAVIGATOR_TEMPLATE['techniques'] = techniques filename = 'atc_attack_navigator_profile.json' exported_analytics_directory = \ ATCconfig.get('exported_analytics_directory') + "/attack_navigator_profiles" with open(exported_analytics_directory + '/' + filename, 'w') as fp: json.dump(NAVIGATOR_TEMPLATE, fp) print(f'[+] Created {filename}')
def convertRPToTemplate(self, file_input, output_file): self.rp_rule = ATCutils.read_yaml_file(file_input) self.case = THC.TheHiveCase() self.case.name = self.rp_rule.get('title') self.case.description = "Description:\n" + \ str(self.rp_rule.get('description')) + \ '\n\nWorkflow:\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)))
from enrichment import Enrichment from responseaction import ResponseAction from responseplaybook import ResponsePlaybook from customer import Customer from attack_mapping import te_mapping # , ta_mapping # Import ATC Utils from atcutils import ATCutils # Others import glob import sys import traceback import os ATCconfig = ATCutils.load_config("config.yml") class PopulateConfluence: """Desc""" def __init__(self, auth, lp=False, dn=False, dr=False, en=False, tg=False, ra=False, rp=False, cu=False, ms=False,
def parse_into_fields(self, yaml_file): """Description""" self.ra_parsed_file = ATCutils.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\"]") # Point to the templates directory env = Environment(loader=FileSystemLoader('templates')) # Get proper template if template_type == "markdown": template = env\ .get_template('markdown_dataneeded_template.md.j2') logging_policies = self.dn_fields.get("loggingpolicy") if isinstance(logging_policies, str): logging_policies = [logging_policies] refs = self.dn_fields.get("references") self.dn_fields.update({'loggingpolicy': logging_policies}) self.dn_fields.update( {'description': self.dn_fields.get('description').strip()}) if isinstance(refs, str): self.dn_fields.update({'references': [refs]}) elif template_type == "confluence": template = env\ .get_template('confluence_dataneeded_template.html.j2') self.dn_fields.update({ 'confluence_viewpage_url': ATCconfig.get('confluence_viewpage_url') }) self.dn_fields.update( {'description': self.dn_fields.get('description').strip()}) logging_policies = self.dn_fields.get("loggingpolicy") if not logging_policies: logging_policies = [ "None", ] logging_policies_with_id = [] for lp in logging_policies: if lp != "None" and self.apipath and self.auth and self.space: logging_policies_id = str( ATCutils.confluence_get_page_id( self.apipath, self.auth, self.space, lp)) else: logging_policies_id = "" lp = (lp, logging_policies_id) logging_policies_with_id.append(lp) refs = self.dn_fields.get("references") if isinstance(refs, str): self.dn_fields.update({'references': [refs]}) self.dn_fields.update({'loggingpolicy': logging_policies_with_id}) self.content = template.render(self.dn_fields) return True
def render_template(self, template_type): """Render template with data in it template_type: - "markdown" - "confluence" """ if template_type not in ["markdown", "confluence"]: raise Exception("Bad template_type. Available values: " + "[\"markdown\", \"confluence\"]") # Point to the templates directory env = Environment(loader=FileSystemLoader('templates')) # Get proper template if template_type == "markdown": template = env.get_template('markdown_alert_template.md.j2') # Read raw sigma rule sigma_rule = ATCutils.read_rule_file(self.yaml_file) # Put raw sigma rule into fields var self.fields.update({'sigma_rule': sigma_rule}) # Define which queries we want from Sigma #queries = ["es-qs", "xpack-watcher", "graylog", "splunk", "logpoint", "grep", "fieldlist"] queries = ATCconfig.get('detection_queries').split(",") # dict to store query key + query values det_queries = {} # Convert sigma rule into queries (for instance, graylog query) for query in queries: # prepare command to execute from shell # (yes, we know) cmd = ATCconfig.get('sigmac_path') + " --shoot-yourself-in-the-foot -t " + \ query + " --ignore-backend-errors " + self.yaml_file #query + " --ignore-backend-errors " + self.yaml_file + \ #" 2> /dev/null" p = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True) (query2, err) = p.communicate() # Wait for date to terminate. Get return returncode # p_status = p.wait() p.wait() """ Had to remove '-' due to problems with Jinja2 variable naming, e.g es-qs throws error 'no es variable' """ det_queries[query] = str(query2)[2:-3] # Update detection rules self.fields.update({"det_queries": det_queries}) self.fields.update({"queries": queries}) # Data Needed data_needed = ATCutils.main_dn_calculatoin_func(self.yaml_file) # if there is only 1 element in the list, print it as a string, # without quotes # if isistance(data_needed, list) and len(data_needed) == 1: # [data_needed] = data_needed # print("%s || Dataneeded: \n%s\n" % # (self.fields.get("title"), data_needed)) self.fields.update({'data_needed': data_needed}) # Enrichments enrichments = self.fields.get("enrichment") if isinstance(enrichments, str): enrichments = [enrichments] self.fields.update({'enrichment': enrichments}) tactic = [] tactic_re = re.compile(r'attack\.\w\D+$') technique = [] technique_re = re.compile(r'attack\.t\d{1,5}$') other_tags = [] if self.fields.get('tags'): for tag in self.fields.get('tags'): if tactic_re.match(tag): if ta_mapping.get(tag): tactic.append(ta_mapping.get(tag)) else: other_tags.append(tag) elif technique_re.match(tag): te = tag.upper()[7:] technique.append((te_mapping.get(te), te)) else: other_tags.append(tag) if not tactic_re.match(tag) and not \ technique_re.match(tag): other_tags.append(tag) if len(tactic): self.fields.update({'tactics': tactic}) if len(technique): self.fields.update({'techniques': technique}) if len(other_tags): self.fields.update({'other_tags': other_tags}) triggers = [] for trigger in technique: if trigger is "None": continue try: triggers.append(trigger) except FileNotFoundError: print(trigger + ": No atomics trigger for this technique") """ triggers.append( trigger + ": No atomics trigger for this technique" ) """ self.fields.update( {'description': self.fields.get('description').strip()}) self.fields.update({'triggers': triggers}) elif template_type == "confluence": template = env.get_template('confluence_alert_template.html.j2') self.fields.update({ 'confluence_viewpage_url': ATCconfig.get('confluence_viewpage_url') }) sigma_rule = ATCutils.read_rule_file(self.yaml_file) self.fields.update({'sigma_rule': sigma_rule}) outputs = ["es-qs", "xpack-watcher", "graylog"] for output in outputs: cmd = ATCconfig.get('sigmac_path') + " -t " + \ output + " --ignore-backend-errors " + self.yaml_file + \ " 2> /dev/null" p = subprocess.Popen(cmd, stdout=subprocess.PIPE, shell=True) (query, err) = p.communicate() # Wait for date to terminate. Get return returncode ## # p_status = p.wait() p.wait() # have to remove '-' due to problems with # Jinja2 variable naming,e.g es-qs throws error # 'no es variable' self.fields.update({output.replace("-", ""): str(query)[2:-3]}) # Data Needed data_needed = ATCutils.main_dn_calculatoin_func(self.yaml_file) data_needed_with_id = [] for data in data_needed: data_needed_id = str( ATCutils.confluence_get_page_id(self.apipath, self.auth, self.space, data)) data = (data, data_needed_id) data_needed_with_id.append(data) self.fields.update({'data_needed': data_needed_with_id}) # Enrichments enrichments = self.fields.get("enrichment") enrichments_with_page_id = [] if isinstance(enrichments, str): enrichments = [enrichments] if enrichments: for enrichment_name in enrichments: enrichment_page_id = str( ATCutils.confluence_get_page_id( self.apipath, self.auth, self.space, enrichment_name)) enrichment_data = (enrichment_name, enrichment_page_id) enrichments_with_page_id.append(enrichment_data) self.fields.update({'enrichment': enrichments_with_page_id}) tactic = [] tactic_re = re.compile(r'attack\.\w\D+$') technique = [] technique_re = re.compile(r'attack\.t\d{1,5}$') other_tags = [] if self.fields.get('tags'): for tag in self.fields.get('tags'): if tactic_re.match(tag): if ta_mapping.get(tag): tactic.append(ta_mapping.get(tag)) else: other_tags.append(tag) elif technique_re.match(tag): te = tag.upper()[7:] technique.append((te_mapping.get(te), te)) else: other_tags.append(tag) if not tactic_re.match(tag) and not \ technique_re.match(tag): other_tags.append(tag) if len(tactic): self.fields.update({'tactics': tactic}) if len(technique): self.fields.update({'techniques': technique}) if len(other_tags): self.fields.update({'other_tags': other_tags}) triggers = [] for trigger_name, trigger_id in technique: if trigger_id is "None": continue try: page_name = trigger_id + ": " + trigger_name trigger_page_id = str( ATCutils.confluence_get_page_id( self.apipath, self.auth, self.space, page_name)) trigger = (trigger_name, trigger_id, trigger_page_id) triggers.append(trigger) except FileNotFoundError: print(trigger + ": No atomics trigger for this technique") self.fields.update({'triggers': triggers}) self.content = template.render(self.fields) # Need to convert ampersand into HTML "save" format # Otherwise confluence throws an error # self.content = self.content.replace("&", "&") # Done in the template itself return True