Skip to content
This repository was archived by the owner on Dec 11, 2023. It is now read-only.

Commit 893f9ab

Browse files
author
clittle
committed
Efficency pass 1 - now using objects to clean things up a bit
1 parent 216261b commit 893f9ab

2 files changed

Lines changed: 94 additions & 76 deletions

File tree

layers/exporters/excel_templates.py

Lines changed: 3 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,11 @@ def _build_raw(self, showName=True, showID=False, subtechs=[], exclude=[]):
5252
c = sheet.cell(row=entry[0], column=entry[1])
5353
write_val = ''
5454
if showName and showID:
55-
write_val = self._get_ID(template[entry]) + ': ' + template[entry]
55+
write_val = MatrixGen._get_ID(self.codex, template[entry]) + ': ' + template[entry]
5656
elif showName:
5757
write_val = template[entry]
5858
elif showID:
59-
write_val = self._get_ID(template[entry])
59+
write_val = MatrixGen._get_ID(self.codex, template[entry])
6060
c.value = write_val
6161
if entry[0] == 1:
6262
c.font = header_template_f
@@ -83,41 +83,6 @@ def _build_raw(self, showName=True, showID=False, subtechs=[], exclude=[]):
8383

8484
return wb
8585

86-
def _get_ID(self, name):
87-
"""
88-
INTERNAL - Do lookups to retrieve the ID of a technique given it's name
89-
90-
:param name: The name of the technique to retrieve the ID of
91-
:return: The ID of the technique referenced by name
92-
"""
93-
t_lookup = {'Initial Access': 'TA0001',
94-
'Execution': 'TA0002',
95-
'Persistence': 'TA0003',
96-
'Privilege Escalation': 'TA0004',
97-
'Defense Evasion': 'TA0005',
98-
'Credential Access': 'TA0006',
99-
'Discovery': 'TA0007',
100-
'Lateral Movement': 'TA0008',
101-
'Collection': 'TA0009',
102-
'Command and Control': 'TA0011',
103-
'Exfiltration': 'TA0010',
104-
'Impact': 'TA0040'}
105-
for col in self.codex:
106-
for elm in col:
107-
for key in elm:
108-
if key == 'tactic':
109-
if elm[key] == name:
110-
return t_lookup[elm[key]]
111-
elif key == 'subtechs':
112-
for en in elm[key]:
113-
for ent in elm[key][en]:
114-
for sub in ent:
115-
if name == sub:
116-
return str(ent[sub])
117-
else:
118-
if name == key:
119-
return str(elm[key])
120-
12186
def export(self, showName, showID, subtechs=[], exclude=[]):
12287
"""
12388
Export a raw customized excel template
@@ -140,18 +105,7 @@ def retrieve_coords(self, techniqueID, tactic=None):
140105
:return: A tuple representing the (row, column) of the target element in the workbook
141106
"""
142107
listing = []
143-
match = ''
144-
for col in self.codex:
145-
for elm in col:
146-
for name in elm:
147-
if name == "subtechs":
148-
for sp in elm[name]:
149-
for t in elm[name][sp]:
150-
for na in t:
151-
if t[na] == techniqueID:
152-
match = na
153-
if elm[name] == techniqueID:
154-
match = name
108+
match = MatrixGen._get_name(self.codex, techniqueID)
155109
for entry in self.template:
156110
if self.template[entry] == match:
157111
if tactic is not None:

layers/exporters/matrix_gen.py

Lines changed: 91 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,30 @@
22
from stix2 import TAXIICollectionSource, Filter, FileSystemSource
33
from taxii2client import Server, Collection
44

5+
class MatrixEntry:
6+
def __init__(self, id=None, name=None):
7+
if id is not None:
8+
self.id = id
9+
if name is not None:
10+
self.name = name
11+
12+
@property
13+
def id(self):
14+
if self.__id is not None:
15+
return self.__id
16+
17+
@id.setter
18+
def id(self, id):
19+
self.__id = id
20+
21+
@property
22+
def name(self):
23+
if self.__name is not None:
24+
return self.__name
25+
26+
@name.setter
27+
def name(self, name):
28+
self.__name = name
529

630
class MatrixGen:
731
convert = {
@@ -18,6 +42,18 @@ class MatrixGen:
1842
'exfiltration': 'Exfiltration',
1943
'impact': 'Impact'
2044
}
45+
t_lookup = {'Initial Access': 'TA0001',
46+
'Execution': 'TA0002',
47+
'Persistence': 'TA0003',
48+
'Privilege Escalation': 'TA0004',
49+
'Defense Evasion': 'TA0005',
50+
'Credential Access': 'TA0006',
51+
'Discovery': 'TA0007',
52+
'Lateral Movement': 'TA0008',
53+
'Collection': 'TA0009',
54+
'Command and Control': 'TA0011',
55+
'Exfiltration': 'TA0010',
56+
'Impact': 'TA0040'}
2157
def __init__(self, fresh=True):
2258
"""
2359
Initialization - Creates a matrix generator object
@@ -64,19 +100,19 @@ def _get_technique_listing(self, tactic, mode='enterprise'):
64100
:param tactic: The tactic to grab techniques from
65101
:param mode: The domain to draw from
66102
"""
67-
techniques = {}
103+
techniques = []
68104
subtechs = {}
69105
techs = self.collections[mode].query([Filter('type', '=', 'attack-pattern'), Filter('kill_chain_phases.phase_name', '=', tactic)])
70106
for entry in techs:
71107
if entry['kill_chain_phases'][0]['kill_chain_name'] == 'mitre-attack':
72108
tid = [t['external_id'] for t in entry['external_references'] if t['source_name'] == 'mitre-attack']
73109
if '.' not in tid[0]:
74-
techniques[entry['name']] = tid[0]
110+
techniques.append(MatrixEntry(id=tid[0], name=entry['name']))
75111
else:
76112
parent = tid[0].split('.')[0]
77113
if parent not in subtechs:
78114
subtechs[parent] = []
79-
subtechs[parent].append({entry['name']: tid[0]})
115+
subtechs[parent].append(MatrixEntry(id=tid[0], name=entry['name']))
80116
return techniques, subtechs
81117

82118
@staticmethod
@@ -107,18 +143,18 @@ def _construct_panop(codex, subtechs, excludes):
107143
sr = entry[0]
108144
joins.append([entry[0], column-1, len(stechs[entry[1]])])
109145
for element in stechs[entry[1]]:
110-
matrix_obj[(sr, column)] = [x for x in element.keys()][0]
146+
matrix_obj[(sr, column)] = element.name
111147
sr += 1
112148
cycle = False
113149
column += 1
114150
row = 2
115-
matrix_obj[(1, column)] = col[0]['tactic']
116-
c_name = col[0]['tactic']
151+
matrix_obj[(1, column)] = col[0].name
152+
c_name = col[0].name
117153
stechs = col[1]['subtechs']
118154
to_add = []
119155
for element in col[2:]:
120-
elname = [x for x in element.keys()][0]
121-
tid = element[[x for x in element.keys()][0]]
156+
elname = element.name
157+
tid = element.id
122158
skip = False
123159
for entry in range(0, len(et)):
124160
if et[entry] == tid and (e_tacs[entry] == False or MatrixGen.convert[e_tacs[entry]] == c_name):
@@ -139,6 +175,48 @@ def _construct_panop(codex, subtechs, excludes):
139175
row += 1
140176
return matrix_obj, joins
141177

178+
@staticmethod
179+
def _get_ID(codex, name):
180+
"""
181+
INTERNAL - Do lookups to retrieve the ID of a technique given it's name
182+
183+
:param codex: The list of lists matrix object (output of build_matrix)
184+
:param name: The name of the technique to retrieve the ID of
185+
:return: The ID of the technique referenced by name
186+
"""
187+
for col in codex:
188+
for elm in col:
189+
if col.index(elm) == 1:
190+
for sp in elm['subtechs']:
191+
for t in elm['subtechs'][sp]:
192+
if t.name == name:
193+
return t.id
194+
else:
195+
if elm.name == name:
196+
return elm.id
197+
return ''
198+
199+
@staticmethod
200+
def _get_name(codex, id):
201+
"""
202+
INTERNAL - Do lookups to retrieve the name of a technique given it's ID
203+
204+
:param codex: The list of lists matrix object (output of build_matrix)
205+
:param id: The ID of the technique to retrieve the name of
206+
:return: The name of the technique referenced by id
207+
"""
208+
for col in codex:
209+
for elm in col:
210+
if col.index(elm) == 1:
211+
for sp in elm['subtechs']:
212+
for t in elm['subtechs'][sp]:
213+
if t.id == id:
214+
return t.name
215+
else:
216+
if elm.id == id:
217+
return elm.name
218+
return ''
219+
142220
def build_matrix(self, mode='enterprise'):
143221
"""
144222
Build a ATT&CK matrix object, as a list of lists containing technique dictionaries
@@ -149,29 +227,15 @@ def build_matrix(self, mode='enterprise'):
149227
tacs = self._get_tactic_listing(mode)
150228
for tac in tacs:
151229
techs, subtechs = self._get_technique_listing(tac.lower().replace(' ', '-'), mode)
152-
colm = [dict(tactic=tac)]
153-
temp = []
230+
colm = [MatrixEntry(id=self.t_lookup[tac], name=tac)]
154231
stemp = {}
155232
# sort subtechniques via id, append to column
156233
for par in subtechs:
157-
stemp[par] = []
158-
temp = []
159-
for entry in subtechs[par]:
160-
for obj in entry:
161-
temp.append(entry[obj])
162-
for entry in sorted(temp):
163-
obj = {}
164-
for k in subtechs[par]:
165-
for j in k:
166-
if k[j] == entry:
167-
obj[j] = entry
168-
stemp[par].append(obj)
234+
subtechs[par].sort(key=lambda x: x.name)
235+
stemp[par] = subtechs[par]
169236
colm.append({'subtechs':stemp})
170-
temp = []
171237
# sort techniques alphabetically, append to column
172-
for entry in techs:
173-
temp.append(entry)
174-
for entry in sorted(temp):
175-
colm.append({entry:techs[entry]})
238+
techs.sort(key=lambda x: x.name)
239+
colm.extend(techs)
176240
matrix.append(colm)
177241
return matrix

0 commit comments

Comments
 (0)