概述

每個人都多次聽說過,智能合約中的一切都是開放的,每個人都可以看到。這意味著,不能在合約中隱藏敏感信息。在這篇簡短的文章中,我們將學習如何從另一個合約中讀取私有變量。

簡單回顧一下:當聲明一個變量(或函數)為“private”時,並不意味著它是“private”,因為沒有人能夠讀懂它(因此才有了這個令人困惑的名稱)。 Private只是指“誰”可以使用它,換句話說,就是變量(或函數)的作用域。

Private→只能從特定的合約中調用。

Internal→可以從該合約和派生的合約中調用。

External →可以從外部源調用。

Public→可以從任何地方調用。

在這篇文章中,我們不會詳細討論作用域,但是更重要的一點是,當聲明一個狀態變量public時,Solidity會自動為這個特定的變量創建一個getter函數,因此用戶可以直接調用它。當一個變量被聲明為“private”時,我們需要做更多……讓我們開始吧!

想像一下,有人寫了這樣一份合約:

乍一看,似乎只有所有者可以獲得分配給secretPassword的值。但是,正如我們之前看到的,所有內容都可以通過智能合約訪問。

為了獲得secretPassword的值,我們首先需要了解存儲。

存儲

默認情況下,Solidity中的所有狀態變量都存儲在storage中。這意味著在函數之外聲明的所有變量都由EVM保存。 →有一個例外,當聲明它為“常量”時。當將一個變量聲明為常量時,它不會佔用一個槽,而是放在編譯後的代碼中。每個插槽的長度為32字節(32字節== 256位== 64十六進制(或半字節))變量按照從0到n (n =最大容量)的順序存儲。如果某個變量超過了該特定槽的空間,那麼它將被傳遞到下一個槽。多個變量可以存儲在一個槽下,如果它們合適的話。 Struct創建一個新的槽,結構的元素的行為與上面描述的相同。固定大小的數組創建一個新的插槽。動態數組為每個元素創建一個插槽。映射存儲在哈希(key, slot)

讓我們應用這個。

如果我們回到合約,我們會看到secretPassword在第二個插槽(槽1)中。

(我把合約部署到Rinkeby,密碼是“不是那麼秘密!”)

為了檢索該值,我們將使用ethers .js:

如你所見,我們調用了provider.getStorageAt(contractAddress, storageSlot)函數。這將以十六進制返回結果。然後,我們只是將其轉換為ascii。就可以隨意使用該代碼和地址,它部署在Rinkeby上!

Source:https://medium.com/coinmonks/a-quick-guide-to-hack-private-variables-in-solidity-b45d5acb89c0