Beispiel #1
0
    def output(self, filename):
        """
            Output the inheritance relation

            _filename is not used
            Args:
                _filename(string)
        """
        info = 'Inheritance\n'

        if not self.contracts:
            return

        info += blue('Child_Contract -> ') + green('Base_Contracts')
        for child in self.contracts:
            info += blue(f'\n+ {child.name}')
            if child.inheritance:
                info += ' -> ' + green(", ".join(map(str, child.inheritance)))

        info += green('\n\nBase_Contract -> ') + blue('Child_Contracts')
        for base in self.contracts:
            info += green(f'\n+ {base.name}')
            children = list(self._get_child_contracts(base))
            if children:
                info += ' -> ' + blue(", ".join(map(str, children)))
        self.info(info)
    def output(self, filename):
        """
        Output the inheritance relation

        _filename is not used
        Args:
            _filename(string)
        """
        info = "Inheritance\n"

        info += blue("Child_Contract -> ") + green("Immediate_Base_Contracts")
        info += green(" [Not_Immediate_Base_Contracts]")

        result = {"child_to_base": {}}

        for child in self.contracts:
            if child.is_top_level:
                continue
            info += blue(f"\n+ {child.name}\n")
            result["child_to_base"][child.name] = {"immediate": [], "not_immediate": []}
            if child.inheritance:

                immediate = child.immediate_inheritance
                not_immediate = [i for i in child.inheritance if i not in immediate]

                info += " -> " + green(", ".join(map(str, immediate))) + "\n"
                result["child_to_base"][child.name]["immediate"] = list(map(str, immediate))
                if not_immediate:
                    info += ", [" + green(", ".join(map(str, not_immediate))) + "]\n"
                    result["child_to_base"][child.name]["not_immediate"] = list(
                        map(str, not_immediate)
                    )

        info += green("\n\nBase_Contract -> ") + blue("Immediate_Child_Contracts") + "\n"
        info += blue(" [Not_Immediate_Child_Contracts]") + "\n"

        result["base_to_child"] = {}
        for base in self.contracts:
            if base.is_top_level:
                continue
            info += green(f"\n+ {base.name}") + "\n"
            children = list(self._get_child_contracts(base))

            result["base_to_child"][base.name] = {"immediate": [], "not_immediate": []}
            if children:
                immediate = [child for child in children if base in child.immediate_inheritance]
                not_immediate = [child for child in children if not child in immediate]

                info += " -> " + blue(", ".join(map(str, immediate))) + "\n"
                result["base_to_child"][base.name]["immediate"] = list(map(str, immediate))
                if not_immediate:
                    info += ", [" + blue(", ".join(map(str, not_immediate))) + "]" + "\n"
                    result["base_to_child"][base.name]["not_immediate"] = list(map(str, immediate))
        self.info(info)

        res = self.generate_output(info, additional_fields=result)

        return res
Beispiel #3
0
def run(filename, mod_name):
    """Executes script"""

    # Init Slither
    slither = Slither(filename)
    if not len(slither.contracts):
        print(f"Error: Slither could not find any contracts")
        exit(-1)

    print(f"== Functions with {yellow(mod_name)} modifier ==")
    txt = ""
    for c in slither.contracts:
            txt += blue(f"\n+ Contract {c.name}\n")

            collect = collections.defaultdict(list)

            for f in filter_by_modifier(c.functions, mod_name):
                collect[f.contract.name].append((f.full_name, f.visibility))
            
            for contract, function_visi_pairs in collect.items():
                txt += blue(f"  - From {contract}\n")
                
                function_visi_pairs = sorted(function_visi_pairs)

                for function, visi in function_visi_pairs:
                    if visi in ['external', 'public']:
                        txt += green(f"    - {function} ({visi})\n")
                
                for function, visi in function_visi_pairs:
                    if visi in ['internal', 'private']:
                        txt += magenta(f"    - {function} ({visi})\n")
                
                for function, visi in function_visi_pairs:
                    if visi not in ['external', 'public', 'internal', 'private']:
                        txt += f"    - {function}  ({visi})\n"

    print(txt)
Beispiel #4
0
    def output(self, _filename):
        """
            _filename is not used
            Args:
                _filename(string)
        """

        txt = ""
        for c in self.contracts:
            (name, _inheritance, _var, func_summaries,
             _modif_summaries) = c.get_summary()
            txt += blue("\n+ Contract %s\n" % name)
            # (c_name, f_name, visi, _, _, _, _, _) in func_summaries
            public = [(elem[0], (elem[1], elem[2])) for elem in func_summaries]

            collect = collections.defaultdict(list)
            for a, b in public:
                collect[a].append(b)
            public = list(collect.items())

            for contract, functions in public:
                txt += blue("  - From {}\n".format(contract))
                functions = sorted(functions)
                for (function, visi) in functions:
                    if visi in ['external', 'public']:
                        txt += green("    - {} ({})\n".format(function, visi))
                for (function, visi) in functions:
                    if visi in ['internal', 'private']:
                        txt += magenta("    - {} ({})\n".format(
                            function, visi))
                for (function, visi) in functions:
                    if visi not in [
                            'external', 'public', 'internal', 'private'
                    ]:
                        txt += "    - {}  ({})\n".format(function, visi)

        self.info(txt)
Beispiel #5
0
def run(filename):
    """Executes script"""

    # Init Slither
    slither = Slither(filename)
    if not len(slither.contracts):
        print(f"Error: Slither could not find any contracts")
        exit(-1)

    text = ""
    for c in slither.contracts:
        text += blue(f"\n+ Contract {c.name}\n")

        collect = collections.defaultdict(list)

        collect[c.name].append(c.modifiers)
        text += "\n" + '\n'.join([m.name for m in c.modifiers]) + "\n"
    print(text)
Beispiel #6
0
    def output(self, _filename):
        """
            _filename is not used
            Args:
                _filename(string)
        """

        txt = ""
        for c in self.contracts:
            (name, _inheritance, _var, func_summaries, _modif_summaries) = c.get_summary()
            txt += blue("\n+ Contract %s\n"%name)
            for (f_name, visi, _, _, _, _, _) in func_summaries:
                txt += "  - "
                if visi in ['external', 'public']:
                    txt += green("%s (%s)\n"%(f_name, visi))
                elif visi in ['internal', 'private']:
                    txt += magenta("%s (%s)\n"%(f_name, visi))
                else:
                    txt += "%s (%s)\n"%(f_name, visi)
        self.info(txt)
Beispiel #7
0
    def output(self, filename):
        """
            Output the inheritance relation

            _filename is not used
            Args:
                _filename(string)
        """
        info = 'Inheritance\n'

        if not self.contracts:
            return

        info += blue('Child_Contract -> ') + green('Immediate_Base_Contracts')
        info += green(' [Not_Immediate_Base_Contracts]')
        for child in self.contracts:
            info += blue(f'\n+ {child.name}')
            if child.inheritance:
                immediate = child.immediate_inheritance
                not_immediate = [
                    i for i in child.inheritance if i not in immediate
                ]
                info += ' -> ' + green(", ".join(map(str, immediate)))
                if not_immediate:
                    info += ", [" + green(", ".join(map(str,
                                                        not_immediate))) + "]"

        info += green('\n\nBase_Contract -> ') + blue(
            'Immediate_Child_Contracts')
        info += blue(' [Not_Immediate_Child_Contracts]')
        for base in self.contracts:
            info += green(f'\n+ {base.name}')
            children = list(self._get_child_contracts(base))
            if children:
                immediate = [
                    child for child in children
                    if base in child.immediate_inheritance
                ]
                not_immediate = [
                    child for child in children if not child in immediate
                ]
                info += ' -> ' + blue(", ".join(map(str, immediate)))
                if not_immediate:
                    info += ', [' + blue(", ".join(map(str,
                                                       not_immediate))) + ']'
        self.info(info)
Beispiel #8
0
def main_impl(all_detector_classes, all_printer_classes):
    """
    :param all_detector_classes: A list of all detectors that can be included/excluded.
    :param all_printer_classes: A list of all printers that can be included.
    """
    # Set logger of Slither to info, to catch warnings related to the arg parsing
    logger.setLevel(logging.INFO)
    args = parse_args(all_detector_classes, all_printer_classes)

    # Set colorization option
    set_colorization_enabled(not args.disable_color)

    # Define some variables for potential JSON output
    json_results = {}
    output_error = None
    outputting_json = args.json is not None
    outputting_json_stdout = args.json == '-'
    outputting_zip = args.zip is not None
    if args.zip_type not in ZIP_TYPES_ACCEPTED.keys():
        logger.error(f'Zip type not accepted, it must be one of {",".join(ZIP_TYPES_ACCEPTED.keys())}')

    # If we are outputting JSON, capture all standard output. If we are outputting to stdout, we block typical stdout
    # output.
    if outputting_json:
        StandardOutputCapture.enable(outputting_json_stdout)

    printer_classes = choose_printers(args, all_printer_classes)
    detector_classes = choose_detectors(args, all_detector_classes)

    default_log = logging.INFO if not args.debug else logging.DEBUG

    for (l_name, l_level) in [('Slither', default_log),
                              ('Contract', default_log),
                              ('Function', default_log),
                              ('Node', default_log),
                              ('Parsing', default_log),
                              ('Detectors', default_log),
                              ('FunctionSolc', default_log),
                              ('ExpressionParsing', default_log),
                              ('TypeParsing', default_log),
                              ('SSA_Conversion', default_log),
                              ('Printers', default_log),
                              # ('CryticCompile', default_log)
                              ]:
        l = logging.getLogger(l_name)
        l.setLevel(l_level)

    console_handler = logging.StreamHandler()
    console_handler.setLevel(logging.INFO)

    console_handler.setFormatter(FormatterCryticCompile())

    crytic_compile_error = logging.getLogger(('CryticCompile'))
    crytic_compile_error.addHandler(console_handler)
    crytic_compile_error.propagate = False
    crytic_compile_error.setLevel(logging.INFO)

    results_detectors = []
    results_printers = []
    try:
        filename = args.filename

        # Determine if we are handling ast from solc
        if args.solc_ast or (filename.endswith('.json') and not is_supported(filename)):
            globbed_filenames = glob.glob(filename, recursive=True)
            filenames = glob.glob(os.path.join(filename, "*.json"))
            if not filenames:
                filenames = globbed_filenames
            number_contracts = 0

            slither_instances = []
            if args.splitted:
                (slither_instance, results_detectors, results_printers, number_contracts) = process_from_asts(filenames,
                                                                                                              args,
                                                                                                              detector_classes,
                                                                                                              printer_classes)
                slither_instances.append(slither_instance)
            else:
                for filename in filenames:
                    (slither_instance, results_detectors_tmp, results_printers_tmp,
                     number_contracts_tmp) = process_single(filename, args, detector_classes, printer_classes)
                    number_contracts += number_contracts_tmp
                    results_detectors += results_detectors_tmp
                    results_printers += results_printers_tmp
                    slither_instances.append(slither_instance)

        # Rely on CryticCompile to discern the underlying type of compilations.
        else:
            (slither_instances, results_detectors, results_printers, number_contracts) = process_all(filename, args,
                                                                                                     detector_classes,
                                                                                                     printer_classes)

        # Determine if we are outputting JSON
        if outputting_json or outputting_zip:
            # Add our compilation information to JSON
            if 'compilations' in args.json_types:
                compilation_results = []
                for slither_instance in slither_instances:
                    compilation_results.append(generate_standard_export(slither_instance.crytic_compile))
                json_results['compilations'] = compilation_results

            # Add our detector results to JSON if desired.
            if results_detectors and 'detectors' in args.json_types:
                json_results['detectors'] = results_detectors

            # Add our printer results to JSON if desired.
            if results_printers and 'printers' in args.json_types:
                json_results['printers'] = results_printers

            # Add our detector types to JSON
            if 'list-detectors' in args.json_types:
                detectors, _ = get_detectors_and_printers()
                json_results['list-detectors'] = output_detectors_json(detectors)

            # Add our detector types to JSON
            if 'list-printers' in args.json_types:
                _, printers = get_detectors_and_printers()
                json_results['list-printers'] = output_printers_json(printers)

        # Output our results to markdown if we wish to compile a checklist.
        if args.checklist:
            output_results_to_markdown(results_detectors)

        # Dont print the number of result for printers
        if number_contracts == 0:
            logger.warning(red('No contract was analyzed'))
        if printer_classes:
            logger.info('%s analyzed (%d contracts)', filename, number_contracts)
        else:
            logger.info('%s analyzed (%d contracts with %d detectors), %d result(s) found', filename,
                        number_contracts, len(detector_classes), len(results_detectors))

        logger.info(blue('Use https://crytic.io/ to get access to additional detectors and Github integration'))
        if args.ignore_return_value:
            return

    except SlitherException as se:
        output_error = str(se)
        traceback.print_exc()
        logging.error(red('Error:'))
        logging.error(red(output_error))
        logging.error('Please report an issue to https://github.com/crytic/slither/issues')

    except Exception:
        output_error = traceback.format_exc()
        logging.error(traceback.print_exc())
        logging.error('Error in %s' % args.filename)
        logging.error(output_error)


    # If we are outputting JSON, capture the redirected output and disable the redirect to output the final JSON.
    if outputting_json:
        if 'console' in args.json_types:
            json_results['console'] = {
                'stdout': StandardOutputCapture.get_stdout_output(),
                'stderr': StandardOutputCapture.get_stderr_output()
            }
        StandardOutputCapture.disable()
        output_to_json(None if outputting_json_stdout else args.json, output_error, json_results)

    if outputting_zip:
        output_to_zip(args.zip, output_error, json_results, args.zip_type)

    # Exit with the appropriate status code
    if output_error:
        sys.exit(-1)
    else:
        exit(results_detectors)
Beispiel #9
0
    def output(self, _filename):
        """
            _filename is not used
            Args:
                _filename(string)
        """

        txt = ""

        all_contracts = []
        for c in self.contracts:
            if c.is_top_level:
                continue

            is_upgradeable_proxy = c.is_upgradeable_proxy
            is_upgradeable = c.is_upgradeable

            additional_txt_info = ''

            if is_upgradeable_proxy:
                additional_txt_info += ' (Upgradeable Proxy)'

            if is_upgradeable:
                additional_txt_info += ' (Upgradeable)'

            if c in self.slither.contracts_derived:
                additional_txt_info += ' (Most derived contract)'

            txt += blue(f"\n+ Contract {c.name}{additional_txt_info}\n")
            additional_fields = output.Output(
                '',
                additional_fields={
                    'is_upgradeable_proxy': is_upgradeable_proxy,
                    'is_upgradeable': is_upgradeable,
                    'is_most_derived': c in self.slither.contracts_derived
                })

            # Order the function with
            # contract_declarer -> list_functions
            public = [(f.contract_declarer.name, f) for f in c.functions
                      if (not f.is_shadowed and not f.is_constructor_variables)
                      ]
            collect = collections.defaultdict(list)
            for a, b in public:
                collect[a].append(b)
            public = list(collect.items())

            for contract, functions in public:
                txt += blue("  - From {}\n".format(contract))

                functions = sorted(functions, key=lambda f: f.full_name)

                for function in functions:
                    if function.visibility in ['external', 'public']:
                        txt += green("    - {} ({})\n".format(
                            function.full_name, function.visibility))
                    if function.visibility in ['internal', 'private']:
                        txt += magenta("    - {} ({})\n".format(
                            function.full_name, function.visibility))
                    if function.visibility not in [
                            'external', 'public', 'internal', 'private'
                    ]:
                        txt += "    - {}  ({})\n".format(
                            function.full_name, function.visibility)

                    additional_fields.add(
                        function,
                        additional_fields={"visibility": function.visibility})

            all_contracts.append((c, additional_fields.data))

        self.info(txt)

        res = self.generate_output(txt)
        for contract, additional_fields in all_contracts:
            res.add(contract, additional_fields=additional_fields)

        return res
    def output(self, _filename):  # pylint: disable=too-many-locals
        """
        _filename is not used
        Args:
            _filename(string)
        """

        txt = ""

        all_contracts = []
        for c in self.contracts:
            if c.is_top_level:
                continue

            is_upgradeable_proxy = c.is_upgradeable_proxy
            is_upgradeable = c.is_upgradeable

            additional_txt_info = ""

            if is_upgradeable_proxy:
                additional_txt_info += " (Upgradeable Proxy)"

            if is_upgradeable:
                additional_txt_info += " (Upgradeable)"

            if c in self.slither.contracts_derived:
                additional_txt_info += " (Most derived contract)"

            txt += blue(f"\n+ Contract {c.name}{additional_txt_info}\n")
            additional_fields = output.Output(
                "",
                additional_fields={
                    "is_upgradeable_proxy": is_upgradeable_proxy,
                    "is_upgradeable": is_upgradeable,
                    "is_most_derived": c in self.slither.contracts_derived,
                },
            )

            # Order the function with
            # contract_declarer -> list_functions
            public = [
                (f.contract_declarer.name, f)
                for f in c.functions
                if (not f.is_shadowed and not f.is_constructor_variables)
            ]
            collect = collections.defaultdict(list)
            for a, b in public:
                collect[a].append(b)
            public = list(collect.items())

            for contract, functions in public:
                txt += blue(f"  - From {contract}\n")

                functions = sorted(functions, key=lambda f: f.full_name)

                for function in functions:
                    if function.visibility in ["external", "public"]:
                        txt += green(f"    - {function.full_name} ({function.visibility})\n")
                    if function.visibility in ["internal", "private"]:
                        txt += magenta(f"    - {function.full_name} ({function.visibility})\n")
                    if function.visibility not in [
                        "external",
                        "public",
                        "internal",
                        "private",
                    ]:
                        txt += f"    - {function.full_name}  ({function.visibility})\n"

                    additional_fields.add(
                        function, additional_fields={"visibility": function.visibility}
                    )

            all_contracts.append((c, additional_fields.data))

        self.info(txt)

        res = self.generate_output(txt)
        for contract, additional_fields in all_contracts:
            res.add(contract, additional_fields=additional_fields)

        return res
Beispiel #11
0
    def output(self, _filename):
        """
        _filename is not used
        Args:
            _filename(string)
        """

        txt = ""
        if not self.slither.crytic_compile:
            txt = "The EVM printer requires to compile with crytic-compile"
            self.info(red(txt))
            res = self.generate_output(txt)
            return res
        evm_info = _extract_evm_info(self.slither)

        for contract in self.slither.contracts_derived:
            txt += blue("Contract {}\n".format(contract.name))

            contract_file = self.slither.source_code[
                contract.source_mapping["filename_absolute"]
            ].encode("utf-8")
            contract_file_lines = open(
                contract.source_mapping["filename_absolute"], "r"
            ).readlines()

            contract_pcs = {}
            contract_cfg = {}

            for function in contract.functions:
                txt += blue(f"\tFunction {function.canonical_name}\n")

                # CFG and source mapping depend on function being constructor or not
                if function.is_constructor:
                    contract_cfg = evm_info["cfg_init", contract.name]
                    contract_pcs = evm_info["mapping_init", contract.name]
                else:
                    contract_cfg = evm_info["cfg", contract.name]
                    contract_pcs = evm_info["mapping", contract.name]

                for node in function.nodes:
                    txt += green("\t\tNode: " + str(node) + "\n")
                    node_source_line = (
                        contract_file[0 : node.source_mapping["start"]].count("\n".encode("utf-8"))
                        + 1
                    )
                    txt += green(
                        "\t\tSource line {}: {}\n".format(
                            node_source_line,
                            contract_file_lines[node_source_line - 1].rstrip(),
                        )
                    )
                    txt += magenta("\t\tEVM Instructions:\n")
                    node_pcs = contract_pcs.get(node_source_line, [])
                    for pc in node_pcs:
                        txt += magenta(
                            "\t\t\t0x{:x}: {}\n".format(
                                int(pc), contract_cfg.get_instruction_at(pc)
                            )
                        )

            for modifier in contract.modifiers:
                txt += blue(f"\tModifier {modifier.canonical_name}\n")
                for node in modifier.nodes:
                    txt += green("\t\tNode: " + str(node) + "\n")
                    node_source_line = (
                        contract_file[0 : node.source_mapping["start"]].count("\n".encode("utf-8"))
                        + 1
                    )
                    txt += green(
                        "\t\tSource line {}: {}\n".format(
                            node_source_line,
                            contract_file_lines[node_source_line - 1].rstrip(),
                        )
                    )
                    txt += magenta("\t\tEVM Instructions:\n")
                    node_pcs = contract_pcs.get(node_source_line, [])
                    for pc in node_pcs:
                        txt += magenta(
                            "\t\t\t0x{:x}: {}\n".format(
                                int(pc), contract_cfg.get_instruction_at(pc)
                            )
                        )

        self.info(txt)
        res = self.generate_output(txt)
        return res
Beispiel #12
0
    def output(self, filename):
        """
            Output the inheritance relation

            _filename is not used
            Args:
                _filename(string)
        """
        info = 'Inheritance\n'

        if not self.contracts:
            return

        info += blue('Child_Contract -> ') + green('Immediate_Base_Contracts')
        info += green(' [Not_Immediate_Base_Contracts]')

        result = {'child_to_base': {}}

        for child in self.contracts:
            if child.is_top_level:
                continue
            info += blue(f'\n+ {child.name}\n')
            result['child_to_base'][child.name] = {
                'immediate': [],
                'not_immediate': []
            }
            if child.inheritance:

                immediate = child.immediate_inheritance
                not_immediate = [
                    i for i in child.inheritance if i not in immediate
                ]

                info += ' -> ' + green(", ".join(map(str, immediate))) + '\n'
                result['child_to_base'][child.name]['immediate'] = list(
                    map(str, immediate))
                if not_immediate:
                    info += ", [" + green(", ".join(map(
                        str, not_immediate))) + "]\n"
                    result['child_to_base'][
                        child.name]['not_immediate'] = list(
                            map(str, not_immediate))

        info += green('\n\nBase_Contract -> ') + blue(
            'Immediate_Child_Contracts') + '\n'
        info += blue(' [Not_Immediate_Child_Contracts]') + '\n'

        result['base_to_child'] = {}
        for base in self.contracts:
            if base.is_top_level:
                continue
            info += green(f'\n+ {base.name}') + '\n'
            children = list(self._get_child_contracts(base))

            result['base_to_child'][base.name] = {
                'immediate': [],
                'not_immediate': []
            }
            if children:
                immediate = [
                    child for child in children
                    if base in child.immediate_inheritance
                ]
                not_immediate = [
                    child for child in children if not child in immediate
                ]

                info += ' -> ' + blue(", ".join(map(str, immediate))) + '\n'
                result['base_to_child'][base.name]['immediate'] = list(
                    map(str, immediate))
                if not_immediate:
                    info += ', [' + blue(", ".join(map(
                        str, not_immediate))) + ']' + '\n'
                    result['base_to_child'][base.name]['not_immediate'] = list(
                        map(str, immediate))
        self.info(info)

        res = self.generate_output(info, additional_fields=result)

        return res