0x00 引子
看到安比實驗室有篇文章在說《警惕!Solidity缺陷易使合約狀態失控》的問題,原文鏈接可以在參考鏈接中獲取。
這個問題實際上之前在慢霧區中,愛上平頂山(山哥)和 keywolf 就有對一篇外文進行了翻譯,可以在 SlowMist 的 GitHub 中找到(地址見參考鏈接),這篇譯文《Solidity 安全:已知攻擊方法和常見防御模式綜合列表》里面就有講到。
其實就是 Unintialised Storage Pointers(未初始化的存儲指針)
的安全問題,EVM中會將數據存儲為 storage 或 memory ,在函數中局部變量的默認類型取決于它們本身的類型,未進行初始化的 storage 變量,會指向合約中的其他變量,從而改變其他變量的值,常見的場景就是指向狀態變量,改變狀態變量的值,導致漏洞的產生。
0x01 分析過程
依據 Solidity 官方手冊上的介紹,以及經過實驗得到了一些總結分析。
這里要注意結構體,數組和映射的局部變量,在官方手冊中有提到這些類型的局部變量默認是放在 storage 中的,因此這些局部變量可能都存在相同的問題。(本文分析了結構體和數組的 Unintialised Storage Pointers 問題,而 mapping 暫未找到存在問題的案例)
而 struct 中在和局部變量進行賦值操作的時候,是保存成一個引用
如下是問題代碼,struct 在函數中被聲明但是沒有初始化,根據官方文檔中可以知道,struct 在局部變量中默認是存放在 storage 中的,因此可以利用 Unintialised Storage Pointers 的問題,p
會被當成一個指針,并默認指向slot[0]
和 slot[1]
,因此在進行p.name
和 p.mappedAddress
賦值的時候,實際上會修改變量testA
,test B
的值。
pragma solidity ^0.4.0;
contract testContract{
bytes32 public testA;
address public testB;
struct Person {
bytes32 name;
address mappedAddress;
}
function test(bytes32 _name, address _mappedAddress) public{
Person p;
p.name = _name;
p.mappedAddress = _mappedAddress;
}
}
同理數組也有同樣的問題,如下是問題代碼
pragma solidity ^0.4.0;
contract C {
uint public someVariable;
uint[] data;
function f() public {
uint[] x;
x.push(2);
data = x;
}
}
0x02 解決方案
結構體 Unintialised Storage Pointers 問題的正確的解決方法是將聲明的 struct 進行賦值初始化,通過創建一個新的臨時 memory 結構體,然后將它拷貝到 storage 中。
pragma solidity ^0.4.0;
contract testContract{
bytes32 public testA;
address public testB;
struct Person {
bytes32 name;
address mappedAddress;
}
mapping (uint => Person) persons;
function test(uint _id, bytes32 _name, address _mappedAddress) public{
Person storage p = persons[_id];
p.name = _name;
p.mappedAddress = _mappedAddress;
}
}
數組 Unintialised Storage Pointers 問題的正確解決方法是在聲明局部變量 x 的時候,同時對 x 進行初始化操作。
pragma solidity ^0.4.0;
contract C {
uint public someVariable;
uint[] data;
function f() public {
uint[] x = data;
x.push(2);
}
}
Solidity 編譯器開發團隊不出意外將在下一個版本(Solidity 0.4.25)中對存在 Unintialised Storage Pointers 問題的代碼進行修復,否則將無法正常通過編譯。
開發人員需要關注 Solidity 0.4.25 版本的發布,并且使用 Solidity 0.4.25 編寫代碼。
最后,本篇未涉及的 mapping 未初始化存儲指針的安全問題和案例,期待能夠和師傅們一起研究討論。
0x03 參考鏈接
《警惕!Solidity 缺陷易使合約狀態失控》
https://mp.weixin.qq.com/s/xex9Eef6Hz5o24sX5vE1Yg
《Solidity 安全:已知攻擊方法和常見防御模式綜合列表》
https://github.com/slowmist/Knowledge-Base/blob/master/solidity-security-comprehensive-list-of-known-attack-vectors-and-common-anti-patterns-chinese.md#%E8%99%9A%E6%8B%9F%E5%8C%96%E5%AD%98%E5%82%A8%E6%8C%87%E9%92%88
《Solidity 官方文檔》
http://solidity.readthedocs.io/en/v0.4.24/frequently-asked-questions.html
http://solidity.readthedocs.io/en/latest/types.html#structs