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

Commit ff3e245

Browse files
committed
merging develop into master
2 parents 604937f + 934b365 commit ff3e245

File tree

10 files changed

+136
-56
lines changed

10 files changed

+136
-56
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
# v1.8 - 15 December 2020
2+
## Improvements
3+
- Updated Layer library to support ATT&CK Navigator Layer format version 4.1.
4+
15
# v1.7 - 27 October 2020
26
## Improvements
37
- Removed pre-ATT&CK domain from scripts to support migration of that content to enterprise tactics. See issue [#36](https://github.com/mitre-attack/attack-scripts/issues/36).

layers/README.md

Lines changed: 37 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
# layers
22

3-
This folder contains modules and scripts for working with ATT&CK Navigator layers. ATT&CK Navigator Layers are a set of annotations overlayed on top of the ATT&CK Matrix. For more about ATT&CK Navigator layers, visit the ATT&CK Navigator repository. The core module allows users to load, validate, manipulate, and save ATT&CK layers. A brief overview of the components can be found below. All scripts adhere to the MITRE ATT&CK Navigator Layer file format, [version 4.0](https://github.com/mitre-attack/attack-navigator/blob/develop/layers/LAYERFORMATv4.md), but will accept legacy [version 3.0](https://github.com/mitre-attack/attack-navigator/blob/develop/layers/LAYERFORMATv3.md) layers, upgrading them to version 4.
3+
This folder contains modules and scripts for working with ATT&CK Navigator layers. ATT&CK Navigator Layers are a set of annotations overlaid on top of the ATT&CK Matrix. For more about ATT&CK Navigator layers, visit the ATT&CK Navigator repository. The core module allows users to load, validate, manipulate, and save ATT&CK layers. A brief overview of the components can be found below. All scripts adhere to the MITRE ATT&CK Navigator Layer file format, [version 4.1](https://github.com/mitre-attack/attack-navigator/blob/develop/layers/LAYERFORMATv4_1.md), but will accept legacy [version 3.0](https://github.com/mitre-attack/attack-navigator/blob/develop/layers/LAYERFORMATv3.md) layers, upgrading them to version 4.1.
44

55
#### Core Modules
66
| script | description |
77
|:-------|:------------|
8-
| [filter](core/filter.py) | Implements a basic [filter object](https://github.com/mitre-attack/attack-navigator/blob/develop/layers/LAYERFORMATv4.md#filter-object-properties). |
9-
| [gradient](core/gradient.py) | Implements a basic [gradient object](https://github.com/mitre-attack/attack-navigator/blob/develop/layers/LAYERFORMATv4.md#gradient-object-properties). |
8+
| [filter](core/filter.py) | Implements a basic [filter object](https://github.com/mitre-attack/attack-navigator/blob/develop/layers/LAYERFORMATv4_1.md#filter-object-properties). |
9+
| [gradient](core/gradient.py) | Implements a basic [gradient object](https://github.com/mitre-attack/attack-navigator/blob/develop/layers/LAYERFORMATv4_1.md#gradient-object-properties). |
1010
| [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. |
11-
| [layout](core/layout.py) | Implements a basic [layout object](https://github.com/mitre-attack/attack-navigator/blob/develop/layers/LAYERFORMATv4.md#layout-object-properties). |
12-
| [legenditem](core/legenditem.py) | Implements a basic [legenditem object](https://github.com/mitre-attack/attack-navigator/blob/develop/layers/LAYERFORMATv4.md#legenditem-object-properties). |
13-
| [metadata](core/metadata.py) | Implements a basic [metadata object](https://github.com/mitre-attack/attack-navigator/blob/develop/layers/LAYERFORMATv4.md#metadata-object-properties). |
14-
| [technique](core/technique.py) | Implements a basic [technique object](https://github.com/mitre-attack/attack-navigator/blob/develop/layers/LAYERFORMATv4.md#technique-object-properties). |
15-
| [versions](core/versions.py) | Impelments a basic [versions object](https://github.com/mitre-attack/attack-navigator/blob/develop/layers/LAYERFORMATv4.md#versions-object-properties).|
11+
| [layout](core/layout.py) | Implements a basic [layout object](https://github.com/mitre-attack/attack-navigator/blob/develop/layers/LAYERFORMATv4_1.md#layout-object-properties). |
12+
| [legenditem](core/legenditem.py) | Implements a basic [legenditem object](https://github.com/mitre-attack/attack-navigator/blob/develop/layers/LAYERFORMATv4_1.md#legenditem-object-properties). |
13+
| [metadata](core/metadata.py) | Implements a basic [metadata object](https://github.com/mitre-attack/attack-navigator/blob/develop/layers/LAYERFORMATv4_1.md#metadata-object-properties). |
14+
| [technique](core/technique.py) | Implements a basic [technique object](https://github.com/mitre-attack/attack-navigator/blob/develop/layers/LAYERFORMATv4_1.md#technique-object-properties). |
15+
| [versions](core/versions.py) | Impelments a basic [versions object](https://github.com/mitre-attack/attack-navigator/blob/develop/layers/LAYERFORMATv4_1.md#versions-object-properties).|
1616
#### Manipulator Scripts
1717
| script | description |
1818
|:-------|:------------|
@@ -22,14 +22,14 @@ This folder contains modules and scripts for working with ATT&CK Navigator layer
2222
| script | description |
2323
|:-------|:------------|
2424
| [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. |
25-
| [to_svg](exporters/to_svg.py) | Provides a means by which to export an ATT&CK layer to an svg image file. A further breakdown can be found in the corresponding [section](#to_svg.py) below. This file also contains the `SVGConfig` object that can be used to configure the SVG export.|
25+
| [to_svg](exporters/to_svg.py) | Provides a means by which to export an ATT&CK layer to an svg image file. A further breakdown can be found in the corresponding [section](#to_svg.py) below. This file also contains the `SVGConfig` object that can be used to configure the SVG export.|
2626
##### Utility Modules
2727
| script | description |
2828
|:-------|:------------|
2929
| [excel_templates](exporters/excel_templates.py) | Provides a means by which to convert a matrix into a clean excel matrix template. |
3030
| [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 STIX Bundle. |
3131
| [svg_templates](exporters/svg_templates.py) | Provides a means by which to convert a layer file into a marked up svg file. |
32-
| [svg_objects](exporters/svg_objects.py) | Provides raw templates and supporting functionality for generating svg objects. |
32+
| [svg_objects](exporters/svg_objects.py) | Provides raw templates and supporting functionality for generating svg objects. |
3333
##### Command Line Tools
3434
| script | description |
3535
|:-------|:------------|
@@ -45,7 +45,7 @@ The Layer class provides format validation and read/write capabilities to aid in
4545
| x.from_file(_filepath_) | Loads an ATT&CK layer from a file location specified by the _filepath_. |
4646
| x.to_file(_filepath_) | Saves the current state of the loaded ATT&CK layer to a json file denoted by the _filepath_. |
4747
| x.to_dict() | Returns a representation of the current ATT&CK layer object as a dictionary. |
48-
| x.to_str() | Returns a representation of the current ATT&CK layer object as a string representation of a dictionary. |
48+
| x.to_str() | Returns a representation of the current ATT&CK layer object as a string representation of a dictionary. |
4949

5050
#### Example Usage
5151

@@ -57,10 +57,11 @@ example_layer3_dict = {
5757
}
5858

5959
example_layer4_dict = {
60-
"name": "layer v4 example",
60+
"name": "layer v4.1 example",
6161
"versions" : {
62-
"layer" : "4.0",
63-
"navigator": "4.0"
62+
"attack": "8",
63+
"layer" : "4.1",
64+
"navigator": "4.1"
6465
},
6566
"domain": "enterprise-attack"
6667
}
@@ -88,7 +89,7 @@ Layerops.py provides the LayerOps class, which is a way to combine layer files i
8889
```python
8990
x = LayerOps(score=score, comment=comment, enabled=enabled, colors=colors, metadata=metadata, name=name, desc=desc, default_values=default_values)
9091
```
91-
92+
9293
Each of the _inputs_ takes a lambda function that will be used to combine technique object fields matching the parameter. The one exception to this is _default_values_, which is an optional dictionary argument containing default values to provide the lambda functions if techniques of the combined layers are missing them.
9394

9495
##### .process() Method
@@ -111,17 +112,17 @@ demo3 = Layer()
111112
demo3.from_file("C:\Users\attack\Downloads\layer3.json")
112113

113114
# Example 1) Build a LayerOps object that takes a list and averages scores across the layers
114-
lo = LayerOps(score=lambda x: sum(x) / len(x),
115-
name=lambda x: x[1],
115+
lo = LayerOps(score=lambda x: sum(x) / len(x),
116+
name=lambda x: x[1],
116117
desc=lambda x: "This is an list example") # Build LayerOps object
117118
out_layer = lo.process([demo, demo2]) # Trigger processing on a list of demo and demo2 layers
118119
out_layer.to_file("C:\demo_layer1.json") # Save averaged layer to file
119120
out_layer2 = lo.process([demo, demo2, demo3]) # Trigger processing on a list of demo, demo2, demo3
120121
visual_aid = out_layer2.to_dict() # Retrieve dictionary representation of processed layer
121122

122123
# Example 2) Build a LayerOps object that takes a dictionary and averages scores across the layers
123-
lo2 = LayerOps(score=lambda x: sum([x[y] for y in x]) / len([x[y] for y in x]),
124-
color=lambda x: x['b'],
124+
lo2 = LayerOps(score=lambda x: sum([x[y] for y in x]) / len([x[y] for y in x]),
125+
color=lambda x: x['b'],
125126
desc=lambda x: "This is a dict example") # Build LayerOps object, with lambda
126127
out_layer3 = lo2.process({'a': demo, 'b': demo2}) # Trigger processing on a dictionary of demo and demo2
127128
dict_layer = out_layer3.to_dict() # Retrieve dictionary representation of processed layer
@@ -147,23 +148,23 @@ out_layer6.to_file("C:\demo_layer6.json") # Save combined co
147148
```
148149

149150
## to_excel.py
150-
to_excel.py provides the ToExcel class, which is a way to export an existing layer file as an Excel
151-
spreadsheet. The ToExcel class has an optional parameter for the initialization function, that
152-
tells the exporter what data source to use when building the output matrix. Valid options include using live data from cti-taxii.mitre.org or using a local STIX bundle.
151+
to_excel.py provides the ToExcel class, which is a way to export an existing layer file as an Excel
152+
spreadsheet. The ToExcel class has an optional parameter for the initialization function, that
153+
tells the exporter what data source to use when building the output matrix. Valid options include using live data from cti-taxii.mitre.org or using a local STIX bundle.
153154

154155
##### ToExcel()
155156
```python
156157
x = ToExcel(domain='enterprise', source='taxii', local=None)
157158
```
158-
The ToExcel constructor takes domain, server, and local arguments during instantiation. The domain can
159+
The ToExcel constructor takes domain, server, and local arguments during instantiation. The domain can
159160
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 official ATT&CK Taxii Server (`cti-taxii`) when building the matrix, while the `local` option indicates that it should use a local bundle 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 bundle.
160161

161162
##### .to_xlsx() Method
162163
```python
163164
x.to_xlsx(layer=layer, filepath="layer.xlsx")
164165
```
165-
The to_xlsx method exports the layer file referenced as `layer`, as an excel file to the
166-
`filepath` specified.
166+
The to_xlsx method exports the layer file referenced as `layer`, as an excel file to the
167+
`filepath` specified.
167168

168169
#### Example Usage
169170
```python
@@ -181,8 +182,8 @@ t2.to_xlsx(layer=lay, filepath="demo2.xlsx")
181182
```
182183

183184
## to_svg.py
184-
to_svg.py provides the ToSvg class, which is a way to export an existing layer file as an SVG image file. The ToSvg class, like the ToExcel class, has an optional parameter for the initialization function, that
185-
tells the exporter what data source to use when building the output matrix. Valid options include using live data from cti-taxii.mitre.org or using a local STIX bundle.
185+
to_svg.py provides the ToSvg class, which is a way to export an existing layer file as an SVG image file. The ToSvg class, like the ToExcel class, has an optional parameter for the initialization function, that
186+
tells the exporter what data source to use when building the output matrix. Valid options include using live data from cti-taxii.mitre.org or using a local STIX bundle.
186187

187188
##### ToSvg()
188189
```python
@@ -195,7 +196,7 @@ The ToSvg constructor, just like the ToExcel constructor, takes domain, server,
195196
y = SVGConfig(width=8.5, height=11, headerHeight=1, unit="in", showSubtechniques="expanded",
196197
font="sans-serif", tableBorderColor="#6B7279", showHeader=True, legendDocked=True,
197198
legendX=0, legendY=0, legendWidth=2, legendHeight=1, showLegend=True, showFilters=True,
198-
showAbout=True, border=0.104)
199+
showAbout=True, showDomain=True, border=0.104)
199200
```
200201
The SVGConfig object is used to configure how an SVG export behaves. The defaults for each of the available values can be found in the declaration above, and a brief explanation for each field is included in the table below. The config object should be provided to the ToSvg object during instantiation, but if values need to be updated on the fly, the currently loaded configuration can be interacted with at `ToSvg().config`. The configuration can also be populated from a json file using the `.load_from_file(filename="path/to/file.json")` method, or stored to one using the `.save_to_file(filename="path/to/file.json)` method.
201202

@@ -204,10 +205,10 @@ The SVGConfig object is used to configure how an SVG export behaves. The default
204205
| width | Desired SVG width | number | 8.5 |
205206
| height | Desired SVG height | number | 11 |
206207
| headerHeight | Desired Header Block height | number | 1 |
207-
| unit | SVG measurement units (qualifies width, height, etc.) - "in", "cm", "px", "em", or "pt"| string | "in" |
208-
| showSubtechniques | Display form for subtechniques - "all", "expanded" (decided by layer), or "none" | string | "expanded" |
208+
| unit | SVG measurement units (qualifies width, height, etc.) - "in", "cm", "px", "em", or "pt"| string | "in" |
209+
| showSubtechniques | Display form for subtechniques - "all", "expanded" (decided by layer), or "none" | string | "expanded" |
209210
| font | What font style to use - "serif", "sans-serif", or "monospace" | string | "sans-serif" |
210-
| tableBorderColor | Hex color to use for the technique borders | string | "#6B7279" |
211+
| tableBorderColor | Hex color to use for the technique borders | string | "#6B7279" |
211212
| showHeader | Whether or not to show Header Blocks | bool | True |
212213
| legendDocked | Whether or not the legend should be docked | bool | True |
213214
| legendX | Where to place the legend on the x axis if not docked | number | 0 |
@@ -216,15 +217,16 @@ The SVGConfig object is used to configure how an SVG export behaves. The default
216217
| legendHeight | Height of the legend if not docked | number | 1 |
217218
| showLegend | Whether or not to show the legend | bool | True |
218219
| showFilters | Whether or not to show the Filter Header Block | bool | True |
220+
| showDomain | Whether or not to show the Domain and Version Header Block | bool | True |
219221
| showAbout | Whether or not to show the About Header Block | bool | True |
220-
| border | What default border width to use | number | 0.104 |
222+
| border | What default border width to use | number | 0.104 |
221223

222224
##### .to_svg() Method
223225
```python
224226
x.to_svg(layer=layer, filepath="layer.svg")
225227
```
226-
The to_svg method exports the layer file referenced as `layer`, as an excel file to the
227-
`filepath` specified.
228+
The to_svg method exports the layer file referenced as `layer`, as an excel file to the
229+
`filepath` specified.
228230

229231
#### Example Usage
230232
```python
@@ -243,4 +245,4 @@ conf.load_from_file(filename="path/to/poster/config.json")
243245

244246
t2 = ToSvg(domain='mobile', source='local', local='path/to/local/stix.json', config=conf)
245247
t2.to_svg(layer=lay, filepath="demo2.svg")
246-
```
248+
```

layers/core/layerobj.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from ..core.technique import Technique
55
from ..core.gradient import Gradient
66
from ..core.legenditem import LegendItem
7-
from ..core.metadata import Metadata
7+
from ..core.metadata import Metadata, MetaDiv
88
from ..core.versions import Versions
99
from ..core.exceptions import UNSETVALUE, typeChecker, BadInput, handler, \
1010
categoryChecker, UnknownLayerProperty, loadChecker, MissingParameters
@@ -14,7 +14,7 @@
1414
from core.technique import Technique
1515
from core.gradient import Gradient
1616
from core.legenditem import LegendItem
17-
from core.metadata import Metadata
17+
from core.metadata import Metadata, MetaDiv
1818
from core.versions import Versions
1919
from core.exceptions import UNSETVALUE, typeChecker, BadInput, handler, \
2020
categoryChecker, UnknownLayerProperty, loadChecker, MissingParameters
@@ -53,7 +53,7 @@ def version(self):
5353
@version.setter
5454
def version(self, version):
5555
typeChecker(type(self).__name__, version, str, "version")
56-
categoryChecker(type(self).__name__, version, ["3.0", "4.0"], "version")
56+
categoryChecker(type(self).__name__, version, ["3.0", "4.0", "4.1"], "version")
5757
if self.__versions is UNSETVALUE:
5858
self.__versions = Versions()
5959
self.__versions.layer = version
@@ -278,8 +278,11 @@ def metadata(self, metadata):
278278
self.__metadata = []
279279
for entry in metadata:
280280
try:
281-
loadChecker(type(self).__name__, entry, ['name', 'value'], "metadata")
282-
self.__metadata.append(Metadata(entry['name'], entry['value']))
281+
if "divider" in entry:
282+
self.__metadata.append(MetaDiv(entry["divider"]))
283+
else:
284+
loadChecker(type(self).__name__, entry, ['name', 'value'], "metadata")
285+
self.__metadata.append(Metadata(entry['name'], entry['value']))
283286
except MissingParameters as e:
284287
handler(type(self).__name__, 'Metadata {} is missing parameters: '
285288
'{}. Skipping.'

layers/core/metadata.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,31 @@ def get_dict(self):
3939
:returns: A dict representation of the local metadata object
4040
"""
4141
return dict(name=self.__name, value=self.__value)
42+
43+
class MetaDiv:
44+
def __init__(self, active):
45+
"""
46+
Initialization - Creates a metadata object divider
47+
"""
48+
self.__name = "DIVIDER"
49+
self.__value = active
50+
51+
@property
52+
def name(self):
53+
return self.__name
54+
55+
@property
56+
def state(self):
57+
return self.__value
58+
59+
@state.setter
60+
def state(self, state):
61+
typeChecker(type(self).__name__, state, bool, "state")
62+
self.__value = state
63+
64+
def get_dict(self):
65+
"""
66+
Converts the currently loaded data into a dict
67+
:returns: A dict representation of the local metadata object
68+
"""
69+
return dict(name=self.__name, value=self.__value)

layers/core/technique.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
try:
22
from ..core.exceptions import BadInput, handler, typeChecker, \
33
UNSETVALUE, UnknownTechniqueProperty, BadType
4-
from ..core.metadata import Metadata
4+
from ..core.metadata import Metadata, MetaDiv
55
except ValueError:
66
from core.exceptions import BadInput, handler, typeChecker, \
77
UNSETVALUE, UnknownTechniqueProperty, BadType
8-
from core.metadata import Metadata
8+
from core.metadata import Metadata, MetaDiv
99

1010

1111
class Technique:
@@ -104,7 +104,10 @@ def metadata(self, metadata):
104104
entry = ""
105105
try:
106106
for entry in metadata:
107-
self.__metadata.append(Metadata(entry['name'], entry['value']))
107+
if "divider" in entry:
108+
self.__metadata.append(MetaDiv(entry["divider"]))
109+
else:
110+
self.__metadata.append(Metadata(entry['name'], entry['value']))
108111
except KeyError as e:
109112
handler(type(self).__name__, 'Metadata {} is missing parameters: '
110113
'{}. Unable to load.'

0 commit comments

Comments
 (0)