mal-toolbox 0.3.6__tar.gz → 0.3.7__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.
- {mal_toolbox-0.3.6/mal_toolbox.egg-info → mal_toolbox-0.3.7}/PKG-INFO +1 -1
- {mal_toolbox-0.3.6 → mal_toolbox-0.3.7/mal_toolbox.egg-info}/PKG-INFO +1 -1
- {mal_toolbox-0.3.6 → mal_toolbox-0.3.7}/maltoolbox/__init__.py +2 -2
- {mal_toolbox-0.3.6 → mal_toolbox-0.3.7}/maltoolbox/attackgraph/analyzers/apriori.py +5 -5
- {mal_toolbox-0.3.6 → mal_toolbox-0.3.7}/maltoolbox/attackgraph/query.py +31 -51
- {mal_toolbox-0.3.6 → mal_toolbox-0.3.7}/pyproject.toml +1 -1
- {mal_toolbox-0.3.6 → mal_toolbox-0.3.7}/AUTHORS +0 -0
- {mal_toolbox-0.3.6 → mal_toolbox-0.3.7}/LICENSE +0 -0
- {mal_toolbox-0.3.6 → mal_toolbox-0.3.7}/README.md +0 -0
- {mal_toolbox-0.3.6 → mal_toolbox-0.3.7}/mal_toolbox.egg-info/SOURCES.txt +0 -0
- {mal_toolbox-0.3.6 → mal_toolbox-0.3.7}/mal_toolbox.egg-info/dependency_links.txt +0 -0
- {mal_toolbox-0.3.6 → mal_toolbox-0.3.7}/mal_toolbox.egg-info/entry_points.txt +0 -0
- {mal_toolbox-0.3.6 → mal_toolbox-0.3.7}/mal_toolbox.egg-info/requires.txt +0 -0
- {mal_toolbox-0.3.6 → mal_toolbox-0.3.7}/mal_toolbox.egg-info/top_level.txt +0 -0
- {mal_toolbox-0.3.6 → mal_toolbox-0.3.7}/maltoolbox/__main__.py +0 -0
- {mal_toolbox-0.3.6 → mal_toolbox-0.3.7}/maltoolbox/attackgraph/__init__.py +0 -0
- {mal_toolbox-0.3.6 → mal_toolbox-0.3.7}/maltoolbox/attackgraph/analyzers/__init__.py +0 -0
- {mal_toolbox-0.3.6 → mal_toolbox-0.3.7}/maltoolbox/attackgraph/attacker.py +0 -0
- {mal_toolbox-0.3.6 → mal_toolbox-0.3.7}/maltoolbox/attackgraph/attackgraph.py +0 -0
- {mal_toolbox-0.3.6 → mal_toolbox-0.3.7}/maltoolbox/attackgraph/node.py +0 -0
- {mal_toolbox-0.3.6 → mal_toolbox-0.3.7}/maltoolbox/exceptions.py +0 -0
- {mal_toolbox-0.3.6 → mal_toolbox-0.3.7}/maltoolbox/file_utils.py +0 -0
- {mal_toolbox-0.3.6 → mal_toolbox-0.3.7}/maltoolbox/ingestors/__init__.py +0 -0
- {mal_toolbox-0.3.6 → mal_toolbox-0.3.7}/maltoolbox/ingestors/neo4j.py +0 -0
- {mal_toolbox-0.3.6 → mal_toolbox-0.3.7}/maltoolbox/language/__init__.py +0 -0
- {mal_toolbox-0.3.6 → mal_toolbox-0.3.7}/maltoolbox/language/compiler/__init__.py +0 -0
- {mal_toolbox-0.3.6 → mal_toolbox-0.3.7}/maltoolbox/language/compiler/mal_lexer.py +0 -0
- {mal_toolbox-0.3.6 → mal_toolbox-0.3.7}/maltoolbox/language/compiler/mal_parser.py +0 -0
- {mal_toolbox-0.3.6 → mal_toolbox-0.3.7}/maltoolbox/language/languagegraph.py +0 -0
- {mal_toolbox-0.3.6 → mal_toolbox-0.3.7}/maltoolbox/model.py +0 -0
- {mal_toolbox-0.3.6 → mal_toolbox-0.3.7}/maltoolbox/translators/__init__.py +0 -0
- {mal_toolbox-0.3.6 → mal_toolbox-0.3.7}/maltoolbox/translators/securicad.py +0 -0
- {mal_toolbox-0.3.6 → mal_toolbox-0.3.7}/maltoolbox/translators/updater.py +0 -0
- {mal_toolbox-0.3.6 → mal_toolbox-0.3.7}/setup.cfg +0 -0
- {mal_toolbox-0.3.6 → mal_toolbox-0.3.7}/tests/test_model.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: mal-toolbox
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.7
|
|
4
4
|
Summary: A collection of tools used to create MAL models and attack graphs.
|
|
5
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
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.2
|
|
2
2
|
Name: mal-toolbox
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.7
|
|
4
4
|
Summary: A collection of tools used to create MAL models and attack graphs.
|
|
5
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
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
|
2
|
-
# MAL Toolbox v0.3.
|
|
2
|
+
# MAL Toolbox v0.3.7
|
|
3
3
|
# Copyright 2025, Andrei Buhaiu.
|
|
4
4
|
#
|
|
5
5
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
@@ -21,7 +21,7 @@ MAL-Toolbox Framework
|
|
|
21
21
|
"""
|
|
22
22
|
|
|
23
23
|
__title__ = "maltoolbox"
|
|
24
|
-
__version__ = "0.3.
|
|
24
|
+
__version__ = "0.3.7"
|
|
25
25
|
__authors__ = [
|
|
26
26
|
"Andrei Buhaiu",
|
|
27
27
|
"Giuseppe Nebbione",
|
|
@@ -195,7 +195,7 @@ def prune_unviable_and_unnecessary_nodes(graph: AttackGraph) -> None:
|
|
|
195
195
|
|
|
196
196
|
def propagate_viability_from_unviable_node(
|
|
197
197
|
unviable_node: AttackGraphNode,
|
|
198
|
-
) ->
|
|
198
|
+
) -> set[AttackGraphNode]:
|
|
199
199
|
"""
|
|
200
200
|
Update viability of nodes affected by newly enabled defense
|
|
201
201
|
`unviable_node` in the graph and return any attack steps
|
|
@@ -207,12 +207,12 @@ def propagate_viability_from_unviable_node(
|
|
|
207
207
|
unviable_node - the node to propagate viability from
|
|
208
208
|
|
|
209
209
|
Returns:
|
|
210
|
-
attack_steps_made_unviable -
|
|
210
|
+
attack_steps_made_unviable - set of the attack steps that have been
|
|
211
211
|
made unviable by a defense enabled in the
|
|
212
212
|
current step. Builds up recursively.
|
|
213
213
|
"""
|
|
214
214
|
|
|
215
|
-
attack_steps_made_unviable =
|
|
215
|
+
attack_steps_made_unviable = set()
|
|
216
216
|
|
|
217
217
|
logger.debug(
|
|
218
218
|
'Update viability for node "%s"(%d)',
|
|
@@ -226,7 +226,7 @@ def propagate_viability_from_unviable_node(
|
|
|
226
226
|
)
|
|
227
227
|
|
|
228
228
|
if unviable_node.type in ('and', 'or'):
|
|
229
|
-
attack_steps_made_unviable.
|
|
229
|
+
attack_steps_made_unviable.add(unviable_node)
|
|
230
230
|
|
|
231
231
|
for child in unviable_node.children:
|
|
232
232
|
original_value = child.is_viable
|
|
@@ -238,7 +238,7 @@ def propagate_viability_from_unviable_node(
|
|
|
238
238
|
child.is_viable = False
|
|
239
239
|
|
|
240
240
|
if child.is_viable != original_value:
|
|
241
|
-
attack_steps_made_unviable
|
|
241
|
+
attack_steps_made_unviable |= \
|
|
242
242
|
propagate_viability_from_unviable_node(child)
|
|
243
243
|
|
|
244
244
|
return attack_steps_made_unviable
|
|
@@ -5,8 +5,9 @@ This submodule contains functions that analyze the information present in the
|
|
|
5
5
|
attack graph, but do not alter the structure or nodes in any way.
|
|
6
6
|
"""
|
|
7
7
|
from __future__ import annotations
|
|
8
|
+
from collections.abc import Iterable
|
|
8
9
|
import logging
|
|
9
|
-
from typing import TYPE_CHECKING
|
|
10
|
+
from typing import TYPE_CHECKING, Optional
|
|
10
11
|
|
|
11
12
|
from .attackgraph import AttackGraph, Attacker
|
|
12
13
|
|
|
@@ -113,25 +114,37 @@ def is_node_traversable_by_attacker(
|
|
|
113
114
|
)
|
|
114
115
|
return False
|
|
115
116
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
117
|
+
|
|
118
|
+
def calculate_attack_surface(
|
|
119
|
+
attacker: Attacker,
|
|
120
|
+
*,
|
|
121
|
+
from_nodes: Optional[Iterable[AttackGraphNode]] = None,
|
|
122
|
+
skip_compromised: bool = False,
|
|
123
|
+
) -> set[AttackGraphNode]:
|
|
119
124
|
"""
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
125
|
+
Calculate the attack surface of the attacker. If from_nodes are provided
|
|
126
|
+
only calculate the attack surface stemming from those nodes, otherwise use
|
|
127
|
+
all nodes the attacker has compromised. If skip_compromised is true,
|
|
128
|
+
exclude already compromised nodes from the returned attack surface.
|
|
129
|
+
|
|
130
|
+
The attack surface includes all of the viable children nodes that are of
|
|
131
|
+
'or' type and the 'and' type children nodes which have all of their
|
|
132
|
+
necessary parents compromised by the attacker.
|
|
124
133
|
|
|
125
134
|
Arguments:
|
|
126
|
-
attacker
|
|
135
|
+
attacker - the Attacker whose attack surface is sought
|
|
136
|
+
from_nodes - the nodes to calculate the attack surface from; defaults
|
|
137
|
+
to the attackers compromised nodes list if omitted
|
|
138
|
+
skip_compromised - if true do not add already compromised nodes to the
|
|
139
|
+
attack surface
|
|
127
140
|
"""
|
|
128
141
|
logger.debug(
|
|
129
142
|
'Get the attack surface for Attacker "%s"(%d).',
|
|
130
143
|
attacker.name,
|
|
131
144
|
attacker.id
|
|
132
145
|
)
|
|
133
|
-
attack_surface =
|
|
134
|
-
for attack_step in attacker.reached_attack_steps:
|
|
146
|
+
attack_surface = set()
|
|
147
|
+
for attack_step in from_nodes or attacker.reached_attack_steps:
|
|
135
148
|
logger.debug(
|
|
136
149
|
'Determine attack surface stemming from '
|
|
137
150
|
'"%s"(%d) for Attacker "%s"(%d).',
|
|
@@ -141,44 +154,10 @@ def get_attack_surface(
|
|
|
141
154
|
attacker.id
|
|
142
155
|
)
|
|
143
156
|
for child in attack_step.children:
|
|
157
|
+
if skip_compromised and child.is_compromised_by(attacker):
|
|
158
|
+
continue
|
|
144
159
|
if is_node_traversable_by_attacker(child, attacker) and \
|
|
145
160
|
child not in attack_surface:
|
|
146
|
-
attack_surface.append(child)
|
|
147
|
-
return attack_surface
|
|
148
|
-
|
|
149
|
-
def update_attack_surface_add_nodes(
|
|
150
|
-
attacker: Attacker,
|
|
151
|
-
current_attack_surface: list[AttackGraphNode],
|
|
152
|
-
nodes: list[AttackGraphNode]
|
|
153
|
-
) -> list[AttackGraphNode]:
|
|
154
|
-
"""
|
|
155
|
-
Update the attack surface of an attacker with the new attack step nodes
|
|
156
|
-
provided to see if any of their children can be added.
|
|
157
|
-
|
|
158
|
-
Arguments:
|
|
159
|
-
attacker - the Attacker whose attack surface is sought
|
|
160
|
-
current_attack_surface - the current attack surface that we wish to
|
|
161
|
-
expand
|
|
162
|
-
nodes - the newly compromised attack step nodes that we
|
|
163
|
-
wish to see if any of their children should be
|
|
164
|
-
added to the attack surface
|
|
165
|
-
"""
|
|
166
|
-
logger.debug('Update the attack surface for Attacker "%s"(%d).',
|
|
167
|
-
attacker.name,
|
|
168
|
-
attacker.id)
|
|
169
|
-
attack_surface = current_attack_surface
|
|
170
|
-
for attack_step in nodes:
|
|
171
|
-
logger.debug(
|
|
172
|
-
'Determine attack surface stemming from "%s"(%d) '
|
|
173
|
-
'for Attacker "%s"(%d).',
|
|
174
|
-
attack_step.full_name,
|
|
175
|
-
attack_step.id,
|
|
176
|
-
attacker.name,
|
|
177
|
-
attacker.id
|
|
178
|
-
)
|
|
179
|
-
for child in attack_step.children:
|
|
180
|
-
is_traversable = is_node_traversable_by_attacker(child, attacker)
|
|
181
|
-
if is_traversable and child not in attack_surface:
|
|
182
161
|
logger.debug(
|
|
183
162
|
'Add node "%s"(%d) to the attack surface of '
|
|
184
163
|
'Attacker "%s"(%d).',
|
|
@@ -187,10 +166,11 @@ def update_attack_surface_add_nodes(
|
|
|
187
166
|
attacker.name,
|
|
188
167
|
attacker.id
|
|
189
168
|
)
|
|
190
|
-
attack_surface.
|
|
169
|
+
attack_surface.add(child)
|
|
170
|
+
|
|
191
171
|
return attack_surface
|
|
192
172
|
|
|
193
|
-
def get_defense_surface(graph: AttackGraph) ->
|
|
173
|
+
def get_defense_surface(graph: AttackGraph) -> set[AttackGraphNode]:
|
|
194
174
|
"""
|
|
195
175
|
Get the defense surface. All non-suppressed defense steps that are not
|
|
196
176
|
already fully enabled.
|
|
@@ -199,8 +179,8 @@ def get_defense_surface(graph: AttackGraph) -> list[AttackGraphNode]:
|
|
|
199
179
|
graph - the attack graph
|
|
200
180
|
"""
|
|
201
181
|
logger.debug('Get the defense surface.')
|
|
202
|
-
return
|
|
203
|
-
if node.is_available_defense()
|
|
182
|
+
return {node for node in graph.nodes.values()
|
|
183
|
+
if node.is_available_defense()}
|
|
204
184
|
|
|
205
185
|
def get_enabled_defenses(graph: AttackGraph) -> list[AttackGraphNode]:
|
|
206
186
|
"""
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|