Example #1
0
def test_detector(test_item: Test):
    set_solc(test_item)
    sl = Slither(test_item.test_file)
    sl.register_detector(test_item.detector)
    results = sl.run_detectors()

    with open(test_item.expected_result, encoding="utf8") as f:
        expected_result = json.load(f)

    results_as_string = json.dumps(results)
    current_path = str(pathlib.Path(pathlib.Path().absolute(), test_item.test_file).absolute())
    for additional_file in test_item.additional_files:
        additional_path = str(pathlib.Path(pathlib.Path().absolute(), additional_file).absolute())
        results_as_string = results_as_string.replace(
            additional_path, str(pathlib.Path(GENERIC_PATH))
        )
    results_as_string = results_as_string.replace(current_path, str(pathlib.Path(GENERIC_PATH)))
    results = json.loads(results_as_string)

    diff = DeepDiff(results, expected_result, ignore_order=True, verbose_level=2)
    if diff:
        pprint(diff)
        diff_as_dict = diff.to_dict()

        if "iterable_item_added" in diff_as_dict:
            print("#### Findings added")
            for findings_added in diff_as_dict["iterable_item_added"].values():
                for finding_added in findings_added:
                    print(finding_added["description"])
        if "iterable_item_removed" in diff_as_dict:
            print("#### Findings removed")
            for findings_added in diff_as_dict["iterable_item_removed"].values():
                for finding_added in findings_added:
                    print(finding_added["description"])
        assert False
Example #2
0
def main():
    args = parse_args()

    proxy_filename = vars(args)['proxy.sol']
    proxy = Slither(proxy_filename,
                    is_truffle=os.path.isdir(proxy_filename),
                    solc=args.solc,
                    disable_solc_warnings=True)
    proxy_name = args.ProxyName

    v1_filename = vars(args)['implem.sol']
    v1 = Slither(v1_filename,
                 is_truffle=os.path.isdir(v1_filename),
                 solc=args.solc,
                 disable_solc_warnings=True)
    v1_name = args.ContractName

    check_initialization(v1)

    if not args.new_version:
        compare_function_ids(v1, v1_name, proxy, proxy_name)
        compare_variables_order_proxy(v1, v1_name, proxy, proxy_name)
    else:
        v2 = Slither(args.new_version,
                     is_truffle=os.path.isdir(args.new_version),
                     solc=args.solc,
                     disable_solc_warnings=True)
        v2_name = v1_name if not args.new_contract_name else args.new_contract_name
        check_initialization(v2)
        compare_function_ids(v2, v2_name, proxy, proxy_name)
        compare_variables_order_proxy(v2, v2_name, proxy, proxy_name)
        compare_variables_order_implementation(v1, v1_name, v2, v2_name)
Example #3
0
def main():
    args = parse_args()

    # Perform slither analysis on the given filename
    slither = Slither(args.project, **vars(args))

    ret = defaultdict(list)

    if args.erc.upper() in ERCS:

        contract = slither.get_contract_from_name(args.contract_name)

        if not contract:
            err = f"Contract not found: {args.contract_name}"
            _log_error(err, args)
            return
        # First elem is the function, second is the event
        erc = ERCS[args.erc.upper()]
        generic_erc_checks(contract, erc[0], erc[1], ret)

        if args.erc.upper() in ADDITIONAL_CHECKS:
            ADDITIONAL_CHECKS[args.erc.upper()](contract, ret)

    else:
        err = f"Incorrect ERC selected {args.erc}"
        _log_error(err, args)
        return

    if args.json:
        output_to_json(args.json, None, {"upgradeability-check": ret})
Example #4
0
def _generate_test(test_item: Test, skip_existing=False):
    test_dir_path = pathlib.Path(
        pathlib.Path().absolute(),
        "tests",
        "detectors",
        test_item.detector.ARGUMENT,
        test_item.solc_ver,
    )
    test_file_path = str(pathlib.Path(test_dir_path, test_item.test_file))
    expected_result_path = str(pathlib.Path(test_dir_path, test_item.expected_result).absolute())

    if skip_existing:
        if os.path.isfile(expected_result_path):
            return

    set_solc(test_item)
    sl = Slither(test_file_path)
    sl.register_detector(test_item.detector)
    results = sl.run_detectors()

    results_as_string = json.dumps(results)
    results_as_string = results_as_string.replace(test_file_path, str(pathlib.Path(GENERIC_PATH)))

    for additional_file in test_item.additional_files:
        additional_path = str(pathlib.Path(test_dir_path, additional_file).absolute())
        results_as_string = results_as_string.replace(
            additional_path, str(pathlib.Path(GENERIC_PATH))
        )

    results = json.loads(results_as_string)
    with open(expected_result_path, "w") as f:
        f.write(json.dumps(results, indent=4))
Example #5
0
def _generate_test(test_item: Test, skip_existing=False):

    if skip_existing:
        if os.path.isfile(test_item.expected_result):
            return

    set_solc(test_item)
    sl = Slither(test_item.test_file)
    sl.register_detector(test_item.detector)
    results = sl.run_detectors()

    results_as_string = json.dumps(results)
    current_path = str(pathlib.Path(pathlib.Path().absolute(), test_item.test_file).absolute())
    results_as_string = results_as_string.replace(current_path, str(pathlib.Path(GENERIC_PATH)))

    for additional_file in test_item.additional_files:
        additional_path = str(pathlib.Path(pathlib.Path().absolute(), additional_file).absolute())
        results_as_string = results_as_string.replace(
            additional_path, str(pathlib.Path(GENERIC_PATH))
        )

    results = json.loads(results_as_string)

    with open(test_item.expected_result, "w") as f:
        f.write(json.dumps(results, indent=4))
Example #6
0
def test_parsing(test_item: Test):
    flavors = ["compact"]
    if not test_item.disable_legacy:
        flavors += ["legacy"]
    for version, flavor in test_item.versions_with_flavors:
        test_file = os.path.join(
            TEST_ROOT, "compile",
            f"{test_item.test_file}-{version}-{flavor}.zip")
        expected_file = os.path.join(
            TEST_ROOT, "expected",
            f"{test_item.test_file}-{version}-{flavor}.json")

        cc = load_from_zip(test_file)[0]

        sl = Slither(
            cc,
            solc_force_legacy_json=flavor == "legacy",
            disallow_partial=True,
            skip_analyze=True,
        )

        actual = generate_output(sl)

        try:
            with open(expected_file, "r", encoding="utf8") as f:
                expected = json.load(f)
        except OSError:
            pytest.xfail("the file for this test was not generated")
            raise

        diff = DeepDiff(expected,
                        actual,
                        ignore_order=True,
                        verbose_level=2,
                        view="tree")

        if diff:
            for change in diff.get("values_changed", []):
                path_list = re.findall(r"\['(.*?)'\]", change.path())
                path = "_".join(path_list)
                with open(
                        f"test_artifacts/{test_item.test_file}_{path}_expected.dot",
                        "w",
                        encoding="utf8",
                ) as f:
                    f.write(change.t1)
                with open(
                        f"test_artifacts/{test_item.test_file}_{version}_{flavor}_{path}_actual.dot",
                        "w",
                        encoding="utf8",
                ) as f:
                    f.write(change.t2)

        assert not diff, diff.pretty()

        sl = Slither(cc,
                     solc_force_legacy_json=flavor == "legacy",
                     disallow_partial=True)
        sl.register_printer(Echidna)
        sl.run_printers()
Example #7
0
def main() -> None:
    args = parse_args()

    if len(args.contract_source) == 2:
        # Source code is file.sol or project directory
        source_code, target = args.contract_source
        slither = Slither(source_code, **vars(args))
    else:
        # Source code is published and retrieved via etherscan
        target = args.contract_source[0]
        slither = Slither(target, **vars(args))

    if args.contract_name:
        contracts = slither.get_contract_from_name(args.contract_name)
    else:
        contracts = slither.contracts

    srs = SlitherReadStorage(contracts, args.max_depth)

    if args.rpc_url:
        # Remove target prefix e.g. rinkeby:0x0 -> 0x0.
        address = target[target.find(":") + 1:]
        # Default to implementation address unless a storage address is given.
        if not args.storage_address:
            args.storage_address = address
        srs.storage_address = args.storage_address

        srs.rpc = args.rpc_url

    if args.layout:
        srs.get_all_storage_variables()
        srs.get_storage_layout()
    else:
        assert args.variable_name
        # Use a lambda func to only return variables that have same name as target.
        # x is a tuple (`Contract`, `StateVariable`).
        srs.get_all_storage_variables(
            lambda x: bool(x[1].name == args.variable_name))
        srs.get_target_variables(**vars(args))

    # To retrieve slot values an rpc url is required.
    if args.value:
        assert args.rpc_url
        srs.get_slot_values()

    # Only write file if storage layout is used.
    if len(srs.slot_info) > 1:
        with open("storage_layout.json", "w", encoding="utf-8") as file:
            json.dump(srs.slot_info, file, indent=4)
Example #8
0
def main():
    args = parse_args()

    slither = Slither(args.filename, **vars(args))
    flat = Flattening(slither, external_to_public=args.convert_external)

    flat.export(target=args.contract)
def _generate_test(test_item: Item, skip_existing=False):
    flavor = "legacy" if test_item.is_legacy else "compact"
    test_file = os.path.join(TEST_ROOT,
                             f"{test_item.test_id}-{test_item.base_ver}.sol")
    expected_file = os.path.join(
        TEST_ROOT, "expected",
        f"{test_item.test_id}-{test_item.solc_ver}-{flavor}.json")

    if skip_existing:
        if os.path.isfile(expected_file):
            return
    if id_test(test_item) in XFAIL:
        return
    set_solc(test_item)
    sl = Slither(
        test_file,
        solc_force_legacy_json=test_item.is_legacy,
        disallow_partial=True,
        skip_analyze=True,
    )

    actual = generate_output(sl)
    print(f"Generate {expected_file}")
    with open(expected_file, "w") as f:
        json.dump(actual, f, indent="  ")
Example #10
0
def main():
    args = parse_args()

    slither = Slither(args.filename, **vars(args))
    flat = Flattening(
        slither,
        external_to_public=args.convert_external,
        remove_assert=args.remove_assert,
        private_to_internal=args.convert_private,
        export_path=args.dir,
    )

    try:
        strategy = Strategy[args.strategy]
    except KeyError:
        logger.error(
            f"{args.strategy} is not a valid strategy, use: {STRATEGIES_NAMES} (default MostDerived)"
        )
        return
    flat.export(
        strategy=strategy,
        target=args.contract,
        json=args.json,
        zip=args.zip,
        zip_type=args.zip_type,
    )
Example #11
0
def encode_contract(cfilename, **kwargs):
    r = dict()

    # Init slither
    try:
        slither = Slither(cfilename, **kwargs)
    except Exception:  # pylint: disable=broad-except
        simil_logger.error("Compilation failed for %s using %s", cfilename,
                           kwargs["solc"])
        return r

    # Iterate over all the contracts
    for contract in slither.contracts:

        # Iterate over all the functions
        for function in contract.functions_declared:

            if function.nodes == [] or function.is_constructor_variables:
                continue

            x = (cfilename, contract.name, function.name)

            r[x] = []

            # Iterate over the nodes of the function
            for node in function.nodes:
                # Print the Solidity expression of the nodes
                # And the SlithIR operations
                if node.expression:
                    for ir in node.irs:
                        r[x].append(encode_ir(ir))
    return r
Example #12
0
def main():
    args = parse_args()

    # Perform slither analysis on the given filename
    _slither = Slither(args.filename, **vars(args))

    logger.info("Analysis done!")
Example #13
0
def test_ternary_conversions() -> None:
    """This tests that true and false sons define the same number of variables that the father node declares"""
    slither = Slither("./tests/slithir/ternary_expressions.sol")
    for contract in slither.contracts:
        for function in contract.functions:
            for node in function.nodes:
                if node.type in [NodeType.IF, NodeType.IFLOOP]:
                    vars_declared = 0
                    vars_assigned = 0

                    # Iterate over true and false son
                    for inner_node in node.sons:
                        # Count all variables declared
                        expression = inner_node.expression
                        if isinstance(expression, AssignmentOperation):
                            var_expr = expression.expression_left
                            # Only tuples declare more than one var
                            if isinstance(var_expr, TupleExpression):
                                vars_declared += len(var_expr.expressions)
                            else:
                                vars_declared += 1

                        for ir in inner_node.irs:
                            # Count all variables defined
                            if isinstance(ir, Assignment):
                                vars_assigned += 1

                    assert vars_declared == vars_assigned
Example #14
0
def test_storage_layout():
    subprocess.run(["solc-select", "use", "0.8.10"],
                   stdout=subprocess.PIPE,
                   check=True)

    test_item = os.path.join(STORAGE_TEST_ROOT, "storage_layout-0.8.10.sol")

    sl = Slither(test_item,
                 solc_force_legacy_json=False,
                 disallow_partial=True)

    with Popen(["solc", test_item, "--storage-layout"],
               stdout=PIPE) as process:
        for line in process.stdout:  # parse solc output
            if '{"storage":[{' in line.decode(
                    "utf-8"):  # find the storage layout
                layout = iter(json.loads(line)["storage"])
                while True:
                    try:
                        for contract in sl.contracts:
                            curr_var = next(layout)
                            var_name = curr_var["label"]
                            sl_name = contract.variables_as_dict[var_name]
                            slot, offset = contract.compilation_unit.storage_layout_of(
                                contract, sl_name)
                            assert slot == int(curr_var["slot"])
                            assert offset == int(curr_var["offset"])
                    except StopIteration:
                        break
                    except KeyError as e:
                        print(f"not found {e} ")
Example #15
0
def encode_contract(cfilename, **kwargs):
    r = dict()

    # Init slither
    try:
        slither = Slither(cfilename, **kwargs)
    except:
        simil_logger.error("Compilation failed for %s using %s", cfilename,
                           kwargs['solc'])
        return r

    # Iterate over all the contracts
    for contract in slither.contracts:

        # Iterate over all the functions
        for function in contract.functions_not_inherited:

            if function.nodes == []:
                continue

            x = (cfilename, contract.name, function.name)

            r[x] = []

            # Iterate over the nodes of the function
            for node in function.nodes:
                # Print the Solidity expression of the nodes
                # And the SlithIR operations
                if node.expression:
                    for ir in node.irs:
                        r[x].append(encode_ir(ir))
    return r
Example #16
0
def _generate_test(test_item: Item, skip_existing=False):
    flavor = "legacy" if test_item.is_legacy else "compact"
    test_file = os.path.join(
        TEST_ROOT, "compile", f"{test_item.test_id}-{test_item.solc_ver}-{flavor}.zip"
    )
    expected_file = os.path.join(
        TEST_ROOT, "expected", f"{test_item.test_id}-{test_item.solc_ver}-{flavor}.json"
    )

    if expected_file in XFAIL:
        return
    if skip_existing:
        if os.path.isfile(expected_file):
            return
    if id_test(test_item) in XFAIL:
        return
    # set_solc(test_item)
    try:
        sl = Slither(
            test_file,
            solc_force_legacy_json=test_item.is_legacy,
            disallow_partial=True,
            skip_analyze=True,
        )
    # pylint: disable=broad-except
    except Exception:
        print(test_item)
        print(f"{expected_file} failed")
        return

    actual = generate_output(sl)
    print(f"Generate {expected_file}")
    with open(expected_file, "w") as f:
        json.dump(actual, f, indent="  ")
Example #17
0
def test_parsing(test_item: Item):
    flavor = "legacy" if test_item.is_legacy else "compact"
    test_file = os.path.join(
        TEST_ROOT, "compile",
        f"{test_item.test_id}-{test_item.solc_ver}-{flavor}.zip")
    expected_file = os.path.join(
        TEST_ROOT, "expected",
        f"{test_item.test_id}-{test_item.solc_ver}-{flavor}.json")

    if id_test(test_item) in XFAIL:
        pytest.xfail("this test needs to be fixed")

    # set_solc(test_item)

    cc = load_from_zip(test_file)[0]

    sl = Slither(
        cc,
        solc_force_legacy_json=test_item.is_legacy,
        disallow_partial=True,
        skip_analyze=True,
    )

    actual = generate_output(sl)

    try:
        with open(expected_file, "r") as f:
            expected = json.load(f)
    except OSError:
        pytest.xfail("the file for this test was not generated")
        raise

    diff = DeepDiff(expected,
                    actual,
                    ignore_order=True,
                    verbose_level=2,
                    view="tree")

    if diff:
        for change in diff.get("values_changed", []):
            path_list = re.findall(r"\['(.*?)'\]", change.path())
            path = "_".join(path_list)
            with open(
                    f"test_artifacts/{id_test(test_item)}_{path}_expected.dot",
                    "w") as f:
                f.write(change.t1)
            with open(f"test_artifacts/{id_test(test_item)}_{path}_actual.dot",
                      "w") as f:
                f.write(change.t2)

    assert not diff, diff.pretty()

    sl = Slither(cc,
                 solc_force_legacy_json=test_item.is_legacy,
                 disallow_partial=True)
    sl.register_printer(Echidna)
    sl.run_printers()
def kspec_coverage(args):

    contract = args.contract
    kspec = args.kspec

    slither = Slither(contract, **vars(args))

    # Run the analysis on the Klab specs
    run_analysis(args, slither, kspec)
Example #19
0
def main():
    args = parse_args()

    slither = Slither(args.filename, **vars(args))
    flat = Flattening(slither,
                      external_to_public=args.convert_external,
                      remove_assert=args.remove_assert,
                      private_to_internal=args.convert_private)

    flat.export(target=args.contract)
Example #20
0
def main():

    args = parse_args()

    print(args.codebase)
    sl = Slither(args.codebase, **vars(args))

    for M in _get_mutators():
        m = M(sl)
        m.mutate()
Example #21
0
def main(fname):
    try:
        slither = Slither(fname)

        with open(fname, "r") as src_file:
            src = ''.join(src_file.readlines())
            for contract in slither.contracts:
                for function in contract.functions_declared:
                    extract_loops(contract, function, src)
    except Exception as e:
        print("FAILED TO RUN: {0}".format(fname))
        print(e)
Example #22
0
def main():
    args = parse_args()

    # Perform slither analysis on the given filename
    slither = Slither(args.filename, **vars(args))

    contract = slither.get_contract_from_name(args.contract)
    if not contract:
        if len(slither.contracts) == 1:
            contract = slither.contracts[0]
        else:
            if args.contract is None:
                logger.error(f'Specify the target: --contract ContractName')
            else:
                logger.error(f'{args.contract} not found')
            return

    addresses = Addresses(args.address_owner, args.address_user,
                          args.address_attacker)

    generate_erc20(contract, args.scenario, addresses)
    def do_filter_contract(self):
        """
        判断当前合约是否具有交易功能
        """
        slither = Slither(self.file_name)
        for contract in slither.contracts:

            for function in contract.functions:
                if function.can_send_eth():
                    # 只分析存在交易行为的函数
                    return True

        return False
Example #24
0
def kspec_coverage(args):

    contract = args.contract
    kspec = args.kspec

    slither = Slither(contract, **vars(args))

    compilation_units = slither.compilation_units
    if len(compilation_units) != 1:
        print("Only single compilation unit supported")
        return
    # Run the analysis on the Klab specs
    run_analysis(args, compilation_units[0], kspec)
Example #25
0
def main():

    args = parse_args()
    slither = Slither(args.filename, is_truffle=os.path.isdir(args.filename), solc=args.solc)

    slither.register_printer(PrinterCallGraphStateChange)

    slither.run_printers()
    def do_analyze_a_file_for_cfg_pdg(self):

        if self.cfg_filter is None:
            return

        print("使用过滤器:", self.cfg_filter)
        slither = Slither(self.file_name)
        for contract in slither.contracts:

            # 构建过滤器
            contract_filter = {}
            if contract.name in self.cfg_filter:
                print("匹配到过滤器合约:{}".format(contract.name))
                for target_function in self.cfg_filter[contract.name]:
                    contract_filter[target_function] = 1
            else:
                continue

            contract_info = ContractInfo(contract)  # 1.合约信息抽取
            for function in contract.functions:

                if function.name in contract_filter:

                    print("【********】开始分析: {}".format(function.name))

                    # 简易流程,目标是获得CFG 和 PDG
                    function_info = FunctionInfo(contract_info,
                                                 function,
                                                 test_mode=0,
                                                 simple=1)  # 函数对象
                    if function_info.cfg is None:
                        continue  # 没有cfg

                    control_flow_analyzer = ControlFlowAnalyzer(
                        contract_info, function_info)  # 当前函数的控制流分析器
                    data_flow_analyzer = DataFlowAnalyzer(
                        contract_info, function_info)  # 当前函数的数据流分析器
                    code_constructor = CodeGraphConstructor(contract_info,
                                                            function_info,
                                                            mode=0)  # 代码图表示构建器

                    # PDG分析
                    control_flow_analyzer.do_control_dependency_analyze(
                    )  # 控制流分析
                    data_flow_analyzer.do_data_semantic_analyze()  # 数据流分析

                    # 获得psc表示
                    function_info.save_psc_to_file()

                    # 获得CFG和PDG
                    code_constructor.get_cfg_and_pdg()
Example #27
0
def main():
    # ------------------------------
    # PossiblePaths.py
    #       Usage: python3 possible_paths.py filename targets
    #       Example: python3 possible_paths.py contract.sol contract1.function1 contract2.function2 contract3.function3
    # ------------------------------
    # Parse all arguments
    args = parse_args()

    # Perform slither analysis on the given filename
    slither = Slither(args.filename,
                      is_truffle=os.path.isdir(args.filename),
                      solc=args.solc,
                      disable_solc_warnings=True)

    try:
        targets = resolve_functions(slither, args.targets)
    except ResolveFunctionException as r:
        print(red(r))
        exit(-1)

    # Print out all target functions.
    print(f"Target functions:")
    for target in targets:
        print(f"- {target.contract.name}.{target.full_name}")
    print("\n")

    # Obtain all paths which reach the target functions.
    reaching_paths = find_target_paths(slither, targets)
    reaching_functions = set(
        [y for x in reaching_paths for y in x if y not in targets])

    # Print out all function names which can reach the targets.
    print(f"The following functions reach the specified targets:")
    for function_desc in sorted(
        [f"{f.contract.name}.{f.full_name}" for f in reaching_functions]):
        print(f"- {function_desc}")
    print("\n")

    # Format all function paths.
    reaching_paths_str = [
        ' -> '.join(
            [f"{f.contract.name}.{f.full_name}" for f in reaching_path])
        for reaching_path in reaching_paths
    ]

    # Print a sorted list of all function paths which can reach the targets.
    print(f"The following paths reach the specified targets:")
    for reaching_path in sorted(reaching_paths_str):
        print(f"{reaching_path}\n")
Example #28
0
def main():
    args = parse_args()

    proxy = Slither(vars(args)['proxy.sol'], solc=args.solc)
    proxy_name = args.ProxyName
    v1 = Slither(vars(args)['implem.sol'], solc=args.solc)
    v1_name = args.ContractName

    last_contract = v1
    last_name = v1_name

    if args.new_version:
        v2 = Slither(args.new_version, solc=args.solc)
        last_contract = v2

    if args.new_contract_name:
        last_name = args.new_contract_name

    compare_function_ids(last_contract, proxy)
    compare_variables_order_proxy(last_contract, last_name, proxy, proxy_name)

    if args.new_version:
        compare_variables_order_implementation(v1, v1_name, v2, last_name)
Example #29
0
def main():
    args = parse_args()

    proxy_filename = vars(args)['proxy.sol']
    proxy = Slither(proxy_filename, **vars(args))
    proxy_name = args.ProxyName

    v1_filename = vars(args)['implem.sol']
    v1 = Slither(v1_filename, **vars(args))
    v1_name = args.ContractName

    check_initialization(v1)

    if not args.new_version:
        compare_function_ids(v1, v1_name, proxy, proxy_name)
        compare_variables_order_proxy(v1, v1_name, proxy, proxy_name)
    else:
        v2 = Slither(args.new_version, **vars(args))
        v2_name = v1_name if not args.new_contract_name else args.new_contract_name
        check_initialization(v2)
        compare_function_ids(v2, v2_name, proxy, proxy_name)
        compare_variables_order_proxy(v2, v2_name, proxy, proxy_name)
        compare_variables_order_implementation(v1, v1_name, v2, v2_name)
Example #30
0
def main():
    # ------------------------------
    #       Usage: python3 -m slither_format filename
    #       Example: python3 -m slither_format contract.sol
    # ------------------------------
    # Parse all arguments
    args = parse_args()

    read_config_file(args)

    # Perform slither analysis on the given filename
    slither = Slither(args.filename, **vars(args))

    # Format the input files based on slither analysis
    slither_format(slither, **vars(args))