From 40b1ae005846fe620fd3138c8832be42580749e2 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Wed, 30 Mar 2022 13:37:47 +0530 Subject: [PATCH 1/7] Agent: Modify puppet to run PBAs instead of using the mock puppet --- .../post_breach/actions/clear_command_history.py | 3 ++- .../post_breach/actions/collect_processes_list.py | 3 ++- .../post_breach/actions/communicate_as_backdoor_user.py | 3 ++- monkey/infection_monkey/post_breach/actions/hide_files.py | 6 ++++-- .../post_breach/actions/modify_shell_startup_files.py | 3 ++- .../infection_monkey/post_breach/actions/schedule_jobs.py | 6 ++++-- .../post_breach/actions/use_signed_scripts.py | 5 +++-- monkey/infection_monkey/puppet/puppet.py | 3 ++- 8 files changed, 21 insertions(+), 11 deletions(-) diff --git a/monkey/infection_monkey/post_breach/actions/clear_command_history.py b/monkey/infection_monkey/post_breach/actions/clear_command_history.py index e6ab2d23e..3ef363121 100644 --- a/monkey/infection_monkey/post_breach/actions/clear_command_history.py +++ b/monkey/infection_monkey/post_breach/actions/clear_command_history.py @@ -1,4 +1,5 @@ import subprocess +from typing import Dict from common.common_consts.post_breach_consts import POST_BREACH_CLEAR_CMD_HISTORY from infection_monkey.i_puppet.i_puppet import PostBreachData @@ -13,7 +14,7 @@ class ClearCommandHistory(PBA): def __init__(self, telemetry_messenger: ITelemetryMessenger): super().__init__(telemetry_messenger, name=POST_BREACH_CLEAR_CMD_HISTORY) - def run(self): + def run(self, options: Dict): results = [pba.run() for pba in self.clear_command_history_pba_list()] if results: # `self.command` is empty here diff --git a/monkey/infection_monkey/post_breach/actions/collect_processes_list.py b/monkey/infection_monkey/post_breach/actions/collect_processes_list.py index 409583d18..78102c595 100644 --- a/monkey/infection_monkey/post_breach/actions/collect_processes_list.py +++ b/monkey/infection_monkey/post_breach/actions/collect_processes_list.py @@ -1,4 +1,5 @@ import logging +from typing import Dict import psutil @@ -21,7 +22,7 @@ class ProcessListCollection(PBA): def __init__(self, telemetry_messenger: ITelemetryMessenger): super().__init__(telemetry_messenger, POST_BREACH_PROCESS_LIST_COLLECTION) - def run(self): + def run(self, options: Dict): """ Collects process information from the host. Currently lists process name, ID, parent ID, command line diff --git a/monkey/infection_monkey/post_breach/actions/communicate_as_backdoor_user.py b/monkey/infection_monkey/post_breach/actions/communicate_as_backdoor_user.py index 60990d67a..93b461c11 100644 --- a/monkey/infection_monkey/post_breach/actions/communicate_as_backdoor_user.py +++ b/monkey/infection_monkey/post_breach/actions/communicate_as_backdoor_user.py @@ -3,6 +3,7 @@ import random import shutil import string import subprocess +from typing import Dict from common.common_consts.post_breach_consts import POST_BREACH_COMMUNICATE_AS_BACKDOOR_USER from infection_monkey.i_puppet.i_puppet import PostBreachData @@ -39,7 +40,7 @@ class CommunicateAsBackdoorUser(PBA): telemetry_messenger, name=POST_BREACH_COMMUNICATE_AS_BACKDOOR_USER ) - def run(self): + def run(self, options: Dict): username = CommunicateAsBackdoorUser.get_random_new_user_name() try: password = get_random_password(14) diff --git a/monkey/infection_monkey/post_breach/actions/hide_files.py b/monkey/infection_monkey/post_breach/actions/hide_files.py index 457b9dafe..838fae222 100644 --- a/monkey/infection_monkey/post_breach/actions/hide_files.py +++ b/monkey/infection_monkey/post_breach/actions/hide_files.py @@ -1,3 +1,5 @@ +from typing import Dict + from common.common_consts.post_breach_consts import POST_BREACH_HIDDEN_FILES from infection_monkey.i_puppet.i_puppet import PostBreachData from infection_monkey.post_breach.pba import PBA @@ -21,7 +23,7 @@ class HiddenFiles(PBA): def __init__(self, telemetry_messenger: ITelemetryMessenger): super(HiddenFiles, self).__init__(telemetry_messenger, name=POST_BREACH_HIDDEN_FILES) - def run(self): + def run(self, options: Dict): # create hidden files and folders for function_to_get_commands in HIDDEN_FSO_CREATION_COMMANDS: linux_cmds, windows_cmds = function_to_get_commands() @@ -30,7 +32,7 @@ class HiddenFiles(PBA): linux_cmd=" ".join(linux_cmds), windows_cmd=windows_cmds, ) - super(HiddenFiles, self).run() + super(HiddenFiles, self).run(options) if is_windows_os(): # use winAPI result, status = get_winAPI_to_hide_files() diff --git a/monkey/infection_monkey/post_breach/actions/modify_shell_startup_files.py b/monkey/infection_monkey/post_breach/actions/modify_shell_startup_files.py index 4d755567b..9b15de77f 100644 --- a/monkey/infection_monkey/post_breach/actions/modify_shell_startup_files.py +++ b/monkey/infection_monkey/post_breach/actions/modify_shell_startup_files.py @@ -1,4 +1,5 @@ import subprocess +from typing import Dict from common.common_consts.post_breach_consts import POST_BREACH_SHELL_STARTUP_FILE_MODIFICATION from infection_monkey.i_puppet.i_puppet import PostBreachData @@ -19,7 +20,7 @@ class ModifyShellStartupFiles(PBA): def __init__(self, telemetry_messenger: ITelemetryMessenger): super().__init__(telemetry_messenger, name=POST_BREACH_SHELL_STARTUP_FILE_MODIFICATION) - def run(self): + def run(self, options: Dict): results = [pba.run() for pba in self.modify_shell_startup_PBA_list()] if not results: results = [ diff --git a/monkey/infection_monkey/post_breach/actions/schedule_jobs.py b/monkey/infection_monkey/post_breach/actions/schedule_jobs.py index 8aeb0b42d..4ab023e35 100644 --- a/monkey/infection_monkey/post_breach/actions/schedule_jobs.py +++ b/monkey/infection_monkey/post_breach/actions/schedule_jobs.py @@ -1,3 +1,5 @@ +from typing import Dict + from common.common_consts.post_breach_consts import POST_BREACH_JOB_SCHEDULING from infection_monkey.post_breach.job_scheduling.job_scheduling import ( get_commands_to_schedule_jobs, @@ -22,7 +24,7 @@ class ScheduleJobs(PBA): windows_cmd=windows_cmds, ) - def run(self): - super(ScheduleJobs, self).run() + def run(self, options: Dict): + super(ScheduleJobs, self).run(options) remove_scheduled_jobs() return self.pba_data diff --git a/monkey/infection_monkey/post_breach/actions/use_signed_scripts.py b/monkey/infection_monkey/post_breach/actions/use_signed_scripts.py index d7323b54e..470e07bb1 100644 --- a/monkey/infection_monkey/post_breach/actions/use_signed_scripts.py +++ b/monkey/infection_monkey/post_breach/actions/use_signed_scripts.py @@ -1,5 +1,6 @@ import logging import subprocess +from typing import Dict from common.common_consts.post_breach_consts import POST_BREACH_SIGNED_SCRIPT_PROXY_EXEC from infection_monkey.post_breach.pba import PBA @@ -22,14 +23,14 @@ class SignedScriptProxyExecution(PBA): windows_cmd=" ".join(windows_cmds), ) - def run(self): + def run(self, options: Dict): original_comspec = "" try: if is_windows_os(): original_comspec = subprocess.check_output( # noqa: DUO116 "if defined COMSPEC echo %COMSPEC%", shell=True ).decode() - super().run() + super().run(options) return self.pba_data except Exception as e: logger.warning( diff --git a/monkey/infection_monkey/puppet/puppet.py b/monkey/infection_monkey/puppet/puppet.py index 061fe1132..ec3f97134 100644 --- a/monkey/infection_monkey/puppet/puppet.py +++ b/monkey/infection_monkey/puppet/puppet.py @@ -37,7 +37,8 @@ class Puppet(IPuppet): return credential_collector.collect_credentials(options) def run_pba(self, name: str, options: Dict) -> Iterable[PostBreachData]: - return self._mock_puppet.run_pba(name, options) + pba = self._plugin_registry.get_plugin(name, PluginType.POST_BREACH_ACTION) + return pba.run(options) def ping(self, host: str, timeout: float = CONNECTION_TIMEOUT) -> PingScanData: return network_scanning.ping(host, timeout) From 0be6af2d5c43a96c403e926ef0e238ab9af8455e Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Wed, 30 Mar 2022 13:42:17 +0530 Subject: [PATCH 2/7] Agent: Modify clear command history PBA to return pba_data and not None --- .../post_breach/actions/clear_command_history.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/monkey/infection_monkey/post_breach/actions/clear_command_history.py b/monkey/infection_monkey/post_breach/actions/clear_command_history.py index 3ef363121..fbffc9079 100644 --- a/monkey/infection_monkey/post_breach/actions/clear_command_history.py +++ b/monkey/infection_monkey/post_breach/actions/clear_command_history.py @@ -19,7 +19,8 @@ class ClearCommandHistory(PBA): if results: # `self.command` is empty here self.pba_data.append(PostBreachData(self.name, self.command, results)) - return self.pba_data + + return self.pba_data def clear_command_history_pba_list(self): return self.CommandHistoryPBAGenerator().get_clear_command_history_pbas() From 9f8463f707a1428862e9741335f5fbced2b6f565 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Wed, 30 Mar 2022 13:42:58 +0530 Subject: [PATCH 3/7] Agent: Modify PBA base class to accept options in its run method --- monkey/infection_monkey/post_breach/pba.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/monkey/infection_monkey/post_breach/pba.py b/monkey/infection_monkey/post_breach/pba.py index 9222d5e1a..302830e74 100644 --- a/monkey/infection_monkey/post_breach/pba.py +++ b/monkey/infection_monkey/post_breach/pba.py @@ -1,6 +1,6 @@ import logging import subprocess -from typing import Iterable +from typing import Dict, Iterable from common.utils.attack_utils import ScanStatus from infection_monkey.i_puppet.i_puppet import PostBreachData @@ -30,7 +30,7 @@ class PBA: self.pba_data = [] self.telemetry_messenger = telemetry_messenger - def run(self) -> Iterable[PostBreachData]: + def run(self, options: Dict) -> Iterable[PostBreachData]: """ Runs post breach action command """ From 501d32b1719360ef125bb0a9339b7346219df3c9 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Wed, 30 Mar 2022 13:44:38 +0530 Subject: [PATCH 4/7] Agent: Modify master to pass PostBreachData to PostBreachTelem --- monkey/infection_monkey/master/automated_master.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/monkey/infection_monkey/master/automated_master.py b/monkey/infection_monkey/master/automated_master.py index b499b578d..e5269fa64 100644 --- a/monkey/infection_monkey/master/automated_master.py +++ b/monkey/infection_monkey/master/automated_master.py @@ -201,9 +201,7 @@ class AutomatedMaster(IMaster): return for pba_data in self._puppet.run_pba(name, options): - self._telemetry_messenger.send_telemetry( - PostBreachTelem(pba_data.display_name, pba_data.command, pba_data.result) - ) + self._telemetry_messenger.send_telemetry(PostBreachTelem(pba_data)) def _can_propagate(self) -> bool: return True From a2bad110a1029ce3cf8c99a44d5741f17e74010c Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Wed, 30 Mar 2022 13:46:09 +0530 Subject: [PATCH 5/7] Agent: Modify PBA base class to return pba_data and not None --- monkey/infection_monkey/post_breach/pba.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/monkey/infection_monkey/post_breach/pba.py b/monkey/infection_monkey/post_breach/pba.py index 302830e74..ba027972e 100644 --- a/monkey/infection_monkey/post_breach/pba.py +++ b/monkey/infection_monkey/post_breach/pba.py @@ -45,10 +45,11 @@ class PBA: ) ) self.pba_data.append(PostBreachData(self.name, self.command, result)) - return self.pba_data else: logger.debug(f"No command available for PBA '{self.name}' on current OS, skipping.") + return self.pba_data + def is_script(self): """ Determines if PBA is a script (PBA might be a single command) From 3f01b9bcac20036d9d3137508ab7e9b8919e65f2 Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Wed, 30 Mar 2022 13:52:53 +0530 Subject: [PATCH 6/7] Agent: Pass telemetry_messenger to PBA constructors where it was missing --- .../post_breach/actions/clear_command_history.py | 6 +++++- monkey/infection_monkey/post_breach/actions/hide_files.py | 1 + .../post_breach/actions/modify_shell_startup_files.py | 1 + 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/monkey/infection_monkey/post_breach/actions/clear_command_history.py b/monkey/infection_monkey/post_breach/actions/clear_command_history.py index fbffc9079..c668550c4 100644 --- a/monkey/infection_monkey/post_breach/actions/clear_command_history.py +++ b/monkey/infection_monkey/post_breach/actions/clear_command_history.py @@ -46,7 +46,11 @@ class ClearCommandHistory(PBA): class ClearCommandHistoryFile(PBA): def __init__(self, linux_cmds): - super().__init__(name=POST_BREACH_CLEAR_CMD_HISTORY, linux_cmd=linux_cmds) + super().__init__( + self.telemetry_messenger, + name=POST_BREACH_CLEAR_CMD_HISTORY, + linux_cmd=linux_cmds, + ) def run(self): if self.command: diff --git a/monkey/infection_monkey/post_breach/actions/hide_files.py b/monkey/infection_monkey/post_breach/actions/hide_files.py index 838fae222..5c0bda507 100644 --- a/monkey/infection_monkey/post_breach/actions/hide_files.py +++ b/monkey/infection_monkey/post_breach/actions/hide_files.py @@ -28,6 +28,7 @@ class HiddenFiles(PBA): for function_to_get_commands in HIDDEN_FSO_CREATION_COMMANDS: linux_cmds, windows_cmds = function_to_get_commands() super(HiddenFiles, self).__init__( + self.telemetry_messenger, name=POST_BREACH_HIDDEN_FILES, linux_cmd=" ".join(linux_cmds), windows_cmd=windows_cmds, diff --git a/monkey/infection_monkey/post_breach/actions/modify_shell_startup_files.py b/monkey/infection_monkey/post_breach/actions/modify_shell_startup_files.py index 9b15de77f..1310d2140 100644 --- a/monkey/infection_monkey/post_breach/actions/modify_shell_startup_files.py +++ b/monkey/infection_monkey/post_breach/actions/modify_shell_startup_files.py @@ -64,6 +64,7 @@ class ModifyShellStartupFiles(PBA): class ModifyShellStartupFile(PBA): def __init__(self, linux_cmds, windows_cmds): super().__init__( + self.telemetry_messenger, name=POST_BREACH_SHELL_STARTUP_FILE_MODIFICATION, linux_cmd=linux_cmds, windows_cmd=windows_cmds, From ca0972f84737b238643c6fdce1b5ca94be228e0f Mon Sep 17 00:00:00 2001 From: Shreya Malviya Date: Wed, 30 Mar 2022 14:01:12 +0530 Subject: [PATCH 7/7] Agent: Pass None to telemetry_messenger arg in nested PBA classes This is not the most ideal way but it gets the job done without the unnecessary complexity of passing the telemetry messenger through different classes and functions when it's not needed. --- .../post_breach/actions/clear_command_history.py | 2 +- .../post_breach/actions/modify_shell_startup_files.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/monkey/infection_monkey/post_breach/actions/clear_command_history.py b/monkey/infection_monkey/post_breach/actions/clear_command_history.py index c668550c4..e92185fbf 100644 --- a/monkey/infection_monkey/post_breach/actions/clear_command_history.py +++ b/monkey/infection_monkey/post_breach/actions/clear_command_history.py @@ -47,7 +47,7 @@ class ClearCommandHistory(PBA): class ClearCommandHistoryFile(PBA): def __init__(self, linux_cmds): super().__init__( - self.telemetry_messenger, + telemetry_messenger=None, name=POST_BREACH_CLEAR_CMD_HISTORY, linux_cmd=linux_cmds, ) diff --git a/monkey/infection_monkey/post_breach/actions/modify_shell_startup_files.py b/monkey/infection_monkey/post_breach/actions/modify_shell_startup_files.py index 1310d2140..1a78aa3f0 100644 --- a/monkey/infection_monkey/post_breach/actions/modify_shell_startup_files.py +++ b/monkey/infection_monkey/post_breach/actions/modify_shell_startup_files.py @@ -64,7 +64,7 @@ class ModifyShellStartupFiles(PBA): class ModifyShellStartupFile(PBA): def __init__(self, linux_cmds, windows_cmds): super().__init__( - self.telemetry_messenger, + telemetry_messenger=None, name=POST_BREACH_SHELL_STARTUP_FILE_MODIFICATION, linux_cmd=linux_cmds, windows_cmd=windows_cmds,