Example #1
0
 def testReadTrailer(self):
     blank_trailer = StringIO.StringIO()
     plist = binplist.BinaryPlist(blank_trailer)
     self.assertRaises(IOError, plist._ReadTrailer)
     plist = binplist.BinaryPlist(self.minimal)
     # We allow parsing the minimal plist, even though it's not valid
     plist._ReadTrailer()
Example #2
0
 def testReadHeader(self):
     blank_header = StringIO.StringIO()
     plist = binplist.BinaryPlist(blank_header)
     self.assertRaises(binplist.FormatError, plist._ReadHeader)
     wrong_header = StringIO.StringIO("bla")
     plist = binplist.BinaryPlist(wrong_header)
     self.assertRaises(binplist.FormatError, plist._ReadHeader)
     unknown_version = StringIO.StringIO("bplist99")
     plist = binplist.BinaryPlist(unknown_version)
     plist._ReadHeader()
     self.assertEqual(plist.version, "99")
     usual_header = StringIO.StringIO("bplist00")
     plist = binplist.BinaryPlist(usual_header)
     plist._ReadHeader()
     self.assertEqual(plist.version, "00")
Example #3
0
  def _OpenPlistFile(self, searcher, path_spec):
    """Open a Plist file given a path and returns a plist top level object.

    Args:
      searcher: The file system searcher object (instance of
                dfvfs.FileSystemSearcher).
      path_spec: The path specification (instance of dfvfs.PathSpec)
                 of the plist file.

    Raises:
      errors.PreProcessFail: if the preprocessing fails.
    """
    plist_file_location = getattr(path_spec, 'location', u'')
    file_entry = searcher.GetFileEntryByPathSpec(path_spec)
    file_object = file_entry.GetFileObject()

    try:
      plist_file = binplist.BinaryPlist(file_object)
      top_level_object = plist_file.Parse()

    except binplist.FormatError as exception:
      exception = utils.GetUnicodeString(exception)
      raise errors.PreProcessFail(
          u'File is not a plist: {0:s}'.format(exception))

    except OverflowError as exception:
      raise errors.PreProcessFail(
          u'Error processing: {0:s} with error: {1:s}'.format(
              plist_file_location, exception))

    if not plist_file:
      raise errors.PreProcessFail(
          u'File is not a plist: {0:s}'.format(plist_file_location))

    return top_level_object
Example #4
0
def __init__():
    f = open(sys.argv[1], 'rb')
    plist = binplist.BinaryPlist(f, False, False)
    try:
        parsed_plist = plist.Parse()
    except binplist.FormatError:
        print "Error!"
        exit()
    '''
  system_items = parsed_plist['systemitems']
  elem_list = system_items['VolumesList']
  favorite_items = parsed_plist['favorites']
  elem_list.extend(favorite_items['VolumesList'])
  '''
    favorite_items = parsed_plist['favorites']
    elem_list = favorite_items['VolumesList']
    for volume in elem_list:
        if 'Alias' in volume:
            try:
                data = volume['Alias']
                s = s_alias.parse(data)
                data = data[s_alias.sizeof():]

                # Search for 0x000e volume ID
                type = s_type.parse(data)
                data = data[s_type.sizeof():]
                while type != 14 and data != '':
                    type = s_type.parse(data)
                    data = data[s_type.sizeof():]
            except:
                print "Fail!"
                continue

            # If not volume ID
            if data == '':
                print "Fail!"
                continue
            v = s_volume.parse(data)
            time = datetime.datetime.fromtimestamp(
                s.timestamp1 - HFS_to_Epoch).strftime('%Y-%m-%d %H:%M:%S')
            print u'\n\tFile name: {}'.format(v.volume1)
            print u'\tVolume name: {}'.format(v.volume2)
            print u'\tTime: {}'.format(time)
            if s.timestamp1 != s.timestamp2:
                time = datetime.datetime.fromtimestamp(
                    s.timestamp2 - HFS_to_Epoch).strftime('%Y-%m-%d %H:%M:%S')
                print u'\tSecond time: {}'.format(time)

            type = s_type.parse(data)
            data = data[s_type.sizeof():]
            while type != 19 and data != '':
                type = s_type.parse(data)
                data = data[s_type.sizeof():]
            if data == '':
                continue
            mount_point = s_mount_point.parse(data)
            print u'\tMount point: {}'.format(mount_point)
Example #5
0
 def testParseOfftable(self):
     plist = binplist.BinaryPlist(self.minimal)
     # Start by parsing a minimal offsets table
     plist._ReadTrailer()
     self.assertRaises(binplist.FormatError, plist._ReadOffsetTable)
     # single offset table
     plist = binplist.BinaryPlist(self.single)
     plist._ReadTrailer()
     plist._ReadOffsetTable()
     self.assertListEqual([0x09], plist.object_offsets)
     # Test the plist that doesn't have a full trailer
     plist = binplist.BinaryPlist(self.short)
     plist._ReadTrailer()
     plist._ReadOffsetTable()
     self.assertListEqual([9, 10, 11], plist.object_offsets)
     # Test the plist with an offset table that overflows the file
     plist = binplist.BinaryPlist(self.overflow)
     plist._ReadTrailer()
     self.assertRaises(binplist.FormatError, plist._ReadOffsetTable)
def parse_plist(fd):
    bplist = binplist.BinaryPlist(fd)
    parsed_list = bplist.Parse()
    for item in parsed_list['$objects']:
        if isinstance(item, (str)):
            if 'file:///' in item:
                try:
                    print str(item).encode('utf-8')
                except:
                    pass
Example #7
0
 def testCanParseBinplistAtOffset(self):
     for _ in range(5):
         self.single.seek(0, os.SEEK_SET)
         rand_int = random.randint(0, 2048)
         padding = "A" * rand_int
         padded_singleplist = padding + self.single.read()
         fd = StringIO.StringIO(padded_singleplist)
         fd.seek(rand_int, os.SEEK_SET)
         plist = binplist.BinaryPlist(fd)
         plist.Parse()
Example #8
0
 def ObjectTest(self, values):
     for test_value in values:
         raises, data, expected_result, result_type = test_value
         fd = StringIO.StringIO(data)
         plist = binplist.BinaryPlist(fd)
         if not raises:
             result = plist._ParseObject()
             logging.debug("Result was %r.", result)
             self.assertTrue(isinstance(result, result_type))
             self.assertEqual(result, expected_result)
         else:
             self.assertRaises(expected_result, plist._ParseObject)
Example #9
0
def get_parrot_zik_mac_darwin():
    fd = open("/Library/Preferences/com.apple.Bluetooth.plist", "rb")
    plist = binplist.BinaryPlist(file_obj=fd)
    parsed_plist = plist.Parse()
    try:
        for mac in parsed_plist['PairedDevices']:
            if p.match(mac.replace("-", ":")):
                return mac.replace("-", ":")
        else:
            raise DeviceNotConnected
    except Exception:
        pass
Example #10
0
    def test_ParseObjectByIndex(self):
        unicode_string = (
            "\x6F\x00\x11\x65\xaf\x8b\xfa\x76\x7b\x90\x7f\x96\xbe"
            "\x75\x33\x8b\xf7\x7e\xc8\x88\xab\x90\x1a\x8f\xc7\x00"
            "\x20\x00\x2d\x00\x20\x00\x68\x00\x65\x00\x68")
        actual_string = u"斯诺登避难申请终被通过 - heh"
        fd = StringIO.StringIO(unicode_string)
        plist = binplist.BinaryPlist(file_obj=fd)
        # Make an external offset_list
        offset_list = [0]
        resulting_object = plist._ParseObjectByIndex(0, offset_list)
        self.assertEqual(resulting_object, actual_string)

        # Second test
        second_resulting_object = plist._ParseObjectByIndex(0, offset_list)
        # Test that the UTF16 object was in the cache
        self.assert_(second_resulting_object is resulting_object)
        self.assertEqual(resulting_object, actual_string)

        # Now test for something more complex. An array that has both unicode and
        # str strings.
        two_element_array = (
            "\xA2"  # Array of 2 objects
            "\x01"  # Reference to object unicode string
            "\x02"  # Reference to object str string
            "\x61\x65\xaf"  # Unicode object
            "\x52\x99\xcd"  # Str object
        )
        fd = StringIO.StringIO(two_element_array)
        plist = binplist.BinaryPlist(fd)
        # Parsing with _ParseObjectByIndex requires setting up some bplist
        # properties.
        offset_list = [0, 3, 6]
        plist.object_count = len(offset_list)
        plist.object_offsets = offset_list
        plist.object_ref_size = 1
        plist._file_size = len(two_element_array)
        resulting_object = plist._ParseObjectByIndex(0, offset_list)
        self.assertEqual(resulting_object, [u"斯", "\x99\xcd"])
Example #11
0
 def testParseBoolFill(self):
     # null
     data = StringIO.StringIO("\x00")
     plist = binplist.BinaryPlist(data)
     self.assertEqual(binplist.NullValue, plist._ParseObject())
     # false
     data = StringIO.StringIO("\x08")
     plist = binplist.BinaryPlist(data)
     self.assertEqual(False, plist._ParseObject())
     # true
     data = StringIO.StringIO("\x09")
     plist = binplist.BinaryPlist(data)
     self.assertEqual(True, plist._ParseObject())
     # fill byte
     data = StringIO.StringIO("\x0F")
     plist = binplist.BinaryPlist(data)
     self.assertEqual(None, plist._ParseObject())
     # unknown
     for i in "\x01\x02\x03\x04\x05\x06\x07\x0a\x0b\x0c\x0d\x0e":
         unk = StringIO.StringIO(i)
         plist = binplist.BinaryPlist(unk)
         self.assertEqual(binplist.UnknownObject, plist._ParseObject())
Example #12
0
    def ParseFile(self, file_entry, file_object):
        """Parses the plist file and returns the parsed key.

    Args:
      file_entry: The file entry (instance of dfvfs.FileEntry).
      file_object: The file-like object.

    Returns:
      The value of the first key defined by PLIST_KEYS that is found.

    Raises:
      errors.PreProcessFail: if the preprocessing fails.
    """
        try:
            plist_file = binplist.BinaryPlist(file_object)
            top_level_object = plist_file.Parse()

        except binplist.FormatError as exception:
            raise errors.PreProcessFail(
                u'File is not a plist: {0:s} with error: {1:s}'.format(
                    file_entry.path_spec.comparable, exception))

        except OverflowError as exception:
            raise errors.PreProcessFail(
                u'Unable to process plist: {0:s} with error: {1:s}'.format(
                    file_entry.path_spec.comparable, exception))

        if not plist_file:
            raise errors.PreProcessFail(u'File is not a plist: {0:s}'.format(
                file_entry.path_spec.comparable))

        match = None
        key_name = ''
        for plist_key in self.PLIST_KEYS:
            try:
                match = plist_interface.GetKeys(top_level_object,
                                                frozenset([plist_key]))
            except KeyError:
                continue
            if match:
                key_name = plist_key
                break

        if not match:
            raise errors.PreProcessFail(
                u'Keys not found inside plist file: {0:s}.'.format(u','.join(
                    self.PLIST_KEYS)))

        return self.ParseKey(match, key_name)
Example #13
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 u'name' not in match or u'uid' not in match:
            return

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

        # 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 and time_string != u'2001-01-01T00:00:00Z':
                try:
                    date_time = dfdatetime_time_elements.TimeElements()
                    date_time.CopyFromStringISO8601(time_string)
                except ValueError:
                    date_time = None
                    parser_mediator.ProduceExtractionError(
                        u'unable to parse passworkd last set time string: {0:s}'
                        .format(time_string))

                shadow_hash_data = match.get(u'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 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)
                    shadow_hash_data_path_spec = fake_path_spec.FakePathSpec(
                        location=u'ShadowHashData')
                    fake_file.open(path_spec=shadow_hash_data_path_spec)

                    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'

                    event_data = plist_event.PlistTimeEventData()
                    event_data.desc = (
                        u'Last time {0:s} ({1!s}) changed the password: {2!s}'
                    ).format(account, uid, password_hash)
                    event_data.key = u'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(u'lastLoginTimestamp', None)
            if time_string and time_string != u'2001-01-01T00:00:00Z':
                try:
                    date_time = dfdatetime_time_elements.TimeElements()
                    date_time.CopyFromStringISO8601(time_string)
                except ValueError:
                    date_time = None
                    parser_mediator.ProduceExtractionError(
                        u'unable to parse last login time string: {0:s}'.
                        format(time_string))

                if date_time:
                    event_data = plist_event.PlistTimeEventData()
                    event_data.desc = u'Last login from {0:s} ({1!s})'.format(
                        account, uid)
                    event_data.key = u'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(u'failedLoginTimestamp', None)
            if time_string and time_string != u'2001-01-01T00:00:00Z':
                try:
                    date_time = dfdatetime_time_elements.TimeElements()
                    date_time.CopyFromStringISO8601(time_string)
                except ValueError:
                    date_time = None
                    parser_mediator.ProduceExtractionError(
                        u'unable to parse failed login time string: {0:s}'.
                        format(time_string))

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

                    event = time_events.DateTimeValuesEvent(
                        date_time, definitions.TIME_DESCRIPTION_WRITTEN)
                    parser_mediator.ProduceEventWithEventData(
                        event, event_data)
Example #14
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)
Example #15
0
                value.append(INT.parse(bookmark))
                bookmark = bookmark[4:]
            if token.type == 1024:
                t = value.pop(0) + 978307200
                timestamp = time.strftime('%Y-%m-%d %H:%M:%S',
                                          time.localtime(t))
                print u'Timestamp: {}, extra: {}'.format(timestamp, value)
            else:
                print u'Unknown type {}({}): {}'.format(
                    token.type, hex(token.type), value)
    print "--------///-------"


name = sys.argv[1]
fd = open(name, 'rb')
plist = binplist.BinaryPlist(fd, False, False)

print u'File: {}\n'.format(name)

try:
    parsed_plist = plist.Parse()
except binplist.FormatError, e:
    parsed_plist = plistlib.readPlist(name)

# /Users/moxilo/Library/Preferences
# Recent documents
#     com.apple.PROGRAM.LSSharedFileList.plist
#     com.apple.recentitems.plist
try:
    documents = parsed_plist['RecentDocuments']
except KeyError:
Example #16
0
      data_to_return = self._data[self._offset:]
      self._offset = len(self._data)
      return data_to_return

    data_to_return = self._data[self._offset:self._offset + size]
    self._offset += size
    return data_to_return

  def close(self):
    pass


name = sys.argv[1]

fd = open(name, 'rb')
plist = binplist.BinaryPlist(fd, False, False)
parsed_plist = plist.Parse()
account = parsed_plist['name'][0]
name = parsed_plist['realname'][0]
uid = parsed_plist['uid'][0]
gid = parsed_plist['gid'][0]
shell = parsed_plist['shell'][0]
password = parsed_plist['authentication_authority']
ShadowHashData = parsed_plist['ShadowHashData']
foo = FooFile(ShadowHashData[0])
plist_file = binplist.BinaryPlist(file_obj=foo)
top_level = plist_file.Parse()['SALTED-SHA512-PBKDF2']
salt = binascii.hexlify(top_level['salt'])
entropy = binascii.hexlify(top_level['entropy'])
iterations = top_level['iterations']
Example #17
0
 def testParseInt(self):
     # 1 byte
     data = StringIO.StringIO("\x10\x00")
     plist = binplist.BinaryPlist(data)
     self.assertEqual(0, plist._ParseObject())
     # 2 bytes
     data = StringIO.StringIO("\x11\x00\x01")
     plist = binplist.BinaryPlist(data)
     self.assertEqual(1, plist._ParseObject())
     data = StringIO.StringIO("\x11\x01\x00")
     plist = binplist.BinaryPlist(data)
     self.assertEqual(256, plist._ParseObject())
     # 4 bytes
     data = StringIO.StringIO("\x12\x00\x00\x00\x01")
     plist = binplist.BinaryPlist(data)
     self.assertEqual(1, plist._ParseObject())
     # 8 bytes - should be unsigned
     data = StringIO.StringIO("\x13\x00\x00\x00\x00\x00\x00\x00\x01")
     plist = binplist.BinaryPlist(data)
     self.assertEqual(1, plist._ParseObject())
     # Now with version 00 - signed
     data = StringIO.StringIO("\x13\x00\x00\x00\x00\x00\x00\x00\x01")
     plist = binplist.BinaryPlist(data)
     plist.version = "00"
     self.assertEqual(1, plist._ParseObject())
     # 8 bytes - should be unsigned
     data = StringIO.StringIO("\x13\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE")
     plist = binplist.BinaryPlist(data)
     self.assertEqual((1 << 64) - 2, plist._ParseObject())
     # Now with version 00 - signed
     data = StringIO.StringIO("\x13\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE")
     plist = binplist.BinaryPlist(data)
     plist.version = "00"
     self.assertEqual(-2, plist._ParseObject())
     # 16 bytes - should be unsigned
     raw = "\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01"
     data = StringIO.StringIO(raw)
     plist = binplist.BinaryPlist(data)
     self.assertEqual(1, plist._ParseObject())
     raw = "\x14\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01"
     data = StringIO.StringIO(raw)
     plist = binplist.BinaryPlist(data)
     plist.version = "00"
     self.assertEqual(1, plist._ParseObject())
     # 16 bytes - should be unsigned
     raw = "\x14\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE"
     data = StringIO.StringIO(raw)
     plist = binplist.BinaryPlist(data)
     self.assertEqual((1 << 128) - 2, plist._ParseObject())
     # Now with version 00 - signed
     raw = "\x14\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFE"
     data = StringIO.StringIO(raw)
     plist = binplist.BinaryPlist(data)
     plist.version = "00"
     self.assertEqual(-2, plist._ParseObject())
     # Test incomplete data
     data = StringIO.StringIO("\x10")
     plist = binplist.BinaryPlist(data)
     int_object = plist._ParseObject()
     self.assertTrue(isinstance(int_object, binplist.RawValue))
     data = StringIO.StringIO("\x11\x12")
     plist = binplist.BinaryPlist(data)
     int_object = plist._ParseObject()
     self.assertTrue(isinstance(int_object, binplist.RawValue))
     # Test unknown size
     data = StringIO.StringIO("\x16\x00\x00")
     plist = binplist.BinaryPlist(data)
     int_object = plist._ParseObject()
     self.assertEqual(int_object, binplist.RawValue("\x00\x00"))
Example #18
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)
Example #19
0
    options = parser.parse_args()
    if not options.plist:
        parser.print_help()
        sys.exit(-1)

    ultra_verbosity = False
    if options.verbose:
        if len(options.verbose) == 1:
            logging.basicConfig(level=logging.DEBUG)
        else:
            ultra_verbosity = True
            logging.basicConfig(level=binplist.LOG_ULTRA_VERBOSE)

    with open(options.plist, "rb") as fd:
        plist = binplist.BinaryPlist(file_obj=fd,
                                     ultra_verbosity=ultra_verbosity,
                                     discovery_mode=options.discovery_mode)
        try:
            parsed_plist = plist.Parse()
            if plist.is_corrupt:
                logging.warn(
                    "%s LOOKS CORRUPTED. You might not obtain all data!\n",
                    options.plist)
        except binplist.FormatError, e:
            parsed_plist = plistlib.readPlist(options.plist)

        print binplist.PlistToUnicode(
            parsed_plist,
            string_encoding=options.string_encoding,
            encoding_options=options.string_encoding_option).encode(
                options.output_encoding, options.output_encoding_option)
Example #20
0
    def testParseArray(self):
        values = [
            # (ref_size, object_offsets, expected_result, data)
            # Array of 0 objects
            (1, [], [], "\xA0"),
            # Array of 1 object
            (
                1,
                [0, 2],
                [False],
                (
                    "\xA1"  # Array of 1 object
                    "\x01"  # Reference to object False
                    "\x08"  # False object
                )),
            # Array of 2 objects
            (
                1,
                [0, 3, 4],
                [False, True],
                (
                    "\xA2"  # Array of 2 objects
                    "\x01"  # Reference to object False
                    "\x02"  # Reference to object True
                    "\x08"  # False object
                    "\x09"  # True object
                )),
            # Array of 2 objects, 1 nonexistant
            (
                1,
                [0, 3, 4],
                [False, binplist.CorruptReference],
                (
                    "\xA2"  # Array of 2 objects
                    "\x01"  # Reference to object False
                    "\x09"  # Reference to a nonexistant object
                    "\x08"  # False object
                    "\x09"  # True object
                )),
            # Array of 2 objects, 1 out of bounds
            (
                1,
                [0, 3, 200],
                [False, binplist.CorruptReference],
                (
                    "\xA2"  # Array of 2 objects
                    "\x01"  # Reference to object False
                    "\x02"  # Reference out of bounds
                    "\x08"  # False object
                    "\x09"  # True object
                )),
            # Array of 2 objects, 1 circular reference to the array itself
            (
                1,
                [0, 3, 4],
                [False, binplist.CorruptReference],
                (
                    "\xA2"  # Array of 2 objects
                    "\x01"  # Reference to object False
                    "\x00"  # circular reference to the array
                    "\x08"  # False object
                    "\x09"  # True object
                )),
            # Array of 2 objects, one a False value. The other is an array that
            # has a reference to the first array.
            # Tests deep circular reference detection
            (
                1,
                [0, 3, 4],
                [False, [binplist.CorruptReference]],
                (
                    "\xA2"  # Array of 2 objects
                    "\x01"  # Reference to object False
                    "\x02"  # Reference to the second array
                    "\x08"  # False object
                    "\xA1"  # Array of 1 object, points to the first array
                    "\x00"  # circular reference to the first array
                )),
            # Array with not enough elements. This is hardly possible
            # in a real world scenario because of the trailer always being
            # past the objects. However on a corrupt bplist the object offset might
            # be pointing to the last elements of the trailer, one of them
            # being interpreted as an array... Thus why this scenario.
            (
                1,
                [0, 3, 4],
                [binplist.CorruptReference, binplist.CorruptReference],
                (
                    "\xA2"  # Array of 2 objects
                    "\x01"  # Reference to a nonexistant object
                )),
        ]

        for value in values:
            (ref_size, object_offsets, expected_result, data) = value
            fd = StringIO.StringIO(data)
            plist = binplist.BinaryPlist(fd)
            # Fill objects_traversed with the current value as if we had been called
            # by a normal _Parse
            plist.objects_traversed = {0}
            plist.object_ref_size = ref_size
            plist.object_offsets = object_offsets
            plist.object_count = len(object_offsets)
            result = plist._ParseObject()
            self.assertListEqual(expected_result, result)
            # Test that the circular reference detection helper is cleaned properly
            self.assertSetEqual(plist.objects_traversed, {0})
Example #21
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)
Example #22
0
    def testParseDict(self):
        values = [
            # (ref_size, object_offsets, expected_result, data)
            # Dict of 0 objects
            (1, [], {}, "\xD0"),
            # Dict of 1 entry
            (
                1,
                [0, 3, 5],
                {
                    "a": True
                },
                (
                    "\xD1"  # Dict of 1 entry
                    "\x01"  # Ref to key#1
                    "\x02"  # Ref to val#1
                    "\x51a"  # "a" (key#1)
                    "\x09"  # True (val#1)
                )),
            # Dict of 1 entry, a key being an integer
            (
                1,
                [0, 3, 5],
                {
                    1: True
                },
                (
                    "\xD1"  # Dict of 1 entry
                    "\x01"  # Ref to key#1
                    "\x02"  # Ref to val#1
                    "\x10\x01"  # 1 (key#1)
                    "\x09"  # True (val#1)
                )),
            # Dict of 1 entry, has a circular key
            (
                1,
                [0, 3, 5],
                {
                    "corrupt:0": True
                },
                (
                    "\xD1"  # Dict of 1 entry
                    "\x00"  # Circular key
                    "\x02"  # Ref to val#1
                    "\x10\x01"  # 1 (key#1)
                    "\x09"  # True (val#1)
                )),
            # Dict of 1 entry, has a circular value
            (
                1,
                [0, 3, 5],
                {
                    1: binplist.CorruptReference
                },
                (
                    "\xD1"  # Dict of 1 entry
                    "\x01"  # Ref to key#1
                    "\x00"  # Circular value
                    "\x10\x01"  # 1 (key#1)
                    "\x09"  # True (val#1)
                )),
            # Dict of 1 entry, has both a circular key and a circular value
            (
                1,
                [0, 3, 5],
                {
                    "corrupt:0": binplist.CorruptReference
                },
                (
                    "\xD1"  # Dict of 1 entry
                    "\x00"  # Circular key
                    "\x00"  # Circular value
                    "\x10\x01"  # 1 (key#1)
                    "\x09"  # True (val#1)
                )),
            # Dict of 1 entry, value is a list that contains a circular value
            (
                1,
                [0, 3, 5, 8],
                {
                    "a": [binplist.CorruptReference, 1]
                },
                (
                    "\xD1"  # Dict of 1 entry
                    "\x01"  # key#1
                    "\x02"  # val#1
                    "\x51a"  # "a" (key#1)
                    "\xA2\x00\x03"  # Array with 2 elements. The dict and an integer
                    "\x10\x01"  # 1
                )),
            # Dict of 2 entries
            (
                1,
                [0, 5, 7, 9, 10],
                {
                    "a": False,
                    "b": True
                },
                (
                    "\xD2"  # Dict of 2 entries
                    "\x01"  # key#1
                    "\x02"  # key#2
                    "\x03"  # val#2
                    "\x04"  # val#2
                    "\x51a"  # "a"
                    "\x51b"  # "b"
                    "\x08"  # False object
                    "\x09"  # True object
                )),
            # Dict with not enough references
            (
                1,
                [0],
                {
                    "corrupt:1": binplist.CorruptReference
                },
                (
                    "\xD1"  # Dict of 1 entry
                    "\x01"  # key#1
                )),
            # Dict with a nonexistant reference
            (
                1,
                [0],
                {
                    "corrupt:32": binplist.CorruptReference
                },
                (
                    "\xD1"  # Dict of 1 entry
                    "\x20"  # key#1
                    "\x99"  # val#1
                )),
        ]

        for value in values:
            (ref_size, object_offsets, expected_result, data) = value
            fd = StringIO.StringIO(data)
            plist = binplist.BinaryPlist(fd)
            # Fill objects_traversed with the current value as if we had been called
            # by a normal _Parse
            plist.objects_traversed = {0}
            plist.object_ref_size = ref_size
            plist.object_offsets = object_offsets
            plist.object_count = len(object_offsets)
            result = plist._ParseObject()
            self.assertEqual(expected_result, result)
            # Test that the circular reference detection helper is cleaned properly
            self.assertSetEqual(plist.objects_traversed, {0})