mal-toolbox 0.0.27__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.27.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.27.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 +99 -21
- maltoolbox/attackgraph/attackgraph.py +507 -217
- maltoolbox/attackgraph/node.py +143 -21
- maltoolbox/attackgraph/query.py +128 -26
- 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.27.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 -279
- {mal_toolbox-0.0.27.dist-info → mal_toolbox-0.1.12.dist-info}/AUTHORS +0 -0
- {mal_toolbox-0.0.27.dist-info → mal_toolbox-0.1.12.dist-info}/LICENSE +0 -0
- {mal_toolbox-0.0.27.dist-info → mal_toolbox-0.1.12.dist-info}/top_level.txt +0 -0
|
@@ -2,33 +2,69 @@
|
|
|
2
2
|
MAL-Toolbox Attack Graph Attacker Class
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
from dataclasses import dataclass, field
|
|
7
|
+
import copy
|
|
5
8
|
import logging
|
|
6
9
|
|
|
7
|
-
from
|
|
8
|
-
from typing import
|
|
10
|
+
from typing import Optional
|
|
11
|
+
from typing import TYPE_CHECKING
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from .attackgraph import AttackGraphNode
|
|
9
14
|
|
|
10
15
|
logger = logging.getLogger(__name__)
|
|
11
16
|
|
|
12
17
|
@dataclass
|
|
13
18
|
class Attacker:
|
|
14
|
-
|
|
15
|
-
entry_points:
|
|
16
|
-
reached_attack_steps:
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
"node": self.node.id
|
|
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
|
|
24
|
+
|
|
25
|
+
def to_dict(self) -> dict:
|
|
26
|
+
attacker_dict: dict = {
|
|
27
|
+
'id': self.id,
|
|
28
|
+
'name': self.name,
|
|
29
|
+
'entry_points': {},
|
|
30
|
+
'reached_attack_steps': {}
|
|
27
31
|
}
|
|
28
32
|
|
|
33
|
+
for entry_point in self.entry_points:
|
|
34
|
+
attacker_dict['entry_points'][entry_point.id] = \
|
|
35
|
+
entry_point.full_name
|
|
36
|
+
for attack_step in self.reached_attack_steps:
|
|
37
|
+
attacker_dict['reached_attack_steps'][attack_step.id] = \
|
|
38
|
+
attack_step.full_name
|
|
39
|
+
|
|
29
40
|
return attacker_dict
|
|
30
41
|
|
|
31
|
-
def
|
|
42
|
+
def __repr__(self) -> str:
|
|
43
|
+
return str(self.to_dict())
|
|
44
|
+
|
|
45
|
+
def __deepcopy__(self, memo) -> Attacker:
|
|
46
|
+
"""Deep copy an Attacker"""
|
|
47
|
+
|
|
48
|
+
# Check if the object is already in the memo dictionary
|
|
49
|
+
if id(self) in memo:
|
|
50
|
+
return memo[id(self)]
|
|
51
|
+
|
|
52
|
+
copied_attacker = Attacker(
|
|
53
|
+
id = self.id,
|
|
54
|
+
name = self.name,
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
# Remember that self was already copied
|
|
58
|
+
memo[id(self)] = copied_attacker
|
|
59
|
+
|
|
60
|
+
copied_attacker.entry_points = copy.deepcopy(
|
|
61
|
+
self.entry_points, memo = memo)
|
|
62
|
+
copied_attacker.reached_attack_steps = copy.deepcopy(
|
|
63
|
+
self.reached_attack_steps, memo = memo)
|
|
64
|
+
|
|
65
|
+
return copied_attacker
|
|
66
|
+
|
|
67
|
+
def compromise(self, node: AttackGraphNode) -> None:
|
|
32
68
|
"""
|
|
33
69
|
Have the attacke compromise the node given as a parameter.
|
|
34
70
|
|
|
@@ -36,12 +72,54 @@ class Attacker:
|
|
|
36
72
|
node - the node that the attacker will compromise
|
|
37
73
|
"""
|
|
38
74
|
|
|
39
|
-
logger.debug(
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
75
|
+
logger.debug(
|
|
76
|
+
'Attacker "%s"(%d) is compromising node "%s"(%d).',
|
|
77
|
+
self.name,
|
|
78
|
+
self.id,
|
|
79
|
+
node.full_name,
|
|
80
|
+
node.id
|
|
81
|
+
)
|
|
82
|
+
if node.is_compromised_by(self):
|
|
83
|
+
logger.info(
|
|
84
|
+
'Attacker "%s"(%d) already compromised node "%s"(%d). '
|
|
85
|
+
'Do nothing.',
|
|
86
|
+
self.name,
|
|
87
|
+
self.id,
|
|
88
|
+
node.full_name,
|
|
89
|
+
node.id
|
|
90
|
+
)
|
|
44
91
|
return
|
|
45
92
|
|
|
46
93
|
node.compromised_by.append(self)
|
|
47
94
|
self.reached_attack_steps.append(node)
|
|
95
|
+
|
|
96
|
+
def undo_compromise(self, node: AttackGraphNode) -> None:
|
|
97
|
+
"""
|
|
98
|
+
Remove the attacker from the list of attackers that have compromised
|
|
99
|
+
the node given as a parameter.
|
|
100
|
+
|
|
101
|
+
Arguments:
|
|
102
|
+
node - the node that we wish to remove this attacker from.
|
|
103
|
+
"""
|
|
104
|
+
|
|
105
|
+
logger.debug(
|
|
106
|
+
'Removing attacker "%s"(%d) from compromised_by '
|
|
107
|
+
'list of node "%s"(%d).',
|
|
108
|
+
self.name,
|
|
109
|
+
self.id,
|
|
110
|
+
node.full_name,
|
|
111
|
+
node.id
|
|
112
|
+
)
|
|
113
|
+
if not node.is_compromised_by(self):
|
|
114
|
+
logger.info(
|
|
115
|
+
'Attacker "%s"(%d) had not compromised node "%s"(%d).'
|
|
116
|
+
' Do nothing.',
|
|
117
|
+
self.name,
|
|
118
|
+
self.id,
|
|
119
|
+
node.full_name,
|
|
120
|
+
node.id
|
|
121
|
+
)
|
|
122
|
+
return
|
|
123
|
+
|
|
124
|
+
node.compromised_by.remove(self)
|
|
125
|
+
self.reached_attack_steps.remove(node)
|