讲溢出攻击之前,先给大家讲个故事: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. 【原创】智能合约安全事故回顾分析(1):The Dao事件

    首先需要说明的一点是,这个世界上没有绝对安全的技术.在区块链发展的十年里,各种基于区块链的数字货币引发的安全事故层出不穷,这些安全威胁主要来源有三个方面: 自身安全机制的问题,类似智能合约. 生态安全 ...

  2. 智能合约安全事故回顾(3)-DOS漏洞导致的KotET事件

    现实世界中的网络都是有带宽限制的,想象一下,一个访问量稳定的网站,突然有人利用某种方式爆发式的将网站的访问量提升,这个时候系统会作何反应?如果系统没有合理的防DOS攻击的方式,这种时候往往会造成服务器 ...

  3. 智能合约bug以及修改方案

    截取两篇文章:第一遍文章说的是智能合约能不能修改的问题: ETC转到ETH地址以及转币进ETH智能合约账户能不能转出来? 第0章 引言 如果ETC充值到了ETH地址上,能找回来吗?答案是不一定. ET ...

  4. 智能合约语言 Solidity 教程系列8 - Solidity API

    这是Solidity教程系列文章第8篇介绍Solidity API,它们主要表现为内置的特殊的变量及函数,存在于全局命名空间里. 写在前面 Solidity 是以太坊智能合约编程语言,阅读本文前,你应 ...

  5. 智能合约语言 Solidity 教程系列1 - 类型介绍

    现在的Solidity中文文档,要么翻译的太烂,要么太旧,决定重新翻译下.尤其点名批评极客学院名为<Solidity官方文档中文版>的翻译,机器翻译的都比它好,大家还是别看了. 写在前面 ...

  6. Go语言打造以太坊智能合约测试框架(level3)

    传送门: 柏链项目学院 第三课 智能合约自动化测试 之前课程回顾 我们之前介绍了go语言调用exec处理命令行,介绍了toml配置文件的处理,以及awk处理文本文件获得ABI信息.我们的代码算是完成了 ...

  7. Go语言打造以太坊智能合约测试框架(level2)

    传送门: 柏链项目学院 第二课 智能合约自动化编译 前期内容回顾 之前我们的介绍的是如何通过solc编译智能合约,并且调用智能合约,本节我们继续实践,将智能合约的代码自动化编译以及abi文件生成搞定. ...

  8. 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, ...

  9. [转]EOS智能合约 & 私链激活 & 基本操作

    链接:https://www.jianshu.com/p/90dea623ffdf 简介 本篇文章,将跟大家介绍eos私链的激活.基础智能合约的安装,以及为大家演示转账等基础操作.还没有安装eos私链 ...

随机推荐

  1. Java基础--HashCode

    如果一个类的对象要用做hashMap的key,那么一定要注意覆盖该类的equals和hashCode方法. equals()是基类Object的方法,用于判断对象是否有相同地址及是否为同一对象 pub ...

  2. NHibernate使用总结(2)

    首先,映射文件的名称一定要是XXX.hbm.xml且生成方式一定要是嵌入的资源+不复制. hibernate.cfg.xml这个文件要放在根目录下,且生成方式必须是内容+始终复制. private v ...

  3. 2016.1.23 通过cmd在程序中执行sql脚本

    System.Diagnostics.Process pro = new System.Diagnostics.Process(); pro.StartInfo.FileName = "cm ...

  4. FFMPEG: avformat_find_stream_info()函数

    av_find_stream_info()中是要不断的读取数据包,解码获得相应的信息 其中: st->codec->codec_type:0:视频,1:音频,2:数据 st->cod ...

  5. paramiko远程执行命令成功

  6. 问题:oracle 排序 null值放在最后;结果: ORACLE中null的排序问题

    ORACLE中null的排序问题 关键字: oracle nulls 问题描述:    在平时的业务处理中,经常遇到要对业务数据进行排序,并且要对null值也做相应的排序.在Oracle中,进行Ord ...

  7. ansible for devops 读书笔记第二章Ad-Hoc Commands

    参数 参数 说明 -a ‘Arguments’, —args=’Arguments’ 命令行参数 -m NAME, —module-name=NAME 执行模块的名字,默认使用 command 模块, ...

  8. setAttribute这个方法

    setAttribute这个方法,在JSP内置对象session和request都有这个方法,这个方法作用就是保存数据,然后还可以用getAttribute方法来取出.比如现在又个User对象,Use ...

  9. 201671010127 2016—2017-2 java学习新征程

    通过大一整个学年对Python和C语言的学习,我对编程的感受有了更进一步的认识.随着时代的进步,编程语言也在实时更新,面对越来越多的编程语言,对于在编程方面的初学者,选择一门适合自己的编程语言就显得十 ...

  10. html标签的显示模式(块级标签,行内标签,行内块标签)(转)

    html标签的显示模式(块级标签,行内标签,行内块标签)   今天讲课的时候,讲到了html中的标签的显示模式,大致分为块级标签和行内标签.那么初学者在刚使用标签的时候会发现有些属性在一些标签上不起作 ...