예제 #1
0
    def _prepare_chall_resp(self, state):
        # now we need to find the challenge response stuff
        # first break constraints at And's
        constraints = []
        for c in state.se.constraints:
            if c.op == "And":
                constraints.extend(c.args)
            else:
                constraints.append(c)

        # filter for possible flag constraints
        filtered_constraints = []
        for c in constraints:
            if any(
                    v.startswith("cgc-flag") or v.startswith("random")
                    for v in c.variables):
                filtered_constraints.append(c)

        self.filter_uncontrolled_constraints(state)
        # now separate into constraints we can probably control, and those we can't

        controllable_constraints = []
        uncontrollable_constraints = []
        if not state.has_plugin("chall_resp_info"):
            # register a blank one
            state.register_plugin("chall_resp_info", ChallRespInfo())

        chall_resp_info = state.get_plugin("chall_resp_info")

        for c in filtered_constraints:
            if any(v.startswith("file_/dev/stdin") for v in c.variables) or \
                    any(v in chall_resp_info.vars_we_added for v in c.variables):
                controllable_constraints.append(c)
            elif any(v.startswith("output_var") for v in c.variables):
                # an output like a leak
                pass
            else:
                # uncontrollable constraints will show up as zen constraints etc
                uncontrollable_constraints.append(c)

        if len(controllable_constraints) > 0:
            l.warning("challenge response detected!")
            file_1 = state.posix.get_file(1)
            stdout = file_1.content.load(0, file_1.pos)

            stdout_len = state.se.eval(file_1.pos)
            stdout_bvs = [
                claripy.BVS("file_stdout_0_%#x" % i, 8, explicit_name=True)
                for i in range(stdout_len)
            ]
            stdout_bv = claripy.Concat(*stdout_bvs)

            state.add_constraints(stdout == stdout_bv)
            # we call simplify to separate the contraints/dependencies
            state.se.simplify()

            merged_solver = state.se._solver._merged_solver_for(
                lst=[self._mem] + controllable_constraints)
            # todo here we can verify that there are actually stdout bytes here, otherwise we have little hope

            # add the important stdout vars to mem
            needed_vars = []
            for bv in stdout_bvs:
                if len(bv.variables & merged_solver.variables) != 0:
                    needed_vars.append(bv)

            # add the str_to_int vars and int_to_str vars
            for _, v in chall_resp_info.str_to_int_pairs:
                needed_vars.append(v)
            for v, _ in chall_resp_info.int_to_str_pairs:
                needed_vars.append(v)
            self._mem = claripy.Concat(self._mem, *needed_vars)
예제 #2
0
    def _create_solvers(self, ft, extra_vars_to_solve=None):
        split_solvers = ft.split()

        if extra_vars_to_solve is None:
            extra_vars_to_solve = []

        # make sure there is a chall_resp_info plugin
        if not self.crash.state.has_plugin("chall_resp_info"):
            # register a blank one
            self.crash.state.register_plugin("chall_resp_info",
                                             ChallRespInfo())

        # figure out start indices for all solvers
        stdin_solver = []
        for solver in split_solvers:
            stdin_indices = self._get_stdin_start_indices(solver)
            for idx, min_stdout_needed in stdin_indices:
                stdin_solver.append((idx, min_stdout_needed, solver))

        # get an extra solver for the extra_vars_to_solve
        merged_extra_solver = None
        if len(extra_vars_to_solve) > 0:
            extra_vars_to_solve = set(extra_vars_to_solve)
            important_solvers = [
                x for x in split_solvers
                if len(x.variables & extra_vars_to_solve) > 0
            ]
            if len(important_solvers) > 0:
                merged_extra_solver = important_solvers[0]
                for s in important_solvers[1:]:
                    merged_extra_solver = merged_extra_solver.combine(s)

        # sort them
        stdin_solver = sorted(stdin_solver, key=lambda x: x[0])

        # get int nums
        self._stdin_int_infos = {}
        self._stdout_int_infos = {}
        for solver in split_solvers:
            for info in self._get_stdin_int_infos(solver):
                self._stdin_int_infos[info.var_name] = info
            for info in self._get_stdout_int_infos(solver):
                self._stdout_int_infos[info.var_name] = info

        # sort them
        self._sorted_stdin_int_infos = sorted(self._stdin_int_infos.values(),
                                              key=lambda x: x.start)
        self._sorted_stdout_int_infos = sorted(self._stdout_int_infos.values(),
                                               key=lambda x: x.start)

        # FIXME FLAG THIS WILL NEED TO BE CHANGED
        if extra_vars_to_solve is not None and len(extra_vars_to_solve) > 0:
            stdin_solver.append((self.crash.state.se.eval(
                self.crash.state.posix.get_file(0).pos),
                                 self.crash.state.se.eval(
                                     self.crash.state.posix.get_file(1).pos),
                                 merged_extra_solver))

        l.debug("There are %d solvers after splitting", len(stdin_solver))

        self._solver_code = ""
        for i, (min_stdin, min_stdout_needed,
                solver) in enumerate(stdin_solver):

            formula = CGCFormula(solver)
            self._formulas.append(formula)

            btor_name = "btor_%d" % i
            formula.name = btor_name
            solver_code = ""

            # possibly send more
            solver_code += self._create_send_stdin(min_stdin,
                                                   min_stdout_needed)
            # we need to read until we get the bytes
            solver_code += self._create_read_bytes(min_stdout_needed)

            # now we have all the bytes we needed
            # parse the formula
            solver_code += self._create_boolector_parse(btor_name, formula)
            # constrain any "input" variables (regval, addr)
            solver_code += self._create_constrain_vals(solver, btor_name,
                                                       formula)
            # add constraints to any stdin we've already sent
            solver_code += self._create_constrain_stdin(
                solver, btor_name, formula)
            # add constraints to stdout for the bytes we got
            solver_code += self._create_constrain_stdout(
                solver, btor_name, formula)
            # add constraints to any integers we have already used
            solver_code += self._create_constrain_integers(
                solver, btor_name, formula)
            # now create the byte setters
            solver_code += self._create_byte_setters(solver, btor_name,
                                                     formula)
            self._solver_code += solver_code + "\n"

        # we are done
        l.debug("done creating solvers")