mal-toolbox 0.1.12__tar.gz → 0.3.0__tar.gz

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.
Files changed (50) hide show
  1. {mal_toolbox-0.1.12/mal_toolbox.egg-info → mal_toolbox-0.3.0}/PKG-INFO +43 -25
  2. {mal_toolbox-0.1.12 → mal_toolbox-0.3.0}/README.md +41 -22
  3. {mal_toolbox-0.1.12 → mal_toolbox-0.3.0/mal_toolbox.egg-info}/PKG-INFO +43 -25
  4. {mal_toolbox-0.1.12 → mal_toolbox-0.3.0}/mal_toolbox.egg-info/SOURCES.txt +2 -6
  5. mal_toolbox-0.3.0/mal_toolbox.egg-info/entry_points.txt +2 -0
  6. {mal_toolbox-0.1.12 → mal_toolbox-0.3.0}/mal_toolbox.egg-info/requires.txt +0 -1
  7. mal_toolbox-0.3.0/maltoolbox/__init__.py +75 -0
  8. {mal_toolbox-0.1.12 → mal_toolbox-0.3.0}/maltoolbox/__main__.py +43 -14
  9. {mal_toolbox-0.1.12 → mal_toolbox-0.3.0}/maltoolbox/attackgraph/__init__.py +1 -1
  10. {mal_toolbox-0.1.12 → mal_toolbox-0.3.0}/maltoolbox/attackgraph/analyzers/apriori.py +10 -6
  11. {mal_toolbox-0.1.12 → mal_toolbox-0.3.0}/maltoolbox/attackgraph/attacker.py +26 -13
  12. mal_toolbox-0.3.0/maltoolbox/attackgraph/attackgraph.py +818 -0
  13. {mal_toolbox-0.1.12 → mal_toolbox-0.3.0}/maltoolbox/attackgraph/node.py +72 -54
  14. {mal_toolbox-0.1.12 → mal_toolbox-0.3.0}/maltoolbox/attackgraph/query.py +4 -2
  15. {mal_toolbox-0.1.12 → mal_toolbox-0.3.0}/maltoolbox/file_utils.py +4 -8
  16. mal_toolbox-0.3.0/maltoolbox/ingestors/neo4j.py +244 -0
  17. mal_toolbox-0.3.0/maltoolbox/language/__init__.py +12 -0
  18. mal_toolbox-0.1.12/maltoolbox/language/compiler/mal_visitor.py → mal_toolbox-0.3.0/maltoolbox/language/compiler/__init__.py +111 -27
  19. mal_toolbox-0.3.0/maltoolbox/language/compiler/mal_lexer.py +232 -0
  20. {mal_toolbox-0.1.12 → mal_toolbox-0.3.0}/maltoolbox/language/compiler/mal_parser.py +1370 -663
  21. mal_toolbox-0.3.0/maltoolbox/language/languagegraph.py +1735 -0
  22. mal_toolbox-0.3.0/maltoolbox/model.py +685 -0
  23. mal_toolbox-0.3.0/maltoolbox/translators/securicad.py +179 -0
  24. mal_toolbox-0.3.0/maltoolbox/translators/updater.py +255 -0
  25. {mal_toolbox-0.1.12 → mal_toolbox-0.3.0}/pyproject.toml +7 -5
  26. mal_toolbox-0.3.0/tests/test_model.py +679 -0
  27. mal_toolbox-0.1.12/maltoolbox/__init__.py +0 -94
  28. mal_toolbox-0.1.12/maltoolbox/attackgraph/attackgraph.py +0 -742
  29. mal_toolbox-0.1.12/maltoolbox/default.conf +0 -17
  30. mal_toolbox-0.1.12/maltoolbox/ingestors/neo4j.py +0 -255
  31. mal_toolbox-0.1.12/maltoolbox/language/__init__.py +0 -4
  32. mal_toolbox-0.1.12/maltoolbox/language/classes_factory.py +0 -243
  33. mal_toolbox-0.1.12/maltoolbox/language/compiler/__init__.py +0 -32
  34. mal_toolbox-0.1.12/maltoolbox/language/compiler/mal_lexer.py +0 -212
  35. mal_toolbox-0.1.12/maltoolbox/language/languagegraph.py +0 -1184
  36. mal_toolbox-0.1.12/maltoolbox/model.py +0 -858
  37. mal_toolbox-0.1.12/maltoolbox/translators/securicad.py +0 -178
  38. mal_toolbox-0.1.12/maltoolbox/translators/updater.py +0 -132
  39. mal_toolbox-0.1.12/maltoolbox/wrappers.py +0 -62
  40. mal_toolbox-0.1.12/tests/test_model.py +0 -906
  41. mal_toolbox-0.1.12/tests/test_wrappers.py +0 -10
  42. {mal_toolbox-0.1.12 → mal_toolbox-0.3.0}/AUTHORS +0 -0
  43. {mal_toolbox-0.1.12 → mal_toolbox-0.3.0}/LICENSE +0 -0
  44. {mal_toolbox-0.1.12 → mal_toolbox-0.3.0}/mal_toolbox.egg-info/dependency_links.txt +0 -0
  45. {mal_toolbox-0.1.12 → mal_toolbox-0.3.0}/mal_toolbox.egg-info/top_level.txt +0 -0
  46. {mal_toolbox-0.1.12 → mal_toolbox-0.3.0}/maltoolbox/attackgraph/analyzers/__init__.py +0 -0
  47. {mal_toolbox-0.1.12 → mal_toolbox-0.3.0}/maltoolbox/exceptions.py +0 -0
  48. {mal_toolbox-0.1.12 → mal_toolbox-0.3.0}/maltoolbox/ingestors/__init__.py +0 -0
  49. {mal_toolbox-0.1.12 → mal_toolbox-0.3.0}/maltoolbox/translators/__init__.py +0 -0
  50. {mal_toolbox-0.1.12 → mal_toolbox-0.3.0}/setup.cfg +0 -0
@@ -1,8 +1,8 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: mal-toolbox
3
- Version: 0.1.12
3
+ Version: 0.3.0
4
4
  Summary: A collection of tools used to create MAL models and attack graphs.
5
- Author-email: Andrei Buhaiu <buhaiu@kth.se>, Giuseppe Nebbione <nebbione@kth.se>, Nikolaos Kakouros <nkak@kth.se>, Jakob Nyberg <jaknyb@kth.se>, Joakim Loxdal <loxdal@kth.se>
5
+ Author-email: Andrei Buhaiu <buhaiu@kth.se>, Joakim Loxdal <loxdal@kth.se>, Nikolaos Kakouros <nkak@kth.se>, Jakob Nyberg <jaknyb@kth.se>, Giuseppe Nebbione <nebbione@kth.se>
6
6
  License: Apache Software License
7
7
  Project-URL: Homepage, https://github.com/mal-lang/mal-toolbox
8
8
  Project-URL: Bug Tracker, https://github.com/mal-lang/mal-toolbox/issues
@@ -19,7 +19,6 @@ Description-Content-Type: text/markdown
19
19
  License-File: LICENSE
20
20
  License-File: AUTHORS
21
21
  Requires-Dist: py2neo>=2021.2.3
22
- Requires-Dist: python-jsonschema-objects>=0.5.5
23
22
  Requires-Dist: antlr4-tools
24
23
  Requires-Dist: antlr4-python3-runtime
25
24
  Requires-Dist: docopt
@@ -48,17 +47,6 @@ then be used to generate python classes representing the assets and
48
47
  associations of the language and to determine the attack steps for each asset
49
48
  when generating the attack graph.
50
49
 
51
- ### The Language Classes Factory Submodule
52
-
53
- The language classes factory submodule is used to generate python classes
54
- using the `python_jsonschema_objects` package from a language specification.
55
- The classes generated by the `create_classes` function can then be accessed
56
- from within that namespace(.e.g: `lang_classes_factory.ns.Application()`,
57
- `lang_classes_factory.ns.AppExecution()`). Because these classes are built
58
- using JSON Schema validators they will enforce their restrictions when using
59
- the python objects created. These classes are typically used in conjunction
60
- with model module to create instance models.
61
-
62
50
  ## The Model Module
63
51
 
64
52
  With a MAL language a Model (a MAL instance model) can be created either
@@ -109,21 +97,51 @@ pip install mal-toolbox
109
97
  ```
110
98
 
111
99
  ## Configuration
112
- A default configuration file `default.conf` can be found in the package
113
- directory. This contains the default values to use for logging and can also be
114
- used to store the information needed to access the local Neo4J instance.
100
+ You can use a `maltoolbox.yml` file in the current working directory to
101
+ configure the toolbox. Alternatively, you can use the `MALTOOLBOX_CONFIG`
102
+ environment variable to set a custom config file location:
103
+
104
+ """bash
105
+ # in your shell, e.g. bash do:
106
+ export MALTOOLBOX_CONFIG=path/to/yml/config/file
107
+ """
108
+
109
+ The default configuration can be found here:
110
+
111
+ https://github.com/mal-lang/mal-toolbox/blob/main/maltoolbox/__init__.py#L39-L53
115
112
 
116
113
  ## Command Line Client
117
- In addition to the modules that make up the MAL-Toolbox package it also
118
- provides a simple command line client that can be used to easily generate
119
- attack graphs from a .mar language specification file and a JSON instance
120
- model file.
121
114
 
122
- The usage is: `maltoolbox gen_ag [--neo4j] <model_json_file>
123
- <language_mar_file>`
115
+ You can use the maltoolbox cli to:
116
+
117
+ - Generate attack graphs from model files
118
+ - Compile MAL languages
119
+ - Upgrade model files from older versions
124
120
 
125
- If the `--neo4j` flag is specified the model and attack graph will be loaded
126
- into a local Neo4J instance.
121
+ ```
122
+ Command-line interface for MAL toolbox operations
123
+
124
+ Usage:
125
+ maltoolbox attack-graph generate [options] <model_file> <lang_file>
126
+ maltoolbox compile <lang_file> <output_file>
127
+ maltoolbox upgrade-model <model_file> <lang_file> <output_file>
128
+
129
+ Arguments:
130
+ <model_file> Path to JSON instance model file.
131
+ <lang_file> Path to .mar or .mal file containing MAL spec.
132
+ <output_file> Path to write the result of the compilation (yml/json).
133
+
134
+ Options:
135
+ --neo4j Ingest attack graph and instance model into a Neo4j instance
136
+
137
+ Notes:
138
+ - <lang_file> can be either a .mar file (generated by the older MAL
139
+ compiler) or a .mal file containing the DSL written in MAL.
140
+
141
+ - If --neo4j is used, the Neo4j instance should be running. The connection
142
+ parameters required for this app to reach the Neo4j instance should be
143
+ defined in the default.conf file.
144
+ ```
127
145
 
128
146
  ## Code examples / Tutorial
129
147
 
@@ -21,17 +21,6 @@ then be used to generate python classes representing the assets and
21
21
  associations of the language and to determine the attack steps for each asset
22
22
  when generating the attack graph.
23
23
 
24
- ### The Language Classes Factory Submodule
25
-
26
- The language classes factory submodule is used to generate python classes
27
- using the `python_jsonschema_objects` package from a language specification.
28
- The classes generated by the `create_classes` function can then be accessed
29
- from within that namespace(.e.g: `lang_classes_factory.ns.Application()`,
30
- `lang_classes_factory.ns.AppExecution()`). Because these classes are built
31
- using JSON Schema validators they will enforce their restrictions when using
32
- the python objects created. These classes are typically used in conjunction
33
- with model module to create instance models.
34
-
35
24
  ## The Model Module
36
25
 
37
26
  With a MAL language a Model (a MAL instance model) can be created either
@@ -82,21 +71,51 @@ pip install mal-toolbox
82
71
  ```
83
72
 
84
73
  ## Configuration
85
- A default configuration file `default.conf` can be found in the package
86
- directory. This contains the default values to use for logging and can also be
87
- used to store the information needed to access the local Neo4J instance.
74
+ You can use a `maltoolbox.yml` file in the current working directory to
75
+ configure the toolbox. Alternatively, you can use the `MALTOOLBOX_CONFIG`
76
+ environment variable to set a custom config file location:
77
+
78
+ """bash
79
+ # in your shell, e.g. bash do:
80
+ export MALTOOLBOX_CONFIG=path/to/yml/config/file
81
+ """
82
+
83
+ The default configuration can be found here:
84
+
85
+ https://github.com/mal-lang/mal-toolbox/blob/main/maltoolbox/__init__.py#L39-L53
88
86
 
89
87
  ## Command Line Client
90
- In addition to the modules that make up the MAL-Toolbox package it also
91
- provides a simple command line client that can be used to easily generate
92
- attack graphs from a .mar language specification file and a JSON instance
93
- model file.
94
88
 
95
- The usage is: `maltoolbox gen_ag [--neo4j] <model_json_file>
96
- <language_mar_file>`
89
+ You can use the maltoolbox cli to:
90
+
91
+ - Generate attack graphs from model files
92
+ - Compile MAL languages
93
+ - Upgrade model files from older versions
97
94
 
98
- If the `--neo4j` flag is specified the model and attack graph will be loaded
99
- into a local Neo4J instance.
95
+ ```
96
+ Command-line interface for MAL toolbox operations
97
+
98
+ Usage:
99
+ maltoolbox attack-graph generate [options] <model_file> <lang_file>
100
+ maltoolbox compile <lang_file> <output_file>
101
+ maltoolbox upgrade-model <model_file> <lang_file> <output_file>
102
+
103
+ Arguments:
104
+ <model_file> Path to JSON instance model file.
105
+ <lang_file> Path to .mar or .mal file containing MAL spec.
106
+ <output_file> Path to write the result of the compilation (yml/json).
107
+
108
+ Options:
109
+ --neo4j Ingest attack graph and instance model into a Neo4j instance
110
+
111
+ Notes:
112
+ - <lang_file> can be either a .mar file (generated by the older MAL
113
+ compiler) or a .mal file containing the DSL written in MAL.
114
+
115
+ - If --neo4j is used, the Neo4j instance should be running. The connection
116
+ parameters required for this app to reach the Neo4j instance should be
117
+ defined in the default.conf file.
118
+ ```
100
119
 
101
120
  ## Code examples / Tutorial
102
121
 
@@ -1,8 +1,8 @@
1
1
  Metadata-Version: 2.2
2
2
  Name: mal-toolbox
3
- Version: 0.1.12
3
+ Version: 0.3.0
4
4
  Summary: A collection of tools used to create MAL models and attack graphs.
5
- Author-email: Andrei Buhaiu <buhaiu@kth.se>, Giuseppe Nebbione <nebbione@kth.se>, Nikolaos Kakouros <nkak@kth.se>, Jakob Nyberg <jaknyb@kth.se>, Joakim Loxdal <loxdal@kth.se>
5
+ Author-email: Andrei Buhaiu <buhaiu@kth.se>, Joakim Loxdal <loxdal@kth.se>, Nikolaos Kakouros <nkak@kth.se>, Jakob Nyberg <jaknyb@kth.se>, Giuseppe Nebbione <nebbione@kth.se>
6
6
  License: Apache Software License
7
7
  Project-URL: Homepage, https://github.com/mal-lang/mal-toolbox
8
8
  Project-URL: Bug Tracker, https://github.com/mal-lang/mal-toolbox/issues
@@ -19,7 +19,6 @@ Description-Content-Type: text/markdown
19
19
  License-File: LICENSE
20
20
  License-File: AUTHORS
21
21
  Requires-Dist: py2neo>=2021.2.3
22
- Requires-Dist: python-jsonschema-objects>=0.5.5
23
22
  Requires-Dist: antlr4-tools
24
23
  Requires-Dist: antlr4-python3-runtime
25
24
  Requires-Dist: docopt
@@ -48,17 +47,6 @@ then be used to generate python classes representing the assets and
48
47
  associations of the language and to determine the attack steps for each asset
49
48
  when generating the attack graph.
50
49
 
51
- ### The Language Classes Factory Submodule
52
-
53
- The language classes factory submodule is used to generate python classes
54
- using the `python_jsonschema_objects` package from a language specification.
55
- The classes generated by the `create_classes` function can then be accessed
56
- from within that namespace(.e.g: `lang_classes_factory.ns.Application()`,
57
- `lang_classes_factory.ns.AppExecution()`). Because these classes are built
58
- using JSON Schema validators they will enforce their restrictions when using
59
- the python objects created. These classes are typically used in conjunction
60
- with model module to create instance models.
61
-
62
50
  ## The Model Module
63
51
 
64
52
  With a MAL language a Model (a MAL instance model) can be created either
@@ -109,21 +97,51 @@ pip install mal-toolbox
109
97
  ```
110
98
 
111
99
  ## Configuration
112
- A default configuration file `default.conf` can be found in the package
113
- directory. This contains the default values to use for logging and can also be
114
- used to store the information needed to access the local Neo4J instance.
100
+ You can use a `maltoolbox.yml` file in the current working directory to
101
+ configure the toolbox. Alternatively, you can use the `MALTOOLBOX_CONFIG`
102
+ environment variable to set a custom config file location:
103
+
104
+ """bash
105
+ # in your shell, e.g. bash do:
106
+ export MALTOOLBOX_CONFIG=path/to/yml/config/file
107
+ """
108
+
109
+ The default configuration can be found here:
110
+
111
+ https://github.com/mal-lang/mal-toolbox/blob/main/maltoolbox/__init__.py#L39-L53
115
112
 
116
113
  ## Command Line Client
117
- In addition to the modules that make up the MAL-Toolbox package it also
118
- provides a simple command line client that can be used to easily generate
119
- attack graphs from a .mar language specification file and a JSON instance
120
- model file.
121
114
 
122
- The usage is: `maltoolbox gen_ag [--neo4j] <model_json_file>
123
- <language_mar_file>`
115
+ You can use the maltoolbox cli to:
116
+
117
+ - Generate attack graphs from model files
118
+ - Compile MAL languages
119
+ - Upgrade model files from older versions
124
120
 
125
- If the `--neo4j` flag is specified the model and attack graph will be loaded
126
- into a local Neo4J instance.
121
+ ```
122
+ Command-line interface for MAL toolbox operations
123
+
124
+ Usage:
125
+ maltoolbox attack-graph generate [options] <model_file> <lang_file>
126
+ maltoolbox compile <lang_file> <output_file>
127
+ maltoolbox upgrade-model <model_file> <lang_file> <output_file>
128
+
129
+ Arguments:
130
+ <model_file> Path to JSON instance model file.
131
+ <lang_file> Path to .mar or .mal file containing MAL spec.
132
+ <output_file> Path to write the result of the compilation (yml/json).
133
+
134
+ Options:
135
+ --neo4j Ingest attack graph and instance model into a Neo4j instance
136
+
137
+ Notes:
138
+ - <lang_file> can be either a .mar file (generated by the older MAL
139
+ compiler) or a .mal file containing the DSL written in MAL.
140
+
141
+ - If --neo4j is used, the Neo4j instance should be running. The connection
142
+ parameters required for this app to reach the Neo4j instance should be
143
+ defined in the default.conf file.
144
+ ```
127
145
 
128
146
  ## Code examples / Tutorial
129
147
 
@@ -5,15 +5,14 @@ pyproject.toml
5
5
  mal_toolbox.egg-info/PKG-INFO
6
6
  mal_toolbox.egg-info/SOURCES.txt
7
7
  mal_toolbox.egg-info/dependency_links.txt
8
+ mal_toolbox.egg-info/entry_points.txt
8
9
  mal_toolbox.egg-info/requires.txt
9
10
  mal_toolbox.egg-info/top_level.txt
10
11
  maltoolbox/__init__.py
11
12
  maltoolbox/__main__.py
12
- maltoolbox/default.conf
13
13
  maltoolbox/exceptions.py
14
14
  maltoolbox/file_utils.py
15
15
  maltoolbox/model.py
16
- maltoolbox/wrappers.py
17
16
  maltoolbox/attackgraph/__init__.py
18
17
  maltoolbox/attackgraph/attacker.py
19
18
  maltoolbox/attackgraph/attackgraph.py
@@ -24,14 +23,11 @@ maltoolbox/attackgraph/analyzers/apriori.py
24
23
  maltoolbox/ingestors/__init__.py
25
24
  maltoolbox/ingestors/neo4j.py
26
25
  maltoolbox/language/__init__.py
27
- maltoolbox/language/classes_factory.py
28
26
  maltoolbox/language/languagegraph.py
29
27
  maltoolbox/language/compiler/__init__.py
30
28
  maltoolbox/language/compiler/mal_lexer.py
31
29
  maltoolbox/language/compiler/mal_parser.py
32
- maltoolbox/language/compiler/mal_visitor.py
33
30
  maltoolbox/translators/__init__.py
34
31
  maltoolbox/translators/securicad.py
35
32
  maltoolbox/translators/updater.py
36
- tests/test_model.py
37
- tests/test_wrappers.py
33
+ tests/test_model.py
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ maltoolbox = maltoolbox.__main__:main
@@ -1,5 +1,4 @@
1
1
  py2neo>=2021.2.3
2
- python-jsonschema-objects>=0.5.5
3
2
  antlr4-tools
4
3
  antlr4-python3-runtime
5
4
  docopt
@@ -0,0 +1,75 @@
1
+ # -*- encoding: utf-8 -*-
2
+ # MAL Toolbox v0.3.0
3
+ # Copyright 2024, Andrei Buhaiu.
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # https://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ #
17
+
18
+
19
+ """
20
+ MAL-Toolbox Framework
21
+ """
22
+
23
+ __title__ = "maltoolbox"
24
+ __version__ = "0.3.0"
25
+ __authors__ = [
26
+ "Andrei Buhaiu",
27
+ "Giuseppe Nebbione",
28
+ "Nikolaos Kakouros",
29
+ "Jakob Nyberg",
30
+ "Joakim Loxdal",
31
+ ]
32
+ __license__ = "Apache 2.0"
33
+ __docformat__ = "restructuredtext en"
34
+
35
+ __all__ = ()
36
+
37
+ import os
38
+ import yaml
39
+ import logging
40
+ from typing import Any
41
+
42
+ config: dict[str, Any] = {
43
+ "logging": {
44
+ "log_level": logging.INFO,
45
+ "log_file": "logs/log.txt",
46
+ "attackgraph_file": "logs/attackgraph.yml",
47
+ "model_file": "logs/model.yml",
48
+ "langspec_file": "logs/langspec_file.yml",
49
+ },
50
+ "neo4j": {"uri": None, "username": None, "password": None, "dbname": None},
51
+ }
52
+
53
+ config_file = os.getenv("MALTOOLBOX_CONFIG", "maltoolbox.yml")
54
+
55
+ if os.path.exists(config_file):
56
+ with open(config_file) as f:
57
+ config |= yaml.safe_load(f)
58
+
59
+ log_configs, neo4j_configs = config.values()
60
+
61
+ os.makedirs(os.path.dirname(log_configs["log_file"]), exist_ok=True)
62
+
63
+ formatter = logging.Formatter(
64
+ "%(asctime)s %(name)-12s %(levelname)-8s %(message)s", datefmt="%m-%d %H:%M"
65
+ )
66
+ file_handler = logging.FileHandler(log_configs["log_file"], mode="w")
67
+ file_handler.setFormatter(formatter)
68
+
69
+ logger = logging.getLogger(__name__)
70
+ logger.addHandler(file_handler)
71
+
72
+ logger.setLevel(log_configs.get("log_level"))
73
+ logger.info("Set loggin level of %s to %s.", __name__, log_configs.get("log_level"))
74
+
75
+ logger.debug("Config file location: %s", config_file)
@@ -2,13 +2,14 @@
2
2
  Command-line interface for MAL toolbox operations
3
3
 
4
4
  Usage:
5
- maltoolbox attack-graph generate [options] <model> <lang_file>
5
+ maltoolbox attack-graph generate [options] <model_file> <lang_file>
6
6
  maltoolbox compile <lang_file> <output_file>
7
+ maltoolbox upgrade-model <model_file> <lang_file> <output_file>
7
8
 
8
9
  Arguments:
9
- <model> Path to JSON instance model file.
10
+ <model_file> Path to JSON instance model file.
10
11
  <lang_file> Path to .mar or .mal file containing MAL spec.
11
- <output_file> Path to write the JSON result of the compilation.
12
+ <output_file> Path to write the result of the compilation (yml/json).
12
13
 
13
14
  Options:
14
15
  --neo4j Ingest attack graph and instance model into a Neo4j instance
@@ -26,10 +27,12 @@ import logging
26
27
  import json
27
28
  import docopt
28
29
 
29
- from maltoolbox.wrappers import create_attack_graph
30
30
  from . import log_configs, neo4j_configs
31
+ from .attackgraph import create_attack_graph
31
32
  from .language.compiler import MalCompiler
32
33
  from .ingestors import neo4j
34
+ from .language.languagegraph import LanguageGraph
35
+ from .translators.updater import load_model_from_older_version
33
36
 
34
37
  logger = logging.getLogger(__name__)
35
38
 
@@ -39,7 +42,7 @@ def generate_attack_graph(
39
42
  send_to_neo4j: bool
40
43
  ) -> None:
41
44
  """Create an attack graph and optionally send to neo4j
42
-
45
+
43
46
  Args:
44
47
  model_file - path to the model file
45
48
  lang_file - path to the language file
@@ -53,19 +56,23 @@ def generate_attack_graph(
53
56
 
54
57
  if send_to_neo4j:
55
58
  logger.debug('Ingest model graph into Neo4J database.')
56
- neo4j.ingest_model(attack_graph.model,
59
+ neo4j.ingest_model(
60
+ attack_graph.model,
57
61
  neo4j_configs['uri'],
58
62
  neo4j_configs['username'],
59
63
  neo4j_configs['password'],
60
64
  neo4j_configs['dbname'],
61
- delete=True)
65
+ delete=True
66
+ )
62
67
  logger.debug('Ingest attack graph into Neo4J database.')
63
- neo4j.ingest_attack_graph(attack_graph,
68
+ neo4j.ingest_attack_graph(
69
+ attack_graph,
64
70
  neo4j_configs['uri'],
65
71
  neo4j_configs['username'],
66
72
  neo4j_configs['password'],
67
73
  neo4j_configs['dbname'],
68
- delete=False)
74
+ delete=False
75
+ )
69
76
 
70
77
 
71
78
  def compile(lang_file: str, output_file: str) -> None:
@@ -75,9 +82,31 @@ def compile(lang_file: str, output_file: str) -> None:
75
82
  json.dump(compiler.compile(lang_file), f, indent=2)
76
83
 
77
84
 
78
- args = docopt.docopt(__doc__)
85
+ def upgrade_model(model_file: str, lang_file: str, output_file: str):
86
+ lang_graph = LanguageGraph.load_from_file(lang_file)
87
+
88
+ if log_configs['langspec_file']:
89
+ lang_graph.save_to_file(log_configs['langspec_file'])
90
+
91
+ model = load_model_from_older_version(model_file, lang_graph)
92
+ model.save_to_file(output_file)
93
+
94
+
95
+ def main():
96
+ args = docopt.docopt(__doc__)
97
+
98
+ if args['attack-graph'] and args['generate']:
99
+ generate_attack_graph(
100
+ args['<model_file>'], args['<lang_file>'], args['--neo4j']
101
+ )
102
+ elif args['compile']:
103
+ compile(
104
+ args['<lang_file>'], args['<output_file>']
105
+ )
106
+ elif args['upgrade-model']:
107
+ upgrade_model(
108
+ args['<model_file>'], args['<lang_file>'], args['<output_file>']
109
+ )
79
110
 
80
- if args['attack-graph'] and args['generate']:
81
- generate_attack_graph(args['<model>'], args['<lang_file>'], args['--neo4j'])
82
- elif args['compile']:
83
- compile(args['<lang_file>'], args['<output_file>'])
111
+ if __name__ == "__main__":
112
+ main()
@@ -4,5 +4,5 @@ models and analyze attack graphs.
4
4
  """
5
5
 
6
6
  from .attacker import Attacker
7
- from .attackgraph import AttackGraph
7
+ from .attackgraph import AttackGraph, create_attack_graph
8
8
  from .node import AttackGraphNode
@@ -12,11 +12,12 @@ Currently these are:
12
12
  """
13
13
 
14
14
  from __future__ import annotations
15
- from typing import Optional
15
+ from typing import Optional, TYPE_CHECKING
16
16
  import logging
17
17
 
18
- from ..attackgraph import AttackGraph
19
- from ..node import AttackGraphNode
18
+ if TYPE_CHECKING:
19
+ from ..attackgraph import AttackGraph
20
+ from ..node import AttackGraphNode
20
21
 
21
22
  logger = logging.getLogger(__name__)
22
23
 
@@ -55,11 +56,13 @@ def propagate_necessity_from_node(node: AttackGraphNode) -> None:
55
56
  )
56
57
 
57
58
  if node.ttc and 'name' in node.ttc:
58
- if node.ttc['name'] not in ['Enabled', 'Disabled']:
59
+ if node.ttc['name'] not in ['Enabled', 'Disabled', 'Instant']:
59
60
  # Do not propagate unnecessary state from nodes that have a TTC
60
61
  # probability distribution associated with them.
61
62
  # TODO: Evaluate this more carefully, how do we want to have TTCs
62
63
  # impact necessity and viability.
64
+ # TODO: Have this condition be any probability that has a
65
+ # Bernoulli component
63
66
  return
64
67
 
65
68
  for child in node.children:
@@ -160,7 +163,7 @@ def calculate_viability_and_necessity(graph: AttackGraph) -> None:
160
163
  graph - the attack graph for which we wish to determine the
161
164
  viability and necessity statuses for the nodes.
162
165
  """
163
- for node in graph.nodes:
166
+ for node in graph.nodes.values():
164
167
  if node.type in ['exist', 'notExist', 'defense']:
165
168
  evaluate_viability_and_necessity(node)
166
169
  if not node.is_viable:
@@ -175,7 +178,8 @@ def prune_unviable_and_unnecessary_nodes(graph: AttackGraph) -> None:
175
178
  graph - the attack graph for which we wish to remove the
176
179
  the nodes which are not viable or necessary.
177
180
  """
178
- for node in graph.nodes:
181
+ logger.debug('Prune unviable and unnecessary nodes from the attack graph.')
182
+ for node in graph.nodes.values():
179
183
  if (node.type == 'or' or node.type == 'and') and \
180
184
  (not node.is_viable or not node.is_necessary):
181
185
  graph.remove_node(node)
@@ -3,7 +3,6 @@ MAL-Toolbox Attack Graph Attacker Class
3
3
  """
4
4
 
5
5
  from __future__ import annotations
6
- from dataclasses import dataclass, field
7
6
  import copy
8
7
  import logging
9
8
 
@@ -14,13 +13,19 @@ if TYPE_CHECKING:
14
13
 
15
14
  logger = logging.getLogger(__name__)
16
15
 
17
- @dataclass
18
16
  class Attacker:
19
- name: str
20
- entry_points: list[AttackGraphNode] = field(default_factory=list)
21
- reached_attack_steps: list[AttackGraphNode] = \
22
- field(default_factory=list)
23
- id: Optional[int] = None
17
+
18
+ def __init__(
19
+ self,
20
+ name: str,
21
+ entry_points: set[AttackGraphNode],
22
+ reached_attack_steps: set[AttackGraphNode],
23
+ attacker_id: Optional[int] = None
24
+ ):
25
+ self.name = name
26
+ self.entry_points = entry_points
27
+ self.reached_attack_steps = reached_attack_steps
28
+ self.id = attacker_id
24
29
 
25
30
  def to_dict(self) -> dict:
26
31
  attacker_dict: dict = {
@@ -40,18 +45,26 @@ class Attacker:
40
45
  return attacker_dict
41
46
 
42
47
  def __repr__(self) -> str:
43
- return str(self.to_dict())
48
+ return f'Attacker(name: "{self.name}", id: {self.id})'
44
49
 
45
50
  def __deepcopy__(self, memo) -> Attacker:
46
- """Deep copy an Attacker"""
51
+ """Deep copy an Attacker
52
+ The deepcopy will copy over attacker specific information, name and
53
+ id, but it will not copy relations to attack graph nodes, reached
54
+ attack steps or entry points. These references should be recreated
55
+ when deepcopying the attack graph itself.
56
+
57
+ """
47
58
 
48
59
  # Check if the object is already in the memo dictionary
49
60
  if id(self) in memo:
50
61
  return memo[id(self)]
51
62
 
52
63
  copied_attacker = Attacker(
53
- id = self.id,
54
64
  name = self.name,
65
+ attacker_id = self.id,
66
+ entry_points = set(),
67
+ reached_attack_steps = set()
55
68
  )
56
69
 
57
70
  # Remember that self was already copied
@@ -66,7 +79,7 @@ class Attacker:
66
79
 
67
80
  def compromise(self, node: AttackGraphNode) -> None:
68
81
  """
69
- Have the attacke compromise the node given as a parameter.
82
+ Have the attacker compromise the node given as a parameter.
70
83
 
71
84
  Arguments:
72
85
  node - the node that the attacker will compromise
@@ -90,8 +103,8 @@ class Attacker:
90
103
  )
91
104
  return
92
105
 
93
- node.compromised_by.append(self)
94
- self.reached_attack_steps.append(node)
106
+ node.compromised_by.add(self)
107
+ self.reached_attack_steps.add(node)
95
108
 
96
109
  def undo_compromise(self, node: AttackGraphNode) -> None:
97
110
  """