Exemple #1
0
    def execute_command(self, cmd, timeout):
        ret = None
        if self.debugging_interface is None:
            cmd_obj = TimeoutCommand(cmd)
            ret = cmd_obj.run(timeout=self.timeout)
            if cmd_obj.stderr is not None:
                print cmd_obj.stderr
        else:
            self.iface.timeout = self.timeout
            if not has_pykd or self.iface != pykd_iface:
                if self.iface == asan_iface:
                    crash = self.iface.main(
                        asan_symbolizer_path=self.asan_symbolizer_path,
                        args=cmd)
                else:
                    crash = self.iface.main(cmd)
            else:
                # Avoid network timeouts and unnecessary delays when using pykd
                os.putenv("_NT_SYMBOL_PATH", "")
                crash = pykd_iface.main([cmd],
                                        timeout,
                                        mode=self.mode,
                                        windbg_path=self.windbg_path,
                                        exploitable_path=self.exploitable_path)

            if crash is not None:
                self.last_crash = crash
                ret = 0xC0000005  # Access violation in Windows

        return ret
Exemple #2
0
    def coverage(self, command, timeout=36000, hide_output=True):
        tool_path = self.path + "/source/tools/RunTracer"
        if int(self.arch) == 32:
            tool_path = tool_path + "/obj-ia32/ccovtrace.so"
        elif int(self.arch) == 64:
            tool_path = tool_path + "/obj-intel64/ccovtrace.so"

        logfile = mkstemp()[1]
        # XXX: Do we want to use the .sh script? Using this we're limiting
        # ourselves to only Linux and MacOSX.
        cmdline = "%s/pin.sh -t %s -o %s -- %s"
        if hide_output:
            # ...although, when using "hide_output", we're already doing it...
            cmdline += " >/dev/null 2>/dev/null"
        cmdline = cmdline % (self.path, tool_path, logfile, command)

        debug("Running command %s" % cmdline)
        cmd = TimeoutCommand(cmdline)
        ret = cmd.run(timeout)
        coverage = self.read_coverage_log(logfile)
        debug("Removing temporary file %s " % logfile)
        os.remove(logfile)

        debug("Returning coverage data...")
        cover = CCoverResults(coverage[0], coverage[1], ret)
        return cover
Exemple #3
0
    def run(self):
        os.putenv("LANG", "C")
        os.putenv("ASAN_SYMBOLIZER_PATH", self.asan_symbolizer_path)

        cmd = self.program
        print "Running %s" % cmd

        cmd_obj = TimeoutCommand(cmd)
        cmd_obj.run(self.timeout, get_output=True)

        buf = cmd_obj.stderr
        self.asan.parse_buffer(buf)

        if self.asan.reason is not None:
            crash_data = CCrashData(self.asan.pc, self.asan.reason)
            i = 0
            for line in self.asan.stack_trace:
                crash_data.add_data("stack trace", "%d" % i,
                                    (line[0], line[1]))
                i += 1

            crash_data.add_data("registers", "pc", self.asan.pc)
            crash_data.add_data("registers", "bp", self.asan.bp)
            crash_data.add_data("registers", "sp", self.asan.sp)

            crash_data.add_data("disassembly", int(self.asan.pc), "")
            j = 0
            for line in self.asan.additional:
                crash_data.add_data("information", j, line)
                j += 1
            crash_data.disasm = [self.asan.pc, ""]

            if not self.asan.reason.startswith("SIG"):
                crash_data.exploitable = "EXPLOITABLE"
            else:
                crash_data.exploitable = "UNKNOWN"

            crash_data.add_data("exploitability", "reason", self.asan.reason)

            crash_data_buf = crash_data.dump_json()
            crash_data_dict = crash_data.dump_dict()

            line = "Program received %s at PC 0x%x SP 0x%x BP 0x%x"
            print line % (self.asan.reason, self.asan.pc, self.asan.sp,
                          self.asan.bp)
            print
            for i, line in enumerate(self.asan.stack_trace):
                if i > 10:
                    break
                print "0x%08x %s" % (line[0], line[1])

            print
            print "Yep, we got a crash! \o/"
            print

            return crash_data_dict

        return
    def do_try(self, outdir, start_at=0):
        # Try to minimize to just one change
        current_change = 0
        minimized = False
        iteration = 0
        for i in range(len(self.diff)):
            for pos in self.diff:
                if start_at <= iteration:
                    log("Minimizing, iteration %d (Max. %d)..." %
                        (iteration, (len(self.diff)) * len(self.diff)))
                    temp_file = tempfile.mktemp()
                    buf = bytearray(self.template)
                    if pos not in self.crash:
                        continue

                    buf[pos] = self.crash[pos]

                    with open(temp_file, "wb") as f:
                        f.write(buf)

                    try:
                        for key in self.env:
                            os.putenv(key, self.env[key])

                        cmd = "%s %s" % (self.command, temp_file)
                        cmd_obj = TimeoutCommand(cmd)
                        ret = cmd_obj.run(timeout=self.timeout)

                        if ret in RETURN_SIGNALS:
                            log("Successfully minimized, caught signal %d (%s)!"
                                % (ret, RETURN_SIGNALS[ret]))
                            filename = sha1(buf).hexdigest()
                            filename = os.path.join(
                                outdir, "%s%s" % (filename, self.extension))
                            shutil.copy(temp_file, filename)
                            log("Minized test case %s written to disk." %
                                filename)
                            minimized = True
                            break
                    finally:
                        os.remove(temp_file)

                if minimized:
                    break

                iteration += 1

            if minimized:
                break

            value = self.diff.pop()
            if value in self.crash:
                self.template[value] = self.crash[value]
                del self.crash[value]

        if not minimized:
            log("Sorry, could not minimize crashing file!")
Exemple #5
0
    def run(self):
        global buf

        os.putenv("LANG", "C")

        logfile = mkstemp()[1]
        try:
            cmd = '/bin/bash -c "/usr/bin/gdb -q --batch --command=%s --args %s" 2>/dev/null > %s'
            cmd %= (self.gdb_commands, self.program, logfile)
            print cmd
            print "Running %s" % cmd

            cmd_obj = TimeoutCommand(cmd)
            #cmd_obj.shell = True
            cmd_obj.run(self.timeout)

            buf = open(logfile, "rb").readlines()
            self.parse_dump(buf)

            if self.signal:
                crash_data = CCrashData(self.pc, self.signal)
                i = 0
                for stack in self.stack:
                    crash_data.add_data("stack trace", "%d" % i, stack)
                    i += 1

                for reg in self.registers:
                    crash_data.add_data("registers", reg, self.registers[reg])

                crash_data.add_data("disassembly", int(self.pc), self.disasm)
                for dis in self.disasm_around:
                    if type(dis[0]) is int or dis[0].isdigit():
                        crash_data.add_data("disassembly", dis[0], dis[1])
                crash_data.disasm = [self.pc, self.disasm]

                if self.exploitability is not None:
                    crash_data.exploitable = self.exploitability

                if self.exploitability_reason is not None:
                    crash_data.add_data("exploitability", "reason",
                                        self.exploitability_reason)

                crash_data_buf = crash_data.dump_json()
                crash_data_dict = crash_data.dump_dict()

                print
                print "Yep, we got a crash! \o/"
                print

                return crash_data_dict

            return
        finally:
            os.remove(logfile)
Exemple #6
0
    def coverage(self, command, timeout=36000, hide_output=True):
        logdir = mkdtemp()
        cmdline = "%s/bin%s/drrun -t drcov -dump_text -logdir %s -- %s"
        if hide_output:
            cmdline += " >/dev/null 2>/dev/null"
        cmdline = cmdline % (self.path, self.arch, logdir, command)

        debug("Running command %s" % cmdline)
        cmd = TimeoutCommand(cmdline)
        ret = cmd.run(timeout)
        coverage = self.read_coverage_log(logdir)
        debug("Removing temporary directory %s " % logdir)
        shutil.rmtree(logdir)

        debug("Returning coverage data...")
        cover = CCoverResults(coverage[0], coverage[1], ret)
        return cover
Exemple #7
0
    def execute_command(self, cmd, timeout):
        ret = None
        if self.debugging_interface is None:
            cmd_obj = TimeoutCommand(cmd)
            ret = cmd_obj.run(timeout=self.timeout)
        else:
            self.iface.timeout = self.timeout
            if self.iface != pykd_iface:
                crash = self.iface.main(cmd)
            else:
                crash = pykd_iface.main([cmd],
                                        mode=self.mode,
                                        windbg_path=self.windbg_path,
                                        exploitable_path=self.exploitable_path)

            if crash is not None:
                ret = 0xC0000005  # Access violation in Windows

        return ret
Exemple #8
0
    def execute_command(self, cmd, timeout):
        ret = None
        if self.debugging_interface is None:
            cmd_obj = TimeoutCommand(cmd)
            ret = cmd_obj.run(timeout=self.timeout)
            if cmd_obj.stderr is not None:
                print cmd_obj.stderr
        else:
            self.iface.timeout = self.timeout
            if not has_pykd or self.iface != pykd_iface:
                crash = self.iface.main(cmd)
            else:
                os.putenv("_NT_SYMBOL_PATH", "")
                crash = pykd_iface.main([cmd],
                                        timeout,
                                        mode=self.mode,
                                        windbg_path=self.windbg_path,
                                        exploitable_path=self.exploitable_path)

            if crash is not None:
                ret = 0xC0000005  # Access violation in Windows

        return ret
Exemple #9
0
    def run_test(self, name, data):
        track_lines = int(data[0])
        track_return = int(data[1])
        mitigate_lines = int(data[2])
        mitigate_return = int(data[3])

        args = ["-track 1", "-track 1 -mitigate 1"]
        archs = ["ia32", "intel64"]
        for arch in archs:
            failed = False
            tmp_cmd = "%s/pin -t %s/obj-%s/%s" % (
                self.pin_path, self.tool_path, arch, self.tool_name)
            for arg in args:
                suffix = ""
                if arch == "ia32":
                    suffix = "32"
                cmd = "%s %s -- %s/%s%s" % (
                    tmp_cmd, arg, self.testcases_directory, name, suffix)
                debug("Running %s" % cmd)
                t = TimeoutCommand(cmd)
                code = t.run(get_output=True)
                stdout = t.stdout

                if arg.find("mitigate") == -1:
                    if code != track_return:
                        failed = True
                        line = "*** TEST %s FAILED *** Different return code for tracker: got %d, expected %d"
                        log(line % (repr(name), code, track_return))
                        print "-" * 80
                        print repr(stdout)
                        print "-" * 80

                    lines = stdout.count("\n")
                    if lines != track_lines:
                        failed = True
                        line = "*** TEST %s FAILED *** Different number of lines for tracker: got %d, expected %d"
                        log(line % (repr(name), lines, track_lines))
                        print "-" * 80
                        print repr(stdout)
                        print "-" * 80
                else:
                    if code != mitigate_return:
                        failed = True
                        line = "*** TEST %s FAILED *** Different return code for mitigator: got %d, expected %d"
                        log(line % (repr(name), code, mitigate_return))
                        print "-" * 80
                        print repr(stdout)
                        print "-" * 80

                    lines = stdout.count("\n")
                    if lines != mitigate_lines:
                        failed = True
                        line = "*** TEST %s FAILED *** Different number of lines for mitigator: got %d, expected %d"
                        log(line % (repr(name), lines, mitigate_lines))
                        print "-" * 80
                        print repr(stdout)
                        print "-" * 80

                if not failed:
                    test_type = "tracker"
                    if arg.find("mitigate") == -1:
                        test_type = "mitigator"
                    log("TEST %s FOR %s ARCH %s PASSED" %
                        (repr(name), test_type, arch))
                else:
                    self.failed = True
    def do_try(self, outdir, start_at=0):
        """ Try to remove a random number of lines iterating from the first
        line to the last one a number of times. Basically, we calculate
        a total number of lines to remove between 1 line and 10%. If the
        number of lines removed produces a test-case that still crashes,
        remove the lines from the template, otherwise, drop the changes 
        and move to the next line.

        IDEAS: Remove all empty lines before starting?
    """
        orig_lines = len(self.template)

        current_line = 0
        iteration = 0
        loops = 0
        while 1:
            self.minimized = False
            total_lines = len(self.template)
            log("Starting loop %d" % loops)
            current_line = 0

            for i in range(len(self.template)):
                self.read_configuration()
                log("Minimizing, iteration %d..." % iteration)
                iteration += 1
                temp_file = tempfile.mktemp(suffix=self.extension)
                lines = self.template

                if current_line >= len(lines):
                    break

                if loops == 0 and not self.line_per_line:
                    # Rip a random number of lines between 1 and self.lines_percent
                    # but only at the very first iteration (when we remove most of
                    # the stuff).
                    val = (total_lines -
                           current_line) * self.lines_percent / 100
                    if val == 0:
                        val = 1

                    lines_to_rip = random.randint(1, val)
                    log("Removing %d line(s) (maximum of %d%%)" %
                        (lines_to_rip, self.lines_percent))
                else:
                    # For the likely final run remove only one line per try (or
                    # whatever is specified in the configuration file)
                    lines_to_rip = self.lines_to_rip
                    log("Removing %d line(s)" % lines_to_rip)

                lines = lines[:current_line] + lines[current_line +
                                                     lines_to_rip:]
                buf = "".join(lines)

                with open(temp_file, "wb") as f:
                    f.write(buf)

                try:
                    for key in self.env:
                        os.putenv(key, self.env[key])

                    self.remove_crash_path()

                    cmd = "%s %s" % (self.command, temp_file)
                    cmd_obj = TimeoutCommand(cmd)
                    ret = cmd_obj.run(timeout=self.timeout)

                    if ret in RETURN_SIGNALS or (self.signal is not None and ret == self.signal) or \
                       self.crash_file_exists():
                        self.template = lines
                        log("Process crashed as expected...")
                        buf = "".join(self.template)
                        if not os.path.exists(outdir):
                            log("Directory %s does not exists, creating it..."
                                % outdir)
                            os.mkdir(outdir)

                        filename = os.path.join(
                            outdir, "last_minimized%s" % self.extension)
                        with open(filename, "wb") as f:
                            f.write(buf)
                        log("Last minimized test case %s written to disk." %
                            filename)
                    else:
                        current_line += 1

                    self.remove_crash_path()
                finally:
                    os.remove(temp_file)

            loops += 1

            if len(self.template) == total_lines:
                log("File minimized from %d line(s) to %d line(s)" %
                    (orig_lines, len(self.template)))
                buf = "".join(self.template)
                filename = sha1(buf).hexdigest()
                filename = os.path.join(outdir,
                                        "%s%s" % (filename, self.extension))
                with open(filename, "wb") as f:
                    f.write(buf)
                log("Minimized test case %s written to disk." % filename)
                self.minimized = True
                break