def run(self):
     self.entries = {}
     logger.info('Started Services enumeration Plugin...')
     for control_set_services_path in self.registry_hive.get_control_sets(SERVICES_PATH):
         try:
             subkey = self.registry_hive.get_key(control_set_services_path)
         except RegistryKeyNotFoundException as ex:
             logger.error(ex)
             continue
         self.entries[control_set_services_path] = {
             'timestamp': convert_wintime(subkey.header.last_modified, as_json=self.as_json)        
         }
         services = []
         for service in subkey.iter_subkeys():
             values = None
             if service.values_count > 0:
                 values = [attr.asdict(x) for x in service.iter_values(as_json=True)]
             entry = {
                 'name': service.name,
                 'last_modified': convert_wintime(service.header.last_modified, as_json=self.as_json),
                 'values': values,
                 'parameters': [attr.asdict(x) for x in self.registry_hive.recurse_subkeys(nk_record=service, path=r'{}\{}'.format(
                     control_set_services_path, service.name), as_json=True)] if service.subkey_count else None
             }
             services.append(entry)
         self.entries[control_set_services_path]['services'] = services
Example #2
0
    def recurse_subkeys(self, nk_record=None, path=None, as_json=False):
        """
        Recurse over a subkey, and yield all of its subkeys and values
        :param nk_record: an instance of NKRecord from which to start iterating, if None, will start from Root
        :param path: The current registry path
        :param as_json: Whether to normalize the data as JSON or not
        """
        # If None, will start iterating from Root NK entry
        if not nk_record:
            nk_record = self.root

        # Iterate over subkeys
        for subkey in nk_record.iter_subkeys():
            if subkey.subkey_count:
                if path:
                    yield from self.recurse_subkeys(nk_record=subkey,
                                                    path=r'{}\{}'.format(
                                                        path, subkey.name),
                                                    as_json=as_json)
                else:
                    yield from self.recurse_subkeys(nk_record=subkey,
                                                    path=r'\{}'.format(
                                                        subkey.name),
                                                    as_json=as_json)

            values = []
            if subkey.values_count:
                if as_json:
                    values = [
                        attr.asdict(x)
                        for x in subkey.iter_values(as_json=as_json)
                    ]
                else:
                    values = list(subkey.iter_values(as_json=as_json))

            ts = convert_wintime(subkey.header.last_modified)
            yield Subkey(
                subkey_name=subkey.name,
                path=r'{}\{}'.format(path, subkey.name) if path else '\\',
                timestamp=ts.isoformat() if as_json else ts,
                values=values,
                values_count=len(values))

        # Get the values of the subkey
        values = []
        if nk_record.values_count:
            if as_json:
                values = [
                    attr.asdict(x)
                    for x in nk_record.iter_values(as_json=as_json)
                ]
            else:
                values = list(nk_record.iter_values(as_json=as_json))

        ts = convert_wintime(nk_record.header.last_modified)
        yield Subkey(subkey_name=nk_record.name,
                     path=path,
                     timestamp=ts.isoformat() if as_json else ts,
                     values=values,
                     values_count=len(values))
Example #3
0
    def run(self):
        logger.info('Started AmCache Plugin...')
        is_win_7_hive = False
        entries = []

        try:
            amcache_subkey = self.registry_hive.get_key(r'\Root\File')
        except RegistryKeyNotFoundException:
            amcache_subkey = self.registry_hive.get_key(
                r'\Root\InventoryApplicationFile')
            is_win_7_hive = True

        if is_win_7_hive:
            for subkey in amcache_subkey.iter_subkeys():
                entry = {
                    underscore(x.name): x.value
                    for x in subkey.iter_values(as_json=self.as_json)
                }
                entry['program_id'] = entry['program_id'][4:]
                entry['file_id'] = entry['file_id'][4:]
                entry['sha1'] = entry['file_id']
                entry['timestamp'] = convert_wintime(
                    subkey.header.last_modified, as_json=self.as_json)
                entry['size'] = int(entry['size'], 16) if isinstance(
                    entry['size'], str) else entry['size']

                entry['is_pe_file'] = bool(entry['is_pe_file'])
                entry['is_os_component'] = bool(entry['is_os_component'])

                if entry['link_date'] == 0:
                    entry.pop('link_date')

                entry['type'] = 'win_7_amcache'
                entries.append(entry)
        else:
            for subkey in amcache_subkey.iter_subkeys():
                for file_subkey in subkey.iter_subkeys():
                    entry = {
                        x.name: x.value
                        for x in file_subkey.iter_values(as_json=self.as_json)
                    }
                    entry['timestamp'] = convert_wintime(
                        file_subkey.header.last_modified, as_json=self.as_json)

                    for k, v in WIN8_AMCACHE_MAPPINGS.items():
                        content = entry.pop(k, None)
                        if content:
                            entry[v] = content

                    entry['sha1'] = entry['sha1'][4:]
                    entry['program_id'] = entry['program_id'][4:]
                    entry['type'] = 'win_8+_amcache'

                    for ts_field_name in WIN8_TS_FIELDS:
                        ts = entry.pop(ts_field_name, None)
                        if ts:
                            entry[ts_field_name] = convert_wintime(
                                ts, as_json=self.as_json)
                    entries.append(entry)
        return entries
Example #4
0
    def run(self):
        for guid in GUIDS:
            try:
                subkey = self.registry_hive.get_key(r'{}\{}'.format(USER_ASSIST_KEY_PATH, guid))
                count_subkey = subkey.get_subkey('Count')

                if not count_subkey.values_count:
                    logger.debug('Skipping {}'.format(guid))
                    continue

                for value in count_subkey.iter_values():
                    name = codecs.decode(value.name, encoding='rot-13')

                    if name in WHITELISTED_NAMES:
                        continue

                    for k, v in GUID_TO_PATH_MAPPINGS.items():
                        if k in name:
                            name = name.replace(k, v)
                            break

                    entry = None
                    data = value.value
                    if len(data) == 72:
                        try:
                            parsed_entry = WIN7_USER_ASSIST.parse(data)
                        except ConstError as ex:
                            logger.error(f'Could not parse user assist entry named {name}: {ex}')
                            continue

                        entry = {
                            'name': name,
                            'timestamp': convert_wintime(parsed_entry.last_execution_timestamp, as_json=self.as_json),
                            'run_counter': parsed_entry.run_counter,
                            'focus_count': parsed_entry.focus_count,
                            'total_focus_time_ms': parsed_entry.total_focus_time_ms,
                            'session_id': parsed_entry.session_id
                        }

                    elif len(data) == 16:
                        try:
                            parsed_entry = WIN_XP_USER_ASSIST.parse(data)
                        except ConstError as ex:
                            logger.error(f'Could not parse user assist entry named {name}: {ex}')
                            continue

                        entry = {
                            'name': name,
                            'timestamp': convert_wintime(parsed_entry.last_execution_timestamp, as_json=self.as_json),
                            'session_id': parsed_entry.session_id,
                            'run_counter': parsed_entry.run_counter - 5
                        }

                    if entry:
                        self.entries.append(entry)
            except RegistryKeyNotFoundException:
                continue
Example #5
0
    def parse_amcache_file_entry(self, subkey):
        entry = {
            underscore(x.name): x.value
            for x in subkey.iter_values(as_json=self.as_json)
        }

        # Sometimes the value names might be numeric instead. Translate them:
        for k, v in AMCACHE_FIELD_NUMERIC_MAPPINGS.items():
            content = entry.pop(k, None)
            if content:
                entry[v] = content

        if 'sha1' in entry:
            entry['sha1'] = entry['sha1'][4:]

        if 'file_id' in entry and entry['file_id'] != 0:
            entry['file_id'] = entry['file_id'][4:]
            if 'sha1' not in entry:
                entry['sha1'] = entry['file_id']

        if 'program_id' in entry:
            entry['program_id'] = entry['program_id'][4:]

        entry['timestamp'] = convert_wintime(subkey.header.last_modified,
                                             as_json=self.as_json)

        if 'size' in entry:
            entry['size'] = int(entry['size'], 16) if isinstance(
                entry['size'], str) else entry['size']

        is_pefile = entry.get('is_pe_file')
        if is_pefile is not None:
            entry['is_pe_file'] = bool(is_pefile)

        is_os_component = entry.get('is_os_component')
        if is_os_component is not None:
            entry['is_os_component'] = bool(is_os_component)

        if entry.get('link_date') == 0:
            entry.pop('link_date')

        for ts_field_name in WIN8_TS_FIELDS:
            ts = entry.pop(ts_field_name, None)
            if ts:
                entry[ts_field_name] = convert_wintime(ts,
                                                       as_json=self.as_json)

        self.entries.append(entry)
    def run(self):
        try:
            subkey = self.registry_hive.get_key(WORD_WHEEL_QUERY_KEY_PATH)
        except RegistryKeyNotFoundException as ex:
            logger.error(
                f'Could not find {self.NAME} plugin data at: {WORD_WHEEL_QUERY_KEY_PATH}: {ex}'
            )
            return None

        timestamp = convert_wintime(subkey.header.last_modified,
                                    as_json=self.as_json)

        mru_list_order = subkey.get_value('MRUListEx')

        # If this is the value, the list is empty
        if mru_list_order == 0xffffffff:
            return None

        for i, entry_name in enumerate(
                GreedyRange(Int32ul).parse(mru_list_order)):
            entry_value = subkey.get_value(str(entry_name))

            if not entry_value:
                continue

            self.entries.append({
                'last_write': timestamp,
                'mru_id': entry_name,
                'order': i,
                'name': CString('utf-16').parse(entry_value)
            })
Example #7
0
    def run(self):
        logger.info('Started profile list plugin...')
        try:
            subkey = self.registry_hive.get_key(PROFILE_LIST_KEY_PATH)
        except RegistryKeyNotFoundException as ex:
            logger.error(ex)

        for profile in subkey.iter_subkeys():
            self.entries.append({
                'last_write':
                convert_wintime(profile.header.last_modified,
                                as_json=self.as_json),
                'path':
                profile.get_value('ProfileImagePath'),
                'flags':
                profile.get_value('Flags'),
                'full_profile':
                profile.get_value('FullProfile'),
                'state':
                profile.get_value('State'),
                'sid':
                profile.name,
                'load_time':
                convert_filetime(profile.get_value('ProfileLoadTimeLow'),
                                 profile.get_value('ProfileLoadTimeHigh')),
                'local_load_time':
                convert_filetime(profile.get_value('LocalProfileLoadTimeLow'),
                                 profile.get_value('LocalProfileLoadTimeHigh'))
            })
Example #8
0
def get_timestamp_for_subkeys(registry_hive, subkey_list):
    for subkey_path in subkey_list:
        try:
            subkey = registry_hive.get_key(subkey_path)
        except RegistryKeyNotFoundException as ex:
            logger.exception(f'Could not obtain timestamp for subkey {subkey_path}')
            continue
        yield subkey_path, convert_wintime(subkey.header.last_modified, as_json=True)
Example #9
0
    def run(self):
        try:
            open_subkey = self.registry_hive.get_key(WINRAR_ARCHIVE_OPEN_HIST)

            timestamp = convert_wintime(open_subkey.header.last_modified, as_json=self.as_json)
            opened_archives = [value.value for value in open_subkey.iter_values(as_json=self.as_json)]
            for archive in opened_archives:
                self.entries.append({
                    'last_write': timestamp,
                    'archive_path': archive,
                    'operation': 'archive_opened'
                })

        except RegistryKeyNotFoundException as ex:
            logger.error(f'Could not find {self.NAME} plugin data at: {WINRAR_ARCHIVE_OPEN_HIST}: {ex}')

        try:
            create_subkey = self.registry_hive.get_key(WINRAR_ARCHIVE_CREATION_HIST)

            timestamp = convert_wintime(create_subkey.header.last_modified, as_json=self.as_json)
            created_archives = [value.value for value in create_subkey.iter_values(as_json=self.as_json)]
            for archive in created_archives:
                self.entries.append({
                    'last_write': timestamp,
                    'archive_name': archive,
                    'operation': 'archive_created'
                })

        except RegistryKeyNotFoundException as ex:
            logger.error(f'Could not find {self.NAME} plugin data at: {WINRAR_ARCHIVE_CREATION_HIST}: {ex}')

        try:
            extract_subkey = self.registry_hive.get_key(WINRAR_ARCHIVE_EXTRACT_HIST)

            timestamp = convert_wintime(extract_subkey.header.last_modified, as_json=self.as_json)
            extracted_archives = [value.value for value in extract_subkey.iter_values(as_json=self.as_json)]
            for location in extracted_archives:
                self.entries.append({
                    'last_write': timestamp,
                    'destination_folder': location,
                    'operation': 'archive_extracted'
                })

        except RegistryKeyNotFoundException as ex:
            logger.error(f'Could not find {self.NAME} plugin data at: {WINRAR_ARCHIVE_EXTRACT_HIST}: {ex}')
Example #10
0
 def __dict__(self):
     return {
         'name': self.name,
         'subkey_count': self.subkey_count,
         'value_count': self.values_count,
         'values': {x['name']: x['value'] for x in self.iter_values()} if self.values_count else None,
         'subkeys': {x['name'] for x in self.iter_subkeys()} if self.subkey_count else None,
         'timestamp': convert_wintime(self.header.last_modified, as_json=True),
         'volatile_subkeys': self.volatile_subkeys_count
     }
Example #11
0
 def run(self):
     uninstall_sk = self.registry_hive.get_key(INSTALLED_SOFTWARE_PATH)
     for installed_program in uninstall_sk.iter_subkeys():
         values = {
             x.name: x.value
             for x in installed_program.iter_values(as_json=self.as_json)
         } if installed_program.values_count else {}
         self.entries.append({
             'service_name':
             installed_program.name,
             'timestamp':
             convert_wintime(installed_program.header.last_modified,
                             as_json=self.as_json),
             **values
         })
Example #12
0
    def run(self):
        logger.info("Started BootKey Plugin...")

        for subkey_path in self.registry_hive.get_control_sets(LSA_KEY_PATH):
            lsa_key = self.registry_hive.get_key(subkey_path)

            bootkey = _descramble_bootkey(_collect_bootkey(lsa_key))

            self.entries.append({
                "key":
                bootkey.hex() if self.as_json else bootkey,
                'timestamp':
                convert_wintime(lsa_key.header.last_modified,
                                as_json=self.as_json)
            })
Example #13
0
    def run(self) -> None:
        logger.info("Started Boot Entry List Plugin...")

        objects_key = self.registry_hive.get_key(BCD_OBJECTS_PATH)

        for obj_key in objects_key.iter_subkeys():
            desc_key = obj_key.get_subkey("Description")
            # Object type defines the boot entry features
            desc_type = desc_key.get_value("Type")

            # The remaining boot entry attributes are stored as object elements
            desc_name = _get_element_by_type(obj_key, ELEM_TYPE_DESCRIPTION)
            path_name = _get_element_by_type(obj_key,
                                             ELEM_TYPE_APPLICATION_PATH)
            device_data = _get_element_by_type(obj_key,
                                               ELEM_TYPE_APPLICATION_DEVICE)

            # Filter out objects that do not look like boot entries
            if desc_name is None or path_name is None or device_data is None:
                continue

            # TODO: Figure out the device data blob format
            if not isinstance(device_data, bytes) or len(device_data) < 72:
                continue

            # TODO: Figure out how non-GPT partitions are encoded
            gpt_part_guid = str(uuid.UUID(bytes_le=device_data[32:48]))
            gpt_disk_guid = str(uuid.UUID(bytes_le=device_data[56:72]))

            entry_type = "0x%08X" % desc_type if self.as_json else desc_type

            self.entries.append({
                "guid":
                obj_key.name,
                "type":
                entry_type,
                "name":
                desc_name,
                "gpt_disk":
                gpt_disk_guid,
                "gpt_partition":
                gpt_part_guid,
                "image_path":
                path_name,
                "timestamp":
                convert_wintime(obj_key.header.last_modified,
                                as_json=self.as_json),
            })
    def run(self):
        logger.info('Started Computer Name Plugin...')

        for subkey_path in self.registry_hive.get_control_sets(
                COMPUTER_NAME_PATH):
            subkey = self.registry_hive.get_key(subkey_path)

            try:
                self.entries.append({
                    'name':
                    subkey.get_value('ComputerName', as_json=self.as_json),
                    'timestamp':
                    convert_wintime(subkey.header.last_modified,
                                    as_json=self.as_json)
                })
            except RegistryValueNotFoundException as ex:
                continue
Example #15
0
 def run(self):
     image_file_execution_options = self.registry_hive.get_key(
         IMAGE_FILE_EXECUTION_OPTIONS)
     if image_file_execution_options.subkey_count:
         for subkey in image_file_execution_options.iter_subkeys():
             values = {
                 x.name: x.value
                 for x in subkey.iter_values(as_json=self.as_json)
             } if subkey.values_count else {}
             self.entries.append({
                 'name':
                 subkey.name,
                 'timestamp':
                 convert_wintime(subkey.header.last_modified,
                                 as_json=self.as_json),
                 **values
             })
    def _get_installed_software(self, subkey_path):
        try:
            uninstall_sk = self.registry_hive.get_key(subkey_path)
        except RegistryKeyNotFoundException as ex:
            logger.error(ex)
            return

        for installed_program in uninstall_sk.iter_subkeys():
            values = {underscore(x.name): x.value for x in
                      installed_program.iter_values(as_json=self.as_json)} if installed_program.values_count else {}
            self.entries.append({
                'service_name': installed_program.name,
                'timestamp': convert_wintime(installed_program.header.last_modified, as_json=self.as_json),
                'registry_path': subkey_path,
                **values

            })
Example #17
0
    def run(self):
        logger.info('Started WDIGEST Plugin...')
        for subkey_path in self.registry_hive.get_control_sets(WDIGEST_PATH):
            subkey = self.registry_hive.get_key(subkey_path)

            try:
                self.entries.append({
                    'subkey':
                    subkey_path,
                    'use_logon_credential':
                    subkey.get_value('UseLogonCredential',
                                     as_json=self.as_json),
                    'timestamp':
                    convert_wintime(subkey.header.last_modified,
                                    as_json=self.as_json)
                })
            except RegistryValueNotFoundException as ex:
                continue
Example #18
0
    def run(self):
        logger.info('Started Host and Domain Name Plugin...')

        for subkey_path in self.registry_hive.get_control_sets(HOST_PARAMETERS_PATH):
            subkey = self.registry_hive.get_key(subkey_path)

            hostname = subkey.get_value('Hostname', as_json=self.as_json)
            domain = subkey.get_value('Domain', as_json=self.as_json)

            # The default key value is 0x00000000 (REG_DWORD) when
            # the Windows machine is not in an AD domain.
            if not isinstance(domain, str):
                domain = None

            self.entries.append({
                'hostname': hostname,
                'domain': domain,
                'timestamp': convert_wintime(subkey.header.last_modified, as_json=self.as_json)
            })
Example #19
0
    def run(self) -> None:
        logger.info("Started Machine Domain SID Plugin...")

        name_key = self.registry_hive.get_key(DOMAIN_NAME_PATH)

        # Primary Domain Name or Workgroup Name (binary-encoded and length-prefixed)
        name_value = name_key.get_value()

        # Skip UNICODE_STRING struct header and strip trailing \x0000
        domain_name = name_value[8:].decode('utf-16-le',
                                            errors='replace').rstrip('\x00')

        sid_key = self.registry_hive.get_key(DOMAIN_SID_PATH)

        # Domain SID value (binary-encoded)
        sid_value = sid_key.get_value()

        domain_sid: Optional[str] = None
        machine_sid: Optional[str] = None

        # The default key value is 0x00000000 (REG_DWORD) when
        # the Windows machine is not in an AD domain.
        # Otherwise, it contains the domain machine SID data
        # in the standard binary format (REG_BINARY).
        if isinstance(sid_value, bytes):
            parsed_sid = SID.parse(sid_value)
            domain_sid = convert_sid(parsed_sid, strip_rid=True)
            machine_sid = convert_sid(parsed_sid)

        self.entries.append({
            "domain_name":
            domain_name,
            "domain_sid":
            domain_sid,
            "machine_sid":
            machine_sid,
            "timestamp":
            convert_wintime(sid_key.header.last_modified,
                            as_json=self.as_json),
        })
Example #20
0
    def run(self) -> None:
        logger.info("Started Machine Local SID Plugin...")

        account_key = self.registry_hive.get_key(ACCOUNT_PATH)

        # A computer's SID is stored in the SECURITY hive
        # under 'SECURITY\SAM\Domains\Account'.
        # This key has a value named 'F' and a value named 'V'.
        v_value = account_key.get_value("V")

        # The 'V' value is a binary value that has the computer SID embedded
        # within it at the end of its data.
        sid_value = v_value[-24:]

        parsed_sid = SID.parse(sid_value)

        self.entries.append({
            "machine_sid":
            convert_sid(parsed_sid),
            "timestamp":
            convert_wintime(account_key.header.last_modified,
                            as_json=self.as_json),
        })
Example #21
0
    def run(self):
        logger.info('Started Computer Name Plugin...')

        try:
            for subkey_path in self.registry_hive.get_control_sets(BAM_PATH):
                subkey = self.registry_hive.get_key(subkey_path)
                for sid_subkey in subkey.iter_subkeys():

                    sid = sid_subkey.name
                    logger.info(f'Parsing BAM for {sid}')
                    sequence_number = None
                    version = None
                    entries = []

                    for value in sid_subkey.get_values():
                        if value.name == 'SequenceNumber':
                            sequence_number = value.value
                        elif value.name == 'Version':
                            version = value.value
                        else:
                            entries.append({
                                'executable':
                                value.name,
                                'timestamp':
                                convert_wintime(Int64ul.parse(value.value),
                                                as_json=self.as_json)
                            })

                    self.entries.extend([{
                        'sequence_number': sequence_number,
                        'version': version,
                        'sid': sid,
                        **x
                    } for x in entries])
        except RegistryKeyNotFoundException as ex:
            logger.error(ex)
Example #22
0
def get_timestamp_for_subkeys(registry_hive, subkey_list):
    for subkey_path in subkey_list:
        subkey = registry_hive.get_key(subkey_path)
        yield subkey_path, convert_wintime(subkey.header.last_modified, as_json=True)
Example #23
0
    def recurse_subkeys(self,
                        nk_record=None,
                        path=None,
                        as_json=False,
                        is_init=True):
        """
        Recurse over a subkey, and yield all of its subkeys and values
        :param nk_record: an instance of NKRecord from which to start iterating, if None, will start from Root
        :param path: The current registry path
        :param as_json: Whether to normalize the data as JSON or not
        """
        # If None, will start iterating from Root NK entry
        if not nk_record:
            nk_record = self.root

        # Iterate over subkeys
        if nk_record.header.subkey_count:
            for subkey in nk_record.iter_subkeys():
                if path:
                    subkey_path = r'{}\{}'.format(
                        path, subkey.name) if path else r'\{}'.format(
                            subkey.name)
                else:
                    subkey_path = f'\\{subkey.name}'

                # Leaf Index records do not contain subkeys
                if isinstance(subkey, LIRecord):
                    continue

                if subkey.subkey_count:
                    yield from self.recurse_subkeys(nk_record=subkey,
                                                    path=subkey_path,
                                                    as_json=as_json,
                                                    is_init=False)
                values = []
                if subkey.values_count:
                    try:
                        if as_json:
                            values = [
                                attr.asdict(x)
                                for x in subkey.iter_values(as_json=as_json)
                            ]
                        else:
                            values = list(subkey.iter_values(as_json=as_json))
                    except RegistryParsingException as ex:
                        logger.exception(
                            f'Failed to parse hive value at path: {path}')
                        values = []

                ts = convert_wintime(subkey.header.last_modified)
                yield Subkey(
                    subkey_name=subkey.name,
                    path=subkey_path,
                    timestamp=ts.isoformat() if as_json else ts,
                    values=values,
                    values_count=len(values),
                    actual_path=f'{self.partial_hive_path}{subkey_path}'
                    if self.partial_hive_path else None)

        if is_init:
            # Get the values of the subkey
            values = []
            if nk_record.values_count:
                try:
                    if as_json:
                        values = [
                            attr.asdict(x)
                            for x in nk_record.iter_values(as_json=as_json)
                        ]
                    else:
                        values = list(nk_record.iter_values(as_json=as_json))
                except RegistryParsingException as ex:
                    logger.exception(
                        f'Failed to parse hive value at path: {path}')
                    values = []

            ts = convert_wintime(nk_record.header.last_modified)
            subkey_path = path or '\\'
            yield Subkey(subkey_name=nk_record.name,
                         path=subkey_path,
                         timestamp=ts.isoformat() if as_json else ts,
                         values=values,
                         values_count=len(values),
                         actual_path=f'{self.partial_hive_path}\\{subkey_path}'
                         if self.partial_hive_path else None)