Esempio n. 1
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)
Esempio n. 2
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()
Esempio n. 3
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"
Esempio n. 4
0
def execute_command(
    disassembler: MythrilDisassembler,
    address: str,
    parser: argparse.ArgumentParser,
    args: argparse.Namespace,
):

    if args.storage:
        if not args.address:
            exit_with_error(
                args.outform,
                "To read storage, provide the address of a deployed contract with the -a option.",
            )

        storage = disassembler.get_state_variable_from_storage(
            address=address, params=[a.strip() for a in args.storage.strip().split(",")]
        )
        print(storage)
        return

    analyzer = MythrilAnalyzer(
        strategy=args.strategy,
        disassembler=disassembler,
        address=address,
        max_depth=args.max_depth,
        execution_timeout=args.execution_timeout,
        create_timeout=args.create_timeout,
        enable_iprof=args.enable_iprof,
        onchain_storage_access=not args.no_onchain_storage_access,
    )

    if args.disassemble:
        # or mythril.disassemble(mythril.contracts[0])

        if disassembler.contracts[0].code:
            print("Runtime Disassembly: \n" + disassembler.contracts[0].get_easm())
        if disassembler.contracts[0].creation_code:
            print("Disassembly: \n" + disassembler.contracts[0].get_creation_easm())

    elif args.graph or args.fire_lasers:
        if not disassembler.contracts:
            exit_with_error(
                args.outform, "input files do not contain any valid contracts"
            )

        if args.graph:
            html = analyzer.graph_html(
                contract=analyzer.contracts[0],
                enable_physics=args.enable_physics,
                phrackify=args.phrack,
            )

            try:
                with open(args.graph, "w") as f:
                    f.write(html)
            except Exception as e:
                exit_with_error(args.outform, "Error saving graph: " + str(e))

        else:
            try:
                report = analyzer.fire_lasers(
                    modules=[m.strip() for m in args.modules.strip().split(",")]
                    if args.modules
                    else [],
                    verbose_report=args.verbose_report,
                    transaction_count=args.transaction_count,
                )
                outputs = {
                    "json": report.as_json(),
                    "jsonv2": report.as_swc_standard_format(),
                    "text": report.as_text(),
                    "markdown": report.as_markdown(),
                }
                print(outputs[args.outform])
            except ModuleNotFoundError as e:
                exit_with_error(
                    args.outform, "Error loading analyis modules: " + format(e)
                )

    elif args.statespace_json:

        if not analyzer.contracts:
            exit_with_error(
                args.outform, "input files do not contain any valid contracts"
            )

        statespace = analyzer.dump_statespace(contract=analyzer.contracts[0])

        try:
            with open(args.statespace_json, "w") as f:
                json.dump(statespace, f)
        except Exception as e:
            exit_with_error(args.outform, "Error saving json: " + str(e))

    else:
        parser.print_help()
Esempio n. 5
0
def execute_command(
    disassembler: MythrilDisassembler,
    address: str,
    parser: ArgumentParser,
    args: Namespace,
):
    """
    Execute command
    :param disassembler:
    :param address:
    :param parser:
    :param args:
    :return:
    """

    if args.command == "read-storage":
        storage = disassembler.get_state_variable_from_storage(
            address=address,
            params=[a.strip() for a in args.storage_slots.strip().split(",")],
        )
        print(storage)

    elif args.command in DISASSEMBLE_LIST:
        if disassembler.contracts[0].code:
            print("Runtime Disassembly: \n" +
                  disassembler.contracts[0].get_easm())
        if disassembler.contracts[0].creation_code:
            print("Disassembly: \n" +
                  disassembler.contracts[0].get_creation_easm())

    elif args.command in ANALYZE_LIST:
        analyzer = MythrilAnalyzer(
            strategy=args.strategy,
            disassembler=disassembler,
            address=address,
            max_depth=args.max_depth,
            execution_timeout=args.execution_timeout,
            loop_bound=args.loop_bound,
            create_timeout=args.create_timeout,
            enable_iprof=args.enable_iprof,
            disable_dependency_pruning=args.disable_dependency_pruning,
            onchain_storage_access=not args.no_onchain_storage_access,
        )

        if not disassembler.contracts:
            exit_with_error(args.outform,
                            "input files do not contain any valid contracts")

        if args.graph:
            html = analyzer.graph_html(
                contract=analyzer.contracts[0],
                enable_physics=args.enable_physics,
                phrackify=args.phrack,
                transaction_count=args.transaction_count,
            )

            try:
                with open(args.graph, "w") as f:
                    f.write(html)
            except Exception as e:
                exit_with_error(args.outform, "Error saving graph: " + str(e))

        elif args.statespace_json:

            if not analyzer.contracts:
                exit_with_error(
                    args.outform,
                    "input files do not contain any valid contracts")

            statespace = analyzer.dump_statespace(
                contract=analyzer.contracts[0])

            try:
                with open(args.statespace_json, "w") as f:
                    json.dump(statespace, f)
            except Exception as e:
                exit_with_error(args.outform, "Error saving json: " + str(e))

        else:
            try:
                report = analyzer.fire_lasers(
                    modules=[
                        m.strip() for m in args.modules.strip().split(",")
                    ] if args.modules else [],
                    transaction_count=args.transaction_count,
                )
                outputs = {
                    "json": report.as_json(),
                    "jsonv2": report.as_swc_standard_format(),
                    "text": report.as_text(),
                    "markdown": report.as_markdown(),
                }
                print(outputs[args.outform])
            except ModuleNotFoundError as e:
                exit_with_error(args.outform,
                                "Error loading analysis modules: " + format(e))

    else:
        parser.print_help()
Esempio n. 6
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