def decrypt_lsa_key(self, data): logger.debug('[SECURITY] Decrypting LSA key...') if self.lsa_secret_key_vista_type is True: record = LSA_SECRET.from_bytes(data) key = SECURITY.sha256_multi(self.bootkey, record.data[:32]) secret_dec = b'' cipher = AESModeOfOperationECB(key) n = 16 for block in [ record.data[32:][i:i + n] for i in range(0, len(record.data[32:]), n) ]: #terrible, terrible workaround if len(block) < n: block += b'\x00' * (n - len(block)) secret_dec += cipher.decrypt(block) record = LSA_SECRET_BLOB.from_bytes(secret_dec) self.lsa_key = record.secret[52:][:32] else: ctx = hashlib.md5(self.bootkey) for i in range(1000): ctx.update(data[60:76]) cipher = RC4(ctx.digest()) record = cipher.decrypt(data[12:60]) self.lsa_key = record[0x10:0x20] logger.debug('[SECURITY] LSA key value: %s' % self.lsa_key.hex()) return self.lsa_key
def decrypt_hash(self, rid, hashobj, constant): key1, key2 = SAM.rid_to_key(rid) des1 = des(key1) des2 = des(key2) if isinstance(hashobj, SAM_HASH): rc4key = hashlib.md5( self.hashed_bootkey[:0x10] + int(rid, 16).to_bytes(4, 'little', signed=False) + constant).digest() key = RC4(rc4key).encrypt(hashobj.hash) else: key = b'' cipher = AESModeOfOperationCBC(self.hashed_bootkey[:0x10], iv=hashobj.salt) n = 16 for block in [ hashobj.data[i:i + n] for i in range(0, len(hashobj.data), n) ]: #terrible, terrible workaround key += cipher.decrypt(block) key = key[:16] dec_hash = des1.decrypt(key[:8]) + des2.decrypt(key[8:]) return dec_hash
def get_HBoot_key(self): logger.debug('SAM parsing hashed bootkey') QWERTY = b"!@#$%^&*()qwertyUIOPAzxcvbnmQQQQQQQQQQQQ)(*@&%\0" DIGITS = b"0123456789012345678901234567890123456789\0" F = self.hive.get_value(r'SAM\Domains\Account\F')[1] logger.log(1,'[SAM] F key value: %s' % F) domain_properties = DOMAIN_ACCOUNT_F.from_bytes(F) if isinstance(domain_properties.key_0, SAM_KEY_DATA): rc4_key = hashlib.md5(domain_properties.key_0.salt + QWERTY + self.bootkey +DIGITS).digest() self.hashed_bootkey = RC4(rc4_key).encrypt(domain_properties.key_0.key + domain_properties.key_0.checksum) checksum = hashlib.md5(self.hashed_bootkey[:16] + DIGITS + self.hashed_bootkey[:16] + QWERTY).digest() if checksum != self.hashed_bootkey[16:]: logger.error('[SAM] HBootkey checksum verification failed!') raise Exception('[SAM] HBootkey checksum verification failed!') elif isinstance(domain_properties.key_0, SAM_KEY_DATA_AES): self.hashed_bootkey = b'' cipher = AESModeOfOperationCBC(self.bootkey, iv = domain_properties.key_0.salt) n = 16 for block in [domain_properties.key_0.data[i:i+n] for i in range(0, len(domain_properties.key_0.data), n)]: #terrible, terrible workaround self.hashed_bootkey += cipher.decrypt(block) logger.debug('[SAM] HBootkey: %s' % self.hashed_bootkey.hex()) return self.hashed_bootkey
def decrypt_lsa_key(self, data): if self.lsa_secret_key_vista_type is True: record = LSA_SECRET.from_bytes(data) key = SECURITY.sha256_multi(self.bootkey, record.data[:32]) secret_dec = b'' cipher = AESModeOfOperationECB(key) n = 16 for block in [ record.data[32:][i:i + n] for i in range(0, len(record.data[32:]), n) ]: #terrible, terrible workaround secret_dec += cipher.decrypt(block) record = LSA_SECRET_BLOB.from_bytes(secret_dec) self.lsa_key = record.secret[52:][:32] else: ctx = hashlib.md5(self.bootkey) for i in range(1000): ctx.update(value[60:76]) cipher = RC4.new(ctx.digest()) record = rc4.decrypt(value[12:60]) self.lsa_key = record[0x10:0x20] return self.lsa_key
def decrypt(self, encrypted): # TODO: NT version specific, move from here in subclasses. cleartext = b'' size = len(encrypted) if size: if (size % 8) != 0: ctx = RC4(self.random_key) cleartext = ctx.decrypt(encrypted) else: #print('Decryption not implemented!') cleartext = self.__desx_decrypt(encrypted) #raise Exception('Not implemented!') return cleartext
async def dump_dcc(self): logger.debug('[SECURITY] dump_dcc invoked') cache_reg = await self.hive.find_key('Cache', False) if cache_reg is None: logger.debug('[SECURITY] No DCC secrets found') return values = await self.hive.list_values(cache_reg) if values == []: logger.debug('[SECURITY] No DCC secrets found') return if b'NL$Control' in values: values.remove(b'NL$Control') if b'NL$IterationCount' in values: logger.debug('[SECURITY] DCC Setting iteration count') values.remove(b'NL$IterationCount') record = await self.hive.get_value('Cache\\NL$IterationCount') record = record[1] if record > 10240: self.dcc_iteration_count = record & 0xfffffc00 else: self.dcc_iteration_count = record * 1024 await self.get_lsa_key() await self.get_NKLM_key() for value in values: logger.debug('[SECURITY] DCC Checking value: %s' % value) record_data = await self.hive.get_value('Cache\\%s' % value.decode()) record_data = record_data[1] record = NL_RECORD.from_bytes(record_data) if record.IV != b'\x00' * 16: if record.Flags & 1 == 1: # Encrypted if self.lsa_secret_key_vista_type is True: plaintext = b'' cipher = AESModeOfOperationCBC(self.NKLM_key[16:32], iv=record.IV) n = 16 for block in [ record.EncryptedData[i:i + n] for i in range(0, len(record.EncryptedData), n) ]: #terrible, terrible workaround if len(block) < 16: block += b'\x00' * (16 - len(block)) plaintext += cipher.decrypt(block) else: key = hmac.new(self.NKLM_key, record.IV).digest() cipher = RC4(key) plaintext = cipher.decrypt(record.EncryptedData) else: # Plain! Until we figure out what this is, we skip it #plainText = record['EncryptedData'] logger.debug( '[SECURITY] DCC Skipping value %s, unknown formet' % value) continue dcc_hash = plaintext[:0x10] blob = io.BytesIO(plaintext[0x48:]) username = blob.read(record.UserLength).decode('utf-16-le') blob.seek( self.__pad(record.UserLength) + self.__pad(record.DomainNameLength)) domain = blob.read( record.DnsDomainNameLength).decode('utf-16-le') version = 2 if self.lsa_secret_key_vista_type is True else 1 secret = LSADCCSecret(version, domain, username, dcc_hash, iteration=self.dcc_iteration_count) self.dcc_hashes.append(secret) return self.dcc_hashes
def dump_dcc(self): cache_reg = self.hive.find_key('Cache') values = self.hive.list_values(cache_reg) if values == []: return if b'NL$Control' in values: values.remove(b'NL$Control') if b'NL$IterationCount' in values: values.remove(b'NL$IterationCount') record = self.getValue('Cache\\NL$IterationCount')[1] if record > 10240: self.dcc_iteration_count = record & 0xfffffc00 else: self.dcc_iteration_count = record * 1024 self.get_lsa_key() self.get_NKLM_key() print(self.lsa_key) print(self.NKLM_key) for value in values: print('Checking value: %s' % value) record_data = self.hive.get_value('Cache\\%s' % value.decode())[1] record = NL_RECORD.from_bytes(record_data) if record.IV != b'\x00' * 16: if record.Flags & 1 == 1: # Encrypted if self.lsa_secret_key_vista_type is True: plaintext = b'' cipher = AESModeOfOperationCBC(self.NKLM_key[16:32], iv=record.IV) n = 16 for block in [ record.EncryptedData[i:i + n] for i in range(0, len(record.EncryptedData), n) ]: #terrible, terrible workaround if len(block) < 16: block += b'\x00' * (16 - len(block)) plaintext += cipher.decrypt(block) else: key = hmac.new(self.NKLM_key, record.IV).digest() cipher = RC4(key) plaintext = cipher.decrypt(record.EncryptedData) else: # Plain! Until we figure out what this is, we skip it #plainText = record['EncryptedData'] continue dcc_hash = plaintext[:0x10] blob = io.BytesIO(plaintext[0x48:]) username = blob.read(record.UserLength).decode('utf-16-le') blob.seek( self.__pad(record.UserLength) + self.__pad(record.DomainNameLength)) domain = blob.read( record.DnsDomainNameLength).decode('utf-16-le') if self.lsa_secret_key_vista_type is True: ans = "%s/%s:$DCC2$%s#%s#%s" % (domain, username, self.dcc_iteration_count, username, dcc_hash.hex()) else: ans = "%s/%s:%s:%s" % (domain, username, dcc_hash.hex(), username) print(ans)