Exemple #1
0
  def GetEntries(self, match, **unused_kwargs):
    """Extracts relevant user timestamp entries.

    Args:
      match: A dictionary containing keys extracted from PLIST_KEYS.

    Yields:
      EventObject objects extracted from the plist.
    """
    root = '/'
    account = match['name'][0]
    uid = match['uid'][0]
    cocoa_zero = (
        timelib.Timestamp.COCOA_TIME_TO_POSIX_BASE *
        timelib.Timestamp.MICRO_SECONDS_PER_SECOND)
    # INFO: binplist return a string with the Plist XML.
    for policy in match['passwordpolicyoptions']:
      xml_policy = ElementTree.fromstring(policy)
      for dict_elements in xml_policy.iterfind('dict'):
        key_values = [value.text for value in dict_elements.getchildren()]
        policy_dict = dict(zip(key_values[0::2], key_values[1::2]))

      if policy_dict.get('passwordLastSetTime', 0):
        timestamp = timelib.Timestamp.FromTimeString(
             policy_dict.get('passwordLastSetTime', '0'))
        if timestamp > cocoa_zero:
          # Extract the hash password information.
          # It is store in the attribure ShadowHasData which is
          # a binary plist data; However binplist only extract one
          # level of binary plist, then it returns this information
          # as a string.
          fake_file = interface.FakeFile(match['ShadowHashData'][0])
          try:
            plist_file = binplist.BinaryPlist(file_obj=fake_file)
            top_level = plist_file.Parse()
          except binplist.FormatError:
            top_level = dict()
          salted_hash = top_level.get('SALTED-SHA512-PBKDF2', None)
          if salted_hash:
            password_hash = u'$ml${}${}${}'.format(
                salted_hash['iterations'],
                binascii.hexlify(salted_hash['salt']),
                binascii.hexlify(salted_hash['entropy']))
          else:
            password_hash = u'N/A'
          description = u'Last time {} ({}) changed the password: {}'.format(
              account, uid, password_hash)
          yield plist_event.PlistTimeEvent(
              root, u'passwordLastSetTime', timestamp, description)

      if policy_dict.get('lastLoginTimestamp', 0):
        timestamp = timelib.Timestamp.FromTimeString(
             policy_dict.get('lastLoginTimestamp', '0'))
        description = u'Last login from {} ({})'.format(
            account, uid)
        if timestamp > cocoa_zero:
          yield plist_event.PlistTimeEvent(
              root, u'lastLoginTimestamp', timestamp, description)

      if policy_dict.get('failedLoginTimestamp', 0):
        timestamp = timelib.Timestamp.FromTimeString(
             policy_dict.get('failedLoginTimestamp', '0'))
        description = u'Last failed login from {} ({}) ({} times)'.format(
            account, uid, policy_dict['failedLoginCount'])
        if timestamp > cocoa_zero:
          yield plist_event.PlistTimeEvent(
              root, u'failedLoginTimestamp', timestamp, description)
Exemple #2
0
    def GetEntries(self, parser_mediator, match=None, **unused_kwargs):
        """Extracts relevant user timestamp entries.

    Args:
      parser_mediator: A parser mediator object (instance of ParserMediator).
      match: Optional dictionary containing keys extracted from PLIST_KEYS.
             The default is None.
    """
        if u'name' not in match or u'uid' not in match:
            return

        account = match[u'name'][0]
        uid = match[u'uid'][0]
        cocoa_zero = (timelib.Timestamp.COCOA_TIME_TO_POSIX_BASE *
                      timelib.Timestamp.MICRO_SECONDS_PER_SECOND)

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

            for dict_elements in xml_policy.iterfind(u'dict'):
                key_values = [
                    value.text for value in dict_elements.getchildren()
                ]
                # 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(u'passwordLastSetTime', None)
            if time_string:
                try:
                    timestamp = timelib.Timestamp.FromTimeString(time_string)
                except errors.TimestampError:
                    parser_mediator.ProduceParseError(
                        u'Unable to parse time string: {0:s}'.format(
                            time_string))
                    timestamp = 0

                shadow_hash_data = match.get(u'ShadowHashData', None)
                if timestamp > cocoa_zero 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 binplist only extract 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)
                    fake_file.open(path_spec=fake_path_spec.FakePathSpec(
                        location=u'ShadowHashData'))

                    try:
                        plist_file = binplist.BinaryPlist(file_obj=fake_file)
                        top_level = plist_file.Parse()
                    except binplist.FormatError:
                        top_level = dict()
                    salted_hash = top_level.get(u'SALTED-SHA512-PBKDF2', None)
                    if salted_hash:
                        password_hash = u'$ml${0:d}${1:s}${2:s}'.format(
                            salted_hash[u'iterations'],
                            binascii.hexlify(salted_hash[u'salt']),
                            binascii.hexlify(salted_hash[u'entropy']))
                    else:
                        password_hash = u'N/A'
                    description = (
                        u'Last time {0:s} ({1!s}) changed the password: {2!s}'
                    ).format(account, uid, password_hash)
                    event_object = plist_event.PlistTimeEvent(
                        self._ROOT, u'passwordLastSetTime', timestamp,
                        description)
                    parser_mediator.ProduceEvent(event_object)

            time_string = policy_dict.get(u'lastLoginTimestamp', None)
            if time_string:
                try:
                    timestamp = timelib.Timestamp.FromTimeString(time_string)
                except errors.TimestampError:
                    parser_mediator.ProduceParseError(
                        u'Unable to parse time string: {0:s}'.format(
                            time_string))
                    timestamp = 0

                description = u'Last login from {0:s} ({1!s})'.format(
                    account, uid)
                if timestamp > cocoa_zero:
                    event_object = plist_event.PlistTimeEvent(
                        self._ROOT, u'lastLoginTimestamp', timestamp,
                        description)
                    parser_mediator.ProduceEvent(event_object)

            time_string = policy_dict.get(u'failedLoginTimestamp', None)
            if time_string:
                try:
                    timestamp = timelib.Timestamp.FromTimeString(time_string)
                except errors.TimestampError:
                    parser_mediator.ProduceParseError(
                        u'Unable to parse time string: {0:s}'.format(
                            time_string))
                    timestamp = 0

                description = (
                    u'Last failed login from {0:s} ({1!s}) ({2!s} times)'
                ).format(account, uid, policy_dict.get(u'failedLoginCount', 0))
                if timestamp > cocoa_zero:
                    event_object = plist_event.PlistTimeEvent(
                        self._ROOT, u'failedLoginTimestamp', timestamp,
                        description)
                    parser_mediator.ProduceEvent(event_object)
Exemple #3
0
  def GetEntries(self, parser_context, match=None, **unused_kwargs):
    """Extracts relevant user timestamp entries.

    Args:
      parser_context: A parser context object (instance of ParserContext).
      match: Optional dictionary containing keys extracted from PLIST_KEYS.
             The default is None.
    """
    account = match['name'][0]
    uid = match['uid'][0]
    cocoa_zero = (
        timelib.Timestamp.COCOA_TIME_TO_POSIX_BASE *
        timelib.Timestamp.MICRO_SECONDS_PER_SECOND)
    # INFO: binplist return a string with the Plist XML.
    for policy in match['passwordpolicyoptions']:
      xml_policy = ElementTree.fromstring(policy)
      for dict_elements in xml_policy.iterfind('dict'):
        key_values = [value.text for value in dict_elements.getchildren()]
        policy_dict = dict(zip(key_values[0::2], key_values[1::2]))

      if policy_dict.get('passwordLastSetTime', 0):
        timestamp = timelib.Timestamp.FromTimeString(
             policy_dict.get('passwordLastSetTime', '0'))
        if timestamp > cocoa_zero:
          # Extract the hash password information.
          # It is store in the attribure ShadowHasData which is
          # a binary plist data; However binplist only extract 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.
          resolver_context = context.Context()
          fake_file = fake_file_io.FakeFile(
              resolver_context, match['ShadowHashData'][0])
          fake_file.open(path_spec=fake_path_spec.FakePathSpec(
              location=u'ShadowHashData'))

          try:
            plist_file = binplist.BinaryPlist(file_obj=fake_file)
            top_level = plist_file.Parse()
          except binplist.FormatError:
            top_level = dict()
          salted_hash = top_level.get('SALTED-SHA512-PBKDF2', None)
          if salted_hash:
            password_hash = u'$ml${0:d}${1:s}${2:s}'.format(
                salted_hash['iterations'],
                binascii.hexlify(salted_hash['salt']),
                binascii.hexlify(salted_hash['entropy']))
          else:
            password_hash = u'N/A'
          description = (
              u'Last time {0:s} ({1!s}) changed the password: {2!s}').format(
                  account, uid, password_hash)
          event_object = plist_event.PlistTimeEvent(
              self._ROOT, u'passwordLastSetTime', timestamp, description)
          parser_context.ProduceEvent(event_object, plugin_name=self.NAME)

      if policy_dict.get('lastLoginTimestamp', 0):
        timestamp = timelib.Timestamp.FromTimeString(
             policy_dict.get('lastLoginTimestamp', '0'))
        description = u'Last login from {0:s} ({1!s})'.format(account, uid)
        if timestamp > cocoa_zero:
          event_object = plist_event.PlistTimeEvent(
              self._ROOT, u'lastLoginTimestamp', timestamp, description)
          parser_context.ProduceEvent(event_object, plugin_name=self.NAME)

      if policy_dict.get('failedLoginTimestamp', 0):
        timestamp = timelib.Timestamp.FromTimeString(
             policy_dict.get('failedLoginTimestamp', '0'))
        description = (
            u'Last failed login from {0:s} ({1!s}) ({2!s} times)').format(
                account, uid, policy_dict['failedLoginCount'])
        if timestamp > cocoa_zero:
          event_object = plist_event.PlistTimeEvent(
              self._ROOT, u'failedLoginTimestamp', timestamp, description)
          parser_context.ProduceEvent(event_object, plugin_name=self.NAME)