예제 #1
0
  def testRuleDeviceConnection(self):
    """Tests the device_connection tagging rule."""
    event = events.EventObject()
    event.timestamp = self._TEST_TIMESTAMP
    event.timestamp_desc = definitions.TIME_DESCRIPTION_UNKNOWN

    event_data = ipod.IPodPlistEventData()

    storage_writer = self._TagEvent(event, event_data)

    self.assertEqual(storage_writer.number_of_event_tags, 1)
    self._CheckLabels(storage_writer, ['device_connection'])

    event_data = plist_event.PlistTimeEventData()
    event_data.plugin = 'bogus'

    storage_writer = self._TagEvent(event, event_data)

    self.assertEqual(storage_writer.number_of_event_tags, 0)
    self._CheckLabels(storage_writer, [])

    event_data = plist_event.PlistTimeEventData()
    event_data.plugin = 'plist_airport'

    storage_writer = self._TagEvent(event, event_data)

    self.assertEqual(storage_writer.number_of_event_tags, 1)
    self._CheckLabels(storage_writer, ['device_connection'])
예제 #2
0
    def GetEntries(self, parser_mediator, match=None, **unused_kwargs):
        """Extracts relevant Volume Configuration Spotlight entries.

    Args:
      parser_mediator (ParserMediator): mediates interactions between parsers
          and other components, such as storage and dfvfs.
      match (Optional[dict[str: object]]): keys extracted from PLIST_KEYS.
    """
        stores = match.get('Stores', {})
        for volume_name, volume in iter(stores.items()):
            datetime_value = volume.get('CreationDate', None)
            if not datetime_value:
                continue

            partial_path = volume['PartialPath']

            event_data = plist_event.PlistTimeEventData()
            event_data.desc = 'Spotlight Volume {0:s} ({1:s}) activated.'.format(
                volume_name, partial_path)
            event_data.key = ''
            event_data.root = '/Stores'

            event = time_events.PythonDatetimeEvent(
                datetime_value, definitions.TIME_DESCRIPTION_WRITTEN)
            parser_mediator.ProduceEventWithEventData(event, event_data)
예제 #3
0
    def GetEntries(self, parser_mediator, match=None, **unused_kwargs):
        """Extracts relevant Airport entries.

    Args:
      parser_mediator (ParserMediator): mediates interactions between parsers
          and other components, such as storage and dfvfs.
      match (Optional[dict[str: object]]): keys extracted from PLIST_KEYS.
    """
        if 'RememberedNetworks' not in match:
            return

        for wifi in match['RememberedNetworks']:
            ssid = wifi.get('SSIDString', 'UNKNOWN_SSID')
            security_type = wifi.get('SecurityType', 'UNKNOWN_SECURITY_TYPE')

            event_data = plist_event.PlistTimeEventData()
            event_data.desc = (
                '[WiFi] Connected to network: <{0:s}> using security {1:s}'
            ).format(ssid, security_type)
            event_data.key = 'item'
            event_data.root = '/RememberedNetworks'

            datetime_value = wifi.get('LastConnected', None)
            if datetime_value:
                event = time_events.PythonDatetimeEvent(
                    datetime_value, definitions.TIME_DESCRIPTION_WRITTEN)

            else:
                date_time = dfdatetime_semantic_time.SemanticTime('Not set')
                event = time_events.DateTimeValuesEvent(
                    date_time, definitions.TIME_DESCRIPTION_NOT_A_TIME)

            parser_mediator.ProduceEventWithEventData(event, event_data)
예제 #4
0
    def GetEntries(self, parser_mediator, match=None, **unused_kwargs):
        """Extracts relevant TimeMachine entries.

    Args:
      parser_mediator (ParserMediator): mediates interactions between parsers
          and other components, such as storage and dfvfs.
      match (Optional[dict[str: object]]): keys extracted from PLIST_KEYS.
    """
        destinations = match.get('Destinations', [])
        for destination in destinations:
            destination_identifier = (destination.get('DestinationID', None)
                                      or 'Unknown device')

            alias = destination.get('BackupAlias', '<ALIAS>')
            try:
                alias = self.TM_BACKUP_ALIAS.parse(alias).value
                alias = codecs.decode(alias, 'utf-8')
            except construct.FieldError:
                alias = 'Unknown alias'

            event_data = plist_event.PlistTimeEventData()
            event_data.desc = 'TimeMachine Backup in {0:s} ({1:s})'.format(
                alias, destination_identifier)
            event_data.key = 'item/SnapshotDates'
            event_data.root = '/Destinations'

            snapshot_dates = destination.get('SnapshotDates', [])
            for datetime_value in snapshot_dates:
                event = time_events.PythonDatetimeEvent(
                    datetime_value, definitions.TIME_DESCRIPTION_WRITTEN)
                parser_mediator.ProduceEventWithEventData(event, event_data)
예제 #5
0
    def GetEntries(self, parser_mediator, match=None, **unused_kwargs):
        """Extracts relevant Spotlight entries.

    Args:
      parser_mediator (ParserMediator): mediates interactions between parsers
          and other components, such as storage and dfvfs.
      match (Optional[dict[str: object]]): keys extracted from PLIST_KEYS.
    """
        shortcuts = match.get('UserShortcuts', {})
        for search_text, data in iter(shortcuts.items()):
            datetime_value = data.get('LAST_USED', None)
            if not datetime_value:
                continue

            display_name = data.get('DISPLAY_NAME', '<DISPLAY_NAME>')
            path = data.get('PATH', '<PATH>')

            event_data = plist_event.PlistTimeEventData()
            event_data.desc = (
                'Spotlight term searched "{0:s}" associate to {1:s} ({2:s})'
            ).format(search_text, display_name, path)
            event_data.key = search_text
            event_data.root = '/UserShortcuts'

            timestamp = timelib.Timestamp.FromPythonDatetime(datetime_value)
            date_time = dfdatetime_posix_time.PosixTimeInMicroseconds(
                timestamp=timestamp)
            event = time_events.DateTimeValuesEvent(
                date_time, definitions.TIME_DESCRIPTION_WRITTEN)
            parser_mediator.ProduceEventWithEventData(event, event_data)
예제 #6
0
    def GetEntries(self, parser_mediator, top_level=None, **unused_kwargs):
        """Extracts relevant install history entries.

    Args:
      parser_mediator (ParserMediator): mediates interactions between parsers
          and other components, such as storage and dfvfs.
      top_level (dict[str, object]): plist top-level key.
    """
        for entry in top_level:
            datetime_value = entry.get('date', None)
            package_identifiers = entry.get('packageIdentifiers', [])

            if not datetime_value or not package_identifiers:
                continue

            display_name = entry.get('displayName', '<UNKNOWN>')
            display_version = entry.get('displayVersion', '<DISPLAY_VERSION>')
            process_name = entry.get('processName', '<PROCESS_NAME>')
            package_identifiers = ', '.join(package_identifiers)

            event_data = plist_event.PlistTimeEventData()
            event_data.desc = (
                'Installation of [{0:s} {1:s}] using [{2:s}]. Packages: '
                '{3:s}.').format(display_name, display_version, process_name,
                                 package_identifiers)
            event_data.key = ''
            event_data.root = '/item'

            event = time_events.PythonDatetimeEvent(
                datetime_value, definitions.TIME_DESCRIPTION_WRITTEN)
            parser_mediator.ProduceEventWithEventData(event, event_data)
예제 #7
0
파일: launchd.py 프로젝트: tomchop/plaso
  def GetEntries(self, parser_mediator, top_level=None, **unused_kwargs):
    """Extracts launchd information from the plist.

    Args:
      parser_mediator (ParserMediator): mediates interactions between parsers
        and other components, such as storage and dfvfs.
      top_level (Optional[dict[str, object]]): plist top-level item.
    """

    label = top_level.get('Label')
    command = top_level.get('Program', '')
    program_arguments = top_level.get('ProgramArguments')
    for argument in program_arguments:
      command += " %s" % argument

    user_name = top_level.get('UserName')
    group_name = top_level.get('GroupName')

    event_data = plist_event.PlistTimeEventData()
    event_data.desc = ('Launchd service config {0:s} points to {1:s} with '
                       'user:{2:s} group:{3:s}').format(label, command,
                                                        user_name, group_name)
    event_data.key = 'launchdServiceConfig'
    event_data.root = '/'

    date_time = dfdatetime_semantic_time.NotSet()
    event = time_events.DateTimeValuesEvent(
        date_time, definitions.TIME_DESCRIPTION_NOT_A_TIME)

    parser_mediator.ProduceEventWithEventData(event, event_data)
예제 #8
0
    def GetEntries(self, parser_mediator, match=None, **unused_kwargs):
        """Extracts relevant Apple Account entries.

    Args:
      parser_mediator (ParserMediator): mediates interactions between parsers
          and other components, such as storage and dfvfs.
      match (Optional[dict[str: object]]): keys extracted from PLIST_KEYS.
    """
        accounts = match.get('Accounts', {})
        for name_account, account in iter(accounts.items()):
            first_name = account.get('FirstName', '<FirstName>')
            last_name = account.get('LastName', '<LastName>')
            general_description = '{0:s} ({1:s} {2:s})'.format(
                name_account, first_name, last_name)

            event_data = plist_event.PlistTimeEventData()
            event_data.key = name_account
            event_data.root = '/Accounts'

            datetime_value = account.get('CreationDate', None)
            if datetime_value:
                event_data.desc = 'Configured Apple account {0:s}'.format(
                    general_description)

                timestamp = timelib.Timestamp.FromPythonDatetime(
                    datetime_value)
                date_time = dfdatetime_posix_time.PosixTimeInMicroseconds(
                    timestamp=timestamp)
                event = time_events.DateTimeValuesEvent(
                    date_time, definitions.TIME_DESCRIPTION_WRITTEN)
                parser_mediator.ProduceEventWithEventData(event, event_data)

            datetime_value = account.get('LastSuccessfulConnect', None)
            if datetime_value:
                event_data.desc = 'Connected Apple account {0:s}'.format(
                    general_description)

                timestamp = timelib.Timestamp.FromPythonDatetime(
                    datetime_value)
                date_time = dfdatetime_posix_time.PosixTimeInMicroseconds(
                    timestamp=timestamp)
                event = time_events.DateTimeValuesEvent(
                    date_time, definitions.TIME_DESCRIPTION_WRITTEN)
                parser_mediator.ProduceEventWithEventData(event, event_data)

            datetime_value = account.get('ValidationDate', None)
            if datetime_value:
                event_data.desc = 'Last validation Apple account {0:s}'.format(
                    general_description)

                timestamp = timelib.Timestamp.FromPythonDatetime(
                    datetime_value)
                date_time = dfdatetime_posix_time.PosixTimeInMicroseconds(
                    timestamp=timestamp)
                event = time_events.DateTimeValuesEvent(
                    date_time, definitions.TIME_DESCRIPTION_WRITTEN)
                parser_mediator.ProduceEventWithEventData(event, event_data)
예제 #9
0
파일: bluetooth.py 프로젝트: yehias/plaso
    def GetEntries(self, parser_mediator, match=None, **unused_kwargs):
        """Extracts relevant BT entries.

    Args:
      parser_mediator (ParserMediator): mediates interactions between parsers
          and other components, such as storage and dfvfs.
      match (Optional[dict[str: object]]): keys extracted from PLIST_KEYS.
    """
        device_cache = match.get('DeviceCache', {})
        for device, value in iter(device_cache.items()):
            name = value.get('Name', '')
            if name:
                name = ''.join(('Name:', name))

            event_data = plist_event.PlistTimeEventData()
            event_data.root = '/DeviceCache'

            datetime_value = value.get('LastInquiryUpdate', None)
            if datetime_value:
                event_data.desc = ' '.join(
                    filter(None, ('Bluetooth Discovery', name)))
                event_data.key = '{0:s}/LastInquiryUpdate'.format(device)

                event = time_events.PythonDatetimeEvent(
                    datetime_value, definitions.TIME_DESCRIPTION_WRITTEN)
                parser_mediator.ProduceEventWithEventData(event, event_data)

                if device in match.get('PairedDevices', []):
                    event_data.desc = 'Paired:True {0:s}'.format(name)
                    event_data.key = device

                    event = time_events.PythonDatetimeEvent(
                        datetime_value, definitions.TIME_DESCRIPTION_WRITTEN)
                    parser_mediator.ProduceEventWithEventData(
                        event, event_data)

            datetime_value = value.get('LastNameUpdate', None)
            if datetime_value:
                event_data.desc = ' '.join(
                    filter(None, ('Device Name Set', name)))
                event_data.key = '{0:s}/LastNameUpdate'.format(device)

                event = time_events.PythonDatetimeEvent(
                    datetime_value, definitions.TIME_DESCRIPTION_WRITTEN)
                parser_mediator.ProduceEventWithEventData(event, event_data)

            datetime_value = value.get('LastServicesUpdate', None)
            if datetime_value:
                event_data.desc = ' '.join(
                    filter(None, ('Services Updated', name)))
                event_data.key = '{0:s}/LastServicesUpdate'.format(device)

                event = time_events.PythonDatetimeEvent(
                    datetime_value, definitions.TIME_DESCRIPTION_WRITTEN)
                parser_mediator.ProduceEventWithEventData(event, event_data)
예제 #10
0
파일: plist_event.py 프로젝트: x35029/plaso
  def testGetAttributeNames(self):
    """Tests the GetAttributeNames function."""
    attribute_container = plist_event.PlistTimeEventData()

    expected_attribute_names = [
        'data_type', 'desc', 'hostname', 'key', 'offset', 'query',
        'root', 'username']

    attribute_names = sorted(attribute_container.GetAttributeNames())

    self.assertEqual(attribute_names, expected_attribute_names)
예제 #11
0
  def testRuleApplicationInstall(self):
    """Tests the application_install tagging rule."""
    event = events.EventObject()
    event.timestamp = self._TEST_TIMESTAMP
    event.timestamp_desc = definitions.TIME_DESCRIPTION_UNKNOWN

    event_data = plist_event.PlistTimeEventData()
    event_data.plugin = 'bogus'

    storage_writer = self._TagEvent(event, event_data)

    self.assertEqual(storage_writer.number_of_event_tags, 0)
    self._CheckLabels(storage_writer, [])

    event_data = plist_event.PlistTimeEventData()
    event_data.plugin = 'plist_install_history'

    storage_writer = self._TagEvent(event, event_data)

    self.assertEqual(storage_writer.number_of_event_tags, 1)
    self._CheckLabels(storage_writer, ['application_install'])
예제 #12
0
    def GetEntries(self, parser_mediator, match=None, **unused_kwargs):
        """Extracts relevant Mac OS X update entries.

    Args:
      parser_mediator (ParserMediator): mediates interactions between parsers
          and other components, such as storage and dfvfs.
      match (Optional[dict[str: object]]): keys extracted from PLIST_KEYS.
    """
        version = match.get(u'LastAttemptSystemVersion', u'N/A')
        pending = match.get(u'LastUpdatesAvailable', None)

        event_data = plist_event.PlistTimeEventData()
        event_data.desc = u'Last Mac OS X {0:s} full update.'.format(version)
        event_data.key = u''
        event_data.root = u'/'

        datetime_value = match.get(u'LastFullSuccessfulDate', None)
        if datetime_value:
            timestamp = timelib.Timestamp.FromPythonDatetime(datetime_value)
            date_time = dfdatetime_posix_time.PosixTimeInMicroseconds(
                timestamp=timestamp)
            event = time_events.DateTimeValuesEvent(
                date_time, definitions.TIME_DESCRIPTION_WRITTEN)
            parser_mediator.ProduceEventWithEventData(event, event_data)

        datetime_value = match.get(u'LastSuccessfulDate', None)
        if datetime_value and pending:
            software = []
            for update in match.get(u'RecommendedUpdates', []):
                identifier = update.get(u'Identifier', u'<IDENTIFIER>')
                product_key = update.get(u'Product Key', u'<PRODUCT_KEY>')

                software.append(u'{0:s}({1:s})'.format(identifier,
                                                       product_key))

            if not software:
                return

            software = u','.join(software)
            event_data.desc = (
                u'Last Mac OS {0!s} partially update, pending {1!s}: '
                u'{2:s}.').format(version, pending, software)

            timestamp = timelib.Timestamp.FromPythonDatetime(datetime_value)
            date_time = dfdatetime_posix_time.PosixTimeInMicroseconds(
                timestamp=timestamp)
            event = time_events.DateTimeValuesEvent(
                date_time, definitions.TIME_DESCRIPTION_WRITTEN)
            parser_mediator.ProduceEventWithEventData(event, event_data)
예제 #13
0
    def GetEntries(self, parser_mediator, **unused_kwargs):
        """Extracts entries for testing.

    Args:
      parser_mediator (ParserMediator): mediates interactions between parsers
          and other components, such as storage and dfvfs.
    """
        event_data = plist_event.PlistTimeEventData()
        event_data.key = 'LastInquiryUpdate'
        event_data.root = '/DeviceCache/44-00-00-00-00-00'

        date_time = dfdatetime_posix_time.PosixTimeInMicroseconds(
            timestamp=1351827808261762)
        event = time_events.DateTimeValuesEvent(
            date_time, definitions.TIME_DESCRIPTION_WRITTEN)
        parser_mediator.ProduceEventWithEventData(event, event_data)
예제 #14
0
파일: default.py 프로젝트: no-sec/plaso
    def GetEntries(self, parser_mediator, top_level=None, **unused_kwargs):
        """Simple method to exact date values from a Plist.

    Args:
      parser_mediator (ParserMediator): mediates interactions between parsers
          and other components, such as storage and dfvfs.
      top_level (dict[str, object]): plist top-level key.
    """
        for root, key, datetime_value in interface.RecurseKey(top_level):
            if not isinstance(datetime_value, datetime.datetime):
                continue

            event_data = plist_event.PlistTimeEventData()
            event_data.key = key
            event_data.root = root

            event = time_events.PythonDatetimeEvent(
                datetime_value, definitions.TIME_DESCRIPTION_WRITTEN)
            parser_mediator.ProduceEventWithEventData(event, event_data)
예제 #15
0
    def GetEntries(self, parser_mediator, match=None, **unused_kwargs):
        """Extracts relevant TimeMachine entries.

    Args:
      parser_mediator (ParserMediator): mediates interactions between parsers
          and other components, such as storage and dfvfs.
      match (Optional[dict[str: object]]): keys extracted from PLIST_KEYS.
    """
        backup_alias_map = self._GetDataTypeMap('timemachine_backup_alias')

        destinations = match.get('Destinations', [])
        for destination in destinations:
            backup_alias_data = destination.get('BackupAlias', b'')
            try:
                backup_alias = self._ReadStructureFromByteStream(
                    backup_alias_data, 0, backup_alias_map)
                alias = backup_alias.string

            except (ValueError, errors.ParseError) as exception:
                parser_mediator.ProduceExtractionWarning(
                    'unable to parse backup alias value with error: {0!s}'.
                    format(exception))
                alias = 'Unknown alias'

            destination_identifier = (destination.get('DestinationID', None)
                                      or 'Unknown device')

            event_data = plist_event.PlistTimeEventData()
            event_data.desc = 'TimeMachine Backup in {0:s} ({1:s})'.format(
                alias, destination_identifier)
            event_data.key = 'item/SnapshotDates'
            event_data.root = '/Destinations'

            snapshot_dates = destination.get('SnapshotDates', [])
            for datetime_value in snapshot_dates:
                date_time = dfdatetime_time_elements.TimeElementsInMicroseconds(
                )
                date_time.CopyFromDatetime(datetime_value)

                event = time_events.DateTimeValuesEvent(
                    date_time, definitions.TIME_DESCRIPTION_WRITTEN)
                parser_mediator.ProduceEventWithEventData(event, event_data)
예제 #16
0
파일: default.py 프로젝트: dfjxs/plaso
  def _ParsePlist(self, parser_mediator, top_level=None, **unused_kwargs):
    """Extracts events from the values of entries within a plist.

    Args:
      parser_mediator (ParserMediator): mediates interactions between parsers
          and other components, such as storage and dfvfs.
      top_level (Optional[dict[str, object]]): plist top-level item.
    """
    for root, key, datetime_value in self._RecurseKey(top_level):
      if not isinstance(datetime_value, datetime.datetime):
        continue

      event_data = plist_event.PlistTimeEventData()
      event_data.key = key
      event_data.root = root

      date_time = dfdatetime_time_elements.TimeElementsInMicroseconds()
      date_time.CopyFromDatetime(datetime_value)

      event = time_events.DateTimeValuesEvent(
          date_time, definitions.TIME_DESCRIPTION_WRITTEN)
      parser_mediator.ProduceEventWithEventData(event, event_data)
예제 #17
0
    def GetEntries(self, parser_mediator, match=None, **unused_kwargs):
        """Extracts relevant user timestamp entries.

    Args:
      parser_mediator (ParserMediator): mediates interactions between parsers
          and other components, such as storage and dfvfs.
      match (Optional[dict[str: object]]): keys extracted from PLIST_KEYS.
    """
        if 'name' not in match or 'uid' not in match:
            return

        account = match['name'][0]
        uid = match['uid'][0]

        for policy in match.get('passwordpolicyoptions', []):
            try:
                xml_policy = ElementTree.fromstring(policy)
            except (ElementTree.ParseError, LookupError) as exception:
                logger.error((
                    'Unable to parse XML structure for an user policy, account: '
                    '{0:s} and uid: {1!s}, with error: {2!s}').format(
                        account, uid, exception))
                continue

            for dict_elements in xml_policy.iterfind('dict'):
                key_values = [value.text for value in iter(dict_elements)]
                # Taking a list and converting it to a dict, using every other item
                # as the key and the other one as the value.
                policy_dict = dict(zip(key_values[0::2], key_values[1::2]))

            time_string = policy_dict.get('passwordLastSetTime', None)
            if time_string and time_string != '2001-01-01T00:00:00Z':
                try:
                    date_time = dfdatetime_time_elements.TimeElements()
                    date_time.CopyFromStringISO8601(time_string)
                except ValueError:
                    date_time = None
                    parser_mediator.ProduceExtractionWarning(
                        'unable to parse password last set time string: {0:s}'.
                        format(time_string))

                shadow_hash_data = match.get('ShadowHashData', None)
                if date_time and isinstance(shadow_hash_data, (list, tuple)):
                    # Extract the hash password information.
                    # It is store in the attribute ShadowHasData which is
                    # a binary plist data; However biplist only extracts one
                    # level of binary plist, then it returns this information
                    # as a string.

                    # TODO: change this into a DataRange instead. For this we
                    # need the file offset and size of the ShadowHashData value data.
                    shadow_hash_data = shadow_hash_data[0]

                    resolver_context = context.Context()
                    fake_file = fake_file_io.FakeFile(resolver_context,
                                                      shadow_hash_data)
                    shadow_hash_data_path_spec = fake_path_spec.FakePathSpec(
                        location='ShadowHashData')
                    fake_file.open(path_spec=shadow_hash_data_path_spec)

                    try:
                        plist_file = biplist.readPlist(fake_file)
                    except biplist.InvalidPlistException:
                        plist_file = {}
                    salted_hash = plist_file.get('SALTED-SHA512-PBKDF2', None)
                    if salted_hash:
                        salt_hex_bytes = codecs.encode(salted_hash['salt'],
                                                       'hex')
                        salt_string = codecs.decode(salt_hex_bytes, 'ascii')
                        entropy_hex_bytes = codecs.encode(
                            salted_hash['entropy'], 'hex')
                        entropy_string = codecs.decode(entropy_hex_bytes,
                                                       'ascii')
                        password_hash = '$ml${0:d}${1:s}${2:s}'.format(
                            salted_hash['iterations'], salt_string,
                            entropy_string)
                    else:
                        password_hash = 'N/A'

                    event_data = plist_event.PlistTimeEventData()
                    event_data.desc = (
                        'Last time {0:s} ({1!s}) changed the password: {2!s}'
                    ).format(account, uid, password_hash)
                    event_data.key = 'passwordLastSetTime'
                    event_data.root = self._ROOT

                    event = time_events.DateTimeValuesEvent(
                        date_time, definitions.TIME_DESCRIPTION_WRITTEN)
                    parser_mediator.ProduceEventWithEventData(
                        event, event_data)

            time_string = policy_dict.get('lastLoginTimestamp', None)
            if time_string and time_string != '2001-01-01T00:00:00Z':
                try:
                    date_time = dfdatetime_time_elements.TimeElements()
                    date_time.CopyFromStringISO8601(time_string)
                except ValueError:
                    date_time = None
                    parser_mediator.ProduceExtractionWarning(
                        'unable to parse last login time string: {0:s}'.format(
                            time_string))

                if date_time:
                    event_data = plist_event.PlistTimeEventData()
                    event_data.desc = 'Last login from {0:s} ({1!s})'.format(
                        account, uid)
                    event_data.key = 'lastLoginTimestamp'
                    event_data.root = self._ROOT

                    event = time_events.DateTimeValuesEvent(
                        date_time, definitions.TIME_DESCRIPTION_WRITTEN)
                    parser_mediator.ProduceEventWithEventData(
                        event, event_data)

            time_string = policy_dict.get('failedLoginTimestamp', None)
            if time_string and time_string != '2001-01-01T00:00:00Z':
                try:
                    date_time = dfdatetime_time_elements.TimeElements()
                    date_time.CopyFromStringISO8601(time_string)
                except ValueError:
                    date_time = None
                    parser_mediator.ProduceExtractionWarning(
                        'unable to parse failed login time string: {0:s}'.
                        format(time_string))

                if date_time:
                    event_data = plist_event.PlistTimeEventData()
                    event_data.desc = (
                        'Last failed login from {0:s} ({1!s}) ({2!s} times)'
                    ).format(account, uid,
                             policy_dict.get('failedLoginCount', 0))
                    event_data.key = 'failedLoginTimestamp'
                    event_data.root = self._ROOT

                    event = time_events.DateTimeValuesEvent(
                        date_time, definitions.TIME_DESCRIPTION_WRITTEN)
                    parser_mediator.ProduceEventWithEventData(
                        event, event_data)
예제 #18
0
  def _ParsePlist(self, parser_mediator, match=None, **unused_kwargs):
    """Extracts relevant user timestamp entries.

    Args:
      parser_mediator (ParserMediator): mediates interactions between parsers
          and other components, such as storage and dfvfs.
      match (Optional[dict[str: object]]): keys extracted from PLIST_KEYS.
    """
    if 'name' not in match or 'uid' not in match:
      return

    account = match['name'][0]
    uid = match['uid'][0]

    for policy in match.get('passwordpolicyoptions', []):
      try:
        xml_policy = ElementTree.fromstring(policy)
      except (LookupError, ElementTree.ParseError,
              expat.ExpatError) as exception:
        logger.error((
            'Unable to parse XML structure for an user policy, account: '
            '{0:s} and uid: {1!s}, with error: {2!s}').format(
                account, uid, exception))
        continue

      for dict_elements in xml_policy.iterfind('dict'):
        key_values = [value.text for value in dict_elements]
        # Taking a list and converting it to a dict, using every other item
        # as the key and the other one as the value.
        policy_dict = dict(zip(key_values[0::2], key_values[1::2]))

      time_string = policy_dict.get('passwordLastSetTime', None)
      if time_string and time_string != '2001-01-01T00:00:00Z':
        try:
          date_time = dfdatetime_time_elements.TimeElements()
          date_time.CopyFromStringISO8601(time_string)
        except ValueError:
          date_time = None
          parser_mediator.ProduceExtractionWarning(
              'unable to parse password last set time string: {0:s}'.format(
                  time_string))

        shadow_hash_data = match.get('ShadowHashData', None)
        if date_time and isinstance(shadow_hash_data, (list, tuple)):
          # Extract the hash password information, which is stored in
          # the attribute ShadowHashData which is a binary plist data.
          try:
            property_list = plistlib.loads(shadow_hash_data[0])
          except plistlib.InvalidFileException as exception:
            parser_mediator.ProduceExtractionWarning(
                'unable to parse ShadowHashData with error: {0!s}'.format(
                    exception))
            property_list = {}

          password_hash = 'N/A'

          salted_hash = property_list.get('SALTED-SHA512-PBKDF2', None)
          if salted_hash:
            salt_hex_bytes = codecs.encode(salted_hash['salt'], 'hex')
            salt_string = codecs.decode(salt_hex_bytes, 'ascii')
            entropy_hex_bytes = codecs.encode(salted_hash['entropy'], 'hex')
            entropy_string = codecs.decode(entropy_hex_bytes, 'ascii')
            password_hash = '$ml${0:d}${1:s}${2:s}'.format(
                salted_hash['iterations'], salt_string, entropy_string)

          event_data = plist_event.PlistTimeEventData()
          event_data.desc = (
              'Last time {0:s} ({1!s}) changed the password: {2!s}').format(
                  account, uid, password_hash)
          event_data.key = 'passwordLastSetTime'
          event_data.root = self._ROOT

          event = time_events.DateTimeValuesEvent(
              date_time, definitions.TIME_DESCRIPTION_WRITTEN)
          parser_mediator.ProduceEventWithEventData(event, event_data)

      time_string = policy_dict.get('lastLoginTimestamp', None)
      if time_string and time_string != '2001-01-01T00:00:00Z':
        try:
          date_time = dfdatetime_time_elements.TimeElements()
          date_time.CopyFromStringISO8601(time_string)
        except ValueError:
          date_time = None
          parser_mediator.ProduceExtractionWarning(
              'unable to parse last login time string: {0:s}'.format(
                  time_string))

        if date_time:
          event_data = plist_event.PlistTimeEventData()
          event_data.desc = 'Last login from {0:s} ({1!s})'.format(
              account, uid)
          event_data.key = 'lastLoginTimestamp'
          event_data.root = self._ROOT

          event = time_events.DateTimeValuesEvent(
              date_time, definitions.TIME_DESCRIPTION_WRITTEN)
          parser_mediator.ProduceEventWithEventData(event, event_data)

      time_string = policy_dict.get('failedLoginTimestamp', None)
      if time_string and time_string != '2001-01-01T00:00:00Z':
        try:
          date_time = dfdatetime_time_elements.TimeElements()
          date_time.CopyFromStringISO8601(time_string)
        except ValueError:
          date_time = None
          parser_mediator.ProduceExtractionWarning(
              'unable to parse failed login time string: {0:s}'.format(
                  time_string))

        if date_time:
          event_data = plist_event.PlistTimeEventData()
          event_data.desc = (
              'Last failed login from {0:s} ({1!s}) ({2!s} times)').format(
                  account, uid, policy_dict.get('failedLoginCount', 0))
          event_data.key = 'failedLoginTimestamp'
          event_data.root = self._ROOT

          event = time_events.DateTimeValuesEvent(
              date_time, definitions.TIME_DESCRIPTION_WRITTEN)
          parser_mediator.ProduceEventWithEventData(event, event_data)