智能合約 Storage 注意事項

Jun-You Liu
Taipei Ethereum Meetup
4 min readApr 9, 2018

前言

前幾天在逛 Medium 的文章,意外看到這篇在討論如何利用 Ethereum Smart Contract Storage 實際行為跟預想的落差來攻擊。由於這個漏洞相較溢位等其他漏洞比較不會被注意到,決定記錄起來,如果大家未來在使用 Storage 時可以多注意一下。

Code

先來看看以下這個 contract:

在這裡使用跟原文章一樣的 smart contract 來舉例

這是一個幫助使用者 hodl Ether 的 smart contract。當使用者將 Ether 放進這個 contract 中,會被強制鎖定一段時間之後才能取出,在這段時間中使用者毋須擔心自己會受不了誘惑把錢拿去亂投資 ICO 導致血本無歸 (?)。

攻擊

問題出在 PayIn() 這個函式。當使用者想要存一些 Ether 進去,他會送出一筆存款的交易給這份 smart contract,但這筆存款交易其實不會記錄在使用者的 balance,而是會記錄到這份 smart contract owner 的 balance 中。

為什麼會這樣呢?

讓我們仔細看看 payIn() 在幹嘛,以下是他裡面在做的事:

HoldRecord newRecord;
newRecord.amount += msg.value;
newRecord.unlockTime = now + holdTime;
balance[msg.sender] = newRecord;

問題出在第一行,在 EVM (Ethereum Virtual Machine) 中,當沒有指定 storage/memory 時,預設會使用 storage,所以 newRecord 會是 storage 的 pointer。而 newRecord 又沒有給定初始值,那麼 newRecord 就會指向 address(0),也就是這份 contract 最一開始的地方。詳細行為可以參照 Solidity 的文件

那麼本來 newRecord 是希望指到 HoldRecord 的 struct,藉此存取

uint amount;
uint unlockTime;

其實指到的是 contract 一開始的

uint ownerAmount;
uint numberOfPayouts;

所以在 payIn()newRecord.amount += msg.value; 其實是加到 ownerAmount 中,也當然 numberOfPayouts 也被覆蓋掉了。然後 owner 就可以用 ownerWithdrawal() 來將剛剛使用者存入的錢偷走。

反攻擊

但這邊其實有個反攻擊的方法。在 payIn() 的第四行

balance[msg.sender] = newRecord;

如前面所說,newRecord 是指到 ownerAmount,所以這行其實是把 ownerAmount 指定給 msg.sender,使用者可以用一個很短的鎖定時間存一筆很小的 Ether,然後在到期後馬上使用 withdraw() 將 owner 的所有錢提領出來。

結論

這個例子是要舉出在 smart contract 中 storage 預設行為的危險性。其實只要維持一個原則就可以避免這個問題。

養成明確定義使用 storage 還是 memory 的好習慣

一般來說,指定 storage 時就直接給初始值;而在 function 裡面需要用到的暫存器都用 memory,除非想要直接修改鏈上的值。現在 compiler 都會很聰明的提醒開發者要定義 storage 還是 memory,而當 storage pointer 沒有初始值時也會提醒開發者。

然而如果不是開發者只是使用者,其實在看 code 的時候很容易會忽略掉這部分的漏洞,所以在有更安全的選項出來前,就要多加注意了。

在此附上我的更改版,一批很純的Hodl (?)

Hodl啊啊啊!!!

如果覺得內容哪裡有誤,歡迎留言討論交流,然後別忘了分享給你所有很愛用預設參數的朋友 (?

如果覺得這篇文章不錯,也歡迎使用 LikeCoin 丟我,多多支持 LikeCoin!

--

--

Jun-You Liu
Taipei Ethereum Meetup

Ethereum Amateur Researcher+Homeschooler. Now a computer science undergraduate student struggling with research and coding at National Taiwan University.