Ejemplo n.º 1
0
 def __init__(self, r2_obj):
     self.r2_obj = r2_obj
     self.stopaddr = None
     self.bt = self.r2_obj.debug_dbt()
     self.arch_obj = Arch(self.r2_obj)
     self.term_colors = TermColors()
     self.pc_name = self.arch_obj.get_reg("program_counter")
     self.pdj = self.r2_obj.debug_pdj_single(self.pc_name)[0]
     self.pc = self.pdj["offset"]
     self.type = self.pdj["type"]
     if self.type != "invalid":
         self.instr = Instruction(self.r2_obj, self.pc_name)
Ejemplo n.º 2
0
class CrashGraph:
    def __init__(self, object, file_name):
        """" Initialized the object's internal data.
        Args:
            object: Crash object
            file_name: png output file name
        """
        self.r2_obj = object.r2_obj
        self.r2_dbg_obj = object.r2_dbg_obj
        self.r2_stand_obj = object.r2_stand_obj
        self.graph_obj = Graph()
        self.count = 1
        self.file_name = file_name

    def crash_graph(self):
        """ Graph generation """

        self.r2_stand_obj.analyze()
        self.arch_obj = Arch(self.r2_obj)

        self.r2_dbg_obj.debug_setenv("dbg.btdepth", "256")

        #afl
        func_list = self.r2_stand_obj.aflqj()

        if not func_list:
            print("No functions")
            sys.exit(-1)

        #set bps
        for function in func_list:
            self.r2_dbg_obj.debug_break(function)

        self.node_list = []
        self.range_list = []
        first = True

        while True:
            # continue
            self.r2_dbg_obj.debug_continue()

            get_info = self.r2_dbg_obj.debug_infoj()
            signal = get_info["signal"]

            self.r2_dbg_obj.debug_dmmSy()

            self.pc = self.arch_obj.get_reg("program_counter")
            self.pdj = self.r2_dbg_obj.debug_pdj_single(self.pc)
            bt = self.r2_dbg_obj.debug_dbt()

            # check access violation signal
            if Checks.check_signal(signal):
                regs = self.r2_dbg_obj.debug_registers()
                node_name = "crash_node"
                message = ""
                is_exploitable = False

                if self.pdj[0]["type"] == "invalid":
                    print("ERROR: Function crash_graph, the type is invalid!")
                    return False

                opcode = self.pdj[0]["opcode"]
                crash_address = self.pdj[0]["offset"]

                is_exploitable = CrashAnal.exploitable(signal, self.r2_dbg_obj)
                if is_exploitable:
                    exploitable_message = "PROBABLY EXPLOITABLE"
                    message = "crash details"
                else:
                    exploitable_message = "PROBABLY NOT EXPLOITABLE"
                    message = "details"

                label = "Exploitable: " + exploitable_message + " \n " + "crash instruction: \n" + str(
                    hex(crash_address)
                ) + " - " + str(
                    opcode
                ) + " \nbacktrace: \n " + bt + " \n " + "registers: \n" + regs + " \n "
                self.node = self.graph_obj.create_node(node_name, "green",
                                                       label)
                self.node_list.append(self.node)

                # create edge
                try:
                    caller_address = bt.splitlines()[1].split()[1]
                except Exception as ex:
                    print("WARNING: caller address - backtrace error: %s" % ex)
                    caller_address = "0x0"

                self.create_edge(int(caller_address, 16), message)

                break

            if signal != "SIGTRAP":
                break

            if first:
                self.create_node("gold")
                first = False
                continue

            self.create_node("gold")

            try:
                caller_address = self.pdj[0]["xrefs"][0]["addr"]
            except Exception as ex:
                print("WARNING: caller address - xref not there: %s" % ex)
                try:
                    caller_address = bt.splitlines()[1].split()[1]
                except Exception as ex:
                    print("WARNING: caller address - backtrace erro: %s" % ex)
                    continue

            # create edge
            self.create_edge(caller_address, self.count)

        # create png
        self.graph_obj.create_png(self.file_name)

    def create_node(self, color):
        function_address = self.pdj[0]["fcn_addr"]
        func_address_end = self.pdj[0]["fcn_last"]
        r = range(function_address, func_address_end)
        self.range_list.append(r)
        func_name = self.pdj[0]["flags"][0]
        node_name = func_name
        label = func_name + " [ " + str(hex(function_address)) + " - " + str(
            hex(func_address_end)) + " ] "
        self.node = self.graph_obj.create_node(node_name, color, label)
        self.node_list.append(self.node)

    def create_edge(self, caller_address, label):
        for range_addr in self.range_list:
            if caller_address in range_addr:
                for single_node in self.node_list:
                    a = range_addr[0]
                    b = single_node.obj_dict["attributes"]["label"].split()[2]
                    if int(range_addr[0]) == int(b, 16):
                        self.graph_obj.create_edge(single_node, self.node,
                                                   label)
                        self.count += 1
                        return
Ejemplo n.º 3
0
class Engine:
    def __init__(self, r2_obj):
        self.r2_obj = r2_obj
        self.stopaddr = None
        self.bt = self.r2_obj.debug_dbt()
        self.arch_obj = Arch(self.r2_obj)
        self.term_colors = TermColors()
        self.pc_name = self.arch_obj.get_reg("program_counter")
        self.pdj = self.r2_obj.debug_pdj_single(self.pc_name)[0]
        self.pc = self.pdj["offset"]
        self.type = self.pdj["type"]
        if self.type != "invalid":
            self.instr = Instruction(self.r2_obj, self.pc_name)

    def print_crash_info(self):
        print(self.term_colors.bold() + "backtrace" + self.term_colors.reset())
        print(self.bt)
        print(self.term_colors.bold() + "registers" + self.term_colors.reset())
        print(self.r2_obj.debug_registers())

    def stack_overf_libc(self):
        libs = ["fortify_fail", "stack_chk_fail"]
        try:
            if libs[0] in self.bt or libs[1] in self.bt:
                stack_report = "Stack error - Generally it could be exploitable, due to suspicious functions in the backtrace"
                print(self.term_colors.red() + stack_report +
                      self.term_colors.default())
                self.print_crash_info()
                return stack_report
            return False
        except Exception as ex:
            print("stack_overf_libc - error type: %s" % ex)
            return False

    def crash_on_pc(self):
        try:
            dinfo = self.r2_obj.debug_infoj()
            self.stopaddr = dinfo["stopaddr"]

            if self.type == "div":
                self.not_exploitable()
                return False

            if self.stopaddr == self.pc or self.type == "invalid":
                crash_on_pc_report = "Crash on PC - Generally it is exploitable, the PC could be tainted"
                print(self.term_colors.red() + crash_on_pc_report +
                      self.term_colors.default())
                self.print_crash_info()
                return crash_on_pc_report
            return False
        except Exception as ex:
            print("crash_on_pc - error type: %s" % ex)
            return False

    def crash_on_branch(self):
        if self.type != "invalid":
            try:
                is_branch_instr = self.instr.is_branch_instr()
            except Exception as ex:
                print("crash_on_branch - error type: %s" % ex)
                return False

            if is_branch_instr:
                crash_on_branch_report = "Crash on branch instruction - Generally it is exploitable, the branch address could be tainted"
                print(self.term_colors.red() + crash_on_branch_report +
                      self.term_colors.default())
                self.print_crash_info()
                return crash_on_branch_report
            return False
        return False

    def invalid_write(self):
        try:
            if self.type != "invalid":
                is_mem_write = self.instr.is_memory_write()
                if is_mem_write:
                    dest_address = self.instr.get_dest_address()
                    if dest_address and int(dest_address, 16) == self.stopaddr:
                        size = self.instr.write_size()
                        invalid_write_report = "Invalid write crash - Generally it is exploitable, the write value/address could be tainted"

                        if size:
                            print(self.term_colors.red() +
                                  invalid_write_report +
                                  " - Invalid write of size %d" % size +
                                  self.term_colors.default())
                        else:
                            print(self.term_colors.red() +
                                  invalid_write_report + "Invalid write" +
                                  self.term_colors.default())
                        self.print_crash_info()
                    return invalid_write_report
            return False
        except Exception as ex:
            print("invalid_write - error type: %s" % ex)
            return False

    def heap_error(self):

        suspicius_heap_functions = """free malloc calloc realloc""".split()

        try:
            for i in suspicius_heap_functions:
                if i in self.bt:
                    heap_report = "Heap error - Generally it could be exploitable, due to suspicious functions in the backtrace"
                    print(self.term_colors.red() + heap_report +
                          self.term_colors.default())
                    self.print_crash_info()
                    return heap_report
            return False
        except Exception as ex:
            print("heap_error - error type: %s" % ex)
            return False

    def read_access_violation(self):
        """ Check if it is a read access violation, and if it could be exploitable
        :return: True if it could be exploitable
        """
        try:
            if self.type != "invalid":
                is_mem_read = self.instr.is_memory_read()
                if is_mem_read:
                    if self.instr.call_check(self.arch_obj.get_regs()):
                        uaf_report = "It could be just a read access violation, but after few instruction there is a suspicious call, and if the address could be controlled by an attacker, it could lead to code execution"
                        print(self.term_colors.red() + uaf_report +
                              self.term_colors.default())
                        self.print_crash_info()
                        return uaf_report
                    return False
            return False
        except Exception as ex:
            print("read_access_violation - error type: %s" % ex)
            return False

    def not_exploitable(self):
        not_exploitable_report = "PROBABLY NOT EXPLOITABLE"
        print(self.term_colors.green() + not_exploitable_report +
              self.term_colors.default())
Ejemplo n.º 4
0
    def crash_graph(self):
        """ Graph generation """

        self.r2_stand_obj.analyze()
        self.arch_obj = Arch(self.r2_obj)

        self.r2_dbg_obj.debug_setenv("dbg.btdepth", "256")

        #afl
        func_list = self.r2_stand_obj.aflqj()

        if not func_list:
            print("No functions")
            sys.exit(-1)

        #set bps
        for function in func_list:
            self.r2_dbg_obj.debug_break(function)

        self.node_list = []
        self.range_list = []
        first = True

        while True:
            # continue
            self.r2_dbg_obj.debug_continue()

            get_info = self.r2_dbg_obj.debug_infoj()
            signal = get_info["signal"]

            self.r2_dbg_obj.debug_dmmSy()

            self.pc = self.arch_obj.get_reg("program_counter")
            self.pdj = self.r2_dbg_obj.debug_pdj_single(self.pc)
            bt = self.r2_dbg_obj.debug_dbt()

            # check access violation signal
            if Checks.check_signal(signal):
                regs = self.r2_dbg_obj.debug_registers()
                node_name = "crash_node"
                message = ""
                is_exploitable = False

                if self.pdj[0]["type"] == "invalid":
                    print("ERROR: Function crash_graph, the type is invalid!")
                    return False

                opcode = self.pdj[0]["opcode"]
                crash_address = self.pdj[0]["offset"]

                is_exploitable = CrashAnal.exploitable(signal, self.r2_dbg_obj)
                if is_exploitable:
                    exploitable_message = "PROBABLY EXPLOITABLE"
                    message = "crash details"
                else:
                    exploitable_message = "PROBABLY NOT EXPLOITABLE"
                    message = "details"

                label = "Exploitable: " + exploitable_message + " \n " + "crash instruction: \n" + str(
                    hex(crash_address)
                ) + " - " + str(
                    opcode
                ) + " \nbacktrace: \n " + bt + " \n " + "registers: \n" + regs + " \n "
                self.node = self.graph_obj.create_node(node_name, "green",
                                                       label)
                self.node_list.append(self.node)

                # create edge
                try:
                    caller_address = bt.splitlines()[1].split()[1]
                except Exception as ex:
                    print("WARNING: caller address - backtrace error: %s" % ex)
                    caller_address = "0x0"

                self.create_edge(int(caller_address, 16), message)

                break

            if signal != "SIGTRAP":
                break

            if first:
                self.create_node("gold")
                first = False
                continue

            self.create_node("gold")

            try:
                caller_address = self.pdj[0]["xrefs"][0]["addr"]
            except Exception as ex:
                print("WARNING: caller address - xref not there: %s" % ex)
                try:
                    caller_address = bt.splitlines()[1].split()[1]
                except Exception as ex:
                    print("WARNING: caller address - backtrace erro: %s" % ex)
                    continue

            # create edge
            self.create_edge(caller_address, self.count)

        # create png
        self.graph_obj.create_png(self.file_name)