SkillAgentSearch skills...

Octopus

Security Analysis tool for WebAssembly module (wasm) and Blockchain Smart Contracts (BTC/ETH/NEO/EOS)

Install / Use

/learn @FuzzingLabs/Octopus

README

Octopus

<p align="center"> <img src="/images/logo-medium.png" height="300px"/> </p>

made-with-python MIT license

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 | :heavy_check_mark: | :heavy_check_mark:| :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | | :o: | |Disassembler | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | | :heavy_check_mark: | |Control Flow Analysis | :heavy_multiplication_x: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: | | :heavy_check_mark: | |Call Flow Analysis | :heavy_multiplication_x: | :heavy_plus_sign: | :heavy_check_mark: | :heavy_check_mark: | :heavy_plus_sign: | | :heavy_check_mark: | |IR conversion (SSA) | :heavy_multiplication_x: | :heavy_check_mark: | :heavy_plus_sign: | :heavy_plus_sign: | :heavy_multiplication_x: | | :heavy_check_mark: | |Symbolic Execution | :heavy_multiplication_x: | :heavy_plus_sign: | :heavy_plus_sign: | :heavy_plus_sign: | :heavy_multiplication_x: | | :heavy_plus_sign: |

  • PyPI package :heavy_check_mark:
  • Docker :heavy_check_mark:

:heavy_check_mark: DONE / :heavy_plus_sign: WIP / :heavy_multiplication_x: TODO / :o: N/A

Requirements

Octopus is supported on Linux (ideally Ubuntu 16.04) and requires Python >=3.5 (ideally 3.6).

Dependencies:

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, ...)
./run_tests.sh
# Run tests that require internet access (explorer tests)
./run_explorer_tests.sh

# Run tests for only one platforms
# {btc, eth, eos, neo, wasm}_run_tests.sh
cd octopus/tests/
./wasm_run_tests.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

In-depth Examples using APIs

<details><summary>WebAssembly</summary> <p>

Disassembler

Disassembly of a Wasm module:

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))
#[[<octopus.arch.wasm.instruction.WasmInstruction at 0x7f85e4904278>,<octopus.arch.wasm.instruction.WasmInstruction at 0x7f85e4904f60>,<octopus.arch.wasm.instruction.WasmInstruction at 0x7f85e4904ef0>]]

print()
# return text of functions code
print(disasm.disassemble_module(module_bytecode, r_format='text'))
# func 0
# i32.const 0
# call 0
# end

Disassembly of wasm bytecode:

from octopus.arch.wasm.disassembler import WasmDisassembler

# bytecode in WebAssembly is the function code (i.e. function body)
bytecode = b'\x02\x7fA\x18\x10\x1cA\x00\x0f\x0b'
# create a WasmDisassembler object
disasm = WasmDisassembler(bytecode)

# disassemble bytecode into a list of WasmInstruction
# attributes r_format='list' by default
print(disasm.disassemble())

#[<octopus.arch.wasm.instruction.WasmInstruction object at 0x7f85e4904eb8>, <octopus.arch.wasm.instruction.WasmInstruction object at 0x7f85e4904278>, <octopus.arch.wasm.instruction.WasmInstruction object at 0x7f85e4904390>, <octopus.arch.wasm.instruction.WasmInstruction object at 0x7f85e4904ef0>, <octopus.arch.wasm.instruction.WasmInstruction object at 0x7f85e4904f60>, <octopus.arch.wasm.instruction.WasmInstruction object at 0x7f85e4901048>]
print()
print(disasm.disassemble(r_format='reverse'))

#{0: <octopus.arch.wasm.instruction.WasmInstruction object at 0x7f85e4901048>, 1: <octopus.arch.wasm.instruction.WasmInstruction object at 0x7f85e4904240>, 2: <octopus.arch.wasm.instruction.WasmInstruction object at 0x7f85e4904f60>, 3: <octopus.arch.wasm.instruction.WasmInstruction object at 0x7f85e4904ef0>, 4: <octopus.arch.wasm.instruction.WasmInstruction object at 0x7f85e4904278>, 5: <octopus.arch.wasm.instruction.WasmInstruction object at 0x7f85e4904390>}
print()
print(disasm.disassemble(r_format='text'))
# block -1
# i32.const 24
# call 28
# i32.const 0
# return
# end

ModuleAnalyzer

from octopus.arch.wasm.analyzer import WasmModuleAnalyzer

FILE = "examples/wasm/samples/hello_wasm_studio.wasm"

with open(FILE, 'rb') as f:
    module_bytecode = f.read()

# return list of functions instructions (list)
# attributes analysis=True by default
analyzer = WasmModuleAnalyzer(module_bytecode)

# show analyzer attributes
print(analyzer.func_prototypes)
# [('putc_js', 'i32', ''),
#  ('__syscall0', 'i32', 'i32'),
#  ('__syscall3', 'i32 i32 i32 i32', 'i32'),
#  ('__syscall1', 'i32 i32', 'i32'),
#  ('__syscall5', 'i32 i32 i32 i32 i32 i32', 'i32'),
#  ('__syscall4', 'i32 i32 i32 i32 i32', 'i32'),
#  ('$func6', '', ''),
#  ('main', '', 'i32'),
#  ('writev_c', 'i32 i32 i32', 'i32'),
#  ('$func9', '', 'i32'),
#  ('$func10', 'i32', 'i32'),
#  ('$func11', 'i32', 'i32'),
#  ('$func12', 'i32', ''),
#  ('$func13', 'i32', 'i32'),
#  ('$func14', 'i32 i32 i32 i32', 'i32'),
#  ('$func15', 'i32 i32', 'i32'),
#  ('$func16', 'i32 i32', 'i32'),
#  ('$func17', 'i32', 'i32'),
#  ('$func18', 'i32', 'i32'),
#  ('$func19', 'i32', 'i32'),
#  ('$func20', 'i32 i32 i32', 'i32'),
#  ('$func21', 'i32 i32 i32', 'i32'),
#  ('$func22', 'i32 i64 i32', 'i64'),
#  ('$func23', 'i32 i32 i32', 'i32'),
#  ('$func24', 'i32', 'i32'),
#  ('$func25', 'i32 i32 i32 i32', '')]
print()
print(analyzer.contains_emscripten_syscalls())
#[('__syscall0', 'restart_syscall'),
# ('__syscall3', 'read'),
# ('__syscall1', 'exit'),
# ('__syscall5', 'open'),
# ('__syscall4', 'write')]

Control Flow Analysis

from octopus.arch.wasm.cfg import WasmCFG

# complete wasm module
file_name = "examples/wasm/samples/fib.wasm"

# read file
with open(file_name, 'rb') as f:
    raw = f.read()

# create the cfg
cfg = WasmCFG(raw)

# visualize CFGGraph 
# generate graph.dot and graph.pdf file
cfg.visualize()
<p align="center"> <img src="/images/wasm-cfg-fib.png" height="400px"/> </p>

Functions' instructions analytics

from octopus.arch.wasm.cfg import WasmCFG

# complete wasm module
file_name = "examples/wasm/samples/hello_wasm_studio.wasm"

# read file
with open(file_name, 'rb') as f:
    raw = f.read()

# create the cfg
cfg = WasmCFG(raw)

# visualization
cfg.visualize_instrs_per_funcs()
<p align="center"> <img src="/images/wasm-instr-func-analytics.png" height="400px"/> </p>

Call Flow Analysis

from octopus.arch.wasm.cfg import WasmCFG

# fibonacci wasm module
file_name = "examples/wasm/samples/hello_wasm_studio.wasm"

# read file
with open(file_name, 'rb') as f:
    raw = f.read()

# create the cfg
cfg = WasmCFG(raw)

# visualize Call Flow Graph
# generate call_graph.dot and call_graph.pdf file
# 
# color similar to https://webassembly.studio/
# imported func == turquoise / exported func == grey
# edge label = number of different calls to the function
cfg.visualize_call_flow()
<p align="center"> <img src="/images/wasm-callflow-hello-studio.png" height="400px"/> </p>

Legend:

<p align="center"> <img src="/images/legend_callgraph.png" height="400px"/> </p>

IR conversion (SSA)

from octopus.arch.wasm.emulator import WasmSSAEmulatorEngine

# complete wasm module
file_name = "examples/wasm/samples/fib.wasm"

# read file
with open(file_name, 'rb') as f:
    raw = f.read()


# run the emulator for SSA
emul = WasmSSAEmulatorEngine(raw)
emul.emulate_one_function('fib')
# or emul.emulate_functions(['fib'])
# or e
View on GitHub
GitHub Stars492
CategoryDevelopment
Updated5d ago
Forks90

Languages

Python

Security Score

100/100

Audited on Mar 19, 2026

No findings