class Test(unittest.TestCase):
    def setUp(self):
        self.tempdir = tempfile.mkdtemp()
        self.emptymd5 = hashlib.md5('').hexdigest()

        (fd1, self.f1) = tempfile.mkstemp(dir=self.tempdir)
        os.close(fd1)
        self.emptybasicfile = BasicFile(self.f1)

        (fd2, self.f2) = tempfile.mkstemp(dir=self.tempdir)
        self.content = "I'm here and I'm ready. They're not. Bring it."
        os.write(fd2, self.content)
        os.close(fd2)
        self.basicfile = BasicFile(self.f2)

    def tearDown(self):
        shutil.rmtree(self.tempdir)

    def test_basicfile_init(self):
        self.assertEqual(self.emptybasicfile.md5, self.emptymd5)
        self.assertEqual(self.emptybasicfile.len, 0)
        self.assertEqual(self.emptybasicfile.bitlen, 0)
        self.assertEqual(self.basicfile.md5,
                         'b8a17b44dec164d67685a9fe9817da90')
        self.assertEqual(self.basicfile.len, len(self.content))
        self.assertEqual(self.basicfile.bitlen, 8 * len(self.content))

    def test_refresh(self):
        fd = open(self.emptybasicfile.path, 'w')
        fd.write('Boom, crush. Night, losers. Winning, duh. ')
        fd.close()

        self.assertEqual(self.emptybasicfile.md5, self.emptymd5)
        self.assertEqual(self.emptybasicfile.len, 0)
        self.assertEqual(self.emptybasicfile.bitlen, 0)
        self.emptybasicfile.refresh()
        self.assertEqual(self.emptybasicfile.md5,
                         '0281570ea703d7e39dab89319fe96202')
        self.assertEqual(self.emptybasicfile.len, 42)
        self.assertEqual(self.emptybasicfile.bitlen, 8 * 42)

    def test_read(self):
        self.assertEqual(self.basicfile.read(), self.content)

        # nonexistent file should raise an exception
        os.remove(self.basicfile.path)
        self.assertFalse(os.path.exists(self.basicfile.path))
        self.assertRaises(Exception, self.basicfile.read)

    def test_exists(self):
        self.assertTrue(self.emptybasicfile.exists())
        self.assertTrue(self.basicfile.exists())
        os.remove(self.f1)
        self.assertFalse(self.emptybasicfile.exists())
        self.assertTrue(self.basicfile.exists())
        os.remove(self.f2)
        self.assertFalse(self.emptybasicfile.exists())
        self.assertFalse(self.basicfile.exists())
class Test(unittest.TestCase):

    def setUp(self):
        self.tempdir = tempfile.mkdtemp()
        self.emptymd5 = hashlib.md5('').hexdigest()

        (fd1, self.f1) = tempfile.mkstemp(dir=self.tempdir)
        os.close(fd1)
        self.emptybasicfile = BasicFile(self.f1)

        (fd2, self.f2) = tempfile.mkstemp(dir=self.tempdir)
        self.content = "I'm here and I'm ready. They're not. Bring it."
        os.write(fd2, self.content)
        os.close(fd2)
        self.basicfile = BasicFile(self.f2)

    def tearDown(self):
        shutil.rmtree(self.tempdir)

    def test_basicfile_init(self):
        self.assertEqual(self.emptybasicfile.md5, self.emptymd5)
        self.assertEqual(self.emptybasicfile.len, 0)
        self.assertEqual(self.emptybasicfile.bitlen, 0)
        self.assertEqual(self.basicfile.md5, 'b8a17b44dec164d67685a9fe9817da90')
        self.assertEqual(self.basicfile.len, len(self.content))
        self.assertEqual(self.basicfile.bitlen, 8 * len(self.content))

    def test_refresh(self):
        fd = open(self.emptybasicfile.path, 'w')
        fd.write('Boom, crush. Night, losers. Winning, duh. ')
        fd.close()

        self.assertEqual(self.emptybasicfile.md5, self.emptymd5)
        self.assertEqual(self.emptybasicfile.len, 0)
        self.assertEqual(self.emptybasicfile.bitlen, 0)
        self.emptybasicfile.refresh()
        self.assertEqual(self.emptybasicfile.md5, '0281570ea703d7e39dab89319fe96202')
        self.assertEqual(self.emptybasicfile.len, 42)
        self.assertEqual(self.emptybasicfile.bitlen, 8 * 42)

    def test_read(self):
        self.assertEqual(self.basicfile.read(), self.content)

        # nonexistent file should raise an exception
        os.remove(self.basicfile.path)
        self.assertFalse(os.path.exists(self.basicfile.path))
        self.assertRaises(Exception, self.basicfile.read)

    def test_exists(self):
        self.assertTrue(self.emptybasicfile.exists())
        self.assertTrue(self.basicfile.exists())
        os.remove(self.f1)
        self.assertFalse(self.emptybasicfile.exists())
        self.assertTrue(self.basicfile.exists())
        os.remove(self.f2)
        self.assertFalse(self.emptybasicfile.exists())
        self.assertFalse(self.basicfile.exists())
    def setUp(self):
        self.tempdir = tempfile.mkdtemp()
        self.emptymd5 = hashlib.md5('').hexdigest()

        (fd1, self.f1) = tempfile.mkstemp(dir=self.tempdir)
        os.close(fd1)
        self.emptybasicfile = BasicFile(self.f1)

        (fd2, self.f2) = tempfile.mkstemp(dir=self.tempdir)
        self.content = "I'm here and I'm ready. They're not. Bring it."
        os.write(fd2, self.content)
        os.close(fd2)
        self.basicfile = BasicFile(self.f2)
    def setUp(self):
        self.tempdir = tempfile.mkdtemp()
        self.emptymd5 = hashlib.md5('').hexdigest()

        (fd1, self.f1) = tempfile.mkstemp(dir=self.tempdir)
        os.close(fd1)
        self.emptybasicfile = BasicFile(self.f1)

        (fd2, self.f2) = tempfile.mkstemp(dir=self.tempdir)
        self.content = "I'm here and I'm ready. They're not. Bring it."
        os.write(fd2, self.content)
        os.close(fd2)
        self.basicfile = BasicFile(self.f2)
Example #5
0
    def copy_files_to_temp(self):
        if self.fuzzedfile and self.copy_fuzzedfile:
            filetools.copy_file(self.fuzzedfile.path, self.tempdir)
        else:
            # We're in verify mode. Set the fuzzedfile to be the seedfile,
            # since we didn't mutate anything
            self.fuzzedfile = self.seedfile

        if self.seedfile:
            filetools.copy_file(self.seedfile.path, self.tempdir)

        # TODO: This seems hacky. Should be better way to have
        # minimizer_log.txt and core files survive update_crash_details
        minlog = os.path.join(self.fuzzedfile.dirname, 'minimizer_log.txt')
        if os.path.exists(minlog):
            filetools.copy_file(minlog, self.tempdir)

        corefile = os.path.join(self.workdir_base, 'core')
        if os.path.exists(corefile):
            filetools.copy_file(corefile, self.tempdir)

        calltracefile = os.path.join(self.fuzzedfile.dirname,
                                     '%s.calltrace' % self.fuzzedfile.basename)
        if os.path.exists(calltracefile):
            filetools.copy_file(calltracefile, self.tempdir)

        new_fuzzedfile = os.path.join(self.tempdir, self.fuzzedfile.basename)
        self.fuzzedfile = BasicFile(new_fuzzedfile)
Example #6
0
    def _crash_builder(self):
        self.logger.debug('Building new testcase object.')

        # copy our original testcase as the basis for the new testcase
        new_testcase = copy.deepcopy(self.testcase)

        # get a new dir for the next crasher
        newcrash_tmpdir = tempfile.mkdtemp(prefix='minimizer_crash_builder_',
                                           dir=self.tempdir)

        # get a new filename for the next crasher
        sfx = self.testcase.fuzzedfile.ext
        if self.testcase.seedfile:
            pfx = '%s-' % self.testcase.seedfile.root
        else:
            pfx = 'string-'

        (fd, f) = tempfile.mkstemp(suffix=sfx, prefix=pfx, dir=newcrash_tmpdir)
        os.close(fd)
        delete_files(f)
        outfile = f

        if os.path.exists(outfile):
            self._raise('Outfile should not already exist: %s' % outfile)
        self.logger.debug('\tCopying %s to %s', self.tempfile, outfile)
        filetools.copy_file(self.tempfile, outfile)

        if 'copyfuzzedto' in self.cfg['target']:
            copyfuzzedto = str(self.cfg['target'].get('copyfuzzedto', ''))
            logger.debug("Copying fuzzed file to " + copyfuzzedto)
            filetools.copy_file(self.tempfile, copyfuzzedto)

        if 'postprocessfuzzed' in self.cfg['target']:
            postprocessfuzzed = str(self.cfg['target']['postprocessfuzzed'])
            logger.debug("Executing postprocess " + postprocessfuzzed)
            os.system(postprocessfuzzed)

        new_testcase.fuzzedfile = BasicFile(outfile)
        self.logger.debug('\tNew fuzzed_content file: %s %s',
                          new_testcase.fuzzedfile.path,
                          new_testcase.fuzzedfile.md5)

        # clear out the copied testcase signature so that it will be
        # regenerated
        new_testcase.signature = None

        # replace old testcase details with new info specific to this testcase
        self.logger.debug('\tUpdating testcase details')
        new_testcase.update_crash_details()

        # the tempdir we created is no longer needed because
        # update_crash_details creates a fresh one
        shutil.rmtree(newcrash_tmpdir)
        if os.path.exists(newcrash_tmpdir):
            logger.warning("Failed to remove temp dir %s", newcrash_tmpdir)

        return new_testcase
Example #7
0
    def refresh(self):
        '''
        Gets all the file paths from self.dir then
        creates corresponding BasicFile objects in self.files
        '''
        self._verify_dir()

        dir_listing = [
            os.path.join(self.dir, f) for f in os.listdir(self.dir)
            if not f in blocklist
        ]
        self.files = [
            BasicFile(path) for path in dir_listing if os.path.isfile(path)
        ]
Example #8
0
    def __init__(self, output_base_dir, path):
        '''
        Creates an output dir for this seedfile based on its md5 hash.
        @param output_base_dir: The base directory for output files
        @raise SeedFileError: zero-length files will raise a SeedFileError
        '''
        BasicFile.__init__(self, path)

        if not self.len > 0:
            raise SeedFileError(
                'You cannot do bitwise fuzzing on a zero-length file: %s' % self.path)

        # use len for bytewise, bitlen for bitwise
        if self.len > 1:
            self.range_min = 1.0 / self.len
            self.range_max = 1.0 - self.range_min
        else:
            self.range_min = 0
            self.range_max = 1

        self.tries = 0

        self.rangefinder = RangeFinder(self.range_min, self.range_max)
Example #9
0
    def _construct_testcase(self):
        with WindowsTestcase(
                cfg=self.cfg,
                seedfile=self.seedfile,
                fuzzedfile=BasicFile(self.fuzzer.output_file_path),
                program=self.cfg['target']['program'],
                cmd_template=self.cmd_template,
                debugger_timeout=self.cfg['debugger']['runtimeout'],
                cmdlist=get_command_args_list(self.cmd_template,
                                              self.fuzzer.output_file_path)[1],
                dbg_opts=self.cfg['debugger'],
                workdir_base=self.working_dir,
                keep_faddr=self.cfg['runoptions'].get('keep_unique_faddr',
                                                      False),
                heisenbug_retries=self.retries,
                copy_fuzzedfile=self.fuzzer.fuzzed_changes_input) as testcase:

            # put it on the list for the analysis pipeline
            self.testcases.append(testcase)
Example #10
0
 def _construct_testcase(self):
     with LinuxTestcase(
             cfg=self.cfg,
             seedfile=self.seedfile,
             fuzzedfile=BasicFile(self.fuzzer.output_file_path),
             program=self.cfg['target']['program'],
             cmd_template=self.cmd_template,
             debugger_timeout=self.cfg['debugger']['runtimeout'],
             cmdlist=get_command_args_list(
                 self.cmd_template,
                 infile=self.fuzzer.output_file_path,
                 posix=True)[1],
             backtrace_lines=self.cfg['debugger']['backtracelevels'],
             crashers_dir=self.testcase_base_dir,
             workdir_base=self.working_dir,
             keep_faddr=self.cfg['runoptions'].get('keep_unique_faddr',
                                                   False),
             save_failed_asserts=self.cfg['analyzer'].get(
                 'savefailedasserts', False),
             exclude_unmapped_frames=self.cfg['analyzer']
         ['exclude_unmapped_frames']) as testcase:
         # put it on the list for the analysis pipeline
         self.testcases.append(testcase)
Example #11
0
 def __init__(self):
     fd, f = tempfile.mkstemp(suffix='.ext', prefix='fileroot')
     os.close(fd)
     self.fuzzedfile = BasicFile(f)
     self.debugger_template = 'foo'
Example #12
0
def main():
    from optparse import OptionParser

    hdlr = logging.StreamHandler()
    logger.addHandler(hdlr)

    usage = "usage: %prog [options] fuzzedfile"
    parser = OptionParser(usage)
    parser.add_option('',
                      '--debug',
                      dest='debug',
                      action='store_true',
                      help='Enable debug messages (overrides --verbose)')
    parser.add_option('',
                      '--verbose',
                      dest='verbose',
                      action='store_true',
                      help='Enable verbose messages')
    parser.add_option('-c',
                      '--config',
                      default='configs/bff.yaml',
                      dest='config',
                      help='path to the configuration file to use')
    parser.add_option('-e',
                      '--edb',
                      dest='use_edb',
                      action='store_true',
                      help='Use edb instead of gdb')
    parser.add_option('-p',
                      '--debugger',
                      dest='debugger',
                      help='Use specified debugger')
    parser.add_option('-f',
                      '--filepath',
                      dest='filepath',
                      action='store_true',
                      help='Recreate original file path')

    (options, args) = parser.parse_args()

    if options.debug:
        logger.setLevel(logging.DEBUG)
    else:
        logger.setLevel(logging.INFO)

    cfg_file = options.config
    logger.debug('Config file: %s', cfg_file)

    if len(args) and os.path.exists(args[0]):
        fullpath_fuzzed_file = os.path.abspath(args[0])
        fuzzed_file = BasicFile(fullpath_fuzzed_file)
        logger.info('Fuzzed file is: %s', fuzzed_file.path)
    else:
        parser.error('fuzzedfile must be specified')

    iterationpath = ''

    if options.filepath:
        # Recreate same file path as fuzz iteration
        resultdir = os.path.dirname(fuzzed_file.path)
        for gdbfile in all_files(resultdir, '*.gdb'):
            print '** using gdb: %s' % gdbfile
            iterationpath = getiterpath(gdbfile)
            break
        if iterationpath:
            iterationdir = os.path.dirname(iterationpath)
            iterationfile = os.path.basename(iterationpath)
            if iterationdir:
                mkdir_p(iterationdir)
                copy_file(fuzzed_file.path,
                          os.path.join(iterationdir, iterationfile))
                fullpath_fuzzed_file = iterationpath

    config = load_and_fix_config(cfg_file)

    cmd_as_args = get_command_args_list(config['target']['cmdline_template'],
                                        fullpath_fuzzed_file)[1]
    args = []

    if options.use_edb and options.debugger:
        parser.error('Options --edb and --debugger are mutually exclusive.')

    if options.debugger:
        debugger_app = options.debugger
    elif options.use_edb:
        debugger_app = 'edb'
    elif platform.system() == 'Darwin':
        debugger_app = 'lldb'
    else:
        debugger_app = 'gdb'
    args.append(debugger_app)

    if options.use_edb:
        args.append('--run')
    elif debugger_app == 'gdb':
        # Using gdb
        args.append('--args')
    args.extend(cmd_as_args)
    logger.info('args %s' % args)

    p = Popen(args, universal_newlines=True)
    p.wait()
Example #13
0
def main():
    debuggers.verify_supported_platform()

    from optparse import OptionParser

    hdlr = logging.StreamHandler()
    logger.addHandler(hdlr)

    usage = "usage: %prog [options] fuzzedfile"
    parser = OptionParser(usage)
    parser.add_option('',
                      '--debug',
                      dest='debug',
                      action='store_true',
                      help='Enable debug messages (overrides --verbose)')
    parser.add_option('',
                      '--verbose',
                      dest='verbose',
                      action='store_true',
                      help='Enable verbose messages')
    parser.add_option('-c',
                      '--config',
                      default='conf.d/bff.cfg',
                      dest='config',
                      help='path to the configuration file to use')
    parser.add_option('-e',
                      '--edb',
                      dest='use_edb',
                      action='store_true',
                      help='Use edb instead of gdb')
    parser.add_option('-p',
                      '--debugger',
                      dest='debugger',
                      help='Use specified debugger')
    parser.add_option('-f',
                      '--filepath',
                      dest='filepath',
                      action='store_true',
                      help='Recreate original file path')

    (options, args) = parser.parse_args()

    if options.debug:
        logger.setLevel(logging.DEBUG)
    else:
        logger.setLevel(logging.INFO)

    cfg_file = options.config
    logger.debug('Config file: %s', cfg_file)

    if len(args) and os.path.exists(args[0]):
        fullpath_fuzzed_file = os.path.abspath(args[0])
        fuzzed_file = BasicFile(fullpath_fuzzed_file)
        logger.info('Fuzzed file is %s', fuzzed_file)
    else:
        parser.error('fuzzedfile must be specified')

    iterationpath = ''

    if options.filepath:
        # Recreate same file path as fuzz iteration
        resultdir = os.path.dirname(fuzzed_file.path)
        for gdbfile in all_files(resultdir, '*.gdb'):
            print '** using gdb: %s' % gdbfile
            iterationpath = getiterpath(gdbfile)
            break
        iterationdir = os.path.dirname(iterationpath)
        iterationfile = os.path.basename(iterationpath)
        if iterationdir:
            mkdir_p(iterationdir)
            copy_file(fuzzed_file.path,
                      os.path.join(iterationdir, iterationfile))
            fullpath_fuzzed_file = iterationpath

    config = read_config_options(cfg_file)

    cmd_as_args = config.get_command_list(fullpath_fuzzed_file)
    program = cmd_as_args[0]
    if not os.path.exists(program):
        # edb wants a full path to the target app, so let's find it
        for path in os.environ["PATH"].split(":"):
            if os.path.exists(os.path.join(path, program)):
                program = os.path.join(path, program)

    # Recreate command args list with full path to target
    cmd_as_args = []
    cmd_as_args.append(program)
    cmd_as_args.extend(config.get_command_args_list(fullpath_fuzzed_file))

    args = []

    if options.use_edb and options.debugger:
        parser.error('Options --edb and --debugger are mutually exclusive.')

    if options.debugger:
        debugger_app = options.debugger
    elif options.use_edb:
        debugger_app = 'edb'
    else:
        debugger_app = 'gdb'
    args.append(debugger_app)

    if options.use_edb:
        args.append('--run')
    else:
        # Using gdb
        args.append('--args')
    args.extend(cmd_as_args)
    logger.info('args %s' % args)

    p = Popen(args, universal_newlines=True)
    p.wait()
Example #14
0
    def go(self):
        # start by copying the fuzzed_content file since as of now it's our
        # best fit
        filetools.copy_file(self.testcase.fuzzedfile.path, self.outputfile)

        # replace the fuzzedfile object in testcase with the minimized copy
        self.testcase.fuzzedfile = BasicFile(self.outputfile)

        self.logger.info('Attempting to minimize testcase(es) [%s]',
                         self._crash_hashes_string())

        # keep going until either:
        # a. we find a minimum hd of 1
        # b. we run out of discard_chances
        # c. our discard_chance * minimum hd is less than one (we won't discard anything)
        # d. we've exhaustively searched all the possible files with hd less
        # than self.min_distance
        while not self.min_found and not self.try_exhaustive:

            if not self.set_discard_chance():
                break

            if not self.set_n_misses():
                break

            got_hit = False
            while self.consecutive_misses <= self.n_misses_allowed:

                if self.use_watchdog:
                    # touch the watchdog file so we don't reboot during long
                    # minimizations
                    open(self.watchdogfile, 'w').close()

                # Fix for BFF-208
                if self._time_exceeded():
                    logger.info(
                        'Max time for minimization exceeded, ending minimizer early.'
                    )
                    self.min_found = True
                    break

                if not self.set_discard_chance():
                    break

                if not self.set_n_misses():
                    break

                self.swap_bytes()

                self.total_tries += 1

                # have we been at this level before?
                if not self.files_tried_at_hd.get(self.min_distance):
                    # we've reached a new minimum, so create new sets
                    self.files_tried_at_hd[self.min_distance] = set()
                    self.files_tried_singlebyte_at_hd[
                        self.min_distance] = set()

                # have we exhausted all the possible files with smaller hd?
                possible_files = (2**self.min_distance) - 2
                seen_files = len(self.files_tried_at_hd[self.min_distance])

                # maybe we're done?
                if seen_files == possible_files:
                    # we've exhaustively searched everything with hd <
                    # self.min_distance
                    self.logger.info(
                        'Exhaustively searched all files shorter than %d',
                        self.min_distance)
                    self.min_found = True
                    break

                # have we exhausted all files that are 1 byte smaller hd?
                possible_singlebyte_diff_files = self.min_distance
                singlebyte_diff_files_seen = len(
                    self.files_tried_singlebyte_at_hd[self.min_distance])

                # maybe we're done?
                if singlebyte_diff_files_seen == possible_singlebyte_diff_files:
                    self.logger.info(
                        'We have tried all %d files that are one byte closer than the current minimum',
                        self.min_distance)
                    self.min_found = True
                    break

                # remember this file for next time around
                self.files_tried_at_hd[self.min_distance].add(
                    self.newfuzzed_md5)
                if self.newfuzzed_hd == (self.min_distance - 1):
                    self.files_tried_singlebyte_at_hd[self.min_distance].add(
                        self.newfuzzed_md5)

                self.print_intermediate_log()

                if self.newfuzzed_md5 in self.files_tried:
                    # we've already seen this attempt, so skip ahead to the next one
                    # but still count it as a miss since our math assumes we're putting
                    # the marbles back in the jar after each draw
                    self.consecutive_misses += 1
                    self.total_misses += 1
                    continue

                # we didn't skip ahead, so it must have been new. Remember it
                # now
                self.files_tried.add(self.newfuzzed_md5)

                # we have a better match, write it to a file
                if not len(self.newfuzzed):
                    raise MinimizerError(
                        'New fuzzed_content content is empty.')

                self._write_file()

                if self.is_same_crash():
                    # record the result
                    # 1. copy the tempfile
                    filetools.best_effort_move(self.tempfile, self.outputfile)
                    # 2. replace the fuzzed_content file in the crasher with
                    # the current one
                    self.testcase.fuzzedfile = BasicFile(self.outputfile)
                    # 3. replace the current fuzzed_content with newfuzzed
                    self.fuzzed_content = self.newfuzzed
                    self.min_distance = self.newfuzzed_hd

                    got_hit = True

                    if self.min_distance == 1:
                        # we are done
                        self.min_found = True
                    elif self.newfuzzed_hd <= self.exhaustivesearch_threshold:
                        self._set_bytemap()
                        logger.info(
                            'Exhaustively checking remaining %s bytes' %
                            self.newfuzzed_hd)
                        self.try_exhaustive = True
                        break
                    else:
                        # set up for next iteration
                        self.consecutive_misses = 0
                        if not self.set_discard_chance():
                            break
                        if not self.set_n_misses():
                            break
                else:
                    # we missed. increment counter and try again
                    self.total_misses += 1
                    self.consecutive_misses += 1

                    # Fix for BFF-225
                    # There may be some situation that causes testcase uniqueness
                    # hashing to break. (e.g. BFF-224 ). Minimizer should bail
                    # if the number of unique crashes encountered exceeds some
                    # threshold. e.g. 20 maybe?
                    if len(self.other_crashes
                           ) > MAX_OTHER_CRASHES and self.seedfile_as_target:
                        logger.info(
                            'Exceeded maximum number of other crashes (%d), ending minimizer early.',
                            MAX_OTHER_CRASHES)
                        self.min_found = True
                        break

            if not got_hit:
                # we are self.confidence_level sure that self.target_size_guess is wrong
                # so increment it by 1
                self.target_size_guess += 1

        if self.try_exhaustive:
            for offset in list(self.bytemap):
                logger.debug('Verifying byte location: %s' % hex(offset))
                self.revert_byte(offset)
                self._write_file()
                if self.is_same_crash():
                    logger.debug('Fuzzed byte at offset %s is not relevant' %
                                 hex(offset))
                    filetools.best_effort_move(self.tempfile, self.outputfile)
                    self.testcase.fuzzedfile = BasicFile(self.outputfile)
                    self.fuzzed_content = self.newfuzzed
                    self.bytemap.remove(offset)

        # We're done minimizing. Set the bytemap (kept bytes)
        self._set_bytemap()
        self.logger.info('We were looking for [%s] ...',
                         self._crash_hashes_string())
        for (md5, count) in self.crash_sigs_found.items():
            self.logger.info('\t...and found %s\t%d times', md5, count)
        if self.bytemap:
            hex_bytemap = []
            for offset in self.bytemap:
                hex_bytemap.append(hex(offset))
            self.logger.info('Bytemap: %s', hex_bytemap)
Example #15
0
def main():
    debuggers.verify_supported_platform()

    from optparse import OptionParser

    hdlr = logging.StreamHandler()
    logger.addHandler(hdlr)

    usage = "usage: %prog [options] fuzzedfile"
    parser = OptionParser(usage)
    parser.add_option('',
                      '--debug',
                      dest='debug',
                      action='store_true',
                      help='Enable debug messages (overrides --verbose)')
    parser.add_option('',
                      '--verbose',
                      dest='verbose',
                      action='store_true',
                      help='Enable verbose messages')
    parser.add_option('-t',
                      '--target',
                      dest='target',
                      help='the file to minimize to (typically the seedfile)')
    parser.add_option('-o',
                      '--outdir',
                      dest='outdir',
                      help='dir to write output to')
    parser.add_option('-s',
                      '--stringmode',
                      dest='stringmode',
                      action='store_true',
                      help='minimize to a string rather than to a target file')
    parser.add_option(
        '-x',
        '--preferx',
        dest='prefer_x_target',
        action='store_true',
        help='Minimize to \'x\' characters instead of Metasploit string pattern'
    )
    parser.add_option(
        '-f',
        '--faddr',
        dest='keep_uniq_faddr',
        action='store_true',
        help='Use exception faulting addresses as part of crash signature')
    parser.add_option(
        '-b',
        '--bitwise',
        dest='bitwise',
        action='store_true',
        help='if set, use bitwise hamming distance. Default is bytewise')
    parser.add_option('-c',
                      '--confidence',
                      dest='confidence',
                      help='The desired confidence level (default: 0.999)',
                      type='float')
    parser.add_option('-g',
                      '--target-size-guess',
                      dest='initial_target_size',
                      help='A guess at the minimal value (int)',
                      type='int')
    parser.add_option('',
                      '--config',
                      dest='config',
                      help='path to the configuration file to use')
    parser.add_option(
        '',
        '--timeout',
        dest='timeout',
        metavar='N',
        type='int',
        default=0,
        help='Stop minimizing after N seconds (default is 0, never time out).')

    (options, args) = parser.parse_args()

    if options.debug:
        logger.setLevel(logging.DEBUG)
    elif options.verbose:
        logger.setLevel(logging.INFO)

    if options.config:
        cfg_file = os.path.expanduser(options.config)
    else:
        if os.path.isfile("../conf.d/bff.cfg"):
            cfg_file = "../conf.d/bff.cfg"
        elif os.path.isfile("conf.d/bff.cfg"):
            cfg_file = "conf.d/bff.cfg"
        else:
            parser.error(
                'Configuration file (--config) option must be specified.')
    logger.debug('Config file: %s', cfg_file)

    if options.stringmode and options.target:
        parser.error(
            'Options --stringmode and --target are mutually exclusive.')

    # Set some default options. Fast and loose if in string mode
    # More precise with minimize to seedfile
    if not options.confidence:
        if options.stringmode:
            options.confidence = 0.5
        else:
            options.confidence = 0.999
    if not options.initial_target_size:
        if options.stringmode:
            options.initial_target_size = 100
        else:
            options.initial_target_size = 1

    if options.confidence:
        try:
            options.confidence = float(options.confidence)
        except:
            parser.error('Confidence must be a float.')
    if not 0.0 < options.confidence < 1.0:
        parser.error('Confidence must be in the range 0.0 < c < 1.0')

    confidence = options.confidence

    if options.outdir:
        outdir = options.outdir
    else:
        outdir = "./minimizer_out"

    if not os.path.exists(outdir):
        filetools.make_directories(outdir)

    if not os.path.isdir(outdir):
        parser.error('--outdir must either already be a dir or not exist: %s' %
                     outdir)

    if len(args) and os.path.exists(args[0]):
        fuzzed_file = BasicFile(args[0])
        logger.info('Fuzzed file is %s', fuzzed_file)
    else:
        parser.error('fuzzedfile must be specified')

    cfg = read_config_options(cfg_file)

    if options.target:
        seedfile = BasicFile(options.target)
    else:
        seedfile = None

    min2seed = not options.stringmode
    filename_modifier = ''

    crashers_dir = '.'

    with BffCrash(cfg, seedfile, fuzzed_file, cfg.program,
                  cfg.debugger_timeout, cfg.killprocname, cfg.backtracelevels,
                  crashers_dir, options.keep_uniq_faddr) as crash:

        filetools.make_directories(crash.tempdir)
        logger.info('Copying %s to %s', fuzzed_file.path, crash.tempdir)
        filetools.copy_file(fuzzed_file.path, crash.tempdir)

        with Minimizer(cfg=cfg,
                       crash=crash,
                       crash_dst_dir=outdir,
                       seedfile_as_target=min2seed,
                       bitwise=options.bitwise,
                       confidence=confidence,
                       logfile='./min_log.txt',
                       tempdir=crash.tempdir,
                       maxtime=options.timeout,
                       preferx=options.prefer_x_target,
                       keep_uniq_faddr=options.keep_uniq_faddr) as minimize:
            minimize.save_others = False
            minimize.target_size_guess = int(options.initial_target_size)
            minimize.go()

            if options.stringmode:
                logger.debug('x character substitution')
                length = len(minimize.fuzzed)
                if options.prefer_x_target:
                    #We minimized to 'x', so we attempt to get metasploit as a freebie
                    targetstring = list(text.metasploit_pattern_orig(length))
                    filename_modifier = '-mtsp'
                else:
                    #We minimized to metasploit, so we attempt to get 'x' as a freebie
                    targetstring = list('x' * length)
                    filename_modifier = '-x'

                fuzzed = list(minimize.fuzzed)
                for idx in minimize.bytemap:
                    logger.debug('Swapping index %d', idx)
                    targetstring[idx] = fuzzed[idx]
                filename = ''.join((crash.fuzzedfile.root, filename_modifier,
                                    crash.fuzzedfile.ext))
                metasploit_file = os.path.join(crash.tempdir, filename)

                with open(metasploit_file, 'wb') as f:
                    f.writelines(targetstring)

        crash.copy_files(outdir)
        crash.clean_tmpdir()
def main():
    debuggers.verify_supported_platform()

    from optparse import OptionParser

    hdlr = logging.StreamHandler()
    logger.addHandler(hdlr)

    usage = "usage: %prog [options] fuzzedfile"
    parser = OptionParser(usage)
    parser.add_option('', '--debug', dest='debug', action='store_true',
                      help='Enable debug messages (overrides --verbose)')
    parser.add_option('', '--verbose', dest='verbose', action='store_true',
                      help='Enable verbose messages')
    parser.add_option('-t', '--target', dest='target',
                      help='the file to minimize to (typically the seedfile)')
    parser.add_option('-o', '--outdir', dest='outdir',
                      help='dir to write output to')
    parser.add_option('-s', '--stringmode', dest='stringmode',
                      action='store_true',
                      help='minimize to a string rather than to a target file')
    parser.add_option('-x', '--preferx', dest='prefer_x_target',
                      action='store_true',
                      help='Minimize to \'x\' characters instead of Metasploit string pattern')
    parser.add_option('-f', '--faddr', dest='keep_uniq_faddr',
                      action='store_true',
                      help='Use exception faulting addresses as part of crash signature')
    parser.add_option('-b', '--bitwise', dest='bitwise', action='store_true',
                      help='if set, use bitwise hamming distance. Default is bytewise')
    parser.add_option('-c', '--confidence', dest='confidence',
                      help='The desired confidence level (default: 0.999)')
    parser.add_option('-g', '--target-size-guess', dest='initial_target_size',
                      help='A guess at the minimal value (int)')
    parser.add_option('', '--config', default='configs/foe.yaml',
                      dest='config', help='path to the configuration file to use')
    parser.add_option('', '--timeout', dest='timeout',
                      metavar='N', type='int', default=0,
                      help='Stop minimizing after N seconds (default is 0, never time out).')
    parser.add_option('-k', '--keepothers', dest='keep_other_crashes',
                      action='store_true',
                      help='Keep other crash hashes encountered during minimization')
    (options, args) = parser.parse_args()

    if options.debug:
        logger.setLevel(logging.DEBUG)
    else:
        logger.setLevel(logging.INFO)

    if options.config:
        cfg_file = options.config
    else:
        cfg_file = "../conf.d/bff.cfg"
    logger.debug('Config file: %s', cfg_file)

    if options.stringmode and options.target:
        parser.error('Options --stringmode and --target are mutually exclusive.')

    # Set some default options. Fast and loose if in string mode
    # More precise with minimize to seedfile
    if not options.confidence:
        if options.stringmode:
            options.confidence = 0.5
        else:
            options.confidence = 0.999
    if not options.initial_target_size:
        if options.stringmode:
            options.initial_target_size = 100
        else:
            options.initial_target_size = 1

    if options.confidence:
        try:
            options.confidence = float(options.confidence)
        except:
            parser.error('Confidence must be a float.')
    if not 0.0 < options.confidence < 1.0:
        parser.error('Confidence must be in the range 0.0 < c < 1.0')

    confidence = options.confidence

    if options.outdir:
        outdir = options.outdir
    else:
        mydir = os.path.dirname(os.path.abspath(__file__))
        parentdir = os.path.abspath(os.path.join(mydir, '..'))
        outdir = os.path.abspath(os.path.join(parentdir, 'minimizer_out'))

    filetools.make_directories(outdir)

    if len(args) and os.path.exists(args[0]):
        fuzzed_file = BasicFile(args[0])
        logger.info('Fuzzed file is %s', fuzzed_file)
    else:
        parser.error('fuzzedfile must be specified')

    config = Config(cfg_file).config
    cfg = _create_minimizer_cfg(config)

    if options.target:
        seedfile = BasicFile(options.target)
    else:
        seedfile = None

    min2seed = not options.stringmode
    filename_modifier = ''
    retries = 0
    debugger_class = msec.MsecDebugger
    template = string.Template(config['target']['cmdline_template'])
    cmd_as_args = get_command_args_list(template, fuzzed_file.path)[1]
    with FoeCrash(template, seedfile, fuzzed_file, cmd_as_args, None, debugger_class,
               config['debugger'], outdir, options.keep_uniq_faddr, config['target']['program'],
               retries) as crash:
        filetools.make_directories(crash.tempdir)
        logger.info('Copying %s to %s', fuzzed_file.path, crash.tempdir)
        filetools.copy_file(fuzzed_file.path, crash.tempdir)

        minlog = os.path.join(outdir, 'min_log.txt')

        with Minimizer(cfg=cfg, crash=crash, crash_dst_dir=outdir,
                       seedfile_as_target=min2seed, bitwise=options.bitwise,
                       confidence=confidence, tempdir=outdir,
                       logfile=minlog, maxtime=options.timeout, 
                       preferx=options.prefer_x_target) as minimize:
            minimize.save_others = options.keep_other_crashes
            minimize.target_size_guess = int(options.initial_target_size)
            minimize.go()

        if options.stringmode:
            logger.debug('x character substitution')
            length = len(minimize.fuzzed)
            if options.prefer_x_target:
                #We minimized to 'x', so we attempt to get metasploit as a freebie
                targetstring = list(text.metasploit_pattern_orig(length))
                filename_modifier = '-mtsp'
            else:
                #We minimized to metasploit, so we attempt to get 'x' as a freebie
                targetstring = list('x' * length)
                filename_modifier = '-x'
            
            fuzzed = list(minimize.fuzzed)
            for idx in minimize.bytemap:
                logger.debug('Swapping index %d', idx)
                targetstring[idx] = fuzzed[idx]
            filename = ''.join((crash.fuzzedfile.root, filename_modifier, crash.fuzzedfile.ext))
            metasploit_file = os.path.join(crash.tempdir, filename)

            f = open(metasploit_file, 'wb')
            try:
                f.writelines(targetstring)
            finally:
                f.close()
        crash.copy_files(outdir)
        crash.clean_tmpdir()
Example #17
0
def main():
    debuggers.verify_supported_platform()

    from optparse import OptionParser

    hdlr = logging.StreamHandler()
    logger.addHandler(hdlr)

    usage = "usage: %prog [options] fuzzedfile"
    parser = OptionParser(usage)
    parser.add_option('',
                      '--debug',
                      dest='debug',
                      action='store_true',
                      help='Enable debug messages (overrides --verbose)')
    parser.add_option('',
                      '--verbose',
                      dest='verbose',
                      action='store_true',
                      help='Enable verbose messages')
    parser.add_option('-c',
                      '--config',
                      default='configs/foe.yaml',
                      dest='config',
                      help='path to the configuration file to use')
    parser.add_option('-w',
                      '--windbg',
                      dest='use_windbg',
                      action='store_true',
                      help='Use windbg instead of cdb')
    parser.add_option('-b',
                      '--break',
                      dest='break_on_start',
                      action='store_true',
                      help='Break on start of debugger session')
    parser.add_option('-d',
                      '--debugheap',
                      dest='debugheap',
                      action='store_true',
                      help='Use debug heap')
    parser.add_option('-p',
                      '--debugger',
                      dest='debugger',
                      help='Use specified debugger')
    parser.add_option('-f',
                      '--filepath',
                      dest='filepath',
                      action='store_true',
                      help='Recreate original file path')
    (options, args) = parser.parse_args()

    if options.debug:
        logger.setLevel(logging.DEBUG)
    else:
        logger.setLevel(logging.INFO)

    cfg_file = options.config
    logger.debug('Config file: %s', cfg_file)

    if len(args) and os.path.exists(args[0]):
        fullpath_fuzzed_file = os.path.abspath(args[0])
        fuzzed_file = BasicFile(fullpath_fuzzed_file)
        logger.info('Fuzzed file is %s', fuzzed_file)
    else:
        parser.error('fuzzedfile must be specified')

    config = Config(cfg_file).config

    iterationpath = ''
    template = string.Template(config['target']['cmdline_template'])
    if options.filepath:
        # Recreate same file path as fuzz iteration
        resultdir = os.path.dirname(fuzzed_file.path)
        for msecfile in all_files(resultdir, '*.msec'):
            print '** using msecfile: %s' % msecfile
            iterationpath = getiterpath(msecfile)
            break

        if iterationpath:
            iterationdir = os.path.dirname(iterationpath)
            iterationfile = os.path.basename(iterationpath)
            mkdir_p(iterationdir)
            copy_file(fuzzed_file.path,
                      os.path.join(iterationdir, iterationfile))
            fuzzed_file.path = iterationpath

    cmd_as_args = get_command_args_list(template, fuzzed_file.path)[1]
    targetdir = os.path.dirname(cmd_as_args[0])

    args = []

    if options.use_windbg and options.debugger:
        parser.error('Options --windbg and --debugger are mutually exclusive.')

    if options.debugger:
        debugger_app = options.debugger
    elif options.use_windbg:
        debugger_app = 'windbg'
    else:
        debugger_app = 'cdb'

    args.append(debugger_app)

    if not options.debugger:
        # Using cdb or windbg
        args.append('-amsec.dll')
        if options.debugheap:
            # do not use hd, xd options if debugheap is set
            pass
        else:
            args.extend(('-hd', '-xd', 'gp'))
        if not options.break_on_start:
            args.extend(('-xd', 'bpe', '-G'))
        args.extend((
            '-xd',
            'wob',
            '-o',
        ))
    args.extend(cmd_as_args)
    logger.info('args %s' % cmd_as_args)

    p = Popen(args, cwd=targetdir, universal_newlines=True)
    p.wait()
Example #18
0
def main():
    debuggers.verify_supported_platform()

    from optparse import OptionParser

    hdlr = logging.StreamHandler()
    logger.addHandler(hdlr)

    usage = "usage: %prog [options] fuzzedfile"
    parser = OptionParser(usage)
    parser.add_option('', '--debug', dest='debug', action='store_true',
                      help='Enable debug messages (overrides --verbose)')
    parser.add_option('', '--verbose', dest='verbose', action='store_true',
                      help='Enable verbose messages')
    parser.add_option('-c', '--config', default='configs/foe.yaml',
                      dest='config',
                      help='path to the configuration file to use')
    parser.add_option('-w', '--windbg', dest='use_windbg',
                      action='store_true',
                      help='Use windbg instead of cdb')
    parser.add_option('-b', '--break', dest='break_on_start',
                      action='store_true',
                      help='Break on start of debugger session')
    parser.add_option('-d', '--debugheap', dest='debugheap',
                      action='store_true',
                      help='Use debug heap')
    parser.add_option('-p', '--debugger', dest='debugger',
                      help='Use specified debugger')
    parser.add_option('-f', '--filepath', dest='filepath',
                      action='store_true', help='Recreate original file path')
    (options, args) = parser.parse_args()

    if options.debug:
        logger.setLevel(logging.DEBUG)
    else:
        logger.setLevel(logging.INFO)

    cfg_file = options.config
    logger.debug('Config file: %s', cfg_file)

    if len(args) and os.path.exists(args[0]):
        fullpath_fuzzed_file = os.path.abspath(args[0])
        fuzzed_file = BasicFile(fullpath_fuzzed_file)
        logger.info('Fuzzed file is %s', fuzzed_file)
    else:
        parser.error('fuzzedfile must be specified')

    config = Config(cfg_file).config

    iterationpath = ''
    template = string.Template(config['target']['cmdline_template'])
    if options.filepath:
        # Recreate same file path as fuzz iteration
        resultdir = os.path.dirname(fuzzed_file.path)
        for msecfile in all_files(resultdir, '*.msec'):
            print '** using msecfile: %s' % msecfile
            iterationpath = getiterpath(msecfile)
            break

        if iterationpath:
            iterationdir = os.path.dirname(iterationpath)
            iterationfile = os.path.basename(iterationpath)
            mkdir_p(iterationdir)
            copy_file(fuzzed_file.path,
                      os.path.join(iterationdir, iterationfile))
            fuzzed_file.path = iterationpath

    cmd_as_args = get_command_args_list(template, fuzzed_file.path)[1]
    targetdir = os.path.dirname(cmd_as_args[0])

    args = []

    if options.use_windbg and options.debugger:
        parser.error('Options --windbg and --debugger are mutually exclusive.')

    if options.debugger:
        debugger_app = options.debugger
    elif options.use_windbg:
        debugger_app = 'windbg'
    else:
        debugger_app = 'cdb'

    args.append(debugger_app)

    if not options.debugger:
        # Using cdb or windbg
        args.append('-amsec.dll')
        if options.debugheap:
            # do not use hd, xd options if debugheap is set
            pass
        else:
            args.extend(('-hd', '-xd', 'gp'))
        if not options.break_on_start:
            args.extend(('-xd', 'bpe', '-G'))
        args.extend(('-xd', 'wob', '-o',))
    args.extend(cmd_as_args)
    logger.info('args %s' % cmd_as_args)

    p = Popen(args, cwd=targetdir, universal_newlines=True)
    p.wait()
Example #19
0
def main():
    from optparse import OptionParser

    hdlr = logging.StreamHandler()
    logger.addHandler(hdlr)

    usage = "usage: %prog [options] fuzzedfile"
    parser = OptionParser(usage)
    parser.add_option('', '--debug', dest='debug', action='store_true',
                      help='Enable debug messages (overrides --verbose)')
    parser.add_option('', '--verbose', dest='verbose', action='store_true',
                      help='Enable verbose messages')
    parser.add_option('-t', '--target', dest='target',
                      help='the file to minimize to (typically the seedfile)')
    parser.add_option('-o', '--outdir', dest='outdir',
                      help='dir to write output to')
    parser.add_option('-s', '--stringmode', dest='stringmode',
                      action='store_true',
                      help='minimize to a string rather than to a target file')
    parser.add_option('-x', '--preferx', dest='prefer_x_target',
                      action='store_true',
                      help='Minimize to \'x\' characters instead of Metasploit string pattern')
    parser.add_option('-f', '--faddr', dest='keep_uniq_faddr',
                      action='store_true',
                      help='Use exception faulting addresses as part of testcase signature')
    parser.add_option('-b', '--bitwise', dest='bitwise', action='store_true',
                      help='if set, use bitwise hamming distance. Default is bytewise')
    parser.add_option('-c', '--confidence', dest='confidence',
                      help='The desired confidence level (default: 0.999)')
    parser.add_option('-g', '--target-size-guess', dest='initial_target_size',
                      help='A guess at the minimal value (int)')
    parser.add_option('', '--config', default='configs/bff.yaml',
                      dest='config', help='path to the configuration file to use')
    parser.add_option('', '--timeout', dest='timeout',
                      metavar='N', type='int', default=0,
                      help='Stop minimizing after N seconds (default is 0, never time out).')
    parser.add_option('-k', '--keepothers', dest='keep_other_crashes',
                      action='store_true',
                      help='Keep other testcase hashes encountered during minimization')
    (options, args) = parser.parse_args()

    if options.debug:
        logger.setLevel(logging.DEBUG)
    else:
        logger.setLevel(logging.INFO)

    if options.config:
        cfg_file = options.config
    else:
        cfg_file = "../configs/bff.yaml"
    logger.debug('WindowsConfig file: %s', cfg_file)

    if options.stringmode and options.target:
        parser.error(
            'Options --stringmode and --target are mutually exclusive.')

    # Set some default options. Fast and loose if in string mode
    # More precise with minimize to seedfile
    if not options.confidence:
        if options.stringmode:
            options.confidence = 0.5
        else:
            options.confidence = 0.999
    if not options.initial_target_size:
        if options.stringmode:
            options.initial_target_size = 100
        else:
            options.initial_target_size = 1

    if options.confidence:
        try:
            options.confidence = float(options.confidence)
        except:
            parser.error('Confidence must be a float.')
    if not 0.0 < options.confidence < 1.0:
        parser.error('Confidence must be in the range 0.0 < c < 1.0')

    confidence = options.confidence

    if options.outdir:
        outdir = options.outdir
    else:
        outdir = 'minimizer_out'
    outdir = os.path.abspath(outdir)

    filetools.make_directories(outdir)

    if len(args) and os.path.exists(args[0]):
        fuzzed_file = BasicFile(args[0])
        logger.info('Fuzzed file is: %s', fuzzed_file.path)
    else:
        parser.error('fuzzedfile must be specified')

    cfg = load_and_fix_config(cfg_file)

    if options.target:
        seedfile = BasicFile(options.target)
    else:
        seedfile = None

    min2seed = not options.stringmode
    filename_modifier = ''
    retries = 0
    debugger_class = msec.MsecDebugger

    cmd_as_args = get_command_args_list(
        cfg['target']['cmdline_template'], fuzzed_file.path)[1]

    # Figure out an appropriate timeout to use based on the config
    winver = sys.getwindowsversion().major
    machine = platform.machine()
    hook_incompatible = winver > 5 or machine == 'AMD64'
    debugger_timeout = cfg['runner']['runtimeout']
    if not hook_incompatible:
        # Assume the user has tuned timeout to the hook.
        # Allow extra time for the debugger to run
        debugger_timeout *= 2
        if debugger_timeout < 10:
            debugger_timeout = 10
    cfg['debugger']['runtimeout'] = debugger_timeout

    with WindowsTestcase(cfg=cfg,
                         seedfile=seedfile,
                         fuzzedfile=fuzzed_file,
                         program=cfg['target']['program'],
                         cmd_template=cfg['target']['cmdline_template'],
                         debugger_timeout=cfg['debugger']['runtimeout'],
                         cmdlist=cmd_as_args,
                         dbg_opts=cfg['debugger'],
                         workdir_base=outdir,
                         keep_faddr=options.keep_uniq_faddr,
                         heisenbug_retries=retries
                         ) as testcase:
        filetools.make_directories(testcase.tempdir)
        logger.info('Copying %s to %s', fuzzed_file.path, testcase.tempdir)
        filetools.copy_file(fuzzed_file.path, testcase.tempdir)

        minlog = os.path.join(outdir, 'min_log.txt')

        with Minimizer(cfg=cfg, testcase=testcase, crash_dst_dir=outdir,
                       seedfile_as_target=min2seed, bitwise=options.bitwise,
                       confidence=confidence, tempdir=outdir,
                       logfile=minlog, maxtime=options.timeout,
                       preferx=options.prefer_x_target) as minimize:
            minimize.save_others = options.keep_other_crashes
            minimize.target_size_guess = int(options.initial_target_size)
            minimize.go()

        if options.stringmode:
            logger.debug('x character substitution')
            length = len(minimize.fuzzed_content)
            if options.prefer_x_target:
                # We minimized to 'x', so we attempt to get metasploit as a
                # freebie
                targetstring = list(text.metasploit_pattern_orig(length))
                filename_modifier = '-mtsp'
            else:
                # We minimized to metasploit, so we attempt to get 'x' as a
                # freebie
                targetstring = list('x' * length)
                filename_modifier = '-x'

            fuzzed = list(minimize.fuzzed_content)
            for idx in minimize.bytemap:
                logger.debug('Swapping index %d', idx)
                targetstring[idx] = fuzzed[idx]
            filename = ''.join(
                (testcase.fuzzedfile.root, filename_modifier, testcase.fuzzedfile.ext))
            metasploit_file = os.path.join(testcase.tempdir, filename)

            f = open(metasploit_file, 'wb')
            try:
                f.writelines(targetstring)
            finally:
                f.close()
        testcase.copy_files(outdir)
        testcase.clean_tmpdir()
Example #20
0
def main():
    from optparse import OptionParser

    hdlr = logging.StreamHandler()
    logger.addHandler(hdlr)

    usage = "usage: %prog [options] fuzzedfile"
    parser = OptionParser(usage)
    parser.add_option('', '--debug', dest='debug', action='store_true',
                      help='Enable debug messages (overrides --verbose)')
    parser.add_option('', '--verbose', dest='verbose', action='store_true',
                      help='Enable verbose messages')
    parser.add_option('-c', '--config', default='configs/bff.yaml',
                      dest='config', help='path to the configuration file to use')
    parser.add_option('-a', '--args', dest='print_args',
                      action='store_true',
                      help='Print function arguments')
    parser.add_option('-o', '--out', dest='outfile',
                      help='PIN output file')
    parser.add_option('-f', '--filepath', dest='filepath',
                      action='store_true', help='Recreate original file path')

    (options, args) = parser.parse_args()

    if options.debug:
        logger.setLevel(logging.DEBUG)
    else:
        logger.setLevel(logging.INFO)

    if options.outfile:
        outfile = options.outfile
    else:
        outfile = 'calltrace.log'

    cfg_file = options.config
    logger.debug('Config file: %s', cfg_file)

    if len(args) and os.path.exists(args[0]):
        fullpath_fuzzed_file = os.path.abspath(args[0])
        fuzzed_file = BasicFile(fullpath_fuzzed_file)
        logger.info('Fuzzed file is: %s', fuzzed_file.path)
    else:
        parser.error('fuzzedfile must be specified')

    iterationpath = ''

    if options.filepath:
        # Recreate same file path as fuzz iteration
        resultdir = os.path.dirname(fuzzed_file.path)
        for gdbfile in all_files(resultdir, '*.gdb'):
            print '** using gdb: %s' % gdbfile
            iterationpath = getiterpath(gdbfile)
            break
        if iterationpath:
            iterationdir = os.path.dirname(iterationpath)
            iterationfile = os.path.basename(iterationpath)
            if iterationdir:
                mkdir_p(iterationdir)
                copy_file(fuzzed_file.path,
                          os.path.join(iterationdir, iterationfile))
                fullpath_fuzzed_file = iterationpath

    config = load_and_fix_config(cfg_file)

    cmd_as_args = get_command_args_list(
        config['target']['cmdline_template'], fullpath_fuzzed_file)[1]
    args = []

    pin = os.path.expanduser('~/pin/pin')
    pintool = os.path.expanduser('~/pintool/calltrace.so')
    args = [pin, '-injection', 'child', '-t',
            pintool, '-o', outfile]
    if options.print_args:
        args.append('-a')
    args.append('--')
    args.extend(cmd_as_args)

    logger.info('args %s' % args)

    p = Popen(args, universal_newlines=True)
    p.wait()