From 554a180fbd18305beb417b1812e70ce1e124f083 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Mon, 29 Aug 2022 13:24:13 +0530 Subject: [PATCH 01/69] Common: Create CustomPBAConfiguration using pydantic --- .../agent_sub_configurations.py | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/monkey/common/agent_configuration/agent_sub_configurations.py b/monkey/common/agent_configuration/agent_sub_configurations.py index 4ed94d7a8..be1c9ca87 100644 --- a/monkey/common/agent_configuration/agent_sub_configurations.py +++ b/monkey/common/agent_configuration/agent_sub_configurations.py @@ -1,6 +1,12 @@ from dataclasses import dataclass from typing import Dict, Tuple +from pydantic import validator + +from common.base_models import MutableInfectionMonkeyBaseModel + +from .validators import validate_linux_filename, validate_windows_filename + @dataclass(frozen=True) class CustomPBAConfiguration: @@ -25,6 +31,38 @@ class CustomPBAConfiguration: windows_filename: str +class Pydantic___CustomPBAConfiguration(MutableInfectionMonkeyBaseModel): + """ + A configuration for custom post-breach actions + + Attributes: + :param linux_command: Command to run on Linux victim machines. If a file is uploaded, + use this field to change its permissions, execute it, and/or delete it + Example: `chmod +x file.sh; ./file.sh; rm file.sh` + :param linux_filename: Name of the file to upload on Linux victim machines + :param windows_command: Command to run on Windows victim machines. If a file is uploaded, + use this field to change its permissions, execute it, and/or delete + it + Example: `file.bat & del file.bat` + :param windows_filename: Name of the file to upload on Windows victim machines + """ + + linux_command: str + linux_filename: str + windows_command: str + windows_filename: str + + @validator("linux_filename") + def linux_filename_valid(cls, filename): + validate_linux_filename(filename) + return filename + + @validator("windows_filename") + def windows_filename_valid(cls, filename): + validate_windows_filename(filename) + return filename + + @dataclass(frozen=True) class PluginConfiguration: """ From 520183f42d6e785c8955337f70853a20c1e87a0f Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Mon, 29 Aug 2022 13:28:50 +0530 Subject: [PATCH 02/69] Common: Create PluginConfiguration using pydantic --- .../agent_sub_configurations.py | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/monkey/common/agent_configuration/agent_sub_configurations.py b/monkey/common/agent_configuration/agent_sub_configurations.py index be1c9ca87..a01767227 100644 --- a/monkey/common/agent_configuration/agent_sub_configurations.py +++ b/monkey/common/agent_configuration/agent_sub_configurations.py @@ -90,6 +90,32 @@ class PluginConfiguration: options: Dict +class Pydantic___PluginConfiguration(MutableInfectionMonkeyBaseModel): + """ + A configuration for plugins + + Attributes: + :param name: Name of the plugin + Example: "ransomware" + :param options: Any other information/configuration fields relevant to the plugin + Example: { + "encryption": { + "enabled": True, + "directories": { + "linux_target_dir": "~/this_dir", + "windows_target_dir": "C:\that_dir" + }, + }, + "other_behaviors": { + "readme": True + }, + } + """ + + name: str + options: Dict + + @dataclass(frozen=True) class ScanTargetConfiguration: """ From e7b0e6babf7c885b875a3af78267e20de58baecb Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Mon, 29 Aug 2022 13:43:43 +0530 Subject: [PATCH 03/69] Common: Create ScanTargetConfiguration using pydantic --- .../agent_sub_configurations.py | 46 ++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/monkey/common/agent_configuration/agent_sub_configurations.py b/monkey/common/agent_configuration/agent_sub_configurations.py index a01767227..c8eb5ec64 100644 --- a/monkey/common/agent_configuration/agent_sub_configurations.py +++ b/monkey/common/agent_configuration/agent_sub_configurations.py @@ -5,7 +5,15 @@ from pydantic import validator from common.base_models import MutableInfectionMonkeyBaseModel -from .validators import validate_linux_filename, validate_windows_filename +from .validators import ( + validate_hostname, + validate_ip, + validate_ip_network, + validate_ip_range, + validate_linux_filename, + validate_subnet_range, + validate_windows_filename, +) @dataclass(frozen=True) @@ -138,6 +146,42 @@ class ScanTargetConfiguration: subnets: Tuple[str, ...] +class Pydantic___ScanTargetConfiguration(MutableInfectionMonkeyBaseModel): + """ + Configuration of network targets to scan and exploit + + Attributes: + :param blocked_ips: IP's that won't be scanned + Example: ("1.1.1.1", "2.2.2.2") + :param inaccessible_subnets: Subnet ranges that shouldn't be accessible for the agent + Example: ("1.1.1.1", "2.2.2.2/24", "myserver") + :param local_network_scan: Whether or not the agent should scan the local network + :param subnets: Subnet ranges to scan + Example: ("192.168.1.1-192.168.2.255", "3.3.3.3", "2.2.2.2/24", + "myHostname") + """ + + blocked_ips: Tuple[str, ...] + inaccessible_subnets: Tuple[str, ...] + local_network_scan: bool + subnets: Tuple[str, ...] + + @validator("blocked_ips", each_item=True) + def blocked_ips_valid(cls, ip): + validate_ip(ip) + return ip + + @validator("inaccessible_subnets", each_item=True) + def inaccessible_subnets_valid(cls, subnet_range): + validate_subnet_range(subnet_range) + return subnet_range + + @validator("subnets", each_item=True) + def subnets_valid(cls, subnet_range): + validate_subnet_range(subnet_range) + return subnet_range + + @dataclass(frozen=True) class ICMPScanConfiguration: """ From 858b7650acf6160338c15c29e749f73251e23f0d Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Mon, 29 Aug 2022 13:45:25 +0530 Subject: [PATCH 04/69] Common: Create ICMPScanConfiguration using pydantic --- .../agent_configuration/agent_sub_configurations.py | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/monkey/common/agent_configuration/agent_sub_configurations.py b/monkey/common/agent_configuration/agent_sub_configurations.py index c8eb5ec64..7dbed4d41 100644 --- a/monkey/common/agent_configuration/agent_sub_configurations.py +++ b/monkey/common/agent_configuration/agent_sub_configurations.py @@ -1,7 +1,7 @@ from dataclasses import dataclass from typing import Dict, Tuple -from pydantic import validator +from pydantic import PositiveFloat, validator from common.base_models import MutableInfectionMonkeyBaseModel @@ -194,6 +194,17 @@ class ICMPScanConfiguration: timeout: float +class Pydantic___ICMPScanConfiguration(MutableInfectionMonkeyBaseModel): + """ + A configuration for ICMP scanning + + Attributes: + :param timeout: Maximum time in seconds to wait for a response from the target + """ + + timeout: PositiveFloat + + @dataclass(frozen=True) class TCPScanConfiguration: """ From 63a8e81c74180e05138dd227a00f082981a03c65 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Mon, 29 Aug 2022 13:50:24 +0530 Subject: [PATCH 05/69] Common: Create TCPScanConfiguration using pydantic --- .../agent_sub_configurations.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/monkey/common/agent_configuration/agent_sub_configurations.py b/monkey/common/agent_configuration/agent_sub_configurations.py index 7dbed4d41..bd40f984e 100644 --- a/monkey/common/agent_configuration/agent_sub_configurations.py +++ b/monkey/common/agent_configuration/agent_sub_configurations.py @@ -1,7 +1,7 @@ from dataclasses import dataclass from typing import Dict, Tuple -from pydantic import PositiveFloat, validator +from pydantic import PositiveFloat, conint, validator from common.base_models import MutableInfectionMonkeyBaseModel @@ -219,6 +219,19 @@ class TCPScanConfiguration: ports: Tuple[int, ...] +class Pydantic___TCPScanConfiguration(MutableInfectionMonkeyBaseModel): + """ + A configuration for TCP scanning + + Attributes: + :param timeout: Maximum time in seconds to wait for a response from the target + :param ports: Ports to scan + """ + + timeout: PositiveFloat + ports: Tuple[conint(ge=0, le=65535), ...] + + @dataclass(frozen=True) class NetworkScanConfiguration: """ From 153c3e9b9f191c03e6f076a6532b3bba0989c4f9 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Mon, 29 Aug 2022 13:52:08 +0530 Subject: [PATCH 06/69] Common: Create NetworkScanConfiguration using pydantic --- .../agent_sub_configurations.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/monkey/common/agent_configuration/agent_sub_configurations.py b/monkey/common/agent_configuration/agent_sub_configurations.py index bd40f984e..92abb07c5 100644 --- a/monkey/common/agent_configuration/agent_sub_configurations.py +++ b/monkey/common/agent_configuration/agent_sub_configurations.py @@ -250,6 +250,23 @@ class NetworkScanConfiguration: targets: ScanTargetConfiguration +class Pydantic___NetworkScanConfiguration(MutableInfectionMonkeyBaseModel): + """ + A configuration for network scanning + + Attributes: + :param tcp: Configuration for TCP scanning + :param icmp: Configuration for ICMP scanning + :param fingerprinters: Configuration for fingerprinters to run + :param targets: Configuration for targets to scan + """ + + tcp: Pydantic___TCPScanConfiguration + icmp: Pydantic___ICMPScanConfiguration + fingerprinters: Tuple[Pydantic___PluginConfiguration, ...] + targets: Pydantic___ScanTargetConfiguration + + @dataclass(frozen=True) class ExploitationOptionsConfiguration: """ From b74f90fe9b406bceaa89251f80bee41a54c2fdd6 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Mon, 29 Aug 2022 13:53:01 +0530 Subject: [PATCH 07/69] Common: Create ExploitationOptionsConfiguration using pydantic --- .../agent_configuration/agent_sub_configurations.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/monkey/common/agent_configuration/agent_sub_configurations.py b/monkey/common/agent_configuration/agent_sub_configurations.py index 92abb07c5..65c60652a 100644 --- a/monkey/common/agent_configuration/agent_sub_configurations.py +++ b/monkey/common/agent_configuration/agent_sub_configurations.py @@ -279,6 +279,17 @@ class ExploitationOptionsConfiguration: http_ports: Tuple[int, ...] +class Pydantic___ExploitationOptionsConfiguration: + """ + A configuration for exploitation options + + Attributes: + :param http_ports: HTTP ports to exploit + """ + + http_ports: Tuple[conint(ge=0, le=65535), ...] + + @dataclass(frozen=True) class ExploitationConfiguration: """ From 602604e408ff60eef8642df54bcd11a69642ad7f Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Mon, 29 Aug 2022 13:54:32 +0530 Subject: [PATCH 08/69] Common: Create ExploitationConfiguration using pydantic --- .../agent_sub_configurations.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/monkey/common/agent_configuration/agent_sub_configurations.py b/monkey/common/agent_configuration/agent_sub_configurations.py index 65c60652a..11e4b7b78 100644 --- a/monkey/common/agent_configuration/agent_sub_configurations.py +++ b/monkey/common/agent_configuration/agent_sub_configurations.py @@ -306,6 +306,21 @@ class ExploitationConfiguration: vulnerability: Tuple[PluginConfiguration, ...] +class Pydantic___ExploitationConfiguration: + """ + A configuration for exploitation + + Attributes: + :param options: Exploitation options shared by all exploiters + :param brute_force: Configuration for brute force exploiters + :param vulnerability: Configuration for vulnerability exploiters + """ + + options: Pydantic___ExploitationOptionsConfiguration + brute_force: Tuple[Pydantic___PluginConfiguration, ...] + vulnerability: Tuple[Pydantic___PluginConfiguration, ...] + + @dataclass(frozen=True) class PropagationConfiguration: """ From 501f75224829fc60cc8665dc6e1798f1514362af Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Mon, 29 Aug 2022 13:55:49 +0530 Subject: [PATCH 09/69] Common: Create PropagationConfiguration using pydantic --- .../agent_sub_configurations.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/monkey/common/agent_configuration/agent_sub_configurations.py b/monkey/common/agent_configuration/agent_sub_configurations.py index 11e4b7b78..9091058da 100644 --- a/monkey/common/agent_configuration/agent_sub_configurations.py +++ b/monkey/common/agent_configuration/agent_sub_configurations.py @@ -1,7 +1,7 @@ from dataclasses import dataclass from typing import Dict, Tuple -from pydantic import PositiveFloat, conint, validator +from pydantic import PositiveFloat, PositiveInt, conint, validator from common.base_models import MutableInfectionMonkeyBaseModel @@ -337,3 +337,20 @@ class PropagationConfiguration: maximum_depth: int network_scan: NetworkScanConfiguration exploitation: ExploitationConfiguration + + +class Pydantic___PropagationConfiguration: + """ + A configuration for propagation + + Attributes: + :param maximum_depth: Maximum number of hops allowed to spread from the machine where + the attack started i.e. how far to propagate in the network from the + first machine + :param network_scan: Configuration for network scanning + :param exploitation: Configuration for exploitation + """ + + maximum_depth: PositiveInt + network_scan: Pydantic___NetworkScanConfiguration + exploitation: Pydantic___ExploitationConfiguration From b8914101a6affa6ee042b43f4fea4cd9d502a2cb Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Mon, 29 Aug 2022 13:56:35 +0530 Subject: [PATCH 10/69] Common: Remove unused imports in agent_sub_configurations.py --- monkey/common/agent_configuration/agent_sub_configurations.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/monkey/common/agent_configuration/agent_sub_configurations.py b/monkey/common/agent_configuration/agent_sub_configurations.py index 9091058da..f276de794 100644 --- a/monkey/common/agent_configuration/agent_sub_configurations.py +++ b/monkey/common/agent_configuration/agent_sub_configurations.py @@ -6,10 +6,7 @@ from pydantic import PositiveFloat, PositiveInt, conint, validator from common.base_models import MutableInfectionMonkeyBaseModel from .validators import ( - validate_hostname, validate_ip, - validate_ip_network, - validate_ip_range, validate_linux_filename, validate_subnet_range, validate_windows_filename, From 2f05d22780d8eb3284fda492b373f699fcf14a63 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Mon, 29 Aug 2022 13:58:44 +0530 Subject: [PATCH 11/69] Common: Create AgentConfiguration using pydantic --- .../agent_configuration/agent_configuration.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/monkey/common/agent_configuration/agent_configuration.py b/monkey/common/agent_configuration/agent_configuration.py index cfd685d0f..84782bef2 100644 --- a/monkey/common/agent_configuration/agent_configuration.py +++ b/monkey/common/agent_configuration/agent_configuration.py @@ -5,6 +5,9 @@ from typing import Any, Mapping, Tuple from marshmallow import Schema, fields, validate from marshmallow.exceptions import MarshmallowError +from pydantic import PositiveFloat + +from common.base_models import MutableInfectionMonkeyBaseModel from ..utils.code_utils import freeze_lists_in_mapping from .agent_sub_configuration_schemas import ( @@ -16,6 +19,9 @@ from .agent_sub_configurations import ( CustomPBAConfiguration, PluginConfiguration, PropagationConfiguration, + Pydantic___CustomPBAConfiguration, + Pydantic___PluginConfiguration, + Pydantic___PropagationConfiguration, ) @@ -123,3 +129,12 @@ class AgentConfigurationSchema(Schema): credential_collectors = fields.List(fields.Nested(PluginConfigurationSchema)) payloads = fields.List(fields.Nested(PluginConfigurationSchema)) propagation = fields.Nested(PropagationConfigurationSchema) + + +class Pydantic___AgentConfiguration(MutableInfectionMonkeyBaseModel): + keep_tunnel_open_time: PositiveFloat + custom_pbas: Pydantic___CustomPBAConfiguration + post_breach_actions: Tuple[Pydantic___PluginConfiguration, ...] + credential_collectors: Tuple[Pydantic___PluginConfiguration, ...] + payloads: Tuple[Pydantic___PluginConfiguration, ...] + propagation: Pydantic___PropagationConfiguration From 275237c3f7bc74fb2afdce1fdee0b8402c48d232 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Mon, 29 Aug 2022 14:03:32 +0530 Subject: [PATCH 12/69] Common: Inherit from MutableInfectionMonkeyBaseModel where missing in new pydantic configurations --- .../common/agent_configuration/agent_sub_configurations.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/monkey/common/agent_configuration/agent_sub_configurations.py b/monkey/common/agent_configuration/agent_sub_configurations.py index f276de794..14af14c88 100644 --- a/monkey/common/agent_configuration/agent_sub_configurations.py +++ b/monkey/common/agent_configuration/agent_sub_configurations.py @@ -276,7 +276,7 @@ class ExploitationOptionsConfiguration: http_ports: Tuple[int, ...] -class Pydantic___ExploitationOptionsConfiguration: +class Pydantic___ExploitationOptionsConfiguration(MutableInfectionMonkeyBaseModel): """ A configuration for exploitation options @@ -303,7 +303,7 @@ class ExploitationConfiguration: vulnerability: Tuple[PluginConfiguration, ...] -class Pydantic___ExploitationConfiguration: +class Pydantic___ExploitationConfiguration(MutableInfectionMonkeyBaseModel): """ A configuration for exploitation @@ -336,7 +336,7 @@ class PropagationConfiguration: exploitation: ExploitationConfiguration -class Pydantic___PropagationConfiguration: +class Pydantic___PropagationConfiguration(MutableInfectionMonkeyBaseModel): """ A configuration for propagation From 6d29829808d69229439f4fffdd6876af4819e917 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Mon, 29 Aug 2022 14:19:25 +0530 Subject: [PATCH 13/69] UT: Modify tests to use new pydantic configurations TODO: Fix error handling and some assertions (tuple/list stuff) --- .../test_agent_configuration.py | 166 +++++------------- 1 file changed, 47 insertions(+), 119 deletions(-) diff --git a/monkey/tests/unit_tests/common/agent_configuration/test_agent_configuration.py b/monkey/tests/unit_tests/common/agent_configuration/test_agent_configuration.py index 22a09b87b..883b5f6d2 100644 --- a/monkey/tests/unit_tests/common/agent_configuration/test_agent_configuration.py +++ b/monkey/tests/unit_tests/common/agent_configuration/test_agent_configuration.py @@ -1,6 +1,3 @@ -import json -from copy import deepcopy - import pytest from marshmallow import ValidationError from tests.common.example_agent_configuration import ( @@ -28,42 +25,32 @@ from tests.common.example_agent_configuration import ( WINDOWS_FILENAME, ) -from common.agent_configuration import AgentConfiguration, InvalidConfigurationError -from common.agent_configuration.agent_sub_configuration_schemas import ( - CustomPBAConfigurationSchema, - ExploitationConfigurationSchema, - ExploitationOptionsConfigurationSchema, - ICMPScanConfigurationSchema, - NetworkScanConfigurationSchema, - PluginConfigurationSchema, - PropagationConfigurationSchema, - ScanTargetConfigurationSchema, - TCPScanConfigurationSchema, -) +from common.agent_configuration import InvalidConfigurationError +from common.agent_configuration.agent_configuration import Pydantic___AgentConfiguration from common.agent_configuration.agent_sub_configurations import ( - CustomPBAConfiguration, - ExploitationConfiguration, - NetworkScanConfiguration, - PluginConfiguration, - PropagationConfiguration, + Pydantic___CustomPBAConfiguration, + Pydantic___ExploitationConfiguration, + Pydantic___ExploitationOptionsConfiguration, + Pydantic___ICMPScanConfiguration, + Pydantic___NetworkScanConfiguration, + Pydantic___PluginConfiguration, + Pydantic___PropagationConfiguration, + Pydantic___ScanTargetConfiguration, + Pydantic___TCPScanConfiguration, ) INVALID_PORTS = [[-1, 1, 2], [1, 2, 99999]] def test_build_plugin_configuration(): - schema = PluginConfigurationSchema() - - config = schema.load(PLUGIN_CONFIGURATION) + config = Pydantic___PluginConfiguration(**PLUGIN_CONFIGURATION) assert config.name == PLUGIN_NAME assert config.options == PLUGIN_OPTIONS def test_custom_pba_configuration_schema(): - schema = CustomPBAConfigurationSchema() - - config = schema.load(CUSTOM_PBA_CONFIGURATION) + config = Pydantic___CustomPBAConfiguration(**CUSTOM_PBA_CONFIGURATION) assert config.linux_command == LINUX_COMMAND assert config.linux_filename == LINUX_FILENAME @@ -72,12 +59,10 @@ def test_custom_pba_configuration_schema(): def test_custom_pba_configuration_schema__empty_filenames_allowed(): - schema = CustomPBAConfigurationSchema() - empty_filename_configuration = CUSTOM_PBA_CONFIGURATION.copy() empty_filename_configuration.update({"linux_filename": "", "windows_filename": ""}) - config = schema.load(empty_filename_configuration) + config = Pydantic___CustomPBAConfiguration(**empty_filename_configuration) assert config.linux_command == LINUX_COMMAND assert config.linux_filename == "" @@ -87,32 +72,26 @@ def test_custom_pba_configuration_schema__empty_filenames_allowed(): @pytest.mark.parametrize("linux_filename", ["/", "/abc/", "\0"]) def test_custom_pba_configuration_schema__invalid_linux_filename(linux_filename): - schema = CustomPBAConfigurationSchema() - invalid_filename_configuration = CUSTOM_PBA_CONFIGURATION.copy() invalid_filename_configuration["linux_filename"] = linux_filename with pytest.raises(ValidationError): - schema.load(invalid_filename_configuration) + Pydantic___CustomPBAConfiguration(**invalid_filename_configuration) @pytest.mark.parametrize( "windows_filename", ["CON", "CON.txt", "con.abc.pdf", " ", "abc.", "a?b", "d\\e"] ) def test_custom_pba_configuration_schema__invalid_windows_filename(windows_filename): - schema = CustomPBAConfigurationSchema() - invalid_filename_configuration = CUSTOM_PBA_CONFIGURATION.copy() invalid_filename_configuration["windows_filename"] = windows_filename with pytest.raises(ValidationError): - schema.load(invalid_filename_configuration) + Pydantic___CustomPBAConfiguration(**invalid_filename_configuration) def test_scan_target_configuration(): - schema = ScanTargetConfigurationSchema() - - config = schema.load(SCAN_TARGET_CONFIGURATION) + config = Pydantic___ScanTargetConfiguration(**SCAN_TARGET_CONFIGURATION) assert config.blocked_ips == tuple(BLOCKED_IPS) assert config.inaccessible_subnets == tuple(INACCESSIBLE_SUBNETS) @@ -121,27 +100,21 @@ def test_scan_target_configuration(): def test_icmp_scan_configuration_schema(): - schema = ICMPScanConfigurationSchema() - - config = schema.load(ICMP_CONFIGURATION) + config = Pydantic___ICMPScanConfiguration(**ICMP_CONFIGURATION) assert config.timeout == TIMEOUT def test_icmp_scan_configuration_schema__negative_timeout(): - schema = ICMPScanConfigurationSchema() - negative_timeout_configuration = ICMP_CONFIGURATION.copy() negative_timeout_configuration["timeout"] = -1 with pytest.raises(ValidationError): - schema.load(negative_timeout_configuration) + Pydantic___ICMPScanConfiguration(**negative_timeout_configuration) def test_tcp_scan_configuration_schema(): - schema = TCPScanConfigurationSchema() - - config = schema.load(TCP_SCAN_CONFIGURATION) + config = Pydantic___TCPScanConfiguration(**TCP_SCAN_CONFIGURATION) assert config.timeout == TIMEOUT assert config.ports == tuple(PORTS) @@ -149,29 +122,23 @@ def test_tcp_scan_configuration_schema(): @pytest.mark.parametrize("ports", INVALID_PORTS) def test_tcp_scan_configuration_schema__ports_out_of_range(ports): - schema = TCPScanConfigurationSchema() - invalid_ports_configuration = TCP_SCAN_CONFIGURATION.copy() invalid_ports_configuration["ports"] = ports with pytest.raises(ValidationError): - schema.load(invalid_ports_configuration) + Pydantic___TCPScanConfiguration(**invalid_ports_configuration) def test_tcp_scan_configuration_schema__negative_timeout(): - schema = TCPScanConfigurationSchema() - negative_timeout_configuration = TCP_SCAN_CONFIGURATION.copy() negative_timeout_configuration["timeout"] = -1 with pytest.raises(ValidationError): - schema.load(negative_timeout_configuration) + Pydantic___TCPScanConfiguration(**negative_timeout_configuration) def test_network_scan_configuration(): - schema = NetworkScanConfigurationSchema() - - config = schema.load(NETWORK_SCAN_CONFIGURATION) + config = Pydantic___NetworkScanConfiguration(**NETWORK_SCAN_CONFIGURATION) assert config.tcp.ports == tuple(TCP_SCAN_CONFIGURATION["ports"]) assert config.tcp.timeout == TCP_SCAN_CONFIGURATION["timeout"] @@ -186,79 +153,69 @@ def test_network_scan_configuration(): def test_exploitation_options_configuration_schema(): ports = [1, 2, 3] - schema = ExploitationOptionsConfigurationSchema() - config = schema.load({"http_ports": ports}) + config = Pydantic___ExploitationOptionsConfiguration(**{"http_ports": ports}) assert config.http_ports == tuple(ports) @pytest.mark.parametrize("ports", INVALID_PORTS) def test_exploitation_options_configuration_schema__ports_out_of_range(ports): - schema = ExploitationOptionsConfigurationSchema() - invalid_ports_configuration = {"http_ports": ports} with pytest.raises(ValidationError): - schema.load(invalid_ports_configuration) + Pydantic___ExploitationOptionsConfiguration(**invalid_ports_configuration) def test_exploiter_configuration_schema(): name = "bond" options = {"gun": "Walther PPK", "car": "Aston Martin DB5"} - schema = PluginConfigurationSchema() - config = schema.load({"name": name, "options": options}) + config = Pydantic___PluginConfiguration(**{"name": name, "options": options}) assert config.name == name assert config.options == options def test_exploitation_configuration(): - schema = ExploitationConfigurationSchema() + config = Pydantic___ExploitationConfiguration(**EXPLOITATION_CONFIGURATION) + config_dict = config.dict() - config = schema.load(EXPLOITATION_CONFIGURATION) - config_dict = schema.dump(config) - - assert isinstance(config, ExploitationConfiguration) + assert isinstance(config, Pydantic___ExploitationConfiguration) assert config_dict == EXPLOITATION_CONFIGURATION def test_propagation_configuration(): - schema = PropagationConfigurationSchema() + config = Pydantic___PropagationConfiguration(**PROPAGATION_CONFIGURATION) + config_dict = config.dict() - config = schema.load(PROPAGATION_CONFIGURATION) - config_dict = schema.dump(config) - - assert isinstance(config, PropagationConfiguration) - assert isinstance(config.network_scan, NetworkScanConfiguration) - assert isinstance(config.exploitation, ExploitationConfiguration) + assert isinstance(config, Pydantic___PropagationConfiguration) + assert isinstance(config.network_scan, Pydantic___NetworkScanConfiguration) + assert isinstance(config.exploitation, Pydantic___ExploitationConfiguration) assert config.maximum_depth == 5 assert config_dict == PROPAGATION_CONFIGURATION def test_propagation_configuration__invalid_maximum_depth(): - schema = PropagationConfigurationSchema() - negative_maximum_depth_configuration = PROPAGATION_CONFIGURATION.copy() negative_maximum_depth_configuration["maximum_depth"] = -1 with pytest.raises(ValidationError): - schema.load(negative_maximum_depth_configuration) + Pydantic___PropagationConfiguration(**negative_maximum_depth_configuration) def test_agent_configuration(): - config = AgentConfiguration.from_mapping(AGENT_CONFIGURATION) - config_json = AgentConfiguration.to_json(config) + config = Pydantic___AgentConfiguration(**AGENT_CONFIGURATION) + config_dict = config.dict() - assert isinstance(config, AgentConfiguration) + assert isinstance(config, Pydantic___AgentConfiguration) assert config.keep_tunnel_open_time == 30 - assert isinstance(config.custom_pbas, CustomPBAConfiguration) - assert isinstance(config.post_breach_actions[0], PluginConfiguration) - assert isinstance(config.credential_collectors[0], PluginConfiguration) - assert isinstance(config.payloads[0], PluginConfiguration) - assert isinstance(config.propagation, PropagationConfiguration) - assert json.loads(config_json) == AGENT_CONFIGURATION + assert isinstance(config.custom_pbas, Pydantic___CustomPBAConfiguration) + assert isinstance(config.post_breach_actions[0], Pydantic___PluginConfiguration) + assert isinstance(config.credential_collectors[0], Pydantic___PluginConfiguration) + assert isinstance(config.payloads[0], Pydantic___PluginConfiguration) + assert isinstance(config.propagation, Pydantic___PropagationConfiguration) + assert config_dict == AGENT_CONFIGURATION def test_agent_configuration__negative_keep_tunnel_open_time(): @@ -266,41 +223,12 @@ def test_agent_configuration__negative_keep_tunnel_open_time(): negative_keep_tunnel_open_time_configuration["keep_tunnel_open_time"] = -1 with pytest.raises(InvalidConfigurationError): - AgentConfiguration.from_mapping(negative_keep_tunnel_open_time_configuration) + Pydantic___AgentConfiguration(**negative_keep_tunnel_open_time_configuration) def test_incorrect_type(): - valid_config = AgentConfiguration.from_mapping(AGENT_CONFIGURATION) + valid_config = Pydantic___AgentConfiguration(**AGENT_CONFIGURATION) with pytest.raises(InvalidConfigurationError): valid_config_dict = valid_config.__dict__ valid_config_dict["keep_tunnel_open_time"] = "not_a_float" - AgentConfiguration(**valid_config_dict) - - -def test_to_from_mapping(): - config = AgentConfiguration.from_mapping(AGENT_CONFIGURATION) - - assert AgentConfiguration.to_mapping(config) == AGENT_CONFIGURATION - - -def test_from_mapping__invalid_data(): - dict_ = deepcopy(AGENT_CONFIGURATION) - dict_["payloads"] = "payloads" - - with pytest.raises(InvalidConfigurationError): - AgentConfiguration.from_mapping(dict_) - - -def test_to_from_json(): - original_config = AgentConfiguration.from_mapping(AGENT_CONFIGURATION) - config_json = AgentConfiguration.to_json(original_config) - - assert AgentConfiguration.from_json(config_json) == original_config - - -def test_from_json__invalid_data(): - invalid_dict = deepcopy(AGENT_CONFIGURATION) - invalid_dict["payloads"] = "payloads" - - with pytest.raises(InvalidConfigurationError): - AgentConfiguration.from_json(json.dumps(invalid_dict)) + Pydantic___AgentConfiguration(**valid_config_dict) From 1311fd5d27e16acf8e2a1d46f9d7ba152778e742 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Mon, 29 Aug 2022 17:20:06 +0530 Subject: [PATCH 14/69] Common: Remove old AgentConfiguration using marshmallow --- .../agent_configuration.py | 109 +----------------- 1 file changed, 1 insertion(+), 108 deletions(-) diff --git a/monkey/common/agent_configuration/agent_configuration.py b/monkey/common/agent_configuration/agent_configuration.py index 84782bef2..34635577f 100644 --- a/monkey/common/agent_configuration/agent_configuration.py +++ b/monkey/common/agent_configuration/agent_configuration.py @@ -1,24 +1,12 @@ from __future__ import annotations -from dataclasses import dataclass -from typing import Any, Mapping, Tuple +from typing import Tuple -from marshmallow import Schema, fields, validate -from marshmallow.exceptions import MarshmallowError from pydantic import PositiveFloat from common.base_models import MutableInfectionMonkeyBaseModel -from ..utils.code_utils import freeze_lists_in_mapping -from .agent_sub_configuration_schemas import ( - CustomPBAConfigurationSchema, - PluginConfigurationSchema, - PropagationConfigurationSchema, -) from .agent_sub_configurations import ( - CustomPBAConfiguration, - PluginConfiguration, - PropagationConfiguration, Pydantic___CustomPBAConfiguration, Pydantic___PluginConfiguration, Pydantic___PropagationConfiguration, @@ -36,101 +24,6 @@ class InvalidConfigurationError(Exception): ) -@dataclass(frozen=True) -class AgentConfiguration: - """ - A configuration for Infection Monkey agents - - Attributes: - :param keep_tunnel_open_time: Maximum time in seconds to keep a tunnel open after - the last exploit - :param custom_pbas: Configuration for custom post-breach actions - :param post_breach_actions: Configuration for post-breach actions - :param credential_collectors: Configuration for credential collectors - :param payloads: Configuration for payloads - :param propagation: Configuration for propagation - """ - - keep_tunnel_open_time: float - custom_pbas: CustomPBAConfiguration - post_breach_actions: Tuple[PluginConfiguration, ...] - credential_collectors: Tuple[PluginConfiguration, ...] - payloads: Tuple[PluginConfiguration, ...] - propagation: PropagationConfiguration - - def __post_init__(self): - # This will raise an exception if the object is invalid. Calling this in __post__init() - # makes it impossible to construct an invalid object - try: - AgentConfigurationSchema().dump(self) - except Exception as err: - raise InvalidConfigurationError(str(err)) - - @staticmethod - def from_mapping(config_mapping: Mapping[str, Any]) -> AgentConfiguration: - """ - Construct an AgentConfiguration from a Mapping - - :param config_mapping: A Mapping that represents an AgentConfiguration - :return: An AgentConfiguration - :raises: InvalidConfigurationError if the provided Mapping does not represent a valid - AgentConfiguration - """ - - try: - config_dict = AgentConfigurationSchema().load(config_mapping) - config_dict = freeze_lists_in_mapping(config_dict) - return AgentConfiguration(**config_dict) - except MarshmallowError as err: - raise InvalidConfigurationError(str(err)) - - @staticmethod - def from_json(config_json: str) -> AgentConfiguration: - """ - Construct an AgentConfiguration from a JSON string - - :param config_json: A JSON string that represents an AgentConfiguration - :return: An AgentConfiguration - :raises: InvalidConfigurationError if the provided JSON does not represent a valid - AgentConfiguration - """ - try: - config_dict = AgentConfigurationSchema().loads(config_json) - config_dict = freeze_lists_in_mapping(config_dict) - return AgentConfiguration(**config_dict) - except MarshmallowError as err: - raise InvalidConfigurationError(str(err)) - - @staticmethod - def to_mapping(config: AgentConfiguration) -> Mapping[str, Any]: - """ - Serialize an AgentConfiguration to a Mapping - - :param config: An AgentConfiguration - :return: A Mapping that represents the AgentConfiguration - """ - return AgentConfigurationSchema().dump(config) - - @staticmethod - def to_json(config: AgentConfiguration) -> str: - """ - Serialize an AgentConfiguration to JSON - - :param config: An AgentConfiguration - :return: A JSON string that represents the AgentConfiguration - """ - return AgentConfigurationSchema().dumps(config) - - -class AgentConfigurationSchema(Schema): - keep_tunnel_open_time = fields.Float(validate=validate.Range(min=0)) - custom_pbas = fields.Nested(CustomPBAConfigurationSchema) - post_breach_actions = fields.List(fields.Nested(PluginConfigurationSchema)) - credential_collectors = fields.List(fields.Nested(PluginConfigurationSchema)) - payloads = fields.List(fields.Nested(PluginConfigurationSchema)) - propagation = fields.Nested(PropagationConfigurationSchema) - - class Pydantic___AgentConfiguration(MutableInfectionMonkeyBaseModel): keep_tunnel_open_time: PositiveFloat custom_pbas: Pydantic___CustomPBAConfiguration From f2c99526851a9276f04e974712086f2590182606 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Mon, 29 Aug 2022 17:21:34 +0530 Subject: [PATCH 15/69] Common: Remove old sub-configurations using marshmallow --- .../agent_sub_configurations.py | 163 ------------------ 1 file changed, 163 deletions(-) diff --git a/monkey/common/agent_configuration/agent_sub_configurations.py b/monkey/common/agent_configuration/agent_sub_configurations.py index 14af14c88..81e8acfbf 100644 --- a/monkey/common/agent_configuration/agent_sub_configurations.py +++ b/monkey/common/agent_configuration/agent_sub_configurations.py @@ -1,4 +1,3 @@ -from dataclasses import dataclass from typing import Dict, Tuple from pydantic import PositiveFloat, PositiveInt, conint, validator @@ -13,29 +12,6 @@ from .validators import ( ) -@dataclass(frozen=True) -class CustomPBAConfiguration: - """ - A configuration for custom post-breach actions - - Attributes: - :param linux_command: Command to run on Linux victim machines. If a file is uploaded, - use this field to change its permissions, execute it, and/or delete it - Example: `chmod +x file.sh; ./file.sh; rm file.sh` - :param linux_filename: Name of the file to upload on Linux victim machines - :param windows_command: Command to run on Windows victim machines. If a file is uploaded, - use this field to change its permissions, execute it, and/or delete - it - Example: `file.bat & del file.bat` - :param windows_filename: Name of the file to upload on Windows victim machines - """ - - linux_command: str - linux_filename: str - windows_command: str - windows_filename: str - - class Pydantic___CustomPBAConfiguration(MutableInfectionMonkeyBaseModel): """ A configuration for custom post-breach actions @@ -68,33 +44,6 @@ class Pydantic___CustomPBAConfiguration(MutableInfectionMonkeyBaseModel): return filename -@dataclass(frozen=True) -class PluginConfiguration: - """ - A configuration for plugins - - Attributes: - :param name: Name of the plugin - Example: "ransomware" - :param options: Any other information/configuration fields relevant to the plugin - Example: { - "encryption": { - "enabled": True, - "directories": { - "linux_target_dir": "~/this_dir", - "windows_target_dir": "C:\that_dir" - }, - }, - "other_behaviors": { - "readme": True - }, - } - """ - - name: str - options: Dict - - class Pydantic___PluginConfiguration(MutableInfectionMonkeyBaseModel): """ A configuration for plugins @@ -121,28 +70,6 @@ class Pydantic___PluginConfiguration(MutableInfectionMonkeyBaseModel): options: Dict -@dataclass(frozen=True) -class ScanTargetConfiguration: - """ - Configuration of network targets to scan and exploit - - Attributes: - :param blocked_ips: IP's that won't be scanned - Example: ("1.1.1.1", "2.2.2.2") - :param inaccessible_subnets: Subnet ranges that shouldn't be accessible for the agent - Example: ("1.1.1.1", "2.2.2.2/24", "myserver") - :param local_network_scan: Whether or not the agent should scan the local network - :param subnets: Subnet ranges to scan - Example: ("192.168.1.1-192.168.2.255", "3.3.3.3", "2.2.2.2/24", - "myHostname") - """ - - blocked_ips: Tuple[str, ...] - inaccessible_subnets: Tuple[str, ...] - local_network_scan: bool - subnets: Tuple[str, ...] - - class Pydantic___ScanTargetConfiguration(MutableInfectionMonkeyBaseModel): """ Configuration of network targets to scan and exploit @@ -179,18 +106,6 @@ class Pydantic___ScanTargetConfiguration(MutableInfectionMonkeyBaseModel): return subnet_range -@dataclass(frozen=True) -class ICMPScanConfiguration: - """ - A configuration for ICMP scanning - - Attributes: - :param timeout: Maximum time in seconds to wait for a response from the target - """ - - timeout: float - - class Pydantic___ICMPScanConfiguration(MutableInfectionMonkeyBaseModel): """ A configuration for ICMP scanning @@ -202,20 +117,6 @@ class Pydantic___ICMPScanConfiguration(MutableInfectionMonkeyBaseModel): timeout: PositiveFloat -@dataclass(frozen=True) -class TCPScanConfiguration: - """ - A configuration for TCP scanning - - Attributes: - :param timeout: Maximum time in seconds to wait for a response from the target - :param ports: Ports to scan - """ - - timeout: float - ports: Tuple[int, ...] - - class Pydantic___TCPScanConfiguration(MutableInfectionMonkeyBaseModel): """ A configuration for TCP scanning @@ -229,24 +130,6 @@ class Pydantic___TCPScanConfiguration(MutableInfectionMonkeyBaseModel): ports: Tuple[conint(ge=0, le=65535), ...] -@dataclass(frozen=True) -class NetworkScanConfiguration: - """ - A configuration for network scanning - - Attributes: - :param tcp: Configuration for TCP scanning - :param icmp: Configuration for ICMP scanning - :param fingerprinters: Configuration for fingerprinters to run - :param targets: Configuration for targets to scan - """ - - tcp: TCPScanConfiguration - icmp: ICMPScanConfiguration - fingerprinters: Tuple[PluginConfiguration, ...] - targets: ScanTargetConfiguration - - class Pydantic___NetworkScanConfiguration(MutableInfectionMonkeyBaseModel): """ A configuration for network scanning @@ -264,18 +147,6 @@ class Pydantic___NetworkScanConfiguration(MutableInfectionMonkeyBaseModel): targets: Pydantic___ScanTargetConfiguration -@dataclass(frozen=True) -class ExploitationOptionsConfiguration: - """ - A configuration for exploitation options - - Attributes: - :param http_ports: HTTP ports to exploit - """ - - http_ports: Tuple[int, ...] - - class Pydantic___ExploitationOptionsConfiguration(MutableInfectionMonkeyBaseModel): """ A configuration for exploitation options @@ -287,22 +158,6 @@ class Pydantic___ExploitationOptionsConfiguration(MutableInfectionMonkeyBaseMode http_ports: Tuple[conint(ge=0, le=65535), ...] -@dataclass(frozen=True) -class ExploitationConfiguration: - """ - A configuration for exploitation - - Attributes: - :param options: Exploitation options shared by all exploiters - :param brute_force: Configuration for brute force exploiters - :param vulnerability: Configuration for vulnerability exploiters - """ - - options: ExploitationOptionsConfiguration - brute_force: Tuple[PluginConfiguration, ...] - vulnerability: Tuple[PluginConfiguration, ...] - - class Pydantic___ExploitationConfiguration(MutableInfectionMonkeyBaseModel): """ A configuration for exploitation @@ -318,24 +173,6 @@ class Pydantic___ExploitationConfiguration(MutableInfectionMonkeyBaseModel): vulnerability: Tuple[Pydantic___PluginConfiguration, ...] -@dataclass(frozen=True) -class PropagationConfiguration: - """ - A configuration for propagation - - Attributes: - :param maximum_depth: Maximum number of hops allowed to spread from the machine where - the attack started i.e. how far to propagate in the network from the - first machine - :param network_scan: Configuration for network scanning - :param exploitation: Configuration for exploitation - """ - - maximum_depth: int - network_scan: NetworkScanConfiguration - exploitation: ExploitationConfiguration - - class Pydantic___PropagationConfiguration(MutableInfectionMonkeyBaseModel): """ A configuration for propagation From 41e7cfb768f7428691286a1f3c141c36e5b460ea Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Mon, 29 Aug 2022 17:23:00 +0530 Subject: [PATCH 16/69] Common: Remove agent sub-configuration schemas --- .../agent_sub_configuration_schemas.py | 112 ------------------ 1 file changed, 112 deletions(-) delete mode 100644 monkey/common/agent_configuration/agent_sub_configuration_schemas.py diff --git a/monkey/common/agent_configuration/agent_sub_configuration_schemas.py b/monkey/common/agent_configuration/agent_sub_configuration_schemas.py deleted file mode 100644 index 401c04d90..000000000 --- a/monkey/common/agent_configuration/agent_sub_configuration_schemas.py +++ /dev/null @@ -1,112 +0,0 @@ -from marshmallow import Schema, fields, post_load, validate - -from .agent_sub_configurations import ( - CustomPBAConfiguration, - ExploitationConfiguration, - ExploitationOptionsConfiguration, - ICMPScanConfiguration, - NetworkScanConfiguration, - PluginConfiguration, - PropagationConfiguration, - ScanTargetConfiguration, - TCPScanConfiguration, -) -from .utils import freeze_lists -from .validators import ( - validate_ip, - validate_linux_filename, - validate_subnet_range, - validate_windows_filename, -) - - -class CustomPBAConfigurationSchema(Schema): - linux_command = fields.Str() - linux_filename = fields.Str(validate=validate_linux_filename) - windows_command = fields.Str() - windows_filename = fields.Str(validate=validate_windows_filename) - - @post_load - def _make_custom_pba_configuration(self, data, **kwargs): - return CustomPBAConfiguration(**data) - - -class PluginConfigurationSchema(Schema): - name = fields.Str() - options = fields.Mapping() - - @post_load - def _make_plugin_configuration(self, data, **kwargs): - return PluginConfiguration(**data) - - -class ScanTargetConfigurationSchema(Schema): - blocked_ips = fields.List(fields.Str(validate=validate_ip)) - inaccessible_subnets = fields.List(fields.Str(validate=validate_subnet_range)) - local_network_scan = fields.Bool() - subnets = fields.List(fields.Str(validate=validate_subnet_range)) - - @post_load - @freeze_lists - def _make_scan_target_configuration(self, data, **kwargs): - return ScanTargetConfiguration(**data) - - -class ICMPScanConfigurationSchema(Schema): - timeout = fields.Float(validate=validate.Range(min=0)) - - @post_load - def _make_icmp_scan_configuration(self, data, **kwargs): - return ICMPScanConfiguration(**data) - - -class TCPScanConfigurationSchema(Schema): - timeout = fields.Float(validate=validate.Range(min=0)) - ports = fields.List(fields.Int(validate=validate.Range(min=0, max=65535))) - - @post_load - @freeze_lists - def _make_tcp_scan_configuration(self, data, **kwargs): - return TCPScanConfiguration(**data) - - -class NetworkScanConfigurationSchema(Schema): - tcp = fields.Nested(TCPScanConfigurationSchema) - icmp = fields.Nested(ICMPScanConfigurationSchema) - fingerprinters = fields.List(fields.Nested(PluginConfigurationSchema)) - targets = fields.Nested(ScanTargetConfigurationSchema) - - @post_load - @freeze_lists - def _make_network_scan_configuration(self, data, **kwargs): - return NetworkScanConfiguration(**data) - - -class ExploitationOptionsConfigurationSchema(Schema): - http_ports = fields.List(fields.Int(validate=validate.Range(min=0, max=65535))) - - @post_load - @freeze_lists - def _make_exploitation_options_configuration(self, data, **kwargs): - return ExploitationOptionsConfiguration(**data) - - -class ExploitationConfigurationSchema(Schema): - options = fields.Nested(ExploitationOptionsConfigurationSchema) - brute_force = fields.List(fields.Nested(PluginConfigurationSchema)) - vulnerability = fields.List(fields.Nested(PluginConfigurationSchema)) - - @post_load - @freeze_lists - def _make_exploitation_options_configuration(self, data, **kwargs): - return ExploitationConfiguration(**data) - - -class PropagationConfigurationSchema(Schema): - maximum_depth = fields.Int(validate=validate.Range(min=0)) - network_scan = fields.Nested(NetworkScanConfigurationSchema) - exploitation = fields.Nested(ExploitationConfigurationSchema) - - @post_load - def _make_propagation_configuration(self, data, **kwargs): - return PropagationConfiguration(**data) From 0d6e3809d7420051d5c26cf099c31e15d9e9e3f8 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Mon, 29 Aug 2022 17:24:30 +0530 Subject: [PATCH 17/69] Common: Rename all new pydantic configurations appropriately --- .../agent_configuration.py | 18 +++++----- .../agent_sub_configurations.py | 36 +++++++++---------- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/monkey/common/agent_configuration/agent_configuration.py b/monkey/common/agent_configuration/agent_configuration.py index 34635577f..80924257f 100644 --- a/monkey/common/agent_configuration/agent_configuration.py +++ b/monkey/common/agent_configuration/agent_configuration.py @@ -7,9 +7,9 @@ from pydantic import PositiveFloat from common.base_models import MutableInfectionMonkeyBaseModel from .agent_sub_configurations import ( - Pydantic___CustomPBAConfiguration, - Pydantic___PluginConfiguration, - Pydantic___PropagationConfiguration, + CustomPBAConfiguration, + PluginConfiguration, + PropagationConfiguration, ) @@ -24,10 +24,10 @@ class InvalidConfigurationError(Exception): ) -class Pydantic___AgentConfiguration(MutableInfectionMonkeyBaseModel): +class AgentConfiguration(MutableInfectionMonkeyBaseModel): keep_tunnel_open_time: PositiveFloat - custom_pbas: Pydantic___CustomPBAConfiguration - post_breach_actions: Tuple[Pydantic___PluginConfiguration, ...] - credential_collectors: Tuple[Pydantic___PluginConfiguration, ...] - payloads: Tuple[Pydantic___PluginConfiguration, ...] - propagation: Pydantic___PropagationConfiguration + custom_pbas: CustomPBAConfiguration + post_breach_actions: Tuple[PluginConfiguration, ...] + credential_collectors: Tuple[PluginConfiguration, ...] + payloads: Tuple[PluginConfiguration, ...] + propagation: PropagationConfiguration diff --git a/monkey/common/agent_configuration/agent_sub_configurations.py b/monkey/common/agent_configuration/agent_sub_configurations.py index 81e8acfbf..e358c91a9 100644 --- a/monkey/common/agent_configuration/agent_sub_configurations.py +++ b/monkey/common/agent_configuration/agent_sub_configurations.py @@ -12,7 +12,7 @@ from .validators import ( ) -class Pydantic___CustomPBAConfiguration(MutableInfectionMonkeyBaseModel): +class CustomPBAConfiguration(MutableInfectionMonkeyBaseModel): """ A configuration for custom post-breach actions @@ -44,7 +44,7 @@ class Pydantic___CustomPBAConfiguration(MutableInfectionMonkeyBaseModel): return filename -class Pydantic___PluginConfiguration(MutableInfectionMonkeyBaseModel): +class PluginConfiguration(MutableInfectionMonkeyBaseModel): """ A configuration for plugins @@ -70,7 +70,7 @@ class Pydantic___PluginConfiguration(MutableInfectionMonkeyBaseModel): options: Dict -class Pydantic___ScanTargetConfiguration(MutableInfectionMonkeyBaseModel): +class ScanTargetConfiguration(MutableInfectionMonkeyBaseModel): """ Configuration of network targets to scan and exploit @@ -106,7 +106,7 @@ class Pydantic___ScanTargetConfiguration(MutableInfectionMonkeyBaseModel): return subnet_range -class Pydantic___ICMPScanConfiguration(MutableInfectionMonkeyBaseModel): +class ICMPScanConfiguration(MutableInfectionMonkeyBaseModel): """ A configuration for ICMP scanning @@ -117,7 +117,7 @@ class Pydantic___ICMPScanConfiguration(MutableInfectionMonkeyBaseModel): timeout: PositiveFloat -class Pydantic___TCPScanConfiguration(MutableInfectionMonkeyBaseModel): +class TCPScanConfiguration(MutableInfectionMonkeyBaseModel): """ A configuration for TCP scanning @@ -130,7 +130,7 @@ class Pydantic___TCPScanConfiguration(MutableInfectionMonkeyBaseModel): ports: Tuple[conint(ge=0, le=65535), ...] -class Pydantic___NetworkScanConfiguration(MutableInfectionMonkeyBaseModel): +class NetworkScanConfiguration(MutableInfectionMonkeyBaseModel): """ A configuration for network scanning @@ -141,13 +141,13 @@ class Pydantic___NetworkScanConfiguration(MutableInfectionMonkeyBaseModel): :param targets: Configuration for targets to scan """ - tcp: Pydantic___TCPScanConfiguration - icmp: Pydantic___ICMPScanConfiguration - fingerprinters: Tuple[Pydantic___PluginConfiguration, ...] - targets: Pydantic___ScanTargetConfiguration + tcp: TCPScanConfiguration + icmp: ICMPScanConfiguration + fingerprinters: Tuple[PluginConfiguration, ...] + targets: ScanTargetConfiguration -class Pydantic___ExploitationOptionsConfiguration(MutableInfectionMonkeyBaseModel): +class ExploitationOptionsConfiguration(MutableInfectionMonkeyBaseModel): """ A configuration for exploitation options @@ -158,7 +158,7 @@ class Pydantic___ExploitationOptionsConfiguration(MutableInfectionMonkeyBaseMode http_ports: Tuple[conint(ge=0, le=65535), ...] -class Pydantic___ExploitationConfiguration(MutableInfectionMonkeyBaseModel): +class ExploitationConfiguration(MutableInfectionMonkeyBaseModel): """ A configuration for exploitation @@ -168,12 +168,12 @@ class Pydantic___ExploitationConfiguration(MutableInfectionMonkeyBaseModel): :param vulnerability: Configuration for vulnerability exploiters """ - options: Pydantic___ExploitationOptionsConfiguration - brute_force: Tuple[Pydantic___PluginConfiguration, ...] - vulnerability: Tuple[Pydantic___PluginConfiguration, ...] + options: ExploitationOptionsConfiguration + brute_force: Tuple[PluginConfiguration, ...] + vulnerability: Tuple[PluginConfiguration, ...] -class Pydantic___PropagationConfiguration(MutableInfectionMonkeyBaseModel): +class PropagationConfiguration(MutableInfectionMonkeyBaseModel): """ A configuration for propagation @@ -186,5 +186,5 @@ class Pydantic___PropagationConfiguration(MutableInfectionMonkeyBaseModel): """ maximum_depth: PositiveInt - network_scan: Pydantic___NetworkScanConfiguration - exploitation: Pydantic___ExploitationConfiguration + network_scan: NetworkScanConfiguration + exploitation: ExploitationConfiguration From 430885ebd4ed33fc6f6d9b30ada5c604a2a8eca4 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Mon, 29 Aug 2022 17:25:26 +0530 Subject: [PATCH 18/69] UT: Fix new pydantic configuration class names --- .../test_agent_configuration.py | 84 +++++++++---------- 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/monkey/tests/unit_tests/common/agent_configuration/test_agent_configuration.py b/monkey/tests/unit_tests/common/agent_configuration/test_agent_configuration.py index 883b5f6d2..bbff68e5f 100644 --- a/monkey/tests/unit_tests/common/agent_configuration/test_agent_configuration.py +++ b/monkey/tests/unit_tests/common/agent_configuration/test_agent_configuration.py @@ -26,31 +26,31 @@ from tests.common.example_agent_configuration import ( ) from common.agent_configuration import InvalidConfigurationError -from common.agent_configuration.agent_configuration import Pydantic___AgentConfiguration +from common.agent_configuration.agent_configuration import AgentConfiguration from common.agent_configuration.agent_sub_configurations import ( - Pydantic___CustomPBAConfiguration, - Pydantic___ExploitationConfiguration, - Pydantic___ExploitationOptionsConfiguration, - Pydantic___ICMPScanConfiguration, - Pydantic___NetworkScanConfiguration, - Pydantic___PluginConfiguration, - Pydantic___PropagationConfiguration, - Pydantic___ScanTargetConfiguration, - Pydantic___TCPScanConfiguration, + CustomPBAConfiguration, + ExploitationConfiguration, + ExploitationOptionsConfiguration, + ICMPScanConfiguration, + NetworkScanConfiguration, + PluginConfiguration, + PropagationConfiguration, + ScanTargetConfiguration, + TCPScanConfiguration, ) INVALID_PORTS = [[-1, 1, 2], [1, 2, 99999]] def test_build_plugin_configuration(): - config = Pydantic___PluginConfiguration(**PLUGIN_CONFIGURATION) + config = PluginConfiguration(**PLUGIN_CONFIGURATION) assert config.name == PLUGIN_NAME assert config.options == PLUGIN_OPTIONS def test_custom_pba_configuration_schema(): - config = Pydantic___CustomPBAConfiguration(**CUSTOM_PBA_CONFIGURATION) + config = CustomPBAConfiguration(**CUSTOM_PBA_CONFIGURATION) assert config.linux_command == LINUX_COMMAND assert config.linux_filename == LINUX_FILENAME @@ -62,7 +62,7 @@ def test_custom_pba_configuration_schema__empty_filenames_allowed(): empty_filename_configuration = CUSTOM_PBA_CONFIGURATION.copy() empty_filename_configuration.update({"linux_filename": "", "windows_filename": ""}) - config = Pydantic___CustomPBAConfiguration(**empty_filename_configuration) + config = CustomPBAConfiguration(**empty_filename_configuration) assert config.linux_command == LINUX_COMMAND assert config.linux_filename == "" @@ -76,7 +76,7 @@ def test_custom_pba_configuration_schema__invalid_linux_filename(linux_filename) invalid_filename_configuration["linux_filename"] = linux_filename with pytest.raises(ValidationError): - Pydantic___CustomPBAConfiguration(**invalid_filename_configuration) + CustomPBAConfiguration(**invalid_filename_configuration) @pytest.mark.parametrize( @@ -87,11 +87,11 @@ def test_custom_pba_configuration_schema__invalid_windows_filename(windows_filen invalid_filename_configuration["windows_filename"] = windows_filename with pytest.raises(ValidationError): - Pydantic___CustomPBAConfiguration(**invalid_filename_configuration) + CustomPBAConfiguration(**invalid_filename_configuration) def test_scan_target_configuration(): - config = Pydantic___ScanTargetConfiguration(**SCAN_TARGET_CONFIGURATION) + config = ScanTargetConfiguration(**SCAN_TARGET_CONFIGURATION) assert config.blocked_ips == tuple(BLOCKED_IPS) assert config.inaccessible_subnets == tuple(INACCESSIBLE_SUBNETS) @@ -100,7 +100,7 @@ def test_scan_target_configuration(): def test_icmp_scan_configuration_schema(): - config = Pydantic___ICMPScanConfiguration(**ICMP_CONFIGURATION) + config = ICMPScanConfiguration(**ICMP_CONFIGURATION) assert config.timeout == TIMEOUT @@ -110,11 +110,11 @@ def test_icmp_scan_configuration_schema__negative_timeout(): negative_timeout_configuration["timeout"] = -1 with pytest.raises(ValidationError): - Pydantic___ICMPScanConfiguration(**negative_timeout_configuration) + ICMPScanConfiguration(**negative_timeout_configuration) def test_tcp_scan_configuration_schema(): - config = Pydantic___TCPScanConfiguration(**TCP_SCAN_CONFIGURATION) + config = TCPScanConfiguration(**TCP_SCAN_CONFIGURATION) assert config.timeout == TIMEOUT assert config.ports == tuple(PORTS) @@ -126,7 +126,7 @@ def test_tcp_scan_configuration_schema__ports_out_of_range(ports): invalid_ports_configuration["ports"] = ports with pytest.raises(ValidationError): - Pydantic___TCPScanConfiguration(**invalid_ports_configuration) + TCPScanConfiguration(**invalid_ports_configuration) def test_tcp_scan_configuration_schema__negative_timeout(): @@ -134,11 +134,11 @@ def test_tcp_scan_configuration_schema__negative_timeout(): negative_timeout_configuration["timeout"] = -1 with pytest.raises(ValidationError): - Pydantic___TCPScanConfiguration(**negative_timeout_configuration) + TCPScanConfiguration(**negative_timeout_configuration) def test_network_scan_configuration(): - config = Pydantic___NetworkScanConfiguration(**NETWORK_SCAN_CONFIGURATION) + config = NetworkScanConfiguration(**NETWORK_SCAN_CONFIGURATION) assert config.tcp.ports == tuple(TCP_SCAN_CONFIGURATION["ports"]) assert config.tcp.timeout == TCP_SCAN_CONFIGURATION["timeout"] @@ -154,7 +154,7 @@ def test_network_scan_configuration(): def test_exploitation_options_configuration_schema(): ports = [1, 2, 3] - config = Pydantic___ExploitationOptionsConfiguration(**{"http_ports": ports}) + config = ExploitationOptionsConfiguration(**{"http_ports": ports}) assert config.http_ports == tuple(ports) @@ -164,34 +164,34 @@ def test_exploitation_options_configuration_schema__ports_out_of_range(ports): invalid_ports_configuration = {"http_ports": ports} with pytest.raises(ValidationError): - Pydantic___ExploitationOptionsConfiguration(**invalid_ports_configuration) + ExploitationOptionsConfiguration(**invalid_ports_configuration) def test_exploiter_configuration_schema(): name = "bond" options = {"gun": "Walther PPK", "car": "Aston Martin DB5"} - config = Pydantic___PluginConfiguration(**{"name": name, "options": options}) + config = PluginConfiguration(**{"name": name, "options": options}) assert config.name == name assert config.options == options def test_exploitation_configuration(): - config = Pydantic___ExploitationConfiguration(**EXPLOITATION_CONFIGURATION) + config = ExploitationConfiguration(**EXPLOITATION_CONFIGURATION) config_dict = config.dict() - assert isinstance(config, Pydantic___ExploitationConfiguration) + assert isinstance(config, ExploitationConfiguration) assert config_dict == EXPLOITATION_CONFIGURATION def test_propagation_configuration(): - config = Pydantic___PropagationConfiguration(**PROPAGATION_CONFIGURATION) + config = PropagationConfiguration(**PROPAGATION_CONFIGURATION) config_dict = config.dict() - assert isinstance(config, Pydantic___PropagationConfiguration) - assert isinstance(config.network_scan, Pydantic___NetworkScanConfiguration) - assert isinstance(config.exploitation, Pydantic___ExploitationConfiguration) + assert isinstance(config, PropagationConfiguration) + assert isinstance(config.network_scan, NetworkScanConfiguration) + assert isinstance(config.exploitation, ExploitationConfiguration) assert config.maximum_depth == 5 assert config_dict == PROPAGATION_CONFIGURATION @@ -201,20 +201,20 @@ def test_propagation_configuration__invalid_maximum_depth(): negative_maximum_depth_configuration["maximum_depth"] = -1 with pytest.raises(ValidationError): - Pydantic___PropagationConfiguration(**negative_maximum_depth_configuration) + PropagationConfiguration(**negative_maximum_depth_configuration) def test_agent_configuration(): - config = Pydantic___AgentConfiguration(**AGENT_CONFIGURATION) + config = AgentConfiguration(**AGENT_CONFIGURATION) config_dict = config.dict() - assert isinstance(config, Pydantic___AgentConfiguration) + assert isinstance(config, AgentConfiguration) assert config.keep_tunnel_open_time == 30 - assert isinstance(config.custom_pbas, Pydantic___CustomPBAConfiguration) - assert isinstance(config.post_breach_actions[0], Pydantic___PluginConfiguration) - assert isinstance(config.credential_collectors[0], Pydantic___PluginConfiguration) - assert isinstance(config.payloads[0], Pydantic___PluginConfiguration) - assert isinstance(config.propagation, Pydantic___PropagationConfiguration) + assert isinstance(config.custom_pbas, CustomPBAConfiguration) + assert isinstance(config.post_breach_actions[0], PluginConfiguration) + assert isinstance(config.credential_collectors[0], PluginConfiguration) + assert isinstance(config.payloads[0], PluginConfiguration) + assert isinstance(config.propagation, PropagationConfiguration) assert config_dict == AGENT_CONFIGURATION @@ -223,12 +223,12 @@ def test_agent_configuration__negative_keep_tunnel_open_time(): negative_keep_tunnel_open_time_configuration["keep_tunnel_open_time"] = -1 with pytest.raises(InvalidConfigurationError): - Pydantic___AgentConfiguration(**negative_keep_tunnel_open_time_configuration) + AgentConfiguration(**negative_keep_tunnel_open_time_configuration) def test_incorrect_type(): - valid_config = Pydantic___AgentConfiguration(**AGENT_CONFIGURATION) + valid_config = AgentConfiguration(**AGENT_CONFIGURATION) with pytest.raises(InvalidConfigurationError): valid_config_dict = valid_config.__dict__ valid_config_dict["keep_tunnel_open_time"] = "not_a_float" - Pydantic___AgentConfiguration(**valid_config_dict) + AgentConfiguration(**valid_config_dict) From 96f213d4ee2a5b4dd503d3c2b55dcfc601949c7e Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Mon, 29 Aug 2022 17:27:59 +0530 Subject: [PATCH 19/69] Project: Add pydantic validators to Vulture allowlist --- vulture_allowlist.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/vulture_allowlist.py b/vulture_allowlist.py index 32d3686b1..483b5343b 100644 --- a/vulture_allowlist.py +++ b/vulture_allowlist.py @@ -294,6 +294,11 @@ underscore_attrs_are_private extra allow_mutation validate_assignment +linux_filename_valid +windows_filename_valid +blocked_ips_valid +inaccessible_subnets_valid +subnets_valid # CommunicationType CommunicationType From b20ad194ff12c2b65b1486fef6f45000dae38fea Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Mon, 29 Aug 2022 19:09:24 +0530 Subject: [PATCH 20/69] Common: Modify default configurations to work with new pydantic models --- .../default_agent_configuration.py | 51 ++++++++++--------- 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/monkey/common/agent_configuration/default_agent_configuration.py b/monkey/common/agent_configuration/default_agent_configuration.py index 91026e5d2..ec50eb422 100644 --- a/monkey/common/agent_configuration/default_agent_configuration.py +++ b/monkey/common/agent_configuration/default_agent_configuration.py @@ -1,5 +1,3 @@ -import dataclasses - from . import AgentConfiguration from .agent_sub_configurations import ( CustomPBAConfiguration, @@ -27,9 +25,9 @@ PBAS = ( CREDENTIAL_COLLECTORS = ("MimikatzCollector", "SSHCollector") -PBA_CONFIGURATION = tuple(PluginConfiguration(pba, {}) for pba in PBAS) +PBA_CONFIGURATION = tuple(PluginConfiguration(name=pba, options={}) for pba in PBAS) CREDENTIAL_COLLECTOR_CONFIGURATION = tuple( - PluginConfiguration(collector, {}) for collector in CREDENTIAL_COLLECTORS + PluginConfiguration(name=collector, options={}) for collector in CREDENTIAL_COLLECTORS ) RANSOMWARE_OPTIONS = { @@ -41,7 +39,7 @@ RANSOMWARE_OPTIONS = { "other_behaviors": {"readme": True}, } -PAYLOAD_CONFIGURATION = tuple([PluginConfiguration("ransomware", RANSOMWARE_OPTIONS)]) +PAYLOAD_CONFIGURATION = tuple([PluginConfiguration(name="ransomware", options=RANSOMWARE_OPTIONS)]) CUSTOM_PBA_CONFIGURATION = CustomPBAConfiguration( linux_command="", linux_filename="", windows_command="", windows_filename="" @@ -71,35 +69,42 @@ TCP_SCAN_CONFIGURATION = TCPScanConfiguration(timeout=3.0, ports=TCP_PORTS) ICMP_CONFIGURATION = ICMPScanConfiguration(timeout=1.0) HTTP_PORTS = (80, 443, 7001, 8008, 8080, 8983, 9200, 9600) FINGERPRINTERS = ( - PluginConfiguration("elastic", {}), + PluginConfiguration(name="elastic", options={}), # Plugin configuration option contents are not converted to tuples - PluginConfiguration("http", {"http_ports": list(HTTP_PORTS)}), - PluginConfiguration("mssql", {}), - PluginConfiguration("smb", {}), - PluginConfiguration("ssh", {}), + PluginConfiguration(name="http", options={"http_ports": list(HTTP_PORTS)}), + PluginConfiguration(name="mssql", options={}), + PluginConfiguration(name="smb", options={}), + PluginConfiguration(name="ssh", options={}), ) -SCAN_TARGET_CONFIGURATION = ScanTargetConfiguration(tuple(), tuple(), True, tuple()) +SCAN_TARGET_CONFIGURATION = ScanTargetConfiguration( + blocked_ips=tuple(), inaccessible_subnets=tuple(), local_network_scan=True, subnets=tuple() +) NETWORK_SCAN_CONFIGURATION = NetworkScanConfiguration( - TCP_SCAN_CONFIGURATION, ICMP_CONFIGURATION, FINGERPRINTERS, SCAN_TARGET_CONFIGURATION + tcp=TCP_SCAN_CONFIGURATION, + icmp=ICMP_CONFIGURATION, + fingerprinters=FINGERPRINTERS, + targets=SCAN_TARGET_CONFIGURATION, ) -EXPLOITATION_OPTIONS_CONFIGURATION = ExploitationOptionsConfiguration(HTTP_PORTS) +EXPLOITATION_OPTIONS_CONFIGURATION = ExploitationOptionsConfiguration(http_ports=HTTP_PORTS) BRUTE_FORCE_EXPLOITERS = ( - PluginConfiguration("MSSQLExploiter", {}), - PluginConfiguration("PowerShellExploiter", {}), - PluginConfiguration("SSHExploiter", {}), - PluginConfiguration("SmbExploiter", {"smb_download_timeout": 30}), - PluginConfiguration("WmiExploiter", {"smb_download_timeout": 30}), + PluginConfiguration(name="MSSQLExploiter", options={}), + PluginConfiguration(name="PowerShellExploiter", options={}), + PluginConfiguration(name="SSHExploiter", options={}), + PluginConfiguration(name="SmbExploiter", options={"smb_download_timeout": 30}), + PluginConfiguration(name="WmiExploiter", options={"smb_download_timeout": 30}), ) VULNERABILITY_EXPLOITERS = ( - PluginConfiguration("Log4ShellExploiter", {}), - PluginConfiguration("HadoopExploiter", {}), + PluginConfiguration(name="Log4ShellExploiter", options={}), + PluginConfiguration(name="HadoopExploiter", options={}), ) EXPLOITATION_CONFIGURATION = ExploitationConfiguration( - EXPLOITATION_OPTIONS_CONFIGURATION, BRUTE_FORCE_EXPLOITERS, VULNERABILITY_EXPLOITERS + options=EXPLOITATION_OPTIONS_CONFIGURATION, + brute_force=BRUTE_FORCE_EXPLOITERS, + vulnerability=VULNERABILITY_EXPLOITERS, ) PROPAGATION_CONFIGURATION = PropagationConfiguration( @@ -117,6 +122,6 @@ DEFAULT_AGENT_CONFIGURATION = AgentConfiguration( propagation=PROPAGATION_CONFIGURATION, ) -DEFAULT_RANSOMWARE_AGENT_CONFIGURATION = dataclasses.replace( - DEFAULT_AGENT_CONFIGURATION, post_breach_actions=tuple() +DEFAULT_RANSOMWARE_AGENT_CONFIGURATION = DEFAULT_AGENT_CONFIGURATION.copy( + update={"post_breach_actions": tuple()} ) From a1b8bb24b490b0a460494d131373edba9fe00a4e Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Mon, 29 Aug 2022 19:31:38 +0530 Subject: [PATCH 21/69] Common: Raise ValueError instead of marshmallow.ValidationError in validators --- .../validators/filenames.py | 8 +++---- .../validators/ip_ranges.py | 24 +++++++++---------- 2 files changed, 14 insertions(+), 18 deletions(-) diff --git a/monkey/common/agent_configuration/validators/filenames.py b/monkey/common/agent_configuration/validators/filenames.py index 2a8e4df01..22140f2da 100644 --- a/monkey/common/agent_configuration/validators/filenames.py +++ b/monkey/common/agent_configuration/validators/filenames.py @@ -1,24 +1,22 @@ import re from pathlib import PureWindowsPath -from marshmallow import ValidationError - _valid_windows_filename_regex = re.compile(r"^[^<>:\"\\\/|?*]*[^<>:\"\\\/|?* \.]+$|^$") _valid_linux_filename_regex = re.compile(r"^[^\0/]*$") def validate_linux_filename(linux_filename: str): if not re.match(_valid_linux_filename_regex, linux_filename): - raise ValidationError(f"Invalid Unix filename {linux_filename}: illegal characters") + raise ValueError(f"Invalid Unix filename {linux_filename}: illegal characters") def validate_windows_filename(windows_filename: str): _validate_windows_filename_not_reserved(windows_filename) if not re.match(_valid_windows_filename_regex, windows_filename): - raise ValidationError(f"Invalid Windows filename {windows_filename}: illegal characters") + raise ValueError(f"Invalid Windows filename {windows_filename}: illegal characters") def _validate_windows_filename_not_reserved(windows_filename: str): # filename shouldn't start with any of these and be followed by a period if PureWindowsPath(windows_filename).is_reserved(): - raise ValidationError(f"Invalid Windows filename {windows_filename}: reserved name used") + raise ValueError(f"Invalid Windows filename {windows_filename}: reserved name used") diff --git a/monkey/common/agent_configuration/validators/ip_ranges.py b/monkey/common/agent_configuration/validators/ip_ranges.py index 6eabc9e61..05b6107a9 100644 --- a/monkey/common/agent_configuration/validators/ip_ranges.py +++ b/monkey/common/agent_configuration/validators/ip_ranges.py @@ -1,38 +1,36 @@ import re from ipaddress import AddressValueError, IPv4Address, IPv4Network, NetmaskValueError -from marshmallow import ValidationError - def validate_subnet_range(subnet_range: str): try: return validate_ip(subnet_range) - except ValidationError: + except ValueError: pass try: return validate_ip_range(subnet_range) - except ValidationError: + except ValueError: pass try: return validate_ip_network(subnet_range) - except ValidationError: + except ValueError: pass try: return validate_hostname(subnet_range) - except ValidationError: - raise ValidationError(f"Invalid subnet range {subnet_range}") + except ValueError: + raise ValueError(f"Invalid subnet range {subnet_range}") def validate_hostname(hostname: str): # Based on hostname syntax: https://www.rfc-editor.org/rfc/rfc1123#page-13 hostname_segments = hostname.split(".") if any((part.endswith("-") or part.startswith("-") for part in hostname_segments)): - raise ValidationError(f"Hostname segment can't start or end with a hyphen: {hostname}") + raise ValueError(f"Hostname segment can't start or end with a hyphen: {hostname}") if not any((char.isalpha() for char in hostname_segments[-1])): - raise ValidationError(f"Last segment of a hostname must contain a letter: {hostname}") + raise ValueError(f"Last segment of a hostname must contain a letter: {hostname}") valid_characters_pattern = r"^[A-Za-z0-9\-]+$" valid_characters_regex = re.compile(valid_characters_pattern) @@ -41,21 +39,21 @@ def validate_hostname(hostname: str): ) if not all(matches): - raise ValidationError(f"Hostname contains invalid characters: {hostname}") + raise ValueError(f"Hostname contains invalid characters: {hostname}") def validate_ip_network(ip_network: str): try: IPv4Network(ip_network, strict=False) except (NetmaskValueError, AddressValueError): - raise ValidationError(f"Invalid IPv4 network {ip_network}") + raise ValueError(f"Invalid IPv4 network {ip_network}") def validate_ip_range(ip_range: str): ip_range = ip_range.replace(" ", "") ips = ip_range.split("-") if len(ips) != 2: - raise ValidationError(f"Invalid IP range {ip_range}") + raise ValueError(f"Invalid IP range {ip_range}") validate_ip(ips[0]) validate_ip(ips[1]) @@ -64,4 +62,4 @@ def validate_ip(ip: str): try: IPv4Address(ip) except AddressValueError: - raise ValidationError(f"Invalid IP address {ip}") + raise ValueError(f"Invalid IP address {ip}") From c79b3c4497e37461f7d502858dde6391a91dc902 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Mon, 29 Aug 2022 19:35:14 +0530 Subject: [PATCH 22/69] UT: Check that ValueError is raised instead of marshmallow.ValidationError in configuration tests --- .../test_agent_configuration.py | 20 +++++++++---------- .../validators/test_ip_ranges.py | 11 +++++----- 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/monkey/tests/unit_tests/common/agent_configuration/test_agent_configuration.py b/monkey/tests/unit_tests/common/agent_configuration/test_agent_configuration.py index bbff68e5f..ed1f1bfa3 100644 --- a/monkey/tests/unit_tests/common/agent_configuration/test_agent_configuration.py +++ b/monkey/tests/unit_tests/common/agent_configuration/test_agent_configuration.py @@ -1,5 +1,4 @@ import pytest -from marshmallow import ValidationError from tests.common.example_agent_configuration import ( AGENT_CONFIGURATION, BLOCKED_IPS, @@ -25,7 +24,6 @@ from tests.common.example_agent_configuration import ( WINDOWS_FILENAME, ) -from common.agent_configuration import InvalidConfigurationError from common.agent_configuration.agent_configuration import AgentConfiguration from common.agent_configuration.agent_sub_configurations import ( CustomPBAConfiguration, @@ -75,7 +73,7 @@ def test_custom_pba_configuration_schema__invalid_linux_filename(linux_filename) invalid_filename_configuration = CUSTOM_PBA_CONFIGURATION.copy() invalid_filename_configuration["linux_filename"] = linux_filename - with pytest.raises(ValidationError): + with pytest.raises(ValueError): CustomPBAConfiguration(**invalid_filename_configuration) @@ -86,7 +84,7 @@ def test_custom_pba_configuration_schema__invalid_windows_filename(windows_filen invalid_filename_configuration = CUSTOM_PBA_CONFIGURATION.copy() invalid_filename_configuration["windows_filename"] = windows_filename - with pytest.raises(ValidationError): + with pytest.raises(ValueError): CustomPBAConfiguration(**invalid_filename_configuration) @@ -109,7 +107,7 @@ def test_icmp_scan_configuration_schema__negative_timeout(): negative_timeout_configuration = ICMP_CONFIGURATION.copy() negative_timeout_configuration["timeout"] = -1 - with pytest.raises(ValidationError): + with pytest.raises(ValueError): ICMPScanConfiguration(**negative_timeout_configuration) @@ -125,7 +123,7 @@ def test_tcp_scan_configuration_schema__ports_out_of_range(ports): invalid_ports_configuration = TCP_SCAN_CONFIGURATION.copy() invalid_ports_configuration["ports"] = ports - with pytest.raises(ValidationError): + with pytest.raises(ValueError): TCPScanConfiguration(**invalid_ports_configuration) @@ -133,7 +131,7 @@ def test_tcp_scan_configuration_schema__negative_timeout(): negative_timeout_configuration = TCP_SCAN_CONFIGURATION.copy() negative_timeout_configuration["timeout"] = -1 - with pytest.raises(ValidationError): + with pytest.raises(ValueError): TCPScanConfiguration(**negative_timeout_configuration) @@ -163,7 +161,7 @@ def test_exploitation_options_configuration_schema(): def test_exploitation_options_configuration_schema__ports_out_of_range(ports): invalid_ports_configuration = {"http_ports": ports} - with pytest.raises(ValidationError): + with pytest.raises(ValueError): ExploitationOptionsConfiguration(**invalid_ports_configuration) @@ -200,7 +198,7 @@ def test_propagation_configuration__invalid_maximum_depth(): negative_maximum_depth_configuration = PROPAGATION_CONFIGURATION.copy() negative_maximum_depth_configuration["maximum_depth"] = -1 - with pytest.raises(ValidationError): + with pytest.raises(ValueError): PropagationConfiguration(**negative_maximum_depth_configuration) @@ -222,13 +220,13 @@ def test_agent_configuration__negative_keep_tunnel_open_time(): negative_keep_tunnel_open_time_configuration = AGENT_CONFIGURATION.copy() negative_keep_tunnel_open_time_configuration["keep_tunnel_open_time"] = -1 - with pytest.raises(InvalidConfigurationError): + with pytest.raises(ValueError): AgentConfiguration(**negative_keep_tunnel_open_time_configuration) def test_incorrect_type(): valid_config = AgentConfiguration(**AGENT_CONFIGURATION) - with pytest.raises(InvalidConfigurationError): + with pytest.raises(TypeError): valid_config_dict = valid_config.__dict__ valid_config_dict["keep_tunnel_open_time"] = "not_a_float" AgentConfiguration(**valid_config_dict) diff --git a/monkey/tests/unit_tests/common/agent_configuration/validators/test_ip_ranges.py b/monkey/tests/unit_tests/common/agent_configuration/validators/test_ip_ranges.py index 80f24497c..bf6a62640 100644 --- a/monkey/tests/unit_tests/common/agent_configuration/validators/test_ip_ranges.py +++ b/monkey/tests/unit_tests/common/agent_configuration/validators/test_ip_ranges.py @@ -1,5 +1,4 @@ import pytest -from marshmallow import ValidationError from common.agent_configuration.validators.ip_ranges import validate_ip, validate_subnet_range @@ -11,7 +10,7 @@ def test_validate_ip_valid(ip): @pytest.mark.parametrize("ip", ["1.1.1", "257.256.255.255", "1.1.1.1.1"]) def test_validate_ip_invalid(ip): - with pytest.raises(ValidationError): + with pytest.raises(ValueError): validate_ip(ip) @@ -22,7 +21,7 @@ def test_validate_subnet_range__ip_valid(ip): @pytest.mark.parametrize("ip", ["1.1.1", "257.256.255.255", "1.1.1.1.1"]) def test_validate_subnet_range__ip_invalid(ip): - with pytest.raises(ValidationError): + with pytest.raises(ValueError): validate_subnet_range(ip) @@ -42,7 +41,7 @@ def test_validate_subnet_range__ip_range_valid(ip_range): ], ) def test_validate_subnet_range__ip_range_invalid(ip_range): - with pytest.raises(ValidationError): + with pytest.raises(ValueError): validate_subnet_range(ip_range) @@ -55,7 +54,7 @@ def test_validate_subnet_range__hostname_valid(hostname): "hostname", ["hy&!he.host", "čili-peppers.are-hot", "one.two-", "one-.two", "one@two", ""] ) def test_validate_subnet_range__hostname_invalid(hostname): - with pytest.raises(ValidationError): + with pytest.raises(ValueError): validate_subnet_range(hostname) @@ -66,5 +65,5 @@ def test_validate_subnet_range__cidr_valid(cidr_range): @pytest.mark.parametrize("cidr_range", ["1.1.1/24", "1.1.1.1/-1", "1.1.1.1/33", "1.1.1.1/222"]) def test_validate_subnet_range__cidr_invalid(cidr_range): - with pytest.raises(ValidationError): + with pytest.raises(ValueError): validate_subnet_range(cidr_range) From 433e154cd1415952b2b7ba2433704b2701d3a213 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Mon, 29 Aug 2022 19:42:04 +0530 Subject: [PATCH 23/69] Island: Modify AgentConfiguration endpoint to use new pydantic model --- monkey/monkey_island/cc/resources/agent_configuration.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/monkey/monkey_island/cc/resources/agent_configuration.py b/monkey/monkey_island/cc/resources/agent_configuration.py index 6db3f8b63..e96ed5df2 100644 --- a/monkey/monkey_island/cc/resources/agent_configuration.py +++ b/monkey/monkey_island/cc/resources/agent_configuration.py @@ -20,13 +20,13 @@ class AgentConfiguration(AbstractResource): # Used by the agent. Can't secure def get(self): configuration = self._agent_configuration_repository.get_configuration() - configuration_json = AgentConfigurationObject.to_json(configuration) - return make_response(configuration_json, 200) + configuration_dict = configuration.dict() + return make_response(configuration_dict, 200) @jwt_required def put(self): try: - configuration_object = AgentConfigurationObject.from_mapping(request.json) + configuration_object = AgentConfigurationObject(**request.json) self._agent_configuration_repository.store_configuration(configuration_object) # API Spec: Should return 204 (NO CONTENT) return make_response({}, 200) From fe792ffc6fc5bd091c5a5456fc3d1b573d2b6ac3 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Mon, 29 Aug 2022 19:45:35 +0530 Subject: [PATCH 24/69] Island: Catch ValueError and TypeError instead of InvalidConfigurationError in resource AgentConfiguration's PUT --- monkey/monkey_island/cc/resources/agent_configuration.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/monkey/monkey_island/cc/resources/agent_configuration.py b/monkey/monkey_island/cc/resources/agent_configuration.py index e96ed5df2..297c8c79f 100644 --- a/monkey/monkey_island/cc/resources/agent_configuration.py +++ b/monkey/monkey_island/cc/resources/agent_configuration.py @@ -5,7 +5,6 @@ from flask import make_response, request from common.agent_configuration.agent_configuration import ( AgentConfiguration as AgentConfigurationObject, ) -from common.agent_configuration.agent_configuration import InvalidConfigurationError from monkey_island.cc.repository import IAgentConfigurationRepository from monkey_island.cc.resources.AbstractResource import AbstractResource from monkey_island.cc.resources.request_authentication import jwt_required @@ -30,7 +29,7 @@ class AgentConfiguration(AbstractResource): self._agent_configuration_repository.store_configuration(configuration_object) # API Spec: Should return 204 (NO CONTENT) return make_response({}, 200) - except (InvalidConfigurationError, json.JSONDecodeError) as err: + except (ValueError, TypeError, json.JSONDecodeError) as err: return make_response( {"error": f"Invalid configuration supplied: {err}"}, 400, From e68a5391c884a55596cb16fe732e52c4df73b142 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Mon, 29 Aug 2022 19:46:48 +0530 Subject: [PATCH 25/69] UT: Fix POST request in test_agent_configuration_endpoint to use new pydantic model AgentConfiguration --- .../monkey_island/cc/resources/test_agent_configuration.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/monkey/tests/unit_tests/monkey_island/cc/resources/test_agent_configuration.py b/monkey/tests/unit_tests/monkey_island/cc/resources/test_agent_configuration.py index b383bd013..f2010a59e 100644 --- a/monkey/tests/unit_tests/monkey_island/cc/resources/test_agent_configuration.py +++ b/monkey/tests/unit_tests/monkey_island/cc/resources/test_agent_configuration.py @@ -26,7 +26,7 @@ def flask_client(build_flask_client): def test_agent_configuration_endpoint(flask_client): resp = flask_client.put( AGENT_CONFIGURATION_URL, - json=AgentConfiguration.to_mapping(AGENT_CONFIGURATION), + json=AgentConfiguration(**AGENT_CONFIGURATION).dict(), follow_redirects=True, ) assert resp.status_code == 200 From 2b11fde82756c5b92dea66c367a0d13506614df6 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Tue, 30 Aug 2022 12:19:18 +0530 Subject: [PATCH 26/69] Agent: Use keyword arguments when using PluginConfiguration in Master --- monkey/infection_monkey/master/exploiter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/monkey/infection_monkey/master/exploiter.py b/monkey/infection_monkey/master/exploiter.py index ff21ae32b..0c743674c 100644 --- a/monkey/infection_monkey/master/exploiter.py +++ b/monkey/infection_monkey/master/exploiter.py @@ -94,7 +94,7 @@ class Exploiter: # This order allows exploiter-specific options to # override general options for all exploiters. options = {**exploitation_config.options.__dict__, **exploiter.options} - extended_exploiters.append(PluginConfiguration(exploiter.name, options)) + extended_exploiters.append(PluginConfiguration(name=exploiter.name, options=options)) return extended_exploiters From 45c6fda8b28938f4f09a25bb154f7720842465f0 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Tue, 30 Aug 2022 12:19:59 +0530 Subject: [PATCH 27/69] UT: Use keyword arguments when using configurations --- .../infection_monkey/master/test_ip_scanner.py | 8 ++++---- .../infection_monkey/master/test_propagator.py | 14 +++++++------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/monkey/tests/unit_tests/infection_monkey/master/test_ip_scanner.py b/monkey/tests/unit_tests/infection_monkey/master/test_ip_scanner.py index a9c7f601e..c55fdb85c 100644 --- a/monkey/tests/unit_tests/infection_monkey/master/test_ip_scanner.py +++ b/monkey/tests/unit_tests/infection_monkey/master/test_ip_scanner.py @@ -39,10 +39,10 @@ def scan_config(default_agent_configuration): PluginConfiguration(name="SSHFinger", options={}), ] scan_config = NetworkScanConfiguration( - tcp_config, - icmp_config, - fingerprinter_config, - default_agent_configuration.propagation.network_scan.targets, + tcp=tcp_config, + icmp=icmp_config, + fingerprinters=fingerprinter_config, + targets=default_agent_configuration.propagation.network_scan.targets, ) return scan_config diff --git a/monkey/tests/unit_tests/infection_monkey/master/test_propagator.py b/monkey/tests/unit_tests/infection_monkey/master/test_propagator.py index b8ceec5dd..53136e755 100644 --- a/monkey/tests/unit_tests/infection_monkey/master/test_propagator.py +++ b/monkey/tests/unit_tests/infection_monkey/master/test_propagator.py @@ -145,15 +145,15 @@ def get_propagation_config( default_agent_configuration, scan_target_config: ScanTargetConfiguration ): network_scan = NetworkScanConfiguration( - default_agent_configuration.propagation.network_scan.tcp, - default_agent_configuration.propagation.network_scan.icmp, - default_agent_configuration.propagation.network_scan.fingerprinters, - scan_target_config, + tcp=default_agent_configuration.propagation.network_scan.tcp, + icmp=default_agent_configuration.propagation.network_scan.icmp, + fingerprinters=default_agent_configuration.propagation.network_scan.fingerprinters, + targets=scan_target_config, ) propagation_config = PropagationConfiguration( - default_agent_configuration.propagation.maximum_depth, - network_scan, - default_agent_configuration.propagation.exploitation, + maximum_depth=default_agent_configuration.propagation.maximum_depth, + network_scan=network_scan, + exploitation=default_agent_configuration.propagation.exploitation, ) return propagation_config From 163c54a8c3f7249e39268c759f915e9add095372 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Tue, 30 Aug 2022 12:28:12 +0530 Subject: [PATCH 28/69] Agent: Replace fields in configuration using pydantic syntax in propagator --- monkey/infection_monkey/master/propagator.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/monkey/infection_monkey/master/propagator.py b/monkey/infection_monkey/master/propagator.py index c11e38d46..03a5d5ec7 100644 --- a/monkey/infection_monkey/master/propagator.py +++ b/monkey/infection_monkey/master/propagator.py @@ -1,5 +1,4 @@ import logging -from dataclasses import replace from ipaddress import IPv4Interface from queue import Queue from threading import Event @@ -93,9 +92,9 @@ class Propagator: modified_options = fingerprinter.options.copy() modified_options["http_ports"] = list(http_ports) - modified_fingerprinters[i] = replace(fingerprinter, options=modified_options) + modified_fingerprinters[i] = fingerprinter.copy(update={"options": modified_options}) - return replace(network_scan, fingerprinters=modified_fingerprinters) + return network_scan.copy(update={"fingerprinters": modified_fingerprinters}) def _scan_network(self, scan_config: NetworkScanConfiguration, stop: Event): logger.info("Starting network scan") From a9a006a9fd78562402c7cf0384dea714d8255070 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Tue, 30 Aug 2022 12:30:10 +0530 Subject: [PATCH 29/69] Agent: Replace fields in configuration using pydantic syntax in PBA file upload resource --- monkey/monkey_island/cc/resources/pba_file_upload.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/monkey/monkey_island/cc/resources/pba_file_upload.py b/monkey/monkey_island/cc/resources/pba_file_upload.py index c62272e7c..d76b8665a 100644 --- a/monkey/monkey_island/cc/resources/pba_file_upload.py +++ b/monkey/monkey_island/cc/resources/pba_file_upload.py @@ -1,5 +1,4 @@ import logging -from dataclasses import replace from http import HTTPStatus from flask import Response, make_response, request, send_file @@ -102,11 +101,15 @@ class PBAFileUpload(AbstractResource): agent_configuration = self._agent_configuration_repository.get_configuration() if target_os == LINUX_PBA_TYPE: - custom_pbas = replace(agent_configuration.custom_pbas, linux_filename=safe_filename) + custom_pbas = agent_configuration.custom_pbas.copy( + update={"linux_filename": safe_filename} + ) else: - custom_pbas = replace(agent_configuration.custom_pbas, windows_filename=safe_filename) + custom_pbas = agent_configuration.custom_pbas.copy( + update={"windows_filename": safe_filename} + ) - updated_agent_configuration = replace(agent_configuration, custom_pbas=custom_pbas) + updated_agent_configuration = agent_configuration.copy(update={"custom_pbas": custom_pbas}) self._agent_configuration_repository.store_configuration(updated_agent_configuration) @jwt_required From f4e3bc2a89516e58bc8c26914e05887156df9fca Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Tue, 30 Aug 2022 12:38:24 +0530 Subject: [PATCH 30/69] Island: Fix AgentConfiguration logic in FileAgentConfigurationRepository --- .../cc/repository/file_agent_configuration_repository.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/monkey/monkey_island/cc/repository/file_agent_configuration_repository.py b/monkey/monkey_island/cc/repository/file_agent_configuration_repository.py index 33bbcec44..7e1d13d8e 100644 --- a/monkey/monkey_island/cc/repository/file_agent_configuration_repository.py +++ b/monkey/monkey_island/cc/repository/file_agent_configuration_repository.py @@ -1,4 +1,5 @@ import io +import json from common.agent_configuration import AgentConfiguration from monkey_island.cc import repository @@ -23,17 +24,17 @@ class FileAgentConfigurationRepository(IAgentConfigurationRepository): with self._file_repository.open_file(AGENT_CONFIGURATION_FILE_NAME) as f: configuration_json = f.read().decode() - return AgentConfiguration.from_json(configuration_json) + return AgentConfiguration(**json.loads(configuration_json)) except repository.FileNotFoundError: return self._default_agent_configuration except Exception as err: raise RetrievalError(f"Error retrieving the agent configuration: {err}") def store_configuration(self, agent_configuration: AgentConfiguration): - configuration_json = AgentConfiguration.to_json(agent_configuration) + configuration_json = agent_configuration.dict() self._file_repository.save_file( - AGENT_CONFIGURATION_FILE_NAME, io.BytesIO(configuration_json.encode()) + AGENT_CONFIGURATION_FILE_NAME, io.BytesIO(json.dumps(configuration_json).encode()) ) def reset_to_default(self): From 016cf80cddaf8facc9e3084d825194e4af3ac3a6 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Tue, 30 Aug 2022 12:39:14 +0530 Subject: [PATCH 31/69] UT: Fix AgentConfiguration object creation logic FileAgentConfigurationRepository tests --- .../cc/repository/test_file_agent_configuration_repository.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/monkey/tests/unit_tests/monkey_island/cc/repository/test_file_agent_configuration_repository.py b/monkey/tests/unit_tests/monkey_island/cc/repository/test_file_agent_configuration_repository.py index 7f9f40d58..7782aa1ed 100644 --- a/monkey/tests/unit_tests/monkey_island/cc/repository/test_file_agent_configuration_repository.py +++ b/monkey/tests/unit_tests/monkey_island/cc/repository/test_file_agent_configuration_repository.py @@ -12,7 +12,7 @@ def repository(default_agent_configuration): def test_store_agent_config(repository): - agent_configuration = AgentConfiguration.from_mapping(AGENT_CONFIGURATION) + agent_configuration = AgentConfiguration(**AGENT_CONFIGURATION) repository.store_configuration(agent_configuration) retrieved_agent_configuration = repository.get_configuration() @@ -36,7 +36,7 @@ def test_get_agent_config_retrieval_error(default_agent_configuration): def test_reset_to_default(repository, default_agent_configuration): - agent_configuration = AgentConfiguration.from_mapping(AGENT_CONFIGURATION) + agent_configuration = AgentConfiguration(**AGENT_CONFIGURATION) repository.store_configuration(agent_configuration) repository.reset_to_default() From f11e2dc8a1177d9af3013c00f8db82eb13422e7f Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Tue, 30 Aug 2022 12:43:49 +0530 Subject: [PATCH 32/69] UT: Fix configuration logic to work with pydantic in `agent_configuration` fixture --- .../monkey_island/cc/services/test_repository_service.py | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/monkey/tests/unit_tests/monkey_island/cc/services/test_repository_service.py b/monkey/tests/unit_tests/monkey_island/cc/services/test_repository_service.py index 202daf263..292936635 100644 --- a/monkey/tests/unit_tests/monkey_island/cc/services/test_repository_service.py +++ b/monkey/tests/unit_tests/monkey_island/cc/services/test_repository_service.py @@ -1,4 +1,3 @@ -from dataclasses import replace from unittest.mock import MagicMock import pytest @@ -18,12 +17,10 @@ WINDOWS_FILENAME = "windows_pba_file.ps1" @pytest.fixture def agent_configuration(default_agent_configuration: AgentConfiguration) -> AgentConfiguration: - custom_pbas = replace( - default_agent_configuration.custom_pbas, - linux_filename=LINUX_FILENAME, - windows_filename=WINDOWS_FILENAME, + custom_pbas = default_agent_configuration.custom_pbas.copy( + update={"linux_filename": LINUX_FILENAME, "windows_filename": WINDOWS_FILENAME}, ) - return replace(default_agent_configuration, custom_pbas=custom_pbas) + return default_agent_configuration.copy(update={"custom_pbas": custom_pbas}) @pytest.fixture From dda79c0809c152a60c6900436211b8f4abc4e6e2 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Tue, 30 Aug 2022 12:52:16 +0530 Subject: [PATCH 33/69] Common: Remove unneeded code for freezing lists to tuples --- monkey/common/agent_configuration/utils.py | 13 ------------- monkey/common/utils/code_utils.py | 8 -------- 2 files changed, 21 deletions(-) delete mode 100644 monkey/common/agent_configuration/utils.py diff --git a/monkey/common/agent_configuration/utils.py b/monkey/common/agent_configuration/utils.py deleted file mode 100644 index 3470e57a1..000000000 --- a/monkey/common/agent_configuration/utils.py +++ /dev/null @@ -1,13 +0,0 @@ -from functools import wraps -from typing import Callable - -from common.utils.code_utils import freeze_lists_in_mapping - - -def freeze_lists(function: Callable): - @wraps(function) - def wrapper(self, data, **kwargs): - data = freeze_lists_in_mapping(data) - return function(self, data, **kwargs) - - return wrapper diff --git a/monkey/common/utils/code_utils.py b/monkey/common/utils/code_utils.py index 52fdcbaac..21c0ce175 100644 --- a/monkey/common/utils/code_utils.py +++ b/monkey/common/utils/code_utils.py @@ -1,5 +1,4 @@ import queue -from collections.abc import MutableSequence from typing import Any, List, MutableMapping, TypeVar T = TypeVar("T") @@ -49,10 +48,3 @@ def del_key(mapping: MutableMapping[T, Any], key: T): del mapping[key] except KeyError: pass - - -def freeze_lists_in_mapping(mapping: MutableMapping[str, Any]) -> MutableMapping[str, Any]: - for key, value in mapping.items(): - if isinstance(value, MutableSequence): - mapping[key] = tuple(value) - return mapping From fe3706c0b4d1c3a098188e1e7ae362447bba9ad4 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Tue, 30 Aug 2022 12:58:10 +0530 Subject: [PATCH 34/69] Common: Remove agent_configuration.InvalidConfigurationError --- monkey/common/agent_configuration/__init__.py | 2 +- .../common/agent_configuration/agent_configuration.py | 11 ----------- 2 files changed, 1 insertion(+), 12 deletions(-) diff --git a/monkey/common/agent_configuration/__init__.py b/monkey/common/agent_configuration/__init__.py index fb52b54e2..f207eadc6 100644 --- a/monkey/common/agent_configuration/__init__.py +++ b/monkey/common/agent_configuration/__init__.py @@ -1,4 +1,4 @@ -from .agent_configuration import AgentConfiguration, InvalidConfigurationError +from .agent_configuration import AgentConfiguration from .agent_sub_configurations import ( CustomPBAConfiguration, PluginConfiguration, diff --git a/monkey/common/agent_configuration/agent_configuration.py b/monkey/common/agent_configuration/agent_configuration.py index 80924257f..d47eb56b9 100644 --- a/monkey/common/agent_configuration/agent_configuration.py +++ b/monkey/common/agent_configuration/agent_configuration.py @@ -13,17 +13,6 @@ from .agent_sub_configurations import ( ) -class InvalidConfigurationError(Exception): - def __init__(self, message: str): - self._message = message - - def __str__(self) -> str: - return ( - f"Cannot construct an AgentConfiguration object with the supplied, invalid data: " - f"{self._message}" - ) - - class AgentConfiguration(MutableInfectionMonkeyBaseModel): keep_tunnel_open_time: PositiveFloat custom_pbas: CustomPBAConfiguration From 9b924c55b6b1feb126be53665d6a18360d005946 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Tue, 30 Aug 2022 12:58:31 +0530 Subject: [PATCH 35/69] Common: Remove utils.InvalidConfigurationError --- monkey/common/utils/exceptions.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/monkey/common/utils/exceptions.py b/monkey/common/utils/exceptions.py index fbc60d863..0f8a8e8c8 100644 --- a/monkey/common/utils/exceptions.py +++ b/monkey/common/utils/exceptions.py @@ -32,9 +32,3 @@ class FindingWithoutDetailsError(Exception): class DomainControllerNameFetchError(FailedExploitationError): """Raise on failed attempt to extract domain controller's name""" - - -# TODO: This has been replaced by common.configuration.InvalidConfigurationError. Use that error -# instead and remove this one. -class InvalidConfigurationError(Exception): - """Raise when configuration is invalid""" From 1f77fd468aa9cd6d9ea6251c56a07886a9ba7433 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Tue, 30 Aug 2022 14:23:57 +0530 Subject: [PATCH 36/69] UT: Add function `convert_lists_to_tuples` to utils --- monkey/tests/utils.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/monkey/tests/utils.py b/monkey/tests/utils.py index b2268e572..d2a9113ae 100644 --- a/monkey/tests/utils.py +++ b/monkey/tests/utils.py @@ -1,7 +1,7 @@ import ctypes import os from pathlib import Path -from typing import Iterable +from typing import Iterable, Mapping def is_user_admin(): @@ -31,3 +31,15 @@ def add_files_to_dir(parent_dir: Path, file_names: Iterable[str]) -> Iterable[Pa f.touch() return files + + +# This is only needed since values are compared in configuration objects in the tests. +# In practice, the list/tuple differences shouldn't make any difference since both are iterable. +def convert_lists_to_tuples(configuration: Mapping): + for key in configuration: + value = configuration[key] + if isinstance(value, list): + configuration[key] = tuple(value) + if isinstance(value, Mapping): + convert_lists_to_tuples(value) + return configuration From eb207de9194e69d7c7aa15f8006d76dc60a4c383 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Tue, 30 Aug 2022 14:24:43 +0530 Subject: [PATCH 37/69] UT: Convert lists to tuples before comparing values in configuration tests Probably not the best way to do this --- .../common/agent_configuration/test_agent_configuration.py | 7 ++++--- .../monkey_island/cc/resources/test_agent_configuration.py | 6 +++++- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/monkey/tests/unit_tests/common/agent_configuration/test_agent_configuration.py b/monkey/tests/unit_tests/common/agent_configuration/test_agent_configuration.py index ed1f1bfa3..cb561aac5 100644 --- a/monkey/tests/unit_tests/common/agent_configuration/test_agent_configuration.py +++ b/monkey/tests/unit_tests/common/agent_configuration/test_agent_configuration.py @@ -23,6 +23,7 @@ from tests.common.example_agent_configuration import ( WINDOWS_COMMAND, WINDOWS_FILENAME, ) +from tests.utils import convert_lists_to_tuples from common.agent_configuration.agent_configuration import AgentConfiguration from common.agent_configuration.agent_sub_configurations import ( @@ -180,7 +181,7 @@ def test_exploitation_configuration(): config_dict = config.dict() assert isinstance(config, ExploitationConfiguration) - assert config_dict == EXPLOITATION_CONFIGURATION + assert config_dict == convert_lists_to_tuples(EXPLOITATION_CONFIGURATION.copy()) def test_propagation_configuration(): @@ -191,7 +192,7 @@ def test_propagation_configuration(): assert isinstance(config.network_scan, NetworkScanConfiguration) assert isinstance(config.exploitation, ExploitationConfiguration) assert config.maximum_depth == 5 - assert config_dict == PROPAGATION_CONFIGURATION + assert config_dict == convert_lists_to_tuples(PROPAGATION_CONFIGURATION.copy()) def test_propagation_configuration__invalid_maximum_depth(): @@ -213,7 +214,7 @@ def test_agent_configuration(): assert isinstance(config.credential_collectors[0], PluginConfiguration) assert isinstance(config.payloads[0], PluginConfiguration) assert isinstance(config.propagation, PropagationConfiguration) - assert config_dict == AGENT_CONFIGURATION + assert config_dict == convert_lists_to_tuples(AGENT_CONFIGURATION.copy()) def test_agent_configuration__negative_keep_tunnel_open_time(): diff --git a/monkey/tests/unit_tests/monkey_island/cc/resources/test_agent_configuration.py b/monkey/tests/unit_tests/monkey_island/cc/resources/test_agent_configuration.py index f2010a59e..9845405c8 100644 --- a/monkey/tests/unit_tests/monkey_island/cc/resources/test_agent_configuration.py +++ b/monkey/tests/unit_tests/monkey_island/cc/resources/test_agent_configuration.py @@ -5,6 +5,7 @@ from tests.common import StubDIContainer from tests.common.example_agent_configuration import AGENT_CONFIGURATION from tests.monkey_island import InMemoryAgentConfigurationRepository from tests.unit_tests.monkey_island.conftest import get_url_for_resource +from tests.utils import convert_lists_to_tuples from common.agent_configuration import AgentConfiguration from monkey_island.cc.repository import IAgentConfigurationRepository @@ -33,7 +34,10 @@ def test_agent_configuration_endpoint(flask_client): resp = flask_client.get(AGENT_CONFIGURATION_URL) assert resp.status_code == 200 - assert json.loads(resp.data) == AGENT_CONFIGURATION + + assert convert_lists_to_tuples(json.loads(resp.data)) == convert_lists_to_tuples( + AGENT_CONFIGURATION.copy() + ) def test_agent_configuration_invalid_config(flask_client): From 82d8f5bacdf48cad6e60623f92d27885570a6239 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Tue, 30 Aug 2022 22:56:02 +0530 Subject: [PATCH 38/69] Island: Simplify JSON logic inFileAgentConfigurationRepository --- .../cc/repository/file_agent_configuration_repository.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/monkey/monkey_island/cc/repository/file_agent_configuration_repository.py b/monkey/monkey_island/cc/repository/file_agent_configuration_repository.py index 7e1d13d8e..ca720d48c 100644 --- a/monkey/monkey_island/cc/repository/file_agent_configuration_repository.py +++ b/monkey/monkey_island/cc/repository/file_agent_configuration_repository.py @@ -31,10 +31,10 @@ class FileAgentConfigurationRepository(IAgentConfigurationRepository): raise RetrievalError(f"Error retrieving the agent configuration: {err}") def store_configuration(self, agent_configuration: AgentConfiguration): - configuration_json = agent_configuration.dict() + configuration_json = agent_configuration.json() self._file_repository.save_file( - AGENT_CONFIGURATION_FILE_NAME, io.BytesIO(json.dumps(configuration_json).encode()) + AGENT_CONFIGURATION_FILE_NAME, io.BytesIO(configuration_json.encode()) ) def reset_to_default(self): From 4f599c311827d4d69408a466628a9dceb2b0779a Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Tue, 30 Aug 2022 23:07:29 +0530 Subject: [PATCH 39/69] UT: Rename `convert_lists_to_tuples` -> `convert_all_lists_to_tuples_in_mapping` --- .../agent_configuration/test_agent_configuration.py | 8 ++++---- .../cc/resources/test_agent_configuration.py | 8 ++++---- monkey/tests/utils.py | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/monkey/tests/unit_tests/common/agent_configuration/test_agent_configuration.py b/monkey/tests/unit_tests/common/agent_configuration/test_agent_configuration.py index cb561aac5..15e768556 100644 --- a/monkey/tests/unit_tests/common/agent_configuration/test_agent_configuration.py +++ b/monkey/tests/unit_tests/common/agent_configuration/test_agent_configuration.py @@ -23,7 +23,7 @@ from tests.common.example_agent_configuration import ( WINDOWS_COMMAND, WINDOWS_FILENAME, ) -from tests.utils import convert_lists_to_tuples +from tests.utils import convert_all_lists_to_tuples_in_mapping from common.agent_configuration.agent_configuration import AgentConfiguration from common.agent_configuration.agent_sub_configurations import ( @@ -181,7 +181,7 @@ def test_exploitation_configuration(): config_dict = config.dict() assert isinstance(config, ExploitationConfiguration) - assert config_dict == convert_lists_to_tuples(EXPLOITATION_CONFIGURATION.copy()) + assert config_dict == convert_all_lists_to_tuples_in_mapping(EXPLOITATION_CONFIGURATION.copy()) def test_propagation_configuration(): @@ -192,7 +192,7 @@ def test_propagation_configuration(): assert isinstance(config.network_scan, NetworkScanConfiguration) assert isinstance(config.exploitation, ExploitationConfiguration) assert config.maximum_depth == 5 - assert config_dict == convert_lists_to_tuples(PROPAGATION_CONFIGURATION.copy()) + assert config_dict == convert_all_lists_to_tuples_in_mapping(PROPAGATION_CONFIGURATION.copy()) def test_propagation_configuration__invalid_maximum_depth(): @@ -214,7 +214,7 @@ def test_agent_configuration(): assert isinstance(config.credential_collectors[0], PluginConfiguration) assert isinstance(config.payloads[0], PluginConfiguration) assert isinstance(config.propagation, PropagationConfiguration) - assert config_dict == convert_lists_to_tuples(AGENT_CONFIGURATION.copy()) + assert config_dict == convert_all_lists_to_tuples_in_mapping(AGENT_CONFIGURATION.copy()) def test_agent_configuration__negative_keep_tunnel_open_time(): diff --git a/monkey/tests/unit_tests/monkey_island/cc/resources/test_agent_configuration.py b/monkey/tests/unit_tests/monkey_island/cc/resources/test_agent_configuration.py index 9845405c8..f3a8abdb0 100644 --- a/monkey/tests/unit_tests/monkey_island/cc/resources/test_agent_configuration.py +++ b/monkey/tests/unit_tests/monkey_island/cc/resources/test_agent_configuration.py @@ -5,7 +5,7 @@ from tests.common import StubDIContainer from tests.common.example_agent_configuration import AGENT_CONFIGURATION from tests.monkey_island import InMemoryAgentConfigurationRepository from tests.unit_tests.monkey_island.conftest import get_url_for_resource -from tests.utils import convert_lists_to_tuples +from tests.utils import convert_all_lists_to_tuples_in_mapping from common.agent_configuration import AgentConfiguration from monkey_island.cc.repository import IAgentConfigurationRepository @@ -35,9 +35,9 @@ def test_agent_configuration_endpoint(flask_client): assert resp.status_code == 200 - assert convert_lists_to_tuples(json.loads(resp.data)) == convert_lists_to_tuples( - AGENT_CONFIGURATION.copy() - ) + assert convert_all_lists_to_tuples_in_mapping( + json.loads(resp.data) + ) == convert_all_lists_to_tuples_in_mapping(AGENT_CONFIGURATION.copy()) def test_agent_configuration_invalid_config(flask_client): diff --git a/monkey/tests/utils.py b/monkey/tests/utils.py index d2a9113ae..1211e72bc 100644 --- a/monkey/tests/utils.py +++ b/monkey/tests/utils.py @@ -35,11 +35,11 @@ def add_files_to_dir(parent_dir: Path, file_names: Iterable[str]) -> Iterable[Pa # This is only needed since values are compared in configuration objects in the tests. # In practice, the list/tuple differences shouldn't make any difference since both are iterable. -def convert_lists_to_tuples(configuration: Mapping): +def convert_all_lists_to_tuples_in_mapping(configuration: Mapping): for key in configuration: value = configuration[key] if isinstance(value, list): configuration[key] = tuple(value) if isinstance(value, Mapping): - convert_lists_to_tuples(value) + convert_all_lists_to_tuples_in_mapping(value) return configuration From 623426374679e3a520d8bdf752e851e48d011949 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Tue, 30 Aug 2022 23:39:35 +0530 Subject: [PATCH 40/69] Island: Simplify configuration updating logic in PBAFileUpload --- monkey/monkey_island/cc/resources/pba_file_upload.py | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/monkey/monkey_island/cc/resources/pba_file_upload.py b/monkey/monkey_island/cc/resources/pba_file_upload.py index d76b8665a..ef57b2429 100644 --- a/monkey/monkey_island/cc/resources/pba_file_upload.py +++ b/monkey/monkey_island/cc/resources/pba_file_upload.py @@ -101,16 +101,9 @@ class PBAFileUpload(AbstractResource): agent_configuration = self._agent_configuration_repository.get_configuration() if target_os == LINUX_PBA_TYPE: - custom_pbas = agent_configuration.custom_pbas.copy( - update={"linux_filename": safe_filename} - ) + agent_configuration.custom_pbas.linux_filename = safe_filename else: - custom_pbas = agent_configuration.custom_pbas.copy( - update={"windows_filename": safe_filename} - ) - - updated_agent_configuration = agent_configuration.copy(update={"custom_pbas": custom_pbas}) - self._agent_configuration_repository.store_configuration(updated_agent_configuration) + agent_configuration.custom_pbas.windows_filename = safe_filename @jwt_required def delete(self, target_os): From 5b1558ce53680424774e2ae415f2bdaa91a6ca54 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Tue, 30 Aug 2022 23:43:53 +0530 Subject: [PATCH 41/69] Project: Include classes in Vulture allowlist --- vulture_allowlist.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/vulture_allowlist.py b/vulture_allowlist.py index 483b5343b..678e9a22c 100644 --- a/vulture_allowlist.py +++ b/vulture_allowlist.py @@ -3,6 +3,10 @@ Everything in this file is what Vulture found as dead code but either isn't real dead or is kept deliberately. Referencing these in a file like this makes sure that Vulture doesn't mark these as dead again. """ +from common.agent_configuration.agent_sub_configurations import ( + CustomPBAConfiguration, + ScanTargetConfiguration, +) from infection_monkey.exploit.log4shell_utils.ldap_server import LDAPServerFactory from monkey_island.cc.models import Report from monkey_island.cc.models.networkmap import Arc, NetworkMap @@ -294,11 +298,11 @@ underscore_attrs_are_private extra allow_mutation validate_assignment -linux_filename_valid -windows_filename_valid -blocked_ips_valid -inaccessible_subnets_valid -subnets_valid +CustomPBAConfiguration.linux_filename_valid +CustomPBAConfiguration.windows_filename_valid +ScanTargetConfiguration.blocked_ips_valid +ScanTargetConfiguration.inaccessible_subnets_valid +ScanTargetConfiguration.subnets_valid # CommunicationType CommunicationType From f7f00478687d4a0b4d787fa2863d7141c2f64bdc Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Tue, 30 Aug 2022 23:57:48 +0530 Subject: [PATCH 42/69] UT: Simplify assertion logic in test_agent_configuration_endpoint --- .../monkey_island/cc/resources/test_agent_configuration.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/monkey/tests/unit_tests/monkey_island/cc/resources/test_agent_configuration.py b/monkey/tests/unit_tests/monkey_island/cc/resources/test_agent_configuration.py index f3a8abdb0..b8c417e6d 100644 --- a/monkey/tests/unit_tests/monkey_island/cc/resources/test_agent_configuration.py +++ b/monkey/tests/unit_tests/monkey_island/cc/resources/test_agent_configuration.py @@ -5,7 +5,6 @@ from tests.common import StubDIContainer from tests.common.example_agent_configuration import AGENT_CONFIGURATION from tests.monkey_island import InMemoryAgentConfigurationRepository from tests.unit_tests.monkey_island.conftest import get_url_for_resource -from tests.utils import convert_all_lists_to_tuples_in_mapping from common.agent_configuration import AgentConfiguration from monkey_island.cc.repository import IAgentConfigurationRepository @@ -35,9 +34,7 @@ def test_agent_configuration_endpoint(flask_client): assert resp.status_code == 200 - assert convert_all_lists_to_tuples_in_mapping( - json.loads(resp.data) - ) == convert_all_lists_to_tuples_in_mapping(AGENT_CONFIGURATION.copy()) + assert AgentConfiguration(**json.loads(resp.data)) == AgentConfiguration(**AGENT_CONFIGURATION) def test_agent_configuration_invalid_config(flask_client): From fa1620ebb9ffc45dfaf9e71409e71e4a7c84191b Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Wed, 31 Aug 2022 00:43:53 +0530 Subject: [PATCH 43/69] UT: Add tests for checking that validators in ScanTargetConfiguration work --- .../test_agent_configuration.py | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/monkey/tests/unit_tests/common/agent_configuration/test_agent_configuration.py b/monkey/tests/unit_tests/common/agent_configuration/test_agent_configuration.py index 15e768556..cd7344b2a 100644 --- a/monkey/tests/unit_tests/common/agent_configuration/test_agent_configuration.py +++ b/monkey/tests/unit_tests/common/agent_configuration/test_agent_configuration.py @@ -98,6 +98,35 @@ def test_scan_target_configuration(): assert config.subnets == tuple(SUBNETS) +@pytest.mark.parametrize("invalid_blocked_ip_list", [["abc"], [1]]) +def test_scan_target_configuration__invalid_blocked_ips(invalid_blocked_ip_list): + invalid_blocked_ips = SCAN_TARGET_CONFIGURATION.copy() + invalid_blocked_ips["blocked_ips"] = invalid_blocked_ip_list + + with pytest.raises(ValueError): + ScanTargetConfiguration(**invalid_blocked_ips) + + +@pytest.mark.parametrize( + "invalid_inaccessible_subnets_list", [["1-2-3"], ["0.0.0.0/33"], ["www.invalid-.com"]] +) +def test_scan_target_configuration__invalid_inaccessible_subnets(invalid_inaccessible_subnets_list): + invalid_inaccessible_subnets = SCAN_TARGET_CONFIGURATION.copy() + invalid_inaccessible_subnets["inaccessible_subnets"] = invalid_inaccessible_subnets_list + + with pytest.raises(ValueError): + ScanTargetConfiguration(**invalid_inaccessible_subnets) + + +@pytest.mark.parametrize("invalid_subnets_list", [["1-2-3"], ["0.0.0.0/33"], ["www.invalid-.com"]]) +def test_scan_target_configuration__invalid_subnets(invalid_subnets_list): + invalid_subnets = SCAN_TARGET_CONFIGURATION.copy() + invalid_subnets["subnets"] = invalid_subnets_list + + with pytest.raises(ValueError): + ScanTargetConfiguration(**invalid_subnets) + + def test_icmp_scan_configuration_schema(): config = ICMPScanConfiguration(**ICMP_CONFIGURATION) From d5ee4c7f27d24d6b39e2de46bbf4e2ca71748a8b Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Wed, 31 Aug 2022 00:51:27 +0530 Subject: [PATCH 44/69] Island: Use `simplify=True` when converting configuration to dict --- monkey/monkey_island/cc/resources/agent_configuration.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/monkey/monkey_island/cc/resources/agent_configuration.py b/monkey/monkey_island/cc/resources/agent_configuration.py index 297c8c79f..b97d23161 100644 --- a/monkey/monkey_island/cc/resources/agent_configuration.py +++ b/monkey/monkey_island/cc/resources/agent_configuration.py @@ -19,7 +19,7 @@ class AgentConfiguration(AbstractResource): # Used by the agent. Can't secure def get(self): configuration = self._agent_configuration_repository.get_configuration() - configuration_dict = configuration.dict() + configuration_dict = configuration.dict(simplify=True) return make_response(configuration_dict, 200) @jwt_required From 6460639f91c67ec9c7466bbcc516587cd4a28d59 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Wed, 31 Aug 2022 00:53:18 +0530 Subject: [PATCH 45/69] UT: Use `simplify=True` when converting configuration to dict --- .../common/agent_configuration/test_agent_configuration.py | 6 +++--- .../monkey_island/cc/resources/test_agent_configuration.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/monkey/tests/unit_tests/common/agent_configuration/test_agent_configuration.py b/monkey/tests/unit_tests/common/agent_configuration/test_agent_configuration.py index cd7344b2a..72ac501c7 100644 --- a/monkey/tests/unit_tests/common/agent_configuration/test_agent_configuration.py +++ b/monkey/tests/unit_tests/common/agent_configuration/test_agent_configuration.py @@ -207,7 +207,7 @@ def test_exploiter_configuration_schema(): def test_exploitation_configuration(): config = ExploitationConfiguration(**EXPLOITATION_CONFIGURATION) - config_dict = config.dict() + config_dict = config.dict(simplify=True) assert isinstance(config, ExploitationConfiguration) assert config_dict == convert_all_lists_to_tuples_in_mapping(EXPLOITATION_CONFIGURATION.copy()) @@ -215,7 +215,7 @@ def test_exploitation_configuration(): def test_propagation_configuration(): config = PropagationConfiguration(**PROPAGATION_CONFIGURATION) - config_dict = config.dict() + config_dict = config.dict(simplify=True) assert isinstance(config, PropagationConfiguration) assert isinstance(config.network_scan, NetworkScanConfiguration) @@ -234,7 +234,7 @@ def test_propagation_configuration__invalid_maximum_depth(): def test_agent_configuration(): config = AgentConfiguration(**AGENT_CONFIGURATION) - config_dict = config.dict() + config_dict = config.dict(simplify=True) assert isinstance(config, AgentConfiguration) assert config.keep_tunnel_open_time == 30 diff --git a/monkey/tests/unit_tests/monkey_island/cc/resources/test_agent_configuration.py b/monkey/tests/unit_tests/monkey_island/cc/resources/test_agent_configuration.py index b8c417e6d..83243c6c8 100644 --- a/monkey/tests/unit_tests/monkey_island/cc/resources/test_agent_configuration.py +++ b/monkey/tests/unit_tests/monkey_island/cc/resources/test_agent_configuration.py @@ -26,7 +26,7 @@ def flask_client(build_flask_client): def test_agent_configuration_endpoint(flask_client): resp = flask_client.put( AGENT_CONFIGURATION_URL, - json=AgentConfiguration(**AGENT_CONFIGURATION).dict(), + json=AgentConfiguration(**AGENT_CONFIGURATION).dict(simplify=True), follow_redirects=True, ) assert resp.status_code == 200 From 9db1a19ad3220686d9d3e465152a183d2094d34f Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Wed, 31 Aug 2022 00:57:13 +0530 Subject: [PATCH 46/69] UT: Simplify assertion logic in common/agent_configuration/test_agent_configuration.py --- .../common/agent_configuration/test_agent_configuration.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/monkey/tests/unit_tests/common/agent_configuration/test_agent_configuration.py b/monkey/tests/unit_tests/common/agent_configuration/test_agent_configuration.py index 72ac501c7..805bef81f 100644 --- a/monkey/tests/unit_tests/common/agent_configuration/test_agent_configuration.py +++ b/monkey/tests/unit_tests/common/agent_configuration/test_agent_configuration.py @@ -23,7 +23,6 @@ from tests.common.example_agent_configuration import ( WINDOWS_COMMAND, WINDOWS_FILENAME, ) -from tests.utils import convert_all_lists_to_tuples_in_mapping from common.agent_configuration.agent_configuration import AgentConfiguration from common.agent_configuration.agent_sub_configurations import ( @@ -210,7 +209,7 @@ def test_exploitation_configuration(): config_dict = config.dict(simplify=True) assert isinstance(config, ExploitationConfiguration) - assert config_dict == convert_all_lists_to_tuples_in_mapping(EXPLOITATION_CONFIGURATION.copy()) + assert config_dict == EXPLOITATION_CONFIGURATION def test_propagation_configuration(): @@ -221,7 +220,7 @@ def test_propagation_configuration(): assert isinstance(config.network_scan, NetworkScanConfiguration) assert isinstance(config.exploitation, ExploitationConfiguration) assert config.maximum_depth == 5 - assert config_dict == convert_all_lists_to_tuples_in_mapping(PROPAGATION_CONFIGURATION.copy()) + assert config_dict == PROPAGATION_CONFIGURATION def test_propagation_configuration__invalid_maximum_depth(): @@ -243,7 +242,7 @@ def test_agent_configuration(): assert isinstance(config.credential_collectors[0], PluginConfiguration) assert isinstance(config.payloads[0], PluginConfiguration) assert isinstance(config.propagation, PropagationConfiguration) - assert config_dict == convert_all_lists_to_tuples_in_mapping(AGENT_CONFIGURATION.copy()) + assert config_dict == AGENT_CONFIGURATION def test_agent_configuration__negative_keep_tunnel_open_time(): From 46ee6de13e340b8ccf7f4f1f8340e9c1de196123 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Wed, 31 Aug 2022 00:58:01 +0530 Subject: [PATCH 47/69] UT: Remove unneeded function `convert_all_lists_to_tuples_in_mapping()` --- monkey/tests/utils.py | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/monkey/tests/utils.py b/monkey/tests/utils.py index 1211e72bc..b2268e572 100644 --- a/monkey/tests/utils.py +++ b/monkey/tests/utils.py @@ -1,7 +1,7 @@ import ctypes import os from pathlib import Path -from typing import Iterable, Mapping +from typing import Iterable def is_user_admin(): @@ -31,15 +31,3 @@ def add_files_to_dir(parent_dir: Path, file_names: Iterable[str]) -> Iterable[Pa f.touch() return files - - -# This is only needed since values are compared in configuration objects in the tests. -# In practice, the list/tuple differences shouldn't make any difference since both are iterable. -def convert_all_lists_to_tuples_in_mapping(configuration: Mapping): - for key in configuration: - value = configuration[key] - if isinstance(value, list): - configuration[key] = tuple(value) - if isinstance(value, Mapping): - convert_all_lists_to_tuples_in_mapping(value) - return configuration From 1444ce10c3d261417933484091c43bda1b167f0c Mon Sep 17 00:00:00 2001 From: Mike Salvatore Date: Wed, 31 Aug 2022 08:00:24 -0400 Subject: [PATCH 48/69] Common: Remove unneeded `import annotations` from agent_configuration --- monkey/common/agent_configuration/agent_configuration.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/monkey/common/agent_configuration/agent_configuration.py b/monkey/common/agent_configuration/agent_configuration.py index d47eb56b9..1fb99f868 100644 --- a/monkey/common/agent_configuration/agent_configuration.py +++ b/monkey/common/agent_configuration/agent_configuration.py @@ -1,5 +1,3 @@ -from __future__ import annotations - from typing import Tuple from pydantic import PositiveFloat From 8d991f462f4aab2f6b3fc9409140190989c58804 Mon Sep 17 00:00:00 2001 From: Mike Salvatore Date: Wed, 31 Aug 2022 08:31:41 -0400 Subject: [PATCH 49/69] UT: Use kwargs instead of **dict in test_agent_configuration.py --- .../agent_configuration/test_agent_configuration.py | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/monkey/tests/unit_tests/common/agent_configuration/test_agent_configuration.py b/monkey/tests/unit_tests/common/agent_configuration/test_agent_configuration.py index 805bef81f..0cd17fccc 100644 --- a/monkey/tests/unit_tests/common/agent_configuration/test_agent_configuration.py +++ b/monkey/tests/unit_tests/common/agent_configuration/test_agent_configuration.py @@ -181,24 +181,22 @@ def test_network_scan_configuration(): def test_exploitation_options_configuration_schema(): ports = [1, 2, 3] - config = ExploitationOptionsConfiguration(**{"http_ports": ports}) + config = ExploitationOptionsConfiguration(http_ports=ports) assert config.http_ports == tuple(ports) @pytest.mark.parametrize("ports", INVALID_PORTS) def test_exploitation_options_configuration_schema__ports_out_of_range(ports): - invalid_ports_configuration = {"http_ports": ports} - with pytest.raises(ValueError): - ExploitationOptionsConfiguration(**invalid_ports_configuration) + ExploitationOptionsConfiguration(http_ports=ports) def test_exploiter_configuration_schema(): name = "bond" options = {"gun": "Walther PPK", "car": "Aston Martin DB5"} - config = PluginConfiguration(**{"name": name, "options": options}) + config = PluginConfiguration(name=name, options=options) assert config.name == name assert config.options == options From 326d128be870bfed088fcf685515825d78b2f3b0 Mon Sep 17 00:00:00 2001 From: Mike Salvatore Date: Wed, 31 Aug 2022 08:53:10 -0400 Subject: [PATCH 50/69] Common: Allow 0 for maximum_depth --- .../agent_configuration/agent_sub_configurations.py | 4 ++-- .../agent_configuration/test_agent_configuration.py | 9 +++++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/monkey/common/agent_configuration/agent_sub_configurations.py b/monkey/common/agent_configuration/agent_sub_configurations.py index e358c91a9..8c4592d92 100644 --- a/monkey/common/agent_configuration/agent_sub_configurations.py +++ b/monkey/common/agent_configuration/agent_sub_configurations.py @@ -1,6 +1,6 @@ from typing import Dict, Tuple -from pydantic import PositiveFloat, PositiveInt, conint, validator +from pydantic import PositiveFloat, conint, validator from common.base_models import MutableInfectionMonkeyBaseModel @@ -185,6 +185,6 @@ class PropagationConfiguration(MutableInfectionMonkeyBaseModel): :param exploitation: Configuration for exploitation """ - maximum_depth: PositiveInt + maximum_depth: conint(ge=0) network_scan: NetworkScanConfiguration exploitation: ExploitationConfiguration diff --git a/monkey/tests/unit_tests/common/agent_configuration/test_agent_configuration.py b/monkey/tests/unit_tests/common/agent_configuration/test_agent_configuration.py index 0cd17fccc..3431b980d 100644 --- a/monkey/tests/unit_tests/common/agent_configuration/test_agent_configuration.py +++ b/monkey/tests/unit_tests/common/agent_configuration/test_agent_configuration.py @@ -229,6 +229,15 @@ def test_propagation_configuration__invalid_maximum_depth(): PropagationConfiguration(**negative_maximum_depth_configuration) +def test_propagation_configuration__maximum_depth_zero(): + maximum_depth_zero_configuration = PROPAGATION_CONFIGURATION.copy() + maximum_depth_zero_configuration["maximum_depth"] = 0 + + pc = PropagationConfiguration(**maximum_depth_zero_configuration) + + assert pc.maximum_depth == 0 + + def test_agent_configuration(): config = AgentConfiguration(**AGENT_CONFIGURATION) config_dict = config.dict(simplify=True) From 0f21ad2e095d8dea51ec4e4b71c6cadec04df32a Mon Sep 17 00:00:00 2001 From: Mike Salvatore Date: Wed, 31 Aug 2022 08:55:56 -0400 Subject: [PATCH 51/69] Common: Allow 0 for keep_tunnel_open_time --- .../common/agent_configuration/agent_configuration.py | 4 ++-- .../agent_configuration/test_agent_configuration.py | 11 ++++++++++- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/monkey/common/agent_configuration/agent_configuration.py b/monkey/common/agent_configuration/agent_configuration.py index 1fb99f868..7b780096f 100644 --- a/monkey/common/agent_configuration/agent_configuration.py +++ b/monkey/common/agent_configuration/agent_configuration.py @@ -1,6 +1,6 @@ from typing import Tuple -from pydantic import PositiveFloat +from pydantic import confloat from common.base_models import MutableInfectionMonkeyBaseModel @@ -12,7 +12,7 @@ from .agent_sub_configurations import ( class AgentConfiguration(MutableInfectionMonkeyBaseModel): - keep_tunnel_open_time: PositiveFloat + keep_tunnel_open_time: confloat(ge=0) custom_pbas: CustomPBAConfiguration post_breach_actions: Tuple[PluginConfiguration, ...] credential_collectors: Tuple[PluginConfiguration, ...] diff --git a/monkey/tests/unit_tests/common/agent_configuration/test_agent_configuration.py b/monkey/tests/unit_tests/common/agent_configuration/test_agent_configuration.py index 3431b980d..b90490906 100644 --- a/monkey/tests/unit_tests/common/agent_configuration/test_agent_configuration.py +++ b/monkey/tests/unit_tests/common/agent_configuration/test_agent_configuration.py @@ -252,7 +252,16 @@ def test_agent_configuration(): assert config_dict == AGENT_CONFIGURATION -def test_agent_configuration__negative_keep_tunnel_open_time(): +def test_agent_configuration__negative_keep_tunnel_open_time_zero(): + keep_tunnel_open_time_zero_configuration = AGENT_CONFIGURATION.copy() + keep_tunnel_open_time_zero_configuration["keep_tunnel_open_time"] = 0 + + ac = AgentConfiguration(**keep_tunnel_open_time_zero_configuration) + + assert ac.keep_tunnel_open_time == 0 + + +def test_agent_configuration__keep_tunnel_open_time(): negative_keep_tunnel_open_time_configuration = AGENT_CONFIGURATION.copy() negative_keep_tunnel_open_time_configuration["keep_tunnel_open_time"] = -1 From f841bc041b580486f9e2650126b494212f7b44da Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Fri, 2 Sep 2022 11:08:12 +0530 Subject: [PATCH 52/69] Agent: Fix AgentConfiguration object creation logic in ControlChannel.get_config() --- monkey/infection_monkey/master/control_channel.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/monkey/infection_monkey/master/control_channel.py b/monkey/infection_monkey/master/control_channel.py index 93fa67fa6..713ac3aac 100644 --- a/monkey/infection_monkey/master/control_channel.py +++ b/monkey/infection_monkey/master/control_channel.py @@ -93,9 +93,11 @@ class ControlChannel(IControlChannel): ) response.raise_for_status() - logger.debug(f"Received configuration:\n{pformat(json.loads(response.text))}") + config_dict = json.loads(response.text) - return AgentConfiguration.from_json(response.text) + logger.debug(f"Received configuration:\n{pformat(config_dict)}") + + return AgentConfiguration(**config_dict) except ( json.JSONDecodeError, requests.exceptions.ConnectionError, From ff52fbefe46424b5313f4de6410deb6da36dce50 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Tue, 30 Aug 2022 17:17:19 +0530 Subject: [PATCH 53/69] BB: Fix AgentConfiguration logic in MonkeyIslandClient --- envs/monkey_zoo/blackbox/island_client/monkey_island_client.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/envs/monkey_zoo/blackbox/island_client/monkey_island_client.py b/envs/monkey_zoo/blackbox/island_client/monkey_island_client.py index 03ab56d22..43394f24c 100644 --- a/envs/monkey_zoo/blackbox/island_client/monkey_island_client.py +++ b/envs/monkey_zoo/blackbox/island_client/monkey_island_client.py @@ -5,7 +5,6 @@ from typing import Sequence, Union from bson import json_util -from common.agent_configuration import AgentConfiguration from common.credentials import Credentials from envs.monkey_zoo.blackbox.island_client.monkey_island_requests import MonkeyIslandRequests from envs.monkey_zoo.blackbox.test_configurations.test_configuration import TestConfiguration @@ -51,7 +50,7 @@ class MonkeyIslandClient(object): def _import_config(self, test_configuration: TestConfiguration): response = self.requests.put_json( "api/agent-configuration", - json=AgentConfiguration.to_mapping(test_configuration.agent_configuration), + json=test_configuration.agent_configuration.dict(), ) if response.ok: LOGGER.info("Configuration is imported.") From a65415588ffd96487dc551ea350f217c0fa1922a Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Tue, 30 Aug 2022 18:03:45 +0530 Subject: [PATCH 54/69] BB: Simplify logic in BB tests' configurations --- .../blackbox/test_configurations/utils.py | 64 +++++++++---------- 1 file changed, 30 insertions(+), 34 deletions(-) diff --git a/envs/monkey_zoo/blackbox/test_configurations/utils.py b/envs/monkey_zoo/blackbox/test_configurations/utils.py index af7a2368b..29ee47c6b 100644 --- a/envs/monkey_zoo/blackbox/test_configurations/utils.py +++ b/envs/monkey_zoo/blackbox/test_configurations/utils.py @@ -20,78 +20,74 @@ def add_exploiters( brute_force: Sequence[PluginConfiguration] = [], vulnerability: Sequence[PluginConfiguration] = [], ) -> AgentConfiguration: - exploitation_configuration = replace( - agent_configuration.propagation.exploitation, - brute_force=brute_force, - vulnerability=vulnerability, - ) - return replace_exploitation_configuration(agent_configuration, exploitation_configuration) + + agent_configuration.propagation.exploitation.brute_force = brute_force + agent_configuration.propagation.exploitation.vulnerability = vulnerability + + return agent_configuration def add_fingerprinters( agent_configuration: AgentConfiguration, fingerprinters: Sequence[PluginConfiguration] ) -> AgentConfiguration: - network_scan_configuration = replace( - agent_configuration.propagation.network_scan, fingerprinters=fingerprinters - ) - return replace_network_scan_configuration(agent_configuration, network_scan_configuration) + agent_configuration.propagation.network_scan.fingerprinters = fingerprinters + + return agent_configuration def add_tcp_ports( agent_configuration: AgentConfiguration, tcp_ports: Sequence[int] ) -> AgentConfiguration: - tcp_scan_configuration = replace( - agent_configuration.propagation.network_scan.tcp, ports=tuple(tcp_ports) - ) - network_scan_configuration = replace( - agent_configuration.propagation.network_scan, tcp=tcp_scan_configuration - ) - return replace_network_scan_configuration(agent_configuration, network_scan_configuration) + agent_configuration.propagation.network_scan.tcp.ports = tuple(tcp_ports) + + return agent_configuration def add_subnets( agent_configuration: AgentConfiguration, subnets: Sequence[str] ) -> AgentConfiguration: - scan_target_configuration = replace( - agent_configuration.propagation.network_scan.targets, subnets=subnets - ) - return replace_scan_target_configuration(agent_configuration, scan_target_configuration) + + agent_configuration.propagation.network_scan.targets.subnets = subnets + + return agent_configuration def add_credential_collectors( agent_configuration: AgentConfiguration, credential_collectors: Sequence[PluginConfiguration] ) -> AgentConfiguration: - return replace(agent_configuration, credential_collectors=tuple(credential_collectors)) + + agent_configuration.credential_collectors = tuple(credential_collectors) + + return agent_configuration def add_http_ports( agent_configuration: AgentConfiguration, http_ports: Sequence[int] ) -> AgentConfiguration: - exploitation_options_configuration = agent_configuration.propagation.exploitation.options - exploitation_options_configuration = replace( - exploitation_options_configuration, http_ports=http_ports - ) - return replace_exploitation_options_configuration( - agent_configuration, exploitation_options_configuration - ) + agent_configuration.propagation.exploitation.options.http_ports = http_ports + + return agent_configuration def set_keep_tunnel_open_time( agent_configuration: AgentConfiguration, keep_tunnel_open_time: int ) -> AgentConfiguration: - return replace(agent_configuration, keep_tunnel_open_time=keep_tunnel_open_time) + + agent_configuration.keep_tunnel_open_time = keep_tunnel_open_time + + return agent_configuration def set_maximum_depth( agent_configuration: AgentConfiguration, maximum_depth: int ) -> AgentConfiguration: - propagation_configuration = replace( - agent_configuration.propagation, maximum_depth=maximum_depth - ) - return replace_propagation_configuration(agent_configuration, propagation_configuration) + + agent_configuration.propagation.maximum_depth = maximum_depth + + return agent_configuration def replace_exploitation_configuration( From c7ee48fff1837ce522b0ba35bf94da3afe6ff5af Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Tue, 30 Aug 2022 18:12:46 +0530 Subject: [PATCH 55/69] BB: Remove unneeded configuration replacing functions --- .../blackbox/test_configurations/utils.py | 74 +------------------ 1 file changed, 2 insertions(+), 72 deletions(-) diff --git a/envs/monkey_zoo/blackbox/test_configurations/utils.py b/envs/monkey_zoo/blackbox/test_configurations/utils.py index 29ee47c6b..d5bad8afc 100644 --- a/envs/monkey_zoo/blackbox/test_configurations/utils.py +++ b/envs/monkey_zoo/blackbox/test_configurations/utils.py @@ -1,18 +1,6 @@ -from dataclasses import replace -from typing import Sequence, Tuple +from typing import Sequence -from common.agent_configuration import ( - AgentConfiguration, - ExploitationConfiguration, - ExploitationOptionsConfiguration, - NetworkScanConfiguration, - PluginConfiguration, - PropagationConfiguration, - ScanTargetConfiguration, -) -from common.credentials import Credentials - -from . import TestConfiguration +from common.agent_configuration import AgentConfiguration, PluginConfiguration def add_exploiters( @@ -88,61 +76,3 @@ def set_maximum_depth( agent_configuration.propagation.maximum_depth = maximum_depth return agent_configuration - - -def replace_exploitation_configuration( - agent_configuration: AgentConfiguration, exploitation_configuration: ExploitationConfiguration -) -> AgentConfiguration: - propagation_configuration = replace( - agent_configuration.propagation, exploitation=exploitation_configuration - ) - - return replace_propagation_configuration(agent_configuration, propagation_configuration) - - -def replace_scan_target_configuration( - agent_configuration: AgentConfiguration, scan_target_configuration: ScanTargetConfiguration -) -> AgentConfiguration: - network_scan_configuration = replace( - agent_configuration.propagation.network_scan, targets=scan_target_configuration - ) - - return replace_network_scan_configuration(agent_configuration, network_scan_configuration) - - -def replace_network_scan_configuration( - agent_configuration: AgentConfiguration, network_scan_configuration: NetworkScanConfiguration -) -> AgentConfiguration: - propagation_configuration = replace( - agent_configuration.propagation, network_scan=network_scan_configuration - ) - return replace_propagation_configuration(agent_configuration, propagation_configuration) - - -def replace_propagation_configuration( - agent_configuration: AgentConfiguration, propagation_configuration: PropagationConfiguration -) -> AgentConfiguration: - return replace(agent_configuration, propagation=propagation_configuration) - - -def replace_exploitation_options_configuration( - agent_configuration: AgentConfiguration, - exploitation_options_configuration: ExploitationOptionsConfiguration, -) -> AgentConfiguration: - exploitation_configuration = agent_configuration.propagation.exploitation - exploitation_configuration = replace( - exploitation_configuration, options=exploitation_options_configuration - ) - return replace_exploitation_configuration(agent_configuration, exploitation_configuration) - - -def replace_agent_configuration( - test_configuration: TestConfiguration, agent_configuration: AgentConfiguration -) -> TestConfiguration: - return replace(test_configuration, agent_configuration=agent_configuration) - - -def replace_propagation_credentials( - test_configuration: TestConfiguration, propagation_credentials: Tuple[Credentials, ...] -): - return replace(test_configuration, propagation_credentials=propagation_credentials) From 446524b5b8c510bb6713f6dbd8e8b4d414bee3fd Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Tue, 30 Aug 2022 18:18:12 +0530 Subject: [PATCH 56/69] BB: Use keyword arguments where missing in configuration objects' creation --- envs/monkey_zoo/blackbox/test_configurations/noop.py | 4 +++- envs/monkey_zoo/blackbox/test_configurations/wmi_mimikatz.py | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/envs/monkey_zoo/blackbox/test_configurations/noop.py b/envs/monkey_zoo/blackbox/test_configurations/noop.py index 5fc3f90a7..095bd3a12 100644 --- a/envs/monkey_zoo/blackbox/test_configurations/noop.py +++ b/envs/monkey_zoo/blackbox/test_configurations/noop.py @@ -12,7 +12,9 @@ from common.agent_configuration import ( from . import TestConfiguration -_custom_pba_configuration = CustomPBAConfiguration("", "", "", "") +_custom_pba_configuration = CustomPBAConfiguration( + linux_command="", linux_filename="", windows_command="", windows_filename="" +) _tcp_scan_configuration = TCPScanConfiguration(timeout=3.0, ports=[]) _icmp_scan_configuration = ICMPScanConfiguration(timeout=1.0) diff --git a/envs/monkey_zoo/blackbox/test_configurations/wmi_mimikatz.py b/envs/monkey_zoo/blackbox/test_configurations/wmi_mimikatz.py index 018b83075..fe4a1414e 100644 --- a/envs/monkey_zoo/blackbox/test_configurations/wmi_mimikatz.py +++ b/envs/monkey_zoo/blackbox/test_configurations/wmi_mimikatz.py @@ -31,7 +31,7 @@ def _add_subnets(agent_configuration: AgentConfiguration) -> AgentConfiguration: def _add_credential_collectors(agent_configuration: AgentConfiguration) -> AgentConfiguration: return add_credential_collectors( - agent_configuration, [PluginConfiguration("MimikatzCollector", {})] + agent_configuration, [PluginConfiguration(name="MimikatzCollector", options={})] ) From 637023c56883ab29ea5c0ce195ac66ba76cbe084 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Thu, 1 Sep 2022 12:54:54 +0530 Subject: [PATCH 57/69] BB: Create copy of agent configuration when updating it for different tests --- .../blackbox/test_configurations/utils.py | 42 +++++++++++-------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/envs/monkey_zoo/blackbox/test_configurations/utils.py b/envs/monkey_zoo/blackbox/test_configurations/utils.py index d5bad8afc..c1b6b54f8 100644 --- a/envs/monkey_zoo/blackbox/test_configurations/utils.py +++ b/envs/monkey_zoo/blackbox/test_configurations/utils.py @@ -9,70 +9,78 @@ def add_exploiters( vulnerability: Sequence[PluginConfiguration] = [], ) -> AgentConfiguration: - agent_configuration.propagation.exploitation.brute_force = brute_force - agent_configuration.propagation.exploitation.vulnerability = vulnerability + agent_configuration_copy = agent_configuration.copy() + agent_configuration_copy.propagation.exploitation.brute_force = brute_force + agent_configuration_copy.propagation.exploitation.vulnerability = vulnerability - return agent_configuration + return agent_configuration_copy def add_fingerprinters( agent_configuration: AgentConfiguration, fingerprinters: Sequence[PluginConfiguration] ) -> AgentConfiguration: - agent_configuration.propagation.network_scan.fingerprinters = fingerprinters + agent_configuration_copy = agent_configuration.copy() + agent_configuration_copy.propagation.network_scan.fingerprinters = fingerprinters - return agent_configuration + return agent_configuration_copy def add_tcp_ports( agent_configuration: AgentConfiguration, tcp_ports: Sequence[int] ) -> AgentConfiguration: - agent_configuration.propagation.network_scan.tcp.ports = tuple(tcp_ports) + agent_configuration_copy = agent_configuration.copy() + agent_configuration_copy.propagation.network_scan.tcp.ports = tuple(tcp_ports) - return agent_configuration + return agent_configuration_copy def add_subnets( agent_configuration: AgentConfiguration, subnets: Sequence[str] ) -> AgentConfiguration: - agent_configuration.propagation.network_scan.targets.subnets = subnets + agent_configuration_copy = agent_configuration.copy() + agent_configuration_copy.propagation.network_scan.targets.subnets = subnets - return agent_configuration + return agent_configuration_copy def add_credential_collectors( agent_configuration: AgentConfiguration, credential_collectors: Sequence[PluginConfiguration] ) -> AgentConfiguration: - agent_configuration.credential_collectors = tuple(credential_collectors) + agent_configuration_copy = agent_configuration.copy() + agent_configuration_copy.credential_collectors = tuple(credential_collectors) - return agent_configuration + return agent_configuration_copy def add_http_ports( agent_configuration: AgentConfiguration, http_ports: Sequence[int] ) -> AgentConfiguration: - agent_configuration.propagation.exploitation.options.http_ports = http_ports + agent_configuration_copy = agent_configuration.copy() + agent_configuration_copy.propagation.exploitation.options.http_ports = http_ports - return agent_configuration + return agent_configuration_copy def set_keep_tunnel_open_time( agent_configuration: AgentConfiguration, keep_tunnel_open_time: int ) -> AgentConfiguration: - agent_configuration.keep_tunnel_open_time = keep_tunnel_open_time + agent_configuration_copy = agent_configuration.copy() + agent_configuration_copy.keep_tunnel_open_time = keep_tunnel_open_time - return agent_configuration + return agent_configuration_copy def set_maximum_depth( agent_configuration: AgentConfiguration, maximum_depth: int ) -> AgentConfiguration: - agent_configuration.propagation.maximum_depth = maximum_depth + agent_configuration_copy = agent_configuration.copy() + agent_configuration_copy.propagation.maximum_depth = maximum_depth - return agent_configuration + return agent_configuration_copy From 1abf2b7f0313a1e80dffef96d44a2bc89a119b73 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Thu, 1 Sep 2022 12:56:59 +0530 Subject: [PATCH 58/69] BB: Add `simplify=True` when converting test agent configuration to dict in MonkeyIslandClient --- envs/monkey_zoo/blackbox/island_client/monkey_island_client.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/envs/monkey_zoo/blackbox/island_client/monkey_island_client.py b/envs/monkey_zoo/blackbox/island_client/monkey_island_client.py index 43394f24c..88219cef2 100644 --- a/envs/monkey_zoo/blackbox/island_client/monkey_island_client.py +++ b/envs/monkey_zoo/blackbox/island_client/monkey_island_client.py @@ -50,7 +50,7 @@ class MonkeyIslandClient(object): def _import_config(self, test_configuration: TestConfiguration): response = self.requests.put_json( "api/agent-configuration", - json=test_configuration.agent_configuration.dict(), + json=test_configuration.agent_configuration.dict(simplify=True), ) if response.ok: LOGGER.info("Configuration is imported.") From a2b8338ac78b322cb4259e59aea7767fae700cf0 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Thu, 1 Sep 2022 16:45:32 +0530 Subject: [PATCH 59/69] BB: Fix configuration modification logic in depth_1_a.py --- .../blackbox/test_configurations/depth_1_a.py | 26 ++++++++----------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/envs/monkey_zoo/blackbox/test_configurations/depth_1_a.py b/envs/monkey_zoo/blackbox/test_configurations/depth_1_a.py index abcf02b08..f702e3149 100644 --- a/envs/monkey_zoo/blackbox/test_configurations/depth_1_a.py +++ b/envs/monkey_zoo/blackbox/test_configurations/depth_1_a.py @@ -9,8 +9,6 @@ from .utils import ( add_http_ports, add_subnets, add_tcp_ports, - replace_agent_configuration, - replace_propagation_credentials, set_maximum_depth, ) @@ -76,22 +74,20 @@ def _add_http_ports(agent_configuration: AgentConfiguration) -> AgentConfigurati return add_http_ports(agent_configuration, HTTP_PORTS) -test_configuration = set_maximum_depth(noop_test_configuration.agent_configuration, 1) -test_configuration = _add_exploiters(test_configuration) -test_configuration = _add_fingerprinters(test_configuration) -test_configuration = _add_subnets(test_configuration) -test_configuration = _add_tcp_ports(test_configuration) -test_configuration = _add_credential_collectors(test_configuration) -test_configuration = _add_http_ports(test_configuration) +test_agent_configuration = set_maximum_depth(noop_test_configuration.agent_configuration, 1) +test_agent_configuration = _add_exploiters(test_agent_configuration) +test_agent_configuration = _add_fingerprinters(test_agent_configuration) +test_agent_configuration = _add_subnets(test_agent_configuration) +test_agent_configuration = _add_tcp_ports(test_agent_configuration) +test_agent_configuration = _add_credential_collectors(test_agent_configuration) +test_agent_configuration = _add_http_ports(test_agent_configuration) -depth_1_a_test_configuration = replace_agent_configuration( - noop_test_configuration, test_configuration -) CREDENTIALS = ( Credentials(Username("m0nk3y"), None), Credentials(None, Password("Ivrrw5zEzs")), Credentials(None, Password("Xk8VDTsC")), ) -depth_1_a_test_configuration = replace_propagation_credentials( - depth_1_a_test_configuration, CREDENTIALS -) + +depth_1_a_test_configuration = noop_test_configuration.copy() +depth_1_a_test_configuration.agent_configuration = test_agent_configuration +depth_1_a_test_configuration.propagation_credentials = CREDENTIALS From 0392cd579474d25d122db432b9ec6085e076183b Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Thu, 1 Sep 2022 16:47:11 +0530 Subject: [PATCH 60/69] BB: Fix configuration modification logic in depth_2_a.py --- .../blackbox/test_configurations/depth_2_a.py | 29 ++++++------------- 1 file changed, 9 insertions(+), 20 deletions(-) diff --git a/envs/monkey_zoo/blackbox/test_configurations/depth_2_a.py b/envs/monkey_zoo/blackbox/test_configurations/depth_2_a.py index 5159a6ace..396e9ed3e 100644 --- a/envs/monkey_zoo/blackbox/test_configurations/depth_2_a.py +++ b/envs/monkey_zoo/blackbox/test_configurations/depth_2_a.py @@ -2,14 +2,7 @@ from common.agent_configuration import AgentConfiguration, PluginConfiguration from common.credentials import Credentials, Password, Username from .noop import noop_test_configuration -from .utils import ( - add_exploiters, - add_subnets, - add_tcp_ports, - replace_agent_configuration, - replace_propagation_credentials, - set_maximum_depth, -) +from .utils import add_exploiters, add_subnets, add_tcp_ports, set_maximum_depth # Tests: @@ -34,20 +27,16 @@ def _add_tcp_ports(agent_configuration: AgentConfiguration) -> AgentConfiguratio return add_tcp_ports(agent_configuration, ports) -test_configuration = set_maximum_depth(noop_test_configuration.agent_configuration, 2) -test_configuration = _add_exploiters(test_configuration) -test_configuration = _add_subnets(test_configuration) -test_configuration = _add_tcp_ports(test_configuration) - -depth_2_a_test_configuration = replace_agent_configuration( - noop_test_configuration, test_configuration -) - +test_agent_configuration = set_maximum_depth(noop_test_configuration.agent_configuration, 2) +test_agent_configuration = _add_exploiters(test_agent_configuration) +test_agent_configuration = _add_subnets(test_agent_configuration) +test_agent_configuration = _add_tcp_ports(test_agent_configuration) CREDENTIALS = ( Credentials(Username("m0nk3y"), None), Credentials(None, Password("^NgDvY59~8")), ) -depth_2_a_test_configuration = replace_propagation_credentials( - depth_2_a_test_configuration, CREDENTIALS -) + +depth_2_a_test_configuration = noop_test_configuration.copy() +depth_2_a_test_configuration.agent_configuration = test_agent_configuration +depth_2_a_test_configuration.propagation_credentials = CREDENTIALS From 15fd1f9f72620d15820c73cff6afd6eac69bc6e3 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Thu, 1 Sep 2022 16:52:23 +0530 Subject: [PATCH 61/69] BB: Fix configuration modification logic in depth_3_a.py --- .../blackbox/test_configurations/depth_3_a.py | 24 +++++++------------ 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/envs/monkey_zoo/blackbox/test_configurations/depth_3_a.py b/envs/monkey_zoo/blackbox/test_configurations/depth_3_a.py index df1cf1978..8f9bfdc70 100644 --- a/envs/monkey_zoo/blackbox/test_configurations/depth_3_a.py +++ b/envs/monkey_zoo/blackbox/test_configurations/depth_3_a.py @@ -6,8 +6,6 @@ from .utils import ( add_exploiters, add_subnets, add_tcp_ports, - replace_agent_configuration, - replace_propagation_credentials, set_keep_tunnel_open_time, set_maximum_depth, ) @@ -48,16 +46,11 @@ def _add_tcp_ports(agent_configuration: AgentConfiguration) -> AgentConfiguratio return add_tcp_ports(agent_configuration, ports) -test_configuration = set_maximum_depth(noop_test_configuration.agent_configuration, 3) -test_configuration = set_keep_tunnel_open_time(test_configuration, 20) -test_configuration = _add_exploiters(test_configuration) -test_configuration = _add_subnets(test_configuration) -test_configuration = _add_tcp_ports(test_configuration) - -depth_3_a_test_configuration = replace_agent_configuration( - noop_test_configuration, test_configuration -) - +test_agent_configuration = set_maximum_depth(noop_test_configuration.agent_configuration, 3) +test_agent_configuration = set_keep_tunnel_open_time(test_agent_configuration, 20) +test_agent_configuration = _add_exploiters(test_agent_configuration) +test_agent_configuration = _add_subnets(test_agent_configuration) +test_agent_configuration = _add_tcp_ports(test_agent_configuration) CREDENTIALS = ( Credentials(Username("m0nk3y"), None), @@ -70,6 +63,7 @@ CREDENTIALS = ( Credentials(None, NTHash("5da0889ea2081aa79f6852294cba4a5e")), Credentials(None, NTHash("50c9987a6bf1ac59398df9f911122c9b")), ) -depth_3_a_test_configuration = replace_propagation_credentials( - depth_3_a_test_configuration, CREDENTIALS -) + +depth_3_a_test_configuration = noop_test_configuration.copy() +depth_3_a_test_configuration.agent_configuration = test_agent_configuration +depth_3_a_test_configuration.propagation_credentials = CREDENTIALS From e564bd1072d71eb9261edc0109369015a377019b Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Thu, 1 Sep 2022 16:55:03 +0530 Subject: [PATCH 62/69] BB: Fix configuration modification logic in powershell_credentials_reuse.py --- .../powershell_credentials_reuse.py | 21 +++++++------------ 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/envs/monkey_zoo/blackbox/test_configurations/powershell_credentials_reuse.py b/envs/monkey_zoo/blackbox/test_configurations/powershell_credentials_reuse.py index 0073590b3..e8dd214e5 100644 --- a/envs/monkey_zoo/blackbox/test_configurations/powershell_credentials_reuse.py +++ b/envs/monkey_zoo/blackbox/test_configurations/powershell_credentials_reuse.py @@ -1,13 +1,7 @@ from common.agent_configuration import AgentConfiguration, PluginConfiguration from .noop import noop_test_configuration -from .utils import ( - add_exploiters, - add_subnets, - add_tcp_ports, - replace_agent_configuration, - set_maximum_depth, -) +from .utils import add_exploiters, add_subnets, add_tcp_ports, set_maximum_depth def _add_exploiters(agent_configuration: AgentConfiguration) -> AgentConfiguration: @@ -30,11 +24,10 @@ def _add_tcp_ports(agent_configuration: AgentConfiguration) -> AgentConfiguratio return add_tcp_ports(agent_configuration, ports) -test_configuration = set_maximum_depth(noop_test_configuration.agent_configuration, 1) -test_configuration = _add_exploiters(test_configuration) -test_configuration = _add_subnets(test_configuration) -test_configuration = _add_tcp_ports(test_configuration) +test_agent_configuration = set_maximum_depth(noop_test_configuration.agent_configuration, 1) +test_agent_configuration = _add_exploiters(test_agent_configuration) +test_agent_configuration = _add_subnets(test_agent_configuration) +test_agent_configuration = _add_tcp_ports(test_agent_configuration) -powershell_credentials_reuse_test_configuration = replace_agent_configuration( - noop_test_configuration, test_configuration -) +powershell_credentials_reuse_test_configuration = noop_test_configuration.copy() +powershell_credentials_reuse_test_configuration.agent_configuration = test_agent_configuration From a0d0f127f9c7587cfbbcdecef38b97b9b939ffeb Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Thu, 1 Sep 2022 16:58:42 +0530 Subject: [PATCH 63/69] BB: Fix configuration modification logic in smb_pth.py --- .../blackbox/test_configurations/smb_pth.py | 24 +++++++------------ 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/envs/monkey_zoo/blackbox/test_configurations/smb_pth.py b/envs/monkey_zoo/blackbox/test_configurations/smb_pth.py index ec36bb4c7..8863013e9 100644 --- a/envs/monkey_zoo/blackbox/test_configurations/smb_pth.py +++ b/envs/monkey_zoo/blackbox/test_configurations/smb_pth.py @@ -6,8 +6,6 @@ from .utils import ( add_exploiters, add_subnets, add_tcp_ports, - replace_agent_configuration, - replace_propagation_credentials, set_keep_tunnel_open_time, set_maximum_depth, ) @@ -33,16 +31,11 @@ def _add_tcp_ports(agent_configuration: AgentConfiguration) -> AgentConfiguratio return add_tcp_ports(agent_configuration, ports) -test_configuration = set_maximum_depth(noop_test_configuration.agent_configuration, 3) -test_configuration = set_keep_tunnel_open_time(test_configuration, 20) -test_configuration = _add_exploiters(test_configuration) -test_configuration = _add_subnets(test_configuration) -test_configuration = _add_tcp_ports(test_configuration) - -smb_pth_test_configuration = replace_agent_configuration( - noop_test_configuration, test_configuration -) - +test_agent_configuration = set_maximum_depth(noop_test_configuration.agent_configuration, 3) +test_agent_configuration = set_keep_tunnel_open_time(test_agent_configuration, 20) +test_agent_configuration = _add_exploiters(test_agent_configuration) +test_agent_configuration = _add_subnets(test_agent_configuration) +test_agent_configuration = _add_tcp_ports(test_agent_configuration) CREDENTIALS = ( Credentials(Username("Administrator"), None), @@ -54,6 +47,7 @@ CREDENTIALS = ( Credentials(None, NTHash("5da0889ea2081aa79f6852294cba4a5e")), Credentials(None, NTHash("50c9987a6bf1ac59398df9f911122c9b")), ) -smb_pth_test_configuration = replace_propagation_credentials( - smb_pth_test_configuration, CREDENTIALS -) + +smb_pth_test_configuration = noop_test_configuration.copy() +smb_pth_test_configuration.agent_configuration = test_agent_configuration +smb_pth_test_configuration.propagation_credentials = CREDENTIALS From ad6449507d41f28efe9083325ed8bae635aa1013 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Thu, 1 Sep 2022 16:59:58 +0530 Subject: [PATCH 64/69] BB: Fix configuration modification logic in wmi_mimikatz.py --- .../test_configurations/wmi_mimikatz.py | 26 +++++++------------ 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/envs/monkey_zoo/blackbox/test_configurations/wmi_mimikatz.py b/envs/monkey_zoo/blackbox/test_configurations/wmi_mimikatz.py index fe4a1414e..c525f5ca5 100644 --- a/envs/monkey_zoo/blackbox/test_configurations/wmi_mimikatz.py +++ b/envs/monkey_zoo/blackbox/test_configurations/wmi_mimikatz.py @@ -7,8 +7,6 @@ from .utils import ( add_exploiters, add_subnets, add_tcp_ports, - replace_agent_configuration, - replace_propagation_credentials, set_maximum_depth, ) @@ -40,17 +38,12 @@ def _add_tcp_ports(agent_configuration: AgentConfiguration) -> AgentConfiguratio return add_tcp_ports(agent_configuration, ports) -test_configuration = set_maximum_depth(noop_test_configuration.agent_configuration, 1) -test_configuration = _add_exploiters(test_configuration) -test_configuration = _add_subnets(test_configuration) -test_configuration = _add_credential_collectors(test_configuration) -test_configuration = _add_tcp_ports(test_configuration) -test_configuration = _add_credential_collectors(test_configuration) - -wmi_mimikatz_test_configuration = replace_agent_configuration( - noop_test_configuration, test_configuration -) - +test_agent_configuration = set_maximum_depth(noop_test_configuration.agent_configuration, 1) +test_agent_configuration = _add_exploiters(test_agent_configuration) +test_agent_configuration = _add_subnets(test_agent_configuration) +test_agent_configuration = _add_credential_collectors(test_agent_configuration) +test_agent_configuration = _add_tcp_ports(test_agent_configuration) +test_agent_configuration = _add_credential_collectors(test_agent_configuration) CREDENTIALS = ( Credentials(Username("Administrator"), None), @@ -59,6 +52,7 @@ CREDENTIALS = ( Credentials(None, Password("Ivrrw5zEzs")), Credentials(None, Password("Password1!")), ) -wmi_mimikatz_test_configuration = replace_propagation_credentials( - wmi_mimikatz_test_configuration, CREDENTIALS -) + +wmi_mimikatz_test_configuration = noop_test_configuration.copy() +wmi_mimikatz_test_configuration.agent_configuration = test_agent_configuration +wmi_mimikatz_test_configuration.propagation_credentials = CREDENTIALS From 2352bb0d5eac0e51d82608eb9c2fac4ee3513636 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Thu, 1 Sep 2022 17:01:05 +0530 Subject: [PATCH 65/69] BB: Fix configuration modification logic in zerologon.py --- .../blackbox/test_configurations/zerologon.py | 21 +++++++------------ 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/envs/monkey_zoo/blackbox/test_configurations/zerologon.py b/envs/monkey_zoo/blackbox/test_configurations/zerologon.py index 3a956c6f3..8e9a14369 100644 --- a/envs/monkey_zoo/blackbox/test_configurations/zerologon.py +++ b/envs/monkey_zoo/blackbox/test_configurations/zerologon.py @@ -1,13 +1,7 @@ from common.agent_configuration import AgentConfiguration, PluginConfiguration from .noop import noop_test_configuration -from .utils import ( - add_exploiters, - add_subnets, - add_tcp_ports, - replace_agent_configuration, - set_maximum_depth, -) +from .utils import add_exploiters, add_subnets, add_tcp_ports, set_maximum_depth def _add_exploiters(agent_configuration: AgentConfiguration) -> AgentConfiguration: @@ -27,11 +21,10 @@ def _add_subnets(agent_configuration: AgentConfiguration) -> AgentConfiguration: return add_subnets(agent_configuration, subnets) -test_configuration = set_maximum_depth(noop_test_configuration.agent_configuration, 1) -test_configuration = _add_exploiters(test_configuration) -test_configuration = _add_tcp_ports(test_configuration) -test_configuration = _add_subnets(test_configuration) +test_agent_configuration = set_maximum_depth(noop_test_configuration.agent_configuration, 1) +test_agent_configuration = _add_exploiters(test_agent_configuration) +test_agent_configuration = _add_tcp_ports(test_agent_configuration) +test_agent_configuration = _add_subnets(test_agent_configuration) -zerologon_test_configuration = replace_agent_configuration( - noop_test_configuration, test_configuration -) +zerologon_test_configuration = noop_test_configuration.copy() +zerologon_test_configuration.agent_configuration = test_agent_configuration From 6cf62d48cb20a39ab2c5168e17f503de381589e5 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Thu, 1 Sep 2022 17:09:53 +0530 Subject: [PATCH 66/69] BB: Use `replace_agent_configuration()` and `replace_propagation_credentials()` for all test configuration modifications --- .../blackbox/test_configurations/depth_1_a.py | 10 ++++++++-- .../blackbox/test_configurations/depth_2_a.py | 17 ++++++++++++++--- .../blackbox/test_configurations/depth_3_a.py | 10 ++++++++-- .../powershell_credentials_reuse.py | 13 +++++++++++-- .../blackbox/test_configurations/smb_pth.py | 10 ++++++++-- .../blackbox/test_configurations/utils.py | 16 +++++++++++++++- .../test_configurations/wmi_mimikatz.py | 10 ++++++++-- .../blackbox/test_configurations/zerologon.py | 12 ++++++++++-- 8 files changed, 82 insertions(+), 16 deletions(-) diff --git a/envs/monkey_zoo/blackbox/test_configurations/depth_1_a.py b/envs/monkey_zoo/blackbox/test_configurations/depth_1_a.py index f702e3149..b043456a5 100644 --- a/envs/monkey_zoo/blackbox/test_configurations/depth_1_a.py +++ b/envs/monkey_zoo/blackbox/test_configurations/depth_1_a.py @@ -9,6 +9,8 @@ from .utils import ( add_http_ports, add_subnets, add_tcp_ports, + replace_agent_configuration, + replace_propagation_credentials, set_maximum_depth, ) @@ -89,5 +91,9 @@ CREDENTIALS = ( ) depth_1_a_test_configuration = noop_test_configuration.copy() -depth_1_a_test_configuration.agent_configuration = test_agent_configuration -depth_1_a_test_configuration.propagation_credentials = CREDENTIALS +replace_agent_configuration( + test_configuration=depth_1_a_test_configuration, agent_configuration=test_agent_configuration +) +replace_propagation_credentials( + test_configuration=depth_1_a_test_configuration, propagation_credentials=CREDENTIALS +) diff --git a/envs/monkey_zoo/blackbox/test_configurations/depth_2_a.py b/envs/monkey_zoo/blackbox/test_configurations/depth_2_a.py index 396e9ed3e..a8b9a87a5 100644 --- a/envs/monkey_zoo/blackbox/test_configurations/depth_2_a.py +++ b/envs/monkey_zoo/blackbox/test_configurations/depth_2_a.py @@ -2,7 +2,14 @@ from common.agent_configuration import AgentConfiguration, PluginConfiguration from common.credentials import Credentials, Password, Username from .noop import noop_test_configuration -from .utils import add_exploiters, add_subnets, add_tcp_ports, set_maximum_depth +from .utils import ( + add_exploiters, + add_subnets, + add_tcp_ports, + replace_agent_configuration, + replace_propagation_credentials, + set_maximum_depth, +) # Tests: @@ -38,5 +45,9 @@ CREDENTIALS = ( ) depth_2_a_test_configuration = noop_test_configuration.copy() -depth_2_a_test_configuration.agent_configuration = test_agent_configuration -depth_2_a_test_configuration.propagation_credentials = CREDENTIALS +replace_agent_configuration( + test_configuration=depth_2_a_test_configuration, agent_configuration=test_agent_configuration +) +replace_propagation_credentials( + test_configuration=depth_2_a_test_configuration, propagation_credentials=CREDENTIALS +) diff --git a/envs/monkey_zoo/blackbox/test_configurations/depth_3_a.py b/envs/monkey_zoo/blackbox/test_configurations/depth_3_a.py index 8f9bfdc70..a1de4430c 100644 --- a/envs/monkey_zoo/blackbox/test_configurations/depth_3_a.py +++ b/envs/monkey_zoo/blackbox/test_configurations/depth_3_a.py @@ -6,6 +6,8 @@ from .utils import ( add_exploiters, add_subnets, add_tcp_ports, + replace_agent_configuration, + replace_propagation_credentials, set_keep_tunnel_open_time, set_maximum_depth, ) @@ -65,5 +67,9 @@ CREDENTIALS = ( ) depth_3_a_test_configuration = noop_test_configuration.copy() -depth_3_a_test_configuration.agent_configuration = test_agent_configuration -depth_3_a_test_configuration.propagation_credentials = CREDENTIALS +replace_agent_configuration( + test_configuration=depth_3_a_test_configuration, agent_configuration=test_agent_configuration +) +replace_propagation_credentials( + test_configuration=depth_3_a_test_configuration, propagation_credentials=CREDENTIALS +) diff --git a/envs/monkey_zoo/blackbox/test_configurations/powershell_credentials_reuse.py b/envs/monkey_zoo/blackbox/test_configurations/powershell_credentials_reuse.py index e8dd214e5..7938b54e2 100644 --- a/envs/monkey_zoo/blackbox/test_configurations/powershell_credentials_reuse.py +++ b/envs/monkey_zoo/blackbox/test_configurations/powershell_credentials_reuse.py @@ -1,7 +1,13 @@ from common.agent_configuration import AgentConfiguration, PluginConfiguration from .noop import noop_test_configuration -from .utils import add_exploiters, add_subnets, add_tcp_ports, set_maximum_depth +from .utils import ( + add_exploiters, + add_subnets, + add_tcp_ports, + replace_agent_configuration, + set_maximum_depth, +) def _add_exploiters(agent_configuration: AgentConfiguration) -> AgentConfiguration: @@ -30,4 +36,7 @@ test_agent_configuration = _add_subnets(test_agent_configuration) test_agent_configuration = _add_tcp_ports(test_agent_configuration) powershell_credentials_reuse_test_configuration = noop_test_configuration.copy() -powershell_credentials_reuse_test_configuration.agent_configuration = test_agent_configuration +replace_agent_configuration( + test_configuration=powershell_credentials_reuse_test_configuration, + agent_configuration=test_agent_configuration, +) diff --git a/envs/monkey_zoo/blackbox/test_configurations/smb_pth.py b/envs/monkey_zoo/blackbox/test_configurations/smb_pth.py index 8863013e9..b99d21ca8 100644 --- a/envs/monkey_zoo/blackbox/test_configurations/smb_pth.py +++ b/envs/monkey_zoo/blackbox/test_configurations/smb_pth.py @@ -6,6 +6,8 @@ from .utils import ( add_exploiters, add_subnets, add_tcp_ports, + replace_agent_configuration, + replace_propagation_credentials, set_keep_tunnel_open_time, set_maximum_depth, ) @@ -49,5 +51,9 @@ CREDENTIALS = ( ) smb_pth_test_configuration = noop_test_configuration.copy() -smb_pth_test_configuration.agent_configuration = test_agent_configuration -smb_pth_test_configuration.propagation_credentials = CREDENTIALS +replace_agent_configuration( + test_configuration=smb_pth_test_configuration, agent_configuration=test_agent_configuration +) +replace_propagation_credentials( + test_configuration=smb_pth_test_configuration, propagation_credentials=CREDENTIALS +) diff --git a/envs/monkey_zoo/blackbox/test_configurations/utils.py b/envs/monkey_zoo/blackbox/test_configurations/utils.py index c1b6b54f8..3872230c0 100644 --- a/envs/monkey_zoo/blackbox/test_configurations/utils.py +++ b/envs/monkey_zoo/blackbox/test_configurations/utils.py @@ -1,6 +1,8 @@ -from typing import Sequence +from typing import Sequence, Tuple from common.agent_configuration import AgentConfiguration, PluginConfiguration +from common.credentials import Credentials +from envs.monkey_zoo.blackbox.test_configurations.test_configuration import TestConfiguration def add_exploiters( @@ -84,3 +86,15 @@ def set_maximum_depth( agent_configuration_copy.propagation.maximum_depth = maximum_depth return agent_configuration_copy + + +def replace_agent_configuration( + test_configuration: TestConfiguration, agent_configuration: AgentConfiguration +): + test_configuration.agent_configuration = agent_configuration + + +def replace_propagation_credentials( + test_configuration: TestConfiguration, propagation_credentials: Tuple[Credentials, ...] +): + test_configuration.propagation_credentials = propagation_credentials diff --git a/envs/monkey_zoo/blackbox/test_configurations/wmi_mimikatz.py b/envs/monkey_zoo/blackbox/test_configurations/wmi_mimikatz.py index c525f5ca5..db8b6fa1d 100644 --- a/envs/monkey_zoo/blackbox/test_configurations/wmi_mimikatz.py +++ b/envs/monkey_zoo/blackbox/test_configurations/wmi_mimikatz.py @@ -7,6 +7,8 @@ from .utils import ( add_exploiters, add_subnets, add_tcp_ports, + replace_agent_configuration, + replace_propagation_credentials, set_maximum_depth, ) @@ -54,5 +56,9 @@ CREDENTIALS = ( ) wmi_mimikatz_test_configuration = noop_test_configuration.copy() -wmi_mimikatz_test_configuration.agent_configuration = test_agent_configuration -wmi_mimikatz_test_configuration.propagation_credentials = CREDENTIALS +replace_agent_configuration( + test_configuration=wmi_mimikatz_test_configuration, agent_configuration=test_agent_configuration +) +replace_propagation_credentials( + test_configuration=wmi_mimikatz_test_configuration, propagation_credentials=CREDENTIALS +) diff --git a/envs/monkey_zoo/blackbox/test_configurations/zerologon.py b/envs/monkey_zoo/blackbox/test_configurations/zerologon.py index 8e9a14369..87b533aed 100644 --- a/envs/monkey_zoo/blackbox/test_configurations/zerologon.py +++ b/envs/monkey_zoo/blackbox/test_configurations/zerologon.py @@ -1,7 +1,13 @@ from common.agent_configuration import AgentConfiguration, PluginConfiguration from .noop import noop_test_configuration -from .utils import add_exploiters, add_subnets, add_tcp_ports, set_maximum_depth +from .utils import ( + add_exploiters, + add_subnets, + add_tcp_ports, + replace_agent_configuration, + set_maximum_depth, +) def _add_exploiters(agent_configuration: AgentConfiguration) -> AgentConfiguration: @@ -27,4 +33,6 @@ test_agent_configuration = _add_tcp_ports(test_agent_configuration) test_agent_configuration = _add_subnets(test_agent_configuration) zerologon_test_configuration = noop_test_configuration.copy() -zerologon_test_configuration.agent_configuration = test_agent_configuration +replace_agent_configuration( + test_configuration=zerologon_test_configuration, agent_configuration=test_agent_configuration +) From daec8843af61d9b2c7d62d6fa97000c5284c79e6 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Thu, 1 Sep 2022 17:12:16 +0530 Subject: [PATCH 67/69] BB: Use positional arguments for PluginConfiguration object creation where missed in depth_1_a.py --- envs/monkey_zoo/blackbox/test_configurations/depth_1_a.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/envs/monkey_zoo/blackbox/test_configurations/depth_1_a.py b/envs/monkey_zoo/blackbox/test_configurations/depth_1_a.py index b043456a5..4c935ddb4 100644 --- a/envs/monkey_zoo/blackbox/test_configurations/depth_1_a.py +++ b/envs/monkey_zoo/blackbox/test_configurations/depth_1_a.py @@ -60,7 +60,7 @@ def _add_subnets(agent_configuration: AgentConfiguration) -> AgentConfiguration: def _add_credential_collectors(agent_configuration: AgentConfiguration) -> AgentConfiguration: return add_credential_collectors( - agent_configuration, [PluginConfiguration("MimikatzCollector", {})] + agent_configuration, [PluginConfiguration(name="MimikatzCollector", options={})] ) From c985337df0b051ef8893e6e7624177571e358d53 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Thu, 1 Sep 2022 18:34:26 +0530 Subject: [PATCH 68/69] BB: Fix configuration modification logic in all test configurations since TestConfiguration is a dataclass --- envs/monkey_zoo/blackbox/test_configurations/depth_1_a.py | 4 +++- envs/monkey_zoo/blackbox/test_configurations/depth_2_a.py | 4 +++- envs/monkey_zoo/blackbox/test_configurations/depth_3_a.py | 4 +++- .../test_configurations/powershell_credentials_reuse.py | 4 +++- envs/monkey_zoo/blackbox/test_configurations/smb_pth.py | 4 +++- envs/monkey_zoo/blackbox/test_configurations/wmi_mimikatz.py | 4 +++- envs/monkey_zoo/blackbox/test_configurations/zerologon.py | 4 +++- 7 files changed, 21 insertions(+), 7 deletions(-) diff --git a/envs/monkey_zoo/blackbox/test_configurations/depth_1_a.py b/envs/monkey_zoo/blackbox/test_configurations/depth_1_a.py index 4c935ddb4..478aa7373 100644 --- a/envs/monkey_zoo/blackbox/test_configurations/depth_1_a.py +++ b/envs/monkey_zoo/blackbox/test_configurations/depth_1_a.py @@ -1,3 +1,5 @@ +import dataclasses + from common.agent_configuration import AgentConfiguration, PluginConfiguration from common.credentials import Credentials, Password, Username @@ -90,7 +92,7 @@ CREDENTIALS = ( Credentials(None, Password("Xk8VDTsC")), ) -depth_1_a_test_configuration = noop_test_configuration.copy() +depth_1_a_test_configuration = dataclasses.replace(noop_test_configuration) replace_agent_configuration( test_configuration=depth_1_a_test_configuration, agent_configuration=test_agent_configuration ) diff --git a/envs/monkey_zoo/blackbox/test_configurations/depth_2_a.py b/envs/monkey_zoo/blackbox/test_configurations/depth_2_a.py index a8b9a87a5..109a600fc 100644 --- a/envs/monkey_zoo/blackbox/test_configurations/depth_2_a.py +++ b/envs/monkey_zoo/blackbox/test_configurations/depth_2_a.py @@ -1,3 +1,5 @@ +import dataclasses + from common.agent_configuration import AgentConfiguration, PluginConfiguration from common.credentials import Credentials, Password, Username @@ -44,7 +46,7 @@ CREDENTIALS = ( Credentials(None, Password("^NgDvY59~8")), ) -depth_2_a_test_configuration = noop_test_configuration.copy() +depth_2_a_test_configuration = dataclasses.replace(noop_test_configuration) replace_agent_configuration( test_configuration=depth_2_a_test_configuration, agent_configuration=test_agent_configuration ) diff --git a/envs/monkey_zoo/blackbox/test_configurations/depth_3_a.py b/envs/monkey_zoo/blackbox/test_configurations/depth_3_a.py index a1de4430c..0a39a5e59 100644 --- a/envs/monkey_zoo/blackbox/test_configurations/depth_3_a.py +++ b/envs/monkey_zoo/blackbox/test_configurations/depth_3_a.py @@ -1,3 +1,5 @@ +import dataclasses + from common.agent_configuration import AgentConfiguration, PluginConfiguration from common.credentials import Credentials, NTHash, Password, Username @@ -66,7 +68,7 @@ CREDENTIALS = ( Credentials(None, NTHash("50c9987a6bf1ac59398df9f911122c9b")), ) -depth_3_a_test_configuration = noop_test_configuration.copy() +depth_3_a_test_configuration = dataclasses.replace(noop_test_configuration) replace_agent_configuration( test_configuration=depth_3_a_test_configuration, agent_configuration=test_agent_configuration ) diff --git a/envs/monkey_zoo/blackbox/test_configurations/powershell_credentials_reuse.py b/envs/monkey_zoo/blackbox/test_configurations/powershell_credentials_reuse.py index 7938b54e2..5d974cd17 100644 --- a/envs/monkey_zoo/blackbox/test_configurations/powershell_credentials_reuse.py +++ b/envs/monkey_zoo/blackbox/test_configurations/powershell_credentials_reuse.py @@ -1,3 +1,5 @@ +import dataclasses + from common.agent_configuration import AgentConfiguration, PluginConfiguration from .noop import noop_test_configuration @@ -35,7 +37,7 @@ test_agent_configuration = _add_exploiters(test_agent_configuration) test_agent_configuration = _add_subnets(test_agent_configuration) test_agent_configuration = _add_tcp_ports(test_agent_configuration) -powershell_credentials_reuse_test_configuration = noop_test_configuration.copy() +powershell_credentials_reuse_test_configuration = dataclasses.replace(noop_test_configuration) replace_agent_configuration( test_configuration=powershell_credentials_reuse_test_configuration, agent_configuration=test_agent_configuration, diff --git a/envs/monkey_zoo/blackbox/test_configurations/smb_pth.py b/envs/monkey_zoo/blackbox/test_configurations/smb_pth.py index b99d21ca8..f0432129d 100644 --- a/envs/monkey_zoo/blackbox/test_configurations/smb_pth.py +++ b/envs/monkey_zoo/blackbox/test_configurations/smb_pth.py @@ -1,3 +1,5 @@ +import dataclasses + from common.agent_configuration import AgentConfiguration, PluginConfiguration from common.credentials import Credentials, NTHash, Password, Username @@ -50,7 +52,7 @@ CREDENTIALS = ( Credentials(None, NTHash("50c9987a6bf1ac59398df9f911122c9b")), ) -smb_pth_test_configuration = noop_test_configuration.copy() +smb_pth_test_configuration = dataclasses.replace(noop_test_configuration) replace_agent_configuration( test_configuration=smb_pth_test_configuration, agent_configuration=test_agent_configuration ) diff --git a/envs/monkey_zoo/blackbox/test_configurations/wmi_mimikatz.py b/envs/monkey_zoo/blackbox/test_configurations/wmi_mimikatz.py index db8b6fa1d..dc86ee2c8 100644 --- a/envs/monkey_zoo/blackbox/test_configurations/wmi_mimikatz.py +++ b/envs/monkey_zoo/blackbox/test_configurations/wmi_mimikatz.py @@ -1,3 +1,5 @@ +import dataclasses + from common.agent_configuration import AgentConfiguration, PluginConfiguration from common.credentials import Credentials, Password, Username @@ -55,7 +57,7 @@ CREDENTIALS = ( Credentials(None, Password("Password1!")), ) -wmi_mimikatz_test_configuration = noop_test_configuration.copy() +wmi_mimikatz_test_configuration = dataclasses.replace(noop_test_configuration) replace_agent_configuration( test_configuration=wmi_mimikatz_test_configuration, agent_configuration=test_agent_configuration ) diff --git a/envs/monkey_zoo/blackbox/test_configurations/zerologon.py b/envs/monkey_zoo/blackbox/test_configurations/zerologon.py index 87b533aed..b56b7af05 100644 --- a/envs/monkey_zoo/blackbox/test_configurations/zerologon.py +++ b/envs/monkey_zoo/blackbox/test_configurations/zerologon.py @@ -1,3 +1,5 @@ +import dataclasses + from common.agent_configuration import AgentConfiguration, PluginConfiguration from .noop import noop_test_configuration @@ -32,7 +34,7 @@ test_agent_configuration = _add_exploiters(test_agent_configuration) test_agent_configuration = _add_tcp_ports(test_agent_configuration) test_agent_configuration = _add_subnets(test_agent_configuration) -zerologon_test_configuration = noop_test_configuration.copy() +zerologon_test_configuration = dataclasses.replace(noop_test_configuration) replace_agent_configuration( test_configuration=zerologon_test_configuration, agent_configuration=test_agent_configuration ) From 4017f094cf71d5e5ac1c2177d799a404c3dfd9c0 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Fri, 2 Sep 2022 12:25:08 +0530 Subject: [PATCH 69/69] Project: Add entries to Vulture allowlist --- vulture_allowlist.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/vulture_allowlist.py b/vulture_allowlist.py index 678e9a22c..68a94a2db 100644 --- a/vulture_allowlist.py +++ b/vulture_allowlist.py @@ -7,6 +7,8 @@ from common.agent_configuration.agent_sub_configurations import ( CustomPBAConfiguration, ScanTargetConfiguration, ) +from common.credentials import Credentials +from common.utils import IJSONSerializable from infection_monkey.exploit.log4shell_utils.ldap_server import LDAPServerFactory from monkey_island.cc.models import Report from monkey_island.cc.models.networkmap import Arc, NetworkMap @@ -310,3 +312,6 @@ SCANNED EXPLOITED CC CC_TUNNEL + +Credentials.from_json +IJSONSerializable.from_json