這次我們將了解如何訪問合約中的私有數據(private 數據)。
目標合約
話不多說,直接上代碼
這次我們的目標合約是部署在Ropsten 上的一個合約。
合約地址:
0x3505a02BCDFbb225988161a95528bfDb279faD6b
鏈接:
https://ropsten.etherscan.io/address/0x3505a02BCDFbb225988161a95528bfDb279faD6b#code
漏洞分析
由上面的合約代碼我們可以看到,Vault 合約將用戶的用戶名和密碼這樣的敏感數據記錄在了合約中,我們知道合約中修飾變量的關鍵字僅限制其調用範圍,這也就間接證明了合約中的數據均是公開的,可任意讀取的,將敏感數據記錄在合約中是不安全的。
讀取數據
首先,讓我們來學習一下solidity的storage存儲方式:
1)storage 中的數據被永久存儲。其以鍵值對的形式存儲在slot 插槽中。
2)storage在插槽中數據從右向左排列,空間不足時,打包當前插槽,開啟下一個插槽存儲數據;存儲定長數組(長度固定)時,數組中每一個數據佔據一個插槽。
3)存儲變長數組(長度隨元素的數量而改變)比較特殊,在遇到變長數組時,會先啟用一個新的插槽slotA 用來存儲數組的長度,其數據存儲在另外的編號為slotV 的插槽中。
slotA 表示變長數組聲明的位置,同時也存儲著變長數組的長度length:
length = sload(slotA)
用slotV表示變長數組數據存儲的位置(即key),index 表示value 對應的索引下標:
slotV = keccak256(slotA) + index
用value 表示變長數組某個數據的值:
value = sload(slotV)
下面我們就帶大家來讀取這個合約中的數據。
首先我們先看slot0 中的數據:
由合約中可以看到slot0 中只存儲了一個uint 類型的數據,我們讀取出來看一下:
我這裡使用Web3.py 取得數據,首先寫好程序
運行結果:
“7b”是16進制數,轉換成10進制數就是123。
這裡我們就成功的去到了合約中的第一個插槽slot0 中存儲的uint 類型的變量count=123 ,下面我們繼續:
slot1 中存儲三個變量:u16, isTrue, owner
運行結果:
從右往左依次為
owner = f36467c4e023c355026066b8dc51456e7b791d99
isTrue = 01 = true
u16 = 1f = 31
slot2 中就存儲著私有變量password 我們讀取看看
運行結果:
slot 3, 4, 5 中存儲著定長數組中的三個元素
運行結果:
slot6 中存儲著變長數組的長度
運行結果:
返回的結果顯示變長數組的長度為3。
我們從合約代碼中可以看到用戶的id 和password 是由鍵值對的形式存儲的,下面我們來讀取兩個用戶的id 和password:
user1
運行結果:
user2
運行結果:
這樣我們就成功的將合約中的所有數據讀取完成。
由此可見,合約中的私有數據也是可以讀取的。
總結
大家可以看到,合約中的私有數據也是可以讀取的,所以一定不要將任何敏感數據存放在合約中哦。
如果想了解更多的智能合約和區塊鏈知識,歡迎到區塊鏈交流社區CHAINPIP社區,一起交流學習~
社區地址:https://www.chainpip.com/