Ejemplo n.º 1
0
    def key_iterator(
        cls,
        hive: RegistryHive,
        node_path: Sequence[objects.StructType] = None,
        recurse: bool = False
    ) -> Iterable[Tuple[int, bool, datetime.datetime, str, bool,
                        interfaces.objects.ObjectInterface]]:
        """Walks through a set of nodes from a given node (last one in
        node_path). Avoids loops by not traversing into nodes already present
        in the node_path.

        Args:
            hive: The registry hive to walk
            node_path: The list of nodes that make up the
            recurse: Traverse down the node tree or stay only on the same level

        Yields:
            A tuple of results (depth, is_key, last write time, path, volatile, and the node).
        """
        if not node_path:
            node_path = [hive.get_node(hive.root_cell_offset)]
        if not isinstance(node_path, list) or len(node_path) < 1:
            vollog.warning(
                "Hive walker was not passed a valid node_path (or None)")
            return
        node = node_path[-1]
        key_path_items = [hive] + node_path[1:]
        key_path = '\\'.join([k.get_name() for k in key_path_items])
        if node.vol.type_name.endswith(constants.BANG + '_CELL_DATA'):
            raise RegistryFormatException(
                hive.name, "Encountered _CELL_DATA instead of _CM_KEY_NODE")
        last_write_time = conversion.wintime_to_datetime(
            node.LastWriteTime.QuadPart)

        for key_node in node.get_subkeys():
            result = (len(node_path), True, last_write_time, key_path,
                      key_node.get_volatile(), key_node)
            yield result

            if recurse:
                if key_node.vol.offset not in [
                        x.vol.offset for x in node_path
                ]:
                    try:
                        key_node.get_name()
                    except exceptions.InvalidAddressException as excp:
                        vollog.debug(excp)
                        continue

                    yield from cls.key_iterator(hive,
                                                node_path + [key_node],
                                                recurse=recurse)

        for value_node in node.get_values():
            result = (len(node_path), False, last_write_time, key_path,
                      node.get_volatile(), value_node)
            yield result
Ejemplo n.º 2
0
    def _generator(self, syshive: registry.RegistryHive,
                   sechive: registry.RegistryHive):

        vista_or_later = versions.is_vista_or_later(
            context=self.context, symbol_table=self.config['nt_symbols'])

        bootkey = hashdump.Hashdump.get_bootkey(syshive)
        lsakey = self.get_lsa_key(sechive, bootkey, vista_or_later)
        if not bootkey:
            raise ValueError('Unable to find bootkey')

        if not lsakey:
            raise ValueError('Unable to find lsa key')

        secrets_key = sechive.get_key('Policy\\Secrets')
        if not secrets_key:
            raise ValueError('Unable to find secrets key')

        for key in secrets_key.get_subkeys():

            sec_val_key = sechive.get_key('Policy\\Secrets\\' +
                                          key.get_key_path().split('\\')[3] +
                                          '\\CurrVal')
            if not sec_val_key:
                continue

            enc_secret_value = next(sec_val_key.get_values())
            if not enc_secret_value:
                continue

            enc_secret = sechive.read(enc_secret_value.Data + 4,
                                      enc_secret_value.DataLength)
            if not enc_secret:
                continue
            if not vista_or_later:
                secret = self.decrypt_secret(enc_secret[0xC:], lsakey)
            else:
                secret = self.decrypt_aes(enc_secret, lsakey)

            yield (0, (key.get_name(), secret.decode('latin1'), secret))
Ejemplo n.º 3
0
    def get_secret_by_name(cls, sechive: registry.RegistryHive, name: str,
                           lsakey: bytes, is_vista_or_later: bool):
        try:
            enc_secret_key = sechive.get_key("Policy\\Secrets\\" + name +
                                             "\\CurrVal")
        except KeyError:
            raise ValueError("Unable to read cache from memory")

        enc_secret_value = next(enc_secret_key.get_values())
        if not enc_secret_value:
            return None

        enc_secret = sechive.read(enc_secret_value.Data + 4,
                                  enc_secret_value.DataLength)
        if not enc_secret:
            return None

        if not is_vista_or_later:
            secret = cls.decrypt_secret(enc_secret[0xC:], lsakey)
        else:
            secret = cls.decrypt_aes(enc_secret, lsakey)
        return secret
Ejemplo n.º 4
0
    def get_lsa_key(cls, sechive: registry.RegistryHive, bootkey: bytes,
                    vista_or_later: bool) -> Optional[bytes]:
        if not bootkey:
            return None

        if vista_or_later:
            policy_key = 'PolEKList'
        else:
            policy_key = 'PolSecretEncryptionKey'

        enc_reg_key = sechive.get_key("Policy\\" + policy_key)
        if not enc_reg_key:
            return None
        enc_reg_value = next(enc_reg_key.get_values())

        if not enc_reg_value:
            return None

        obf_lsa_key = sechive.read(enc_reg_value.Data + 4,
                                   enc_reg_value.DataLength)

        if not obf_lsa_key:
            return None
        if not vista_or_later:
            md5 = MD5.new()
            md5.update(bootkey)
            for _i in range(1000):
                md5.update(obf_lsa_key[60:76])
            rc4key = md5.digest()

            rc4 = ARC4.new(rc4key)
            lsa_key = rc4.decrypt(obf_lsa_key[12:60])
            lsa_key = lsa_key[0x10:0x20]
        else:
            lsa_key = cls.decrypt_aes(obf_lsa_key, bootkey)
            lsa_key = lsa_key[68:100]
        return lsa_key
Ejemplo n.º 5
0
    def _generator(self, syshive: registry.RegistryHive,
                   sechive: registry.RegistryHive):

        kernel = self.context.modules[self.config['kernel']]

        vista_or_later = versions.is_vista_or_later(
            context=self.context, symbol_table=kernel.symbol_table_name)

        bootkey = hashdump.Hashdump.get_bootkey(syshive)
        lsakey = self.get_lsa_key(sechive, bootkey, vista_or_later)
        if not bootkey:
            vollog.warning("Unable to find bootkey")
            return

        if not lsakey:
            vollog.warning("Unable to find lsa key")
            return

        secrets_key = hashdump.Hashdump.get_hive_key(sechive,
                                                     'Policy\\Secrets')
        if not secrets_key:
            vollog.warning("Unable to find secrets key")
            return

        for key in secrets_key.get_subkeys():

            sec_val_key = hashdump.Hashdump.get_hive_key(
                sechive, 'Policy\\Secrets\\' +
                key.get_key_path().split('\\')[3] + '\\CurrVal')
            if not sec_val_key:
                continue

            enc_secret_value = next(sec_val_key.get_values())
            if not enc_secret_value:
                continue

            enc_secret = sechive.read(enc_secret_value.Data + 4,
                                      enc_secret_value.DataLength)
            if not enc_secret:
                continue
            if not vista_or_later:
                secret = self.decrypt_secret(enc_secret[0xC:], lsakey)
            else:
                secret = self.decrypt_aes(enc_secret, lsakey)

            yield (0, (key.get_name(), secret.decode('latin1'), secret))
Ejemplo n.º 6
0
    def _get_subkeys_recursive(
        self, hive: RegistryHive, node: interfaces.objects.ObjectInterface
    ) -> Iterable[interfaces.objects.ObjectInterface]:
        """Recursively descend a node returning subkeys."""
        # The keylist appears to include 4 bytes of key name after each value
        # We can either double the list and only use the even items, or
        # We could change the array type to a struct with both parts
        try:
            signature = node.cast('string', max_length=2, encoding='latin-1')
        except (exceptions.InvalidAddressException, RegistryFormatException):
            return

        listjump = None
        if signature == 'ri':
            listjump = 1
        elif signature == 'lh' or signature == 'lf':
            listjump = 2
        elif node.vol.type_name.endswith(constants.BANG + "_CM_KEY_NODE"):
            yield node
        else:
            vollog.debug(
                "Unexpected node type encountered when traversing subkeys: {}, signature: {}"
                .format(node.vol.type_name, signature))

        if listjump:
            node.List.count = node.Count * listjump
            for subnode_offset in node.List[::listjump]:
                if (subnode_offset & 0x7fffffff) > hive.maximum_address:
                    vollog.log(
                        constants.LOGLEVEL_VVV,
                        "Node found with address outside the valid Hive size: {}"
                        .format(hex(subnode_offset)))
                else:
                    try:
                        subnode = hive.get_node(subnode_offset)
                    except (exceptions.InvalidAddressException,
                            RegistryFormatException):
                        vollog.log(
                            constants.LOGLEVEL_VVV,
                            "Failed to get node at {}, skipping".format(
                                hex(subnode_offset)))
                        continue
                    yield from self._get_subkeys_recursive(hive, subnode)
Ejemplo n.º 7
0
    def get_secret_by_name(cls, sechive: registry.RegistryHive, name: str,
                           lsakey: bytes, is_vista_or_later: bool):
        enc_secret_key = hashdump.Hashdump.get_hive_key(
            sechive, "Policy\\Secrets\\" + name + "\\CurrVal")

        secret = None
        if enc_secret_key:
            enc_secret_value = next(enc_secret_key.get_values())
            if enc_secret_value:

                enc_secret = sechive.read(enc_secret_value.Data + 4,
                                          enc_secret_value.DataLength)
                if enc_secret:

                    if not is_vista_or_later:
                        secret = cls.decrypt_secret(enc_secret[0xC:], lsakey)
                    else:
                        secret = cls.decrypt_aes(enc_secret, lsakey)

        return secret
Ejemplo n.º 8
0
    def list_userassist(
            self,
            hive: RegistryHive) -> Generator[Tuple[int, Tuple], None, None]:
        """Generate userassist data for a registry hive."""

        hive_name = hive.hive.cast(self.config["nt_symbols"] + constants.BANG +
                                   "_CMHIVE").get_name()

        if self._win7 is None:
            try:
                self._win7 = self._win7_or_later()
            except exceptions.SymbolError:
                # self._win7 will be None and only registry value rawdata will be output
                pass

        self._determine_userassist_type()

        userassist_node_path = hive.get_key(
            "software\\microsoft\\windows\\currentversion\\explorer\\userassist",
            return_list=True)

        if not userassist_node_path:
            vollog.warning(
                "list_userassist did not find a valid node_path (or None)")
            return

        if not isinstance(userassist_node_path, list):
            vollog.warning(
                "userassist_node_path did not return a list as expected")
            return
        userassist_node = userassist_node_path[-1]
        # iterate through the GUIDs under the userassist key
        for guidkey in userassist_node.get_subkeys():
            # each guid key should have a Count key in it
            for countkey in guidkey.get_subkeys():
                countkey_path = countkey.get_key_path()
                countkey_last_write_time = conversion.wintime_to_datetime(
                    countkey.LastWriteTime.QuadPart)

                # output the parent Count key
                result = (
                    0, (renderers.format_hints.Hex(hive.hive_offset),
                        hive_name, countkey_path, countkey_last_write_time,
                        "Key", renderers.NotApplicableValue(),
                        renderers.NotApplicableValue(),
                        renderers.NotApplicableValue(),
                        renderers.NotApplicableValue(),
                        renderers.NotApplicableValue(),
                        renderers.NotApplicableValue(),
                        renderers.NotApplicableValue())
                )  # type: Tuple[int, Tuple[format_hints.Hex, Any, Any, Any, Any, Any, Any, Any, Any, Any, Any, Any]]
                yield result

                # output any subkeys under Count
                for subkey in countkey.get_subkeys():

                    subkey_name = subkey.get_name()
                    result = (1, (
                        renderers.format_hints.Hex(hive.hive_offset),
                        hive_name,
                        countkey_path,
                        countkey_last_write_time,
                        "Subkey",
                        subkey_name,
                        renderers.NotApplicableValue(),
                        renderers.NotApplicableValue(),
                        renderers.NotApplicableValue(),
                        renderers.NotApplicableValue(),
                        renderers.NotApplicableValue(),
                        renderers.NotApplicableValue(),
                    ))
                    yield result

                # output any values under Count
                for value in countkey.get_values():

                    value_name = value.get_name()
                    try:
                        value_name = codecs.encode(value_name, "rot_13")
                    except UnicodeDecodeError:
                        pass

                    if self._win7:
                        guid = value_name.split("\\")[0]
                        if guid in self._folder_guids:
                            value_name = value_name.replace(
                                guid, self._folder_guids[guid])

                    userassist_data_dict = self.parse_userassist_data(value)
                    result = (1, (
                        renderers.format_hints.Hex(hive.hive_offset),
                        hive_name,
                        countkey_path,
                        countkey_last_write_time,
                        "Value",
                        value_name,
                        userassist_data_dict["id"],
                        userassist_data_dict["count"],
                        userassist_data_dict["focus"],
                        userassist_data_dict["time"],
                        userassist_data_dict["lastupdated"],
                        format_hints.HexBytes(userassist_data_dict["rawdata"]),
                    ))
                    yield result