solidity 安全 未初始化指针的风险——天上不会掉馅饼

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

引用类型未初始化

引用类型则必须明确指明数据存储哪种类型的位置里。 有三种位置 内存memory 、 存储storage 以及 调用数据calldata 。

  • memory 即数据在内存中因此数据仅在其生命周期内函数调用期间有效。不能用于外部调用。

  • storage 状态变量保存的位置只要合约存在就一直存储.

  • calldata 用来保存函数参数的特殊数据位置是一个只读位置。

在开发合约时准确地理解如何使用这个操作至关重要。否则可以因为利用不适当地初始化变量来产生有漏洞的合约。

漏洞分析

在讨论这个漏洞之前我们需要先了解状态变量在Solidity中是如何存储的。简单来说状态变量按照合约中出现的顺序保存在slot中例如第一个变量存储在slot0第二个在slot1中依次类推。

Solidity中结构体数组和映射等复杂数据结构都是通过栈上的指针访问实际的存储位置memory或者storage当他们做的局部变量如果没有初始化则默认是放在 storage 中的而且默认指向slot0。

这样意味着我们可以操作这个局部变量间接控制了原来存在slot0上的值。

实例分析

pragma solidity ^0.4.19;

contract CryptoRoulette {

    uint256 public secretNumber;
    uint256 public betPrice = 0.1 ether;

    struct Game {
        address player;
        uint256 number;
    }

    function CryptoRoulette() public {
        shuffle();
    }

    function shuffle() internal {
        //secretNumber = uint8(sha3(now, block.blockhash(block.number-1))) % 20 + 1;
        secretNumber = 6;
    }

    function play(uint256 number) payable public {
        require(msg.value >= betPrice && number <= 10);

        Game game; //问题所在
        game.player = msg.sender;
        game.number = number;

        if (number == secretNumber) {
            msg.sender.transfer(this.balance);
        }

        shuffle();
    }
}

该合约设置了一个public这里是故意的让玩家认为这是合约的漏洞属性的随机数 secretNumbershuffle() 函数作用原来是指定blockhash和时间生成一个随机数为了更加直观我直接写死为6玩家可以通过 play() 函数去盲猜这个随机数如果猜对了就可以将合约中的所有eth取走每次调用 play() 函数后都会重置随机数。即使玩家知道随机数是6也不可能拿走合约里的eth不信大家可以试试

原因就是结构体 game的初始化对存储数据 secretNumber 的覆盖其实就是我们上边讲的secretNumber 存储到了slot0game由于没有指定位置所以默认在storage中且位于slot0所以我们初始化时game.player = msg.sender 由于结构体 game的初始化对存储数据 secretNumber 进行了覆盖导致 secretNumber 变成了 msg.sender 的 uint256 内容这样一来就使得后面的 if判断条件不能成立从而使得玩家不能转走合约中的所有eth。

解决方法

我们在函数里直接初始化结构体必须加 memory 关键字因为 memory 是使用内存来进行存储这样一来就可以避免占用 storage 的存储位该问题在 Solidity 0.5.0 版本以前只是进行了提示并没有做出错误警告所以在老版本编译器中要注意该问题。在最新的版本则不需要担心直接error。

这段代码其实是基于《加密轮盘赌轮》修改的感兴趣的可以看看原来的。

GutHub 地址github.com/smart-contract-honeypots/CryptoRoulette.sol

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6