智能合约安全事故回顾(2)-BEC溢出攻击
讲溢出攻击之前,先给大家讲个故事:2014年的时候,美国的宾夕法尼亚州的某个小镇上发生了一个乌龙事件,征兵系统对一万多名1893年到1897出生的男子发去信函,要求他们注册参军,否则面临罚款和监禁。收到信函的人啼笑皆非,因为这些信函指明的人都是大部分都是他们已故的祖父外祖父。导致这个事件的原因就是“千年虫”。
严格的说“千年虫”属于程序的一个BUG。因为在上个世纪,计算机的存储空间很小,使用人员为了最大化利用计算机的存储空间,规定了在计算机中存储年份的时候使用两位数字来表示,如“1998”年,那么计算机中的存储值则为“98”。当千禧年来临的时候,这个值就会变成“00”,这个时候计算机就不知道这个“00”代表的是1900年还是2000年,所以才会出现刚才文章开始的乌龙事件,这也是我们本文要讲述的”溢出“的概念。
事件介绍
2018年4月23日,一款名为BEC的代币被黑客攻击。黑客利用合约内的漏洞,短时间向外部的账户转入了天价的合约代币, 导致该代币价格迅速缩水几乎归零。攻击手法被披露的24小时内,就有三十多个合约被类似手法攻击。
漏洞原因
在solidity语言中,对int类型的数据变量规定了长度,如uint8代表的是无符号的8位整数,即0到255。假如有下面一个简单的合约:
pragma solidity ^0.4.25;
contract test{
function add(uint8 _a) public pure returns(uint8){
return _a+1;
}
}
可以发现传入的参数是一个uint8类型变量,它的范围在0-255,如果输入的值是255,那么返回的结果会是什么呢?有兴趣的读者可以到remix中试一下,返回值会是0,如果输入256,返回结果会是1。造成这样的原因主要跟数据在计算机中的存储有关,计算机只给uint8的类型变量分配了长度为8的空间,最大值为255,如果超过这个值会产生进位之后被截断,导致存储的8位全部都是0,这就造成了整数溢出。
下面看一下BEC合约中的一个函数:
function batchTransfer(address[] _receivers, uint256 _value) public whenNotPaused returns (bool) {
uint cnt = _receivers.length;
uint256 amount = uint256(cnt) * _value;
require(cnt > 0 && cnt <= 20);
require(_value > 0 && balances[msg.sender] >= amount); balances[msg.sender] = balances[msg.sender].sub(amount);
for (uint i = 0; i < cnt; i++) {
balances[_receivers[i]] = balances[_receivers[i]].add(_value);
Transfer(msg.sender, _receivers[i], _value);
}
return true;
}
这个函数的目的是实现一个批量转账的功能,receivers是接受者的数组,value是转账金额。重点关注
uint256 amount = uint256(cnt) * _value;
这里定义了一个uint256类型的变量amount来接收转账的总金额,后续会通过这个金额的值和用户所发送的金额比较来判断用户是否能够发送这么多的代币。那么重点来了,如果uint256(cnt) * _value的值超过uint256,不就产生了溢出了吗?攻击者通过传递两个账户,__value为2的255次方(实际上是转换成了16进制),2*2^255=2^256完成了溢出,amount的值为0。这个逻辑下的amount能够通过后面的所有校验,最后发送给两个账户的值确是2的255次方的代币。
BEC车祸现场连接:https://etherscan.io/tx/0xad89ff16fd1ebe3a0a7cf4ed282302c06626c1af33221ebe0d3a470aba4a660f。
防范
跟攻击手段一样,针对BEC的溢出攻击的防范也非常简单。我们可以利用safeMath库来避免这种情况。把 uint256(cnt) * _value改成 uint256(cnt) .mul(value)即可。相信稍微有点solidity编程经验的读者都能知道怎么做。BEC遭受的整数溢出的攻击原理非常简单,但是在攻击手段被披露的24小时内就有30多个合约被攻击,这也不得不引起我们的重视和思考:合约本身并不具备安全的属性,却动辄承载上千万价值的代币,我们过往对于合约的安全评估是否过于乐观?
智能合约安全事故回顾(2)-BEC溢出攻击的更多相关文章
- 【原创】智能合约安全事故回顾分析(1):The Dao事件
首先需要说明的一点是,这个世界上没有绝对安全的技术.在区块链发展的十年里,各种基于区块链的数字货币引发的安全事故层出不穷,这些安全威胁主要来源有三个方面: 自身安全机制的问题,类似智能合约. 生态安全 ...
- 智能合约安全事故回顾(3)-DOS漏洞导致的KotET事件
现实世界中的网络都是有带宽限制的,想象一下,一个访问量稳定的网站,突然有人利用某种方式爆发式的将网站的访问量提升,这个时候系统会作何反应?如果系统没有合理的防DOS攻击的方式,这种时候往往会造成服务器 ...
- 智能合约bug以及修改方案
截取两篇文章:第一遍文章说的是智能合约能不能修改的问题: ETC转到ETH地址以及转币进ETH智能合约账户能不能转出来? 第0章 引言 如果ETC充值到了ETH地址上,能找回来吗?答案是不一定. ET ...
- 智能合约语言 Solidity 教程系列8 - Solidity API
这是Solidity教程系列文章第8篇介绍Solidity API,它们主要表现为内置的特殊的变量及函数,存在于全局命名空间里. 写在前面 Solidity 是以太坊智能合约编程语言,阅读本文前,你应 ...
- 智能合约语言 Solidity 教程系列1 - 类型介绍
现在的Solidity中文文档,要么翻译的太烂,要么太旧,决定重新翻译下.尤其点名批评极客学院名为<Solidity官方文档中文版>的翻译,机器翻译的都比它好,大家还是别看了. 写在前面 ...
- Go语言打造以太坊智能合约测试框架(level3)
传送门: 柏链项目学院 第三课 智能合约自动化测试 之前课程回顾 我们之前介绍了go语言调用exec处理命令行,介绍了toml配置文件的处理,以及awk处理文本文件获得ABI信息.我们的代码算是完成了 ...
- Go语言打造以太坊智能合约测试框架(level2)
传送门: 柏链项目学院 第二课 智能合约自动化编译 前期内容回顾 之前我们的介绍的是如何通过solc编译智能合约,并且调用智能合约,本节我们继续实践,将智能合约的代码自动化编译以及abi文件生成搞定. ...
- Go-Ethereum 1.7.2 结合 Mist 0.9.2 实现代币智能合约的实例
目录 目录 1.什么是 Mist 2.Mist 在哪里下载? 3.Mist 有哪些依赖? 4.如何安装 Mist? 4.1.安装 Mist 依赖工具包 4.2.安装 Mist 4.3.启动 Mist, ...
- [转]EOS智能合约 & 私链激活 & 基本操作
链接:https://www.jianshu.com/p/90dea623ffdf 简介 本篇文章,将跟大家介绍eos私链的激活.基础智能合约的安装,以及为大家演示转账等基础操作.还没有安装eos私链 ...
随机推荐
- POJ1061(线性同余方程)
青蛙的约会 Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 105587 Accepted: 20789 Descript ...
- java代码分解质因数
总结: 循环...首位 逻辑要清晰 很简单.首先质因数最小的2.因为1不是质数 然后当输入的数刚好为2时,结束.不用下一步了.否则在循环里不停的输出一个数, 当输入的数比2大时,分能被2整除和不能被2 ...
- 怎样在win7中 安装Tomcat7.0
Tomcat 服务器是一个免费的开放源代码的Web 应用服务器,属于轻量级应用服务器. 我们可以到官方网站下载Tomcat7 工具/原料 win7 Tomcat7.0 方法/步骤 1 在官网下载软件: ...
- Mybatis 内置 Java 类型别名与 typeHandlers
aliases There are many built-in type aliases for common Java types. They are all case insensitive, n ...
- DAY11-MYSQL多表查询
一 介绍 本节主题 多表连接查询 复合条件连接查询 子查询 准备表 #建表 create table department( id int, name ) ); create table employ ...
- bash: telnet: command not found
//安装telnet服务 yum -y install telnet-server //安装telnet客户端 yum -y install telnet.*
- java之静态函数和静态变量
静态变量: 静态变量好似一种成员变量,它的特点是前面有static. 普通变量会有多份,它在每个对象当中都存在,但是静态变量只有一份,它是属于类的. 静态变量的调用方法: 1.类名.变量名 Custo ...
- python之模块(在命令行当中使用pip install 模块来进行模块的安装)
模块:在程序设计中,为完成某一功能所需的一段程序或子程序:或指能由编译程序.装配程序等处理的独立程序单位. 在我们编程的时候我们如果将所有的文件都放在那个py文件中,我们的py文件会很大,这样也很不好 ...
- springmvc 路径问题
web项目中的相对路径可以分为二类: 1.以斜杠开头:以斜杠开头的又分为二类(分类依据是斜杠出现的位置):如果出现在java代码或者配置文件(xml,properties等),这个路径叫做后台路径. ...
- unix 下 shell 遍历指定范围内的日期
UNIX下遍历日期,date 没有 -d 的参数,所以需要自己处理. 下面使用时差的方法进行计算,遍历的日期是降序的 #!/usr/bin/ksh . $HOME/.profile timelag= ...