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

Commit c4a1975

Browse files
author
clittle
committed
Updates to streamline things, clean up approach
1 parent 7824a8e commit c4a1975

6 files changed

Lines changed: 306 additions & 180 deletions

File tree

layers/README.md

Lines changed: 33 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,12 @@ This folder contains modules and scripts for working with ATT&CK Navigator layer
2121
#### Exporter Scripts
2222
| script | description |
2323
|:-------|:------------|
24-
| [matrix_gen](exporters/matrix_gen.py) | Provides a means by which to generate a matrix from raw data, either cached or from the ATT&CK TAXII server. |
25-
| [excel_templates](exporters/excel_templates.py) | Provides a means by which to convert a matrix into a base excel template. |
2624
| [to_excel](exporters/to_excel.py) | Provides a means by which to export an ATT&CK Layer to an excel file. A further breakdown can be found in the corresponding section below. |
25+
##### Utility Modules
26+
| script | description |
27+
|:-------|:------------|
28+
| [excel_templates](exporters/excel_templates.py) | Provides a means by which to convert a matrix into a base excel template. |
29+
| [matrix_gen](exporters/matrix_gen.py) | Provides a means by which to generate a matrix from raw data, either cached or from the ATT&CK TAXII server. |
2730

2831
## Layer
2932
The Layer class provides format validation and read/write capabilities to aid in working with ATT&CK Navigator Layers in python. It is the primary interface through which other Layer-related classes defined in the core module should be used. The Layer class API and a usage example are below.
@@ -128,35 +131,50 @@ out_layer6.to_file("C:\demo_layer6.json") # Save combined co
128131
```
129132

130133
## to_excel.py
131-
to_excel.py provides the ToExcel class, which is a way to export an existing layer file as an Excel spreadsheet. The ToExcel class has an optional parameter for the export function, `to_file()`, that tells the exporter to build the output matrix based on live data from cti-taxii.mitre.org. Otherwise, it will use the cached subtechniques data. If matrix template lacks elements included in a layer's technique listing, those elements will not be visible in the output file.
134+
to_excel.py provides the ToExcel class, which is a way to export an existing layer file as an Excel
135+
spreadsheet. The ToExcel class has an optional parameter for the initialization function, that
136+
tells the exporter to build the output matrix based on live data from cti-taxii.mitre.org. It
137+
can also use cached subtechniques data. If neither of these is used, it will default to pulling from the
138+
ATT&CK cti repo. If matrix template lacks elements included in a layer's technique listing, those
139+
elements will not be visible in the output file.
132140

133141
##### ToExcel()
134142
```python
135-
x = ToExcel(layer=None)
143+
x = ToExcel(domain='enterprise', server=False, local=None)
136144
```
137-
The ToExcel constructor takes an options layer argument during instantiation. If no layer is loaded at this time, it must be loaded later before exporting `x.layer = Layer()`.
145+
The ToExcel constructor takes domain, server, and local arguments during instantiation. The domain can
146+
be either 'enterprise' or 'mobile', and can be pulled from a layer file as `layer.domain`. The server
147+
argument tells the matrix generation tool to use the `cti-taxii` server when building the matrix. The
148+
local argument tells the matrix generation tool the path to a local stix repository to use when
149+
constructing the matrix.
138150

139151
##### .to_file() Method
140152
```python
141-
x.to_file(filepath="layer.xlsx", fresh=False)
153+
x.to_xlsx(layer=layer, filepath="layer.xlsx")
142154
```
143-
The to_file method exports the layer file loaded in the ToExcel class (`x`), as an excel file to the
144-
filepath specified. The fresh parameter is an optional parameter that bases the export on a matrix built
145-
from the live data on the taxii server (`True`), or based on cached data (`False`).
146-
155+
The to_xlsx method exports the layer file referenced as `layer`, as an excel file to the
156+
`filepath` specified.
147157

148158
#### Example Usage
149159
```python
150160
from layers import Layer
151161
from layers import ToExcel
152162

163+
164+
lay3 = Layer()
165+
lay3.from_file('layers/heatmap_example.json')
166+
exporter = ToExcel(domain=lay3.layer.domain, server=False, local=None)
167+
exporter.to_xlsx(layer=lay3, filepath="layer.xlsx")
168+
153169
lay = Layer()
154170
lay.from_file("path/to/layer/file.json")
155171
# Using cached data for template
156-
t = ToExcel(lay)
157-
t.to_file("demo.xlsx")
172+
t = ToExcel(domain=lay.layer.domain, server=False, local=None)
173+
t.to_xlsx(layer=lay, filepath="demo.xlsx")
158174
# Using live data for templates
159-
t2 = ToExcel()
160-
t2.layer = lay
161-
t.to_file("demo2.xlsx", fresh=True)
175+
t2 = ToExcel(domain='enterprise', server=True, local=None)
176+
t.to_xlsx(layer=lay, filepath="demo2.xlsx")
177+
#Using cached local data for templates
178+
t3 = ToExcel(domain='mobile', server=False, local='path/to/local/stix')
179+
t3.to_xlsx(layer=lay, filepath="demo3.xlsx")
162180
```

layers/core/gradient.py

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -58,17 +58,20 @@ def _compute_curve(self):
5858
Computes the gradient color curve
5959
"""
6060
if self.maxValue is not None and self.minValue is not None and self.colors is not None:
61-
if len(self.colors) == 2:
62-
s_c = colour.Color(self.colors[0])
63-
e_c = colour.Color(self.colors[1])
64-
self.curve = list(s_c.range_to(e_c, self.maxValue - self.minValue))
65-
else:
66-
s_c = colour.Color(self.colors[0])
67-
m_c = colour.Color(self.colors[1])
68-
e_c = colour.Color(self.colors[2])
69-
self.curve = list(s_c.range_to(m_c, int(math.floor(self.maxValue - self.minValue)/2)))
70-
curve_2 = list(m_c.range_to(e_c, int(math.ceil(self.maxValue - self.minValue)/2)))
61+
chunksize = int(math.floor((self.maxValue - self.minValue)/(len(self.colors) - 1)))
62+
fchunksize = int(math.ceil((self.maxValue - self.minValue)/(len(self.colors) - 1)))
63+
self.curve = []
64+
index = 1
65+
while index < len(self.colors):
66+
s_c = colour.Color(self.colors[index-1])
67+
e_c = colour.Color(self.colors[index])
68+
if index == len(self.colors):
69+
curve_2 = list(s_c.range_to(e_c, fchunksize))
70+
else:
71+
curve_2 = list(s_c.range_to(e_c, chunksize))
72+
index += 1
7173
self.curve.extend(curve_2)
74+
self.curve.append(colour.Color(self.colors[-1]))
7275

7376
def compute_color(self, score):
7477
"""
@@ -77,9 +80,9 @@ def compute_color(self, score):
7780
the gradient
7881
"""
7982
if score <= self.minValue:
80-
return self.colors[0]
83+
return self.curve[0].hex_l
8184
if score >= self.maxValue:
82-
return self.colors[-1]
85+
return self.curve[-1].hex_l
8386

8487
target = self.curve[score - self.minValue]
8588
return target.hex_l

layers/exporters/excel_templates.py

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,33 +11,37 @@ class BadTemplateException(Exception):
1111

1212
class ExcelTemplates:
1313

14-
def __init__(self, fresh=False, mode='enterprise'):
14+
def __init__(self, server=False, local=None, domain='enterprise'):
1515
"""
1616
Initialization - Creates a ExcelTemplate object
1717
18-
:param mode: The domain to utilize
18+
:param server: Whether or not to use the taxii server to build the matrix
19+
:param local: Optional path to local taxii data
20+
:param domain: The domain to utilize
1921
"""
20-
muse = mode
22+
muse = domain
2123
if muse.startswith('mitre-'):
22-
muse = mode[6:]
24+
muse = domain[6:]
2325
if muse in ['enterprise', 'mobile']:
2426
self.mode = muse
25-
h = MatrixGen(fresh=fresh)
26-
self.codex = h.build_matrix(muse)
27+
self.h = MatrixGen(server=server, local=local)
28+
self.codex = self.h.get_matrix(muse)
2729
else:
2830
raise BadTemplateException
2931

30-
def _build_raw(self, showName=True, showID=False, subtechs=[], exclude=[]):
32+
def _build_raw(self, showName=True, showID=False, sort=0, scores=[], subtechs=[], exclude=[]):
3133
"""
3234
INTERNAL - builds a raw, not-yet-marked-up excel document based on the specifications
3335
3436
:param showName: Whether or not to display names for each entry
3537
:param showID: Whether or not to display Technique IDs for each entry
38+
:param sort: The sort mode to use
3639
:param subtechs: List of all visible subtechniques
3740
:param exclude: List of of techniques to exclude from the matrix
3841
:return: a openpyxl workbook object containing the raw matrix
3942
"""
40-
template, joins = MatrixGen._construct_panop(self.codex, subtechs, exclude)
43+
self.codex = self.h._adjust_ordering(self.codex, sort, scores)
44+
template, joins = self.h._construct_panop(self.codex, subtechs, exclude)
4145
self.template = template
4246
wb = openpyxl.Workbook()
4347

@@ -52,11 +56,11 @@ def _build_raw(self, showName=True, showID=False, subtechs=[], exclude=[]):
5256
c = sheet.cell(row=entry[0], column=entry[1])
5357
write_val = ''
5458
if showName and showID:
55-
write_val = MatrixGen._get_ID(self.codex, template[entry]) + ': ' + template[entry]
59+
write_val = self.h._get_ID(self.codex, template[entry]) + ': ' + template[entry]
5660
elif showName:
5761
write_val = template[entry]
5862
elif showID:
59-
write_val = MatrixGen._get_ID(self.codex, template[entry])
63+
write_val = self.h._get_ID(self.codex, template[entry])
6064
c.value = write_val
6165
if entry[0] == 1:
6266
c.font = header_template_f
@@ -83,18 +87,19 @@ def _build_raw(self, showName=True, showID=False, subtechs=[], exclude=[]):
8387

8488
return wb
8589

86-
def export(self, showName, showID, subtechs=[], exclude=[]):
90+
def export(self, showName, showID, sort=0, scores=[], subtechs=[], exclude=[]):
8791
"""
8892
Export a raw customized excel template
8993
9094
9195
:param showName: Whether or not to display names for each entry
9296
:param showID: Whether or not to display Technique IDs for each entry
97+
:param sort: The sort mode to utilize
9398
:param subtechs: List of all visible subtechniques
9499
:param exclude: List of of techniques to exclude from the matrix
95100
return: a openpyxl workbook object containing the raw matrix
96101
"""
97-
return self._build_raw(showName, showID, subtechs, exclude)
102+
return self._build_raw(showName, showID, sort, scores, subtechs, exclude)
98103

99104
def retrieve_coords(self, techniqueID, tactic=None):
100105
"""
@@ -105,16 +110,21 @@ def retrieve_coords(self, techniqueID, tactic=None):
105110
:return: A tuple representing the (row, column) of the target element in the workbook
106111
"""
107112
listing = []
108-
match = MatrixGen._get_name(self.codex, techniqueID)
113+
match = self.h._get_name(self.codex, techniqueID)
109114
for entry in self.template:
110115
if self.template[entry] == match:
111116
if tactic is not None:
112117
try:
113-
if self.template[(1, entry[1])] != MatrixGen.convert[tactic]:
118+
if self.template[(1, entry[1])] != self.h.convert(tactic):
114119
continue
115120
except KeyError:
116121
# account for subtechniques when scanning
117-
if self.template[(1, entry[1] - 1)] != MatrixGen.convert[tactic]:
122+
if self.template[(1, entry[1] - 1)] != self.h.convert(tactic):
118123
continue
119124
listing.append(entry)
125+
if listing == []:
126+
if '.' in techniqueID:
127+
parent = self.retrieve_coords(techniqueID.split('.')[0], tactic)
128+
if parent != []:
129+
return 'HIDDEN'
120130
return listing

0 commit comments

Comments
 (0)