MythXによるスマートコントラクトの脆弱性検知

Yuya Sugano
18 min readSep 21, 2019

Ethereumでは The DAO Hackを始めコードの不備を突いた様々な事件が発生してきました(その他Parityの自己破壊ライブラリなど)。『Code-is-law』はスマートコントラクトの基本原理ですが、アップグレードする方法の確立やスマートコントラクトのセキュリティ監査はスマートコントラクトの開発工程において必須であると言えます(主にEthereumのスマートコントラクトという前提で書いています)。MythXはMythrilのメンバーによって開発されたツールでスマートコントラクトの脆弱性検知や分析ができる複数コンポーネントから成るSaaSサービスです。[1]

Orchestration of analysis components

本稿ではMythXの概要と実際にハンズオンでSWC(Smartcontract Weakness Classification)の1つが検知できるか確認してみたいと思います。

SWC(Smartcontract Weakness Classification)は、EIP-1470で提案されたスマートコントラクトにおける脆弱性の分類スキーマでCWE(Common Weakness Enumeration)のターミノロジーや構造を緩く引き継いでいます。各SWCの詳細は以下のサイトで対応するID、関連するCWE、テストコードとともに紹介されています。[2]

目次です。

  • MythXとは
  • Truffle環境準備
  • MythXの実行テスト
  • コードの改善
  • まとめ

MythXとは

MythXはコード解析やEVMバイトコードの分析ができる複数のコンポーネントから成り立つSaaSサービスでConsenSysによって提供されています。複合的な分析を行うことで誤検知(False Positive)率を低減させ、より正確な分析結果を提供することができます。[3]

MythX analysis 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.

以下のようなコンポーネントをマイクロサービスで提供します。[4]

  • Maru — 静的コード分析およびリンターで、動的分析において無視しても良い箇所を特定することができます。
  • Harvey 動的コード分析およびインプットファズを行い、より多くの実行パスを探索することでセキュリティの脆弱性を探知します。悪意のある可能性があるコードがMythril++で検知されると入力としてHarveyに送信されます。
  • Mythril++ — シンボリックアナライザーであるオープンソースのMythrilに追加の機能や拡張をMythX用に加えたもので、Quick mode analysisやFull mode analysisの実行エンジンです。カスタム分析も作成することができます。
  • Maestro — 上記のコンポーネントに対するオーケストレーションエンジンで、分析や調整とレポーティングを行います。Maestroのレポートは特定のプロパティを持つ新しいモジュールや追加のテストの作成を促進します。

またその他のスマートコントラクトに関するセキュリティツールはこちらによくまとめられています。[5]

10種のSWCベースの脆弱性検知とクイックモードによる分析(120秒まで)が無料プランで実行可能です。MythXは開発環境であるTruffle/VS Code/Remix/GuardRailsへプラグインや拡張として組み込めるため、導入コストは非常に低いと考えれます。GuardRailsへの統合では、デプロイパイプラインへの組み込みが可能で、githubへのプルリクエスト作成からコード検査をトリガーすることが可能となっています。

MythX Features

今回はスマートコントラクト開発ツールとしてTruffleを使用してテストしてみます。実際にSWCに掲載されているテストケースを参考に脆弱なコードをあえて記述し、MythX無料プランで検知できるかを試します。

Truffleのプラグインの使用はnpmでインストールするだけで、MythXへのサインアップは必要ありません。[6]

Truffle環境準備

まずは必要となるTruffle環境の準備をします。

The MythX plugin requires Truffle 5.0 or higher.

ganacheはグローバルにインストールしているものを使用します。Truffleのバージョン5.0以上が必要なので、Truffle v5.0.36 をインストールしました(Solidityはバージョン0.5.8となりました)。

$ npm ls -g | grep ganache
ganache-cli@6.2.5
$ npm install truffle@5.0.36 -g
$ truffle version
Truffle v5.0.36 (core: 5.0.36)
Solidity v0.5.8 (solc-js)
Node v11.10.0
Web3.js v1.2.1

MythXプラグインのインストールも同様にnpmで行います。truffle-securityバージョン1.5.5がインストールできました(これはローカルへインストールしています)。

$ npm install --save-dev truffle-security
+ truffle-security@1.5.5

プロジェクトのディレクトリ配下でtruffleの雛形を用意してください。

$ truffle init
$ truffle compile
Compiling your contracts...
===========================
> Compiling ./contracts/Migrations.sol
> Artifacts written to /home/ether/work/truffle/test/build/contracts
> Compiled successfully using:
- solc: 0.5.8+commit.23d335f2.Emscripten.clang
$ npm run truffle testCompiling your contracts...
===========================
> Everything is up to date, there is nothing to compile.
0 passing (0ms)

次にバグのあるコードの記述ですが、本稿では The DAO Hack で登場したリエントランシーから、SWC-107の sample_dao.sol を使用してみたいと思います。[7]

サンプルのコードはsolidity 0.4.24向けのコードです。警告がでますが一旦以下のように書き換えてテストしました(solidityはバージョン0.5.8以上を指定しています)。

/*
* @source: http://blockchain.unica.it/projects/ethereum-survey/attacks.html#simpledao
* @author: Atzei N., Bartoletti M., Cimoli T
* Modified by Josselin Feist
*/
pragma solidity ^0.5.8;
contract SimpleDAO {
mapping (address => uint) public credit;
function donate(address to) payable public {
credit[to] += msg.value;
}
function withdraw(uint amount) public {
if (credit[msg.sender]>= amount) {
msg.sender.call.value(amount)();
credit[msg.sender]-=amount;
}
}
function queryCredit(address to) view public returns(uint) {
return credit[to];
}
}

コンパイルします。低レベルコールの戻り値が使用されていないという警告がでますが問題ありません(コンパイルできるという意味において問題ないです)。

$ truffle compileCompiling your contracts...
===========================
> Compiling ./contracts/SimpleDAO.sol
> compilation warnings encountered:/home/ether/work/truffle/test/contracts/SimpleDAO.sol:12:13: Warning: Return value of low-level calls not used.
msg.sender.call.value(amount)("");

最後にtruffle-securityをプラグインとして使用するための設定が必要です。 truffle-config.js へプラグインの設定を追加してください。プラグイン名を配列で渡すだけです。

truffle-config.js

ここまででテストの準備は完了です。実際に脆弱性が検知できるかを確認してみましょう。

MythXの実行テスト

プロジェクトの全てのコントラクトの分析は truffle run verify コマンドで実施できます。以下のようなエラーが発生しました。手元では手動で truffle-error モジュールをインストールすることでこのエラーが解消しています。

$ truffle run verify
Error: Cannot find module 'truffle-error'
$ npm install --save-dev truffle-error
truffle-error@0.0.5: WARNING: This package has been renamed to @truffle/error.
+ truffle-error@0.0.5

※githubで念のためIssueを投げています。

https://github.com/ConsenSys/truffle-security/issues/241

『Would you like to continue with a partial analysis?』と聞かれるので『Y』を入力してください。実際に実行した結果です。出力は結果がトライアルモードの分析であることを示しています。テストの対象となったコントラクト『SimpleDAO.sol』において148.6秒のテスト実行時間で分析が完了したこと、また4件の警告と1件のエラーが発見されたことが分かります。その内3件にはSWCのID(SWC Identifier)が付いています。

truffle run verify in MythX trial mode

20数行のsolidityコードに対して148.6秒かかっている点は、内部で各コンポーネントを使用した複合的な分析がされていることを考慮しても、若干時間がかかりすぎだと思いました。今後改善されることを期待しています。

コードの改善

SWC-107のリエントランシーが検知されていません。表のとおりSWC-107が無料プランではSWC-107が検知できる範囲に含まれていないことに気が付いたので、実際に検知できているSWC-103/104/105についてコードを修正し脆弱性が解消されるか確認してみたいと思います。[8]

SWC Coverage

まずは各警告やエラーの内容を確認してみましょう。

  • Warning A floating pragma is set SWC-103
    solidityのバージョンが固定されていないことに対する警告で、Ethereum Smart Contract Best Practicesに反します。
  • Warning The return value of a message call is not checked SWC-104
    低レベルコールの戻り値がチェックされていないことに対する警告で、Ethereum Smart Contract Best Practicesに反します。
  • Error Anyone can withdraw ETH from the contract account SWC-105
    コンストラクタやその他の関数において悪意のある攻撃者がコントラクトのアカウントからEtherを引き出せる可能性がある脆弱性に対するエラーです。

詳細は各SWCの該当ページを確認して頂きたいのですが、本稿では以下のようにコードを変更してみました。

/*
* @source: http://blockchain.unica.it/projects/ethereum-survey/attacks.html#simpledao
* @author: Atzei N., Bartoletti M., Cimoli T
* Modified by Josselin Feist
*/
pragma solidity 0.5.8;
contract SimpleDAO {
address public owner;
mapping (address => uint) public credit;
constructor() public {
owner = msg.sender;
}
modifier onlyOwner() {
require(msg.sender == owner);
_;
}
function donate(address to) payable public {
credit[to] += msg.value;
}
function withdraw(uint amount) onlyOwner public {
if (credit[msg.sender] >= amount) {
msg.sender.transfer(amount);
credit[msg.sender] -= amount;
}
}

function queryCredit(address to) view public returns (uint) {
return credit[to];
}
}

再度コンパイルします。正常にコンパイルできています。

$ truffle compileCompiling your contracts...
===========================
> Compiling ./contracts/SimpleDAO.sol
> Artifacts written to /home/ether/work/truffle/test/build/contracts
> Compiled successfully using:
- solc: 0.5.8+commit.23d335f2.Emscripten.clang

truffle run verify コマンドで分析を開始します。先ほどまで出ていたSWC-103/104/105の警告とエラーが消えました!!SimpleDAO.sol のコードは前よりセキュアになったと言えるでしょう。

Cool !! Those were gone !!

MythXの強みは開発ツールへ容易に組み込めることやAPIから呼び出しができるSaaSであることで、ソフトウェアライフサイクルにおける早期の段階からセキュリティ分析を行いつつ開発を進められることです。今回検知できなかったSWC-107を含むより広範囲のSWCカバレッジと長い分析可能時間を持つ MythX Pro が9月9日にローンチされました。ただし現状はCoDeFiによるサブスクリプション払いしか対応していないようですが。[9]

Ethereumにおける開発はConsenSysのプロダクトを中心としてエコシステムが出来上がりつつあります。以下のような開発のライフサイクルが紹介されていました。Alethioなどの分析プラットフォームで発見された脆弱性はSWC Registryへアップデートされるため、MythXをデプロイのパイプラインへ組み込んでおくことで、新たに発見された脆弱性もデプロイ前に検知できる可能性があります。

Ethereum Development Lifecycle ?

以上、MythXの概要とハンズオンによる脆弱性の検知のテストでした。

まとめ

  • MythXはスマートコントラクトの脆弱性検知や分析ができる複数コンポーネントから成るSaaSサービスである
  • 既存のスマートコントラクト開発ツールであるTruffle/VS Code/Remix/GuardRailsへプラグインや拡張として容易に組み込める
  • GuardRailsへの組み込みではデプロイパイプラインへ連携することでDevOpsへセキュリティ分析を統合できる
  • セキュリティ分析は各マイクロサービスを使用した複合的な分析のため多少時間がかかる
  • MythX Proが9月9日より提供開始されている

--

--

Yuya Sugano

Cloud Architect and Blockchain Enthusiast, techflare.blog, Vinyl DJ, Backpacker. ブロックチェーン・クラウド(AWS/Azure)関連の記事をパブリッシュ。バックパッカーとしてユーラシア大陸を陸路横断するなど旅が趣味。