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

Commit 99b96b5

Browse files
authored
Merge pull request #50 from mitre-attack/develop
attack-scripts support for ATT&CK v8
2 parents 3ef0ffd + 80e82db commit 99b96b5

File tree

14 files changed

+250
-109
lines changed

14 files changed

+250
-109
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
# v1.7 - 27 October 2020
2+
## Improvements
3+
- 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).
4+
- Updated scripts which produce layers to use v4.0 of the Navigator Layer Format. See issue [#47](https://github.com/mitre-attack/attack-scripts/issues/47).
5+
16
# v1.6 - 5 October 2020
27
## Improvements
38
- Added [layer to SVG](https://github.com/mitre-attack/attack-scripts/tree/master/layers#to_svgpy) converter. See issue [#1](https://github.com/mitre-attack/attack-scripts/issues/1).

layers/README.md

Lines changed: 21 additions & 12 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 3.0](https://github.com/mitre-attack/attack-navigator/blob/develop/layers/LAYERFORMATv3.md).
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.
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/LAYERFORMATv3.md#filter-object-properties). |
9-
| [gradient](core/gradient.py) | Implements a basic [gradient object](https://github.com/mitre-attack/attack-navigator/blob/develop/layers/LAYERFORMATv3.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.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). |
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/LAYERFORMATv3.md#layout-object-properties). |
12-
| [legenditem](core/legenditem.py) | Implements a basic [legenditem object](https://github.com/mitre-attack/attack-navigator/blob/develop/layers/LAYERFORMATv3.md#legenditem-object-properties). |
13-
| [metadata](core/metadata.py) | Implements a basic [metadata object](https://github.com/mitre-attack/attack-navigator/blob/develop/layers/LAYERFORMATv3.md#metadata-object-properties). |
14-
| [technique](core/technique.py) | Implements a basic [technique object](https://github.com/mitre-attack/attack-navigator/blob/develop/layers/LAYERFORMATv3.md#technique-object-properties). |
15-
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).|
1616
#### Manipulator Scripts
1717
| script | description |
1818
|:-------|:------------|
@@ -36,7 +36,7 @@ This folder contains modules and scripts for working with ATT&CK Navigator layer
3636
| [layerExporter_cli.py](layerExporter_cli.py) | A commandline utility to export Layer files to excel or svg formats using the exporter tools. Run with `-h` for usage. |
3737

3838
## Layer
39-
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.
39+
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. The class currently supports version 3 and 4 of the ATT&CK Layer spec, and will upgrade version 3 layers into compatible version 4 ones whenever possible.
4040

4141
| method [x = Layer()]| description |
4242
|:-------|:------------|
@@ -50,22 +50,31 @@ The Layer class provides format validation and read/write capabilities to aid in
5050
#### Example Usage
5151

5252
```python
53-
example_layer_dict = {
53+
example_layer3_dict = {
5454
"name": "example layer",
5555
"version": "3.0",
5656
"domain": "mitre-enterprise"
5757
}
5858

59+
example_layer4_dict = {
60+
"name": "layer v4 example",
61+
"versions" : {
62+
"layer" : "4.0",
63+
"navigator": "4.0"
64+
},
65+
"domain": "enterprise-attack"
66+
}
67+
5968
example_layer_location = "/path/to/layer/file.json"
6069
example_layer_out_location = "/path/to/new/layer/file.json"
6170

6271
from layers.core import Layer
6372

64-
layer1 = Layer(example_layer_dict) # Create a new layer and load existing data
73+
layer1 = Layer(example_layer3_dict) # Create a new layer and load existing data
6574
layer1.to_file(example_layer_out_location) # Write out the loaded layer to the specified file
6675

6776
layer2 = Layer() # Create a new layer object
68-
layer2.from_dict(example_layer_dict) # Load layer data into existing layer object
77+
layer2.from_dict(example_layer4_dict) # Load layer data into existing layer object
6978
print(layer2.to_dict()) # Retrieve the loaded layer's data as a dictionary, and print it
7079

7180
layer3 = Layer() # Create a new layer object

layers/core/exceptions.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ class UnknownTechniqueProperty(Exception):
2121
pass
2222

2323

24+
class MissingParameters(Exception):
25+
pass
26+
2427
def handler(caller, msg):
2528
"""
2629
Prints a debug/warning/error message
@@ -85,3 +88,20 @@ def categoryChecker(caller, testee, valid, field):
8588
if testee not in valid:
8689
handler(caller, '{} not a valid value for {}'.format(testee, field))
8790
raise BadInput
91+
92+
def loadChecker(caller, testee, required, field):
93+
"""
94+
Verifies that the tested object contains all required fields
95+
:param caller: the entity that called this function (used for error
96+
messages)
97+
:param testee: the element to test
98+
:param requireds: a list of required values for the testee
99+
:param field: what the element is to be used as (used for error
100+
messages)
101+
:raises BadInput: error denoting the testee element is not one of
102+
the valid options
103+
"""
104+
for entry in required:
105+
if entry not in testee:
106+
handler(caller, '{} is not present in {} [{}]'.format(entry, field, testee))
107+
raise MissingParameters

layers/core/filter.py

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,30 +7,17 @@
77

88

99
class Filter:
10-
def __init__(self, domain="mitre-enterprise"):
10+
def __init__(self, domain="enterprise-attack"):
1111
"""
1212
Initialization - Creates a filter object, with an optional
1313
domain input
1414
1515
:param domain: The domain used for this layer (mitre-enterprise
1616
or mitre-mobile)
1717
"""
18-
self.__stages = UNSETVALUE
1918
self.domain = domain
2019
self.__platforms = UNSETVALUE
2120

22-
@property
23-
def stages(self):
24-
if self.__stages != UNSETVALUE:
25-
return self.__stages
26-
27-
@stages.setter
28-
def stages(self, stage):
29-
typeCheckerArray(type(self).__name__, stage, str, "stage")
30-
categoryChecker(type(self).__name__, stage[0], ["act", "prepare"],
31-
"stages")
32-
self.__stages = stage
33-
3421
@property
3522
def platforms(self):
3623
if self.__platforms != UNSETVALUE:
@@ -59,7 +46,25 @@ def get_dict(self):
5946
if entry == 'domain':
6047
continue
6148
if listing[entry] != UNSETVALUE:
62-
temp[entry.split(type(self).__name__ + '__')[-1]] \
63-
= listing[entry]
49+
subname = entry.split('__')[-1]
50+
if subname != 'stages':
51+
temp[subname] = listing[entry]
6452
if len(temp) > 0:
6553
return temp
54+
55+
class Filterv3(Filter):
56+
def __init__(self, domain="mitre-enterprise"):
57+
self.__stages = UNSETVALUE
58+
super().__init__(domain)
59+
60+
@property
61+
def stages(self):
62+
if self.__stages != UNSETVALUE:
63+
return self.__stages
64+
65+
@stages.setter
66+
def stages(self, stage):
67+
typeCheckerArray(type(self).__name__, stage, str, "stage")
68+
categoryChecker(type(self).__name__, stage[0], ["act", "prepare"],
69+
"stages")
70+
self.__stages = stage

layers/core/layer.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,8 +75,7 @@ def _build(self):
7575
Loads the data stored in self.data into a LayerObj (self.layer)
7676
"""
7777
try:
78-
self.__layer = _LayerObj(self._data['version'], self._data['name'],
79-
self._data['domain'])
78+
self.__layer = _LayerObj(self._data['name'], self._data['domain'])
8079
except BadType or BadInput as e:
8180
handler(type(self).__name__, 'Layer is malformed: {}. '
8281
'Unable to load.'.format(e))
@@ -89,7 +88,7 @@ def _build(self):
8988
return
9089

9190
for key in self._data:
92-
if key not in ['version', 'name', 'domain']:
91+
if key not in ['name', 'domain']:
9392
try:
9493
self.__layer._linker(key, self._data[key])
9594
except Exception as e:

0 commit comments

Comments
 (0)