octopus
Security Analysis tool for WebAssembly module (wasm) and Blockchain Smart Contracts (BTC/ETH/NEO/EOS)
Science Score: 10.0%
This score indicates how likely this project is to be science-related based on various indicators:
-
○CITATION.cff file
-
○codemeta.json file
-
○.zenodo.json file
-
○DOI references
-
○Academic publication links
-
✓Committers with academic emails
1 of 10 committers (10.0%) from academic institutions -
○Institutional organization owner
-
○JOSS paper metadata
-
○Scientific vocabulary similarity
Low similarity (10.7%) to scientific vocabulary
Keywords
Keywords from Contributors
Repository
Security Analysis tool for WebAssembly module (wasm) and Blockchain Smart Contracts (BTC/ETH/NEO/EOS)
Basic Info
- Host: GitHub
- Owner: FuzzingLabs
- License: mit
- Language: Python
- Default Branch: master
- Homepage: https://fuzzinglabs.com/
- Size: 5.38 MB
Statistics
- Stars: 487
- Watchers: 19
- Forks: 85
- Open Issues: 12
- Releases: 0
Topics
Metadata Files
README.md
Octopus
Huge thanks to QuoScient for having sponsored this project.
Octopus is a security analysis framework for WebAssembly module and Blockchain Smart Contract.
The purpose of Octopus is to provide an easy way to analyze closed-source WebAssembly module and smart contracts bytecode to understand deeper their internal behaviours.
Features
- Explorer: Octopus JSON-RPC client implementation to communicate with blockchain platforms
- Disassembler: Octopus can translate bytecode into assembly representation
- Control Flow Analysis: Octopus can generate a Control Flow Graph (CFG)
- Call Flow Analysis: Octopus can generate a Call Flow Graph (function level)
- IR conversion (SSA): Octopus can simplify assembly into Static Single Assignment (SSA) representation
- Symbolic Execution: Octopus use symbolic execution to find new paths into a program
Platforms / Architectures
Octopus support the following types of programs/smart contracts: * WebAssembly module (WASM) * Bitcoin script (BTC script) * Ethereum smart contracts (EVM bytecode & Ewasm) * EOS smart contracts (WASM) * NEO smart contracts (AVM bytecode)
|| BTC | ETH (EVM) | ETH (WASM) | EOS | NEO || WASM | |:--------------------:|:---:|:---:|:---:|:---:|:---:|:---:|:---:| | Explorer | :heavycheckmark: | :heavycheckmark:| :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | | :o: | |Disassembler | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | | :heavycheckmark: | |Control Flow Analysis | :heavymultiplicationx: | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | :heavycheckmark: | | :heavycheckmark: | |Call Flow Analysis | :heavymultiplicationx: | :heavyplussign: | :heavycheckmark: | :heavycheckmark: | :heavyplussign: | | :heavycheckmark: | |IR conversion (SSA) | :heavymultiplicationx: | :heavycheckmark: | :heavyplussign: | :heavyplussign: | :heavymultiplicationx: | | :heavycheckmark: | |Symbolic Execution | :heavymultiplicationx: | :heavyplussign: | :heavyplussign: | :heavyplussign: | :heavymultiplicationx: | | :heavyplussign: |
- PyPI package :heavycheckmark:
- Docker :heavycheckmark:
:heavycheckmark: DONE / :heavyplussign: WIP / :heavymultiplicationx: TODO / :o: N/A
Requirements
Octopus is supported on Linux (ideally Ubuntu 16.04) and requires Python >=3.5 (ideally 3.6).
Dependencies: * Graph generation: graphviz * Explorer: requests * Symbolic Execution: z3-solver * Wasm: wasm
Quick Start
Install system dependencies ```
Install system dependencies
sudo apt-get update && sudo apt-get install python-pip graphviz xdg-utils -y ```
Install Octopus: ```
Download Octopus
git clone https://github.com/pventuzelo/octopus cd octopus
Install Octopus library/CLI and its dependencies
python3 setup.py install
or
but prefer the first way to install if possible
pip3 install octopus ```
- Run tests ``` # Run tests for all platforms (disassembly, CFG, ...) ./runtests.sh # Run tests that require internet access (explorer tests) ./runexplorer_tests.sh
Run tests for only one platforms
{btc, eth, eos, neo, wasm}runtests.sh
cd octopus/tests/ ./wasmruntests.sh ```
Docker container
A docker container providing the toolset is available at docker hub. In a terminal, run the following commands:
docker pull smartbugs/octopus
docker run -it smartbugs/octopus
cd octopus
python3 octopus_eth_evm.py -s -f examples/ETH/evm_bytecode/61EDCDf5bb737ADffE5043706e7C5bb1f1a56eEA.bytecode
Command-line tools
- WebAssembly: octopus_wasm.py
- Ethereum (EVM): octopusethevm.py
In-depth Examples using APIs
WebAssembly
#### Disassembler
Disassembly of a Wasm module:
```python
from octopus.arch.wasm.disassembler import WasmDisassembler
FILE = "examples/wasm/samples/helloworld.wasm"
with open(FILE, 'rb') as f:
module_bytecode = f.read()
disasm = WasmDisassembler()
# return list of functions instructions (list)
print(disasm.disassemble_module(module_bytecode))
#[[
Ethereum (ETH) - EVM
#### Explorer
```python
from octopus.platforms.ETH.explorer import EthereumInfuraExplorer
from octopus.platforms.ETH.explorer import INFURA_ROPSTEN
KEY_API = "bHuaQhX91nkQBac8Wtgj"
# connection to ROPSTEN network (testnet)
explorer = EthereumInfuraExplorer(KEY_API, network=INFURA_ROPSTEN)
# connection to MAINNET network (mainnet)
# explorer = EthereumInfuraExplorer(KEY_API)
# Test ROPSTEN network current block number
block_number = explorer.eth_blockNumber()
print(block_number)
# 3675552
# Retrieve code of this smart contract
addr = "0x3c6B10a5239B1a8A27398583F49771485382818F"
code = explorer.eth_getCode(addr)
print(code)
# 0x6060604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604e5780636d4ce63c14606e575b600080fd5b3415605857600080fd5b606c60048080359060200190919050506094565b005b3415607857600080fd5b607e609e565b6040518082815260200191505060405180910390f35b8060008190555050565b600080549050905600a165627a7a72305820e1f98c821c12eea52047d7324b034ddccc41eaa7365d369b34580ab73c71a8940029
```
#### Disassembler
```python
from octopus.platforms.ETH.disassembler import EthereumDisassembler
# smart contract bytecode
bytecode_hex = "60606040526000357c0100000000000000000000000000000000000000000000000000000000900480635fd8c7101461004f578063c0e317fb1461005e578063f8b2cb4f1461006d5761004d565b005b61005c6004805050610099565b005b61006b600480505061013e565b005b610083600480803590602001909190505061017d565b6040518082815260200191505060405180910390f35b3373ffffffffffffffffffffffffffffffffffffffff16611111600060005060003373ffffffffffffffffffffffffffffffffffffffff16815260200190815260200160002060005054604051809050600060405180830381858888f19350505050151561010657610002565b6000600060005060003373ffffffffffffffffffffffffffffffffffffffff168152602001908152602001600020600050819055505b565b34600060005060003373ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000828282505401925050819055505b565b6000600060005060008373ffffffffffffffffffffffffffffffffffffffff1681526020019081526020016000206000505490506101b6565b91905056"
disasm = EthereumDisassembler()
disasm.disassemble(bytecode_hex)
# disassemble bytecode into a list of EthereumInstruction
# attributes r_format='list' by default
print(disasm.disassemble(bytecode_hex))
#[
Ethereum (WASM)
#### Explorer
```python
from octopus.platforms.ETH.explorer import EthereumInfuraExplorer
from octopus.platforms.ETH.explorer import INFURA_KOVAN
# connection to ROPSTEN network (testnet)
explorer = EthereumInfuraExplorer("bHuaQhX91nkQBac8Wtgj",
network=INFURA_KOVAN)
# connection to MAINNET network (mainnet)
# explorer = EthereumInfuraExplorer("bHuaQhX91nkQBac8Wtgj")
# test infura access
block_number = explorer.eth_blockNumber()
print('blockNumber = %d' % block_number)
# retrieve code of this smart contract
addr = "0x1120e596b173d953ba52ce262f73ce3734b0e40e"
code = explorer.eth_getCode(addr)
print()
print(code)
# blockNumber = 8803487
#
# 0x0061736d0100000001090260000060027f7f00021a0203656e7603726574000103656e76066d656d6f7279020102100303020000040501700101010501000601000708010463616c6c00010a120205001002000b0a00418008410b1000000b0b1201004180080b0b48656c6c6f20776f726c64000b076c696e6b696e6703010b0066046e616d65015f060003726574010570616e6963020463616c6c032f5f5a4e3134707761736d5f657468657265756d3365787433726574313768363034643830393864313638366338304504066465706c6f790511727573745f626567696e5f756e77696e64
```
#### Disassembler
Disassembly of a Wasm module:
```python
from octopus.platforms.ETH.disassembler import EthereumDisassembler
FILE = "examples/ETH/wasm/helloworld_kovan.bytecode"
with open(FILE, 'r') as f:
module_bytecode = f.read()
disasm = EthereumDisassembler(arch='wasm')
# return list of functions instructions (list)
print(disasm.disassemble_module(module_bytecode))
#[[
NEO
#### Explorer ```python from octopus.platforms.NEO.explorer import NeoExplorerRPC # get list nodes here: http://monitor.cityofzion.io/ explorer = NeoExplorerRPC(host='seed2.neo.org') # get current number of block on the blockchain print(explorer.getblockcount()) # 2534868 # get information on a contract # lock smart contract address: d3cce84d0800172d09c88ccad61130611bd047a4 contract = explorer.getcontractstate("d3cce84d0800172d09c88ccad61130611bd047a4") print(contract) # {'author': 'Erik Zhang', # 'code_version': '2.0', # 'description': 'Lock 2.0', # 'email': 'erik@neo.org', # 'hash': '0xd3cce84d0800172d09c88ccad61130611bd047a4', # 'name': 'Lock', # 'parameters': ['Integer', 'PublicKey', 'Signature'], # 'properties': {'dynamic_invoke': False, 'storage': False}, # 'returntype': 'Boolean', # 'script': '56c56b6c766b00527ac46c766b51527ac46c766b52527ac4616168184e656f2e426c6f636b636861696e2e4765744865696768746168184e656f2e426c6f636b636861696e2e4765744865616465726c766b53527ac46c766b00c36c766b53c36168174e656f2e4865616465722e47657454696d657374616d70a06c766b54527ac46c766b54c3640e00006c766b55527ac4621a006c766b51c36c766b52c3617cac6c766b55527ac46203006c766b55c3616c7566', # 'version': 0} # smart contract code in contract['script'] print(contract['script']) ``` #### Disassembler ```python from octopus.platforms.NEO.disassembler import NeoDisassembler # lock contract file_name = "examples/NEO/samples/Lock.bytecode" # read file with open(file_name) as f: bytecode = f.read() disasm = NeoDisassembler() print(disasm.disassemble(bytecode, r_format='text')) # PUSH6 # NEWARRAY # TOALTSTACK # FROMALTSTACK # DUP # TOALTSTACK # PUSH0 # PUSH2 # ROLL # SETITEM # FROMALTSTACK # .... # PICKITEM # NOP # FROMALTSTACK # DROP # RET ``` #### Control Flow Analysis ```python from octopus.analysis.graph import CFGGraph from octopus.platforms.NEO.cfg import NeoCFG # lock contract file_name = "examples/NEO/samples/Lock.bytecode" # read file with open(file_name) as f: raw = f.read() # create neo cfg - automatic static analysis cfg = NeoCFG(raw) # graph visualization graph = CFGGraph(cfg, filename="Lock_cfg") graph.view_functions() ```
EOS
#### Explorer ```python from octopus.platforms.EOS.explorer import EosExplorer host = "api.cypherglass.com" # by defaul the port is 8888 explo = EosExplorer(host=host) # get info about the node explo.get_info() ''' {'block_cpu_limit': 180289, 'block_net_limit': 1045680, 'chain_id': 'aca376f206b8fc25a6ed44dbdc66547c36c6c33e3a119ffbeaef943642f0e906', 'head_block_id': '018d6e2bcf6295126cd74cf694b5cca3529eefc42b334b394ef87c3a43876739', 'head_block_num': 26045995, 'head_block_producer': 'eosswedenorg', 'head_block_time': '2018-11-09T14:11:29.500', 'last_irreversible_block_id': '018d6cdcff78bbd9f25c605b02fb67c47a337ece78ddcf73089cee4bf6a410ee', 'last_irreversible_block_num': 26045660, 'server_version': 'c71d2245', 'server_version_string': 'mainnet-1.3.0', 'virtual_block_cpu_limit': 38092879, 'virtual_block_net_limit': 1048576000} ''' explo.get_block(1337) ''' {'action_mroot': 'bcb9763baa3bbf98ed36379b4be0ecb2d9cd21c75df01729c63b2b021001c10c', 'block_extensions': [], 'block_num': 1337, 'confirmed': 0, 'header_extensions': [], 'id': '00000539d17a03af7126e073be4c4d99a72b7f58793cf2c87b9bfd41b6c711fb', 'new_producers': None, 'previous': '00000538b374c1cbfaeed7253ad3075ddc72a28f0a0515301fc1bbed675f2316', 'producer': 'eosio', 'producer_signature': 'SIG_K1_K5jWf36t6j454Hb2fGuV37YTwMTvuQ51ZPBtpru8Ud2axtMTEauWyvtpJuTpnvqzReUndDgEDXvoeEP4jdj2bpnYKBt6g2', 'ref_block_prefix': 1944069745, 'schedule_version': 0, 'timestamp': '2018-06-09T12:09:21.500', 'transaction_mroot': '0000000000000000000000000000000000000000000000000000000000000000', 'transactions': []} ''' ``` #### Disassembler ```python from octopus.platforms.EOS.disassembler import EosDisassembler # complete wasm module file_name = "examples/EOS/samples/eos_ping.wasm" # read file with open(file_name, 'rb') as f: raw = f.read() # just disassembly disasm = EosDisassembler() # because we provide full module bytecode # we need to use disassemble_module() # otherwise just disassemble() is enough text = disasm.disassemble_module(raw, r_format="text") print(text) # func 0 # get_local 0 # get_local 1 # i32.const 32 # call 12 # i32.eqz # end # # func 1 # get_local 0 # i64.load 3, 0 # get_local 0 # i64.load 3, 8 # call 6 # end # # func 2 # ... # end # # ... ``` #### ModuleAnalyzer ```python from octopus.platforms.EOS.analyzer import EosAnalyzer # complete wasm module file_name = "examples/EOS/samples/eos_ping.wasm" with open(file_name, 'rb') as f: module_bytecode = f.read() # return list of functions instructions (list) # attributes analysis=True by default analyzer = EosAnalyzer(module_bytecode) # show analyzer attributes print(analyzer.func_prototypes) #[('action_data_size', '', 'i32', 'import'), ('eosio_assert', 'i32 i32', '', 'import'), ('eosio_exit', 'i32', '', 'import'), ('memcpy', 'i32 i32 i32', 'i32', 'import'), ('prints', 'i32', '', 'import'), ('read_action_data', 'i32 i32', 'i32', 'import'), ('require_auth2', 'i64 i64', '', 'import'), ('_ZeqRK11checksum256S1_', 'i32 i32', 'i32', 'export'), ('_ZN5eosio12require_authERKNS_16permission_levelE', 'i32', '', 'export'), ('apply', 'i64 i64 i64', '', 'export'), ('$func10', 'i32 i64', '', 'local'), ('$func11', 'i32 i32', 'i32', 'local'), ('memcmp', 'i32 i32 i32', 'i32', 'export'), ('malloc', 'i32', 'i32', 'export'), ('$func14', 'i32 i32', 'i32', 'local'), ('$func15', 'i32', 'i32', 'local'), ('free', 'i32', '', 'export'), ('$func17', '', '', 'local')] print() print(analyzer.exports) # [{'field_str': 'memory', 'kind': 2, 'index': 0}, {'field_str': '_ZeqRK11checksum256S1_', 'kind': 0, 'index': 7}, {'field_str': '_ZN5eosio12require_authERKNS_16permission_levelE', 'kind': 0, 'index': 8}, {'field_str': 'apply', 'kind': 0, 'index': 9}, {'field_str': 'memcmp', 'kind': 0, 'index': 12}, {'field_str': 'malloc', 'kind': 0, 'index': 13}, {'field_str': 'free', 'kind': 0, 'index': 16}] print() print(analyzer.imports_func) # [('env', 'action_data_size', 3), ('env', 'eosio_assert', 5), ('env', 'eosio_exit', 2), ('env', 'memcpy', 6), ('env', 'prints', 2), ('env', 'read_action_data', 4), ('env', 'require_auth2', 1)] ``` #### Control Flow Analysis ```python from octopus.platforms.EOS.cfg import EosCFG from octopus.analysis.graph import CFGGraph # complete wasm module file_name = "examples/EOS/samples/eos_ping.wasm" # read file with open(file_name, 'rb') as f: raw = f.read() # create the cfg cfg = EosCFG(raw) # visualize graph = CFGGraph(cfg) graph.view_functions() ```
Bitcoin
#### Explorer ```python from octopus.platforms.BTC.explorer import BitcoinExplorerRPC RPC_USER = 'test' RPC_PASSWORD = 'test' RPC_HOST = 'localhost' host = '%s:%s@%s' % (RPC_USER, RPC_PASSWORD, RPC_HOST) explorer = BitcoinExplorerRPC(host) explorer.getbestblockhash() # '00000000000000000012085cfe8c79bcdacf81fbd82f6ab52c3cb3a454d4987c' explorer.getblockcount() #550859 ``` #### Disassembler ```python from octopus.platforms.BTC.disassembler import BitcoinDisassembler # Witness Script file_name = "examples/BTC/witness_script.hex" # read file with open(file_name) as f: bytecode = f.read() disasm = BitcoinDisassembler() print(disasm.disassemble(bytecode, r_format='text')) # 0 # OP_ROT # OP_ROT # 2 # 0203f4d01d0b35588638631ebb7d46d8387fd1aeb3dbecfdd3faf7c056b023c833 # 03aa6677e3ce1bd634f4f2e1cd60a60af002e1b30484d4d1611b183b16d391ee96 # 03bf164811abb8c91ed39e58d4e307f86cb4e487c83f727a2c482bc71a0f96f1db # 3 # OP_CHECKMULTISIG ```
Please find examples in examples folder.
Publications and Videos
- BLACKALPS 2018 Reversing and Vulnerability research of Ethereum Smart Contracts
- Devcon iv. Reversing Ethereum Smart Contracts to find out what's behind EVM bytecode
- hack.lu 2018 Reversing and Vulnerability research of Ethereum Smart Contracts
- ToorCon XX - 2018 Reversing Ethereum Smart Contracts (Introduction)
- ToorCon XX - 2018 Dissection of WebAssembly module
- REcon Montreal 2018: Reverse Engineering Of Blockchain Smart Contracts
Authors
Patrick Ventuzelo - Creator - @Pat_Ventuzelo
See also the list of contributors who participated in this project.
License
This project is licensed under the MIT License - see the LICENSE file for details
Acknowledgments
Sponsor: * QuoScient
Inspired by: * Manticore * Mythril * Rattle * ethersplay * ...
Trainings & Contact
Patrick Ventuzelo - @pat_ventuzelo * Independent Security Researcher / Trainer. * FREE online courses: here
Owner
- Name: FuzzingLabs
- Login: FuzzingLabs
- Kind: organization
- Email: fuzzinglabs@gmail.com
- Location: France
- Website: https://fuzzinglabs.com/
- Twitter: FuzzingLabs
- Repositories: 12
- Profile: https://github.com/FuzzingLabs
Research-oriented security company specializing in vulnerability research, fuzzing and blockchain security.
GitHub Events
Total
- Watch event: 15
- Fork event: 3
Last Year
- Watch event: 15
- Fork event: 3
Committers
Last synced: over 2 years ago
Top Committers
| Name | Commits | |
|---|---|---|
| Patrick Ventuzelo | p****o@q****o | 194 |
| Patrick Ventuzelo | v****k@g****m | 13 |
| Patrick Ventuzelo | 9****o | 8 |
| Patrick Ventuzelo | 7 | |
| Rui Maranhao | r****i@c****g | 2 |
| cdetrio | c****o@g****m | 1 |
| QuoScient | f****d@q****o | 1 |
| atlasquan | a****8@g****m | 1 |
| kei | k****1@g****m | 1 |
| nuanbing | j****i@w****u | 1 |
Committer Domains (Top 20 + Academic)
Issues and Pull Requests
Last synced: 6 months ago
All Time
- Total issues: 15
- Total pull requests: 11
- Average time to close issues: 9 months
- Average time to close pull requests: 5 months
- Total issue authors: 13
- Total pull request authors: 10
- Average comments per issue: 1.53
- Average comments per pull request: 0.55
- Merged pull requests: 6
- Bot issues: 0
- Bot pull requests: 0
Past Year
- Issues: 0
- Pull requests: 0
- Average time to close issues: N/A
- Average time to close pull requests: N/A
- Issue authors: 0
- Pull request authors: 0
- Average comments per issue: 0
- Average comments per pull request: 0
- Merged pull requests: 0
- Bot issues: 0
- Bot pull requests: 0
Top Authors
Issue Authors
- pventuzelo (3)
- 0xKurt (1)
- suhabe (1)
- XinyuShe (1)
- sascha1337 (1)
- Hearmen (1)
- wangyd-hub (1)
- shoaibakram1 (1)
- fproulx-dfuse (1)
- xuxu9110 (1)
- muellerberndt (1)
- naderfyi (1)
- xf97 (1)
Pull Request Authors
- Coder2Programmer (2)
- Asahi-97 (1)
- feliam (1)
- jfoote (1)
- Jim8y (1)
- pventuzelo (1)
- Miller-kk (1)
- ruimaranhao (1)
- Atlasoin (1)
- cdetrio (1)
Top Labels
Issue Labels
Pull Request Labels
Dependencies
- graphviz >=0.8.3
- matplotlib >=2.2.2
- numpy >=1.15.0
- requests >=2.18.4
- wasm >=1.1
- z3-solver >=4.5
- graphviz >=0.8.3
- requests >=2.18.4
- wasm >=1.1
- z3-solver >=4.5
- ubuntu 16.04 build