Пример #1
0
    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 = AES(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
Пример #2
0
 def basic_decrypt(cls, key, ciphertext):
     assert len(ciphertext) >= 16
     aes = AES(key.contents, MODE_ECB)
     if len(ciphertext) == 16:
         return aes.decrypt(ciphertext)
     # Split the ciphertext into blocks.  The last block may be partial.
     cblocks = [ciphertext[p:p + 16] for p in range(0, len(ciphertext), 16)]
     lastlen = len(cblocks[-1])
     # CBC-decrypt all but the last two blocks.
     prev_cblock = b'\x00' * 16
     plaintext = b''
     for b in cblocks[:-2]:
         plaintext += _xorbytes(aes.decrypt(b), prev_cblock)
         prev_cblock = b
     # Decrypt the second-to-last cipher block.  The left side of
     # the decrypted block will be the final block of plaintext
     # xor'd with the final partial cipher block; the right side
     # will be the omitted bytes of ciphertext from the final
     # block.
     b = aes.decrypt(cblocks[-2])
     lastplaintext = _xorbytes(b[:lastlen], cblocks[-1])
     omitted = b[lastlen:]
     # Decrypt the final cipher block plus the omitted bytes to get
     # the second-to-last plaintext block.
     plaintext += _xorbytes(aes.decrypt(cblocks[-1] + omitted), prev_cblock)
     return plaintext + lastplaintext
Пример #3
0
    def get_NKLM_key(self):
        logger.debug('[SECURITY] Fetching NK$LM key...')
        if self.lsa_key is None:
            self.get_lsa_key()

        value = self.hive.get_value('Policy\\Secrets\\NL$KM\\CurrVal\\default')
        if value is None:
            logger.error('[SECURITY] Could not find NL$KM in registry')
            raise Exception('Could not find NL$KM in registry :(')

        if self.lsa_secret_key_vista_type is True:
            self.NKLM_key = b''
            record = LSA_SECRET.from_bytes(value[1])
            key = SECURITY.sha256_multi(self.lsa_key, record.data[:32])
            cipher = AES(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' * (16 - len(block))
                self.NKLM_key += cipher.decrypt(block)

        else:
            self.NKLM_key = self.decrypt_secret(self.lsa_key, value[1])

        logger.debug('[SECURITY] NL$KM key: %s' % self.NKLM_key.hex())
        return self.NKLM_key
Пример #4
0
	def decrypt(self, encrypted):
		# TODO: NT version specific, move from here in subclasses.
		cleartext = b''
		size = len(encrypted)
		if size:
			if size % 8:
				if not self.aes_key or not self.iv:
					return cleartext
				cipher = AES(self.aes_key, MODE_CFB, self.iv)
				cleartext = cipher.decrypt(encrypted)
			else:
				if not self.des_key or not self.iv:
					return cleartext
				cipher = TDES(self.des_key, MODE_CBC, self.iv[:8])
				cleartext = cipher.decrypt(encrypted)
		return cleartext
Пример #5
0
    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 = AES(self.hashed_bootkey[:0x10], MODE_CBC, 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
Пример #6
0
        def decrypt_attr(attr, key):
            if attr.data is not None:
                if attr.iv is not None:
                    cipher = AES(key, MODE_CBC, attr.iv)
                else:
                    cipher = AES(key, MODE_CBC, b'\x00' * 16)

                cleartext = cipher.decrypt(attr.data)
                return cleartext
Пример #7
0
    def get_secrets(self):
        logger.debug('[SECURITY] get_secrets')
        self.get_lsa_key()

        self.dump_dcc()

        # Let's first see if there are cached entries
        keys = self.hive.enum_key('Policy\\Secrets')
        if keys is None:
            logger.debug('[SECURITY] No cached secrets found in hive')
            return

        if b'NL$Control' in keys:
            keys.remove(b'NL$Control')

        for key_name in keys:
            for vl in ['CurrVal', 'OldVal']:
                key_path = 'Policy\\Secrets\\{}\\{}\\default'.format(
                    key_name, vl)
                logger.debug('[SECURITY] Parsing secrets in %s' % key_path)
                v = self.hive.get_value(key_path, False)
                if v and v[1] != 0:
                    logger.log(1,
                               '[SECURITY] Key %s Value %s' % (key_path, v[1]))
                    if self.lsa_secret_key_vista_type is True:
                        record = LSA_SECRET.from_bytes(v[1])
                        key = SECURITY.sha256_multi(self.lsa_key,
                                                    record.data[:32])
                        secret_dec = b''
                        cipher = AES(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)
                        dec_blob = record.secret

                    else:
                        dec_blob = self.decrypt_secret(self.lsa_key, v[1])

                    secret = LSASecret.process(key_name, dec_blob,
                                               vl == 'OldVal',
                                               self.system_hive)
                    if secret is not None:
                        self.cached_secrets.append(secret)

                else:
                    logger.debug('[SECURITY] Could not open %s, skipping!' %
                                 key_path)
Пример #8
0
def gppassword(pw_enc_b64):
    AES_KEY = b'\x4e\x99\x06\xe8\xfc\xb6\x6c\xc9\xfa\xf4\x93\x10\x62\x0f\xfe\xe8\xf4\x96\xe8\x06\xcc\x05\x79\x90\x20\x9b\x09\xa4\x33\xb6\x6c\x1b'
    AES_IV = b'\x00' * 16

    pad = len(pw_enc_b64) % 4
    if pad == 1:
        pw_enc_b64 = pw_enc_b64[:-1]
    elif pad == 2 or pad == 3:
        pw_enc_b64 += '=' * (4 - pad)

    pw_enc = base64.b64decode(pw_enc_b64)

    ctx = AES(AES_KEY, MODE_CBC, IV=AES_IV)
    pw_dec = pkcs7_unpad(ctx.decrypt(pw_enc))

    return pw_dec.decode('utf-16-le')
Пример #9
0
    async def get_HBoot_key(self):
        logger.debug('SAM parsing hashed bootkey')
        QWERTY = b"!@#$%^&*()qwertyUIOPAzxcvbnmQQQQQQQQQQQQ)(*@&%\0"
        DIGITS = b"0123456789012345678901234567890123456789\0"

        F = await self.hive.get_value(r'SAM\Domains\Account\F')
        F = 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 = AES(self.bootkey,
                         MODE_CBC,
                         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
Пример #10
0
    def dump_dcc(self):
        logger.debug('[SECURITY] dump_dcc invoked')
        cache_reg = self.hive.find_key('Cache', False)
        if cache_reg is None:
            logger.debug('[SECURITY] No DCC secrets found')
            return
        values = 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 = self.hive.get_value('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()

        for value in values:
            logger.debug('[SECURITY] DCC 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 = AES(self.NKLM_key[16:32],
                                     MODE_CBC,
                                     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,
                                       digestmod='md5').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
Пример #11
0
    def decrypt_all_chrome(self, dbpaths, throw=False):
        from unicrypto import use_library, get_cipher_by_name
        AES = get_cipher_by_name('AES', 'cryptography')

        results = {}
        results['logins'] = []
        results['cookies'] = []
        results['fmtcookies'] = []
        localstate_dec = None

        for username in dbpaths:
            if 'localstate' in dbpaths[username]:
                with open(dbpaths[username]['localstate'], 'r') as f:
                    encrypted_key = json.load(f)['os_crypt']['encrypted_key']
                    encrypted_key = base64.b64decode(encrypted_key)

                try:
                    localstate_dec = self.decrypt_blob_bytes(encrypted_key[5:])
                except:
                    if throw is True:
                        raise Exception('LocalState decryption failed!')
                    # this localstate was encrypted for another user...
                    continue
            if 'cookies' in dbpaths[username]:
                secrets = DPAPI.get_chrome_encrypted_secret(
                    dbpaths[username]['cookies'])
                for host_key, name, path, encrypted_value in secrets[
                        'cookies']:
                    if encrypted_value.startswith(b'v10'):
                        nonce = encrypted_value[3:3 + 12]
                        ciphertext = encrypted_value[3 + 12:-16]
                        tag = encrypted_value[-16:]
                        cipher = AES(localstate_dec,
                                     MODE_GCM,
                                     IV=nonce,
                                     segment_size=16)
                        dec_val = cipher.decrypt(ciphertext, b'', tag)
                        results['cookies'].append(
                            (dbpaths[username]['cookies'], host_key, name,
                             path, dec_val))
                        results['fmtcookies'].append(
                            DPAPI.cookieformatter('https://' + host_key, name,
                                                  path, dec_val))
                    else:
                        dec_val = self.decrypt_blob_bytes(encrypted_value)
                        results['cookies'].append(
                            (dbpaths[username]['cookies'], host_key, name,
                             path, dec_val))
                        results['fmtcookies'].append(
                            DPAPI.cookieformatter('https://' + host_key, name,
                                                  path, dec_val))

            if 'logindata' in dbpaths[username]:
                secrets = DPAPI.get_chrome_encrypted_secret(
                    dbpaths[username]['logindata'])
                for url, user, enc_password in secrets['logins']:
                    if enc_password.startswith(b'v10'):
                        nonce = enc_password[3:3 + 12]
                        ciphertext = enc_password[3 + 12:-16]
                        tag = enc_password[-16:]
                        cipher = AES(localstate_dec,
                                     MODE_GCM,
                                     IV=nonce,
                                     segment_size=16)
                        password = cipher.decrypt(ciphertext, b'', tag)
                        results['logins'].append(
                            (dbpaths[username]['logindata'], url, user,
                             password))

                    else:
                        password = self.decrypt_blob_bytes(enc_password)
                        results['logins'].append(
                            (dbpaths[username]['logindata'], url, user,
                             password))

        return results
Пример #12
0
    def decrypt_all_chrome(self, dbpaths):
        results = {}
        results['logins'] = []
        results['cookies'] = []
        results['fmtcookies'] = []
        localstate_dec = None

        for username in dbpaths:
            if 'localstate' in dbpaths[username]:
                with open(dbpaths[username]['localstate'], 'r') as f:
                    encrypted_key = json.load(f)['os_crypt']['encrypted_key']
                    encrypted_key = base64.b64decode(encrypted_key)

                try:
                    localstate_dec = self.decrypt_blob_bytes(encrypted_key[5:])
                except:
                    # this localstate was encrypted for another user...
                    continue
            if 'cookies' in dbpaths[username]:
                secrets = DPAPI.get_chrome_encrypted_secret(
                    dbpaths[username]['cookies'])
                for host_key, name, path, encrypted_value in secrets[
                        'cookies']:
                    if encrypted_value.startswith(b'v10'):
                        nonce = encrypted_value[3:3 + 12]
                        ciphertext = encrypted_value[3 + 12:-16]
                        tag = encrypted_value[-16:]
                        cipher = AES(localstate_dec, MODE_GCM)
                        dec_val = cipher.decrypt(nonce,
                                                 ciphertext,
                                                 tag,
                                                 auth_data=b'')
                        results['cookies'].append(
                            (dbpaths[username]['cookies'], host_key, name,
                             path, dec_val))
                        results['fmtcookies'].append(
                            DPAPI.cookieformatter('https://' + host_key, name,
                                                  path, dec_val))
                    else:
                        dec_val = self.decrypt_blob_bytes(encrypted_value)
                        results['cookies'].append(
                            (dbpaths[username]['cookies'], host_key, name,
                             path, dec_val))
                        results['fmtcookies'].append(
                            DPAPI.cookieformatter('https://' + host_key, name,
                                                  path, dec_val))

            if 'logindata' in dbpaths[username]:
                secrets = DPAPI.get_chrome_encrypted_secret(
                    dbpaths[username]['logindata'])
                for url, user, enc_password in secrets['logins']:
                    if enc_password.startswith(b'v10'):
                        nonce = enc_password[3:3 + 12]
                        ciphertext = enc_password[3 + 12:-16]
                        tag = enc_password[-16:]
                        cipher = AES(localstate_dec, MODE_GCM)
                        password = cipher.decrypt(nonce,
                                                  ciphertext,
                                                  tag,
                                                  auth_data=b'')
                        results['logins'].append(
                            (dbpaths[username]['logindata'], url, user,
                             password))

                    else:
                        password = self.decrypt_blob_bytes(enc_password)
                        results['logins'].append(
                            (dbpaths[username]['logindata'], url, user,
                             password))

        return results