mirror of https://github.com/ConsenSys/mythril
commit
52d5afe0b6
@ -0,0 +1,63 @@ |
|||||||
|
MythX Analysis |
||||||
|
================= |
||||||
|
|
||||||
|
Run :code:`myth pro` with one of the input options described below will run a `MythX analysis <https://mythx.io>`_ on the desired input. This includes a run of Mythril, the fuzzer Harvey, and the static analysis engine Maru and has some false-positive filtering only possible by combining the tool capabilities. |
||||||
|
|
||||||
|
************** |
||||||
|
Authentication |
||||||
|
************** |
||||||
|
|
||||||
|
In order to authenticate with the MythX API, set the environment variables ``MYTHX_PASSWORD`` and ``MYTHX_ETH_ADDRESS``. |
||||||
|
|
||||||
|
.. code-block:: bash |
||||||
|
|
||||||
|
$ export MYTHX_ETH_ADDRESS='0x0000000000000000000000000000000000000000' |
||||||
|
$ export MYTHX_PASSWORD='password' |
||||||
|
|
||||||
|
*********************** |
||||||
|
Analyzing Solidity Code |
||||||
|
*********************** |
||||||
|
|
||||||
|
The input format is the same as a regular Mythril analysis. |
||||||
|
|
||||||
|
.. code-block:: bash |
||||||
|
|
||||||
|
$ myth pro ether_send.sol |
||||||
|
==== Unprotected Ether Withdrawal ==== |
||||||
|
SWC ID: 105 |
||||||
|
Severity: High |
||||||
|
Contract: Crowdfunding |
||||||
|
Function name: withdrawfunds() |
||||||
|
PC address: 730 |
||||||
|
Anyone can withdraw ETH from the contract account. |
||||||
|
Arbitrary senders other than the contract creator can withdraw ETH from the contract account without previously having sent an equivalent amount of ETH to it. This is likely to be a vulnerability. |
||||||
|
-------------------- |
||||||
|
In file: tests/testdata/input_contracts/ether_send.sol:21 |
||||||
|
|
||||||
|
msg.sender.transfer(address(this).balance) |
||||||
|
|
||||||
|
-------------------- |
||||||
|
|
||||||
|
If an input file contains multiple contract definitions, Mythril analyzes the *last* bytecode output produced by solc. You can override this by specifying the contract name explicitly: |
||||||
|
|
||||||
|
.. code-block:: bash |
||||||
|
|
||||||
|
myth pro OmiseGo.sol:OMGToken |
||||||
|
|
||||||
|
To specify a contract address, use :code:`-a <address>` |
||||||
|
|
||||||
|
**************************** |
||||||
|
Analyzing On-Chain Contracts |
||||||
|
**************************** |
||||||
|
|
||||||
|
Analyzing a mainnet contract via INFURA: |
||||||
|
|
||||||
|
.. code-block:: bash |
||||||
|
|
||||||
|
myth pro -a 0x5c436ff914c458983414019195e0f4ecbef9e6dd |
||||||
|
|
||||||
|
Adding the :code:`-l` flag will cause mythril to automatically retrieve dependencies, such as dynamically linked library contracts: |
||||||
|
|
||||||
|
.. code-block:: bash |
||||||
|
|
||||||
|
myth -v4 pro -l -a 0xEbFD99838cb0c132016B9E117563CB41f2B02264 |
@ -0,0 +1,111 @@ |
|||||||
|
import sys |
||||||
|
|
||||||
|
import os |
||||||
|
import time |
||||||
|
|
||||||
|
from mythx_models.exceptions import MythXAPIError |
||||||
|
from typing import List, Dict, Any |
||||||
|
|
||||||
|
from mythril.analysis.report import Issue, Report |
||||||
|
from mythril.solidity.soliditycontract import SolidityContract |
||||||
|
|
||||||
|
from pythx import Client |
||||||
|
|
||||||
|
import logging |
||||||
|
|
||||||
|
log = logging.getLogger(__name__) |
||||||
|
|
||||||
|
TRIAL_ETH_ADDRESS = "0x0000000000000000000000000000000000000000" |
||||||
|
TRIAL_PASSWORD = "trial" |
||||||
|
|
||||||
|
|
||||||
|
def analyze(contracts: List[SolidityContract], analysis_mode: str = "quick") -> Report: |
||||||
|
""" |
||||||
|
Analyze contracts via the MythX API. |
||||||
|
|
||||||
|
:param contracts: List of solidity contracts to analyze |
||||||
|
:param analysis_mode: The mode to submit the analysis request with. "quick" or "full" (default: "quick") |
||||||
|
:return: Report with analyzed contracts |
||||||
|
""" |
||||||
|
assert analysis_mode in ("quick", "full"), "analysis_mode must be 'quick' or 'full'" |
||||||
|
|
||||||
|
c = Client( |
||||||
|
eth_address=os.environ.get("MYTHX_ETH_ADDRESS", TRIAL_ETH_ADDRESS), |
||||||
|
password=os.environ.get("MYTHX_PASSWORD", TRIAL_PASSWORD), |
||||||
|
) |
||||||
|
|
||||||
|
if c.eth_address == TRIAL_ETH_ADDRESS: |
||||||
|
print( |
||||||
|
"You are currently running MythX in Trial mode. This mode reports only a partial analysis of your smart contracts, limited to three vulnerabilities. To get a more complete analysis, sign up for a free account at https://mythx.io." |
||||||
|
) |
||||||
|
|
||||||
|
issues = [] # type: List[Issue] |
||||||
|
|
||||||
|
# TODO: Analyze multiple contracts asynchronously. |
||||||
|
for contract in contracts: |
||||||
|
source_codes = {} |
||||||
|
source_list = [] |
||||||
|
sources = {} # type: Dict[str, Any] |
||||||
|
main_source = None |
||||||
|
|
||||||
|
try: |
||||||
|
main_source = contract.input_file |
||||||
|
for solidity_file in contract.solidity_files: |
||||||
|
source_codes[solidity_file.filename] = solidity_file.data |
||||||
|
for filename in contract.solc_json["sources"].keys(): |
||||||
|
sources[filename] = {} |
||||||
|
if source_codes[filename]: |
||||||
|
sources[filename]["source"] = source_codes[filename] |
||||||
|
sources[filename]["ast"] = contract.solc_json["sources"][filename][ |
||||||
|
"ast" |
||||||
|
] |
||||||
|
|
||||||
|
source_list.append(filename) |
||||||
|
|
||||||
|
source_list.sort( |
||||||
|
key=lambda fname: contract.solc_json["sources"][fname]["id"] |
||||||
|
) |
||||||
|
except AttributeError: |
||||||
|
# No solidity file |
||||||
|
pass |
||||||
|
|
||||||
|
assert contract.creation_code, "Creation bytecode must exist." |
||||||
|
try: |
||||||
|
resp = c.analyze( |
||||||
|
contract_name=contract.name, |
||||||
|
analysis_mode=analysis_mode, |
||||||
|
bytecode=contract.creation_code or None, |
||||||
|
deployed_bytecode=contract.code or None, |
||||||
|
sources=sources or None, |
||||||
|
main_source=main_source, |
||||||
|
source_list=source_list or None, |
||||||
|
) |
||||||
|
except MythXAPIError as e: |
||||||
|
log.critical(e) |
||||||
|
|
||||||
|
while not c.analysis_ready(resp.uuid): |
||||||
|
log.info(c.status(resp.uuid).analysis) |
||||||
|
time.sleep(5) |
||||||
|
|
||||||
|
for issue in c.report(resp.uuid): |
||||||
|
issue = Issue( |
||||||
|
contract=contract.name, |
||||||
|
function_name=None, |
||||||
|
address=issue.locations[0].source_map.components[0].offset |
||||||
|
if issue.locations |
||||||
|
else -1, |
||||||
|
swc_id=issue.swc_id[4:] or "None", # remove 'SWC-' prefix |
||||||
|
title=issue.swc_title, |
||||||
|
bytecode=contract.creation_code, |
||||||
|
severity=issue.severity.capitalize(), |
||||||
|
description_head=issue.description_short, |
||||||
|
description_tail=issue.description_long, |
||||||
|
) |
||||||
|
issue.add_code_info(contract) |
||||||
|
issues.append(issue) |
||||||
|
|
||||||
|
report = Report(contracts=contracts) |
||||||
|
for issue in issues: |
||||||
|
report.append_issue(issue) |
||||||
|
|
||||||
|
return report |
File diff suppressed because one or more lines are too long
Loading…
Reference in new issue