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

Commit 0e0b0cb

Browse files
author
clittle
committed
Further refinement
1 parent c4a1975 commit 0e0b0cb

4 files changed

Lines changed: 62 additions & 50 deletions

File tree

layers/README.md

Lines changed: 14 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ This folder contains modules and scripts for working with ATT&CK Navigator layer
77
|:-------|:------------|
88
| [filter](core/filter.py) | Implements a basic [filter object](https://github.com/mitre-attack/attack-navigator/blob/develop/layers/LAYERFORMATv3.md#filter-object-properties). |
99
| [gradient](core/gradient.py) | Implements a basic [gradient object](https://github.com/mitre-attack/attack-navigator/blob/develop/layers/LAYERFORMATv3.md#gradient-object-properties). |
10-
| [layer](core/layer.py) | Provides an interface for interacting with core module's layer representation. A further breakdown can be found in the corresponding section below. |
10+
| [layer](core/layer.py) | Provides an interface for interacting with core module's layer representation. A further breakdown can be found in the corresponding [section](#Layer) below. |
1111
| [layout](core/layout.py) | Implements a basic [layout object](https://github.com/mitre-attack/attack-navigator/blob/develop/layers/LAYERFORMATv3.md#layout-object-properties). |
1212
| [legenditem](core/legenditem.py) | Implements a basic [legenditem object](https://github.com/mitre-attack/attack-navigator/blob/develop/layers/LAYERFORMATv3.md#legenditem-object-properties). |
1313
| [metadata](core/metadata.py) | Implements a basic [metadata object](https://github.com/mitre-attack/attack-navigator/blob/develop/layers/LAYERFORMATv3.md#metadata-object-properties). |
@@ -16,17 +16,17 @@ This folder contains modules and scripts for working with ATT&CK Navigator layer
1616
#### Manipulator Scripts
1717
| script | description |
1818
|:-------|:------------|
19-
| [layerops](manipulators/layerops.py) | Provides a means by which to combine multiple ATT&CK layer objects in customized ways. A further breakdown can be found in the corresponding section below. |
19+
| [layerops](manipulators/layerops.py) | Provides a means by which to combine multiple ATT&CK layer objects in customized ways. A further breakdown can be found in the corresponding [section](#layerops.py) below. |
2020

2121
#### Exporter Scripts
2222
| script | description |
2323
|:-------|:------------|
24-
| [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. |
24+
| [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](#to_excel.py) below. |
2525
##### Utility Modules
2626
| script | description |
2727
|:-------|:------------|
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. |
28+
| [excel_templates](exporters/excel_templates.py) | Provides a means by which to convert a matrix into a clean excel matrix template. |
29+
| [matrix_gen](exporters/matrix_gen.py) | Provides a means by which to generate a matrix from raw data, either from the ATT&CK TAXII server or from a local collection. |
3030

3131
## Layer
3232
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.
@@ -133,20 +133,14 @@ out_layer6.to_file("C:\demo_layer6.json") # Save combined co
133133
## to_excel.py
134134
to_excel.py provides the ToExcel class, which is a way to export an existing layer file as an Excel
135135
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.
136+
tells the exporter what data source to use when building the output matrix. Valid options include using live data from cti-taxii.mitre.org, using data from the Mitre cti repository, or using a local collection.
140137

141138
##### ToExcel()
142139
```python
143-
x = ToExcel(domain='enterprise', server=False, local=None)
140+
x = ToExcel(domain='enterprise', source='taxii', local=None)
144141
```
145142
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.
143+
be either `enterprise` or `mobile`, and can be pulled directly from a layer file as `layer.domain`. The source argument tells the matrix generation tool which data source to use when building the matrix. `taxii` indicates that the tool should utilize the `cti-taxii` server when building the matrix, while the `repo` and `local` options indicate that it should use the repository and a local collection respectively. The local argument is only required if the source is set to `local`, in which case it should be a path to a local stix collection.
150144

151145
##### .to_file() Method
152146
```python
@@ -160,21 +154,15 @@ The to_xlsx method exports the layer file referenced as `layer`, as an excel fil
160154
from layers import Layer
161155
from layers import ToExcel
162156

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-
169157
lay = Layer()
170158
lay.from_file("path/to/layer/file.json")
171-
# Using cached data for template
172-
t = ToExcel(domain=lay.layer.domain, server=False, local=None)
159+
# Using taxii server for template
160+
t = ToExcel(domain=lay.layer.domain, source='taxii')
173161
t.to_xlsx(layer=lay, filepath="demo.xlsx")
174-
# Using live data for templates
175-
t2 = ToExcel(domain='enterprise', server=True, local=None)
162+
# Using repo data for template
163+
t2 = ToExcel(domain='enterprise', source='repo')
176164
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')
165+
#Using local stix data for template
166+
t3 = ToExcel(domain='mobile', source='local', local='path/to/local/stix')
179167
t3.to_xlsx(layer=lay, filepath="demo3.xlsx")
180168
```

layers/exporters/excel_templates.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,20 @@ class BadTemplateException(Exception):
1111

1212
class ExcelTemplates:
1313

14-
def __init__(self, server=False, local=None, domain='enterprise'):
14+
def __init__(self, source='taxii', local=None, domain='enterprise'):
1515
"""
1616
Initialization - Creates a ExcelTemplate object
1717
18-
:param server: Whether or not to use the taxii server to build the matrix
19-
:param local: Optional path to local taxii data
18+
:param source: Source to use when compiling the matrix
19+
:param local: Optional path to local stix data
2020
:param domain: The domain to utilize
2121
"""
2222
muse = domain
2323
if muse.startswith('mitre-'):
2424
muse = domain[6:]
2525
if muse in ['enterprise', 'mobile']:
2626
self.mode = muse
27-
self.h = MatrixGen(server=server, local=local)
27+
self.h = MatrixGen(source=source, local=local)
2828
self.codex = self.h.get_matrix(muse)
2929
else:
3030
raise BadTemplateException

layers/exporters/matrix_gen.py

Lines changed: 33 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ def score(self):
3737
def score(self, score):
3838
self.__score = score
3939

40-
class MatrixColumn:
40+
class Tactic:
4141
def __init__(self, tactic=None, techniques=None, subtechniques=None):
4242
if tactic is not None:
4343
self.tactic = tactic
@@ -73,8 +73,14 @@ def subtechniques(self):
7373
def subtechniques(self, subtechniques):
7474
self.__subtechniques = subtechniques
7575

76+
class BadSource(Exception):
77+
pass
78+
79+
class BadLocation(Exception):
80+
pass
81+
7682
class MatrixGen:
77-
def __init__(self, server=True, local=None):
83+
def __init__(self, source='taxii', local=None):
7884
"""
7985
Initialization - Creates a matrix generator object
8086
@@ -83,27 +89,38 @@ def __init__(self, server=True, local=None):
8389
:param local: string path to local cache of stix data
8490
"""
8591
self.convert_data = {}
86-
if server:
92+
if source.lower() not in ['taxii', 'local', 'repo']:
93+
print('[MatrixGen] - Unable to generate matrix, source {} is not one of "taxii", "local", '
94+
'or "repo"'.format(source))
95+
raise BadSource
96+
97+
if source.lower() == 'taxii':
8798
self.server = Server('https://cti-taxii.mitre.org/taxii')
8899
self.api_root = self.server.api_roots[0]
89100
self.collections = dict()
90-
91101
for collection in self.api_root.collections:
92102
if collection.title != "PRE-ATT&CK":
93103
tc = Collection('https://cti-taxii.mitre.org/stix/collections/' + collection.id)
94104
self.collections[collection.title.split(' ')[0].lower()] = TAXIICollectionSource(tc)
95-
else:
96-
if local is None:
97-
self.collections = dict()
98-
stix_e = requests.get("https://raw.githubusercontent.com/mitre/cti/subtechniques/enterprise-attack"
99-
"/enterprise-attack.json", verify=False).json()
100-
stix_m = requests.get("https://raw.githubusercontent.com/mitre/cti/subtechniques/mobile-attack/mobile"
101-
"-attack.json", verify=False).json()
102-
self.collections['enterprise'] = MemoryStore(stix_data=stix_e["objects"])
103-
self.collections['mobile'] = MemoryStore(stix_data=stix_m["objects"])
105+
elif source.lower() == 'local':
106+
if local is not None:
107+
try:
108+
self.collections['enterprise'] = FileSystemSource(local)
109+
self.collections['mobile'] = FileSystemSource(local)
110+
except:
111+
raise BadLocation
104112
else:
105-
self.collections['enterprise'] = FileSystemSource(local)
106-
self.collections['mobile'] = FileSystemSource(local)
113+
print('[MatrixGen] - "local" source specified, but path to local source not provided')
114+
raise BadSource
115+
else:
116+
self.collections = dict()
117+
stix_e = requests.get("https://raw.githubusercontent.com/mitre/cti/subtechniques/enterprise-attack"
118+
"/enterprise-attack.json", verify=True).json()
119+
stix_m = requests.get("https://raw.githubusercontent.com/mitre/cti/subtechniques/mobile-attack/mobile"
120+
"-attack.json", verify=True).json()
121+
self.collections['enterprise'] = MemoryStore(stix_data=stix_e["objects"])
122+
self.collections['mobile'] = MemoryStore(stix_data=stix_m["objects"])
123+
107124
self.matrix = {}
108125
self._build_matrix()
109126

@@ -318,7 +335,7 @@ def _build_matrix(self, domain='enterprise'):
318335
stemp[par] = subtechs[par]
319336
# sort techniques alphabetically, append to column
320337
techs.sort(key=lambda x: x.name)
321-
colm = MatrixColumn(tactic=tac, techniques=techs, subtechniques=stemp)
338+
colm = Tactic(tactic=tac, techniques=techs, subtechniques=stemp)
322339
self.matrix[domain].append(colm)
323340

324341
def get_matrix(self, domain='enterprise'):

layers/exporters/to_excel.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,20 @@
1111
class NoLayer(Exception):
1212
pass
1313

14+
class MisMatchDomain(Exception):
15+
pass
16+
1417
class ToExcel:
15-
def __init__(self, domain='enterprise', server=False, local=None):
18+
def __init__(self, domain='enterprise', source='taxii', local=None):
1619
"""
1720
Sets up exporting system, builds underlying matrix
1821
19-
:param server: Whether or not to use live cti-taxii data to construct the matrix
20-
:param local: Optional path to local stix data
22+
:param source: Source to generate the matrix from, one of (taxii, repo, or local)
23+
:param local: Optional path to local stix data, required in source is local
2124
2225
"""
23-
self.raw_handle = ExcelTemplates(domain=domain, server=server, local=local)
26+
self.domain = domain
27+
self.raw_handle = ExcelTemplates(domain=domain, source=source, local=local)
2428

2529
def to_xlsx(self, layer, filepath="layer.xlsx"):
2630
"""
@@ -36,6 +40,9 @@ def to_xlsx(self, layer, filepath="layer.xlsx"):
3640
if layer is None:
3741
raise NoLayer
3842

43+
if self.domain not in layer.layer.domain:
44+
raise MisMatchDomain
45+
3946
included_subs = []
4047
if layer.layer.techniques:
4148
for entry in layer.layer.techniques:

0 commit comments

Comments
 (0)