def test_get_data_from_storage(params, ans):
    config = MythrilConfig()
    config.set_api_rpc_infura()
    disassembler = MythrilDisassembler(eth=config.eth, solc_version="0.4.23")
    outtext = disassembler.get_state_variable_from_storage(
        "0x76799f77587738bfeef09452df215b63d2cfb08a", params).split("\n")
    assert outtext == ans
def test_get_data_from_storage_incorrect_params(params):
    config = MythrilConfig()
    config.set_api_rpc_infura()
    disassembler = MythrilDisassembler(eth=config.eth, solc_version="0.4.23")
    with pytest.raises(CriticalError):
        disassembler.get_state_variable_from_storage(
            "0x76799f77587738bfeef09452df215b63d2cfb08a", params)
Example #3
0
    def _run_mythril(self, contract_address=None):
        eth_json_rpc = EthJsonRpc(url=self.web3_rpc)

        disassembler = MythrilDisassembler(eth=eth_json_rpc,
                                           solc_version=None,
                                           enable_online_lookup=True)

        disassembler.load_from_address(contract_address)

        analyzer = MythrilAnalyzer(
            strategy="bfs",
            use_onchain_data=self.onchain_storage,
            disassembler=disassembler,
            address=contract_address,
            execution_timeout=self.timeout,
            solver_timeout=self.timeout,
            loop_bound=self.loop_bound,
            max_depth=64,
            create_timeout=10,
        )

        self.logger.info("Analyzing %s", contract_address)
        self.logger.debug("Running Mythril")

        return analyzer.fire_lasers(modules=self.modules,
                                    transaction_count=self.tx_count)
Example #4
0
    def test_generate_graph(self):
        for input_file in TESTDATA_INPUTS.iterdir():
            output_expected = TESTDATA_OUTPUTS_EXPECTED / (input_file.name +
                                                           ".graph.html")
            output_current = TESTDATA_OUTPUTS_CURRENT / (input_file.name +
                                                         ".graph.html")

            contract = EVMContract(input_file.read_text())
            disassembler = MythrilDisassembler()
            disassembler.contracts.append(contract)
            analyzer = MythrilAnalyzer(
                disassembler=disassembler,
                strategy="dfs",
                execution_timeout=5,
                max_depth=30,
                address=(util.get_indexed_address(0)),
            )

            html = analyzer.graph_html(transaction_count=1)
            output_current.write_text(html)

            lines_expected = re.findall(r"'label': '.*'",
                                        str(output_current.read_text()))
            lines_found = re.findall(r"'label': '.*'",
                                     str(output_current.read_text()))
            if not (lines_expected == lines_found):
                self.found_changed_files(input_file, output_expected,
                                         output_current)

        self.assert_and_show_changed_files()
Example #5
0
def parse_args_and_execute(parser: ArgumentParser, args: Namespace) -> None:
    """
    Parses the arguments
    :param parser: The parser
    :param args: The args
    """

    if args.epic:
        path = os.path.dirname(os.path.realpath(__file__))
        sys.argv.remove("--epic")
        os.system(" ".join(sys.argv) + " | python3 " + path + "/epic.py")
        sys.exit()

    if args.command not in COMMAND_LIST or args.command is None:
        parser.print_help()
        sys.exit()

    if args.command == "version":
        if args.outform == "json":
            print(json.dumps({"version_str": VERSION}))
        else:
            print("Mythril version {}".format(VERSION))
        sys.exit()

    if args.command == "help":
        parser.print_help()
        sys.exit()

    # Parse cmdline args
    validate_args(args)
    try:
        if args.command == "function-to-hash":
            contract_hash_to_address(args)
        config = set_config(args)
        leveldb_search(config, args)
        query_signature = args.__dict__.get("query_signature", None)
        solc_json = args.__dict__.get("solc_json", None)
        solv = args.__dict__.get("solv", None)
        disassembler = MythrilDisassembler(
            eth=config.eth,
            solc_version=solv,
            solc_settings_json=solc_json,
            enable_online_lookup=query_signature,
        )

        address = load_code(disassembler, args)
        execute_command(disassembler=disassembler,
                        address=address,
                        parser=parser,
                        args=args)
    except CriticalError as ce:
        exit_with_error(args.__dict__.get("outform", "text"), str(ce))
    except Exception:
        exit_with_error(args.__dict__.get("outform", "text"),
                        traceback.format_exc())
Example #6
0
def parse_args(parser: argparse.ArgumentParser,
               args: argparse.Namespace) -> None:
    """
    Parses the arguments
    :param parser: The parser
    :param args: The args
    """

    if args.epic:
        path = os.path.dirname(os.path.realpath(__file__))
        sys.argv.remove("--epic")
        os.system(" ".join(sys.argv) + " | python3 " + path + "/epic.py")
        sys.exit()

    if args.version:
        if args.outform == "json":
            print(json.dumps({"version_str": VERSION}))
        else:
            print("Mythril version {}".format(VERSION))
        sys.exit()

    # Parse cmdline args
    validate_args(parser, args)
    try:
        quick_commands(args)
        config = set_config(args)
        leveldb_search(config, args)
        disassembler = MythrilDisassembler(
            eth=config.eth,
            solc_version=args.solv,
            solc_args=args.solc_args,
            enable_online_lookup=args.query_signature,
        )
        if args.truffle:
            try:
                disassembler.analyze_truffle_project(args)
            except FileNotFoundError:
                print(
                    "Build directory not found. Make sure that you start the analysis from the project root, and that 'truffle compile' has executed successfully."
                )
            sys.exit()

        address = get_code(disassembler, args)
        execute_command(disassembler=disassembler,
                        address=address,
                        parser=parser,
                        args=args)
    except CriticalError as ce:
        exit_with_error(args.outform, str(ce))
    except Exception:
        exit_with_error(args.outform, traceback.format_exc())
Example #7
0
def parse_args(parser: argparse.ArgumentParser,
               args: argparse.Namespace) -> None:
    """
    Parses the arguments
    :param parser: The parser
    :param args: The args
    """

    if args.epic:
        path = os.path.dirname(os.path.realpath(__file__))
        sys.argv.remove("--epic")
        os.system(" ".join(sys.argv) + " | python3 " + path + "/epic.py")
        sys.exit()

    if args.version:
        if args.outform == "json":
            print(json.dumps({"version_str": VERSION}))
        else:
            print("Mythril version {}".format(VERSION))
        sys.exit()

    # Parse cmdline args
    validate_args(parser, args)
    try:
        quick_commands(args)
        config = set_config(args)
        leveldb_search(config, args)
        disassembler = MythrilDisassembler(
            eth=config.eth,
            solc_version=args.solv,
            solc_settings_json=args.solc_json,
            enable_online_lookup=args.query_signature,
        )

        address = get_code(disassembler, args)
        execute_command(disassembler=disassembler,
                        address=address,
                        parser=parser,
                        args=args)
    except CriticalError as ce:
        exit_with_error(args.outform, str(ce))
    except Exception:
        exit_with_error(args.outform, traceback.format_exc())
Example #8
0
def test_fire_lasers(mock_sym, mock_fire_lasers, mock_code_info):
    disassembler = MythrilDisassembler(eth=None)
    disassembler.load_from_solidity(
        [
            str(
                (
                    Path(__file__).parent.parent / "testdata/input_contracts/origin.sol"
                ).absolute()
            )
        ]
    )
    analyzer = MythrilAnalyzer(disassembler, strategy="dfs")

    issues = analyzer.fire_lasers(modules=[]).sorted_issues()
    mock_sym.assert_called()
    mock_fire_lasers.assert_called()
    mock_code_info.assert_called()
    assert len(issues) == 1
    assert issues[0]["swc-id"] == "101"
def test_solc_install():
    MythrilDisassembler(eth=None, solc_version="0.4.19")
Example #10
0
def exploits_from_mythril(
    rpcHTTP="http://localhost:8545",
    rpcWS=None,
    rpcIPC=None,
    timeout=300,
    contract="",
    account_pk="",
    strategy="bfs",
    modules=["ether_thief", "suicide"],
    transaction_count=3,
    execution_timeout=120,
    max_depth=32,
    loop_bound=3,
    disable_dependency_pruning=False,
    onchain_storage_access=True,
    enable_online_lookup=False,
):
    if re.match(r"^https", rpcHTTP):
        host, port = rpcHTTP[8:].split(":")
        rpc_tls = True
    else:
        host, port = rpcHTTP[7:].split(":")
        rpc_tls = False

    try:
        # Disassembler
        disassembler = MythrilDisassembler(
            eth=EthJsonRpc(host=host, port=port, tls=rpc_tls),
            solc_version=None,
            solc_args=None,
            enable_online_lookup=enable_online_lookup,
        )
        disassembler.load_from_address(contract)
        # Analyzer
        analyzer = MythrilAnalyzer(
            strategy=strategy,
            disassembler=disassembler,
            address=contract,
            execution_timeout=execution_timeout,
            max_depth=max_depth,
            loop_bound=loop_bound,
            disable_dependency_pruning=disable_dependency_pruning,
            onchain_storage_access=onchain_storage_access,
        )
        # Generate report
        report = analyzer.fire_lasers(
            modules=modules, transaction_count=transaction_count
        )
    except CriticalError as e:
        print(e)
        return []

    if rpcIPC is not None:
        print("Connecting to IPC: {rpc}.".format(rpc=rpcIPC))
        w3 = Web3(Web3.IPCProvider(rpcIPC, timeout=timeout))
    elif rpcWS is not None:
        print("Connecting to WebSocket: {rpc}.".format(rpc=rpcWS))
        w3 = Web3(Web3.WebsocketProvider(rpcWS, websocket_kwargs={"timeout": timeout}))
    else:
        print("Connecting to HTTP: {rpc}.".format(rpc=rpcHTTP))
        w3 = Web3(Web3.HTTPProvider(rpcHTTP, request_kwargs={"timeout": timeout}))

    exploits = []

    for ri in report.issues:
        txs = []
        issue = report.issues[ri]

        for si in issue.transaction_sequence["steps"]:
            txs.append(Tx(data=si["input"], value=si["value"], name=si["name"]))

        exploits.append(
            Exploit(
                txs=txs,
                w3=w3,
                contract=contract,
                account=private_key_to_account(account_pk),
                account_pk=account_pk,
                title=issue.title,
                description=issue.description,
                swc_id=issue.swc_id,
            )
        )

    return exploits