mal-toolbox 0.0.28__py3-none-any.whl → 0.1.12__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.0.28.dist-info → mal_toolbox-0.1.12.dist-info}/METADATA +60 -28
- mal_toolbox-0.1.12.dist-info/RECORD +32 -0
- {mal_toolbox-0.0.28.dist-info → mal_toolbox-0.1.12.dist-info}/WHEEL +1 -1
- maltoolbox/__init__.py +31 -31
- maltoolbox/__main__.py +80 -4
- maltoolbox/attackgraph/__init__.py +8 -0
- maltoolbox/attackgraph/analyzers/__init__.py +0 -0
- maltoolbox/attackgraph/analyzers/apriori.py +173 -27
- maltoolbox/attackgraph/attacker.py +84 -25
- maltoolbox/attackgraph/attackgraph.py +503 -215
- maltoolbox/attackgraph/node.py +92 -31
- maltoolbox/attackgraph/query.py +125 -19
- maltoolbox/default.conf +8 -7
- maltoolbox/exceptions.py +45 -0
- maltoolbox/file_utils.py +66 -0
- maltoolbox/ingestors/__init__.py +0 -0
- maltoolbox/ingestors/neo4j.py +95 -84
- maltoolbox/language/__init__.py +4 -0
- maltoolbox/language/classes_factory.py +145 -64
- maltoolbox/language/{lexer_parser/__main__.py → compiler/__init__.py} +5 -12
- maltoolbox/language/{lexer_parser → compiler}/mal_lexer.py +1 -1
- maltoolbox/language/{lexer_parser → compiler}/mal_parser.py +1 -1
- maltoolbox/language/{lexer_parser → compiler}/mal_visitor.py +4 -5
- maltoolbox/language/languagegraph.py +569 -168
- maltoolbox/model.py +858 -0
- maltoolbox/translators/__init__.py +0 -0
- maltoolbox/translators/securicad.py +76 -52
- maltoolbox/translators/updater.py +132 -0
- maltoolbox/wrappers.py +62 -0
- mal_toolbox-0.0.28.dist-info/RECORD +0 -26
- maltoolbox/cl_parser.py +0 -89
- maltoolbox/language/specification.py +0 -265
- maltoolbox/main.py +0 -84
- maltoolbox/model/model.py +0 -282
- {mal_toolbox-0.0.28.dist-info → mal_toolbox-0.1.12.dist-info}/AUTHORS +0 -0
- {mal_toolbox-0.0.28.dist-info → mal_toolbox-0.1.12.dist-info}/LICENSE +0 -0
- {mal_toolbox-0.0.28.dist-info → mal_toolbox-0.1.12.dist-info}/top_level.txt +0 -0
|
File without changes
|
|
@@ -7,24 +7,28 @@ import json
|
|
|
7
7
|
import logging
|
|
8
8
|
import xml.etree.ElementTree as ET
|
|
9
9
|
|
|
10
|
-
from
|
|
11
|
-
|
|
10
|
+
from typing import Optional
|
|
11
|
+
|
|
12
|
+
from ..model import AttackerAttachment, Model
|
|
13
|
+
from ..language import LanguageGraph, LanguageClassesFactory
|
|
12
14
|
|
|
13
15
|
logger = logging.getLogger(__name__)
|
|
14
16
|
|
|
15
|
-
def load_model_from_scad_archive(
|
|
16
|
-
|
|
17
|
-
|
|
17
|
+
def load_model_from_scad_archive(
|
|
18
|
+
scad_archive: str,
|
|
19
|
+
lang_graph: LanguageGraph,
|
|
20
|
+
lang_classes_factory: LanguageClassesFactory
|
|
21
|
+
) -> Optional[Model]:
|
|
18
22
|
"""
|
|
19
23
|
Reads a '.sCAD' archive generated by securiCAD representing an instance
|
|
20
24
|
model and loads the information into a maltoobox.model.Model object.
|
|
21
25
|
|
|
22
26
|
Arguments:
|
|
23
27
|
scad_archive - the path to a '.sCAD' archive
|
|
24
|
-
|
|
25
|
-
specification
|
|
28
|
+
lang_graph - a language graph representing the MAL
|
|
29
|
+
language specification
|
|
26
30
|
lang_classes_factory - a language classes factory that contains
|
|
27
|
-
the
|
|
31
|
+
the classes defined by the
|
|
28
32
|
language specification
|
|
29
33
|
|
|
30
34
|
Return:
|
|
@@ -36,24 +40,34 @@ def load_model_from_scad_archive(scad_archive: str,
|
|
|
36
40
|
scad_model = archive.read(model_file)
|
|
37
41
|
root = ET.fromstring(scad_model)
|
|
38
42
|
|
|
39
|
-
instance_model =
|
|
40
|
-
lang_spec,
|
|
43
|
+
instance_model = Model(scad_archive,
|
|
41
44
|
lang_classes_factory)
|
|
42
45
|
|
|
43
46
|
for child in root.iter('objects'):
|
|
44
|
-
|
|
45
|
-
|
|
47
|
+
|
|
48
|
+
if logger.isEnabledFor(logging.DEBUG):
|
|
49
|
+
# Avoid running json.dumps when not in debug
|
|
50
|
+
logger.debug(
|
|
51
|
+
'Loading asset from "%s": \n%s',
|
|
52
|
+
scad_archive, json.dumps(child.attrib, indent=2)
|
|
53
|
+
)
|
|
54
|
+
|
|
46
55
|
if child.attrib['metaConcept'] == 'Attacker':
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
instance_model.add_attacker(
|
|
56
|
+
attacker_obj_id = int(child.attrib['id'])
|
|
57
|
+
attacker_at = AttackerAttachment()
|
|
58
|
+
attacker_at.entry_points = []
|
|
59
|
+
instance_model.add_attacker(
|
|
60
|
+
attacker_at,
|
|
61
|
+
attacker_id = attacker_obj_id
|
|
62
|
+
)
|
|
51
63
|
continue
|
|
52
64
|
|
|
53
65
|
if not hasattr(lang_classes_factory.ns,
|
|
54
66
|
child.attrib['metaConcept']):
|
|
55
|
-
logger.error(
|
|
56
|
-
'asset in language specification!'
|
|
67
|
+
logger.error(
|
|
68
|
+
'Failed to find %s asset in language specification!',
|
|
69
|
+
child.attrib["metaConcept"]
|
|
70
|
+
)
|
|
57
71
|
return None
|
|
58
72
|
asset = getattr(lang_classes_factory.ns,
|
|
59
73
|
child.attrib['metaConcept'])(name = child.attrib['name'])
|
|
@@ -62,7 +76,6 @@ def load_model_from_scad_archive(scad_archive: str,
|
|
|
62
76
|
defense_name = subchild.attrib['metaConcept']
|
|
63
77
|
defense_name = defense_name[0].lower() + defense_name[1:]
|
|
64
78
|
for distrib in subchild.iter('evidenceDistribution'):
|
|
65
|
-
distrib_type = distrib.attrib['type']
|
|
66
79
|
for d in distrib.iter('parameters'):
|
|
67
80
|
if 'value' in d.attrib:
|
|
68
81
|
dist_value = d.attrib['value']
|
|
@@ -70,13 +83,12 @@ def load_model_from_scad_archive(scad_archive: str,
|
|
|
70
83
|
instance_model.add_asset(asset, asset_id)
|
|
71
84
|
|
|
72
85
|
for child in root.iter('associations'):
|
|
73
|
-
logger.debug(
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
86
|
+
logger.debug(
|
|
87
|
+
'Load association ("%s", "%s", "%s", "%s") from %s',
|
|
88
|
+
child.attrib["sourceObject"], child.attrib["targetObject"],
|
|
89
|
+
child.attrib["targetProperty"], child.attrib["sourceProperty"],
|
|
90
|
+
scad_archive
|
|
91
|
+
)
|
|
80
92
|
# Note: This is not a bug in the code. The fields and assets are
|
|
81
93
|
# listed incorrectly in the securiCAD format where the source asset
|
|
82
94
|
# matches the target field and vice versa.
|
|
@@ -92,16 +104,20 @@ def load_model_from_scad_archive(scad_archive: str,
|
|
|
92
104
|
target_id = right_id
|
|
93
105
|
target_prop = child.attrib['sourceProperty']
|
|
94
106
|
|
|
95
|
-
if attacker_id:
|
|
107
|
+
if attacker_id is not None:
|
|
96
108
|
attacker = instance_model.get_attacker_by_id(attacker_id)
|
|
97
109
|
if not attacker:
|
|
98
|
-
logger.error(
|
|
99
|
-
'in model!'
|
|
110
|
+
logger.error(
|
|
111
|
+
'Failed to find attacker with id %s in model!',
|
|
112
|
+
attacker_id
|
|
113
|
+
)
|
|
100
114
|
return None
|
|
101
115
|
target_asset = instance_model.get_asset_by_id(target_id)
|
|
102
116
|
if not target_asset:
|
|
103
|
-
logger.error(
|
|
104
|
-
'in model!'
|
|
117
|
+
logger.error(
|
|
118
|
+
'Failed to find asset with id %s in model!',
|
|
119
|
+
target_id
|
|
120
|
+
)
|
|
105
121
|
return None
|
|
106
122
|
attacker.entry_points.append((target_asset,
|
|
107
123
|
[target_prop.split('.')[0]]))
|
|
@@ -109,13 +125,15 @@ def load_model_from_scad_archive(scad_archive: str,
|
|
|
109
125
|
|
|
110
126
|
left_asset = instance_model.get_asset_by_id(left_id)
|
|
111
127
|
if not left_asset:
|
|
112
|
-
logger.error(
|
|
113
|
-
'in model!'
|
|
128
|
+
logger.error(
|
|
129
|
+
'Failed to find asset with id %s in model!', left_id
|
|
130
|
+
)
|
|
114
131
|
return None
|
|
115
132
|
right_asset = instance_model.get_asset_by_id(right_id)
|
|
116
133
|
if not right_asset:
|
|
117
|
-
logger.error(
|
|
118
|
-
'in model!'
|
|
134
|
+
logger.error(
|
|
135
|
+
'Failed to find asset with id %s in model!', right_id
|
|
136
|
+
)
|
|
119
137
|
return None
|
|
120
138
|
|
|
121
139
|
# Note: This is not a bug in the code. The fields and assets are
|
|
@@ -123,27 +141,33 @@ def load_model_from_scad_archive(scad_archive: str,
|
|
|
123
141
|
# matches the target field and vice versa.
|
|
124
142
|
left_field = child.attrib['sourceProperty']
|
|
125
143
|
right_field = child.attrib['targetProperty']
|
|
126
|
-
|
|
127
|
-
lang_spec,
|
|
144
|
+
lang_graph_assoc = lang_graph.get_association_by_fields_and_assets(
|
|
128
145
|
left_field,
|
|
129
146
|
right_field,
|
|
130
|
-
left_asset.
|
|
131
|
-
right_asset.
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
'association in language specification!')
|
|
147
|
+
left_asset.type,
|
|
148
|
+
right_asset.type)
|
|
149
|
+
|
|
150
|
+
if not lang_graph_assoc:
|
|
151
|
+
raise LookupError(
|
|
152
|
+
'Failed to find ("%s", "%s", "%s", "%s")'
|
|
153
|
+
'association in lang specification.' %
|
|
154
|
+
(left_asset.type, right_asset.type,
|
|
155
|
+
left_field, right_field)
|
|
156
|
+
)
|
|
141
157
|
return None
|
|
142
158
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
159
|
+
logger.debug('Found "%s" association.', lang_graph_assoc.name)
|
|
160
|
+
assoc_name = lang_classes_factory.get_association_by_signature(
|
|
161
|
+
lang_graph_assoc.name,
|
|
162
|
+
left_asset.type,
|
|
163
|
+
right_asset.type
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
if assoc_name is None:
|
|
167
|
+
logger.error(
|
|
168
|
+
'Failed to find association with name \"%s\" in model!',
|
|
169
|
+
lang_graph_assoc.name
|
|
170
|
+
)
|
|
147
171
|
return None
|
|
148
172
|
|
|
149
173
|
assoc = getattr(lang_classes_factory.ns, assoc_name)()
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import logging
|
|
3
|
+
|
|
4
|
+
import yaml
|
|
5
|
+
|
|
6
|
+
from ..model import Model, AttackerAttachment
|
|
7
|
+
from ..language import LanguageClassesFactory
|
|
8
|
+
|
|
9
|
+
logger = logging.getLogger(__name__)
|
|
10
|
+
|
|
11
|
+
def load_model_from_older_version(
|
|
12
|
+
filename: str,
|
|
13
|
+
lang_classes_factory: LanguageClassesFactory,
|
|
14
|
+
version: str
|
|
15
|
+
) -> Model:
|
|
16
|
+
match (version):
|
|
17
|
+
case '0.0.39':
|
|
18
|
+
return load_model_from_version_0_0_39(filename,
|
|
19
|
+
lang_classes_factory)
|
|
20
|
+
case _:
|
|
21
|
+
msg = ('Unknown version "%s" format. Could not '
|
|
22
|
+
'load model from file "%s"')
|
|
23
|
+
logger.error(msg % (version, filename))
|
|
24
|
+
raise ValueError(msg % (version, filename))
|
|
25
|
+
|
|
26
|
+
def load_model_from_version_0_0_39(
|
|
27
|
+
filename: str,
|
|
28
|
+
lang_classes_factory: LanguageClassesFactory
|
|
29
|
+
) -> Model:
|
|
30
|
+
"""
|
|
31
|
+
Load model from file.
|
|
32
|
+
|
|
33
|
+
Arguments:
|
|
34
|
+
filename - the name of the input file
|
|
35
|
+
lang_classes_factory - the language classes factory that defines the
|
|
36
|
+
classes needed to build the model
|
|
37
|
+
"""
|
|
38
|
+
|
|
39
|
+
def _process_model(model_dict, lang_classes_factory) -> Model:
|
|
40
|
+
model = Model(model_dict['metadata']['name'], lang_classes_factory)
|
|
41
|
+
|
|
42
|
+
# Reconstruct the assets
|
|
43
|
+
for asset_id, asset_object in model_dict['assets'].items():
|
|
44
|
+
logger.debug(f"Loading asset:\n{json.dumps(asset_object, indent=2)}")
|
|
45
|
+
|
|
46
|
+
# Allow defining an asset via the metaconcept only.
|
|
47
|
+
asset_object = (
|
|
48
|
+
asset_object
|
|
49
|
+
if isinstance(asset_object, dict)
|
|
50
|
+
else {'metaconcept': asset_object, 'name': f"{asset_object}:{asset_id}"}
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
asset = getattr(model.lang_classes_factory.ns,
|
|
54
|
+
asset_object['metaconcept'])(name = asset_object['name'])
|
|
55
|
+
|
|
56
|
+
for defense in (defenses:=asset_object.get('defenses', [])):
|
|
57
|
+
setattr(asset, defense, float(defenses[defense]))
|
|
58
|
+
|
|
59
|
+
model.add_asset(asset, asset_id = int(asset_id))
|
|
60
|
+
|
|
61
|
+
# Reconstruct the associations
|
|
62
|
+
for assoc_dict in model_dict.get('associations', []):
|
|
63
|
+
association = getattr(model.lang_classes_factory.ns, assoc_dict.pop('metaconcept'))()
|
|
64
|
+
|
|
65
|
+
# compatibility with old format
|
|
66
|
+
assoc_dict = assoc_dict.get('association', assoc_dict)
|
|
67
|
+
|
|
68
|
+
for field, targets in assoc_dict.items():
|
|
69
|
+
targets = targets if isinstance(targets, list) else [targets]
|
|
70
|
+
setattr(
|
|
71
|
+
association,
|
|
72
|
+
field,
|
|
73
|
+
[model.get_asset_by_id(int(id)) for id in targets]
|
|
74
|
+
)
|
|
75
|
+
model.add_association(association)
|
|
76
|
+
|
|
77
|
+
# Reconstruct the attackers
|
|
78
|
+
if 'attackers' in model_dict:
|
|
79
|
+
attackers_info = model_dict['attackers']
|
|
80
|
+
for attacker_id in attackers_info:
|
|
81
|
+
attacker = AttackerAttachment(
|
|
82
|
+
name = attackers_info[attacker_id]['name']
|
|
83
|
+
)
|
|
84
|
+
attacker.entry_points = []
|
|
85
|
+
for asset_id in attackers_info[attacker_id]['entry_points']:
|
|
86
|
+
attacker.entry_points.append(
|
|
87
|
+
(model.get_asset_by_id(int(asset_id)),
|
|
88
|
+
attackers_info[attacker_id]['entry_points']\
|
|
89
|
+
[asset_id]['attack_steps']))
|
|
90
|
+
model.add_attacker(attacker, attacker_id = int(attacker_id))
|
|
91
|
+
return model
|
|
92
|
+
|
|
93
|
+
def load_from_json(
|
|
94
|
+
filename: str,
|
|
95
|
+
lang_classes_factory: LanguageClassesFactory
|
|
96
|
+
) -> Model:
|
|
97
|
+
"""
|
|
98
|
+
Load model from a json file.
|
|
99
|
+
|
|
100
|
+
Arguments:
|
|
101
|
+
filename - the name of the input file
|
|
102
|
+
"""
|
|
103
|
+
with open(filename, 'r', encoding='utf-8') as model_file:
|
|
104
|
+
model_dict = json.loads(model_file.read())
|
|
105
|
+
|
|
106
|
+
return _process_model(model_dict, lang_classes_factory)
|
|
107
|
+
|
|
108
|
+
def load_from_yaml(
|
|
109
|
+
filename: str,
|
|
110
|
+
lang_classes_factory: LanguageClassesFactory
|
|
111
|
+
) -> Model:
|
|
112
|
+
"""
|
|
113
|
+
Load model from a yaml file.
|
|
114
|
+
|
|
115
|
+
Arguments:
|
|
116
|
+
filename - the name of the input file
|
|
117
|
+
"""
|
|
118
|
+
with open(filename, 'r', encoding='utf-8') as model_file:
|
|
119
|
+
model_dict = yaml.safe_load(model_file)
|
|
120
|
+
|
|
121
|
+
return _process_model(model_dict, lang_classes_factory)
|
|
122
|
+
|
|
123
|
+
logger.info(f'Loading model from {filename} file.')
|
|
124
|
+
if filename.endswith('.yml') or filename.endswith('.yaml'):
|
|
125
|
+
return load_from_yaml(filename, lang_classes_factory)
|
|
126
|
+
elif filename.endswith('.json'):
|
|
127
|
+
return load_from_json(filename, lang_classes_factory)
|
|
128
|
+
else:
|
|
129
|
+
msg = 'Unknown file extension for model file to load from.'
|
|
130
|
+
logger.error(msg)
|
|
131
|
+
raise ValueError(msg)
|
|
132
|
+
return None
|
maltoolbox/wrappers.py
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"""Contains wrappers combining more than one of the maltoolbox submodules"""
|
|
2
|
+
|
|
3
|
+
import logging
|
|
4
|
+
import sys
|
|
5
|
+
import zipfile
|
|
6
|
+
|
|
7
|
+
from maltoolbox.model import Model
|
|
8
|
+
from maltoolbox.language import LanguageGraph, LanguageClassesFactory
|
|
9
|
+
from maltoolbox.attackgraph import AttackGraph
|
|
10
|
+
from maltoolbox.attackgraph.analyzers.apriori import (
|
|
11
|
+
calculate_viability_and_necessity
|
|
12
|
+
)
|
|
13
|
+
from maltoolbox.exceptions import AttackGraphStepExpressionError
|
|
14
|
+
from maltoolbox import log_configs
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
logger = logging.getLogger(__name__)
|
|
18
|
+
|
|
19
|
+
def create_attack_graph(
|
|
20
|
+
lang_file: str,
|
|
21
|
+
model_file: str,
|
|
22
|
+
attach_attackers=True,
|
|
23
|
+
calc_viability_and_necessity=True
|
|
24
|
+
) -> AttackGraph:
|
|
25
|
+
"""Create and return an attack graph
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
lang_file - path to language file (.mar or .mal)
|
|
29
|
+
model_file - path to model file (yaml or json)
|
|
30
|
+
attach_attackers - whether to run attach_attackers or not
|
|
31
|
+
calc_viability_and_necessity - whether run apriori calculations or not
|
|
32
|
+
"""
|
|
33
|
+
try:
|
|
34
|
+
lang_graph = LanguageGraph.from_mar_archive(lang_file)
|
|
35
|
+
except zipfile.BadZipFile:
|
|
36
|
+
lang_graph = LanguageGraph.from_mal_spec(lang_file)
|
|
37
|
+
|
|
38
|
+
if log_configs['langspec_file']:
|
|
39
|
+
lang_graph.save_to_file(log_configs['langspec_file'])
|
|
40
|
+
|
|
41
|
+
lang_classes_factory = LanguageClassesFactory(lang_graph)
|
|
42
|
+
instance_model = Model.load_from_file(model_file, lang_classes_factory)
|
|
43
|
+
|
|
44
|
+
if log_configs['model_file']:
|
|
45
|
+
instance_model.save_to_file(log_configs['model_file'])
|
|
46
|
+
|
|
47
|
+
try:
|
|
48
|
+
attack_graph = AttackGraph(lang_graph, instance_model)
|
|
49
|
+
except AttackGraphStepExpressionError:
|
|
50
|
+
logger.error(
|
|
51
|
+
'Attack graph generation failed when attempting '
|
|
52
|
+
'to resolve attack step expression!'
|
|
53
|
+
)
|
|
54
|
+
sys.exit(1)
|
|
55
|
+
|
|
56
|
+
if attach_attackers:
|
|
57
|
+
attack_graph.attach_attackers()
|
|
58
|
+
|
|
59
|
+
if calc_viability_and_necessity:
|
|
60
|
+
calculate_viability_and_necessity(attack_graph)
|
|
61
|
+
|
|
62
|
+
return attack_graph
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
maltoolbox/__init__.py,sha256=5c6HEsWFGx3tKaQ073bhsmAnYDg5hooo_VJywZIjaIg,2958
|
|
2
|
-
maltoolbox/__main__.py,sha256=_kfJOkJluA3gfq3HAJM0rAK_SvGO-4Jr6wQQGrItiWs,94
|
|
3
|
-
maltoolbox/cl_parser.py,sha256=zpFAhEx-ZVOQlZkXR3MfxMiYR8aPLKDeUbGhlaap2Sk,2550
|
|
4
|
-
maltoolbox/default.conf,sha256=YbGeYq4aR61G43I7RGEGwgNikIGTuKT56uz_j_6t9K4,282
|
|
5
|
-
maltoolbox/main.py,sha256=OvaMFZGM76DFC6KceYvt4qMU13khEVbqJZzf-N20754,3285
|
|
6
|
-
maltoolbox/attackgraph/attacker.py,sha256=6SnV1AfsHzkEPyR5eplE6Sz2WaaSbwLIMqLzFd9rsYE,2008
|
|
7
|
-
maltoolbox/attackgraph/attackgraph.py,sha256=u-wTOiN7MtR5VAUtSIENOIicVHTqLrBcNl7R9e_xVyQ,19867
|
|
8
|
-
maltoolbox/attackgraph/node.py,sha256=mI7LFibJZNOSeE36MKYGu7nxedRQVjiWzJGLSPBks_c,3984
|
|
9
|
-
maltoolbox/attackgraph/query.py,sha256=c_RU5fBChb7K_p9u4E4pT-mn16rm4lVQNTTOLRa9B8Q,3111
|
|
10
|
-
maltoolbox/attackgraph/analyzers/apriori.py,sha256=el7Dv42FAP7RRe2xLhzhrWDiJw9TYjQrVfe8U41MuNM,3182
|
|
11
|
-
maltoolbox/ingestors/neo4j.py,sha256=xvEnbCG4Z0zuPPOeR8AjrNTA_-EtCo4JKy04EQci6Qk,8307
|
|
12
|
-
maltoolbox/language/classes_factory.py,sha256=US3dTlyLWncqb3SJxpzesa0eRf2RTPxUX64gb_vESsE,7018
|
|
13
|
-
maltoolbox/language/languagegraph.py,sha256=0SMB5Qpm-1wfzqIzTfoc_si-kpb8JjCyzkSv6ApNtvI,31892
|
|
14
|
-
maltoolbox/language/specification.py,sha256=Q96NQmnkskxJlMOsKZBVsg2hMqwU2XOb4qPl16PoR9w,9563
|
|
15
|
-
maltoolbox/language/lexer_parser/__main__.py,sha256=aD1WWM82DDGS5tcEVzfeTQtP6MkwSLZA48FxBMO3soQ,970
|
|
16
|
-
maltoolbox/language/lexer_parser/mal_lexer.py,sha256=_dqX1xGnGxEyqnhWjEMKuywfhe3WamCsnt4hNFel3SI,10778
|
|
17
|
-
maltoolbox/language/lexer_parser/mal_parser.py,sha256=0awGDJDy6YxmGizhT17sbB7cgeD2x3UNxzNymNfq99c,91351
|
|
18
|
-
maltoolbox/language/lexer_parser/mal_visitor.py,sha256=UhejWVvN8lKGw1t0rD8Yx7-Qqn9kfemIlHajV3tsXAI,13203
|
|
19
|
-
maltoolbox/model/model.py,sha256=S-y2oV4GuFu3YMLAFVWwz4IsV3BrJxJgksCE7C9qELU,10249
|
|
20
|
-
maltoolbox/translators/securicad.py,sha256=YizxoIsKkp1AZIYudjxvR3c450vY5iGejAULG8YHIyI,6203
|
|
21
|
-
mal_toolbox-0.0.28.dist-info/AUTHORS,sha256=zxLrLe8EY39WtRKlAY4Oorx4Z2_LHV2ApRvDGZgY7xY,127
|
|
22
|
-
mal_toolbox-0.0.28.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
23
|
-
mal_toolbox-0.0.28.dist-info/METADATA,sha256=Yw-8K1h7vbzjdRLvW_nwBFH-Ha06s4nPSVQB_fcXfCA,4890
|
|
24
|
-
mal_toolbox-0.0.28.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
|
25
|
-
mal_toolbox-0.0.28.dist-info/top_level.txt,sha256=phqRVLRKGdSUgRY03mcpi2cmbbDo5YGjkV4gkqHFFcM,11
|
|
26
|
-
mal_toolbox-0.0.28.dist-info/RECORD,,
|
maltoolbox/cl_parser.py
DELETED
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
MAL-Toolbox Command Line Parsing Module
|
|
3
|
-
"""
|
|
4
|
-
|
|
5
|
-
import sys
|
|
6
|
-
import argparse
|
|
7
|
-
import logging
|
|
8
|
-
from typing import Sequence
|
|
9
|
-
|
|
10
|
-
from maltoolbox import __version__
|
|
11
|
-
|
|
12
|
-
logger = logging.getLogger(__name__)
|
|
13
|
-
|
|
14
|
-
def parse_args(args: Sequence[str]) -> argparse.Namespace:
|
|
15
|
-
"""
|
|
16
|
-
This function parses the arguments which have been passed from the command
|
|
17
|
-
line. It returns an argparse parser object.
|
|
18
|
-
|
|
19
|
-
Arguments:
|
|
20
|
-
args - the list of arguments passed from the command line in the sys.argv
|
|
21
|
-
format
|
|
22
|
-
|
|
23
|
-
Return:
|
|
24
|
-
A parser with the provided arguments, which can be used in a simpler format
|
|
25
|
-
"""
|
|
26
|
-
parser = argparse.ArgumentParser(
|
|
27
|
-
prog='maltoolbox',
|
|
28
|
-
description='Generate Attack Graphs from MAL specifications')
|
|
29
|
-
|
|
30
|
-
parser.add_argument(
|
|
31
|
-
'--version',
|
|
32
|
-
action='version',
|
|
33
|
-
version=f'%(prog)s {__version__}')
|
|
34
|
-
|
|
35
|
-
subparsers = parser.add_subparsers(help='commands', dest='command')
|
|
36
|
-
subparsers.required = True
|
|
37
|
-
|
|
38
|
-
gen_ag_parser = subparsers.add_parser(
|
|
39
|
-
'gen_ag',
|
|
40
|
-
help='Generate an attack graph from an instance model from a json ' \
|
|
41
|
-
'file and language specification from a mar archive.')
|
|
42
|
-
help_parser = subparsers.add_parser(
|
|
43
|
-
'help', help='Show help for a particular command')
|
|
44
|
-
|
|
45
|
-
gen_ag_parser.add_argument(
|
|
46
|
-
'model',
|
|
47
|
-
help='Path to the instance model json file',
|
|
48
|
-
type=str,
|
|
49
|
-
)
|
|
50
|
-
|
|
51
|
-
gen_ag_parser.add_argument(
|
|
52
|
-
'language',
|
|
53
|
-
help='Path to the language specification ".mar" archive',
|
|
54
|
-
type=str,
|
|
55
|
-
)
|
|
56
|
-
|
|
57
|
-
gen_ag_parser.add_argument(
|
|
58
|
-
'--neo4j',
|
|
59
|
-
help='Injest attack graph and instance model into a local Neo4j ' \
|
|
60
|
-
'instance',
|
|
61
|
-
action='store_true'
|
|
62
|
-
)
|
|
63
|
-
|
|
64
|
-
help_parser.add_argument(
|
|
65
|
-
'cmd',
|
|
66
|
-
help='Name of command to get help for',
|
|
67
|
-
nargs='?')
|
|
68
|
-
|
|
69
|
-
if len(args) == 0:
|
|
70
|
-
parser.print_help(sys.stderr)
|
|
71
|
-
logger.error('Received no arugments will print help and exit.')
|
|
72
|
-
sys.exit(1)
|
|
73
|
-
|
|
74
|
-
parsed_args = parser.parse_args()
|
|
75
|
-
if parsed_args.command == 'help':
|
|
76
|
-
if not parsed_args.cmd:
|
|
77
|
-
parser.print_help(sys.stderr)
|
|
78
|
-
else:
|
|
79
|
-
try:
|
|
80
|
-
subparsers.choices[parsed_args.cmd].print_help()
|
|
81
|
-
except KeyError:
|
|
82
|
-
logger.error(f'Unknown command name {parsed_args.cmd}')
|
|
83
|
-
print(f'Unknown command name {parsed_args.cmd}')
|
|
84
|
-
print(
|
|
85
|
-
f'Valid commands are: {", ".join(subparsers.choices.keys())}')
|
|
86
|
-
|
|
87
|
-
sys.exit(1)
|
|
88
|
-
|
|
89
|
-
return parsed_args
|