Пример #1
0
    def run(self, path=""):
        """ Parse UsnJrnl files of a disk """
        self.vss = self.myflag('vss')
        disk = getSourceImage(self.myconfig)

        self.usn_path = self.myconfig(
            'voutdir') if self.vss else self.myconfig('outdir')
        check_folder(self.usn_path)
        self.usn_jrnl_file = os.path.join(self.usn_path, "UsnJrnl")
        self.filesystem = FileSystem(self.config, disk=disk)

        for p in disk.partitions:
            if not p.isMountable:
                continue
            if not self.vss:
                pname = ''.join(['p', p.partition])
                self._parse_usnjrnl(pname)
            else:
                for v, dev in p.vss.items():
                    if dev == "":
                        continue
                    self._parse_usnjrnl(v)

        # Delete the temporal UsnJrnl dumped file
        if os.path.exists(self.usn_jrnl_file):
            os.remove(self.usn_jrnl_file)
        return []
Пример #2
0
    def vss_mount(self):
        vshadowmount = self.myconfig('vshadowmount',
                                     '/usr/local/bin/vshadowmount')

        if len(self.vss) > 0:
            vp = os.path.join(self.mountaux, "vp%s" % self.partition)
            if len(self.fuse) == 0 or "/dev/fuse" not in self.fuse.keys():
                check_folder(vp)
                if self.encrypted:
                    run_command([
                        "sudo", vshadowmount, "-X", "allow_root", self.loop, vp
                    ],
                                logger=self.logger)
                else:
                    run_command([
                        vshadowmount, "-X", "allow_root", self.imagefile, "-o",
                        str(self.obytes), vp
                    ],
                                logger=self.logger)
            for p in self.vss.keys():
                if self.vss[p] == "":
                    mp = os.path.join(self.mountdir, p)
                    self.mount_NTFS(imagefile=os.path.join(
                        vp, "vss%s" % p[1:].split("p")[0]),
                                    mountpath=mp,
                                    offset=False)
        self.refreshMountedImages()
Пример #3
0
    def mount_NTFS(self, imagefile=None, mountpath=None, offset=True):
        """ mount NTFS partition

        Confiugration section:
            :ntfs_args: arguments for mount. offset and sizelimit will be automatically appended to these arguments.
                This parameter will be managed as a format string. The current group id will be passed as an option `gid`.

        Args:
            imagefile (str): imagefile path (used for auxiliary mount point). If None, use self.imagefile.
            mountpath (str): mount the image on this path. If None, use `source/mnt/pXX`.
            offset (bool): Used to ignore disk offset (used for auxiliary mount point)
        """
        args = self.myconfig('ntfs_args').format(
            gid=grp.getgrgid(os.getegid())[2])
        if offset and self.obytes != 0:
            args = "%s,offset=%s,sizelimit=%s" % (args, self.obytes, self.size)
        mount = self.myconfig('mount', '/bin/mount')
        if not mountpath:
            mountpath = os.path.join(self.mountdir, "p%s" % self.partition)
        if not imagefile:
            imagefile = self.imagefile
        check_folder(mountpath)
        run_command(
            ["sudo", mount, imagefile, "-t", "ntfs-3g", "-o", args, mountpath],
            logger=self.logger)
Пример #4
0
    def run(self, path=""):
        """ Parses lnk files, jumlists and customdestinations

        """
        self.logger().info("Extraction of lnk files")

        self.Files = GetFiles(self.config, vss=self.myflag("vss"))
        self.filesystem = FileSystem(self.config)
        self.mountdir = self.myconfig('mountdir')

        lnk_path = self.myconfig('{}outdir'.format('v' if self.vss else ''))
        check_folder(lnk_path)

        users = get_user_list(self.mountdir, self.vss)
        artifacts = {
            'lnk': {
                'filename': "{}_lnk.csv",
                'regex': r"{}/.*\.lnk$",
                'function': self.lnk_parser
            },
            'autodest': {
                'filename': "{}_jl.csv",
                'regex': r"{}/.*\.automaticDestinations-ms$",
                'function': self.automaticDest_parser
            },
            'customdest': {
                'filename': "{}_jlcustom.csv",
                'regex': r"{}/.*\.customDestinations-ms$",
                'function': self.customDest_parser
            }
        }

        for user in users:
            usr = "******".format(user.split("/")[0], user.split("/")[2])

            for a_name, artifact in artifacts.items():
                out_file = os.path.join(lnk_path,
                                        artifact['filename'].format(usr))
                files_list = list(
                    self.Files.search(artifact['regex'].format(user)))
                self.logger().info(
                    "Founded {} {} files for user {} at {}".format(
                        len(files_list), a_name,
                        user.split("/")[-1],
                        user.split("/")[0]))
                if len(files_list) > 0:
                    save_csv(artifact['function'](files_list),
                             config=self.config,
                             outfile=out_file,
                             quoting=0,
                             file_exists='OVERWRITE')
                    self.logger().info(
                        "{} extraction done for user {} at {}".format(
                            a_name,
                            user.split("/")[-1],
                            user.split("/")[0]))

        self.logger().info("RecentFiles extraction done")
        return []
Пример #5
0
 def mount_APFS(self):
     apfsmount = self.myconfig('apfsmount', '/usr/local/bin/apfs-fuse')
     mountpath = os.path.join(self.mountaux, "p%s" % self.partition)
     check_folder(mountpath)
     run_command([
         "sudo", apfsmount, "-s",
         str(self.obytes), "-v",
         str(self.voln), self.imagefile, mountpath
     ],
                 logger=self.logger)
     self.bindfs_mount()
Пример #6
0
    def bindfs_mount(self):
        user = getpass.getuser()
        group = grp.getgrgid(os.getegid())[0]

        mountaux = os.path.join(self.mountaux, "p%s" % self.partition)
        check_folder(self.mountpath)
        bindfs = self.myconfig('bindfs', '/usr/bin/bindfs')
        run_command([
            "sudo", bindfs, "-p", "550", "-u", user, "-g", group, mountaux,
            self.mountpath
        ],
                    logger=self.logger)
Пример #7
0
 def mount_fat(self, imagefile=None, mountpath=None, offset=True):
     args = self.myconfig('fat_args').format(
         gid=grp.getgrgid(os.getegid())[0])
     if offset and self.obytes != 0:
         args = "%s,offset=%s,sizelimit=%s" % (args, self.obytes, self.size)
     mount = self.myconfig('mount', '/bin/mount')
     if not mountpath:
         mountpath = os.path.join(self.mountdir, "p%s" % self.partition)
     if not imagefile:
         imagefile = self.imagefile
     check_folder(mountpath)
     run_command(["sudo", mount, self.imagefile, "-o", args, mountpath],
                 logger=self.logger)
Пример #8
0
 def mount_ext(self):
     mount = self.myconfig('mount', '/bin/mount')
     mountpath = os.path.join(self.mountaux, "p%s" % self.partition)
     check_folder(mountpath)
     args = "%s,sizelimit=%s" % (self.myconfig('ext4_args'), self.size)
     if self.obytes != 0:
         args = "%s,offset=%s,sizelimit=%s" % (self.myconfig('ext4_args'),
                                               self.obytes, self.size)
     try:
         run_command(["sudo", mount, self.imagefile, "-o", args, mountpath],
                     logger=self.logger)
     except Exception:
         args = args + ',norecovery'
         run_command(["sudo", mount, self.imagefile, "-o", args, mountpath],
                     logger=self.logger)
     self.bindfs_mount()
Пример #9
0
    def mount_bitlocker(self):
        if 'dislocker' in self.fuse.keys():
            self.logger.info("Bitlocker partition p{} already mounted".format(
                self.partition))
            return
        rec_key = self.myconfig('recovery_keys')
        dislocker = self.myconfig('dislocker', '/usr/bin/dislocker')
        mountauxpath = os.path.join(self.mountaux, "p%s" % self.partition)
        check_folder(mountauxpath)
        import time

        if rec_key == "":
            self.logger.warning(
                "Recovery key not available on partition p%s. Trying without key"
                % self.partition)
            try:
                cmd = "sudo {} -c -O {} -V {} -r {}".format(
                    dislocker, self.obytes, self.imagefile, mountauxpath)
                run_command(cmd, logger=self.logger)
                time.sleep(4)
                self.refreshMountedImages()
                self.mount_NTFS(os.path.join(mountauxpath, "dislocker-file"),
                                offset=False)
            except Exception:
                self.logger.error("Problems mounting partition p%s" %
                                  self.partition)
                return -1
        else:
            self.logger.info("Trying to mount with recovery keys at {}".format(
                self.mountaux))
            mountauxpath = os.path.join(self.mountaux, "p%s" % self.partition)
            for rk in rec_key.split(
                    ','):  # loop wih different recovery keys, comma separated
                try:
                    cmd = "sudo {} -p{} -O {} -V {} -r {}".format(
                        dislocker, rk, self.obytes, self.imagefile,
                        mountauxpath)
                    run_command(cmd, logger=self.logger)
                    time.sleep(4)
                    self.refreshMountedImages()
                    self.mount_NTFS(os.path.join(mountauxpath,
                                                 "dislocker-file"),
                                    offset=False)
                    break
                except Exception:
                    pass
Пример #10
0
 def _getRawImagefile(self):
     # convert an Encase image to dd using ewfmount
     fuse_path = os.path.join(self.params('mountauxdir'), "encase")
     imagefile = os.path.join(fuse_path, "ewf1")
     self.auxdirectories.append(fuse_path)
     if not os.path.exists(imagefile):
         ewfmount = self.params('ewfmount', '/usr/bin/ewfmount')
         check_folder(fuse_path)
         try:
             run_command(
                 [ewfmount, self.imagefile, "-X", "allow_root", fuse_path])
         except Exception:
             self.logger.error("Cannot mount Encase imagefile=%s",
                               self.imagefile)
             raise base.job.RVTError(
                 "Cannot mount Encase imagefile={}".format(self.imagefile))
     return imagefile
Пример #11
0
    def mount_HFS(self, imagefile="", mountpath="", offset=True):
        # TODO: avoid infinite recursion if mount fails after having called fvdemount
        if mountpath == "":
            mountpath = os.path.join(self.mountaux, "p%s" % self.partition)
        if imagefile == "":
            imagefile = self.imagefile

        mount = self.myconfig('mount', '/bin/mount')
        check_folder(mountpath)
        args = "%s,sizelimit=%s" % (self.myconfig('hfs_args'), self.size)
        if offset and self.obytes != 0:
            args = "%s,offset=%s,sizelimit=%s" % (self.myconfig('hfs_args'),
                                                  self.obytes, self.size)
        try:
            run_command(["sudo", mount, imagefile, "-o", args, mountpath],
                        logger=self.logger)
            self.bindfs_mount()
        except Exception:
            self.fvde_mount()
Пример #12
0
 def _getRawImagefile(self):
     fuse_path = os.path.join(self.params('mountauxdir'), "aff")
     imagefile = os.path.join(fuse_path,
                              "%s.raw" % os.path.basename(self.imagefile))
     self.auxdirectories.append(fuse_path)
     if not os.path.exists(imagefile):
         affuse = self.params('affuse', '/usr/bin/affuse')
         check_folder(fuse_path)
         try:
             run_command(["sudo", affuse, self.imagefile, fuse_path])
             fuse_path = os.path.join(self.params('mountauxdir'), "aff")
             imagefile = os.path.join(
                 fuse_path, "%s.raw" % os.path.basename(self.imagefile))
         except Exception:
             self.logger.error("Cannot mount AFF imagefile=%s",
                               self.imagefile)
             raise base.job.RVTError("Cannot mount AFF imagefile={}".format(
                 self.imagefile))
     return imagefile
Пример #13
0
 def fvde_mount(self):
     self.logger.debug('Obtaining encrypted partition')
     fvdemount = self.myconfig('fvdemount', '/usr/local/bin/fvdemount')
     password = self.myconfig('password')
     mountpoint = os.path.join(self.mountaux, "vp%s" % self.partition)
     check_folder(mountpoint)
     # TODO: get 'EncryptedRoot.plist.wipekey' from recovery partition: https://github.com/libyal/libfvde/wiki/Mounting
     encryptedfile = os.path.join(self.myconfig('sourcedir'),
                                  'EncryptedRoot.plist.wipekey')
     run_command([
         'sudo', fvdemount, "-e", encryptedfile, "-p", password, "-X",
         "allow_root", "-o",
         str(self.obytes), self.imagefile, mountpoint
     ],
                 logger=self.logger)
     time.sleep(2)  # let it do his work
     self.mount_HFS(imagefile=os.path.join(mountpoint, 'fvde1'),
                    mountpath=os.path.join(self.mountaux,
                                           "p%s" % self.partition),
                    offset=False)
Пример #14
0
    def run(self, path=""):
        """ Creates a report based on the output of LnkExtract.

        """
        vss = self.myflag('vss')
        self.logger().info("Generating lnk files report")

        self.mountdir = self.myconfig('mountdir')

        lnk_path = self.config.get('plugins.windows.RVT_lnk.LnkExtract',
                                   '{}outdir'.format('v' * vss))
        report_lnk_path = self.myconfig('{}outdir'.format('v' * vss))

        check_directory(lnk_path, error_missing=True)
        check_folder(report_lnk_path)

        outfile = os.path.join(report_lnk_path, 'recentfiles.csv')
        save_csv(self.report_recent(lnk_path),
                 config=self.config,
                 outfile=outfile,
                 quoting=0)

        return []
Пример #15
0
    def run(self, path=None):
        """ The path is ignored, and the source image is used. """
        vss = self.myflag('vss')
        fls = self.myconfig('fls', 'fls')
        apfs_fls = self.myconfig('apfs_fls', 'fls')
        mactime = self.myconfig('mactime', 'mactime')

        disk = getSourceImage(self.myconfig)

        tl_path = self.myconfig('outdir')
        if vss:
            tl_path = self.myconfig('voutdir')

        check_folder(tl_path)

        if not vss:
            self.logger().info("Generating BODY file for %s", disk.disknumber)
            body = os.path.join(tl_path, "{}_BODY.csv".format(disk.disknumber))

            # create the body file
            with open(body, "wb") as f:
                for p in disk.partitions:
                    mountpath = base.utils.relative_path(
                        p.mountpath, self.myconfig('casedir'))

                    if not p.isMountable:
                        continue
                    if not disk.sectorsize:
                        # unkwown sector size
                        run_command([
                            fls, "-s", "0", "-m", mountpath, "-r", "-o",
                            str(p.osects), "-i", "raw", disk.imagefile
                        ],
                                    stdout=f,
                                    logger=self.logger())
                    elif p.filesystem == "NoName":
                        # APFS filesystems are identified as NoName, according to our experience
                        try:
                            run_command([
                                apfs_fls, "-B",
                                str(p.block_number), "-s", "0", "-m",
                                mountpath, "-r", "-o",
                                str(p.osects), "-b",
                                str(disk.sectorsize), "-i", "raw",
                                disk.imagefile
                            ],
                                        stdout=f,
                                        logger=self.logger())
                        except Exception:
                            # sometimes, APFS filesystems report a wrong offset. Try again with offset*8
                            run_command([
                                apfs_fls, "-B",
                                str(p.block_number), "-s", "0", "-m",
                                mountpath, "-r", "-o",
                                str(p.osects * 8), "-b",
                                str(disk.sectorsize), "-i", "raw",
                                disk.imagefile
                            ],
                                        stdout=f,
                                        logger=self.logger())
                    else:
                        # we know the sector size
                        if p.encrypted:
                            run_command([
                                fls, "-s", "0", "-m", mountpath, "-r", "-b",
                                str(disk.sectorsize), p.loop
                            ],
                                        stdout=f,
                                        logger=self.logger())
                        else:
                            run_command([
                                fls, "-s", "0", "-m", mountpath, "-r", "-o",
                                str(p.osects), "-b",
                                str(disk.sectorsize), disk.imagefile
                            ],
                                        stdout=f,
                                        logger=self.logger())

            # create the timeline using mactime
            self.logger().info("Creating timeline of {}".format(
                disk.disknumber))
            hsum = os.path.join(tl_path, "%s_hour_sum.csv" % disk.disknumber)
            fcsv = os.path.join(tl_path, "%s_TL.csv" % disk.disknumber)
            with open(fcsv, "wb") as f:
                run_command([
                    mactime, "-b", body, "-m", "-y", "-d", "-i", "hour", hsum
                ],
                            stdout=f,
                            logger=self.logger())
            run_command(['sed', '-i', '1,2d',
                         hsum])  # Delete header because full path is included
        else:
            # generate body and timeline for each VSS in the disk
            for p in disk.partitions:
                for v, dev in p.vss.items():
                    if dev != "":
                        self.logger().info(
                            "Generating BODY file for {}".format(v))
                        body = os.path.join(tl_path, "{}_BODY.csv".format(v))

                        with open(body, "wb") as f:
                            mountpath = base.utils.relative_path(
                                p.mountpath, self.myconfig('casedir'))
                            run_command([
                                fls, "-s", "0", "-m",
                                "%s" % mountpath, "-r", dev
                            ],
                                        stdout=f,
                                        logger=self.logger())

                        self.logger().info(
                            "Creating timeline for {}".format(v))
                        hsum = os.path.join(tl_path, "%s_hour_sum.csv" % v)
                        fcsv = os.path.join(tl_path, "%s_TL.csv" % v)
                        with open(fcsv, "wb") as f:
                            run_command([
                                mactime, "-b", body, "-m", "-y", "-d", "-i",
                                "hour", hsum
                            ],
                                        stdout=f,
                                        logger=self.logger())
                        run_command([
                            'sed', '-i', '1,2d', hsum
                        ])  # Delete header because full path is included

        self.logger().info("Timelines generation done!")
        return []