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

Commit fe6d97c

Browse files
committed
Merge branch 'scripts-25' into develop
2 parents 0224e42 + 953675c commit fe6d97c

11 files changed

Lines changed: 869 additions & 5 deletions

File tree

.gitignore

Lines changed: 166 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,166 @@
1-
.DS_Store
1+
# Created by https://www.toptal.com/developers/gitignore/api/python,macos
2+
# Edit at https://www.toptal.com/developers/gitignore?templates=python,macos
3+
4+
### macOS ###
5+
# General
6+
.DS_Store
7+
.AppleDouble
8+
.LSOverride
9+
10+
# Icon must end with two \r
11+
Icon
12+
13+
# Thumbnails
14+
._*
15+
16+
# Files that might appear in the root of a volume
17+
.DocumentRevisions-V100
18+
.fseventsd
19+
.Spotlight-V100
20+
.TemporaryItems
21+
.Trashes
22+
.VolumeIcon.icns
23+
.com.apple.timemachine.donotpresent
24+
25+
# Directories potentially created on remote AFP share
26+
.AppleDB
27+
.AppleDesktop
28+
Network Trash Folder
29+
Temporary Items
30+
.apdisk
31+
32+
### Python ###
33+
# Byte-compiled / optimized / DLL files
34+
__pycache__/
35+
*.py[cod]
36+
*$py.class
37+
38+
# C extensions
39+
*.so
40+
41+
# Distribution / packaging
42+
.Python
43+
build/
44+
develop-eggs/
45+
dist/
46+
downloads/
47+
eggs/
48+
.eggs/
49+
lib/
50+
lib64/
51+
parts/
52+
sdist/
53+
var/
54+
wheels/
55+
pip-wheel-metadata/
56+
share/python-wheels/
57+
*.egg-info/
58+
.installed.cfg
59+
*.egg
60+
MANIFEST
61+
62+
# PyInstaller
63+
# Usually these files are written by a python script from a template
64+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
65+
*.manifest
66+
*.spec
67+
68+
# Installer logs
69+
pip-log.txt
70+
pip-delete-this-directory.txt
71+
72+
# Unit test / coverage reports
73+
htmlcov/
74+
.tox/
75+
.nox/
76+
.coverage
77+
.coverage.*
78+
.cache
79+
nosetests.xml
80+
coverage.xml
81+
*.cover
82+
*.py,cover
83+
.hypothesis/
84+
.pytest_cache/
85+
86+
# Translations
87+
*.mo
88+
*.pot
89+
90+
# Django stuff:
91+
*.log
92+
local_settings.py
93+
db.sqlite3
94+
db.sqlite3-journal
95+
96+
# Flask stuff:
97+
instance/
98+
.webassets-cache
99+
100+
# Scrapy stuff:
101+
.scrapy
102+
103+
# Sphinx documentation
104+
docs/_build/
105+
106+
# PyBuilder
107+
target/
108+
109+
# Jupyter Notebook
110+
.ipynb_checkpoints
111+
112+
# IPython
113+
profile_default/
114+
ipython_config.py
115+
116+
# pyenv
117+
.python-version
118+
119+
# pipenv
120+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
121+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
122+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
123+
# install all needed dependencies.
124+
#Pipfile.lock
125+
126+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
127+
__pypackages__/
128+
129+
# Celery stuff
130+
celerybeat-schedule
131+
celerybeat.pid
132+
133+
# SageMath parsed files
134+
*.sage.py
135+
136+
# Environments
137+
.env
138+
.venv
139+
env/
140+
venv/
141+
ENV/
142+
env.bak/
143+
venv.bak/
144+
145+
# Spyder project settings
146+
.spyderproject
147+
.spyproject
148+
149+
# Rope project settings
150+
.ropeproject
151+
152+
# mkdocs documentation
153+
/site
154+
155+
# mypy
156+
.mypy_cache/
157+
.dmypy.json
158+
dmypy.json
159+
160+
# Pyre type checker
161+
.pyre/
162+
163+
# pytype static type analyzer
164+
.pytype/
165+
166+
# End of https://www.toptal.com/developers/gitignore/api/python,macos

CHANGELOG.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
# v1.5.1 - 27 July 2020
2+
## New Scripts
3+
- Added [layer to excel](https://github.com/mitre-attack/attack-scripts/tree/master/layers#to_excelpy) converter. See issue [#25](https://github.com/mitre-attack/attack-scripts/issues/25).
4+
15
# v1.5 - 8 July 2020
26
## New Scripts
37
Added scripts used to generate the [sample layers in the ATT&CK Navigator repository](https://github.com/mitre-attack/attack-navigator/tree/develop/layers/data/samples). See issue [#21](https://github.com/mitre-attack/attack-scripts/issues/21) and [the sample layer README](scripts/layers/samples/README.md) for more details. The following scripts were added:
@@ -16,7 +20,7 @@ Added scripts used to generate the [sample layers in the ATT&CK Navigator reposi
1620
## Fixes
1721
- Fixed bug in LayerOps causing issues with cross-tactic techniques, as well as a bug where a score lambda could affect the outcome of other lambdas.
1822

19-
# v1.4 - 5 May 2020
23+
# V1.4 - 5 May 2020
2024
## New Scripts
2125
- Added Layers folder with utility scripts for working with [ATT&CK Navigator](https://github.com/mitre-attack/attack-navigator) Layers. See the Layers [README](layers/README.md) for more details. See issues [#2](https://github.com/mitre-attack/attack-scripts/issues/2) and [#3](https://github.com/mitre-attack/attack-scripts/issues/3).
2226

layers/README.md

Lines changed: 46 additions & 2 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,7 +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. |
20+
21+
#### Exporter Scripts
22+
| script | description |
23+
|:-------|:------------|
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. |
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 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 STIX Bundle. |
2030

2131
## Layer
2232
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.
@@ -119,3 +129,37 @@ lo4 = LayerOps(score=lambda x: '; '.join(x),
119129
out_layer6 = lo4.process([demo2, demo3]) # Trigger processing on a list of demo2 and demo0
120130
out_layer6.to_file("C:\demo_layer6.json") # Save combined comment layer to file
121131
```
132+
133+
## to_excel.py
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 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.
137+
138+
##### ToExcel()
139+
```python
140+
x = ToExcel(domain='enterprise', source='taxii', local=None)
141+
```
142+
The ToExcel constructor takes domain, server, and local arguments during instantiation. The domain can
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 `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.
144+
145+
##### .to_file() Method
146+
```python
147+
x.to_xlsx(layer=layer, filepath="layer.xlsx")
148+
```
149+
The to_xlsx method exports the layer file referenced as `layer`, as an excel file to the
150+
`filepath` specified.
151+
152+
#### Example Usage
153+
```python
154+
from layers import Layer
155+
from layers import ToExcel
156+
157+
lay = Layer()
158+
lay.from_file("path/to/layer/file.json")
159+
# Using taxii server for template
160+
t = ToExcel(domain=lay.layer.domain, source='taxii')
161+
t.to_xlsx(layer=lay, filepath="demo.xlsx")
162+
#Using local stix data for template
163+
t2 = ToExcel(domain='mobile', source='local', local='path/to/local/stix.json')
164+
t2.to_xlsx(layer=lay, filepath="demo2.xlsx")
165+
```

layers/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from .core import *
2+
from .exporters import *
3+
from .manipulators import *

layers/core/gradient.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import colour
2+
import math
13
try:
24
from ..core.exceptions import typeChecker, typeCheckerArray
35
except ValueError:
@@ -13,6 +15,8 @@ def __init__(self, colors, minValue, maxValue):
1315
:param minValue: The minValue for this gradient
1416
:param maxValue: The maxValue for this gradient
1517
"""
18+
self.__minValue = None
19+
self.__maxValue = None
1620
self.colors = colors
1721
self.minValue = minValue
1822
self.maxValue = maxValue
@@ -27,6 +31,7 @@ def colors(self, colors):
2731
self.__colors = []
2832
for entry in colors:
2933
self.__colors.append(entry)
34+
self._compute_curve()
3035

3136
@property
3237
def minValue(self):
@@ -36,6 +41,7 @@ def minValue(self):
3641
def minValue(self, minValue):
3742
typeChecker(type(self).__name__, minValue, int, "minValue")
3843
self.__minValue = minValue
44+
self._compute_curve()
3945

4046
@property
4147
def maxValue(self):
@@ -45,6 +51,42 @@ def maxValue(self):
4551
def maxValue(self, maxValue):
4652
typeChecker(type(self).__name__, maxValue, int, "maxValue")
4753
self.__maxValue = maxValue
54+
self._compute_curve()
55+
56+
def _compute_curve(self):
57+
"""
58+
Computes the gradient color curve
59+
"""
60+
if self.maxValue is not None and self.minValue is not None and self.colors is not None:
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
73+
self.curve.extend(curve_2)
74+
self.curve.append(colour.Color(self.colors[-1]))
75+
76+
def compute_color(self, score):
77+
"""
78+
Computes a specific color based on the score value provided
79+
:returns: A hexadecimal color representation of the score on
80+
the gradient
81+
"""
82+
if score <= self.minValue:
83+
return self.curve[0].hex_l
84+
if score >= self.maxValue:
85+
return self.curve[-1].hex_l
86+
87+
target = self.curve[score - self.minValue]
88+
return target.hex_l
89+
4890

4991
def get_dict(self):
5092
"""

layers/core/technique.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ def tactic(self, tactic):
5050

5151
@property
5252
def comment(self):
53-
if self.__tactic != UNSETVALUE:
53+
if self.__comment != UNSETVALUE:
5454
return self.__comment
5555

5656
@comment.setter

layers/exporters/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from .excel_templates import ExcelTemplates
2+
from .matrix_gen import MatrixGen
3+
from .to_excel import ToExcel

0 commit comments

Comments
 (0)