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)
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()
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 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()
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()
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