Consensys / mythril

Security analysis tool for EVM bytecode. Supports smart contracts built for Ethereum, Hedera, Quorum, Vechain, Rootstock, Tron and other EVM-compatible blockchains.
https://mythx.io/
MIT License
3.87k stars 737 forks source link

analyze with --graph or --statespace-json doesn't work #1859

Closed Bac0nj closed 2 months ago

Bac0nj commented 3 months ago

Description

Execute analyze with --graph or --statespace-json could cause a KeyError

How to Reproduce

(myth) ➜  mythril git:(develop) ✗ myth a --statespace-json a.json solidity_examples/exceptions.sol
mythril.interfaces.cli [ERROR]: Traceback (most recent call last):
  File "/home/justin/anaconda3/envs/myth/lib/python3.12/site-packages/mythril/interfaces/cli.py", line 976, in parse_args_and_execute
    execute_command(
  File "/home/justin/anaconda3/envs/myth/lib/python3.12/site-packages/mythril/interfaces/cli.py", line 859, in execute_command
    statespace = analyzer.dump_statespace(contract=analyzer.contracts[0])
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/justin/anaconda3/envs/myth/lib/python3.12/site-packages/mythril/mythril/mythril_analyzer.py", line 103, in dump_statespace
    return get_serializable_statespace(sym)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/justin/anaconda3/envs/myth/lib/python3.12/site-packages/mythril/analysis/traceexplore.py", line 71, in get_serializable_statespace
    code = node.get_cfg_dict()["code"]
           ^^^^^^^^^^^^^^^^^^^
  File "/home/justin/anaconda3/envs/myth/lib/python3.12/site-packages/mythril/laser/ethereum/cfg.py", line 69, in get_cfg_dict
    code += " " + "".join(str(instruction["argument"]))
                              ~~~~~~~~~~~^^^^^^^^^^^^
KeyError: 'argument'

Environment

norhh commented 3 months ago

Hi @Bac0nj, for some reason, I can't reproduce this bug. Can you retry it with the latest mythril develop version?

Bac0nj commented 3 months ago

I pulled the latest develop version, and the same issue occurs

(myth) (base)  justin@HAL  ~/codes/mythril   develop ±  git pull
remote: Enumerating objects: 25, done.
remote: Counting objects: 100% (25/25), done.
remote: Compressing objects: 100% (9/9), done.
remote: Total 25 (delta 16), reused 19 (delta 16), pack-reused 0
展开对象中: 100% (25/25), 11.19 KiB | 1.86 MiB/s, 完成.
来自 https://github.com/Consensys/mythril
   cfa8a1fa..470144b7  develop    -> origin/develop
更新 cfa8a1fa..470144b7
Fast-forward
 mythril/disassembler/disassembly.py     |  6 ++----
 mythril/ethereum/evmcontract.py         | 13 ++++---------
 mythril/interfaces/cli.py               |  9 ---------
 mythril/mythril/mythril_analyzer.py     |  1 -
 mythril/mythril/mythril_disassembler.py | 12 ++----------
 mythril/plugin/discovery.py             | 25 ++++++++++++++++++++-----
 mythril/support/signatures.py           | 61 +++----------------------------------------------------------
 requirements.txt                        | 11 +++++------
 setup.py                                |  2 ++
 tests/analysis/abi_decode_test.py       | 24 ++++--------------------
 tests/laser/evm_testsuite/evm_test.py   |  1 +
 tox.ini                                 |  2 +-
 12 files changed, 44 insertions(+), 123 deletions(-)
(myth) (base)  justin@HAL  ~/codes/mythril   develop ±  ./myth a ./solidity_examples/exceptions.sol 
==== Exception State ====
SWC ID: 110
Severity: Medium
Contract: Exceptions
Function name: assert1()
PC address: 832
Estimated Gas Usage: 224 - 509
An assertion violation was triggered.
It is possible to trigger an assertion violation. Note that Solidity assert() statements should only be used to check invariants. Review the transaction trace generated for this issue and either make sure your program logic is correct, or use require() instead of assert() if your goal is to constrain user inputs or enforce preconditions. Remember to validate inputs from both callers (for instance, via passed arguments) and callees (for instance, via return values).
--------------------
In file: ./solidity_examples/exceptions.sol:19

assert(i == 0)

--------------------
Initial State:

Account: [CREATOR], balance: 0x0, nonce:0, storage:{}
Account: [ATTACKER], balance: 0x0, nonce:0, storage:{}

Transaction Sequence:

Caller: [CREATOR], calldata: , decoded_data: , value: 0x0
Caller: [CREATOR], function: assert1(), txdata: 0xb34c3610, value: 0x0

==== Exception State ====
SWC ID: 110
Severity: Medium
Contract: Exceptions
Function name: assert3(uint256)
PC address: 832
Estimated Gas Usage: 494 - 779
An assertion violation was triggered.
It is possible to trigger an assertion violation. Note that Solidity assert() statements should only be used to check invariants. Review the transaction trace generated for this issue and either make sure your program logic is correct, or use require() instead of assert() if your goal is to constrain user inputs or enforce preconditions. Remember to validate inputs from both callers (for instance, via passed arguments) and callees (for instance, via return values).
--------------------
In file: ./solidity_examples/exceptions.sol:28

assert(input != 23)

--------------------
Initial State:

Account: [CREATOR], balance: 0x0, nonce:0, storage:{}
Account: [ATTACKER], balance: 0x0, nonce:0, storage:{}

Transaction Sequence:

Caller: [CREATOR], calldata: , decoded_data: , value: 0x0
Caller: [SOMEGUY], function: assert3(uint256), txdata: 0x546455b50000000000000000000000000000000000000000000000000000000000000017, decoded_data: (23,), value: 0x0

(myth) (base)  ✘ justin@HAL  ~/codes/mythril   develop ±  ./myth a --statespace-json ./a.json ./solidity_examples/exceptions.sol
mythril.interfaces.cli [ERROR]: Traceback (most recent call last):
  File "/home/justin/codes/mythril/mythril/interfaces/cli.py", line 967, in parse_args_and_execute
    execute_command(
  File "/home/justin/codes/mythril/mythril/interfaces/cli.py", line 852, in execute_command
    statespace = analyzer.dump_statespace(contract=analyzer.contracts[0])
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/justin/codes/mythril/mythril/mythril/mythril_analyzer.py", line 102, in dump_statespace
    return get_serializable_statespace(sym)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/justin/codes/mythril/mythril/analysis/traceexplore.py", line 71, in get_serializable_statespace
    code = node.get_cfg_dict()["code"]
           ^^^^^^^^^^^^^^^^^^^
  File "/home/justin/codes/mythril/mythril/laser/ethereum/cfg.py", line 69, in get_cfg_dict
    code += " " + "".join(str(instruction["argument"]))
                              ~~~~~~~~~~~^^^^^^^^^^^^
KeyError: 'argument'
(myth) (base)  justin@HAL  ~/codes/mythril   develop ±  ./myth version
Mythril version v0.24.8

I ran it in debug mode and make a breakpoint in the KeyError line. For the first several rounds the instruction was passed in with the correct "argument" key. But for some reason in a round the keyword was missing. Here's the screenshot of the instruct with missing argument. 图片

Bac0nj commented 3 months ago

Hi @Bac0nj, for some reason, I can't reproduce this bug. Can you retry it with the latest mythril develop version?

I posted my screenshot of the debug mode and more information about where the KeyError happened.