-
Notifications
You must be signed in to change notification settings - Fork 147
/
Copy pathtactic.py
141 lines (105 loc) · 4.62 KB
/
tactic.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
import json
import os
import requests
import collections
import urllib3
import re
import markdown
import stix2
from . import config
from . import stixhelpers
from . import util
def generate():
"""Responsible for verifying tactic directory and generating tactic
index markdown
"""
# Verify if directory exists
if not os.path.isdir(config.tactics_markdown_path):
os.mkdir(config.tactics_markdown_path)
techniques = {}
techniques_no_sub = {}
tactics = {}
for domain in config.domains:
#Reads the STIX and creates a list of the ATT&CK Techniques
techniques[domain] = stixhelpers.get_techniques(config.ms[domain])
techniques_no_sub[domain] = util.filter_out_subtechniques(techniques[domain])
tactics[domain] = stixhelpers.get_tactic_list(config.ms[domain])
side_nav_data = util.get_side_nav_domains_data("tactics", tactics)
for domain in config.domains:
generate_domain_markdown(domain, techniques_no_sub, tactics, side_nav_data)
def generate_domain_markdown(domain, techniques_no_sub, tactics, side_nav_data):
"""Generate tactic index markdown for each domain and generates
shared data for tactics
"""
# Filter sub-techniques from technique list
# Write out the markdown file for overview of domain
data = {
'domain': domain.split("-")[0],
'tactics_list_len': str(len(tactics))
}
data['side_menu_data'] = side_nav_data
data['tactics_table'] = get_domain_table_data(tactics[domain])
subs = config.tactic_domain_md.substitute(data)
subs = subs + json.dumps(data)
with open(os.path.join(config.tactics_markdown_path, data['domain'] + "-tactics.md"), "w", encoding='utf8') as md_file:
md_file.write(subs)
# Write the tactic index.html page
with open(os.path.join(config.tactics_markdown_path, "overview.md"), "w", encoding='utf8') as i_md_file:
i_md_file.write(config.tactic_overview_md)
# Create the markdown for the enterprise groups in the STIX
for tactic in tactics[domain]:
generate_tactic_md(tactic, domain, tactics[domain], techniques_no_sub[domain], side_nav_data)
def generate_tactic_md(tactic, domain, tactic_list, techniques, side_nav_data):
"""Generate markdown for given tactic"""
attack_id = util.get_attack_id(tactic)
# Add if attack id is found
if attack_id:
data = {}
# Fill out data
data['attack_id'] = attack_id
data['name'] = tactic['name']
data['name_lower'] = tactic['name'].lower()
data['descr'] = markdown.markdown(tactic['description'])
data['side_menu_data'] = side_nav_data
data['domain'] = domain.split("-")[0]
dates = util.get_created_and_modified_dates(tactic)
if dates.get('created'):
data['created'] = dates['created']
if dates.get('modified'):
data['modified'] = dates['modified']
# Get techniques that are in the given tactic
techniques_list = get_techniques_of_tactic(tactic, techniques)
data['techniques_table'] = util.get_technique_table_data(tactic, techniques_list)
data['techniques_table_len'] = str(len(techniques_list))
subs = config.tactic_md.substitute(data)
subs = subs + json.dumps(data)
with open(os.path.join(config.tactics_markdown_path, data['attack_id'] + ".md"), "w", encoding='utf8') as md_file:
md_file.write(subs)
def get_domain_table_data(tactic_list):
"""Given a tactic list, returns an array of jsons with tactic name, id
and their description
"""
tactic_table = []
# Set up the tactics table for a domain
for tactic in tactic_list:
attack_id = util.get_attack_id(tactic)
if attack_id:
# Create json and fill out with tactic data
tactic_dict = {}
tactic_dict['name'] = tactic['name']
tactic_dict['tid'] = attack_id
tactic_dict['description'] = tactic['description'].split("\n")[0]
tactic_table.append(tactic_dict)
return tactic_table
def get_techniques_of_tactic(tactic, techniques):
"""Given a tactic and a full list of techniques, return techniques that
appear inside of tactic
"""
techniques_list = []
for technique in techniques:
if not technique.get('x_mitre_deprecated'):
for phase in technique['kill_chain_phases']:
if phase['phase_name'] == tactic['x_mitre_shortname']:
techniques_list.append(technique)
techniques_list = sorted(techniques_list, key=lambda k: k['name'].lower())
return techniques_list