首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

以太坊智能合约安全漏洞(2):溢出

题图摄于加州太平洋海岸

英文原文已有若干个中文翻译版本,但译文和原文都有错漏或不足。本文系基于译者(Henry)的理解,重新翻译并做了修正,并且加入了个人的注解,力求让读者更容易领会原文的含义。为不影响阅读体验,注解没有单独标出, 可当译文 +“笔记”来阅读。

本期继续“转发即挖矿”的赠书活动,欢迎参与。

本文首发于哈希1024社区:

https://hash1024.org/topics/97

算术运算的上溢/下溢

和绝大多数编程语言一样,以太坊虚拟机(EVM)中的整数类型是有一定的范围的。例如,uint8 只能存储 [0,255] 范围内的数(无符号8位二进制数)。尝试将 256 存储到 uint8 将得到0。如果程序员不留意,没有对用户的输入进行校验就进行计算,将可能导致变量数值超出它们数据类型的有效范围,因此 Solidity 中的变量可被利用。

这个不仅仅是 Solidity 的问题,各类变成语言都有可能出现类似的漏洞。

漏洞描述

当某个操作把超出变量数据类型范围的数值写入变量时,则会发生上溢出或者下溢出。在大学里计算机组成原理的课程里面应该有相关的内容。

例如,从一个值为 0、类型为 uint8(8位的无符号整数,即只有正数)的变量减1,将得到数值 255,这称为下溢。

我们在uint8的范围之下给变量赋值,结果是这个变量成为了 uint8 类型可存储的最大数值。类似地,将 2 ^ 8 = 256 加到 uint8 类型的变量将使变量值保持不变,因为我们已经绕过uint的整个周期范围。这类似于在三角函数的自变量角度添加2π,其值不变,即 :

sin(x)= sin(x + 2π)

变量加上大于数据类型范围的数值称为溢出。为清楚起见,将 257 添加到当前具有零值的 uint8 将得到数值1。固定类型变量的周期循环有时是有益的。如果我们在最大可能的数值之上加上数值,我们将从 0 重新开始计数。如果从 0 开始减去一个数值,姜得到该类型的最大数值。

这样的漏洞允许攻击者滥用代码并创建意外的逻辑流程。例如,考虑下面的时间锁定合约。(请关注公众号:亨利笔记)

TimeLock.sol:

该合约旨在像时间保险库一样,用户可以将以太币存入合约,并且锁定至少一周。如果他们选择,用户可以将等待时间延长到1周以上。但是一旦存入,用户可以确保他们的以太安全地被锁定至少一周。这个合约写得正确吗?(请关注公众号:亨利笔记)

如果用户被迫交出他们的私钥(想想被当成人质的情况),这样的合约可能很有用,可确保在短时间内以太无法被取出。如果用户在此合约中锁定了100个以太币,并将其密钥交给攻击者,则无论 lockTime 如何,攻击者都可以使用溢出来接收以太币。

攻击者可以确定他们拥有密钥的地址当前的 lockTime(一个公共变量)。我们称之为 userLockTime 。然后,他们可以调用 increaseLockTime 函数,并传递数值 2 ^ 256 - userLockTime 作为参数。此数值将被添加到当前 userLockTime并导致溢出,将 lockTime [msg.sender] 重置为0。这样,攻击者只需简单地调用 withdraw 函数来获取其奖励。(请关注公众号:亨利笔记)

让我们看另一个例子,这个来自 Ethernaut 挑战。

剧透警告:如果您正在玩 Ethernaut 挑战,下文是某个级别通关方案。

这是一个简单的 Token 合约,它采用 transfer() 函数,允许参与者移动他们的Token。你能看到合约中的错误吗?

缺陷来自 transfer() 函数。可以使用下溢来绕过第[13]行上的 require 语句。假设有个没有余额的用户,他可使用任何非零 _value 调用 transfer() 函数,并通过第[13]行的 require 语句。(本文首发哈希1024社区:hash1024.org )

这是因为 balances [msg.sender] 为零(且是 uint256类型),因此减去任何正数(不包括 2 ^ 256 )将导致正数,因为我们上面描述的下溢现象。对于第[14]行也是如此,余额将记成正数。因此,在此示例中,由于下溢漏洞,我们获得免费 Token。

预防技术

防止上溢/下溢漏洞的传统技术是使用或建立标准数学运算的替代数学库;加法,减法和乘法(除法除外,因为它不会导致上溢/下溢,EVM会在除以 0 时回滚)。

OppenZepplin 在构建和审核安全库方面做得非常出色,可以被以太坊社区使用。特别值得一提,他们的安全数学库可用于避免上溢/下溢漏洞的参考库。

为了演示如何在 Solidity 中使用这些库,让我们使用 Open Zepplin 的 SafeMath 库来更正 TimeLock 合约。无溢出的合约变成为这样:

请注意,所有标准数学运算都已替换为 SafeMath 库中定义的运算。 TimeLock合约不再执行任何能够执行上溢/下溢的操作。

参考文献:

1. 英文原文:

https://blog.sigmaprime.io/solidity-security.html

新书发布及赠书活动

笔者和邹均、庄鹏等多位区块链大咖一同编写的区块链新书《区块链核心技术与应用》近日出版。此书由知名专家联袂推荐,深度讲解区块链核心技术、平台与应用开发,涵盖架构、共识、加密、P2P、比特币、以太坊、Hyperledger、EOS、问题与测评等。

赠书活动

笔者的新书推出后,不少读者都买书支持,为感谢广大读者,现举办《区块链核心技术与应用》赠书活动,采用“转发即挖矿”的参与方法,共识算法是 PoL (Proof of Like):

1.转发本文到朋友圈

2.朋友圈集赞个数超过5后,截屏发本公众号后台,最早发来合格截图的读者将“”得价值99元的新书一本,以往获赠的朋友请把机会留给其他读者。

截止时间:2018年10月13日23点59分,获奖者可在后台告知联系方式。

感谢机械工业出版社高婧雅编辑提供书籍。

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20181007G1FBLT00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券