def __decryptHash(self, record, rid=None, prefixTable=None, outputFile=None): if self.__useVSSMethod is True: logging.debug('Decrypting hash for user: %s' % record[self.NAME_TO_INTERNAL['name']]) sid = SAMR_RPC_SID( unhexlify(record[self.NAME_TO_INTERNAL['objectSid']])) rid = sid.formatCanonical().split('-')[-1] if record[self.NAME_TO_INTERNAL['dBCSPwd']] is not None: encryptedLMHash = self.CRYPTED_HASH( unhexlify(record[self.NAME_TO_INTERNAL['dBCSPwd']])) tmpLMHash = self.__removeRC4Layer(encryptedLMHash) LMHash = self.__removeDESLayer(tmpLMHash, rid) else: LMHash = ntlm.LMOWFv1('', '') if record[self.NAME_TO_INTERNAL['unicodePwd']] is not None: encryptedNTHash = self.CRYPTED_HASH( unhexlify(record[self.NAME_TO_INTERNAL['unicodePwd']])) tmpNTHash = self.__removeRC4Layer(encryptedNTHash) NTHash = self.__removeDESLayer(tmpNTHash, rid) else: NTHash = ntlm.NTOWFv1('', '') if record[self.NAME_TO_INTERNAL['userPrincipalName']] is not None: domain = record[ self.NAME_TO_INTERNAL['userPrincipalName']].split('@')[-1] userName = '******' % ( domain, record[self.NAME_TO_INTERNAL['sAMAccountName']]) else: userName = '******' % record[ self.NAME_TO_INTERNAL['sAMAccountName']] if record[self.NAME_TO_INTERNAL['pwdLastSet']] is not None: pwdLastSet = self.__fileTimeToDateTime( record[self.NAME_TO_INTERNAL['pwdLastSet']]) else: pwdLastSet = 'N/A' answer = "%s:%s:%s:%s:::" % (userName, rid, hexlify(LMHash), hexlify(NTHash)) if outputFile is not None: self.__writeOutput(outputFile, answer + '\n') if self.__pwdLastSet is True: answer = "%s (pwdLastSet=%s)" % (answer, pwdLastSet) self.__logger.highlight(answer) if self.__history: LMHistory = [] NTHistory = [] if record[self.NAME_TO_INTERNAL['lmPwdHistory']] is not None: encryptedLMHistory = self.CRYPTED_HISTORY( unhexlify( record[self.NAME_TO_INTERNAL['lmPwdHistory']])) tmpLMHistory = self.__removeRC4Layer(encryptedLMHistory) for i in range(0, len(tmpLMHistory) / 16): LMHash = self.__removeDESLayer( tmpLMHistory[i * 16:(i + 1) * 16], rid) LMHistory.append(LMHash) if record[self.NAME_TO_INTERNAL['ntPwdHistory']] is not None: encryptedNTHistory = self.CRYPTED_HISTORY( unhexlify( record[self.NAME_TO_INTERNAL['ntPwdHistory']])) tmpNTHistory = self.__removeRC4Layer(encryptedNTHistory) for i in range(0, len(tmpNTHistory) / 16): NTHash = self.__removeDESLayer( tmpNTHistory[i * 16:(i + 1) * 16], rid) NTHistory.append(NTHash) for i, (LMHash, NTHash) in enumerate( map(lambda l, n: (l, n) if l else ('', n), LMHistory[1:], NTHistory[1:])): if self.__noLMHash: lmhash = hexlify(ntlm.LMOWFv1('', '')) else: lmhash = hexlify(LMHash) answer = "%s_history%d:%s:%s:%s:::" % ( userName, i, rid, lmhash, hexlify(NTHash)) if outputFile is not None: self.__writeOutput(outputFile, answer + '\n') self.__logger.highlight(answer) else: logging.debug('Decrypting hash for user: %s' % record['pmsgOut']['V6']['pNC']['StringName'][:-1]) domain = None if self.__history: LMHistory = [] NTHistory = [] for attr in record['pmsgOut']['V6']['pObjects']['Entinf'][ 'AttrBlock']['pAttr']: try: attId = drsuapi.OidFromAttid(prefixTable, attr['attrTyp']) LOOKUP_TABLE = self.ATTRTYP_TO_ATTID except Exception, e: logging.debug( 'Failed to execute OidFromAttid with error %s, fallbacking to fixed table' % e) # Fallbacking to fixed table and hope for the best attId = attr['attrTyp'] LOOKUP_TABLE = self.NAME_TO_ATTRTYP if attId == LOOKUP_TABLE['dBCSPwd']: if attr['AttrVal']['valCount'] > 0: encrypteddBCSPwd = ''.join( attr['AttrVal']['pAVal'][0]['pVal']) encryptedLMHash = drsuapi.DecryptAttributeValue( self.__remoteOps.getDrsr(), encrypteddBCSPwd) LMHash = drsuapi.removeDESLayer(encryptedLMHash, rid) else: LMHash = ntlm.LMOWFv1('', '') elif attId == LOOKUP_TABLE['unicodePwd']: if attr['AttrVal']['valCount'] > 0: encryptedUnicodePwd = ''.join( attr['AttrVal']['pAVal'][0]['pVal']) encryptedNTHash = drsuapi.DecryptAttributeValue( self.__remoteOps.getDrsr(), encryptedUnicodePwd) NTHash = drsuapi.removeDESLayer(encryptedNTHash, rid) else: NTHash = ntlm.NTOWFv1('', '') elif attId == LOOKUP_TABLE['userPrincipalName']: if attr['AttrVal']['valCount'] > 0: try: domain = ''.join( attr['AttrVal']['pAVal'][0]['pVal']).decode( 'utf-16le').split('@')[-1] except: domain = None else: domain = None elif attId == LOOKUP_TABLE['sAMAccountName']: if attr['AttrVal']['valCount'] > 0: try: userName = ''.join(attr['AttrVal']['pAVal'][0] ['pVal']).decode('utf-16le') except: logging.error('Cannot get sAMAccountName for %s' % record['pmsgOut']['V6']['pNC'] ['StringName'][:-1]) userName = '******' else: logging.error( 'Cannot get sAMAccountName for %s' % record['pmsgOut']['V6']['pNC']['StringName'][:-1]) userName = '******' elif attId == LOOKUP_TABLE['objectSid']: if attr['AttrVal']['valCount'] > 0: objectSid = ''.join( attr['AttrVal']['pAVal'][0]['pVal']) else: logging.error( 'Cannot get objectSid for %s' % record['pmsgOut']['V6']['pNC']['StringName'][:-1]) objectSid = rid elif attId == LOOKUP_TABLE['pwdLastSet']: if attr['AttrVal']['valCount'] > 0: try: pwdLastSet = self.__fileTimeToDateTime( unpack( '<Q', ''.join(attr['AttrVal']['pAVal'][0] ['pVal']))[0]) except: traceback.print_exc() logging.error('Cannot get pwdLastSet for %s' % record['pmsgOut']['V6']['pNC'] ['StringName'][:-1]) pwdLastSet = 'N/A' if self.__history: if attId == LOOKUP_TABLE['lmPwdHistory']: if attr['AttrVal']['valCount'] > 0: encryptedLMHistory = ''.join( attr['AttrVal']['pAVal'][0]['pVal']) tmpLMHistory = drsuapi.DecryptAttributeValue( self.__remoteOps.getDrsr(), encryptedLMHistory) for i in range(0, len(tmpLMHistory) / 16): LMHashHistory = drsuapi.removeDESLayer( tmpLMHistory[i * 16:(i + 1) * 16], rid) LMHistory.append(LMHashHistory) else: logging.debug('No lmPwdHistory for user %s' % record['pmsgOut']['V6']['pNC'] ['StringName'][:-1]) elif attId == LOOKUP_TABLE['ntPwdHistory']: if attr['AttrVal']['valCount'] > 0: encryptedNTHistory = ''.join( attr['AttrVal']['pAVal'][0]['pVal']) tmpNTHistory = drsuapi.DecryptAttributeValue( self.__remoteOps.getDrsr(), encryptedNTHistory) for i in range(0, len(tmpNTHistory) / 16): NTHashHistory = drsuapi.removeDESLayer( tmpNTHistory[i * 16:(i + 1) * 16], rid) NTHistory.append(NTHashHistory) else: logging.debug('No ntPwdHistory for user %s' % record['pmsgOut']['V6']['pNC'] ['StringName'][:-1]) if domain is not None: userName = '******' % (domain, userName) answer = "%s:%s:%s:%s:::" % (userName, rid, hexlify(LMHash), hexlify(NTHash)) if outputFile is not None: self.__writeOutput(outputFile, answer + '\n') if self.__pwdLastSet is True: answer = "%s (pwdLastSet=%s)" % (answer, pwdLastSet) self.__logger.highlight(answer) if self.__history: for i, (LMHashHistory, NTHashHistory) in enumerate( map(lambda l, n: (l, n) if l else ('', n), LMHistory[1:], NTHistory[1:])): if self.__noLMHash: lmhash = hexlify(ntlm.LMOWFv1('', '')) else: lmhash = hexlify(LMHashHistory) answer = "%s_history%d:%s:%s:%s:::" % ( userName, i, rid, lmhash, hexlify(NTHashHistory)) self.__logger.highlight(answer) if outputFile is not None: self.__writeOutput(outputFile, answer + '\n')
def __decryptHash(self, record, rid=None, prefixTable=None, outputFile=None): if self.__useVSSMethod is True: logging.debug('Decrypting hash for user: %s' % record[self.NAME_TO_INTERNAL['name']]) sid = SAMR_RPC_SID(unhexlify(record[self.NAME_TO_INTERNAL['objectSid']])) rid = sid.formatCanonical().split('-')[-1] if record[self.NAME_TO_INTERNAL['dBCSPwd']] is not None: encryptedLMHash = self.CRYPTED_HASH(unhexlify(record[self.NAME_TO_INTERNAL['dBCSPwd']])) tmpLMHash = self.__removeRC4Layer(encryptedLMHash) LMHash = self.__removeDESLayer(tmpLMHash, rid) else: LMHash = ntlm.LMOWFv1('', '') if record[self.NAME_TO_INTERNAL['unicodePwd']] is not None: encryptedNTHash = self.CRYPTED_HASH(unhexlify(record[self.NAME_TO_INTERNAL['unicodePwd']])) tmpNTHash = self.__removeRC4Layer(encryptedNTHash) NTHash = self.__removeDESLayer(tmpNTHash, rid) else: NTHash = ntlm.NTOWFv1('', '') if record[self.NAME_TO_INTERNAL['userPrincipalName']] is not None: domain = record[self.NAME_TO_INTERNAL['userPrincipalName']].split('@')[-1] userName = '******' % (domain, record[self.NAME_TO_INTERNAL['sAMAccountName']]) else: userName = '******' % record[self.NAME_TO_INTERNAL['sAMAccountName']] if record[self.NAME_TO_INTERNAL['pwdLastSet']] is not None: pwdLastSet = self.__fileTimeToDateTime(record[self.NAME_TO_INTERNAL['pwdLastSet']]) else: pwdLastSet = 'N/A' answer = "%s:%s:%s:%s:::" % (userName, rid, hexlify(LMHash), hexlify(NTHash)) if outputFile is not None: self.__writeOutput(outputFile, answer + '\n') if self.__pwdLastSet is True: answer = "%s (pwdLastSet=%s)" % (answer, pwdLastSet) self.__logger.highlight(answer) if self.__history: LMHistory = [] NTHistory = [] if record[self.NAME_TO_INTERNAL['lmPwdHistory']] is not None: encryptedLMHistory = self.CRYPTED_HISTORY(unhexlify(record[self.NAME_TO_INTERNAL['lmPwdHistory']])) tmpLMHistory = self.__removeRC4Layer(encryptedLMHistory) for i in range(0, len(tmpLMHistory) / 16): LMHash = self.__removeDESLayer(tmpLMHistory[i * 16:(i + 1) * 16], rid) LMHistory.append(LMHash) if record[self.NAME_TO_INTERNAL['ntPwdHistory']] is not None: encryptedNTHistory = self.CRYPTED_HISTORY(unhexlify(record[self.NAME_TO_INTERNAL['ntPwdHistory']])) tmpNTHistory = self.__removeRC4Layer(encryptedNTHistory) for i in range(0, len(tmpNTHistory) / 16): NTHash = self.__removeDESLayer(tmpNTHistory[i * 16:(i + 1) * 16], rid) NTHistory.append(NTHash) for i, (LMHash, NTHash) in enumerate( map(lambda l, n: (l, n) if l else ('', n), LMHistory[1:], NTHistory[1:])): if self.__noLMHash: lmhash = hexlify(ntlm.LMOWFv1('', '')) else: lmhash = hexlify(LMHash) answer = "%s_history%d:%s:%s:%s:::" % (userName, i, rid, lmhash, hexlify(NTHash)) if outputFile is not None: self.__writeOutput(outputFile, answer + '\n') self.__logger.highlight(answer) else: logging.debug('Decrypting hash for user: %s' % record['pmsgOut']['V6']['pNC']['StringName'][:-1]) domain = None if self.__history: LMHistory = [] NTHistory = [] for attr in record['pmsgOut']['V6']['pObjects']['Entinf']['AttrBlock']['pAttr']: try: attId = drsuapi.OidFromAttid(prefixTable, attr['attrTyp']) LOOKUP_TABLE = self.ATTRTYP_TO_ATTID except Exception, e: logging.debug('Failed to execute OidFromAttid with error %s, fallbacking to fixed table' % e) # Fallbacking to fixed table and hope for the best attId = attr['attrTyp'] LOOKUP_TABLE = self.NAME_TO_ATTRTYP if attId == LOOKUP_TABLE['dBCSPwd']: if attr['AttrVal']['valCount'] > 0: encrypteddBCSPwd = ''.join(attr['AttrVal']['pAVal'][0]['pVal']) encryptedLMHash = drsuapi.DecryptAttributeValue(self.__remoteOps.getDrsr(), encrypteddBCSPwd) LMHash = drsuapi.removeDESLayer(encryptedLMHash, rid) else: LMHash = ntlm.LMOWFv1('', '') elif attId == LOOKUP_TABLE['unicodePwd']: if attr['AttrVal']['valCount'] > 0: encryptedUnicodePwd = ''.join(attr['AttrVal']['pAVal'][0]['pVal']) encryptedNTHash = drsuapi.DecryptAttributeValue(self.__remoteOps.getDrsr(), encryptedUnicodePwd) NTHash = drsuapi.removeDESLayer(encryptedNTHash, rid) else: NTHash = ntlm.NTOWFv1('', '') elif attId == LOOKUP_TABLE['userPrincipalName']: if attr['AttrVal']['valCount'] > 0: try: domain = ''.join(attr['AttrVal']['pAVal'][0]['pVal']).decode('utf-16le').split('@')[-1] except: domain = None else: domain = None elif attId == LOOKUP_TABLE['sAMAccountName']: if attr['AttrVal']['valCount'] > 0: try: userName = ''.join(attr['AttrVal']['pAVal'][0]['pVal']).decode('utf-16le') except: logging.error('Cannot get sAMAccountName for %s' % record['pmsgOut']['V6']['pNC']['StringName'][:-1]) userName = '******' else: logging.error('Cannot get sAMAccountName for %s' % record['pmsgOut']['V6']['pNC']['StringName'][:-1]) userName = '******' elif attId == LOOKUP_TABLE['objectSid']: if attr['AttrVal']['valCount'] > 0: objectSid = ''.join(attr['AttrVal']['pAVal'][0]['pVal']) else: logging.error('Cannot get objectSid for %s' % record['pmsgOut']['V6']['pNC']['StringName'][:-1]) objectSid = rid elif attId == LOOKUP_TABLE['pwdLastSet']: if attr['AttrVal']['valCount'] > 0: try: pwdLastSet = self.__fileTimeToDateTime(unpack('<Q', ''.join(attr['AttrVal']['pAVal'][0]['pVal']))[0]) except: traceback.print_exc() logging.error('Cannot get pwdLastSet for %s' % record['pmsgOut']['V6']['pNC']['StringName'][:-1]) pwdLastSet = 'N/A' if self.__history: if attId == LOOKUP_TABLE['lmPwdHistory']: if attr['AttrVal']['valCount'] > 0: encryptedLMHistory = ''.join(attr['AttrVal']['pAVal'][0]['pVal']) tmpLMHistory = drsuapi.DecryptAttributeValue(self.__remoteOps.getDrsr(), encryptedLMHistory) for i in range(0, len(tmpLMHistory) / 16): LMHashHistory = drsuapi.removeDESLayer(tmpLMHistory[i * 16:(i + 1) * 16], rid) LMHistory.append(LMHashHistory) else: logging.debug('No lmPwdHistory for user %s' % record['pmsgOut']['V6']['pNC']['StringName'][:-1]) elif attId == LOOKUP_TABLE['ntPwdHistory']: if attr['AttrVal']['valCount'] > 0: encryptedNTHistory = ''.join(attr['AttrVal']['pAVal'][0]['pVal']) tmpNTHistory = drsuapi.DecryptAttributeValue(self.__remoteOps.getDrsr(), encryptedNTHistory) for i in range(0, len(tmpNTHistory) / 16): NTHashHistory = drsuapi.removeDESLayer(tmpNTHistory[i * 16:(i + 1) * 16], rid) NTHistory.append(NTHashHistory) else: logging.debug('No ntPwdHistory for user %s' % record['pmsgOut']['V6']['pNC']['StringName'][:-1]) if domain is not None: userName = '******' % (domain, userName) answer = "%s:%s:%s:%s:::" % (userName, rid, hexlify(LMHash), hexlify(NTHash)) if outputFile is not None: self.__writeOutput(outputFile, answer + '\n') if self.__pwdLastSet is True: answer = "%s (pwdLastSet=%s)" % (answer, pwdLastSet) self.__logger.highlight(answer) if self.__history: for i, (LMHashHistory, NTHashHistory) in enumerate( map(lambda l, n: (l, n) if l else ('', n), LMHistory[1:], NTHistory[1:])): if self.__noLMHash: lmhash = hexlify(ntlm.LMOWFv1('', '')) else: lmhash = hexlify(LMHashHistory) answer = "%s_history%d:%s:%s:%s:::" % (userName, i, rid, lmhash, hexlify(NTHashHistory)) self.__logger.highlight(answer) if outputFile is not None: self.__writeOutput(outputFile, answer + '\n')
def test_DRSGetNCChanges(self): # Not yet working dce, rpctransport, hDrs = self.connect() request = drsuapi.DRSGetNCChanges() request['hDrs'] = hDrs request['dwInVersion'] = 10 request['pmsgIn']['tag'] =10 request['pmsgIn']['V10']['uuidDsaObjDest'] = string_to_bin('e85bbad7-0923-41cb-911e-3691d2014815') request['pmsgIn']['V10']['uuidInvocIdSrc'] = string_to_bin('e85bbad7-0923-41cb-911e-3691d2014815') #request['pmsgIn']['V10']['pNC'] = NULL dsName = drsuapi.DSNAME() dsName['SidLen'] = 0 dsName['Guid'] = drsuapi.NULLGUID dsName['Sid'] = '' #name = 'CN=NTDS Settings,CN=FREEFLY-DC,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,DC=FREEFLY,DC=NET' #name = 'CN=admin,CN=Users,DC=FREEFLY,DC=NET' name = 'CN=krbtgt,CN=Users,DC=FREEFLY,DC=NET' #name = 'DC=FREEFLY,DC=NET' #name = 'CN=Schema,CN=Configuration,DC=FREEFLY,DC=NET' #name = 'CN=Aggregate,CN=Schema,CN=Configuration,DC=FREEFLY,DC=NET' dsName['NameLen'] = len(name) dsName['StringName'] = (name + '\x00') dsName['structLen'] = len(dsName.getData()) request['pmsgIn']['V10']['pNC'] = dsName request['pmsgIn']['V10']['usnvecFrom']['usnHighObjUpdate'] = 0 request['pmsgIn']['V10']['usnvecFrom']['usnHighPropUpdate'] = 0 request['pmsgIn']['V10']['pUpToDateVecDest'] = NULL request['pmsgIn']['V10']['ulFlags'] = drsuapi.DRS_INIT_SYNC | drsuapi.DRS_PER_SYNC #| drsuapi.DRS_CRITICAL_ONLY request['pmsgIn']['V10']['cMaxObjects'] = 50 request['pmsgIn']['V10']['cMaxBytes'] = 0 request['pmsgIn']['V10']['ulExtendedOp'] = drsuapi.EXOP_REPL_OBJ | drsuapi.EXOP_REPL_SECRETS request['pmsgIn']['V10']['pPartialAttrSet'] = NULL request['pmsgIn']['V10']['pPartialAttrSetEx1'] = NULL request['pmsgIn']['V10']['PrefixTableDest']['pPrefixEntry'] = NULL #request['pmsgIn']['V10']['ulMoreFlags'] = 0 from impacket.winregistry import hexdump print 'SESSION KEY' hexdump(dce.get_session_key()) resp = dce.request(request) resp.dump() unicodePwdAttr = 589914 for attr in resp['pmsgOut']['V6']['pObjects']['Entinf']['AttrBlock']['pAttr']: if attr['attrTyp'] == unicodePwdAttr: print "Found encrypted unicodePwd" encryptedUnicodePwd = ''.join(attr['AttrVal']['pAVal'][0]['pVal']) elif attr['attrTyp'] == 0x00090092: import struct userSid = ''.join(attr['AttrVal']['pAVal'][0]['pVal'])[-4:] userRid = struct.unpack('<L', userSid)[0] print "Found RID ", userRid ntHash = drsuapi.DecryptAttributeValue(dce, encryptedUnicodePwd) # Now remove the DES layer ntHash = drsuapi.removeDESLayer(ntHash, userRid) print "User: %s" % name print "HTHASH ", ntHash.encode('hex')