Esempio n. 1
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
Esempio n. 2
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
Esempio n. 3
0
	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
Esempio n. 4
0
    def get_currentcontrol(self):
        logger.debug('[SYSTEM] determining current control set')
        if self.currentcontrol is not None:
            return self.currentcontrol

        ccs = self.hive.get_value('Select\\Current')[1]
        self.currentcontrol = "ControlSet%03d" % ccs
        logger.debug('[SYSTEM] current control set name: %s' %
                     self.currentcontrol)
        return self.currentcontrol
Esempio n. 5
0
    async def get_secrets(self):
        logger.debug('SAM get_secrets invoked')
        NTPASSWORD = b"NTPASSWORD\0"
        LMPASSWORD = b"LMPASSWORD\0"

        NTDEFAULT = '31d6cfe0d16ae931b73c59d7e0c089c0'
        LMDEFAULT = 'aad3b435b51404eeaad3b435b51404ee'

        await self.get_HBoot_key()
        await self.get_machine_sid()

        names = await self.hive.enum_key('SAM\\Domains\\Account\\Users')
        for rid in names:
            uac = None
            if rid == 'Names':
                continue

            key_path = 'SAM\\Domains\\Account\\Users\\%s\\V' % rid
            logger.debug('[SAM] Parsing secrets for RID: %s' % rid)
            uac_data = await self.hive.get_value(key_path)
            uac_data = uac_data[1]
            uac = USER_ACCOUNT_V.from_bytes(uac_data)

            nthash = bytes.fromhex(NTDEFAULT)
            lmhash = bytes.fromhex(LMDEFAULT)
            if uac.NT_hash and isinstance(uac.NT_hash, SAM_HASH_AES):
                if uac.NT_hash.data != b'':
                    nthash = self.decrypt_hash(rid, uac.NT_hash, NTPASSWORD)
            elif uac.NT_hash and isinstance(uac.NT_hash, SAM_HASH):
                if uac.NT_hash.hash != b'':
                    nthash = self.decrypt_hash(rid, uac.NT_hash, NTPASSWORD)

            if uac.LM_hash and isinstance(uac.LM_hash, SAM_HASH_AES):
                if uac.LM_hash.data != b'':
                    lmhash = self.decrypt_hash(rid, uac.LM_hash, LMPASSWORD)

            elif uac.LM_hash and isinstance(uac.LM_hash, SAM_HASH):
                if uac.LM_hash.hash != b'':
                    lmhash = self.decrypt_hash(rid, uac.LM_hash, LMPASSWORD)

            secret = SAMSecret(uac.name, int(rid, 16), nthash, lmhash)
            self.secrets.append(secret)

        return self.secrets
Esempio n. 6
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)
Esempio n. 7
0
    def get_bootkey(self):
        logger.debug('[SYSTEM] get_bootkey invoked')
        if self.bootkey is not None:
            return self.bootkey
        if self.currentcontrol is None:
            self.get_currentcontrol()

        transforms = [8, 5, 4, 2, 11, 9, 13, 3, 0, 6, 1, 12, 14, 10, 15, 7]
        bootkey_obf = ''
        for key in ['JD', 'Skew1', 'GBG', 'Data']:
            bootkey_obf += self.hive.get_class('%s\\Control\\Lsa\\%s' %
                                               (self.currentcontrol, key))

        bootkey_obf = bytes.fromhex(bootkey_obf)
        self.bootkey = b''
        for i in range(len(bootkey_obf)):
            self.bootkey += bootkey_obf[transforms[i]:transforms[i] + 1]

        logger.debug('[SYSTEM] bootkey: %s' % self.bootkey.hex())
        return self.bootkey
Esempio n. 8
0
	def get_lsa_key(self):
		logger.debug('[SECURITY] Fetching LSA key...')
		value = self.hive.get_value('Policy\\PolEKList\\default', False)
		if value is None:
			value = self.hive.get_value('Policy\\PolSecretEncryptionKey\\default', False)
			if not value:
				logger.debug('[SECURITY] LSA key not found!')
				return None
			
			self.lsa_secret_key_vista_type = False
			logger.debug('[SECURITY] LSA secrets default to VISTA type')
		
		return self.decrypt_lsa_key(value[1])
Esempio n. 9
0
    def from_live_system():
        logger.debug('Obtaining registry from local system')
        try:
            from pypykatz.commons.winapi.processmanipulator import ProcessManipulator
            from pypykatz.commons.winapi.constants import SE_BACKUP
            import winreg
            import tempfile
            import os
            import ntpath
        except Exception as e:
            logger.error(
                'Could not import necessary packages! Are you on Windows? Error: %s'
                % str(e))
            raise

        sam_name = ntpath.join(tempfile.gettempdir(), os.urandom(4).hex())
        system_name = ntpath.join(tempfile.gettempdir(), os.urandom(4).hex())
        security_name = ntpath.join(tempfile.gettempdir(), os.urandom(4).hex())

        locations = [
            ('SAM', sam_name),
            ('SYSTEM', system_name),
            ('SECURITY', security_name),
        ]

        logger.debug('Obtaining SE_BACKUP privilege...')
        try:
            po = ProcessManipulator()
            po.set_privilege(SE_BACKUP)
        except Exception as e:
            logger.error(
                'Failed to obtain SE_BACKUP privilege! Registry dump will not work! Reason: %s'
                % str(e))
            raise e
        logger.debug('Obtaining SE_BACKUP OK!')

        dumped_names = {}
        for reg_name, location in locations:
            logger.debug('Dumping %s...' % reg_name)
            try:
                key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE,
                                     reg_name,
                                     access=0x00020000)
                winreg.SaveKey(key, location)
                key.Close()
            except Exception as e:
                logger.error('Dumping %s FAILED!! Reason: %s' %
                             (reg_name, str(e)))
            else:
                logger.debug('Dumping %s OK!' % reg_name)
                dumped_names[reg_name] = location
        ###
        ### Do Parsing here!
        ###
        po = None
        if 'SYSTEM' in dumped_names:
            try:
                po = OffineRegistry.from_files(
                    system_name, sam_name if 'SAM' in dumped_names else None,
                    security_name if 'SECURITY' in dumped_names else None)
            except Exception as e:
                import traceback
                traceback.print_exc()
        else:
            logger.error('Failed to dump SYSTEM hive, exiting...')

        logger.debug('Cleaning up temp files')
        for reg_name, location in locations:
            try:
                os.remove(location)
            except Exception as e:
                logger.error(
                    'Failed to clean up temp file for %s! Sensitive files might have been left on the filesystem! Path: %s Reason: %s'
                    % (reg_name, location, str(e)))
            else:
                logger.debug('Cleanup for %s OK!' % reg_name)

        return po
Esempio n. 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