智能合约中的“高铁座霸”|存储器局部变量未初始化——漏洞分析连载之七

安全,区块链领域举足轻重的话题,本期我们带你分析存储器局部变量未初始化会带来什么后果?我们又需要注意什么? 「区块链大本营」携手「成都链安科技」团队重磅推出「合约安全漏洞解析连载」,以讲故事的方式,带你回顾区块链安全走过的历程;分析漏洞背后的玄机。让开发者在趣味中学习,写出更加牢固的合约,且防患于未然。 当然,这些文章并不是专为开发者而作的,即使你不是开发者,当你读完本连载,相信再有安全问题爆出时,你会有全新的理解。

引子:行身践规矩,甘辱耻媚灶。——韩愈

上回讲到:

区块链游戏江山如画

安全防护未规划

一片残阳西挂

我们在上一期的区块链游戏漏洞的汇总和分析中将目前游戏合约出现的问题与前几期的漏洞连载分析进行了联动,发现游戏合约的漏洞很大一部分是在重复之前代币合约的重大错误。开发者在被鲜亮外衣包裹的游戏合约吸引更多眼球的同时,也需要对安全问题提高重视,才能获得更长远的发展。

本回咱们来聊聊:

本地变量存储措手不及

意外变量覆盖易帜拔旗

最近新闻上的“座霸”事件,在社会中引起了强烈的反响,一个理应对号入座的乘车环境,在某些人不守规矩的情况下,导致买了票的乘客没有座位,以及车厢内的秩序混乱。

于是我们联想到,没有对号入座而引起混乱的这个问题,其实在智能合约漏洞问题当中也有类似的情况。

基础小知识

大家都清楚,谈到存储,变量被存储时都会被分配一个存储位置。这个位置可以被理解为乘车时的座位。

在智能合约语言 Solidity当中,存在Storage(存储器)Memory(内存)两个不同的概念。Storage变量是指永久存储在区块链中的变量。Memory变量是临时的,这些变量在外部调用结束后会被移除。

但是Solidity目前对复杂的数据类型,比如array(数组)和struct(结构体),在函数中作为局部变量时,会默认储存在Storage当中。

此外,Solidity对于状态变量,存储次序一般是按照出现的先后顺序依次排列的。这些状态变量的位置就相当于它们的座位。

问题出在哪

Solidity与传统语言有一个很明显的不同,就是允许定义一个指向Storage的引用未初始化的外部指针(引用)会默认指向起始地址,如果不加以初始化,直接进行赋值,0地址上的状态变量就会被覆写。

拿乘坐列车打个比方,第一批乘客上车时没有安排相应的座位号,于是大家都是按照上车顺序,从前往后坐。到了新的目的地,第二批乘客上车时没有被指定座位号,坐剩余的座位,又想从前往后坐,第一批乘客原本坐在座位上,现在直接被“座霸”赶走,无位可坐。

合约中的“座霸”实例

开发中的缺一手

这种漏洞原先体现为由于开发者疏忽遗留出的已被攻击者利用的漏洞,例如有关安全公司发现的BancorLender相关的指针问题。

如图所示,状态变量agreements一开始被声明在第一个黄色框内,进入起始位置slot 0x00

第二个黄色框框是在函数offerToLend()中试图声明一个新的局部变量agreement,但其未做初始化处理,所以起始位置slot 0x00会被新的局部变量agreement占据。更具体些讲,从粉红色划线处开始的后面三项赋值操作都会覆盖slot 0x00slot 0x03上原有的值。

最后导致了代码逻辑紊乱,功能无法正常实现[1]

蜜罐中的留一手

此外,联系上一期我们提到的游戏合约,这个漏洞不出意外的在游戏合约中也出现了,但是出现的形式是蜜罐,蜜罐我们之前也提到过,是故意放置明显的破绽让略懂技术的玩家以为有机可趁,但实际上更深处有合约拥有者留给自己的不公平获利操作空间。所以我们将这种情况归为此类漏洞的第二种具体情况。

案例来源于一个名为OpenAddressLottery的博彩合约。

这部分代码中的“s”被声明但是并没有做相应的初始化处理,所以实际上之后的赋值操作都会覆盖原有地址上重要的值。

会代替哪些值呢?我们来看谁“坐在”最初始Storage地址上:

所谓的可预测的最终答案是LuckyNumber占据的最初始的位置,所以实际上是会被tx.gasprice*7所覆盖的, 而address owner会被msg.sender代替,但这两个值实际上是一样的。

由于luckyNumberOfAddress的结果以模8(二进制)的形式计算,而被覆盖后tx.gasprice*7真实的结果一定会大于7,所以玩家想赢是绝对不可能的[2]

其中我们还要注意一点,第一部分代码中,require(msg.send==owner),表示只有合约拥有者才能调用这个能覆盖原有值的函数,所以合约的蜜罐意图非常明显。

最终的结果也符合了我们的推断:

合约创建者在转出所有参与者的资金后,启动自毁,逃之夭夭。

表现形式总结与修复建议

总结上述具体案例的情况,我们可以说:

未初始化的存储器局部变量可以指向合约中的状态变量,从而导致故意(即开发人员故意将它们放在那里进行攻击)或无意的漏洞。

我们将一些典型的默认储存在Storage中的变量分为结构体(struct)和数组(Array)展示出错误范例。

典型结构体(struct)错误范例:

当输入

_name="0x0000000000000000000000000000000000000000000000000000000000000001"(63个0),地址任意地址时,会覆盖unlocked的值,使其变为true。

典型数组(Array)错误范例:

当输入

elements=["0x0000000000000000000000000000000000000000000000000000000000000001"](63个0)

会覆盖frozen的值,使其变为true。

漏洞修复建议

Remix-ide等编译器会对未初始化的存储器局部变量进行告警,开发人员不能忽略这个警告,在声明变量时,应对这些存储器局部变量进行初始化,或者根据其使用情况,将其安排在暂时的存储空间Memory上,避免安全漏洞。

良好的秩序,良好的心态

本期介绍的漏洞,是由于Solidity语言的默认存储规则,以及引用未初始化变量的特殊性共同导致的。在传统语言当中,这个情况会在编译器当中报错,无法通过。目前的Solidity版本(0.4.24)却没有进行相同严格的禁止, 只会在编译器中给出告警。

所以我们在这里针对智能合约开发和使用两方面再次强调:

  1. 遵守合约开发规范,缜密筹备安全防护,是我们屡次三番提到的合约开发精神,在区块链这个新兴的技术应用时遵守规范、周全规划,才能更好的帮助新兴技术稳步发展。
  2. 对于蓄谋欺骗大众的投机合约,当发现破绽时,一定要提防合约创建者的蜜罐手段,多留一个心眼,避免上当受骗。

目前的区块链是一个尚未成熟,有待发展的产业,追逐机遇的同时,做到冷静思考,心态平和是成功的必备素养,请大家给变量分配位置的同时,也给自己的心态调整位置。

引用:

[1] Solidity缺陷易使合约状态失控

https://zhuanlan.zhihu.com/p/41412333

[2] How does this honeypot work?

https://www.reddit.com/r/ethdev/comments/7wp363/how_does_this_honeypot_work_it_seems_like_a/

[3] 构造函数失控、未初始化的存储指针

https://ethfans.org/posts/comprehensive-list-of-common-attacks-and-defense-part-7

原文发布于微信公众号 - 区块链大本营(blockchain_camp)

原文发表时间:2018-08-30

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏老付的网络博客

装饰者模式

在23种设计模式中,装饰者模式在游戏开发的过程中,使用的很是频繁。因为这个设计模式,把所有的业务的逻辑封装的对应的实体类中,从而为主流程减负了。首先看下一个应用...

32140
来自专栏张善友的专栏

微软在动态语言支持上超越了Java?

当.NET在2000/2001年第一次发布的时候,Java社区认为它仅仅是从语言以及标准库上对Java的一个“克隆”。我们把二者的简单实例代码进行比较以后就可以...

191100
来自专栏YoungGy

ML基石_8_NoiseAndError

recap Noise and Probabilistic Target noise来源 Probabilistic Target Error Measure ...

20350
来自专栏圆方圆学院精选

【刘文彬】【精解】EOS标准货币体系与源码实现分析

原文链接:醒者呆的博客园,https://www.cnblogs.com/Evsward/p/eos-exchange.html

12210
来自专栏三木的博客

Kobject浅析

面向对象的思想的确在应用软件的开发中颇具优势,它让一个个纯逻辑的函数和数据变成了一个个有生命的个体。鉴于性能的考虑,系统软件的实现(例如linux kernel...

21980
来自专栏牛客网

今日头条2018春招安卓面经

一面: 协变 线程间通信?有几种同步/加锁方式? 进程间通信?答了三个只知道概念的和安卓的AIDL。 又问这“三个”中任选一个阐述原理 hashCode()方法...

36960
来自专栏醒者呆

【精解】EOS标准货币体系与源码实现分析

EOS智能合约中包含一个exchange合约,它支持用户创建一笔交易,是任何两个基本货币类型之间的交易。这个合约的作用是跨不同币种(都是EOS上的标准货币类型...

1.2K90
来自专栏不二小段

【爬虫与反爬】记一次网址编码研究

相爱相杀的爬虫与反爬工程师啊……愿你们和谐相处。 前些日子写爬虫时遇到一个比较奇怪的编码,是构造目标网址的一个组成部分,我更倾向于说是编码而不是加密,虽然的确有...

35080
来自专栏小樱的经验随笔

CTF---密码学入门第六题 古典密码

古典密码分值:10 来源: 北邮天枢战队 难度:易 参与人数:5115人 Get Flag:1549人 答题人数:1783人 解题通过率:87% 密文内容如...

33190
来自专栏青玉伏案

设计模式(一):“穿越火线”中的“策略模式”(Strategy Pattern)

在前段时间呢陆陆续续的更新了一系列关于重构的文章。在重构我们既有的代码时,往往会用到设计模式。在之前重构系列的博客中,我们在重构时用到了“工厂模式”、“策略模式...

22560

扫码关注云+社区

领取腾讯云代金券