Ejemplo n.º 1
0
 def test_key_material_read(self):
     volume = Volume(disk=Disk(ImageParser(keys={'3': 'hello'}), "..."), index='3')
     self.assertEqual(volume.key, "hello")
     volume = Volume(disk=Disk(ImageParser(keys={'3': 'hello', '*': 'ola'}), "..."), index='2')
     self.assertEqual(volume.key, "ola")
     volume = Volume(disk=Disk(ImageParser(keys={'3': 'hello'}), "..."), index='1')
     self.assertEqual(volume.key, "")
Ejemplo n.º 2
0
    def test_ext4(self):
        # Removed some items from this output as we don't use it in its entirety anyway
        result = b"""FILE SYSTEM INFORMATION
--------------------------------------------
File System Type: Ext4
Volume Name: Example
Volume ID: 2697f5b0479b15b1b4c81994387cdba

Last Written at: 2017-07-02 12:23:22 (CEST)
Last Checked at: 2016-07-09 20:27:28 (CEST)

Last Mounted at: 2017-07-02 12:23:23 (CEST)
Unmounted properly
Last mounted on: /

Source OS: Linux

BLOCK GROUP INFORMATION
--------------------------------------------"""
        with mock.patch('subprocess.Popen') as mock_popen:
            type(mock_popen()).stdout = mock.PropertyMock(return_value=io.BytesIO(result))

            volume = Volume(disk=Disk(ImageParser(), "..."))
            volume.get_raw_path = mock.Mock(return_value="...")

            volume._load_fsstat_data()

            self.assertEqual(volume.info['statfstype'], 'Ext4')
            self.assertEqual(volume.info['lastmountpoint'], '/')
            self.assertEqual(volume.info['label'], '/ (Example)')
            self.assertEqual(volume.info['version'], 'Linux')

            # must be called after reading BLOCK GROUP INFORMATION
            mock_popen().terminate.assert_called()
Ejemplo n.º 3
0
    def test_magic(self):
        # Add values here that are shown in the wild for file magic output
        # !! Always try to add it also to test_combination

        descriptions = {
            "Linux Compressed ROM File System data": "cramfs",
            "Linux rev 1.0 ext2 filesystem data": "ext",

            'DOS/MBR boot sector, code offset 0x3c+2, OEM-ID "mkfs.fat", sectors/cluster 4, '
            'root entries 512, sectors 100 (volumes <=32 MB) , Media descriptor 0xf8, '
            'sectors/FAT 1, sectors/track 32, heads 64, serial number 0x3cb7474b, '
            'label: "TEST       ", FAT (12 bit)': "fat",

            "ISO 9660 CD-ROM filesystem data 'test'": "iso",
            "Minix filesystem, V1, 30 char names, 12800 zones": "minix",

            'DOS/MBR boot sector, code offset 0x52+2, OEM-ID "NTFS    ", sectors/cluster 8, '
            'Media descriptor 0xf8, sectors/track 0, dos < 4.0 BootSector (0x80), FAT (1Y bit '
            'by descriptor); NTFS, sectors 2048, $MFT start cluster 4, $MFTMirror start '
            'cluster 128, bytes/RecordSegment 2^(-1*246), clusters/index block 1, serial '
            'number 04e8742c12a96cecd; contains Microsoft Windows XP/VISTA bootloader BOOTMGR': "ntfs",

            "Squashfs filesystem, little endian, version 4.0": "squashfs",
        }

        for description, fstype in descriptions.items():
            volume = Volume(disk=Disk(ImageParser(), "..."))
            volume._get_blkid_type = mock.Mock(return_value=None)
            volume._get_magic_type = mock.Mock(return_value=description)
            volume.determine_fs_type()
            self.assertEqual(FILE_SYSTEM_TYPES[fstype], volume.fstype)
Ejemplo n.º 4
0
    def test_luks_key_communication(self, _, check_call):
        def modified_check_call(cmd, *args, **kwargs):
            if cmd[0:2] == ['cryptsetup', 'isLuks']:
                return True
            return mock.DEFAULT
        check_call.side_effect = modified_check_call

        original_popen = subprocess.Popen
        def modified_popen(cmd, *args, **kwargs):
            if cmd[0:3] == ['cryptsetup', '-r', 'luksOpen']:
                # A command that requests user input
                x = original_popen(["python2", "-c", "print(raw_input(''))"],
                                   *args, **kwargs)
                return x
            return mock.DEFAULT

        with mock.patch("subprocess.Popen", side_effect=modified_popen) as popen:
            disk = Disk(ImageParser(keys={'1': 'p:passphrase'}), "...")
            disk.is_mounted = True
            volume = Volume(disk=disk, fstype='luks', index='1', parent=disk)
            volume.mount()

            self.assertTrue(volume.is_mounted)
            self.assertEqual(len(volume.volumes), 1)
            self.assertEqual(volume.volumes[0].info['fsdescription'], "LUKS Volume")
Ejemplo n.º 5
0
    def _mount_pytsk3_volumes(self):
        """Generator that mounts every partition of this image and yields the mountpoint."""

        # Loop over all volumes in image.
        for p in self._find_pytsk3_volumes():
            import pytsk3

            volume = Volume(disk=self, **self.args)
            self.volumes.append(volume)

            # Fill volume with more information
            volume.offset = p.start * BLOCK_SIZE
            volume.fsdescription = p.desc
            if self.index is not None:
                volume.index = '{0}.{1}'.format(self.index, p.addr)
            else:
                volume.index = p.addr
            volume.size = p.len * BLOCK_SIZE

            if p.flags == pytsk3.TSK_VS_PART_FLAG_ALLOC:
                volume.flag = 'alloc'
            elif p.flags == pytsk3.TSK_VS_PART_FLAG_UNALLOC:
                volume.flag = 'unalloc'
                self._debug("    Unallocated space: block offset: {0}, length: {1} ".format(p.start, p.len))
            elif p.flags == pytsk3.TSK_VS_PART_FLAG_META:
                volume.flag = 'meta'

            # unalloc / meta partitions do not have stats and can not be mounted
            if volume.flag != 'alloc':
                yield volume
                continue

            for v in volume.init():
                yield v
Ejemplo n.º 6
0
    def test_ext4(self):
        # Removed some items from this output as we don't use it in its entirety anyway
        result = b"""FILE SYSTEM INFORMATION
--------------------------------------------
File System Type: Ext4
Volume Name: Example
Volume ID: 2697f5b0479b15b1b4c81994387cdba

Last Written at: 2017-07-02 12:23:22 (CEST)
Last Checked at: 2016-07-09 20:27:28 (CEST)

Last Mounted at: 2017-07-02 12:23:23 (CEST)
Unmounted properly
Last mounted on: /

Source OS: Linux

BLOCK GROUP INFORMATION
--------------------------------------------"""
        with mock.patch('subprocess.Popen') as mock_popen:
            type(mock_popen()).stdout = mock.PropertyMock(return_value=io.BytesIO(result))

            volume = Volume(disk=Disk(ImageParser(), "..."))
            volume.get_raw_path = mock.Mock(return_value="...")

            volume._load_fsstat_data()

            self.assertEqual(volume.info['statfstype'], 'Ext4')
            self.assertEqual(volume.info['lastmountpoint'], '/')
            self.assertEqual(volume.info['label'], '/ (Example)')
            self.assertEqual(volume.info['version'], 'Linux')

            # must be called after reading BLOCK GROUP INFORMATION
            mock_popen().terminate.assert_called()
Ejemplo n.º 7
0
    def test_luks_key_communication(self, _, check_call):
        def modified_check_call(cmd, *args, **kwargs):
            if cmd[0:2] == ['cryptsetup', 'isLuks']:
                return True
            return mock.DEFAULT

        check_call.side_effect = modified_check_call

        original_popen = subprocess.Popen

        def modified_popen(cmd, *args, **kwargs):
            if cmd[0:3] == ['cryptsetup', '-r', 'luksOpen']:
                # A command that requests user input
                x = original_popen(["python2", "-c", "print(raw_input(''))"],
                                   *args, **kwargs)
                return x
            return mock.DEFAULT

        with mock.patch("subprocess.Popen", side_effect=modified_popen) as popen:
            disk = Disk(ImageParser(keys={'1': 'p:passphrase'}), "...")
            disk.is_mounted = True
            volume = Volume(disk=disk, fstype='luks', index='1', parent=disk)
            volume.mount()

            self.assertTrue(volume.is_mounted)
            self.assertEqual(len(volume.volumes), 1)
            self.assertEqual(volume.volumes[0].info['fsdescription'], "LUKS Volume")
Ejemplo n.º 8
0
    def mount_single_volume(self):
        """Mounts a volume assuming that the mounted image does not contain a full disk image, but only a
        single volume.

        A new :class:`Volume` object is created based on the disk file and :func:`init` is called on this object.

        This function will typically yield one volume, although if the volume contains other volumes, multiple volumes
        may be returned.
        """

        volume = Volume(disk=self, **self.args)
        volume.offset = 0
        if self.index is None:
            volume.index = 0
        else:
            volume.index = '{0}.0'.format(self.index)

        description = util.check_output_(['file', '-sL', self.get_fs_path()]).strip()
        if description:
            # description is the part after the :, until the first comma
            volume.fsdescription = description.split(': ', 1)[1].split(',', 1)[0].strip()
            if 'size' in description:
                volume.size = re.findall(r'size: (\d+)', description)[0]
            else:
                volume.size = os.path.getsize(self.get_fs_path())

        volume.flag = 'alloc'
        self.volumes = [volume]
        self.volume_source = 'single'

        for v in volume.init(no_stats=True):  # stats can't  be retrieved from single volumes
            yield v
Ejemplo n.º 9
0
    def test_killed_after_timeout(self):
        def mock_side_effect(*args, **kwargs):
            time.sleep(0.2)
            return io.BytesIO(b"")

        with mock.patch('subprocess.Popen') as mock_popen:
            type(mock_popen()).stdout = mock.PropertyMock(side_effect=mock_side_effect)

            volume = Volume(disk=Disk(ImageParser(), "..."))
            volume.get_raw_path = mock.Mock(return_value="...")

            volume._load_fsstat_data(timeout=0.1)
            mock_popen().terminate.assert_called()
Ejemplo n.º 10
0
    def test_killed_after_timeout(self):
        def mock_side_effect(*args, **kwargs):
            time.sleep(0.2)
            return io.BytesIO(b"")

        with mock.patch('subprocess.Popen') as mock_popen:
            type(mock_popen()).stdout = mock.PropertyMock(side_effect=mock_side_effect)

            volume = Volume(disk=Disk(ImageParser(), "..."))
            volume.get_raw_path = mock.Mock(return_value="...")

            volume._load_fsstat_data(timeout=0.1)
            mock_popen().terminate.assert_called()
Ejemplo n.º 11
0
    def mount_directory(self):
        """Method that 'mounts' a directory. It actually just symlinks it. It is useful for AVFS mounts, that
        are not otherwise detected. This is a last resort method.
        """

        if not self.mount_directories:
            return

        volume = Volume(disk=self, **self.args)
        volume.offset = 0
        if self.index is None:
            volume.index = 0
        else:
            volume.index = '{0}.0'.format(self.index)

        filesize = _util.check_output_(['du', '-scDb', self.get_fs_path()]).strip()
        if filesize:
            volume.size = int(filesize.splitlines()[-1].split()[0])

        volume.flag = 'alloc'
        volume.fsdescription = 'Directory'
        self.volumes = [volume]
        self.volume_source = 'directory'

        for v in volume.init(no_stats=True):  # stats can't be retrieved from directory
            yield v
Ejemplo n.º 12
0
    def _mount_mmls_volumes(self):
        """Finds and mounts all volumes based on mmls."""

        try:
            cmd = ['mmls']
            if self.vstype != 'detect':
                cmd.extend(['-t', self.vstype])
            cmd.append(self.get_raw_path())
            output = util.check_output_(cmd, self.parser)
            self.volume_source = 'multi'
        except Exception as e:
            self._debug("[-] Failed executing mmls command")
            self._debug(e)
            return

        output = output.split("Description", 1)[-1]
        for line in output.splitlines():
            if not line:
                continue
            try:
                index, slot, start, end, length, description = line.split(None, 5)
                volume = Volume(disk=self, **self.args)
                self.volumes.append(volume)

                volume.offset = int(start) * BLOCK_SIZE
                volume.fsdescription = description
                if self.index is not None:
                    volume.index = '{0}.{1}'.format(self.index, int(index[:-1]))
                else:
                    volume.index = int(index[:-1])
                volume.size = int(length) * BLOCK_SIZE
            except Exception as e:
                self._debug("[-] Error while parsing mmls output")
                self._debug(e)
                continue

            if slot.lower() == 'meta':
                volume.flag = 'meta'
            elif slot.lower() == '-----':
                volume.flag = 'unalloc'
            else:
                volume.flag = 'alloc'

            # unalloc / meta partitions do not have stats and can not be mounted
            if volume.flag != 'alloc':
                yield volume
                continue

            for v in volume.init():
                yield v
Ejemplo n.º 13
0
 def test_fstype_fallback(self):
     volume = Volume(disk=Disk(ImageParser(), "..."))
     volume._get_blkid_type = mock.Mock(return_value=None)
     volume._get_magic_type = mock.Mock(return_value=None)
     volume._get_fstype_from_parser('?ufs')
     volume.determine_fs_type()
     self.assertEqual(FILE_SYSTEM_TYPES["ufs"], volume.fstype)
Ejemplo n.º 14
0
    def test_utf8_label(self):
        # Removed some items from this output as we don't use it in its entirety anyway
        result = b"""FILE SYSTEM INFORMATION
--------------------------------------------
File System Type: Ext4
Volume Name: \xd0\xa0\xd0\xbe\xd1\x81\xd1\x81\xd0\xb8\xd0\xb8
Volume ID: 2697f5b0479b15b1b4c81994387cdba"""
        with mock.patch('subprocess.Popen') as mock_popen:
            type(mock_popen()).stdout = mock.PropertyMock(return_value=io.BytesIO(result))

            volume = Volume(disk=Disk(ImageParser(), "..."))
            volume.get_raw_path = mock.Mock(return_value="...")

            volume._load_fsstat_data()

            self.assertEqual(volume.info['statfstype'], 'Ext4')
            self.assertEqual(volume.info['label'], u'\u0420\u043e\u0441\u0441\u0438\u0438')
Ejemplo n.º 15
0
    def test_utf8_label(self):
        # Removed some items from this output as we don't use it in its entirety anyway
        result = b"""FILE SYSTEM INFORMATION
--------------------------------------------
File System Type: Ext4
Volume Name: \xd0\xa0\xd0\xbe\xd1\x81\xd1\x81\xd0\xb8\xd0\xb8
Volume ID: 2697f5b0479b15b1b4c81994387cdba"""
        with mock.patch('subprocess.Popen') as mock_popen:
            type(mock_popen()).stdout = mock.PropertyMock(return_value=io.BytesIO(result))

            volume = Volume(disk=Disk(ImageParser(), "..."))
            volume.get_raw_path = mock.Mock(return_value="...")

            volume._load_fsstat_data()

            self.assertEqual(volume.info['statfstype'], 'Ext4')
            self.assertEqual(volume.info['label'], u'\u0420\u043e\u0441\u0441\u0438\u0438')
Ejemplo n.º 16
0
    def test_combination(self):
        # Add values here to test full combinations of specific filesystem types
        # The _ as key is the expected result

        _ = "use as key for the expected result"
        definitions = [
            {_: "cramfs", "blkid": "cramfs", "magic": "Linux Compressed ROM File System data", "fsdescription": "???"},
            {_: "exfat", "blkid": "exfat", "fsdescription": "NTFS / exFAT", "statfstype": "exFAT"},
            {_: "ext", "blkid": "ext4", "fsdescription": "Linux (0x83)", "guid": "", "statfstype": "Ext2"},
            {_: "fat", "blkid": "vfat", "magic": "FAT (12 bit)", "fsdescription": "DOS FAT12 (0x04)",
             "statfstype": "FAT12"},
            {_: "iso", "blkid": "iso9660", "magic": ".. ISO 9660 ..", "statfstype": "ISO9660"},
            {_: "minix", "blkid": "min  ix", "magic": "Minix filesystem", "fsdescription": "???"},
            {_: "ntfs", "blkid": "ntfs", "magic": ".. NTFS ..", "fsdescription": "NTFS / exFAT", "statfstype": "NTFS"},
            {_: "squashfs", "blkid": "squashfs", "magic": "Squashfs filesystem", "fsdescription": "???"},

            {_: "lvm", "guid": "79D3D6E6-07F5-C244-A23C-238F2A3DF928"},
            {_: "raid", "fsdescription": "Linux (0x83)", "blkid": "linux_raid_member"},

            {_: "volumesystem", "blkid": "dos", "fsdescription": "Logical Volume"},
            {_: "volumesystem", "blkid": "dos", "fsdescription": "RAID Volume"},
            {_: "volumesystem", "blkid": "dos", "magic": "DOS/MBR boot sector"},
            {_: "volumesystem", "fsdescription": "BSD/386, 386BSD, NetBSD, FreeBSD (0xa5)", "blkid": "ufs"},
            {_: "ufs", "fsdescription": "4.2BSD (0x07)", "blkid": "ufs"},
        ]

        for definition in definitions:
            volume = Volume(disk=Disk(ImageParser(), "..."))
            volume._get_blkid_type = mock.Mock(return_value=definition.get("blkid"))
            volume._get_magic_type = mock.Mock(return_value=definition.get("magic"))
            volume.info = definition
            volume.determine_fs_type()
            self.assertEqual(FILE_SYSTEM_TYPES[definition[_]], volume.fstype)
Ejemplo n.º 17
0
 def test_fstype_fallback(self):
     volume = Volume(disk=Disk(ImageParser(), "..."))
     volume._get_blkid_type = mock.Mock(return_value=None)
     volume._get_magic_type = mock.Mock(return_value=None)
     volume._get_fstype_from_parser('?ufs')
     volume.determine_fs_type()
     self.assertEqual(FILE_SYSTEM_TYPES["ufs"], volume.fstype)
Ejemplo n.º 18
0
 def test_fstype_fallback(self):
     volume = Volume(disk=Disk(ImageParser(), "..."))
     volume.fstype = "?bsd"
     volume._get_blkid_type = mock.Mock(return_value=None)
     volume._get_magic_type = mock.Mock(return_value=None)
     volume.determine_fs_type()
     self.assertEqual("bsd", volume.fstype)
Ejemplo n.º 19
0
    def test_fsdescription(self):
        # Add names in here that are shown in the wild for output of mmls / gparted
        # !! Always try to add it also to test_combination

        descriptions = {
            # Names assigned by imagemounter
            "Logical Volume": "unknown",
            "LUKS Volume": "unknown",
            "BDE Volume": "unknown",
            "RAID Volume": "unknown",
            "VSS Store": "unknown",

            "NTFS / exFAT": "ntfs",  # mmls, should use fallback
            "Linux (0x83)": "unknown",  # should use unknown
            "4.2BSD": "ufs",
            "BSD/386, 386BSD, NetBSD, FreeBSD (0xa5)": "volumesystem",
            "DOS FAT16": "fat",
        }
        for description, fstype in descriptions.items():
            volume = Volume(disk=Disk(ImageParser(), "..."))
            volume._get_blkid_type = mock.Mock(return_value=None)
            volume._get_magic_type = mock.Mock(return_value=None)
            self.fstype = ""  # prevent fallback to unknown by default
            volume.info['fsdescription'] = description
            volume.determine_fs_type()
            self.assertEqual(FILE_SYSTEM_TYPES[fstype], volume.fstype)
Ejemplo n.º 20
0
 def test_guid(self):
     for description, fstype in FILE_SYSTEM_GUIDS.items():
         volume = Volume(disk=Disk(ImageParser(), "..."))
         volume._get_blkid_type = mock.Mock(return_value=None)
         volume._get_magic_type = mock.Mock(return_value=None)
         volume.info['guid'] = description
         volume.determine_fs_type()
         self.assertEqual(fstype, volume.fstype)
Ejemplo n.º 21
0
 def test_no_root(self):
     parser = ImageParser()
     disk = parser.add_disk("...")
     v1 = Volume(disk)
     v1.mountpoint = '...'
     v1.info['lastmountpoint'] = '/etc/x'
     v2 = Volume(disk)
     v2.mountpoint = '....'
     v2.info['lastmountpoint'] = '/etc'
     disk.volumes.volumes = [v1, v2]
     with self.assertRaises(NoRootFoundError):
         parser.reconstruct()
Ejemplo n.º 22
0
    def test_ntfs(self):
        # Removed some items from this output as we don't use it in its entirety anyway
        result = b"""FILE SYSTEM INFORMATION
--------------------------------------------
File System Type: NTFS
Volume Serial Number: 4E8742C12A96CECD
OEM Name: NTFS    
Version: Windows XP"""
        with mock.patch('subprocess.Popen') as mock_popen:
            type(mock_popen()).stdout = mock.PropertyMock(return_value=io.BytesIO(result))

            volume = Volume(disk=Disk(ImageParser(), "..."))
            volume.get_raw_path = mock.Mock(return_value="...")

            volume._load_fsstat_data()

            self.assertEqual(volume.info['statfstype'], 'NTFS')
            self.assertNotIn("lastmountpoint", volume.info)
            self.assertNotIn("label", volume.info)
            self.assertEqual(volume.info['version'], 'Windows XP')
Ejemplo n.º 23
0
 def test_simple(self):
     parser = ImageParser()
     disk = parser.add_disk("...")
     v1 = Volume(disk)
     v1.mountpoint = '...'
     v1.info['lastmountpoint'] = '/'
     v2 = Volume(disk)
     v2.mountpoint = '....'
     v2.info['lastmountpoint'] = '/etc'
     disk.volumes.volumes = [v1, v2]
     with mock.patch.object(v2, "bindmount") as v2_bm:
         parser.reconstruct()
         v2_bm.assert_called_once_with(".../etc")
Ejemplo n.º 24
0
    def test_ntfs(self):
        # Removed some items from this output as we don't use it in its entirety anyway
        result = b"""FILE SYSTEM INFORMATION
--------------------------------------------
File System Type: NTFS
Volume Serial Number: 4E8742C12A96CECD
OEM Name: NTFS    
Version: Windows XP"""
        with mock.patch('subprocess.Popen') as mock_popen:
            type(mock_popen()).stdout = mock.PropertyMock(return_value=io.BytesIO(result))

            volume = Volume(disk=Disk(ImageParser(), "..."))
            volume.get_raw_path = mock.Mock(return_value="...")

            volume._load_fsstat_data()

            self.assertEqual(volume.info['statfstype'], 'NTFS')
            self.assertNotIn("lastmountpoint", volume.info)
            self.assertNotIn("label", volume.info)
            self.assertEqual(volume.info['version'], 'Windows XP')
Ejemplo n.º 25
0
    def _make_subvolume(self, **args):
        """Creates a subvolume, adds it to this class and returns it."""

        from imagemounter.volume import Volume
        v = Volume(
            disk=self.disk,
            parent=self.parent,
            volume_detector=self.volume_detector,
            **args)  # vstype is not passed down, let it decide for itself.
        self.volumes.append(v)
        return v
Ejemplo n.º 26
0
    def test_magic(self):
        # Add values here that are shown in the wild for file magic output
        # !! Always try to add it also to test_combination

        descriptions = {
            "Linux Compressed ROM File System data": "cramfs",
            "Linux rev 1.0 ext2 filesystem data": "ext",

            'DOS/MBR boot sector, code offset 0x3c+2, OEM-ID "mkfs.fat", sectors/cluster 4, '
            'root entries 512, sectors 100 (volumes <=32 MB) , Media descriptor 0xf8, '
            'sectors/FAT 1, sectors/track 32, heads 64, serial number 0x3cb7474b, '
            'label: "TEST       ", FAT (12 bit)': "fat",

            "ISO 9660 CD-ROM filesystem data 'test'": "iso",
            "Minix filesystem, V1, 30 char names, 12800 zones": "minix",

            'DOS/MBR boot sector, code offset 0x52+2, OEM-ID "NTFS    ", sectors/cluster 8, '
            'Media descriptor 0xf8, sectors/track 0, dos < 4.0 BootSector (0x80), FAT (1Y bit '
            'by descriptor); NTFS, sectors 2048, $MFT start cluster 4, $MFTMirror start '
            'cluster 128, bytes/RecordSegment 2^(-1*246), clusters/index block 1, serial '
            'number 04e8742c12a96cecd; contains Microsoft Windows XP/VISTA bootloader BOOTMGR': "ntfs",

            "Squashfs filesystem, little endian, version 4.0": "squashfs",
        }

        for description, fstype in descriptions.items():
            volume = Volume(disk=Disk(ImageParser(), "..."))
            volume._get_blkid_type = mock.Mock(return_value=None)
            volume._get_magic_type = mock.Mock(return_value=description)
            volume.determine_fs_type()
            self.assertEqual(FILE_SYSTEM_TYPES[fstype], volume.fstype)
Ejemplo n.º 27
0
    def test_fsdescription(self):
        # Add names in here that are shown in the wild for output of mmls / gparted
        # !! Always try to add it also to test_combination

        descriptions = {
            # Names assigned by imagemounter
            "Logical Volume": "unknown",
            "LUKS Volume": "unknown",
            "BDE Volume": "unknown",
            "RAID Volume": "unknown",
            "VSS Store": "unknown",

            "NTFS / exFAT": "ntfs",  # mmls, should use fallback
            "Linux (0x83)": "unknown",  # should use unknown
            "4.2BSD": "ufs",
            "BSD/386, 386BSD, NetBSD, FreeBSD (0xa5)": "volumesystem",
            "DOS FAT16": "fat",
        }
        for description, fstype in descriptions.items():
            volume = Volume(disk=Disk(ImageParser(), "..."))
            volume._get_blkid_type = mock.Mock(return_value=None)
            volume._get_magic_type = mock.Mock(return_value=None)
            self.fstype = ""  # prevent fallback to unknown by default
            volume.info['fsdescription'] = description
            volume.determine_fs_type()
            self.assertEqual(FILE_SYSTEM_TYPES[fstype], volume.fstype)
Ejemplo n.º 28
0
    def test_combination(self):
        # Add values here to test full combinations of specific filesystem types
        # The _ as key is the expected result

        _ = "use as key for the expected result"
        definitions = [
            {_: "cramfs", "blkid": "cramfs", "magic": "Linux Compressed ROM File System data", "fsdescription": "???"},
            {_: "exfat", "blkid": "exfat", "fsdescription": "NTFS / exFAT", "statfstype": "exFAT"},
            {_: "ext", "blkid": "ext4", "fsdescription": "Linux (0x83)", "guid": "", "statfstype": "Ext2"},
            {_: "fat", "blkid": "vfat", "magic": "FAT (12 bit)", "fsdescription": "DOS FAT12 (0x04)",
                       "statfstype": "FAT12"},
            {_: "iso", "blkid": "iso9660", "magic": ".. ISO 9660 ..", "statfstype": "ISO9660"},
            {_: "minix", "blkid": "min  ix", "magic": "Minix filesystem", "fsdescription": "???"},
            {_: "ntfs", "blkid": "ntfs", "magic": ".. NTFS ..", "fsdescription": "NTFS / exFAT", "statfstype": "NTFS"},
            {_: "squashfs", "blkid": "squashfs", "magic": "Squashfs filesystem", "fsdescription": "???"},

            {_: "lvm", "guid": "79D3D6E6-07F5-C244-A23C-238F2A3DF928"},
            {_: "raid", "fsdescription": "Linux (0x83)", "blkid": "linux_raid_member"},

            {_: "volumesystem", "blkid": "dos", "fsdescription": "Logical Volume"},
            {_: "volumesystem", "blkid": "dos", "fsdescription": "RAID Volume"},
            {_: "volumesystem", "blkid": "dos", "magic": "DOS/MBR boot sector"},
            {_: "volumesystem", "fsdescription": "BSD/386, 386BSD, NetBSD, FreeBSD (0xa5)", "blkid": "ufs"},
            {_: "ufs", "fsdescription": "4.2BSD (0x07)", "blkid": "ufs"},
        ]

        for definition in definitions:
            volume = Volume(disk=Disk(ImageParser(), "..."))
            volume._get_blkid_type = mock.Mock(return_value=definition.get("blkid"))
            volume._get_magic_type = mock.Mock(return_value=definition.get("magic"))
            volume.info = definition
            volume.determine_fs_type()
            self.assertEqual(FILE_SYSTEM_TYPES[definition[_]], volume.fstype)
Ejemplo n.º 29
0
    def test_blkid(self):
        # Add values here that are shown in the wild for blkid
        # !! Always try to add it also to test_combination

        descriptions = {
            "cramfs": "cramfs",
            "ext4": "ext",
            "ext2": "ext",
            "vfat": "fat",
            "iso9660": "iso",
            "minix": "minix",
            "ntfs": "ntfs",
            "squashfs": "squashfs",
            "ufs": "ufs",

            "dos": "volumesystem",
        }

        for description, fstype in descriptions.items():
            volume = Volume(disk=Disk(ImageParser(), "..."))
            volume._get_blkid_type = mock.Mock(return_value=description)
            volume._get_magic_type = mock.Mock(return_value=None)
            volume.determine_fs_type()
            self.assertEqual(FILE_SYSTEM_TYPES[fstype], volume.fstype)
Ejemplo n.º 30
0
    def test_guid(self):

        FILE_SYSTEM_GUIDS = {
            '2AE031AA-0F40-DB11-9590-000C2911D1B8': 'vmfs',
            # '8053279D-AD40-DB11-BF97-000C2911D1B8': 'vmkcore-diagnostics',
            # '6A898CC3-1DD2-11B2-99A6-080020736631': 'zfs-member',
            # 'C38C896A-D21D-B211-99A6-080020736631': 'zfs-member',
            # '0FC63DAF-8483-4772-8E79-3D69D8477DE4': 'linux',
            'E6D6D379-F507-44C2-A23C-238F2A3DF928': 'lvm',
            '79D3D6E6-07F5-C244-A23C-238F2A3DF928': 'lvm',
            'CA7D7CCB-63ED-4C53-861C-1742536059CC': 'luks'
        }

        for description, fstype in FILE_SYSTEM_GUIDS.items():
            volume = Volume(disk=Disk(ImageParser(), "..."))
            volume._get_blkid_type = mock.Mock(return_value=None)
            volume._get_magic_type = mock.Mock(return_value=None)
            volume.info['guid'] = description
            volume.determine_fs_type()
            self.assertEqual(FILE_SYSTEM_TYPES[fstype], volume.fstype)
Ejemplo n.º 31
0
    def test_guid(self):

        FILE_SYSTEM_GUIDS = {
            '2AE031AA-0F40-DB11-9590-000C2911D1B8': 'vmfs',
            #'8053279D-AD40-DB11-BF97-000C2911D1B8': 'vmkcore-diagnostics',
            #'6A898CC3-1DD2-11B2-99A6-080020736631': 'zfs-member',
            #'C38C896A-D21D-B211-99A6-080020736631': 'zfs-member',
            #'0FC63DAF-8483-4772-8E79-3D69D8477DE4': 'linux',
            'E6D6D379-F507-44C2-A23C-238F2A3DF928': 'lvm',
            '79D3D6E6-07F5-C244-A23C-238F2A3DF928': 'lvm',
            'CA7D7CCB-63ED-4C53-861C-1742536059CC': 'luks'
        }

        for description, fstype in FILE_SYSTEM_GUIDS.items():
            volume = Volume(disk=Disk(ImageParser(), "..."))
            volume._get_blkid_type = mock.Mock(return_value=None)
            volume._get_magic_type = mock.Mock(return_value=None)
            volume.info['guid'] = description
            volume.determine_fs_type()
            self.assertEqual(FILE_SYSTEM_TYPES[fstype], volume.fstype)
Ejemplo n.º 32
0
    def test_blkid(self):
        # Add values here that are shown in the wild for blkid
        # !! Always try to add it also to test_combination

        descriptions = {
            "cramfs": "cramfs",
            "ext4": "ext",
            "ext2": "ext",
            "vfat": "fat",
            "iso9660": "iso",
            "minix": "minix",
            "ntfs": "ntfs",
            "squashfs": "squashfs",
            "ufs": "ufs",
            "dos": "volumesystem",
        }

        for description, fstype in descriptions.items():
            volume = Volume(disk=Disk(ImageParser(), "..."))
            volume._get_blkid_type = mock.Mock(return_value=description)
            volume._get_magic_type = mock.Mock(return_value=None)
            volume.determine_fs_type()
            self.assertEqual(fstype, volume.fstype)
Ejemplo n.º 33
0
    def test_fstype_fallback_unknown(self):
        volume = Volume(disk=Disk(ImageParser(), "..."))
        volume._get_blkid_type = mock.Mock(return_value=None)
        volume._get_magic_type = mock.Mock(return_value=None)
        volume.info['fsdescription'] = "Linux (0x83)"

        # If something more specific is set, we use that
        volume._get_fstype_from_parser('?ufs')
        volume.determine_fs_type()
        self.assertEqual(FILE_SYSTEM_TYPES["ufs"], volume.fstype)

        # Otherwise we fallback to unknown if Linux (0x83) is set
        volume._get_fstype_from_parser('')
        volume.determine_fs_type()
        self.assertEqual(UnknownFileSystemType(), volume.fstype)
Ejemplo n.º 34
0
 def test_valid_fstype(self):
     volume = Volume(disk=Disk(ImageParser(), "..."), fstype='ext')
     volume.determine_fs_type()
     self.assertEqual(FILE_SYSTEM_TYPES['ext'], volume.fstype)
Ejemplo n.º 35
0
    def test_read_bytes_crash(self, mock_open):
        mock_open().__enter__().read.side_effect = IOError
        volume = Volume(disk=Disk(ImageParser(), "..."))
        volume.get_raw_path = mock.Mock(return_value="...")

        self.assertIsNone(volume._get_magic_type())
Ejemplo n.º 36
0
    def test_read_bytes_crash(self, mock_open):
        mock_open().__enter__().read.side_effect = IOError
        volume = Volume(disk=Disk(ImageParser(), "..."))
        volume.get_raw_path = mock.Mock(return_value="...")

        self.assertIsNone(volume._get_magic_type())
Ejemplo n.º 37
0
    def test_fstype_fallback_unknown(self):
        volume = Volume(disk=Disk(ImageParser(), "..."))
        volume._get_blkid_type = mock.Mock(return_value=None)
        volume._get_magic_type = mock.Mock(return_value=None)
        volume.info['fsdescription'] = "Linux (0x83)"

        # If something more specific is set, we use that
        volume._get_fstype_from_parser('?ufs')
        volume.determine_fs_type()
        self.assertEqual(FILE_SYSTEM_TYPES["ufs"], volume.fstype)

        # Otherwise we fallback to unknown if Linux (0x83) is set
        volume._get_fstype_from_parser('')
        volume.determine_fs_type()
        self.assertEqual(UnknownFileSystemType(), volume.fstype)
Ejemplo n.º 38
0
 def test_valid_vstype(self):
     volume = Volume(disk=Disk(ImageParser(), "..."), fstype="dos")
     volume.determine_fs_type()
     self.assertEqual("dos", volume.volumes.vstype)
     self.assertEqual(FILE_SYSTEM_TYPES["volumesystem"], volume.fstype)
Ejemplo n.º 39
0
 def test_valid_vstype(self):
     volume = Volume(disk=Disk(ImageParser(), "..."), fstype="dos")
     volume.determine_fs_type()
     self.assertEqual("dos", volume.volumes.vstype)
     self.assertEqual(FILE_SYSTEM_TYPES["volumesystem"], volume.fstype)
Ejemplo n.º 40
0
    def _mount_pytsk3_volumes(self):
        """Generator that mounts every partition of this image and yields the mountpoint."""

        # Loop over all volumes in image.
        for p in self._find_pytsk3_volumes():
            import pytsk3

            volume = Volume(disk=self, **self.args)
            self.volumes.append(volume)

            # Fill volume with more information
            volume.offset = p.start * self.block_size
            volume.fsdescription = p.desc.strip()
            if self.index is not None:
                volume.index = '{0}.{1}'.format(self.index, p.addr)
            else:
                volume.index = p.addr
            volume.size = p.len * self.block_size

            if p.flags == pytsk3.TSK_VS_PART_FLAG_ALLOC:
                volume.flag = 'alloc'
                volume.slot = _util.determine_slot(p.table_num, p.slot_num)
                self._assign_disktype_data(volume)
                logger.info("Found allocated {2}: block offset: {0}, length: {1} ".format(p.start, p.len,
                                                                                          volume.fsdescription))
            elif p.flags == pytsk3.TSK_VS_PART_FLAG_UNALLOC:
                volume.flag = 'unalloc'
                logger.info("Found unallocated space: block offset: {0}, length: {1} ".format(p.start, p.len))
            elif p.flags == pytsk3.TSK_VS_PART_FLAG_META:
                volume.flag = 'meta'
                logger.info("Found meta volume: block offset: {0}, length: {1} ".format(p.start, p.len))

            # unalloc / meta partitions do not have stats and can not be mounted
            if volume.flag != 'alloc':
                yield volume
                continue

            for v in volume.init():
                yield v
Ejemplo n.º 41
0
    def _mount_mmls_volumes(self):
        """Finds and mounts all volumes based on mmls."""

        try:
            cmd = ['mmls']
            if self.vstype != 'detect':
                cmd.extend(['-t', self.vstype])
            cmd.append(self.get_raw_path())
            output = _util.check_output_(cmd, stderr=subprocess.STDOUT)
            self.volume_source = 'multi'
        except Exception as e:
            # some bug in sleuthkit makes detection sometimes difficult, so we hack around it:
            if hasattr(e, 'output') and "(GPT or DOS at 0)" in e.output.decode() and self.vstype != 'gpt':
                self.vstype = 'gpt'
                try:
                    logger.warning("Error in retrieving volume info: mmls couldn't decide between GPT and DOS, "
                                   "choosing GPT for you. Use --vstype=dos to force DOS.", exc_info=True)
                    cmd = ['mmls', '-t', self.vstype, self.get_raw_path()]
                    output = _util.check_output_(cmd, stderr=subprocess.STDOUT)
                    self.volume_source = 'multi'
                except Exception as e:
                    logger.exception("Failed executing mmls command")
                    return
            else:
                logger.exception("Failed executing mmls command")
                return

        output = output.split("Description", 1)[-1]
        for line in output.splitlines():
            if not line:
                continue
            try:
                values = line.split(None, 5)

                # sometimes there are only 5 elements available
                description = ''
                index, slot, start, end, length = values[0:5]
                if len(values) > 5:
                    description = values[5]

                volume = Volume(disk=self, **self.args)
                self.volumes.append(volume)

                volume.offset = int(start) * self.block_size
                volume.fsdescription = description
                if self.index is not None:
                    volume.index = '{0}.{1}'.format(self.index, int(index[:-1]))
                else:
                    volume.index = int(index[:-1])
                volume.size = int(length) * self.block_size
            except Exception as e:
                logger.exception("Error while parsing mmls output")
                continue

            if slot.lower() == 'meta':
                volume.flag = 'meta'
                logger.info("Found meta volume: block offset: {0}, length: {1}".format(start, length))
            elif slot.lower() == '-----':
                volume.flag = 'unalloc'
                logger.info("Found unallocated space: block offset: {0}, length: {1}".format(start, length))
            else:
                volume.flag = 'alloc'
                if ":" in slot:
                    volume.slot = _util.determine_slot(*slot.split(':'))
                else:
                    volume.slot = _util.determine_slot(-1, slot)
                self._assign_disktype_data(volume)
                logger.info("Found allocated {2}: block offset: {0}, length: {1} ".format(start, length,
                                                                                          volume.fsdescription))

            # unalloc / meta partitions do not have stats and can not be mounted
            if volume.flag != 'alloc':
                yield volume
                continue

            for v in volume.init():
                yield v
Ejemplo n.º 42
0
    def test_fstype_fallback_unknown(self):
        volume = Volume(disk=Disk(ImageParser(), "..."))
        volume._get_blkid_type = mock.Mock(return_value=None)
        volume._get_magic_type = mock.Mock(return_value=None)
        volume.info['fsdescription'] = "Linux (0x83)"

        # If something more specific is set, we use that
        volume.fstype = "?bsd"
        volume.determine_fs_type()
        self.assertEqual("bsd", volume.fstype)

        # Otherwise we fallback to unknown if Linux (0x83) is set
        volume.fstype = ""
        volume.determine_fs_type()
        self.assertEqual("unknown", volume.fstype)
Ejemplo n.º 43
0
 def test_valid_fstype(self):
     volume = Volume(disk=Disk(ImageParser(), "..."))
     volume.fstype = 'ext'
     volume.determine_fs_type()
     self.assertEqual("ext", volume.fstype)
Ejemplo n.º 44
0
 def test_little_clue_fstype(self):
     volume = Volume(disk=Disk(ImageParser(), "..."))
     volume._get_blkid_type = mock.Mock(return_value="-")
     volume._get_magic_type = mock.Mock(return_value="-")
     volume.determine_fs_type()
     self.assertEqual(UnknownFileSystemType(), volume.fstype)
Ejemplo n.º 45
0
 def test_little_clue_fstype(self):
     volume = Volume(disk=Disk(ImageParser(), "..."))
     volume._get_blkid_type = mock.Mock(return_value="-")
     volume._get_magic_type = mock.Mock(return_value="-")
     volume.determine_fs_type()
     self.assertEqual(UnknownFileSystemType(), volume.fstype)
Ejemplo n.º 46
0
 def test_multiple_roots(self):
     parser = ImageParser()
     disk = parser.add_disk("...")
     v1 = Volume(disk)
     v1.index = '1'
     v1.mountpoint = '...'
     v1.info['lastmountpoint'] = '/'
     v2 = Volume(disk)
     v2.index = '2'
     v2.mountpoint = '....'
     v2.info['lastmountpoint'] = '/'
     v3 = Volume(disk)
     v3.index = '3'
     v3.mountpoint = '.....'
     v3.info['lastmountpoint'] = '/etc'
     disk.volumes.volumes = [v1, v2, v3]
     with mock.patch.object(v1, "bindmount") as v1_bm, mock.patch.object(v2, "bindmount") as v2_bm, \
             mock.patch.object(v3, "bindmount") as v3_bm:
         parser.reconstruct()
         v1_bm.assert_not_called()
         v2_bm.assert_not_called()
         v3_bm.assert_called_with('.../etc')
Ejemplo n.º 47
0
 def test_valid_fstype(self):
     volume = Volume(disk=Disk(ImageParser(), "..."), fstype='ext')
     volume.determine_fs_type()
     self.assertEqual(FILE_SYSTEM_TYPES['ext'], volume.fstype)
Ejemplo n.º 48
0
    def _mount_parted_volumes(self):
        """Finds and mounts all volumes based on parted."""

        # for some reason, parted does not properly return extended volume types in its machine
        # output, so we need to execute it twice.
        meta_volumes = []
        try:
            output = _util.check_output_(['parted', self.get_raw_path(), 'print'])
            for line in output.splitlines():
                if 'extended' in line:
                    meta_volumes.append(int(line.split()[0]))
        except Exception:
            logger.exception("Failed executing parted command.")
            # skip detection of meta volumes

        try:
            # parted does not support passing in the vstype. It either works, or it doesn't.
            cmd = ['parted', self.get_raw_path(), '-sm', 'unit s', 'print free']
            output = _util.check_output_(cmd)
            self.volume_source = 'multi'
        except Exception as e:
            logger.exception("Failed executing parted command")
            return

        num = 0
        for line in output.splitlines():
            if line.startswith("Warning") or not line or ':' not in line or line.startswith(self.get_raw_path()):
                continue
            line = line[:-1]  # remove last ;
            try:
                slot, start, end, length, description = line.split(':', 4)
                if ':' in description:
                    description, label, flags = description.split(':', 2)
                else:
                    description, label, flags = description, '', ''

                volume = Volume(disk=self, **self.args)
                self.volumes.append(volume)
                volume.offset = int(start[:-1]) * self.block_size  # remove last s
                volume.size = int(length[:-1]) * self.block_size
                volume.fsdescription = description
                if self.index is not None:
                    volume.index = '{0}.{1}'.format(self.index, num)
                else:
                    volume.index = num

                # TODO: detection of meta volumes

                if description == 'free':
                    volume.flag = 'unalloc'
                    logger.info("Found unallocated space: block offset: {0}, length: {1}".format(start[:-1], length[:-1]))
                elif int(slot) in meta_volumes:
                    volume.flag = 'meta'
                    volume.slot = int(slot)
                    logger.info("Found meta volume: block offset: {0}, length: {1}".format(start[:-1], length[:-1]))
                else:
                    volume.flag = 'alloc'
                    volume.slot = int(slot)
                    self._assign_disktype_data(volume)
                    logger.info("Found allocated {2}: block offset: {0}, length: {1} ".format(start[:-1], length[:-1],
                                                                                              volume.fsdescription))
            except AttributeError as e:
                logger.exception("Error while parsing parted output")
                continue

            num += 1

            # unalloc / meta partitions do not have stats and can not be mounted
            if volume.flag != 'alloc':
                yield volume
                continue

            for v in volume.init():
                yield v
Ejemplo n.º 49
0
 def test_valid_vstype(self):
     volume = Volume(disk=Disk(ImageParser(), "..."))
     volume.fstype = 'dos'
     volume.determine_fs_type()
     self.assertEqual("dos", volume.volumes.vstype)
     self.assertEqual("volumesystem", volume.fstype)
Ejemplo n.º 50
0
 def test_no_clue_fstype(self):
     volume = Volume(disk=Disk(ImageParser(), "..."))
     volume._get_blkid_type = mock.Mock(return_value=None)
     volume._get_magic_type = mock.Mock(return_value=None)
     volume.determine_fs_type()
     self.assertEqual("unknown", volume.fstype)
Ejemplo n.º 51
0
 def test_no_clue_fstype(self):
     volume = Volume(disk=Disk(ImageParser(), "..."))
     volume._get_blkid_type = mock.Mock(return_value=None)
     volume._get_magic_type = mock.Mock(return_value=None)
     volume.determine_fs_type()
     self.assertEqual(UnknownFileSystem, volume.filesystem.__class__)