csle-attack-profiler 0.5.2__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.
Potentially problematic release.
This version of csle-attack-profiler might be problematic. Click here for more details.
- csle_attack_profiler-0.5.2/PKG-INFO +17 -0
- csle_attack_profiler-0.5.2/README.md +177 -0
- csle_attack_profiler-0.5.2/pyproject.toml +27 -0
- csle_attack_profiler-0.5.2/setup.cfg +74 -0
- csle_attack_profiler-0.5.2/setup.py +4 -0
- csle_attack_profiler-0.5.2/src/csle_attack_profiler/__init__.py +1 -0
- csle_attack_profiler-0.5.2/src/csle_attack_profiler/__version__.py +1 -0
- csle_attack_profiler-0.5.2/src/csle_attack_profiler/attack_profiler.py +204 -0
- csle_attack_profiler-0.5.2/src/csle_attack_profiler/hmm_profiling.py +449 -0
- csle_attack_profiler-0.5.2/src/csle_attack_profiler.egg-info/PKG-INFO +17 -0
- csle_attack_profiler-0.5.2/src/csle_attack_profiler.egg-info/SOURCES.txt +17 -0
- csle_attack_profiler-0.5.2/src/csle_attack_profiler.egg-info/dependency_links.txt +1 -0
- csle_attack_profiler-0.5.2/src/csle_attack_profiler.egg-info/not-zip-safe +1 -0
- csle_attack_profiler-0.5.2/src/csle_attack_profiler.egg-info/requires.txt +27 -0
- csle_attack_profiler-0.5.2/src/csle_attack_profiler.egg-info/top_level.txt +1 -0
- csle_attack_profiler-0.5.2/tests/test_attack_profiler.py +799 -0
- csle_attack_profiler-0.5.2/tests/test_hmm_profiler.py +71 -0
- csle_attack_profiler-0.5.2/tests/test_kullback.py +35 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: csle_attack_profiler
|
|
3
|
+
Version: 0.5.2
|
|
4
|
+
Summary: Library with MITRE attack profiler for CSLE
|
|
5
|
+
Author: Bength Pappila
|
|
6
|
+
Author-email: brpa@kth.se
|
|
7
|
+
License: Creative Commons Attribution-ShareAlike 4.0 International
|
|
8
|
+
Keywords: Reinforcement-Learning Cyber-Security Markov-Games Markov-Decision-Processes
|
|
9
|
+
Platform: unix
|
|
10
|
+
Platform: linux
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
15
|
+
Classifier: Intended Audience :: Science/Research
|
|
16
|
+
Requires-Python: >=3.8
|
|
17
|
+
Provides-Extra: testing
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
# `csle-attack-profiler`
|
|
2
|
+
|
|
3
|
+
Scripts and programs to profile attacks, attack sequences, and a probabilistic HMM profiler
|
|
4
|
+
using data from the csle platform, profiling attacks to MITRE ATT&CK techniques, and tactics.
|
|
5
|
+
|
|
6
|
+
[![PyPI version]] 0.5.1
|
|
7
|
+
![PyPI - Downloads] (https://pypi.org/project/csle-attack-profiler/)
|
|
8
|
+
|
|
9
|
+
## Requirements
|
|
10
|
+
|
|
11
|
+
- Python 3.8+
|
|
12
|
+
- `csle-common`
|
|
13
|
+
- `csle-base`
|
|
14
|
+
- `mitreattack-python`
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
## Development Requirement`
|
|
18
|
+
|
|
19
|
+
- Python 3.8+
|
|
20
|
+
- `flake8` (for linting)
|
|
21
|
+
- `flake8-rst-docstrings` (for linting docstrings)
|
|
22
|
+
- `tox` (for automated testing)
|
|
23
|
+
- `pytest` (for unit tests)
|
|
24
|
+
- `pytest-cov` (for unit test coverage)
|
|
25
|
+
- `mypy` (for static typing)
|
|
26
|
+
- `mypy-extensions` (for static typing)
|
|
27
|
+
- `mypy-protobuf` (for static typing)
|
|
28
|
+
- `types-PyYaml` (for static typing)
|
|
29
|
+
- `types-paramiko` (for static typing)
|
|
30
|
+
- `types-protobuf` (for static typing)
|
|
31
|
+
- `types-requests` (for static typing)
|
|
32
|
+
- `types-urllib3` (for static typing)
|
|
33
|
+
- `sphinx` (for API documentation)
|
|
34
|
+
- `sphinxcontrib-napoleon` (for API documentation)
|
|
35
|
+
- `sphinx-rtd-theme` (for API documentation)
|
|
36
|
+
- `pytest-mock` (for mocking tests)
|
|
37
|
+
- `pytest-grpc` (for grpc tests)
|
|
38
|
+
|
|
39
|
+
## Installation
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
# install from pip
|
|
43
|
+
pip install csle-attack-profiler==<version>
|
|
44
|
+
# local install from source
|
|
45
|
+
$ pip install -e csle-attack-profiler
|
|
46
|
+
# or (equivalently):
|
|
47
|
+
make install
|
|
48
|
+
# force upgrade deps
|
|
49
|
+
$ pip install -e csle-attack-profiler --upgrade
|
|
50
|
+
# git clone and install from source
|
|
51
|
+
git clone https://github.com/Limmen/csle
|
|
52
|
+
cd csle/simulation-system/libs/csle-attack-profiler
|
|
53
|
+
pip3 install -e .
|
|
54
|
+
# Install development dependencies
|
|
55
|
+
$ pip install -r requirements_dev.txt
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Development tools
|
|
59
|
+
|
|
60
|
+
Install all development tools at once:
|
|
61
|
+
```bash
|
|
62
|
+
make install_dev
|
|
63
|
+
```
|
|
64
|
+
or
|
|
65
|
+
```bash
|
|
66
|
+
pip install -r requirements_dev.txt
|
|
67
|
+
```
|
|
68
|
+
## API documentation
|
|
69
|
+
|
|
70
|
+
This section contains instructions for generating API documentation using `sphinx`.
|
|
71
|
+
|
|
72
|
+
### Latest Documentation
|
|
73
|
+
|
|
74
|
+
The latest documentation is available at [https://limmen.dev/csle/docs/csle-base](https://limmen.dev/csle/docs/csle-base)
|
|
75
|
+
|
|
76
|
+
### Generate API Documentation
|
|
77
|
+
|
|
78
|
+
First make sure that the `CSLE_HOME` environment variable is set:
|
|
79
|
+
```bash
|
|
80
|
+
echo $CSLE_HOME
|
|
81
|
+
```
|
|
82
|
+
Then generate the documentation with the commands:
|
|
83
|
+
```bash
|
|
84
|
+
cd docs
|
|
85
|
+
sphinx-apidoc -f -o source/ ../src/csle_attack_profiler/
|
|
86
|
+
make html
|
|
87
|
+
```
|
|
88
|
+
To update the official documentation at [https://limmen.dev/csle](https://limmen.dev/csle),
|
|
89
|
+
copy the generated HTML files to the documentation folder:
|
|
90
|
+
```bash
|
|
91
|
+
cp -r build/html ../../../../docs/_docs/csle-attack-profiler
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
To run all documentation commands at once, use the command:
|
|
95
|
+
```bash
|
|
96
|
+
make docs
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Static code analysis
|
|
100
|
+
|
|
101
|
+
To run the Python linter, execute the following command:
|
|
102
|
+
```
|
|
103
|
+
flake8 .
|
|
104
|
+
# or (equivalently):
|
|
105
|
+
make lint
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
To run the mypy type checker, execute the following command:
|
|
109
|
+
```
|
|
110
|
+
mypy .
|
|
111
|
+
# or (equivalently):
|
|
112
|
+
make types
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Unit tests
|
|
116
|
+
|
|
117
|
+
To run the unit tests, execute the following command:
|
|
118
|
+
```
|
|
119
|
+
pytest
|
|
120
|
+
# or (equivalently):
|
|
121
|
+
make unit_tests
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
To run tests of a specific test suite, execute the following command:
|
|
125
|
+
```
|
|
126
|
+
pytest -k "ClassName"
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
To generate a coverage report, execute the following command:
|
|
130
|
+
```
|
|
131
|
+
pytest --cov=csle_attack_profiler
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Run tests and code analysis in different python environments
|
|
135
|
+
|
|
136
|
+
To run tests and code analysis in different python environments, execute the following command:
|
|
137
|
+
|
|
138
|
+
```bash
|
|
139
|
+
tox
|
|
140
|
+
# or (equivalently):
|
|
141
|
+
make tests
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
## Create a new release and publish to PyPi
|
|
145
|
+
|
|
146
|
+
First build the package by executing:
|
|
147
|
+
```bash
|
|
148
|
+
python3 -m build
|
|
149
|
+
# or (equivalently)
|
|
150
|
+
make build
|
|
151
|
+
```
|
|
152
|
+
After running the command above, the built package is available at `./dist`.
|
|
153
|
+
|
|
154
|
+
Push the built package to PyPi by running:
|
|
155
|
+
```bash
|
|
156
|
+
python3 -m twine upload dist/*
|
|
157
|
+
# or (equivalently)
|
|
158
|
+
make push
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
To run all commands for the release at once, execute:
|
|
162
|
+
```bash
|
|
163
|
+
make release
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## Author & Maintainer
|
|
167
|
+
|
|
168
|
+
Bength Pappila <brpa@kth.se>
|
|
169
|
+
|
|
170
|
+
## Copyright and license
|
|
171
|
+
|
|
172
|
+
[LICENSE](LICENSE.md)
|
|
173
|
+
|
|
174
|
+
Creative Commons
|
|
175
|
+
|
|
176
|
+
(C) 2024, Bength Pappila
|
|
177
|
+
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools==68.0.0"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[tool.pytest.ini_options]
|
|
6
|
+
addopts = "--cov=csle_attack_profiler -p no:warnings"
|
|
7
|
+
testpaths = [
|
|
8
|
+
"tests",
|
|
9
|
+
]
|
|
10
|
+
log_cli = 1
|
|
11
|
+
log_cli_level = "INFO"
|
|
12
|
+
log_cli_format = "%(asctime)s [%(levelname)8s] %(message)s (%(filename)s:%(lineno)s)"
|
|
13
|
+
log_cli_date_format="%Y-%m-%d %H:%M:%S"
|
|
14
|
+
|
|
15
|
+
[tool.mypy]
|
|
16
|
+
mypy_path = "src"
|
|
17
|
+
check_untyped_defs = true
|
|
18
|
+
disallow_any_generics = true
|
|
19
|
+
ignore_missing_imports = true
|
|
20
|
+
no_implicit_optional = true
|
|
21
|
+
show_error_codes = true
|
|
22
|
+
strict_equality = true
|
|
23
|
+
warn_redundant_casts = true
|
|
24
|
+
warn_return_any = true
|
|
25
|
+
warn_unreachable = true
|
|
26
|
+
warn_unused_configs = true
|
|
27
|
+
no_implicit_reexport = true
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
[metadata]
|
|
2
|
+
name = csle_attack_profiler
|
|
3
|
+
version = attr: csle_attack_profiler.__version__
|
|
4
|
+
description = Library with MITRE attack profiler for CSLE
|
|
5
|
+
author = Bength Pappila
|
|
6
|
+
author_email = brpa@kth.se
|
|
7
|
+
license = Creative Commons Attribution-ShareAlike 4.0 International
|
|
8
|
+
keywords = Reinforcement-Learning Cyber-Security Markov-Games Markov-Decision-Processes
|
|
9
|
+
license_files =
|
|
10
|
+
- LICENSE.md
|
|
11
|
+
- README.md
|
|
12
|
+
platforms = unix, linux
|
|
13
|
+
classifiers =
|
|
14
|
+
Programming Language :: Python :: 3
|
|
15
|
+
Programming Language :: Python :: 3 :: Only
|
|
16
|
+
Programming Language :: Python :: 3.8
|
|
17
|
+
Programming Language :: Python :: 3.9
|
|
18
|
+
Intended Audience :: Science/Research
|
|
19
|
+
|
|
20
|
+
[options]
|
|
21
|
+
python_requires = >=3.8
|
|
22
|
+
package_dir =
|
|
23
|
+
=src
|
|
24
|
+
packages = find:
|
|
25
|
+
zip_safe = no
|
|
26
|
+
install_requires =
|
|
27
|
+
mitreattack-python==2.0.14
|
|
28
|
+
csle-base==0.5.2
|
|
29
|
+
csle-common==0.5.2
|
|
30
|
+
|
|
31
|
+
[options.packages.find]
|
|
32
|
+
where = src
|
|
33
|
+
|
|
34
|
+
[options.extras_require]
|
|
35
|
+
testing =
|
|
36
|
+
pytest>=6.0
|
|
37
|
+
pytest-cov>=2.0
|
|
38
|
+
pytest-mock>=3.6.0
|
|
39
|
+
grpcio>=1.57.0
|
|
40
|
+
grpcio-tools>=1.57.0
|
|
41
|
+
pytest-grpc>=0.8.0
|
|
42
|
+
mypy>=1.4.1
|
|
43
|
+
mypy-extensions>=1.0.0
|
|
44
|
+
mypy-protobuf>=3.5.0
|
|
45
|
+
types-PyYAML>=6.0.12.11
|
|
46
|
+
types-paramiko>=3.2.0.0
|
|
47
|
+
types-protobuf>=4.23.0.3
|
|
48
|
+
types-requests>=2.31.0.1
|
|
49
|
+
types-urllib3>=1.26.25.13
|
|
50
|
+
flake8>=6.1.0
|
|
51
|
+
flake8-rst-docstrings>=0.3.0
|
|
52
|
+
tox>=3.24
|
|
53
|
+
sphinx>=5.3.0
|
|
54
|
+
sphinxcontrib-napoleon>=0.7
|
|
55
|
+
sphinx-rtd-theme>=1.1.1
|
|
56
|
+
twine>=4.0.2
|
|
57
|
+
build>=0.10.0
|
|
58
|
+
|
|
59
|
+
[options.package_data]
|
|
60
|
+
csle_attack_profiler = py.typed
|
|
61
|
+
|
|
62
|
+
[flake8]
|
|
63
|
+
max-line-length = 120
|
|
64
|
+
exclude = .git,__pycache__,docs/source/conf.py,old,build,dist,*_pb2*,*init__*,.tox
|
|
65
|
+
ignore = E741, W503, W504, F821, W605
|
|
66
|
+
rst-roles = class, func, ref
|
|
67
|
+
rst-directives = envvar, exception
|
|
68
|
+
rst-substitutions = version
|
|
69
|
+
extend-ignore = D401, D400, D100, RST305, RST219, D205, D202, D200, D204, RST206, W293, D403, D402, RST306
|
|
70
|
+
|
|
71
|
+
[egg_info]
|
|
72
|
+
tag_build =
|
|
73
|
+
tag_date = 0
|
|
74
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from . __version__ import __version__
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = '0.5.2'
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
from csle_common.dao.emulation_action.attacker.emulation_attacker_action \
|
|
2
|
+
import EmulationAttackerAction
|
|
3
|
+
from csle_common.dao.emulation_action.attacker.emulation_attacker_action_id \
|
|
4
|
+
import EmulationAttackerActionId
|
|
5
|
+
from csle_attack_profiler.dao.tactics import Tactics
|
|
6
|
+
from csle_attack_profiler.dao.attack_mapping import EmulationAttackerMapping
|
|
7
|
+
from csle_attack_profiler.dao.attack_graph import AttackGraph
|
|
8
|
+
from mitreattack.stix20 import MitreAttackData
|
|
9
|
+
from typing import List, Dict, Union
|
|
10
|
+
import os
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class AttackProfiler:
|
|
14
|
+
"""
|
|
15
|
+
Class representing the attack profile based on the MITRE ATT&CK framework for Enterprise.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
def __init__(self, techniques_tactics: Dict[str, List[str]], mitigations: Dict[str, List[str]],
|
|
19
|
+
data_sources: Dict[str, List[str]], subtechniques: Dict[str, str],
|
|
20
|
+
action_id: EmulationAttackerActionId) -> None:
|
|
21
|
+
"""
|
|
22
|
+
Class constructor
|
|
23
|
+
|
|
24
|
+
:params techniques_tactics: the techniques and tactics used by the attacker action.
|
|
25
|
+
The key is the technique and the value is the tactics
|
|
26
|
+
:params mitigations: the mitigations used by the attacker action. The key is the technique and the
|
|
27
|
+
value is the mitigations
|
|
28
|
+
:params data_sources: the data sources used by the attacker action. The key is the technqiue and the value is
|
|
29
|
+
the data sources
|
|
30
|
+
:params sub_techniques: the sub-techniques used by the attacker action. The key is the technique and
|
|
31
|
+
the value is the sub-techniques
|
|
32
|
+
:params action_id: the id of the attacker action
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
self.techniques_tactics = techniques_tactics
|
|
36
|
+
self.mitigations = mitigations
|
|
37
|
+
self.data_sources = data_sources
|
|
38
|
+
self.subtechniques = subtechniques
|
|
39
|
+
self.action_id = action_id
|
|
40
|
+
|
|
41
|
+
@staticmethod
|
|
42
|
+
def get_attack_profile(attacker_action: EmulationAttackerAction) -> 'AttackProfiler':
|
|
43
|
+
"""
|
|
44
|
+
Returns the attack profile of the actions
|
|
45
|
+
|
|
46
|
+
:params attacker_action: the attacker action
|
|
47
|
+
:return: the attack profile of the action
|
|
48
|
+
"""
|
|
49
|
+
current_dir = os.path.dirname(__file__)
|
|
50
|
+
path = os.path.join(current_dir, "./dao/enterprise-attack.json")
|
|
51
|
+
mitre_attack_data = MitreAttackData(path)
|
|
52
|
+
|
|
53
|
+
# Retrieve the id from the attacker action
|
|
54
|
+
attacker_id = attacker_action.id
|
|
55
|
+
# Get the defined tactics and techniques for the attack
|
|
56
|
+
attack_mapping = EmulationAttackerMapping.get_attack_info(attacker_id)
|
|
57
|
+
if attack_mapping is None:
|
|
58
|
+
return AttackProfiler({}, {}, {}, {}, EmulationAttackerActionId.CONTINUE)
|
|
59
|
+
|
|
60
|
+
attack_techniques_vals = [technique.value for technique in attack_mapping['techniques']]
|
|
61
|
+
|
|
62
|
+
attacker_action_id = attacker_action.id
|
|
63
|
+
techniques_tactics = {}
|
|
64
|
+
mitigations = {}
|
|
65
|
+
data_sources = {}
|
|
66
|
+
sub_techniques = {}
|
|
67
|
+
# Loop over the techniques associated with the attack
|
|
68
|
+
for technique_name in attack_techniques_vals:
|
|
69
|
+
# Get technique from MitreAttackData, stix_id maps to technique in the library.
|
|
70
|
+
try:
|
|
71
|
+
obj = mitre_attack_data.get_objects_by_name(technique_name, "attack-pattern")
|
|
72
|
+
except Exception as e:
|
|
73
|
+
os.system("echo 'Error in getting technique: {}'".format(e))
|
|
74
|
+
continue
|
|
75
|
+
technique = obj[0]
|
|
76
|
+
stix_id = technique.id
|
|
77
|
+
|
|
78
|
+
# Collect the tactics and add it to the dictionary
|
|
79
|
+
tactics = [phase['phase_name'] for phase in technique.kill_chain_phases]
|
|
80
|
+
techniques_tactics[technique_name] = tactics
|
|
81
|
+
|
|
82
|
+
# Add the data sources to the dictionary
|
|
83
|
+
if hasattr(technique, 'x_mitre_data_sources'):
|
|
84
|
+
data_sources[technique_name] = technique.x_mitre_data_sources
|
|
85
|
+
# Fetch the mitigations from the technique and add it to the dictionary
|
|
86
|
+
try:
|
|
87
|
+
mitigations_object = mitre_attack_data.get_mitigations_mitigating_technique(stix_id)
|
|
88
|
+
mitigations_list = [mitig['object']['name'] for mitig in mitigations_object]
|
|
89
|
+
mitigations[technique_name] = mitigations_list
|
|
90
|
+
except Exception as e:
|
|
91
|
+
os.system("echo 'Error in getting mitigations: {}'".format(e))
|
|
92
|
+
continue
|
|
93
|
+
|
|
94
|
+
# Add the sub-technique to the dictionary
|
|
95
|
+
if 'subtechniques' in attack_mapping:
|
|
96
|
+
sub_techniques_mapping = [sub_technique.value for sub_technique in attack_mapping['subtechniques']]
|
|
97
|
+
for st in sub_techniques_mapping:
|
|
98
|
+
try:
|
|
99
|
+
sub_technique_obj = mitre_attack_data.get_objects_by_name(st, "attack-pattern")
|
|
100
|
+
parent_technique_obj = mitre_attack_data.get_parent_technique_of_subtechnique(
|
|
101
|
+
sub_technique_obj[0].id)
|
|
102
|
+
sub_techniques[parent_technique_obj[0]['object'].name] = st
|
|
103
|
+
except Exception as e:
|
|
104
|
+
os.system("echo 'Error in getting sub-techniques: {}'".format(e))
|
|
105
|
+
continue
|
|
106
|
+
|
|
107
|
+
return AttackProfiler(techniques_tactics, mitigations, data_sources, sub_techniques, attacker_action_id)
|
|
108
|
+
|
|
109
|
+
@staticmethod
|
|
110
|
+
def get_attack_profile_sequence(attacker_actions: List[EmulationAttackerAction],
|
|
111
|
+
attack_graph: Union[AttackGraph, None] = None) -> List['AttackProfiler']:
|
|
112
|
+
"""
|
|
113
|
+
Returns the attack profile of the actions in a sequence
|
|
114
|
+
|
|
115
|
+
:params attacker_action: a list of attacker actions
|
|
116
|
+
|
|
117
|
+
:return: a list of attack profiles of the actions
|
|
118
|
+
"""
|
|
119
|
+
|
|
120
|
+
attack_profiles = []
|
|
121
|
+
for action in attacker_actions:
|
|
122
|
+
attack_profiles.append(AttackProfiler.get_attack_profile(action))
|
|
123
|
+
|
|
124
|
+
# IF attack graph is provided
|
|
125
|
+
if attack_graph:
|
|
126
|
+
|
|
127
|
+
node = attack_graph.get_root_node()
|
|
128
|
+
for profile in attack_profiles:
|
|
129
|
+
# Get the mappings of the techniques and tactics
|
|
130
|
+
techniques_tactics = profile.techniques_tactics
|
|
131
|
+
techniques_to_keep = []
|
|
132
|
+
children = attack_graph.get_children(node[0], node[2])
|
|
133
|
+
possible_nodes = []
|
|
134
|
+
# First we check the techniques in node we are currently at
|
|
135
|
+
for technique in techniques_tactics:
|
|
136
|
+
# If the node.name is in the techniques_tactics, add it to the techniques_to_keep
|
|
137
|
+
if node[0].value in techniques_tactics[technique]:
|
|
138
|
+
techniques_to_keep.append(technique)
|
|
139
|
+
if node not in possible_nodes:
|
|
140
|
+
possible_nodes.append(node)
|
|
141
|
+
if children is None:
|
|
142
|
+
continue
|
|
143
|
+
for child in children:
|
|
144
|
+
# Child is a list of tuples, where the first element is the node name,
|
|
145
|
+
# and the second element is the node id
|
|
146
|
+
for technique in techniques_tactics:
|
|
147
|
+
if child[0].value in techniques_tactics[technique]:
|
|
148
|
+
|
|
149
|
+
techniques_to_keep.append(technique)
|
|
150
|
+
# If the child is not in the possible_children, add it to the list.
|
|
151
|
+
if attack_graph.get_node(child[0], child[1]) not in possible_nodes:
|
|
152
|
+
p_node = attack_graph.get_node(child[0], child[1])
|
|
153
|
+
if p_node is not None:
|
|
154
|
+
possible_nodes.append(p_node)
|
|
155
|
+
|
|
156
|
+
# If the possible node is just one node, move to that node
|
|
157
|
+
if len(possible_nodes) == 1:
|
|
158
|
+
node = possible_nodes[0]
|
|
159
|
+
if not techniques_to_keep:
|
|
160
|
+
continue
|
|
161
|
+
# Remove the techniques and associated tactics, data sources,
|
|
162
|
+
# mitigations and sub-techniques that are not in the techniques_to_keep
|
|
163
|
+
techniques_to_remove = set(profile.techniques_tactics.keys()) - set(techniques_to_keep)
|
|
164
|
+
for technique in techniques_to_remove:
|
|
165
|
+
try:
|
|
166
|
+
del profile.techniques_tactics[technique]
|
|
167
|
+
del profile.mitigations[technique]
|
|
168
|
+
del profile.data_sources[technique]
|
|
169
|
+
del profile.subtechniques[technique]
|
|
170
|
+
except Exception as e:
|
|
171
|
+
os.system("echo 'Error in removing techniques: {}'".format(e))
|
|
172
|
+
continue
|
|
173
|
+
|
|
174
|
+
# ELSE Baseline conditions
|
|
175
|
+
else:
|
|
176
|
+
initial_access = False
|
|
177
|
+
for profile in attack_profiles:
|
|
178
|
+
techniques_tactics = profile.techniques_tactics
|
|
179
|
+
techniques_to_remove = set()
|
|
180
|
+
# Loop over the mappings of the techniques to tactics
|
|
181
|
+
for technique in techniques_tactics:
|
|
182
|
+
if Tactics.DISCOVERY.value in techniques_tactics[technique] and not initial_access:
|
|
183
|
+
techniques_to_remove.add(technique)
|
|
184
|
+
elif Tactics.RECONNAISSANCE.value in techniques_tactics[technique] and initial_access:
|
|
185
|
+
techniques_to_remove.add(technique)
|
|
186
|
+
if Tactics.INITIAL_ACCESS.value in techniques_tactics[technique] and not initial_access:
|
|
187
|
+
initial_access = True
|
|
188
|
+
elif Tactics.INITIAL_ACCESS.value in techniques_tactics[technique] and initial_access:
|
|
189
|
+
techniques_to_remove.add(technique)
|
|
190
|
+
elif Tactics.LATERAL_MOVEMENT.value in techniques_tactics[technique] and not initial_access:
|
|
191
|
+
techniques_to_remove.add(technique)
|
|
192
|
+
|
|
193
|
+
# Remove the techniques and associated tactics, data sources, mitigations and sub-techniques
|
|
194
|
+
for technique in techniques_to_remove:
|
|
195
|
+
try:
|
|
196
|
+
del profile.techniques_tactics[technique]
|
|
197
|
+
del profile.mitigations[technique]
|
|
198
|
+
del profile.data_sources[technique]
|
|
199
|
+
del profile.subtechniques[technique]
|
|
200
|
+
except Exception as e:
|
|
201
|
+
os.system("echo 'Error in removing techniques: {}'".format(e))
|
|
202
|
+
continue
|
|
203
|
+
|
|
204
|
+
return attack_profiles
|