From ba6bf7177607fb55a6410ed6452b76df5ff63961 Mon Sep 17 00:00:00 2001 From: Mike Salvatore Date: Tue, 9 Mar 2021 11:56:06 -0500 Subject: [PATCH 01/16] agent: Fix typo in HTTPFinger --- monkey/infection_monkey/network/httpfinger.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/monkey/infection_monkey/network/httpfinger.py b/monkey/infection_monkey/network/httpfinger.py index 1ce026c11..86c48cbde 100644 --- a/monkey/infection_monkey/network/httpfinger.py +++ b/monkey/infection_monkey/network/httpfinger.py @@ -45,6 +45,6 @@ class HTTPFinger(HostFinger): except Timeout: LOG.debug(f"Timout while requesting headers from {url}") except ConnectionError: # Someone doesn't like us - LOG.debug(f"ConnetionError while requesting headers from {url}") + LOG.debug(f"Connection error while requesting headers from {url}") return True From 4ac7c0197654ba26b4ba7136921a3533db75d218 Mon Sep 17 00:00:00 2001 From: Mike Salvatore Date: Tue, 9 Mar 2021 11:32:52 -0500 Subject: [PATCH 02/16] agent: add 2 new log statements to the dropper --- monkey/infection_monkey/dropper.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/monkey/infection_monkey/dropper.py b/monkey/infection_monkey/dropper.py index cb7be181d..d98eb8e9e 100644 --- a/monkey/infection_monkey/dropper.py +++ b/monkey/infection_monkey/dropper.py @@ -145,6 +145,8 @@ class MonkeyDrops(object): LOG.warning("Seems like monkey died too soon") def cleanup(self): + LOG.info("Cleaning up the dropper") + try: if (self._config['source_path'].lower() != self._config['destination_path'].lower()) and \ os.path.exists(self._config['source_path']) and \ @@ -166,5 +168,7 @@ class MonkeyDrops(object): LOG.debug("Dropper source file '%s' is marked for deletion on next boot", self._config['source_path']) T1106Telem(ScanStatus.USED, UsageEnum.DROPPER_WINAPI).send() + + LOG.info("Dropper cleanup complete") except AttributeError: LOG.error("Invalid configuration options. Failing") From e7528e95448e2298a191ca6930f9eaea1a895186 Mon Sep 17 00:00:00 2001 From: Mike Salvatore Date: Tue, 9 Mar 2021 11:35:38 -0500 Subject: [PATCH 03/16] agent: Use PIPE for stdin, stdout, and stderr in dropper The dropper is expected to detatch the child monkey agent process. If stdin, stdout, and stderr are set to `None`, the child process inherits them. Since the child process inherits the parent's file descriptors and holds them open, issues like #1026 can occur. --- monkey/infection_monkey/dropper.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/monkey/infection_monkey/dropper.py b/monkey/infection_monkey/dropper.py index d98eb8e9e..9b374c9f1 100644 --- a/monkey/infection_monkey/dropper.py +++ b/monkey/infection_monkey/dropper.py @@ -134,7 +134,9 @@ class MonkeyDrops(object): 'monkey_commandline': inner_monkey_cmdline} monkey_process = subprocess.Popen(monkey_cmdline, shell=True, - stdin=None, stdout=None, stderr=None, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, close_fds=True, creationflags=DETACHED_PROCESS) LOG.info("Executed monkey process (PID=%d) with command line: %s", From 3714dd2f6f184a2c4f625e54abb820ed768981db Mon Sep 17 00:00:00 2001 From: Mike Salvatore Date: Tue, 9 Mar 2021 11:39:44 -0500 Subject: [PATCH 04/16] agent: Use the dropper in the DrupalExploiter Fixes #1026 --- monkey/infection_monkey/exploit/drupal.py | 1 + 1 file changed, 1 insertion(+) diff --git a/monkey/infection_monkey/exploit/drupal.py b/monkey/infection_monkey/exploit/drupal.py index 5872f4703..04b0ce431 100644 --- a/monkey/infection_monkey/exploit/drupal.py +++ b/monkey/infection_monkey/exploit/drupal.py @@ -36,6 +36,7 @@ class DrupalExploiter(WebRCE): exploit_config = super(DrupalExploiter, self).get_exploit_config() exploit_config['url_extensions'] = ['node/', # In Linux, no path is added 'drupal/node/'] # However, Bitnami installations are under /drupal + exploit_config['dropper'] = True return exploit_config def add_vulnerable_urls(self, potential_urls, stop_checking=False): From 307e1e309314886a940ad8ae3d676294e4a91e36 Mon Sep 17 00:00:00 2001 From: Shreya Date: Tue, 9 Mar 2021 15:19:29 +0530 Subject: [PATCH 05/16] Rephrase custom PBA file descriptions in configuration --- .../cc/services/config_schema/monkey.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/monkey/monkey_island/cc/services/config_schema/monkey.py b/monkey/monkey_island/cc/services/config_schema/monkey.py index 01d463672..faf27c481 100644 --- a/monkey/monkey_island/cc/services/config_schema/monkey.py +++ b/monkey/monkey_island/cc/services/config_schema/monkey.py @@ -20,9 +20,9 @@ MONKEY = { "title": "Linux post breach file", "type": "string", "format": "data-url", - "description": "File to be executed after breaching. " - "If you want custom execution behavior, " - "specify it in 'Linux post breach command' field. " + "description": "File to be uploaded after breaching. " + "If you want the file to be executed, " + "specify it in the 'Linux post breach command' field. " "Reference your file by filename." }, "custom_PBA_windows_cmd": { @@ -35,9 +35,9 @@ MONKEY = { "title": "Windows post breach file", "type": "string", "format": "data-url", - "description": "File to be executed after breaching. " - "If you want custom execution behavior, " - "specify it in 'Windows post breach command' field. " + "description": "File to be uploaded after breaching. " + "If you want the file to be executed, " + "specify it in the 'Windows post breach command' field. " "Reference your file by filename." }, "PBA_windows_filename": { From eeba0513d226758cf11c7da5d6e96927d00d054c Mon Sep 17 00:00:00 2001 From: Shreya Date: Tue, 9 Mar 2021 18:02:55 +0530 Subject: [PATCH 06/16] Only upload custom PBA file; execute only if specified in custom PBA command --- .../post_breach/actions/users_custom_pba.py | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/monkey/infection_monkey/post_breach/actions/users_custom_pba.py b/monkey/infection_monkey/post_breach/actions/users_custom_pba.py index 175d6b215..b282bc4bd 100644 --- a/monkey/infection_monkey/post_breach/actions/users_custom_pba.py +++ b/monkey/infection_monkey/post_breach/actions/users_custom_pba.py @@ -15,10 +15,6 @@ LOG = logging.getLogger(__name__) __author__ = 'VakarisZ' -# Default commands for executing PBA file and then removing it -DEFAULT_LINUX_COMMAND = "chmod +x {0} ; {0} ; rm {0}" -DEFAULT_WINDOWS_COMMAND = "{0} & del {0}" - DIR_CHANGE_WINDOWS = 'cd %s & ' DIR_CHANGE_LINUX = 'cd %s ; ' @@ -31,37 +27,28 @@ class UsersPBA(PBA): def __init__(self): super(UsersPBA, self).__init__(POST_BREACH_FILE_EXECUTION) self.filename = '' + if not is_windows_os(): # Add linux commands to PBA's if WormConfiguration.PBA_linux_filename: + self.filename = WormConfiguration.PBA_linux_filename if WormConfiguration.custom_PBA_linux_cmd: # Add change dir command, because user will try to access his file self.command = (DIR_CHANGE_LINUX % get_monkey_dir_path()) + WormConfiguration.custom_PBA_linux_cmd - self.filename = WormConfiguration.PBA_linux_filename - else: - file_path = os.path.join(get_monkey_dir_path(), WormConfiguration.PBA_linux_filename) - self.command = DEFAULT_LINUX_COMMAND.format(file_path) - self.filename = WormConfiguration.PBA_linux_filename elif WormConfiguration.custom_PBA_linux_cmd: self.command = WormConfiguration.custom_PBA_linux_cmd else: # Add windows commands to PBA's if WormConfiguration.PBA_windows_filename: + self.filename = WormConfiguration.PBA_windows_filename if WormConfiguration.custom_PBA_windows_cmd: # Add change dir command, because user will try to access his file self.command = (DIR_CHANGE_WINDOWS % get_monkey_dir_path()) + WormConfiguration.custom_PBA_windows_cmd - self.filename = WormConfiguration.PBA_windows_filename - else: - file_path = os.path.join(get_monkey_dir_path(), WormConfiguration.PBA_windows_filename) - self.command = DEFAULT_WINDOWS_COMMAND.format(file_path) - self.filename = WormConfiguration.PBA_windows_filename elif WormConfiguration.custom_PBA_windows_cmd: self.command = WormConfiguration.custom_PBA_windows_cmd - def _execute_default(self): if self.filename: UsersPBA.download_pba_file(get_monkey_dir_path(), self.filename) - return super(UsersPBA, self)._execute_default() @staticmethod def should_run(class_name): From 6f134bdb0362a51323016b51d9b09043045c0049 Mon Sep 17 00:00:00 2001 From: Shreya Date: Wed, 10 Mar 2021 12:28:30 +0530 Subject: [PATCH 07/16] Download custom PBA file during execution, not initialisation --- monkey/infection_monkey/post_breach/actions/users_custom_pba.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/monkey/infection_monkey/post_breach/actions/users_custom_pba.py b/monkey/infection_monkey/post_breach/actions/users_custom_pba.py index b282bc4bd..dd723c14d 100644 --- a/monkey/infection_monkey/post_breach/actions/users_custom_pba.py +++ b/monkey/infection_monkey/post_breach/actions/users_custom_pba.py @@ -47,8 +47,10 @@ class UsersPBA(PBA): elif WormConfiguration.custom_PBA_windows_cmd: self.command = WormConfiguration.custom_PBA_windows_cmd + def _execute_default(self): if self.filename: UsersPBA.download_pba_file(get_monkey_dir_path(), self.filename) + return super(UsersPBA, self)._execute_default() @staticmethod def should_run(class_name): From 72a88c81a3e7976ce6d59b02e4c9f9a8a45ffc59 Mon Sep 17 00:00:00 2001 From: Shreya Date: Mon, 8 Mar 2021 13:53:01 +0530 Subject: [PATCH 08/16] Add unit tests --- .../tests/actions/test_users_custom_pba.py | 227 ++++++++++++++++++ 1 file changed, 227 insertions(+) create mode 100644 monkey/infection_monkey/post_breach/tests/actions/test_users_custom_pba.py diff --git a/monkey/infection_monkey/post_breach/tests/actions/test_users_custom_pba.py b/monkey/infection_monkey/post_breach/tests/actions/test_users_custom_pba.py new file mode 100644 index 000000000..dab6ee59e --- /dev/null +++ b/monkey/infection_monkey/post_breach/tests/actions/test_users_custom_pba.py @@ -0,0 +1,227 @@ +import pytest + +from infection_monkey.post_breach.actions.users_custom_pba import ( + DEFAULT_LINUX_COMMAND, DEFAULT_WINDOWS_COMMAND, DIR_CHANGE_LINUX, + DIR_CHANGE_WINDOWS, UsersPBA) + +MONKEY_DIR_PATH = "/dir/to/monkey/" +CUSTOM_LINUX_CMD_SEPARATE = "command-for-linux" +CUSTOM_LINUX_FILENAME = "filename-for-linux" +CUSTOM_LINUX_CMD_RELATED = f"command-with-{CUSTOM_LINUX_FILENAME}" +CUSTOM_WINDOWS_CMD_SEPARATE = "command-for-windows" +CUSTOM_WINDOWS_FILENAME = "filename-for-windows" +CUSTOM_WINDOWS_CMD_RELATED = f"command-with-{CUSTOM_WINDOWS_FILENAME}" + + +@pytest.fixture +def fake_monkey_dir_path(monkeypatch): + monkeypatch.setattr( + "infection_monkey.post_breach.actions.users_custom_pba.get_monkey_dir_path", + lambda: MONKEY_DIR_PATH, + ) + + +@pytest.fixture +def set_os_linux(monkeypatch): + monkeypatch.setattr( + "infection_monkey.post_breach.actions.users_custom_pba.is_windows_os", + lambda: False, + ) + + +@pytest.fixture +def set_os_windows(monkeypatch): + monkeypatch.setattr( + "infection_monkey.post_breach.actions.users_custom_pba.is_windows_os", + lambda: True, + ) + + +@pytest.fixture +def mock_UsersPBA_linux_custom_file_and_cmd_separate( + set_os_linux, fake_monkey_dir_path, monkeypatch +): + monkeypatch.setattr( + "infection_monkey.config.WormConfiguration.custom_PBA_linux_cmd", + CUSTOM_LINUX_CMD_SEPARATE, + ) + monkeypatch.setattr( + "infection_monkey.config.WormConfiguration.PBA_linux_filename", + CUSTOM_LINUX_FILENAME, + ) + return UsersPBA() + + +def test_command_list_linux_custom_file_and_cmd_separate( + mock_UsersPBA_linux_custom_file_and_cmd_separate, +): + expected_command_list = [ + f"cd {MONKEY_DIR_PATH} ; {CUSTOM_LINUX_CMD_SEPARATE}", + f"chmod +x {MONKEY_DIR_PATH}{CUSTOM_LINUX_FILENAME} ; {MONKEY_DIR_PATH}{CUSTOM_LINUX_FILENAME} ; " + + f"rm {MONKEY_DIR_PATH}{CUSTOM_LINUX_FILENAME}", + ] + assert ( + mock_UsersPBA_linux_custom_file_and_cmd_separate.command_list + == expected_command_list + ) + + +@pytest.fixture +def mock_UsersPBA_windows_custom_file_and_cmd_separate( + set_os_windows, fake_monkey_dir_path, monkeypatch +): + monkeypatch.setattr( + "infection_monkey.config.WormConfiguration.custom_PBA_windows_cmd", + CUSTOM_WINDOWS_CMD_SEPARATE, + ) + monkeypatch.setattr( + "infection_monkey.config.WormConfiguration.PBA_windows_filename", + CUSTOM_WINDOWS_FILENAME, + ) + return UsersPBA() + + +def test_command_list_windows_custom_file_and_cmd_separate( + mock_UsersPBA_windows_custom_file_and_cmd_separate, +): + expected_command_list = [ + f"cd {MONKEY_DIR_PATH} & {CUSTOM_WINDOWS_CMD_SEPARATE}", + f"{MONKEY_DIR_PATH}{CUSTOM_WINDOWS_FILENAME} & del {MONKEY_DIR_PATH}{CUSTOM_WINDOWS_FILENAME}", + ] + assert ( + mock_UsersPBA_windows_custom_file_and_cmd_separate.command_list + == expected_command_list + ) + + +@pytest.fixture +def mock_UsersPBA_linux_custom_file_and_cmd_related( + set_os_linux, fake_monkey_dir_path, monkeypatch +): + monkeypatch.setattr( + "infection_monkey.config.WormConfiguration.custom_PBA_linux_cmd", + CUSTOM_LINUX_CMD_RELATED, + ) + monkeypatch.setattr( + "infection_monkey.config.WormConfiguration.PBA_linux_filename", + CUSTOM_LINUX_FILENAME, + ) + return UsersPBA() + + +def test_command_list_linux_custom_file_and_cmd_related( + mock_UsersPBA_linux_custom_file_and_cmd_related, +): + expected_command_list = [f"cd {MONKEY_DIR_PATH} ; {CUSTOM_LINUX_CMD_RELATED}"] + assert ( + mock_UsersPBA_linux_custom_file_and_cmd_related.command_list + == expected_command_list + ) + + +@pytest.fixture +def mock_UsersPBA_windows_custom_file_and_cmd_related( + set_os_windows, fake_monkey_dir_path, monkeypatch +): + + monkeypatch.setattr( + "infection_monkey.config.WormConfiguration.custom_PBA_windows_cmd", + CUSTOM_WINDOWS_CMD_RELATED, + ) + monkeypatch.setattr( + "infection_monkey.config.WormConfiguration.PBA_windows_filename", + CUSTOM_WINDOWS_FILENAME, + ) + return UsersPBA() + + +def test_command_list_windows_custom_file_and_cmd_related( + mock_UsersPBA_windows_custom_file_and_cmd_related, +): + expected_command_list = [ + f"cd {MONKEY_DIR_PATH} & {CUSTOM_WINDOWS_CMD_RELATED}", + ] + assert ( + mock_UsersPBA_windows_custom_file_and_cmd_related.command_list + == expected_command_list + ) + + +@pytest.fixture +def mock_UsersPBA_linux_custom_file(set_os_linux, fake_monkey_dir_path, monkeypatch): + + monkeypatch.setattr( + "infection_monkey.config.WormConfiguration.custom_PBA_linux_cmd", None + ) + monkeypatch.setattr( + "infection_monkey.config.WormConfiguration.PBA_linux_filename", + CUSTOM_LINUX_FILENAME, + ) + return UsersPBA() + + +def test_command_list_linux_custom_file(mock_UsersPBA_linux_custom_file): + expected_command_list = [ + f"chmod +x {MONKEY_DIR_PATH}{CUSTOM_LINUX_FILENAME} ; {MONKEY_DIR_PATH}{CUSTOM_LINUX_FILENAME} ; " + + f"rm {MONKEY_DIR_PATH}{CUSTOM_LINUX_FILENAME}" + ] + + assert mock_UsersPBA_linux_custom_file.command_list == expected_command_list + + +@pytest.fixture +def mock_UsersPBA_windows_custom_file( + set_os_windows, fake_monkey_dir_path, monkeypatch +): + + monkeypatch.setattr( + "infection_monkey.config.WormConfiguration.custom_PBA_windows_cmd", None + ) + monkeypatch.setattr( + "infection_monkey.config.WormConfiguration.PBA_windows_filename", + CUSTOM_WINDOWS_FILENAME, + ) + return UsersPBA() + + +def test_command_list_windows_custom_file(mock_UsersPBA_windows_custom_file): + expected_command_list = [ + f"{MONKEY_DIR_PATH}{CUSTOM_WINDOWS_FILENAME} & del {MONKEY_DIR_PATH}{CUSTOM_WINDOWS_FILENAME}", + ] + assert mock_UsersPBA_windows_custom_file.command_list == expected_command_list + + +@pytest.fixture +def mock_UsersPBA_linux_custom_cmd(set_os_linux, fake_monkey_dir_path, monkeypatch): + + monkeypatch.setattr( + "infection_monkey.config.WormConfiguration.custom_PBA_linux_cmd", + CUSTOM_LINUX_CMD_SEPARATE, + ) + monkeypatch.setattr( + "infection_monkey.config.WormConfiguration.PBA_linux_filename", None + ) + return UsersPBA() + + +def test_command_list_linux_custom_cmd(mock_UsersPBA_linux_custom_cmd): + expected_command_list = [CUSTOM_LINUX_CMD_SEPARATE] + assert mock_UsersPBA_linux_custom_cmd.command_list == expected_command_list + + +@pytest.fixture +def mock_UsersPBA_windows_custom_cmd(set_os_windows, fake_monkey_dir_path, monkeypatch): + + monkeypatch.setattr( + "infection_monkey.config.WormConfiguration.custom_PBA_windows_cmd", + CUSTOM_WINDOWS_CMD_SEPARATE, + ) + monkeypatch.setattr( + "infection_monkey.config.WormConfiguration.PBA_windows_filename", None + ) + return UsersPBA() + + +def test_command_list_windows_custom_cmd(mock_UsersPBA_windows_custom_cmd): + expected_command_list = [CUSTOM_WINDOWS_CMD_SEPARATE] + assert mock_UsersPBA_windows_custom_cmd.command_list == expected_command_list From 9167aa6460e70f2febbf4d740da841ce8ede97bf Mon Sep 17 00:00:00 2001 From: Shreya Date: Wed, 10 Mar 2021 12:44:51 +0530 Subject: [PATCH 09/16] Unit test modifications --- .../tests/actions/test_users_custom_pba.py | 133 ++++-------------- 1 file changed, 29 insertions(+), 104 deletions(-) diff --git a/monkey/infection_monkey/post_breach/tests/actions/test_users_custom_pba.py b/monkey/infection_monkey/post_breach/tests/actions/test_users_custom_pba.py index dab6ee59e..83af6e00a 100644 --- a/monkey/infection_monkey/post_breach/tests/actions/test_users_custom_pba.py +++ b/monkey/infection_monkey/post_breach/tests/actions/test_users_custom_pba.py @@ -1,16 +1,13 @@ import pytest from infection_monkey.post_breach.actions.users_custom_pba import ( - DEFAULT_LINUX_COMMAND, DEFAULT_WINDOWS_COMMAND, DIR_CHANGE_LINUX, - DIR_CHANGE_WINDOWS, UsersPBA) + DIR_CHANGE_LINUX, DIR_CHANGE_WINDOWS, UsersPBA) MONKEY_DIR_PATH = "/dir/to/monkey/" -CUSTOM_LINUX_CMD_SEPARATE = "command-for-linux" +CUSTOM_LINUX_CMD = "command-for-linux" CUSTOM_LINUX_FILENAME = "filename-for-linux" -CUSTOM_LINUX_CMD_RELATED = f"command-with-{CUSTOM_LINUX_FILENAME}" -CUSTOM_WINDOWS_CMD_SEPARATE = "command-for-windows" +CUSTOM_WINDOWS_CMD = "command-for-windows" CUSTOM_WINDOWS_FILENAME = "filename-for-windows" -CUSTOM_WINDOWS_CMD_RELATED = f"command-with-{CUSTOM_WINDOWS_FILENAME}" @pytest.fixture @@ -38,12 +35,12 @@ def set_os_windows(monkeypatch): @pytest.fixture -def mock_UsersPBA_linux_custom_file_and_cmd_separate( +def mock_UsersPBA_linux_custom_file_and_cmd( set_os_linux, fake_monkey_dir_path, monkeypatch ): monkeypatch.setattr( "infection_monkey.config.WormConfiguration.custom_PBA_linux_cmd", - CUSTOM_LINUX_CMD_SEPARATE, + CUSTOM_LINUX_CMD, ) monkeypatch.setattr( "infection_monkey.config.WormConfiguration.PBA_linux_filename", @@ -52,27 +49,20 @@ def mock_UsersPBA_linux_custom_file_and_cmd_separate( return UsersPBA() -def test_command_list_linux_custom_file_and_cmd_separate( - mock_UsersPBA_linux_custom_file_and_cmd_separate, +def test_command_linux_custom_file_and_cmd( + mock_UsersPBA_linux_custom_file_and_cmd, ): - expected_command_list = [ - f"cd {MONKEY_DIR_PATH} ; {CUSTOM_LINUX_CMD_SEPARATE}", - f"chmod +x {MONKEY_DIR_PATH}{CUSTOM_LINUX_FILENAME} ; {MONKEY_DIR_PATH}{CUSTOM_LINUX_FILENAME} ; " + - f"rm {MONKEY_DIR_PATH}{CUSTOM_LINUX_FILENAME}", - ] - assert ( - mock_UsersPBA_linux_custom_file_and_cmd_separate.command_list - == expected_command_list - ) + expected_command = f"cd {MONKEY_DIR_PATH} ; {CUSTOM_LINUX_CMD}" + assert mock_UsersPBA_linux_custom_file_and_cmd.command == expected_command @pytest.fixture -def mock_UsersPBA_windows_custom_file_and_cmd_separate( +def mock_UsersPBA_windows_custom_file_and_cmd( set_os_windows, fake_monkey_dir_path, monkeypatch ): monkeypatch.setattr( "infection_monkey.config.WormConfiguration.custom_PBA_windows_cmd", - CUSTOM_WINDOWS_CMD_SEPARATE, + CUSTOM_WINDOWS_CMD, ) monkeypatch.setattr( "infection_monkey.config.WormConfiguration.PBA_windows_filename", @@ -81,70 +71,11 @@ def mock_UsersPBA_windows_custom_file_and_cmd_separate( return UsersPBA() -def test_command_list_windows_custom_file_and_cmd_separate( - mock_UsersPBA_windows_custom_file_and_cmd_separate, +def test_command_windows_custom_file_and_cmd( + mock_UsersPBA_windows_custom_file_and_cmd, ): - expected_command_list = [ - f"cd {MONKEY_DIR_PATH} & {CUSTOM_WINDOWS_CMD_SEPARATE}", - f"{MONKEY_DIR_PATH}{CUSTOM_WINDOWS_FILENAME} & del {MONKEY_DIR_PATH}{CUSTOM_WINDOWS_FILENAME}", - ] - assert ( - mock_UsersPBA_windows_custom_file_and_cmd_separate.command_list - == expected_command_list - ) - - -@pytest.fixture -def mock_UsersPBA_linux_custom_file_and_cmd_related( - set_os_linux, fake_monkey_dir_path, monkeypatch -): - monkeypatch.setattr( - "infection_monkey.config.WormConfiguration.custom_PBA_linux_cmd", - CUSTOM_LINUX_CMD_RELATED, - ) - monkeypatch.setattr( - "infection_monkey.config.WormConfiguration.PBA_linux_filename", - CUSTOM_LINUX_FILENAME, - ) - return UsersPBA() - - -def test_command_list_linux_custom_file_and_cmd_related( - mock_UsersPBA_linux_custom_file_and_cmd_related, -): - expected_command_list = [f"cd {MONKEY_DIR_PATH} ; {CUSTOM_LINUX_CMD_RELATED}"] - assert ( - mock_UsersPBA_linux_custom_file_and_cmd_related.command_list - == expected_command_list - ) - - -@pytest.fixture -def mock_UsersPBA_windows_custom_file_and_cmd_related( - set_os_windows, fake_monkey_dir_path, monkeypatch -): - - monkeypatch.setattr( - "infection_monkey.config.WormConfiguration.custom_PBA_windows_cmd", - CUSTOM_WINDOWS_CMD_RELATED, - ) - monkeypatch.setattr( - "infection_monkey.config.WormConfiguration.PBA_windows_filename", - CUSTOM_WINDOWS_FILENAME, - ) - return UsersPBA() - - -def test_command_list_windows_custom_file_and_cmd_related( - mock_UsersPBA_windows_custom_file_and_cmd_related, -): - expected_command_list = [ - f"cd {MONKEY_DIR_PATH} & {CUSTOM_WINDOWS_CMD_RELATED}", - ] - assert ( - mock_UsersPBA_windows_custom_file_and_cmd_related.command_list - == expected_command_list - ) + expected_command = f"cd {MONKEY_DIR_PATH} & {CUSTOM_WINDOWS_CMD}" + assert mock_UsersPBA_windows_custom_file_and_cmd.command == expected_command @pytest.fixture @@ -160,13 +91,9 @@ def mock_UsersPBA_linux_custom_file(set_os_linux, fake_monkey_dir_path, monkeypa return UsersPBA() -def test_command_list_linux_custom_file(mock_UsersPBA_linux_custom_file): - expected_command_list = [ - f"chmod +x {MONKEY_DIR_PATH}{CUSTOM_LINUX_FILENAME} ; {MONKEY_DIR_PATH}{CUSTOM_LINUX_FILENAME} ; " + - f"rm {MONKEY_DIR_PATH}{CUSTOM_LINUX_FILENAME}" - ] - - assert mock_UsersPBA_linux_custom_file.command_list == expected_command_list +def test_command_linux_custom_file(mock_UsersPBA_linux_custom_file): + expected_command = "" + assert mock_UsersPBA_linux_custom_file.command == expected_command @pytest.fixture @@ -184,11 +111,9 @@ def mock_UsersPBA_windows_custom_file( return UsersPBA() -def test_command_list_windows_custom_file(mock_UsersPBA_windows_custom_file): - expected_command_list = [ - f"{MONKEY_DIR_PATH}{CUSTOM_WINDOWS_FILENAME} & del {MONKEY_DIR_PATH}{CUSTOM_WINDOWS_FILENAME}", - ] - assert mock_UsersPBA_windows_custom_file.command_list == expected_command_list +def test_command_windows_custom_file(mock_UsersPBA_windows_custom_file): + expected_command = "" + assert mock_UsersPBA_windows_custom_file.command == expected_command @pytest.fixture @@ -196,7 +121,7 @@ def mock_UsersPBA_linux_custom_cmd(set_os_linux, fake_monkey_dir_path, monkeypat monkeypatch.setattr( "infection_monkey.config.WormConfiguration.custom_PBA_linux_cmd", - CUSTOM_LINUX_CMD_SEPARATE, + CUSTOM_LINUX_CMD, ) monkeypatch.setattr( "infection_monkey.config.WormConfiguration.PBA_linux_filename", None @@ -204,9 +129,9 @@ def mock_UsersPBA_linux_custom_cmd(set_os_linux, fake_monkey_dir_path, monkeypat return UsersPBA() -def test_command_list_linux_custom_cmd(mock_UsersPBA_linux_custom_cmd): - expected_command_list = [CUSTOM_LINUX_CMD_SEPARATE] - assert mock_UsersPBA_linux_custom_cmd.command_list == expected_command_list +def test_command_linux_custom_cmd(mock_UsersPBA_linux_custom_cmd): + expected_command = CUSTOM_LINUX_CMD + assert mock_UsersPBA_linux_custom_cmd.command == expected_command @pytest.fixture @@ -214,7 +139,7 @@ def mock_UsersPBA_windows_custom_cmd(set_os_windows, fake_monkey_dir_path, monke monkeypatch.setattr( "infection_monkey.config.WormConfiguration.custom_PBA_windows_cmd", - CUSTOM_WINDOWS_CMD_SEPARATE, + CUSTOM_WINDOWS_CMD, ) monkeypatch.setattr( "infection_monkey.config.WormConfiguration.PBA_windows_filename", None @@ -222,6 +147,6 @@ def mock_UsersPBA_windows_custom_cmd(set_os_windows, fake_monkey_dir_path, monke return UsersPBA() -def test_command_list_windows_custom_cmd(mock_UsersPBA_windows_custom_cmd): - expected_command_list = [CUSTOM_WINDOWS_CMD_SEPARATE] - assert mock_UsersPBA_windows_custom_cmd.command_list == expected_command_list +def test_command_windows_custom_cmd(mock_UsersPBA_windows_custom_cmd): + expected_command = CUSTOM_WINDOWS_CMD + assert mock_UsersPBA_windows_custom_cmd.command == expected_command From 4928109be2ff9c0aff6c7ad4894147b2312696ab Mon Sep 17 00:00:00 2001 From: Shreya Date: Thu, 11 Mar 2021 18:42:01 +0530 Subject: [PATCH 10/16] Rephrase custom PBA file config descriptions --- .../cc/services/config_schema/monkey.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/monkey/monkey_island/cc/services/config_schema/monkey.py b/monkey/monkey_island/cc/services/config_schema/monkey.py index faf27c481..f54b79886 100644 --- a/monkey/monkey_island/cc/services/config_schema/monkey.py +++ b/monkey/monkey_island/cc/services/config_schema/monkey.py @@ -11,33 +11,33 @@ MONKEY = { "type": "object", "properties": { "custom_PBA_linux_cmd": { - "title": "Linux post breach command", + "title": "Linux post-breach command", "type": "string", "default": "", "description": "Linux command to be executed after breaching." }, "PBA_linux_file": { - "title": "Linux post breach file", + "title": "Linux post-breach file", "type": "string", "format": "data-url", "description": "File to be uploaded after breaching. " - "If you want the file to be executed, " - "specify it in the 'Linux post breach command' field. " + "Use the 'Linux post-breach command' field to " + "change permissions, run, or delete the file. " "Reference your file by filename." }, "custom_PBA_windows_cmd": { - "title": "Windows post breach command", + "title": "Windows post-breach command", "type": "string", "default": "", "description": "Windows command to be executed after breaching." }, "PBA_windows_file": { - "title": "Windows post breach file", + "title": "Windows post-breach file", "type": "string", "format": "data-url", "description": "File to be uploaded after breaching. " - "If you want the file to be executed, " - "specify it in the 'Windows post breach command' field. " + "Use the 'Windows post-breach command' field to " + "change permissions, run, or delete the file. " "Reference your file by filename." }, "PBA_windows_filename": { From 2b4fd9e9a7dae299887600a5258b6141cb0729e1 Mon Sep 17 00:00:00 2001 From: Shreya Date: Thu, 11 Mar 2021 18:55:00 +0530 Subject: [PATCH 11/16] Rephrase custom PBA command config descriptions --- .../monkey_island/cc/services/config_schema/monkey.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/monkey/monkey_island/cc/services/config_schema/monkey.py b/monkey/monkey_island/cc/services/config_schema/monkey.py index f54b79886..82a394b65 100644 --- a/monkey/monkey_island/cc/services/config_schema/monkey.py +++ b/monkey/monkey_island/cc/services/config_schema/monkey.py @@ -14,7 +14,10 @@ MONKEY = { "title": "Linux post-breach command", "type": "string", "default": "", - "description": "Linux command to be executed after breaching." + "description": "Command to be executed after breaching. " + "Use this field to run custom commands or execute uploaded " + "files on exploited machines.\nExample: " + "\"chmod +x ./my_script.sh; ./my_script.sh ; rm ./my_script.sh\"" }, "PBA_linux_file": { "title": "Linux post-breach file", @@ -29,7 +32,10 @@ MONKEY = { "title": "Windows post-breach command", "type": "string", "default": "", - "description": "Windows command to be executed after breaching." + "description": "Command to be executed after breaching. " + "Use this field to run custom commands or execute uploaded " + "files on exploited machines.\nExample: " + "\"my_script.bat & del my_script.bat\"" }, "PBA_windows_file": { "title": "Windows post-breach file", From fd058c7ff0f10ca154e17d919262e1b859c4c059 Mon Sep 17 00:00:00 2001 From: VakarisZ Date: Tue, 16 Mar 2021 09:11:45 +0200 Subject: [PATCH 12/16] Refactored ScoutSuite into a separate package rather than submodule --- .gitmodules | 3 --- monkey/common/cloud/scoutsuite | 1 - monkey/infection_monkey/monkey.spec | 27 ++++++++++++------- monkey/infection_monkey/requirements.txt | 1 + .../scoutsuite_collector/__init__.py | 15 ----------- .../scoutsuite_collector/scoutsuite_api.py | 5 ---- .../scoutsuite_collector.py | 13 ++++----- .../telemetry/scoutsuite_telem.py | 4 +-- .../zero_trust/scoutsuite/__init__.py | 13 --------- .../scoutsuite/scoutsuite_auth_service.py | 2 +- monkey/monkey_island/requirements.txt | 1 + 11 files changed, 29 insertions(+), 56 deletions(-) delete mode 160000 monkey/common/cloud/scoutsuite delete mode 100644 monkey/infection_monkey/system_info/collectors/scoutsuite_collector/__init__.py delete mode 100644 monkey/infection_monkey/system_info/collectors/scoutsuite_collector/scoutsuite_api.py delete mode 100644 monkey/monkey_island/cc/services/zero_trust/scoutsuite/__init__.py diff --git a/.gitmodules b/.gitmodules index b898f160a..2fb33dd37 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,6 +4,3 @@ [submodule "docs/themes/learn"] path = docs/themes/learn url = https://github.com/guardicode/hugo-theme-learn.git -[submodule "monkey/infection_monkey/system_info/collectors/scoutsuite"] - path = monkey/common/cloud/scoutsuite - url = https://github.com/guardicode/ScoutSuite.git diff --git a/monkey/common/cloud/scoutsuite b/monkey/common/cloud/scoutsuite deleted file mode 160000 index 9de1e78ba..000000000 --- a/monkey/common/cloud/scoutsuite +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 9de1e78ba475f925c66c5b645564ec9eb08e2309 diff --git a/monkey/infection_monkey/monkey.spec b/monkey/infection_monkey/monkey.spec index 51bd4bb83..2031ee92a 100644 --- a/monkey/infection_monkey/monkey.spec +++ b/monkey/infection_monkey/monkey.spec @@ -1,15 +1,17 @@ # -*- mode: python -*- import os -import sys import platform - +import sys __author__ = 'itay.mizeretz' +from PyInstaller.utils.hooks import collect_data_files + block_cipher = None def main(): + print(collect_data_files('policyuniverse')) a = Analysis(['main.py'], pathex=['..'], hiddenimports=get_hidden_imports(), @@ -17,7 +19,7 @@ def main(): runtime_hooks=None, binaries=None, datas=[ - ("../common/BUILD", "/common") + ("../common/BUILD", "/common") ], excludes=None, win_no_prefer_redirects=None, @@ -48,7 +50,7 @@ def is_windows(): def is_32_bit(): - return sys.maxsize <= 2**32 + return sys.maxsize <= 2 ** 32 def get_bin_folder(): @@ -79,7 +81,12 @@ def get_linux_only_binaries(): def get_hidden_imports(): - return ['_cffi_backend', 'queue', '_mssql'] if is_windows() else ['_cffi_backend','_mssql'] + imports = ['ScoutSuite'] + if is_windows(): + imports.extend(['_cffi_backend', 'queue', '_mssql']) + else: + imports.extend(['_cffi_backend', '_mssql']) + return imports def get_sc_binaries(): @@ -94,15 +101,15 @@ def get_traceroute_binaries(): def get_monkey_filename(): name = 'monkey-' if is_windows(): - name = name+"windows-" + name = name + "windows-" else: - name = name+"linux-" + name = name + "linux-" if is_32_bit(): - name = name+"32" + name = name + "32" else: - name = name+"64" + name = name + "64" if is_windows(): - name = name+".exe" + name = name + ".exe" return name diff --git a/monkey/infection_monkey/requirements.txt b/monkey/infection_monkey/requirements.txt index dc0ab227e..e478095ac 100644 --- a/monkey/infection_monkey/requirements.txt +++ b/monkey/infection_monkey/requirements.txt @@ -16,3 +16,4 @@ pypykatz==0.3.12 pysmb==1.2.5 requests>=2.24 wmi==1.5.1 ; sys_platform == 'win32' +git+https://github.com/guardicode/ScoutSuite diff --git a/monkey/infection_monkey/system_info/collectors/scoutsuite_collector/__init__.py b/monkey/infection_monkey/system_info/collectors/scoutsuite_collector/__init__.py deleted file mode 100644 index 97e736b4b..000000000 --- a/monkey/infection_monkey/system_info/collectors/scoutsuite_collector/__init__.py +++ /dev/null @@ -1,15 +0,0 @@ -import pkgutil -import sys -from pathlib import PurePath - -_scoutsuite_api_package = pkgutil.get_loader('common.cloud.scoutsuite.ScoutSuite.__main__') - - -def _add_scoutsuite_to_python_path(): - scoutsuite_path = PurePath(_scoutsuite_api_package.path).parent.parent.__str__() - sys.path.append(scoutsuite_path) - - -# Add ScoutSuite to python path because this way -# we don't need to change any imports in ScoutSuite code -_add_scoutsuite_to_python_path() diff --git a/monkey/infection_monkey/system_info/collectors/scoutsuite_collector/scoutsuite_api.py b/monkey/infection_monkey/system_info/collectors/scoutsuite_collector/scoutsuite_api.py deleted file mode 100644 index 88ef32293..000000000 --- a/monkey/infection_monkey/system_info/collectors/scoutsuite_collector/scoutsuite_api.py +++ /dev/null @@ -1,5 +0,0 @@ -import common.cloud.scoutsuite.ScoutSuite.api_run as scoutsuite_api - - -def run(*args, **kwargs): - return scoutsuite_api.run(*args, **kwargs) diff --git a/monkey/infection_monkey/system_info/collectors/scoutsuite_collector/scoutsuite_collector.py b/monkey/infection_monkey/system_info/collectors/scoutsuite_collector/scoutsuite_collector.py index c637e3593..79aabea56 100644 --- a/monkey/infection_monkey/system_info/collectors/scoutsuite_collector/scoutsuite_collector.py +++ b/monkey/infection_monkey/system_info/collectors/scoutsuite_collector/scoutsuite_collector.py @@ -1,8 +1,9 @@ import logging from typing import Union -import infection_monkey.system_info.collectors.scoutsuite_collector.scoutsuite_api as scoutsuite_api -from common.cloud.scoutsuite.ScoutSuite.providers.base.provider import BaseProvider +import ScoutSuite.api_run +from ScoutSuite.providers.base.provider import BaseProvider + from common.cloud.scoutsuite_consts import CloudProviders from common.utils.exceptions import ScoutSuiteScanError from infection_monkey.config import WormConfiguration @@ -22,10 +23,10 @@ def scan_cloud_security(cloud_type: CloudProviders): def run_scoutsuite(cloud_type: str) -> Union[BaseProvider, dict]: - return scoutsuite_api.run(provider=cloud_type, - aws_access_key_id=WormConfiguration.aws_access_key_id, - aws_secret_access_key=WormConfiguration.aws_secret_access_key, - aws_session_token=WormConfiguration.aws_session_token) + return ScoutSuite.api_run.run(provider=cloud_type, + aws_access_key_id=WormConfiguration.aws_access_key_id, + aws_secret_access_key=WormConfiguration.aws_secret_access_key, + aws_session_token=WormConfiguration.aws_session_token) def send_scoutsuite_run_results(run_results: BaseProvider): diff --git a/monkey/infection_monkey/telemetry/scoutsuite_telem.py b/monkey/infection_monkey/telemetry/scoutsuite_telem.py index 16cf47bdd..ba112f8b9 100644 --- a/monkey/infection_monkey/telemetry/scoutsuite_telem.py +++ b/monkey/infection_monkey/telemetry/scoutsuite_telem.py @@ -1,5 +1,5 @@ -from common.cloud.scoutsuite.ScoutSuite.output.result_encoder import ScoutJsonEncoder -from common.cloud.scoutsuite.ScoutSuite.providers.base.provider import BaseProvider +from ScoutSuite.output.result_encoder import ScoutJsonEncoder +from ScoutSuite.providers.base.provider import BaseProvider from common.common_consts.telem_categories import TelemCategoryEnum from infection_monkey.telemetry.base_telem import BaseTelem diff --git a/monkey/monkey_island/cc/services/zero_trust/scoutsuite/__init__.py b/monkey/monkey_island/cc/services/zero_trust/scoutsuite/__init__.py deleted file mode 100644 index e8a36338b..000000000 --- a/monkey/monkey_island/cc/services/zero_trust/scoutsuite/__init__.py +++ /dev/null @@ -1,13 +0,0 @@ -import pkgutil -import sys -from pathlib import PurePath - -_scoutsuite_api_package = pkgutil.get_loader('common.cloud.scoutsuite.ScoutSuite.__main__') - - -def _add_scoutsuite_to_python_path(): - scoutsuite_path = PurePath(_scoutsuite_api_package.path).parent.parent.__str__() - sys.path.append(scoutsuite_path) - - -_add_scoutsuite_to_python_path() diff --git a/monkey/monkey_island/cc/services/zero_trust/scoutsuite/scoutsuite_auth_service.py b/monkey/monkey_island/cc/services/zero_trust/scoutsuite/scoutsuite_auth_service.py index b5d405234..701598168 100644 --- a/monkey/monkey_island/cc/services/zero_trust/scoutsuite/scoutsuite_auth_service.py +++ b/monkey/monkey_island/cc/services/zero_trust/scoutsuite/scoutsuite_auth_service.py @@ -14,7 +14,7 @@ def is_cloud_authentication_setup(provider: CloudProviders) -> Tuple[bool, str]: if is_aws_keys_setup(): return True, "AWS keys already setup." - import common.cloud.scoutsuite.ScoutSuite.providers.aws.authentication_strategy as auth_strategy + import ScoutSuite.providers.aws.authentication_strategy as auth_strategy try: profile = auth_strategy.AWSAuthenticationStrategy().authenticate() return True, f" Profile \"{profile.session.profile_name}\" is already setup. " diff --git a/monkey/monkey_island/requirements.txt b/monkey/monkey_island/requirements.txt index 3cb3a4e42..ddbf2418a 100644 --- a/monkey/monkey_island/requirements.txt +++ b/monkey/monkey_island/requirements.txt @@ -26,5 +26,6 @@ tqdm>=4.47 virtualenv>=20.0.26 werkzeug>=1.0.1 wheel>=0.34.2 +git+https://github.com/guardicode/ScoutSuite pyjwt>=1.5.1 # not directly required, pinned by Snyk to avoid a vulnerability From 24564fd0f04c1cc861fa81f8ff810f20f3dd91b4 Mon Sep 17 00:00:00 2001 From: VakarisZ Date: Wed, 17 Mar 2021 10:20:17 +0200 Subject: [PATCH 13/16] Removed ScoutSuite from travis, since it's no longer a submodule --- .travis.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 668d9cdc3..8ac8db204 100644 --- a/.travis.yml +++ b/.travis.yml @@ -27,7 +27,6 @@ install: - pip install flake8 pytest pytest-cov dlint isort # for next stages - pip install coverage # for code coverage - pip install -r monkey/infection_monkey/requirements.txt # for unit tests -- pip install -r monkey/common/cloud/scoutsuite/requirements.txt - pip install pipdeptree # Fail builds on possible conflicting dependencies. - pipdeptree --warn fail @@ -56,7 +55,7 @@ install: script: # Check Python code ## Check syntax errors and fail the build if any are found. -- flake8 ./monkey --exclude=monkey/common/cloud/scoutsuite --config=./ci_scripts/flake8_syntax_check.ini +- flake8 ./monkey --config=./ci_scripts/flake8_syntax_check.ini ## Warn about linter issues. ### --exit-zero forces Flake8 to use the exit status code 0 even if there are errors, which means this will NOT fail the build. From 80776f2b1db81a9f2770119ddffecd7ec3975e19 Mon Sep 17 00:00:00 2001 From: VakarisZ Date: Wed, 17 Mar 2021 12:45:08 +0200 Subject: [PATCH 14/16] Minor spec file style improvement --- monkey/infection_monkey/monkey.spec | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/monkey/infection_monkey/monkey.spec b/monkey/infection_monkey/monkey.spec index 2031ee92a..f9b656611 100644 --- a/monkey/infection_monkey/monkey.spec +++ b/monkey/infection_monkey/monkey.spec @@ -18,9 +18,7 @@ def main(): hookspath=['./pyinstaller_hooks'], runtime_hooks=None, binaries=None, - datas=[ - ("../common/BUILD", "/common") - ], + datas=[("../common/BUILD", "/common")], excludes=None, win_no_prefer_redirects=None, win_private_assemblies=None, From 6a13fa90e60e2cdf944c776de454ca5bb1bad373 Mon Sep 17 00:00:00 2001 From: VakarisZ Date: Tue, 16 Mar 2021 16:51:21 +0200 Subject: [PATCH 15/16] Small profiling decorator improvement --- monkey/monkey_island/cc/test_common/profiling/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/monkey/monkey_island/cc/test_common/profiling/README.md b/monkey/monkey_island/cc/test_common/profiling/README.md index 1c1446b2f..d0cb92bfa 100644 --- a/monkey/monkey_island/cc/test_common/profiling/README.md +++ b/monkey/monkey_island/cc/test_common/profiling/README.md @@ -2,7 +2,7 @@ To profile specific methods on island a `@profile(sort_args=['cumulative'], print_args=[100])` decorator can be used. -Use it as any other decorator. After decorated method is used, a file will appear in a +Use it as a parameterised decorator(`@profile()`). After decorated method is used, a file will appear in a directory provided in `profiler_decorator.py`. Filename describes the path of the method that was profiled. For example if method `monkey_island/cc/resources/netmap.get` was profiled, then the results of this profiling will appear in From 3ca7537a99e11b192d233ed5ad471c1c3d91c540 Mon Sep 17 00:00:00 2001 From: VakarisZ Date: Wed, 17 Mar 2021 10:02:13 +0200 Subject: [PATCH 16/16] ScoutSuite performance upgrades. --- monkey/common/utils/code_utils.py | 10 ++++++++++ .../cc/services/telemetry/processing/scoutsuite.py | 7 ++++--- .../zero_trust/scoutsuite/data_parsing/rule_parser.py | 5 ++--- .../rule_path_building/abstract_rule_path_creator.py | 4 ++-- 4 files changed, 18 insertions(+), 8 deletions(-) diff --git a/monkey/common/utils/code_utils.py b/monkey/common/utils/code_utils.py index 214e6d108..d9ad573b1 100644 --- a/monkey/common/utils/code_utils.py +++ b/monkey/common/utils/code_utils.py @@ -1,5 +1,8 @@ # abstract, static method decorator # noinspection PyPep8Naming +from typing import List + + class abstractstatic(staticmethod): __slots__ = () @@ -8,3 +11,10 @@ class abstractstatic(staticmethod): function.__isabstractmethod__ = True __isabstractmethod__ = True + + +def get_value_from_dict(dict_data: dict, path: List[str]): + current_data = dict_data + for key in path: + current_data = current_data[key] + return current_data diff --git a/monkey/monkey_island/cc/services/telemetry/processing/scoutsuite.py b/monkey/monkey_island/cc/services/telemetry/processing/scoutsuite.py index 8ee4737e8..9160861ea 100644 --- a/monkey/monkey_island/cc/services/telemetry/processing/scoutsuite.py +++ b/monkey/monkey_island/cc/services/telemetry/processing/scoutsuite.py @@ -3,6 +3,7 @@ import json from monkey_island.cc.database import mongo from monkey_island.cc.models.zero_trust.scoutsuite_data_json import ScoutSuiteRawDataJson from monkey_island.cc.services.zero_trust.scoutsuite.consts.scoutsuite_findings_list import SCOUTSUITE_FINDINGS +from monkey_island.cc.services.zero_trust.scoutsuite.consts.service_consts import SERVICES from monkey_island.cc.services.zero_trust.scoutsuite.data_parsing.rule_parser import RuleParser from monkey_island.cc.services.zero_trust.scoutsuite.scoutsuite_rule_service import ScoutSuiteRuleService from monkey_island.cc.services.zero_trust.scoutsuite.scoutsuite_zt_finding_service import ScoutSuiteZTFindingService @@ -13,14 +14,14 @@ def process_scoutsuite_telemetry(telemetry_json): telemetry_json['data'] = json.dumps(telemetry_json['data']) ScoutSuiteRawDataJson.add_scoutsuite_data(telemetry_json['data']) scoutsuite_data = json.loads(telemetry_json['data'])['data'] - create_scoutsuite_findings(scoutsuite_data) + create_scoutsuite_findings(scoutsuite_data[SERVICES]) update_data(telemetry_json) -def create_scoutsuite_findings(scoutsuite_data): +def create_scoutsuite_findings(cloud_services: dict): for finding in SCOUTSUITE_FINDINGS: for rule in finding.rules: - rule_data = RuleParser.get_rule_data(scoutsuite_data, rule) + rule_data = RuleParser.get_rule_data(cloud_services, rule) rule = ScoutSuiteRuleService.get_rule_from_rule_data(rule_data) ScoutSuiteZTFindingService.process_rule(finding, rule) diff --git a/monkey/monkey_island/cc/services/zero_trust/scoutsuite/data_parsing/rule_parser.py b/monkey/monkey_island/cc/services/zero_trust/scoutsuite/data_parsing/rule_parser.py index e07431541..935f1c989 100644 --- a/monkey/monkey_island/cc/services/zero_trust/scoutsuite/data_parsing/rule_parser.py +++ b/monkey/monkey_island/cc/services/zero_trust/scoutsuite/data_parsing/rule_parser.py @@ -1,7 +1,6 @@ from enum import Enum -import dpath.util - +from common.utils.code_utils import get_value_from_dict from common.utils.exceptions import RulePathCreatorNotFound from monkey_island.cc.services.zero_trust.scoutsuite.data_parsing.rule_path_building.rule_path_creators_list import \ RULE_PATH_CREATORS_LIST @@ -23,7 +22,7 @@ class RuleParser: @staticmethod def get_rule_data(scoutsuite_data: dict, rule_name: Enum) -> dict: rule_path = RuleParser._get_rule_path(rule_name) - return dpath.util.get(scoutsuite_data, rule_path) + return get_value_from_dict(scoutsuite_data, rule_path) @staticmethod def _get_rule_path(rule_name: Enum): diff --git a/monkey/monkey_island/cc/services/zero_trust/scoutsuite/data_parsing/rule_path_building/abstract_rule_path_creator.py b/monkey/monkey_island/cc/services/zero_trust/scoutsuite/data_parsing/rule_path_building/abstract_rule_path_creator.py index b4767124b..ee7f7c38b 100644 --- a/monkey/monkey_island/cc/services/zero_trust/scoutsuite/data_parsing/rule_path_building/abstract_rule_path_creator.py +++ b/monkey/monkey_island/cc/services/zero_trust/scoutsuite/data_parsing/rule_path_building/abstract_rule_path_creator.py @@ -3,7 +3,7 @@ from enum import Enum from typing import List, Type from monkey_island.cc.services.zero_trust.scoutsuite.consts.rule_names.rule_name_enum import RuleNameEnum -from monkey_island.cc.services.zero_trust.scoutsuite.consts.service_consts import FINDINGS, SERVICES, SERVICE_TYPES +from monkey_island.cc.services.zero_trust.scoutsuite.consts.service_consts import FINDINGS, SERVICE_TYPES class AbstractRulePathCreator(ABC): @@ -21,4 +21,4 @@ class AbstractRulePathCreator(ABC): @classmethod def build_rule_path(cls, rule_name: Enum) -> List[str]: assert(rule_name in cls.supported_rules) - return [SERVICES, cls.service_type.value, FINDINGS, rule_name.value] + return [cls.service_type.value, FINDINGS, rule_name.value]