mal-toolbox 0.1.12__py3-none-any.whl → 0.3.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {mal_toolbox-0.1.12.dist-info → mal_toolbox-0.3.0.dist-info}/METADATA +43 -25
- mal_toolbox-0.3.0.dist-info/RECORD +29 -0
- mal_toolbox-0.3.0.dist-info/entry_points.txt +2 -0
- maltoolbox/__init__.py +38 -57
- maltoolbox/__main__.py +43 -14
- maltoolbox/attackgraph/__init__.py +1 -1
- maltoolbox/attackgraph/analyzers/apriori.py +10 -6
- maltoolbox/attackgraph/attacker.py +26 -13
- maltoolbox/attackgraph/attackgraph.py +431 -355
- maltoolbox/attackgraph/node.py +72 -54
- maltoolbox/attackgraph/query.py +4 -2
- maltoolbox/file_utils.py +4 -8
- maltoolbox/ingestors/neo4j.py +146 -157
- maltoolbox/language/__init__.py +10 -2
- maltoolbox/language/compiler/__init__.py +485 -17
- maltoolbox/language/compiler/mal_lexer.py +172 -152
- maltoolbox/language/compiler/mal_parser.py +1370 -663
- maltoolbox/language/languagegraph.py +1096 -545
- maltoolbox/model.py +312 -485
- maltoolbox/translators/securicad.py +164 -163
- maltoolbox/translators/updater.py +231 -108
- mal_toolbox-0.1.12.dist-info/RECORD +0 -32
- maltoolbox/default.conf +0 -17
- maltoolbox/language/classes_factory.py +0 -243
- maltoolbox/language/compiler/mal_visitor.py +0 -416
- maltoolbox/wrappers.py +0 -62
- {mal_toolbox-0.1.12.dist-info → mal_toolbox-0.3.0.dist-info}/AUTHORS +0 -0
- {mal_toolbox-0.1.12.dist-info → mal_toolbox-0.3.0.dist-info}/LICENSE +0 -0
- {mal_toolbox-0.1.12.dist-info → mal_toolbox-0.3.0.dist-info}/WHEEL +0 -0
- {mal_toolbox-0.1.12.dist-info → mal_toolbox-0.3.0.dist-info}/top_level.txt +0 -0
|
@@ -10,169 +10,170 @@ import xml.etree.ElementTree as ET
|
|
|
10
10
|
from typing import Optional
|
|
11
11
|
|
|
12
12
|
from ..model import AttackerAttachment, Model
|
|
13
|
-
from ..language import LanguageGraph
|
|
13
|
+
from ..language import LanguageGraph
|
|
14
14
|
|
|
15
15
|
logger = logging.getLogger(__name__)
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
17
|
+
# TODO: Update this at some point
|
|
18
|
+
|
|
19
|
+
# def load_model_from_scad_archive(
|
|
20
|
+
# scad_archive: str,
|
|
21
|
+
# lang_graph: LanguageGraph
|
|
22
|
+
# ) -> Optional[Model]:
|
|
23
|
+
# """
|
|
24
|
+
# Reads a '.sCAD' archive generated by securiCAD representing an instance
|
|
25
|
+
# model and loads the information into a maltoobox.model.Model object.
|
|
26
|
+
#
|
|
27
|
+
# Arguments:
|
|
28
|
+
# scad_archive - the path to a '.sCAD' archive
|
|
29
|
+
# lang_graph - a language graph representing the MAL
|
|
30
|
+
# language specification
|
|
31
|
+
#
|
|
32
|
+
# Return:
|
|
33
|
+
# A maltoobox.model.Model object containing the instance model.
|
|
34
|
+
# """
|
|
35
|
+
# with zipfile.ZipFile(scad_archive, 'r') as archive:
|
|
36
|
+
# filelist = archive.namelist()
|
|
37
|
+
# model_file = next(filter(lambda x: ( x[-4:] == '.eom'), filelist))
|
|
38
|
+
# scad_model = archive.read(model_file)
|
|
39
|
+
# root = ET.fromstring(scad_model)
|
|
40
|
+
#
|
|
41
|
+
# instance_model = Model(scad_archive,
|
|
42
|
+
# lang_classes_factory)
|
|
43
|
+
#
|
|
44
|
+
# for child in root.iter('objects'):
|
|
45
|
+
#
|
|
46
|
+
# if logger.isEnabledFor(logging.DEBUG):
|
|
47
|
+
# # Avoid running json.dumps when not in debug
|
|
48
|
+
# logger.debug(
|
|
49
|
+
# 'Loading asset from "%s": \n%s',
|
|
50
|
+
# scad_archive, json.dumps(child.attrib, indent=2)
|
|
51
|
+
# )
|
|
52
|
+
#
|
|
53
|
+
# if child.attrib['metaConcept'] == 'Attacker':
|
|
54
|
+
# attacker_obj_id = int(child.attrib['id'])
|
|
55
|
+
# attacker_at = AttackerAttachment()
|
|
56
|
+
# attacker_at.entry_points = []
|
|
57
|
+
# instance_model.add_attacker(
|
|
58
|
+
# attacker_at,
|
|
59
|
+
# attacker_id = attacker_obj_id
|
|
60
|
+
# )
|
|
61
|
+
# continue
|
|
62
|
+
#
|
|
63
|
+
# if not hasattr(lang_classes_factory.ns,
|
|
64
|
+
# child.attrib['metaConcept']):
|
|
65
|
+
# logger.error(
|
|
66
|
+
# 'Failed to find %s asset in language specification!',
|
|
67
|
+
# child.attrib["metaConcept"]
|
|
68
|
+
# )
|
|
69
|
+
# return None
|
|
70
|
+
# asset = getattr(lang_classes_factory.ns,
|
|
71
|
+
# child.attrib['metaConcept'])(name = child.attrib['name'])
|
|
72
|
+
# asset_id = int(child.attrib['id'])
|
|
73
|
+
# for subchild in child.iter('evidenceAttributes'):
|
|
74
|
+
# defense_name = subchild.attrib['metaConcept']
|
|
75
|
+
# defense_name = defense_name[0].lower() + defense_name[1:]
|
|
76
|
+
# for distrib in subchild.iter('evidenceDistribution'):
|
|
77
|
+
# for d in distrib.iter('parameters'):
|
|
78
|
+
# if 'value' in d.attrib:
|
|
79
|
+
# dist_value = d.attrib['value']
|
|
80
|
+
# setattr(asset, defense_name, float(dist_value))
|
|
81
|
+
# instance_model.add_asset(asset, asset_id)
|
|
82
|
+
#
|
|
83
|
+
# for child in root.iter('associations'):
|
|
84
|
+
# logger.debug(
|
|
85
|
+
# 'Load association ("%s", "%s", "%s", "%s") from %s',
|
|
86
|
+
# child.attrib["sourceObject"], child.attrib["targetObject"],
|
|
87
|
+
# child.attrib["targetProperty"], child.attrib["sourceProperty"],
|
|
88
|
+
# scad_archive
|
|
89
|
+
# )
|
|
90
|
+
# # Note: This is not a bug in the code. The fields and assets are
|
|
91
|
+
# # listed incorrectly in the securiCAD format where the source asset
|
|
92
|
+
# # matches the target field and vice versa.
|
|
93
|
+
# left_id = int(child.attrib['targetObject'])
|
|
94
|
+
# right_id = int(child.attrib['sourceObject'])
|
|
95
|
+
# attacker_id = None
|
|
96
|
+
# if child.attrib['sourceProperty'] == 'firstSteps':
|
|
97
|
+
# attacker_id = right_id
|
|
98
|
+
# target_id = left_id
|
|
99
|
+
# target_prop = child.attrib['targetProperty']
|
|
100
|
+
# elif child.attrib['targetProperty'] == 'firstSteps':
|
|
101
|
+
# attacker_id = left_id
|
|
102
|
+
# target_id = right_id
|
|
103
|
+
# target_prop = child.attrib['sourceProperty']
|
|
104
|
+
#
|
|
105
|
+
# if attacker_id is not None:
|
|
106
|
+
# attacker = instance_model.get_attacker_by_id(attacker_id)
|
|
107
|
+
# if not attacker:
|
|
108
|
+
# logger.error(
|
|
109
|
+
# 'Failed to find attacker with id %s in model!',
|
|
110
|
+
# attacker_id
|
|
111
|
+
# )
|
|
112
|
+
# return None
|
|
113
|
+
# target_asset = instance_model.get_asset_by_id(target_id)
|
|
114
|
+
# if not target_asset:
|
|
115
|
+
# logger.error(
|
|
116
|
+
# 'Failed to find asset with id %s in model!',
|
|
117
|
+
# target_id
|
|
118
|
+
# )
|
|
119
|
+
# return None
|
|
120
|
+
# attacker.entry_points.append((target_asset,
|
|
121
|
+
# [target_prop.split('.')[0]]))
|
|
122
|
+
# continue
|
|
123
|
+
#
|
|
124
|
+
# left_asset = instance_model.get_asset_by_id(left_id)
|
|
125
|
+
# if not left_asset:
|
|
126
|
+
# logger.error(
|
|
127
|
+
# 'Failed to find asset with id %s in model!', left_id
|
|
128
|
+
# )
|
|
129
|
+
# return None
|
|
130
|
+
# right_asset = instance_model.get_asset_by_id(right_id)
|
|
131
|
+
# if not right_asset:
|
|
132
|
+
# logger.error(
|
|
133
|
+
# 'Failed to find asset with id %s in model!', right_id
|
|
134
|
+
# )
|
|
135
|
+
# return None
|
|
136
|
+
#
|
|
137
|
+
# # Note: This is not a bug in the code. The fields and assets are
|
|
138
|
+
# # listed incorrectly in the securiCAD format where the source asset
|
|
139
|
+
# # matches the target field and vice versa.
|
|
140
|
+
# left_field = child.attrib['sourceProperty']
|
|
141
|
+
# right_field = child.attrib['targetProperty']
|
|
142
|
+
# lang_graph_assoc = None
|
|
143
|
+
# for assoc in left_asset.lg_asset.associations:
|
|
144
|
+
# if (assoc.left_field.fieldname == left_field and
|
|
145
|
+
# assoc.right_field.fieldname == right_field) or \
|
|
146
|
+
# (assoc.left_field.fieldname == right_field and
|
|
147
|
+
# assoc.right_field.fieldname == left_field):
|
|
148
|
+
# lang_graph_assoc = assoc
|
|
149
|
+
# break
|
|
150
|
+
#
|
|
151
|
+
# if not lang_graph_assoc:
|
|
152
|
+
# raise LookupError(
|
|
153
|
+
# 'Failed to find ("%s", "%s", "%s", "%s")'
|
|
154
|
+
# 'association in lang specification.' %
|
|
155
|
+
# (left_asset.type, right_asset.type,
|
|
156
|
+
# left_field, right_field)
|
|
157
|
+
# )
|
|
158
|
+
# return None
|
|
159
|
+
#
|
|
160
|
+
# logger.debug('Found "%s" association.', lang_graph_assoc.name)
|
|
161
|
+
# assoc_name = lang_classes_factory.get_association_by_signature(
|
|
162
|
+
# lang_graph_assoc.name,
|
|
163
|
+
# left_asset.type,
|
|
164
|
+
# right_asset.type
|
|
165
|
+
# )
|
|
166
|
+
#
|
|
167
|
+
# if assoc_name is None:
|
|
168
|
+
# logger.error(
|
|
169
|
+
# 'Failed to find association with name \"%s\" in model!',
|
|
170
|
+
# lang_graph_assoc.name
|
|
171
|
+
# )
|
|
172
|
+
# return None
|
|
173
|
+
#
|
|
174
|
+
# assoc = getattr(lang_classes_factory.ns, assoc_name)()
|
|
175
|
+
# setattr(assoc, left_field, [left_asset])
|
|
176
|
+
# setattr(assoc, right_field, [right_asset])
|
|
177
|
+
# instance_model.add_association(assoc)
|
|
178
|
+
#
|
|
179
|
+
# return instance_model
|