Merge pull request #1822 from guardicore/1604-modify-pbas-to-return-postbreachdata
Modify PBAs to return PostBreachData
This commit is contained in:
commit
314bc49d1c
|
@ -198,8 +198,14 @@ class AutomatedMaster(IMaster):
|
|||
name = pba[0]
|
||||
options = pba[1]
|
||||
|
||||
result = self._puppet.run_pba(name, options)
|
||||
self._telemetry_messenger.send_telemetry(PostBreachTelem(result))
|
||||
# TEMPORARY; TO AVOID ERRORS SINCE THIS ISN'T IMPLEMENTED YET
|
||||
if name == "Custom":
|
||||
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)
|
||||
)
|
||||
|
||||
def _can_propagate(self) -> bool:
|
||||
return True
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import subprocess
|
||||
|
||||
from common.common_consts.post_breach_consts import POST_BREACH_CLEAR_CMD_HISTORY
|
||||
from infection_monkey.i_puppet.i_puppet import PostBreachData
|
||||
from infection_monkey.post_breach.clear_command_history.clear_command_history import (
|
||||
get_commands_to_clear_command_history,
|
||||
)
|
||||
from infection_monkey.post_breach.pba import PBA
|
||||
from infection_monkey.telemetry.post_breach_telem import PostBreachTelem
|
||||
|
||||
|
||||
class ClearCommandHistory(PBA):
|
||||
|
@ -15,7 +15,9 @@ class ClearCommandHistory(PBA):
|
|||
def run(self):
|
||||
results = [pba.run() for pba in self.clear_command_history_PBA_list()]
|
||||
if results:
|
||||
PostBreachTelem(self, results).send()
|
||||
# `self.command` is empty here
|
||||
self.pba_data.append(PostBreachData(self.name, self.command, results))
|
||||
return self.pba_data
|
||||
|
||||
def clear_command_history_PBA_list(self):
|
||||
return self.CommandHistoryPBAGenerator().get_clear_command_history_pbas()
|
||||
|
|
|
@ -3,6 +3,7 @@ import logging
|
|||
import psutil
|
||||
|
||||
from common.common_consts.post_breach_consts import POST_BREACH_PROCESS_LIST_COLLECTION
|
||||
from infection_monkey.i_puppet.i_puppet import PostBreachData
|
||||
from infection_monkey.post_breach.pba import PBA
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
@ -16,9 +17,6 @@ except NameError:
|
|||
|
||||
|
||||
class ProcessListCollection(PBA):
|
||||
# TODO: (?) Move all PBA consts into their classes
|
||||
display_name = POST_BREACH_PROCESS_LIST_COLLECTION
|
||||
|
||||
def __init__(self):
|
||||
super().__init__(POST_BREACH_PROCESS_LIST_COLLECTION)
|
||||
|
||||
|
@ -54,4 +52,6 @@ class ProcessListCollection(PBA):
|
|||
}
|
||||
continue
|
||||
|
||||
return self.command, (processes, success_state)
|
||||
# No command here; used psutil
|
||||
self.pba_data.append(PostBreachData(self.name, self.command, (processes, success_state)))
|
||||
return self.pba_data
|
||||
|
|
|
@ -5,8 +5,8 @@ import string
|
|||
import subprocess
|
||||
|
||||
from common.common_consts.post_breach_consts import POST_BREACH_COMMUNICATE_AS_BACKDOOR_USER
|
||||
from infection_monkey.i_puppet.i_puppet import PostBreachData
|
||||
from infection_monkey.post_breach.pba import PBA
|
||||
from infection_monkey.telemetry.post_breach_telem import PostBreachTelem
|
||||
from infection_monkey.utils.auto_new_user_factory import create_auto_new_user
|
||||
from infection_monkey.utils.environment import is_windows_os
|
||||
from infection_monkey.utils.new_user_error import NewUserError
|
||||
|
@ -49,11 +49,20 @@ class CommunicateAsBackdoorUser(PBA):
|
|||
)
|
||||
)
|
||||
exit_status = new_user.run_as(http_request_commandline)
|
||||
self.send_result_telemetry(exit_status, http_request_commandline, username)
|
||||
result = CommunicateAsBackdoorUser._get_result_for_telemetry(
|
||||
exit_status, http_request_commandline, username
|
||||
)
|
||||
# `command` is empty here; we could get the command from `new_user` but that
|
||||
# doesn't work either since Windows doesn't use a command, it uses win32 modules
|
||||
self.pba_data.append(PostBreachData(self.name, self.command, result))
|
||||
except subprocess.CalledProcessError as e:
|
||||
PostBreachTelem(self, (e.output.decode(), False)).send()
|
||||
self.pba_data.append(
|
||||
PostBreachData(self.name, self.command, (e.output.decode(), False))
|
||||
)
|
||||
except NewUserError as e:
|
||||
PostBreachTelem(self, (str(e), False)).send()
|
||||
self.pba_data.append(PostBreachData(self.name, self.command, (str(e), False)))
|
||||
finally:
|
||||
return self.pba_data
|
||||
|
||||
@staticmethod
|
||||
def get_random_new_user_name():
|
||||
|
@ -79,28 +88,19 @@ class CommunicateAsBackdoorUser(PBA):
|
|||
format_string = "wget -O/dev/null -q {url} --method=HEAD --timeout=10"
|
||||
return format_string.format(url=url)
|
||||
|
||||
def send_result_telemetry(self, exit_status, commandline, username):
|
||||
"""
|
||||
Parses the result of the command and sends telemetry accordingly.
|
||||
|
||||
:param exit_status: In both Windows and Linux, 0 exit code indicates success.
|
||||
:param commandline: Exact commandline which was executed, for reporting back.
|
||||
:param username: Username from which the command was executed, for reporting back.
|
||||
"""
|
||||
@staticmethod
|
||||
def _get_result_for_telemetry(exit_status, commandline, username):
|
||||
if exit_status == 0:
|
||||
PostBreachTelem(
|
||||
self, (CREATED_PROCESS_AS_USER_SUCCESS_FORMAT.format(commandline, username), True)
|
||||
).send()
|
||||
result = (CREATED_PROCESS_AS_USER_SUCCESS_FORMAT.format(commandline, username), True)
|
||||
else:
|
||||
PostBreachTelem(
|
||||
self,
|
||||
(
|
||||
CREATED_PROCESS_AS_USER_FAILED_FORMAT.format(
|
||||
commandline, username, exit_status, twos_complement(exit_status)
|
||||
),
|
||||
False,
|
||||
result = (
|
||||
CREATED_PROCESS_AS_USER_FAILED_FORMAT.format(
|
||||
commandline, username, exit_status, twos_complement(exit_status)
|
||||
),
|
||||
).send()
|
||||
False,
|
||||
)
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def twos_complement(exit_status):
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
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
|
||||
from infection_monkey.telemetry.post_breach_telem import PostBreachTelem
|
||||
from infection_monkey.utils.environment import is_windows_os
|
||||
from infection_monkey.utils.hidden_files import (
|
||||
cleanup_hidden_files,
|
||||
|
@ -30,9 +30,13 @@ class HiddenFiles(PBA):
|
|||
windows_cmd=windows_cmds,
|
||||
)
|
||||
super(HiddenFiles, self).run()
|
||||
|
||||
if is_windows_os(): # use winAPI
|
||||
result, status = get_winAPI_to_hide_files()
|
||||
PostBreachTelem(self, (result, status)).send()
|
||||
# no command here, used WinAPI
|
||||
self.pba_data.append(PostBreachData(self.name, self.command, (result, status)))
|
||||
|
||||
# cleanup hidden files and folders
|
||||
cleanup_hidden_files(is_windows_os())
|
||||
|
||||
return self.pba_data
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import subprocess
|
||||
|
||||
from common.common_consts.post_breach_consts import POST_BREACH_SHELL_STARTUP_FILE_MODIFICATION
|
||||
from infection_monkey.i_puppet.i_puppet import PostBreachData
|
||||
from infection_monkey.post_breach.pba import PBA
|
||||
from infection_monkey.post_breach.shell_startup_files.shell_startup_files_modification import (
|
||||
get_commands_to_modify_shell_startup_files,
|
||||
)
|
||||
from infection_monkey.telemetry.post_breach_telem import PostBreachTelem
|
||||
|
||||
|
||||
class ModifyShellStartupFiles(PBA):
|
||||
|
@ -27,13 +27,18 @@ class ModifyShellStartupFiles(PBA):
|
|||
False,
|
||||
)
|
||||
]
|
||||
PostBreachTelem(self, results).send()
|
||||
# `command` is empty here since multiple commands were run through objects of the nested
|
||||
# class. The results of each of those were aggregated to send the telemetry just once.
|
||||
self.pba_data.append(PostBreachData(self.name, self.command, results))
|
||||
return self.pba_data
|
||||
|
||||
def modify_shell_startup_PBA_list(self):
|
||||
return self.ShellStartupPBAGenerator().get_modify_shell_startup_pbas()
|
||||
@classmethod
|
||||
def modify_shell_startup_PBA_list(cls):
|
||||
return cls.ShellStartupPBAGenerator.get_modify_shell_startup_pbas()
|
||||
|
||||
class ShellStartupPBAGenerator:
|
||||
def get_modify_shell_startup_pbas(self):
|
||||
@classmethod
|
||||
def get_modify_shell_startup_pbas(cls):
|
||||
(cmds_for_linux, shell_startup_files_for_linux, usernames_for_linux), (
|
||||
cmds_for_windows,
|
||||
shell_startup_files_per_user_for_windows,
|
||||
|
@ -43,14 +48,14 @@ class ModifyShellStartupFiles(PBA):
|
|||
|
||||
for startup_file_per_user in shell_startup_files_per_user_for_windows:
|
||||
windows_cmds = " ".join(cmds_for_windows).format(startup_file_per_user)
|
||||
pbas.append(self.ModifyShellStartupFile(linux_cmds="", windows_cmds=windows_cmds))
|
||||
pbas.append(cls.ModifyShellStartupFile(linux_cmds="", windows_cmds=windows_cmds))
|
||||
|
||||
for username in usernames_for_linux:
|
||||
for shell_startup_file in shell_startup_files_for_linux:
|
||||
linux_cmds = (
|
||||
" ".join(cmds_for_linux).format(shell_startup_file).format(username)
|
||||
)
|
||||
pbas.append(self.ModifyShellStartupFile(linux_cmds=linux_cmds, windows_cmds=""))
|
||||
pbas.append(cls.ModifyShellStartupFile(linux_cmds=linux_cmds, windows_cmds=""))
|
||||
|
||||
return pbas
|
||||
|
||||
|
|
|
@ -23,3 +23,4 @@ class ScheduleJobs(PBA):
|
|||
def run(self):
|
||||
super(ScheduleJobs, self).run()
|
||||
remove_scheduled_jobs()
|
||||
return self.pba_data
|
||||
|
|
|
@ -18,13 +18,14 @@ class SignedScriptProxyExecution(PBA):
|
|||
super().__init__(POST_BREACH_SIGNED_SCRIPT_PROXY_EXEC, windows_cmd=" ".join(windows_cmds))
|
||||
|
||||
def run(self):
|
||||
original_comspec = ""
|
||||
try:
|
||||
original_comspec = ""
|
||||
if is_windows_os():
|
||||
original_comspec = subprocess.check_output( # noqa: DUO116
|
||||
"if defined COMSPEC echo %COMSPEC%", shell=True
|
||||
).decode()
|
||||
super().run()
|
||||
return self.pba_data
|
||||
except Exception as e:
|
||||
logger.warning(
|
||||
f"An exception occurred on running PBA "
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import logging
|
||||
import subprocess
|
||||
from typing import Iterable
|
||||
|
||||
from common.utils.attack_utils import ScanStatus
|
||||
from infection_monkey.i_puppet.i_puppet import PostBreachData
|
||||
from infection_monkey.telemetry.attack.t1064_telem import T1064Telem
|
||||
from infection_monkey.telemetry.post_breach_telem import PostBreachTelem
|
||||
from infection_monkey.utils.environment import is_windows_os
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
@ -23,8 +24,9 @@ class PBA:
|
|||
"""
|
||||
self.command = PBA.choose_command(linux_cmd, windows_cmd)
|
||||
self.name = name
|
||||
self.pba_data = []
|
||||
|
||||
def run(self):
|
||||
def run(self) -> Iterable[PostBreachData]:
|
||||
"""
|
||||
Runs post breach action command
|
||||
"""
|
||||
|
@ -35,7 +37,8 @@ class PBA:
|
|||
T1064Telem(
|
||||
ScanStatus.USED, f"Scripts were used to execute {self.name} post breach action."
|
||||
).send()
|
||||
PostBreachTelem(self, result).send()
|
||||
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.")
|
||||
|
||||
|
|
|
@ -53,9 +53,9 @@ class MockPuppet(IPuppet):
|
|||
logger.debug(f"run_pba({name}, {options})")
|
||||
|
||||
if name == "AccountDiscovery":
|
||||
return PostBreachData(name, "pba command 1", ["pba result 1", True])
|
||||
yield PostBreachData(name, "pba command 1", ["pba result 1", True])
|
||||
else:
|
||||
return PostBreachData(name, "pba command 2", ["pba result 2", False])
|
||||
yield PostBreachData(name, "pba command 2", ["pba result 2", False])
|
||||
|
||||
def ping(self, host: str, timeout: float = 1) -> PingScanData:
|
||||
logger.debug(f"run_ping({host}, {timeout})")
|
||||
|
|
|
@ -92,6 +92,7 @@ AccountDiscovery # unused class (monkey/infection_monkey/post_breach/actions/di
|
|||
ModifyShellStartupFiles # unused class (monkey/infection_monkey/post_breach/actions/modify_shell_startup_files.py:11)
|
||||
Timestomping # unused class (monkey/infection_monkey/post_breach/actions/timestomping.py:6)
|
||||
SignedScriptProxyExecution # unused class (monkey/infection_monkey/post_breach/actions/use_signed_scripts.py:15)
|
||||
ProcessListCollection # unused class (monkey/infection_monkey/post_breach/actions/collect_processes_list.py:19)
|
||||
EnvironmentCollector # unused class (monkey/infection_monkey/system_info/collectors/environment_collector.py:19)
|
||||
HostnameCollector # unused class (monkey/infection_monkey/system_info/collectors/hostname_collector.py:10)
|
||||
_.representations # unused attribute (monkey/monkey_island/cc/app.py:180)
|
||||
|
|
Loading…
Reference in New Issue