アルゴリズムとかオーダーとか

仕事で勉強したことなどをまとめてます

ERC20のバグと誤報されたBatchOverFlowを体験してみる

先日セキュリティーアラートが上がり、多くの取引所が一時ERC20準拠トークンの取引を停止したという報道とともに話題になった、BatchOverFlowについて今更な感じですが自分なりにまとめてみます。

今回の問題についてはGunosy@yamarkzさんがいち早くまとめていましたので、そちらに詳細の説明は譲ります。
blockchain.gunosy.io

本ブログでは前々から使ってみたかったEthFiddle.comを使いこのバグを体験できる擬似コードと、またMythrilを用いての危険なコードの機械的な検証がどの程度有効なのかについてまとめてみたいと思います。


BatchOverFlowを体験してみる

EthFiddle.comで今回問題になったERC20Tokenを簡単に実装してみました。これは@yamarkzさんがまとめてくださったgitterのコードを含めただけの擬似的な実装です。
「Compile and Run」をクリックしてEthFiddle.comのページを表示することで実際にコントラクトを動かすことができますのでぜひ試してみてください。
ethfiddle.com

操作説明

今回のBatchOverFlowを実際に起こすための操作方法を説明します。

1.BatchOverFlowTokenをデプロイする

まずはTokenをデプロイします。
BatchOverFlowTokenをデプロイしてください。それ以外のContractはデプロイする必要はありません。
f:id:y_nakajo:20180430234612p:plain

2.batchTransferメソッドをcallする

今回の原因であるbatchTransferメソッドをcallします。callボタンを押すとパラメータを設定する画面が表示されます。
f:id:y_nakajo:20180430234819p:plain

3.Addressを設定する

_receiversをクリックするとアドレスの一覧が表示されるので、2番目と3番目の2つのアドレスをそれぞれ設定します。
addressを複数設定するには複数回選択すればOKです。選択すると前に選択したaddressを保持して新しいaddressを追加してくれます。
この辺のEthFiddle.comのUI設計はとても親切
f:id:y_nakajo:20180430234852p:plain

4. valueを設定して実行する

_value

0x8000000000000000000000000000000000000000000000000000000000000000

を入力し、CallをクリックしてbatchTransferメソッドを実行します。
f:id:y_nakajo:20180430235817p:plain

5.balanceOfを実行して残高を確認

balanceOfメソッドをcallして_ownerにbatchTransferに指定したアドレスを入力して実行します。
実行結果で表示される値が非常に大きな値になってるのが確認できます。
また、totalSupplyよりも大きな値になっていることも確認できます。
f:id:y_nakajo:20180501000023p:plain

Mythrilでのチェック

Solidityコードの安全性をチェックしてくれるツールであるMythrilで上記の擬似コードをチェックしてみました。
github.com

結果は以下の通りです。

$ myth -x contracts/BatchOverFlowToken.sol:BatchOverFlowToken
==== Exception state ====
Type: Informational
Contract: BatchOverFlowToken
Function name: batchTransfer(address[],uint256)
PC address: 933
A reachable exception (opcode 0xfe) has been detected. This can be caused by type errors, division by zero, out-of-bounds array access, or assert violations. This is acceptable in most situations. Note however that `assert()` should only be used to check invariants. Use `require()` for regular input checking. 
--------------------
In file: contracts/BatchOverFlowToken.sol:79

_receivers[i]

--------------------

==== Exception state ====
Type: Informational
Contract: BatchOverFlowToken
Function name: transfer(address,uint256)
PC address: 1747
A reachable exception (opcode 0xfe) has been detected. This can be caused by type errors, division by zero, out-of-bounds array access, or assert violations. This is acceptable in most situations. Note however that `assert()` should only be used to check invariants. Use `require()` for regular input checking. 
--------------------
In file: contracts/BatchOverFlowToken.sol:128

assert(c >= a)

--------------------

==== Integer Overflow  ====
Type: Warning
Contract: BatchOverFlowToken
Function name: transfer(address,uint256)
PC address: 1734
A possible integer overflow exists in the function `transfer(address,uint256)`.
The addition or multiplication may result in a value higher than the maximum representable integer.
--------------------
In file: contracts/BatchOverFlowToken.sol:127

a + b

--------------------

==== Integer Overflow  ====
Type: Warning
Contract: BatchOverFlowToken
Function name: batchTransfer(address[],uint256)
PC address: 529
A possible integer overflow exists in the function `batchTransfer(address[],uint256)`.
The addition or multiplication may result in a value higher than the maximum representable integer.
--------------------
In file: contracts/BatchOverFlowToken.sol:69

uint256(cnt) * _value

--------------------

69行目の危ないコードをしっかりと補足して通知してくれています。(2byte文字があるとレポート表示のコード部分がうまく表示できないようなので、実際に試す場合は日本語コメントをすべて削除してからMythrilを実行してください。)

まとめ

まだまだSolidityは成熟した言語ではなくスマートコントラクトの開発には今回のような危険が常に潜んでいます。
しかし、Mythrilやtruffleなどのスマートコントラクトの安全性を事前にチェックできるツールや、testも備えた開発ツールを用いることで機械的なチェックも可能になってきています。
スマートコントラクトの開発環境もどんどん発達してきていますので、これらの便利なツールを使いより安全に開発が行えるようにしましょう。