警惕!Solidity缺陷易使合约状态失控

本文揭示了 Solidity 语言中的一个设计缺陷,即未初始化的 storage 指针可能导致合约状态失控。通过蜜罐合约和 BancorLender 示例,展示了这一问题如何引发安全漏洞。Solidity 编译器即将进行改进以解决这个问题,提高编译器的错误提示级别,减少类似问题的发生。
摘要由CSDN通过智能技术生成

作者:安比(SECBIT)实验室 & 轻信科技(LedgerGo)

本文以蜜罐合约和 BancorLender 合约为例,详细介绍 Solidity 语言中「未初始化的 storage 指针」问题,并追踪 Solidity 编译器关于此问题的开发进展。

安比(SECBIT)实验室在 BancorLender (0x2d820ea3A6b9302c500feeb7F6361bA1DdfA5aBa) 合约中发现野指针问题(uninitialized-wild-pointer)。该合约中的一个状态变量会意外地被另一个函数修改,偏离原本设计意图。目前项目方不明确。建议项目方应立即废弃该合约,并重新发布修复后的合约。野指针问题是 Solidity 语言的最初设计欠缺考虑,而且 Solidity 编译器为了向前兼容,对这类安全问题仅采取警告提示,而开发者往往又很容易忽视这些提示,最终导致问题代码部署上线。

下面我们通过一个蜜罐例子来解释「未初始化的 storage 指针」这个缺陷。

蜜罐合约:别人看中的是你的本金

这里写图片描述
在计算机领域,蜜罐(Honeypot)通常指故意伪装成看似有利用价值并故意留有 bug 的系统,用来吸引黑客攻击,从而达到分析、监控、收集证据、拖延攻击等目的。

而以太坊主网上存在这样一类游戏合约:以高额回报为诱饵,并故意露出破绽,让参与者误认为自己有很高的概率可以获胜,诱导参与者转入以太参与游戏而损失本金。通常称这类合约为“蜜罐合约”。

“蜜罐”这个词,其实很形象:罐子里有可口的蜂蜜,吸引着熊去吃,但周边其实有暗藏的陷阱,真正目的是为了抓住熊。

“蜜罐合约”的部署者通常利用各种技巧使代码部分特殊用途不易被参与者发现,利用当中的信息不对称,使参与者产生错误判断,从而被骗取本金。

「未初始化的 storage 指针」正是“蜜罐合约”部署者最常用的一种技巧。这个问题源于 Solidity 语言以及编译器设计上的失误。

我们结合下面这个名为 Honeypot 的简化合约说明。这是一个竞猜合约,参与者调用 guess() 接口,传入 _number 数字进行竞猜,如果猜的数字等于合约中的 luckyNum,则竞猜成功,参与者可获取两倍回报。

聪明的你可以仔细思考一下,竞猜数字 _number 应该填多少?

这里写图片描述

终极答案是 42 吗?由于变量 luckyNum 在最开始(第 2 行)被赋值 42,并且没有其他被赋值操作,因此绝大多数人都会猜 42。

然而这个合约极具迷惑性,42 并不是正确答案。到底哪里出了问题?变量 luckyNum 什么时候被修改了?

让我们来理一理:函数 guess() 先把参与者的地址和竞猜数字放入 gameHistory 数组中保存(第 12 ~ 15 行)。而数组 gameHistoryGame 结构体(Struct)构成。函数开始先通过 Game game 声明了一个结构体变量 game(第 12 行),再分别对成员变量进行赋值(第 13 ~ 14 行),最后将变量 game 塞到 gameHistory 数组中(第 15 行)。

看着“似乎”没毛病。然而,这里有很严重的问题。

传统编程语言中,我们在函数内部申明一个变量,通常默认是局部变量。但 Solidity 在语言设计上埋了个坑,在此处反直觉地默认让引用类型(Reference Type)变量 game(第 12 行)存储位置为 storage,因此对变量 game 的修改,作用范围是“全局”的。并且对于未初始化的 storage 指针(类似传统语言中的空指针),Solidity 默认其指向 storage 的起始地址,即指向合约开头定义的状态变量(第 2 ~ 3 行)。

变量 luckyNum 值不是 42,那么到底是多少呢?

Solidity 将源码中的状态变量(常量除外),根据一定规则,按照出现顺序依次排列存储在 storage 中。

luckyNum<

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值