This commit is contained in:
Yugoslavskiy Daniil 2020-05-12 04:02:15 +02:00
parent 18e780c398
commit 83aab8a5e9
10 changed files with 358 additions and 463 deletions

View File

@ -130,8 +130,8 @@ if __name__ == '__main__':
dn=args.dataneeded, dr=args.detectionrule,
tg=args.triggers, en=args.enrichment,
ra=args.responseactions, rp=args.responseplaybook,
cu=args.customers, hp=args.hardeningpolicy,
init=args.init)
rs=args.responsestage, cu=args.customers,
hp=args.hardeningpolicy, init=args.init)
elif args.react_stix:
GenerateSTIX()

View File

@ -11,6 +11,7 @@ from triggers import Triggers
from enrichment import Enrichment
from responseaction import ResponseAction
from responseplaybook import ResponsePlaybook
from responsestage import ResponseStage
from customer import Customer
from attack_mapping import te_mapping # , ta_mapping
@ -30,11 +31,11 @@ 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, mp=False, hp=False,
ra=False, rp=False, rs=False, cu=False, ms=False, mp=False, hp=False,
auto=False, art_dir=False, atc_dir=False, lp_path=False,
dn_path=False, dr_path=False, en_path=False, tg_path=False,
ra_path=False, rp_path=False, cu_path=False, hp_path=False,
ms_path=False, mp_path=False, init=False):
ra_path=False, rp_path=False, rs_path=False, cu_path=False,
hp_path=False, ms_path=False, mp_path=False, init=False):
"""Desc"""
self.auth = auth
@ -79,8 +80,10 @@ class PopulateConfluence:
self.data_needed(dn_path)
self.enrichment(en_path)
self.triggers(tg_path)
self.response_stage(rs_path)
self.response_action(ra_path)
self.response_playbook(rp_path)
self.response_stage(rs_path)
self.detection_rule(dr_path)
self.customer(cu_path)
@ -106,11 +109,18 @@ class PopulateConfluence:
self.detection_rule(dr_path)
if ra:
print("[*] We need to create Response Stages first...")
self.response_stage(rs_path)
self.response_action(ra_path)
print("[*] Updating Response Stages...")
self.response_stage(rs_path)
if rp:
self.response_playbook(rp_path)
if rs:
self.response_stage(rs_path)
if tg:
self.triggers(tg_path)
@ -127,7 +137,7 @@ class PopulateConfluence:
def triggers(self, tg_path):
"""Populate Triggers"""
print("Populating Triggers..")
print("[*] Populating Triggers...")
if tg_path:
tg_list = glob.glob(tg_path + '*.yml')
else:
@ -160,12 +170,12 @@ class PopulateConfluence:
traceback.print_exc(file=sys.stdout)
print('-' * 60)
print("Triggers populated!")
print("[+] Triggers populated!")
def hardening_policy(self, hp_path):
"""Populate Hardening Policies"""
print("Populating Hardening Policies..")
print("[*] Populating Hardening Policies...")
if hp_path:
hp_list = glob.glob(hp_path + '*.yml')
else:
@ -195,12 +205,12 @@ class PopulateConfluence:
print('-' * 60)
traceback.print_exc(file=sys.stdout)
print('-' * 60)
print("Hardening Policies populated!")
print("[+] Hardening Policies populated!")
def mitigation_system(self, ms_path):
"""Populate Mitigation Systems"""
print("Populating Mitigation Systems..")
print("[*] Populating Mitigation Systems...")
if ms_path:
ms_list = glob.glob(ms_path + '*.yml')
else:
@ -230,12 +240,12 @@ class PopulateConfluence:
print('-' * 60)
traceback.print_exc(file=sys.stdout)
print('-' * 60)
print("Mitigation Systems populated!")
print("[+] Mitigation Systems populated!")
def mitigation_policy(self, mp_path):
"""Populate Mitigation Policies"""
print("Populating Mitigation Policies..")
print("[*] Populating Mitigation Policies...")
if mp_path:
mp_list = glob.glob(mp_path + '*.yml')
else:
@ -266,12 +276,12 @@ class PopulateConfluence:
print('-' * 60)
traceback.print_exc(file=sys.stdout)
print('-' * 60)
print("Mitigation Policies populated!")
print("[+] Mitigation Policies populated!")
def logging_policy(self, lp_path):
"""Desc"""
print("Populating Logging Policies..")
print("[*] Populating Logging Policies...")
if lp_path:
lp_list = glob.glob(lp_path + '*.yml')
else:
@ -302,12 +312,12 @@ class PopulateConfluence:
print('-' * 60)
traceback.print_exc(file=sys.stdout)
print('-' * 60)
print("Logging Policies populated!")
print("[+] Logging Policies populated!")
def data_needed(self, dn_path):
"""Desc"""
print("Populating Data Needed..")
print("[*] Populating Data Needed...")
if dn_path:
dn_list = glob.glob(dn_path + '*.yml')
else:
@ -338,12 +348,12 @@ class PopulateConfluence:
print('-' * 60)
traceback.print_exc(file=sys.stdout)
print('-' * 60)
print("Data Needed populated!")
print("[+] Data Needed populated!")
def detection_rule(self, dr_path):
"""Desc"""
print("Populating Detection Rules..")
print("[*] Populating Detection Rules...")
if dr_path:
dr_list = glob.glob(dr_path + '*.yml')
else:
@ -382,12 +392,12 @@ class PopulateConfluence:
print('-' * 60)
traceback.print_exc(file=sys.stdout)
print('-' * 60)
print("Detection Rules populated!")
print("[+] Detection Rules populated!")
def enrichment(self, en_path):
"""Nothing here yet"""
print("Populating Enrichments..")
print("[*] Populating Enrichments...")
if en_path:
en_list = glob.glob(en_path + '*.yml')
else:
@ -419,12 +429,12 @@ class PopulateConfluence:
print('-' * 60)
traceback.print_exc(file=sys.stdout)
print('-' * 60)
print("Enrichments populated!")
print("[+] Enrichments populated!")
def response_action(self, ra_path):
"""Nothing here yet"""
print("Populating Response Actions..")
print("[*] Populating Response Actions...")
if ra_path:
ra_list = glob.glob(ra_path + '*.yml')
else:
@ -456,12 +466,12 @@ class PopulateConfluence:
traceback.print_exc(file=sys.stdout)
print('-' * 60)
print("Response Actions populated!")
print("[+] Response Actions populated!")
def response_playbook(self, rp_path):
"""Nothing here yet"""
print("Populating Response Playbooks..")
print("[*] Populating Response Playbooks...")
if rp_path:
rp_list = glob.glob(rp_path + '*.yml')
else:
@ -496,12 +506,52 @@ class PopulateConfluence:
print('-' * 60)
traceback.print_exc(file=sys.stdout)
print('-' * 60)
print("Response Playbooks populated!")
print("[+] Response Playbooks populated!")
def response_stage(self, rs_path):
"""Nothing here yet"""
print("[*] Populating Response Stages...")
if rs_path:
rs_list = glob.glob(rs_path + '*.yml')
else:
rs_dir = ATCconfig.get('response_stages_dir')
rs_list = glob.glob(rs_dir + '/*.yml')
for rs_file in rs_list:
try:
rs = ResponseStage(rs_file, apipath=self.apipath,
auth=self.auth, space=self.space)
rs.render_template("confluence")
base = os.path.basename(rs_file)
confluence_data = {
"title": rs.rs_parsed_file['title'],
"spacekey": self.space,
"parentid": str(ATCutils.confluence_get_page_id(
self.apipath, self.auth, self.space,
"Response Stages")),
"confluencecontent": rs.content,
}
res = ATCutils.push_to_confluence(confluence_data, self.apipath,
self.auth)
if res == 'Page updated':
print("==> updated page: RS '" + base + "'")
# print("Done: ", rp.rp_parsed_file['title'])
except Exception as err:
print(rs_file + " failed")
print("Err message: %s" % err)
print('-' * 60)
traceback.print_exc(file=sys.stdout)
print('-' * 60)
print("[+] Response Stages populated!")
def customer(self, cu_path):
"""Nothing here yet"""
print("Populating Customers..")
print("[+] Populating Customers...")
if cu_path:
cu_list = glob.glob(cu_path + '*.yml')
else:
@ -534,4 +584,4 @@ class PopulateConfluence:
print('-' * 60)
traceback.print_exc(file=sys.stdout)
print('-' * 60)
print("Customers populated!")
print("[+] Customers populated!")

View File

@ -7,11 +7,13 @@ from react_scripts.react_mapping import rs_mapping
import os
# ########################################################################### #
# ########################### Response Action ############################### #
# ########################################################################### #
ATCconfig = ATCutils.load_config("config.yml")
env = Environment(loader=FileSystemLoader('templates'))
class ResponseAction:
@ -22,9 +24,6 @@ class ResponseAction:
# Init vars
self.yaml_file = yaml_file
# The name of the directory containing future markdown LogginPolicy
self.parent_title = "Response_Actions"
self.apipath = apipath
self.auth = auth
self.space = space
@ -40,85 +39,66 @@ class ResponseAction:
def render_template(self, template_type):
"""Description
template_type:
- "markdown"
- "confluence"
"""
if template_type not in ["markdown", "confluence"]:
if template_type not in ["confluence"]:
raise Exception(
"Bad template_type. Available values:" +
" [\"markdown\", \"confluence\"]")
# Point to the templates directory
env = Environment(loader=FileSystemLoader('templates'))
"Bad template_type. Available value:" +
" \"confluence\"]")
# Get proper template
if template_type == "markdown":
template = env.get_template(
'markdown_responseaction_template.md.j2'
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}
)
self.ra_parsed_file.update(
{'title': ATCutils.normalize_react_title(self.ra_parsed_file
.get('title'))}
)
# 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(
{'description': self.ra_parsed_file.get('description').strip()}
)
elif template_type == "confluence":
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')})
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')}
)
self.ra_parsed_file.update(
{'workflow': self.ra_parsed_file.get('workflow')}
)
self.content = template.render(self.ra_parsed_file)
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"
return ATCutils.write_file(file_path, self.content)

View File

@ -24,8 +24,6 @@ class ResponsePlaybook:
# Init vars
self.yaml_file = yaml_file
# The name of the directory containing future markdown LogginPolicy
self.parent_title = "Response_Playbooks"
self.apipath = apipath
self.auth = auth
@ -46,288 +44,177 @@ class ResponsePlaybook:
- "confluence"
"""
if template_type not in ["markdown", "confluence"]:
if template_type not in ["confluence"]:
raise Exception(
"Bad template_type. Available values:" +
" [\"markdown\", \"confluence\"]")
" \"confluence\"]")
# Point to the templates directory
env = Environment(loader=FileSystemLoader('templates'))
# Get proper template
if template_type == "markdown":
template = env.get_template(
'markdown_responseplaybook_template.md.j2'
)
self.rp_parsed_file.update(
{'title': ATCutils.normalize_react_title(self.rp_parsed_file
.get('title'))}
)
template = env.get_template(
'confluence_responseplaybook_template.html.j2'
)
# MITRE ATT&CK Tactics and Techniques
tactic = []
tactic_re = re.compile(r'attack\.\w\D+$')
technique = []
technique_re = re.compile(r'attack\.t\d{1,5}$')
# 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}$')
new_title = self.rp_parsed_file.get('id')\
+ ": "\
+ ATCutils.normalize_react_title(self.rp_parsed_file.get('title'))
self.rp_parsed_file.update(
{'title': new_title }
)
other_tags = []
self.rp_parsed_file.update(
{'confluence_viewpage_url': ATCconfig.get('confluence_viewpage_url')})
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)
# MITRE ATT&CK Tactics and Techniques
tactic = []
tactic_re = re.compile(r'attack\.\w\D+$')
technique = []
technique_re = re.compile(r'attack\.t\d{1,5}$')
# 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}$')
# 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})
other_tags = []
preparation = []
identification = []
containment = []
eradication = []
recovery = []
lessons_learned = []
detect = []
deny = []
disrupt = []
degrade = []
deceive = []
destroy = []
deter = []
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)
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)
]
# 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})
# 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 = ATCutils.read_yaml_file(
ATCconfig.get('response_actions_dir')
+ '/' + task + '.yml'
)
# get links to response action
action_title = action.get('id')\
+ ":"\
+ ATCutils.normalize_react_title(action.get('title'))
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 = ATCutils.read_yaml_file(
ATCconfig.get('response_actions_dir')
+ '/' + task + '.yml'
)
action_title = action.get('id')\
+ ": "\
+ ATCutils.normalize_react_title(action.get('title'))
if self.apipath and self.auth and self.space:
stage_list.append(
(action_title, task, action.get('description'), action.get('workflow'))
)
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': stages})
self.rp_parsed_file.update(
{'description': self.rp_parsed_file
.get('description').strip()}
)
elif template_type == "confluence":
template = env.get_template(
'confluence_responseplaybook_template.html.j2'
)
new_title = self.rp_parsed_file.get('id')\
+ ": "\
+ ATCutils.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': ATCconfig.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{1,5}$')
# 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 = ATCutils.read_yaml_file(
ATCconfig.get('response_actions_dir')
+ '/' + task + '.yml'
)
action_title = action.get('id')\
+ ": "\
+ ATCutils.normalize_react_title(action.get('title'))
if self.apipath and self.auth and self.space:
stage_list.append(
(action_title,
str(ATCutils.confluence_get_page_id(
self.apipath, self.auth,
self.space, action_title)
)
(action_title,
str(ATCutils.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 = ATCutils.read_yaml_file(
ATCconfig.get('response_actions_dir')
+ '/' + task + '.yml')
stage_list.append(
(action.get('description'),
action.get('workflow'))
)
)
except TypeError:
pass
else:
stage_list.append((action_title, ""))
# change stages name to more pretty format
stages = [(stage_name.replace('_', ' ').capitalize(), stage_list)
for stage_name, stage_list in stages]
except TypeError:
pass
self.rp_parsed_file.update({'stages': stages})
self.rp_parsed_file.update(
{'workflow':
self.rp_parsed_file.get('workflow')
}
)
self.rp_parsed_file.update(
{'description': self.rp_parsed_file
.get('description').strip()}
)
# 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 = ATCutils.read_yaml_file(
ATCconfig.get('response_actions_dir')
+ '/' + task + '.yml')
stage_list.append(
(action.get('description'),
action.get('workflow'))
)
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': stages})
self.rp_parsed_file.update(
{'workflow':
self.rp_parsed_file.get('workflow')
}
)
self.rp_parsed_file.update(
{'description': self.rp_parsed_file
.get('description').strip()}
)
# Render
self.content = template.render(self.rp_parsed_file)
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"
return ATCutils.write_file(file_path, self.content)

View File

@ -1,24 +1,27 @@
#!/usr/bin/env python3
from scripts.atcutils import ATCutils
from atcutils import ATCutils
from jinja2 import Environment, FileSystemLoader
from scripts.react_mapping import rs_mapping
from react_scripts.react_mapping import rs_mapping
import os
ATCconfig = ATCutils.load_config("scripts/config.yml")
ATCconfig = ATCutils.load_config("config.yml")
env = Environment(loader=FileSystemLoader('templates'))
class ResponseStage:
"""Class for the Playbook Stage entity"""
def __init__(self, yaml_file):
def __init__(self, yaml_file, apipath=None, auth=None, space=None):
"""Init method"""
# Init vars
self.apipath = apipath
self.auth = auth
self.space = space
self.yaml_file = yaml_file
# The name of the directory containing future markdown Response_Stages
self.parent_title = "Response_Stages"
# Init methods
self.parse_into_fields(self.yaml_file)
@ -26,7 +29,7 @@ class ResponseStage:
def parse_into_fields(self, yaml_file):
"""Description"""
self.ra_parsed_file = ATCutils.read_yaml_file(yaml_file)
self.rs_parsed_file = ATCutils.read_yaml_file(yaml_file)
def render_template(self, template_type):
"""Description
@ -34,28 +37,29 @@ class ResponseStage:
- "markdown"
"""
if template_type not in ["markdown"]:
if template_type not in ["confluence"]:
raise Exception(
"Bad template_type. Available values:" +
" [\"markdown\"]")
# Point to the templates directory
env = Environment(loader=FileSystemLoader('scripts/templates'))
" \"confluence\"]")
template = env.get_template(
'markdown_responsestage_template.md.j2'
'confluence_responsestage_template.html.j2'
)
self.ra_parsed_file.update(
{'description': self.ra_parsed_file
self.rs_parsed_file.update(
{'description': self.rs_parsed_file
.get('description').strip()}
)
ras, ra_paths = ATCutils.load_yamls_with_paths(ATCconfig.get('response_actions_dir'))
ra_filenames = [ra_path.split('/')[-1].replace('.yml', '') for ra_path in ra_paths]
ras, ra_paths = ATCutils.load_yamls_with_paths(
ATCconfig.get('response_actions_dir'))
ra_filenames = [ra_path.split('/')[-1].replace('.yml', '')
for ra_path in ra_paths]
rs_id = self.rs_parsed_file.get('id')
rs_id = self.ra_parsed_file.get('id')
self.rs_parsed_file.update(
{'confluence_viewpage_url': ATCconfig.get('confluence_viewpage_url')})
stage_list = []
@ -65,20 +69,28 @@ class ResponseStage:
ra_filename = ra_filenames[i]
ra_title = ATCutils.normalize_react_title(ras[i].get('title'))
ra_description = ras[i].get('description').strip()
stage_list.append((ra_id, ra_filename, ra_title, ra_description))
ra_confluence_page_name = ra_id + ": " + ra_title
print(ra_confluence_page_name)
if self.apipath and self.auth and self.space:
ra_confluence_page_id = str(ATCutils.confluence_get_page_id(
self.apipath, self.auth, self.space, ra_confluence_page_name)
)
else:
ra_confluence_page_id = ""
self.ra_parsed_file.update({'stage_list': sorted(stage_list)})
print(ra_confluence_page_id)
stage_list.append(
(ra_id, ra_filename, ra_title, ra_description, ra_confluence_page_id))
self.content = template.render(self.ra_parsed_file)
new_title = self.rs_parsed_file.get('id')\
+ ": "\
+ ATCutils.normalize_react_title(self.rs_parsed_file.get('title'))
def save_markdown_file(self,
atc_dir=ATCconfig.get('md_name_of_root_directory')):
"""Write content (md template filled with data) to a file"""
self.rs_parsed_file.update(
{'title': new_title}
)
base = os.path.basename(self.yaml_file)
title = os.path.splitext(base)[0]
self.rs_parsed_file.update({'stage_list': sorted(stage_list)})
file_path = atc_dir + self.parent_title + "/" + \
title + ".md"
return ATCutils.write_file(file_path, self.content)
self.content = template.render(self.rs_parsed_file)

View File

@ -26,9 +26,15 @@
<td class="confluenceTd">{{ creation_date|e }}<br /></td>
</tr>
{% endif %}
<tr>
<th class="confluenceTh">Category</th>
<td class="confluenceTd">{{ category|e }}<br /></td>
</tr>
<tr>
<th class="confluenceTh">Stage</th>
<td class="confluenceTd">{{ stage|e }}<br /></td>
{%- for rs_id, rs_name, rs_confluence_page_id in stage %}
<td class="confluenceTd"><a href="{{confluence_viewpage_url}}{{rs_confluence_page_id}}">{{ rs_id }}: {{ rs_name }}</a><br /></td>
{% endfor -%}
</tr>
{% if automation is defined and automation|length %}
<tr>

View File

@ -0,0 +1,29 @@
<b>ID:</b>{{ id|e }}
<pre><br/></pre>
{{ description }}
{%- if stage_list is not none and stage_list|length -%}
<h2>Response Actions</h2>
<table data-layout="default"><colgroup><col /><col /><col /></colgroup>
<tbody>
<tr>
<th>
<p style="text-align: center;"><strong>ID</strong></p></th>
<th>
<p style="text-align: center;"><strong>Name</strong></p></th>
<th>
<p><strong>Description</strong></p>
</th>
</tr>
{%- for ra_id, ra_filename, ra_title, ra_description, ra_confluence_page_id in stage_list -%}
<tr>
<td>
<p><a href="{{confluence_viewpage_url}}{{ra_confluence_page_id}}">{{ ra_id }}</a></p></td>
<td>
<p><a href="{{confluence_viewpage_url}}{{ra_confluence_page_id}}">{{ ra_title }}</a></p></td>
<td>
<p>{{ ra_description }}</p></td>
</tr>
{%- endfor -%}
</tbody></table>
<p />
{%- endif -%}

View File

@ -1,11 +0,0 @@
| Title | {{ title }} |
|:---------------------------:|:--------------------|
| **ID** | {{ id }} |
| **Description** | {{ description }} |
| **Author** | {{ author }} |
| **Creation Date** | {{ creation_date }} |
| **Stage** | {{ stage }} |{% if automation is not none and automation|length %}{{ '\n' }}| **Automation** |<ul>{% for auto in automation %}<li>{{ auto }}</li>{% endfor %}</ul>|{% endif %}{% if references is not none and references|length %}{{ '\n' }}| **References** |<ul>{% for ref in references %}<li>[{{ ref }}]({{ ref }})</li>{% endfor %}</ul>|{% endif %}{% if requirements is not none and requirements|length %}{{ '\n' }}| **Requirements** |<ul>{% for requirement in requirements %}<li>{{ requirement }}</li>{% endfor %}</ul>|{% endif %}
### Workflow
{{ workflow }}

View File

@ -1,43 +0,0 @@
| Title | {{ title }} |
|:-----------------:|:-----------------------------------------------------------------------------------------------------------------|
| **ID** | {{ id }} |
| **Description** | {{ description }} |
| **Author** | {{ author }} |
| **Creation Date** | {{ creation_date }} |
| **Severity** | {{ severity }} |
| **TLP** | {{ tlp }} |
| **PAP** | {{ pap }} |
{%- if tactics is not none and tactics|length -%}
{{ '\n' }}| **ATT&amp;CK Tactic** |<ul>{%- for tactic_name, tactic_id in tactics %}<li>[{{ tactic_id }}: {{tactic_name}}](https://attack.mitre.org/tactics/{{tactic_id}})</li>{% endfor -%}</ul>|
{%- endif -%}
{%- if techniques is not none and tactics|length -%}
{{ '\n' }}| **ATT&amp;CK Technique** |<ul>{% for technique_name, technique_id in techniques %}<li>[{{ technique_id }}: {{technique_name}}](https://attack.mitre.org/tactics/{{technique_id}})</li>{% endfor -%}</ul>|
{%- endif -%}
{%- if amitt_tactics is not none and amitt_tactics|length -%}
{{ '\n' }}| **AM&excl;TT Tactic** |<ul>{%- for tactic_name, tactic_id in amitt_tactics %}<li>[{{ tactic_id }}: {{tactic_name}}](https://vvx7.xyz/tactics/{{tactic_id}})</li>{% endfor %}</ul>|
{%- endif -%}
{%- if amitt_techniques is not none and amitt_techniques|length -%}
{{ '\n' }}| **AM&excl;TT Technique** |<ul>{% for technique_name, technique_id in amitt_techniques %}<li>[{{ technique_id }}: {{technique_name}}](https://vvx7.xyz/tactics/{{technique_id}})</li>{% endfor %}</ul>|
{%- endif -%}
{%- if other_tags is not none and other_tags|length -%}
{{ '\n' }}| **Tags** | <ul>{% for tag in other_tags %}<li>{{ tag }}</li>{% endfor %}</ul> |
{%- endif -%}
{%- for stage_name, stage_actions in stages -%}
{%- if stage_actions is not none and stage_actions|length -%}
{{'\n'}}| **{{stage_name}}** |<ul>{% for action_title, action_filename, action_description, action_workflow in stage_actions %}<li>[{{ action_title }}](../Response_Actions/{{action_filename}}.md)</li>{% endfor %}</ul>|
{%- endif -%}
{%- endfor %}
### Workflow
{{ workflow }}
{% for stage_name, stage_actions in stages %}
{% if stage_actions is not none and stage_actions|length %}#### {{ stage_name }}{% endif %}
{% for action_title, action_filename, action_description, action_workflow in stage_actions%}
##### {{ action_description }}
{{ action_workflow }}
{%- endfor %}
{%- endfor %}

View File

@ -1,15 +0,0 @@
# {{ title }}
**ID**: {{ id }}
{{ description }}
{%- if stage_list is not none and stage_list|length -%}
{{ '\n' }}## Response Actions
| ID | Name | Description |
|:-----:|:--------:|-------------|
{%- for ra_id, ra_filename, ra_title, ra_description in stage_list -%}
{{ '\n' }}| [{{ ra_id }}](../Response_Actions/{{ra_filename}}.md) | [{{ ra_title }}](../Response_Actions/{{ra_filename}}.md) | {{ra_description}} |
{%- endfor -%}
{%- endif -%}