forked from p15670423/monkey
Merge pull request #1791 from guardicore/1611-interruptable-powershell
1611 Make powershell exploiter interruptable
This commit is contained in:
commit
b1716e9457
|
@ -94,14 +94,15 @@ class HostExploiter:
|
||||||
)
|
)
|
||||||
self.set_start_time()
|
self.set_start_time()
|
||||||
|
|
||||||
def is_interrupted(self):
|
def _is_interrupted(self):
|
||||||
|
return self.interrupt.is_set()
|
||||||
|
|
||||||
|
def _set_interrupted(self):
|
||||||
# This method should be refactored to raise an exception to reduce duplication in the
|
# This method should be refactored to raise an exception to reduce duplication in the
|
||||||
# "if is_interrupted: return self.exploitation_results"
|
# "if is_interrupted: return self.exploitation_results"
|
||||||
# Ideally the user should only do "check_for_interrupt()"
|
# Ideally the user should only do "check_for_interrupt()"
|
||||||
if self.interrupt.is_set():
|
|
||||||
logger.info("Exploiter has been interrupted")
|
logger.info("Exploiter has been interrupted")
|
||||||
self.exploit_result.error_message = "Exploiter has been interrupted"
|
self.exploit_result.interrupted = True
|
||||||
return self.interrupt.is_set()
|
|
||||||
|
|
||||||
def post_exploit(self):
|
def post_exploit(self):
|
||||||
self.set_finish_time()
|
self.set_finish_time()
|
||||||
|
|
|
@ -73,7 +73,8 @@ class MSSQLExploiter(HostExploiter):
|
||||||
)
|
)
|
||||||
return self.exploit_result
|
return self.exploit_result
|
||||||
|
|
||||||
if self.is_interrupted():
|
if self._is_interrupted():
|
||||||
|
self._set_interrupted()
|
||||||
return self.exploit_result
|
return self.exploit_result
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -23,6 +23,7 @@ from infection_monkey.exploit.tools.helpers import get_random_file_suffix
|
||||||
from infection_monkey.model import DROPPER_ARG, RUN_MONKEY, VictimHost
|
from infection_monkey.model import DROPPER_ARG, RUN_MONKEY, VictimHost
|
||||||
from infection_monkey.utils.commands import build_monkey_commandline
|
from infection_monkey.utils.commands import build_monkey_commandline
|
||||||
from infection_monkey.utils.environment import is_windows_os
|
from infection_monkey.utils.environment import is_windows_os
|
||||||
|
from infection_monkey.utils.threading import interruptable_iter
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -68,14 +69,17 @@ class PowerShellExploiter(HostExploiter):
|
||||||
auth_options = [get_auth_options(creds, use_ssl) for creds in credentials]
|
auth_options = [get_auth_options(creds, use_ssl) for creds in credentials]
|
||||||
|
|
||||||
self._client = self._authenticate_via_brute_force(credentials, auth_options)
|
self._client = self._authenticate_via_brute_force(credentials, auth_options)
|
||||||
|
|
||||||
|
if self._is_interrupted():
|
||||||
|
self._set_interrupted()
|
||||||
|
return self.exploit_result
|
||||||
|
|
||||||
if not self._client:
|
if not self._client:
|
||||||
self.exploit_result.error_message = (
|
self.exploit_result.error_message = (
|
||||||
"Unable to authenticate to the remote host using any of the available credentials"
|
"Unable to authenticate to the remote host using any of the available credentials"
|
||||||
)
|
)
|
||||||
return self.exploit_result
|
return self.exploit_result
|
||||||
|
|
||||||
self.exploit_result.exploitation_success = True
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self._execute_monkey_agent_on_victim()
|
self._execute_monkey_agent_on_victim()
|
||||||
self.exploit_result.propagation_success = True
|
self.exploit_result.propagation_success = True
|
||||||
|
@ -133,7 +137,7 @@ class PowerShellExploiter(HostExploiter):
|
||||||
def _authenticate_via_brute_force(
|
def _authenticate_via_brute_force(
|
||||||
self, credentials: List[Credentials], auth_options: List[AuthOptions]
|
self, credentials: List[Credentials], auth_options: List[AuthOptions]
|
||||||
) -> Optional[IPowerShellClient]:
|
) -> Optional[IPowerShellClient]:
|
||||||
for (creds, opts) in zip(credentials, auth_options):
|
for (creds, opts) in interruptable_iter(zip(credentials, auth_options), self.interrupt):
|
||||||
try:
|
try:
|
||||||
client = PowerShellClient(self.host.ip_addr, creds, opts)
|
client = PowerShellClient(self.host.ip_addr, creds, opts)
|
||||||
client.connect()
|
client.connect()
|
||||||
|
@ -142,7 +146,9 @@ class PowerShellExploiter(HostExploiter):
|
||||||
f"{creds.username}, Secret Type: {creds.secret_type.name}"
|
f"{creds.username}, Secret Type: {creds.secret_type.name}"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
self.exploit_result.exploitation_success = True
|
||||||
self._report_login_attempt(True, creds)
|
self._report_login_attempt(True, creds)
|
||||||
|
|
||||||
return client
|
return client
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
logger.debug(
|
logger.debug(
|
||||||
|
|
|
@ -70,7 +70,8 @@ class WmiExploiter(HostExploiter):
|
||||||
|
|
||||||
downloaded_agent = self.agent_repository.get_agent_binary(self.host.os["type"])
|
downloaded_agent = self.agent_repository.get_agent_binary(self.host.os["type"])
|
||||||
|
|
||||||
if self.is_interrupted():
|
if self._is_interrupted():
|
||||||
|
self._set_interrupted()
|
||||||
return self.exploit_result
|
return self.exploit_result
|
||||||
|
|
||||||
remote_full_path = SmbTools.copy_file(
|
remote_full_path = SmbTools.copy_file(
|
||||||
|
|
|
@ -24,6 +24,7 @@ class UnknownPluginError(Exception):
|
||||||
class ExploiterResultData:
|
class ExploiterResultData:
|
||||||
exploitation_success: bool = False
|
exploitation_success: bool = False
|
||||||
propagation_success: bool = False
|
propagation_success: bool = False
|
||||||
|
interrupted: bool = False
|
||||||
os: str = ""
|
os: str = ""
|
||||||
info: Mapping = None
|
info: Mapping = None
|
||||||
attempts: Iterable = None
|
attempts: Iterable = None
|
||||||
|
|
|
@ -190,17 +190,18 @@ class MockPuppet(IPuppet):
|
||||||
successful_exploiters = {
|
successful_exploiters = {
|
||||||
DOT_1: {
|
DOT_1: {
|
||||||
"PowerShellExploiter": ExploiterResultData(
|
"PowerShellExploiter": ExploiterResultData(
|
||||||
True, True, os_windows, info_powershell, attempts, None
|
True, True, False, os_windows, info_powershell, attempts, None
|
||||||
),
|
),
|
||||||
"ZerologonExploiter": ExploiterResultData(
|
"ZerologonExploiter": ExploiterResultData(
|
||||||
False, False, os_windows, {}, [], "Zerologon failed"
|
False, False, False, os_windows, {}, [], "Zerologon failed"
|
||||||
),
|
),
|
||||||
"SSHExploiter": ExploiterResultData(
|
"SSHExploiter": ExploiterResultData(
|
||||||
False, False, os_linux, info_ssh, attempts, "Failed exploiting"
|
False, False, False, os_linux, info_ssh, attempts, "Failed exploiting"
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
DOT_3: {
|
DOT_3: {
|
||||||
"PowerShellExploiter": ExploiterResultData(
|
"PowerShellExploiter": ExploiterResultData(
|
||||||
|
False,
|
||||||
False,
|
False,
|
||||||
False,
|
False,
|
||||||
os_windows,
|
os_windows,
|
||||||
|
@ -209,9 +210,11 @@ class MockPuppet(IPuppet):
|
||||||
"PowerShell Exploiter Failed",
|
"PowerShell Exploiter Failed",
|
||||||
),
|
),
|
||||||
"SSHExploiter": ExploiterResultData(
|
"SSHExploiter": ExploiterResultData(
|
||||||
False, False, os_linux, info_ssh, attempts, "Failed exploiting"
|
False, False, False, os_linux, info_ssh, attempts, "Failed exploiting"
|
||||||
|
),
|
||||||
|
"ZerologonExploiter": ExploiterResultData(
|
||||||
|
True, False, False, os_windows, {}, [], None
|
||||||
),
|
),
|
||||||
"ZerologonExploiter": ExploiterResultData(True, False, os_windows, {}, [], None),
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -219,7 +222,7 @@ class MockPuppet(IPuppet):
|
||||||
return successful_exploiters[host.ip_addr][name]
|
return successful_exploiters[host.ip_addr][name]
|
||||||
except KeyError:
|
except KeyError:
|
||||||
return ExploiterResultData(
|
return ExploiterResultData(
|
||||||
False, False, os_linux, {}, [], f"{name} failed for host {host}"
|
False, False, False, os_linux, {}, [], f"{name} failed for host {host}"
|
||||||
)
|
)
|
||||||
|
|
||||||
def run_payload(self, name: str, options: Dict, interrupt: threading.Event):
|
def run_payload(self, name: str, options: Dict, interrupt: threading.Event):
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
from typing import Dict
|
from typing import Dict
|
||||||
|
|
||||||
from common.common_consts.telem_categories import TelemCategoryEnum
|
from common.common_consts.telem_categories import TelemCategoryEnum
|
||||||
|
from infection_monkey.i_puppet.i_puppet import ExploiterResultData
|
||||||
from infection_monkey.model.host import VictimHost
|
from infection_monkey.model.host import VictimHost
|
||||||
from infection_monkey.telemetry.base_telem import BaseTelem
|
from infection_monkey.telemetry.base_telem import BaseTelem
|
||||||
from infection_monkey.i_puppet.i_puppet import ExploiterResultData
|
|
||||||
|
|
||||||
|
|
||||||
class ExploitTelem(BaseTelem):
|
class ExploitTelem(BaseTelem):
|
||||||
|
@ -25,6 +25,7 @@ class ExploitTelem(BaseTelem):
|
||||||
self.host = host.__dict__
|
self.host = host.__dict__
|
||||||
self.exploitation_result = result.exploitation_success
|
self.exploitation_result = result.exploitation_success
|
||||||
self.propagation_result = result.propagation_success
|
self.propagation_result = result.propagation_success
|
||||||
|
self.interrupted = result.interrupted
|
||||||
self.info = result.info
|
self.info = result.info
|
||||||
self.attempts = result.attempts
|
self.attempts = result.attempts
|
||||||
|
|
||||||
|
@ -34,6 +35,7 @@ class ExploitTelem(BaseTelem):
|
||||||
return {
|
return {
|
||||||
"exploitation_result": self.exploitation_result,
|
"exploitation_result": self.exploitation_result,
|
||||||
"propagation_result": self.propagation_result,
|
"propagation_result": self.propagation_result,
|
||||||
|
"interrupted": self.interrupted,
|
||||||
"machine": self.host,
|
"machine": self.host,
|
||||||
"exploiter": self.name,
|
"exploiter": self.name,
|
||||||
"info": self.info,
|
"info": self.info,
|
||||||
|
|
|
@ -201,38 +201,38 @@ class MockExploiter:
|
||||||
results_callback(
|
results_callback(
|
||||||
"PowerShellExploiter",
|
"PowerShellExploiter",
|
||||||
host,
|
host,
|
||||||
ExploiterResultData(True, True, os_windows, {}, {}, None),
|
ExploiterResultData(True, True, False, os_windows, {}, {}, None),
|
||||||
)
|
)
|
||||||
results_callback(
|
results_callback(
|
||||||
"SSHExploiter",
|
"SSHExploiter",
|
||||||
host,
|
host,
|
||||||
ExploiterResultData(False, False, os_linux, {}, {}, "SSH FAILED for .1"),
|
ExploiterResultData(False, False, False, os_linux, {}, {}, "SSH FAILED for .1"),
|
||||||
)
|
)
|
||||||
elif host.ip_addr.endswith(".2"):
|
elif host.ip_addr.endswith(".2"):
|
||||||
results_callback(
|
results_callback(
|
||||||
"PowerShellExploiter",
|
"PowerShellExploiter",
|
||||||
host,
|
host,
|
||||||
ExploiterResultData(
|
ExploiterResultData(
|
||||||
False, False, os_windows, {}, {}, "POWERSHELL FAILED for .2"
|
False, False, False, os_windows, {}, {}, "POWERSHELL FAILED for .2"
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
results_callback(
|
results_callback(
|
||||||
"SSHExploiter",
|
"SSHExploiter",
|
||||||
host,
|
host,
|
||||||
ExploiterResultData(False, False, os_linux, {}, {}, "SSH FAILED for .2"),
|
ExploiterResultData(False, False, False, os_linux, {}, {}, "SSH FAILED for .2"),
|
||||||
)
|
)
|
||||||
elif host.ip_addr.endswith(".3"):
|
elif host.ip_addr.endswith(".3"):
|
||||||
results_callback(
|
results_callback(
|
||||||
"PowerShellExploiter",
|
"PowerShellExploiter",
|
||||||
host,
|
host,
|
||||||
ExploiterResultData(
|
ExploiterResultData(
|
||||||
False, False, os_windows, {}, {}, "POWERSHELL FAILED for .3"
|
False, False, False, os_windows, {}, {}, "POWERSHELL FAILED for .3"
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
results_callback(
|
results_callback(
|
||||||
"SSHExploiter",
|
"SSHExploiter",
|
||||||
host,
|
host,
|
||||||
ExploiterResultData(True, True, os_linux, {}, {}, None),
|
ExploiterResultData(True, True, False, os_linux, {}, {}, None),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -40,7 +40,7 @@ def exploit_telem_test_instance():
|
||||||
EXPLOITER_NAME,
|
EXPLOITER_NAME,
|
||||||
HOST,
|
HOST,
|
||||||
ExploiterResultData(
|
ExploiterResultData(
|
||||||
RESULT, RESULT, OS_LINUX, EXPLOITER_INFO, EXPLOITER_ATTEMPTS, ERROR_MSG
|
RESULT, RESULT, False, OS_LINUX, EXPLOITER_INFO, EXPLOITER_ATTEMPTS, ERROR_MSG
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -50,6 +50,7 @@ def test_exploit_telem_send(exploit_telem_test_instance, spy_send_telemetry):
|
||||||
expected_data = {
|
expected_data = {
|
||||||
"exploitation_result": RESULT,
|
"exploitation_result": RESULT,
|
||||||
"propagation_result": RESULT,
|
"propagation_result": RESULT,
|
||||||
|
"interrupted": False,
|
||||||
"machine": HOST_AS_DICT,
|
"machine": HOST_AS_DICT,
|
||||||
"exploiter": EXPLOITER_NAME,
|
"exploiter": EXPLOITER_NAME,
|
||||||
"info": EXPLOITER_INFO,
|
"info": EXPLOITER_INFO,
|
||||||
|
|
Loading…
Reference in New Issue