智能合约安全事故回顾(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私链 ...
随机推荐
- 获取wifi热点
https://stackoverflow.com/questions/31555640/how-to-get-wifi-ssid-in-ios9-after-captivenetwork-is-de ...
- (转)详解C#中的反射
本文转载自:http://blog.csdn.net/educast/article/details/2894892 两个现实中的例子:1.B超:大家体检的时候大概都做过B超吧,B超可以透过肚皮探测到 ...
- Spring单例Bean和线程安全
Spring的bean默认都是单例的,这些单例Bean在多线程程序下如何保证线程安全呢?例如对于Web应用来说,Web容器对于每个用户请求都创建一个单独的Sevlet线程来处理请求,引入Spring框 ...
- codeforce 103B Cthulhu
B. Cthulhu time limit per test 2 seconds memory limit per test 256 megabytes input standard input ou ...
- Flash在线签名小程序,可回放,动态导出gif图片
需求: 公司为了使得和客户领导签字的时候记录下来,签字过程,可以以后动态回放演示,最好是gif图片,在网页上也容易展示,文件也小. 解决过程: 始我们去寻找各种app,最终也没有找到合适的,后来我在f ...
- C Primer Plus学习笔记(一)- C语言概述
从一个简单的C语言程序开始 #include <stdio.h> /*这是一个简单的C语言程序*/ //注释 int main(void) { int num; num = 1; prin ...
- Python打造一个目录扫描工具
目标:用Python3写一款小型的web目录扫描工具 功能:1.扫描指定站点 2.指定网站脚本类型来扫描 3.可控线程 4.可保存扫描结果 首先定义一个命令参数的函数 def parse_option ...
- C++知识点总结(四)——面向对象的编程细节总结
1.空类的默认函数 一般情况下,对于任意一个类A,如果程序员不显示的声明和定义上述函数,C++编译器将会自动的为A产生4个public inline(公有.内联)的默认函数,这4个函数最常见的形式为: ...
- 解决ftp无法连接登录linux的办法
1. 首先安装vsftpd 命令:yum -y install vsftpd 之后开启服务:service vsftpd start 2.关闭防火墙 1) 重启后生效 开启: chkconfig ip ...
- Ros学习service——小海龟
rosservice 服务(services)是节点之间通讯的另一种方式.服务允许节点发送请求(request) 并获得一个响应(response) rosservice list 输出可用服务的信息 ...