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

Posted 许强#

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了solidity 安全 未初始化指针的风险——天上不会掉馅饼相关的知识,希望对你有一定的参考价值。

引用类型未初始化

引用类型,则必须明确指明数据存储哪种类型的位置里。 有三种位置: 内存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(这里是故意的,让玩家认为这是合约的漏洞)属性的随机数 secretNumber,在 shuffle() 函数作用原来是指定blockhash和时间生成一个随机数(为了更加直观,我直接写死为6),玩家可以通过 play() 函数去盲猜这个随机数,如果猜对了就可以将合约中的所有eth取走,每次调用 play() 函数后都会重置随机数。即使玩家知道随机数是6,也不可能拿走合约里的eth,不信大家可以试试;

原因就是结构体 game的初始化对存储数据 secretNumber 的覆盖;其实就是我们上边讲的,secretNumber 存储到了slot0,game由于没有指定位置,所以默认在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

以上是关于solidity 安全 未初始化指针的风险——天上不会掉馅饼的主要内容,如果未能解决你的问题,请参考以下文章

网站未安装SSL证书存在哪些安全风险?

指针变量初始化为NULL啥意思

C语言野指针就是未初始化的指针么

智能家居——安全信息收集

在未初始化的对象(空指针)上调用方法

javaWeb安全漏洞修复总结