
引子
看到安比實驗室有篇文章在說《警惕!Solidity缺陷易使合約狀態(tài)失控》的問題,原文鏈接可以在參考鏈接中獲取。
這個問題實際上之前在慢霧區(qū)中,愛上平頂山(山哥)和 keywolf 就有對一篇外文進(jìn)行了翻譯,可以在 SlowMist 的 GitHub 中找到(地址見參考鏈接),這篇譯文《Solidity 安全:已知攻擊方法和常見防御模式綜合列表》里面就有講到。
其實就是 Unintialised Storage Pointers(未初始化的存儲指針)的安全問題,EVM中會將數(shù)據(jù)存儲為 storage 或 memory ,在函數(shù)中局部變量的默認(rèn)類型取決于它們本身的類型,未進(jìn)行初始化的 storage 變量,會指向合約中的其他變量,從而改變其他變量的值,常見的場景就是指向狀態(tài)變量,改變狀態(tài)變量的值,導(dǎo)致漏洞的產(chǎn)生。
1,分析過程
依據(jù) Solidity 官方手冊上的介紹,以及經(jīng)過實驗得到了一些總結(jié)分析。
這里要注意結(jié)構(gòu)體,數(shù)組和映射的局部變量,在官方手冊中有提到這些類型的局部變量默認(rèn)是放在 storage 中的,因此這些局部變量可能都存在相同的問題。(本文分析了結(jié)構(gòu)體和數(shù)組的 Unintialised Storage Pointers 問題,而 mapping 暫未找到存在問題的案例)

而 struct 中在和局部變量進(jìn)行賦值操作的時候,是保存成一個引用

如下是問題代碼,struct 在函數(shù)中被聲明但是沒有初始化,根據(jù)官方文檔中可以知道,struct 在局部變量中默 認(rèn)是存放在 storage 中的,因此可以利用 Unintialised Storage Pointers 的問題, p 會被當(dāng)成一個指針,并默 認(rèn)指向 slot[0] 和 slot[1] ,因此在進(jìn)行 p.name 和 p.mappedAddress 賦值的時候,實際上會修改變量 testA , test B 的值。

同理數(shù)組也有同樣的問題,如下是問題代碼:

2,解決方案
結(jié)構(gòu)體 Unintialised Storage Pointers 問題的正確的解決方法是將聲明的 struct 進(jìn)行賦值初始化,通過創(chuàng)建一 個新的臨時 memory 結(jié)構(gòu)體,然后將它拷貝到 storage 中。

數(shù)組 Unintialised Storage Pointers 問題的正確解決方法是在聲明局部變量 x 的時候,同時對 x 進(jìn)行初始化操作。

Solidity 編譯器開發(fā)團(tuán)隊不出意外將在下一個版本(Solidity 0.4.25)中對存在 Unintialised Storage Pointers 問題的代碼進(jìn)行修復(fù),否則將無法正常通過編譯。
開發(fā)人員需要關(guān)注 Solidity 0.4.25 版本的發(fā)布,并且使用 Solidity 0.4.25 編寫代碼。
最后,本篇未涉及的 mapping 未初始化存儲指針的安全問題和案例,期待能夠和師傅們一起研究討論。
3, 參考鏈接
1)《警惕!Solidity 缺陷易使合約狀態(tài)失控》
2)《Solidity 安全:已知攻擊方法和常見防御模式綜合列表》
3) Solidity 官方-常見問題
4)Solidity 官方-結(jié)構(gòu)定義