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

Commit 3ef0ffd

Browse files
committed
merging develop into master
2 parents 73aefc1 + 186c59f commit 3ef0ffd

File tree

13 files changed

+1328
-15
lines changed

13 files changed

+1328
-15
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
# v1.6 - 5 October 2020
2+
## Improvements
3+
- 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).
4+
- Added option to filter mappings by tactic in [technique_mappings_to_csv](technique_mappings_to_csv.py). See pull request [#46](https://github.com/mitre-attack/attack-scripts/pull/46).
5+
16
# v1.5.2 - 2 September 2020
27
## Improvements
38
- Clarified documentation on creation of virtual environments for Windows compatibility.

layers/README.md

Lines changed: 74 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,18 @@ 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.|
2526
##### Utility Modules
2627
| script | description |
2728
|:-------|:------------|
2829
| [excel_templates](exporters/excel_templates.py) | Provides a means by which to convert a matrix into a clean excel matrix template. |
2930
| [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. |
31+
| [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. |
33+
##### Command Line Tools
34+
| script | description |
35+
|:-------|:------------|
36+
| [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. |
3037

3138
## Layer
3239
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.
@@ -140,9 +147,9 @@ tells the exporter what data source to use when building the output matrix. Vali
140147
x = ToExcel(domain='enterprise', source='taxii', local=None)
141148
```
142149
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.
150+
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.
144151

145-
##### .to_file() Method
152+
##### .to_xlsx() Method
146153
```python
147154
x.to_xlsx(layer=layer, filepath="layer.xlsx")
148155
```
@@ -162,4 +169,69 @@ t.to_xlsx(layer=lay, filepath="demo.xlsx")
162169
#Using local stix data for template
163170
t2 = ToExcel(domain='mobile', source='local', local='path/to/local/stix.json')
164171
t2.to_xlsx(layer=lay, filepath="demo2.xlsx")
172+
```
173+
174+
## to_svg.py
175+
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
176+
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.
177+
178+
##### ToSvg()
179+
```python
180+
x = ToSvg(domain='enterprise', source='taxii', local=None, config=None)
181+
```
182+
The ToSvg constructor, just like the ToExcel constructor, takes domain, server, and local arguments during instantiation. The domain can 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. The `config` parameter is an optional SVGConfig object that can be used to configure the export as desired. If not provided, the configuration for the export will be set to default values.
183+
184+
##### SVGConfig()
185+
```python
186+
y = SVGConfig(width=8.5, height=11, headerHeight=1, unit="in", showSubtechniques="expanded",
187+
font="sans-serif", tableBorderColor="#6B7279", showHeader=True, legendDocked=True,
188+
legendX=0, legendY=0, legendWidth=2, legendHeight=1, showLegend=True, showFilters=True,
189+
showAbout=True, border=0.104)
190+
```
191+
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.
192+
193+
| attribute| description | type | default value |
194+
|:-------|:------------|:------------|:------------|
195+
| width | Desired SVG width | number | 8.5 |
196+
| height | Desired SVG height | number | 11 |
197+
| headerHeight | Desired Header Block height | number | 1 |
198+
| unit | SVG measurement units (qualifies width, height, etc.) - "in", "cm", "px", "em", or "pt"| string | "in" |
199+
| showSubtechniques | Display form for subtechniques - "all", "expanded" (decided by layer), or "none" | string | "expanded" |
200+
| font | What font style to use - "serif", "sans-serif", or "monospace" | string | "sans-serif" |
201+
| tableBorderColor | Hex color to use for the technique borders | string | "#6B7279" |
202+
| showHeader | Whether or not to show Header Blocks | bool | True |
203+
| legendDocked | Whether or not the legend should be docked | bool | True |
204+
| legendX | Where to place the legend on the x axis if not docked | number | 0 |
205+
| legendY | Where to place the legend on the y axis if not docked | number | 1 |
206+
| legendWidth | Width of the legend if not docked | number | 2 |
207+
| legendHeight | Height of the legend if not docked | number | 1 |
208+
| showLegend | Whether or not to show the legend | bool | True |
209+
| showFilters | Whether or not to show the Filter Header Block | bool | True |
210+
| showAbout | Whether or not to show the About Header Block | bool | True |
211+
| border | What default border width to use | number | 0.104 |
212+
213+
##### .to_svg() Method
214+
```python
215+
x.to_svg(layer=layer, filepath="layer.svg")
216+
```
217+
The to_svg method exports the layer file referenced as `layer`, as an excel file to the
218+
`filepath` specified.
219+
220+
#### Example Usage
221+
```python
222+
from layers import Layer
223+
from layers import ToSvg, SVGConfig
224+
225+
lay = Layer()
226+
lay.from_file("path/to/layer/file.json")
227+
# Using taxii server for template
228+
t = ToSvg(domain=lay.layer.domain, source='taxii')
229+
t.to_svg(layer=lay, filepath="demo.svg")
230+
#Using local stix data for template
231+
232+
conf = SVGConfig()
233+
conf.load_from_file(filename="path/to/poster/config.json")
234+
235+
t2 = ToSvg(domain='mobile', source='local', local='path/to/local/stix.json', config=conf)
236+
t2.to_svg(layer=lay, filepath="demo2.svg")
165237
```

layers/exporters/__init__.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
from .excel_templates import ExcelTemplates
22
from .matrix_gen import MatrixGen
3-
from .to_excel import ToExcel
3+
from .to_excel import ToExcel
4+
from .to_svg import ToSvg, SVGConfig
5+
from .svg_templates import SvgTemplates
350 KB
Binary file not shown.
311 KB
Binary file not shown.

layers/exporters/fonts/serif.ttf

83.2 KB
Binary file not shown.

layers/exporters/matrix_gen.py

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,20 @@ def __init__(self, source='taxii', local=None):
109109
self.matrix = {}
110110
self._build_matrix()
111111

112+
@staticmethod
113+
def _remove_revoked_deprecated(content):
114+
"""Remove any revoked or deprecated objects from queries made to the data source"""
115+
return list(
116+
filter(
117+
lambda x: x.get("x_mitre_deprecated", False) is False and x.get("revoked", False) is False,
118+
content
119+
)
120+
)
121+
122+
def _search(self, domain, query):
123+
interum = self.collections[domain].query(query)
124+
return self._remove_revoked_deprecated(interum)
125+
112126
def _get_tactic_listing(self, domain='enterprise'):
113127
"""
114128
INTERNAL - retrieves tactics for the associated domain
@@ -117,11 +131,11 @@ def _get_tactic_listing(self, domain='enterprise'):
117131
"""
118132
tactics = {}
119133
t_filt = []
120-
matrix = self.collections[domain].query([Filter('type', '=', 'x-mitre-matrix')])
134+
matrix = self._search(domain, [Filter('type', '=', 'x-mitre-matrix')])
121135
for i in range(len(matrix)):
122136
tactics[matrix[i]['name']] = []
123137
for tactic_id in matrix[i]['tactic_refs']:
124-
tactics[matrix[i]['name']].append(self.collections[domain].query([Filter('id', '=', tactic_id)])[0])
138+
tactics[matrix[i]['name']].append(self._search(domain,([Filter('id', '=', tactic_id)]))[0])
125139
for entry in tactics[matrix[0]['name']]:
126140
self.convert_data[entry['x_mitre_shortname']] = entry['name']
127141
self.convert_data[entry['name']] = entry['x_mitre_shortname']
@@ -137,9 +151,11 @@ def _get_technique_listing(self, tactic, domain='enterprise'):
137151
"""
138152
techniques = []
139153
subtechs = {}
140-
techs = self.collections[domain].query([Filter('type', '=', 'attack-pattern'), Filter('kill_chain_phases.phase_name', '=', tactic)])
154+
techs = self._search(domain,[Filter('type', '=', 'attack-pattern'),
155+
Filter('kill_chain_phases.phase_name', '=', tactic)])
141156
for entry in techs:
142-
if entry['kill_chain_phases'][0]['kill_chain_name'] == 'mitre-attack':
157+
if entry['kill_chain_phases'][0]['kill_chain_name'] == 'mitre-attack' or \
158+
entry['kill_chain_phases'][0]['kill_chain_name'] == 'mitre-mobile-attack':
143159
tid = [t['external_id'] for t in entry['external_references'] if 'attack' in t['source_name']]
144160
if '.' not in tid[0]:
145161
techniques.append(MatrixEntry(id=tid[0], name=entry['name']))

0 commit comments

Comments
 (0)