区块链兄弟社区,区块链技术专业问答先行者,中国区块链技术爱好者聚集地

作者:吴寿鹤,《区块链开发实战——以太坊关键技术与案例分析》的第一作者,《区块链开发实战——Hyperledger Fabric关键技术与案例分析》联合作者,IONChain 离子链 首席架构师,hyperLedger核心项目开发人员,区块链技术社区-区块链兄弟联合创始人。github: https://github.com/gcc2ge

来源:区块链兄弟,国内第一家专注区块链技术分享实战的公益性媒体社区

原文链接:http://www.blockchainbrother.com/article/1992

文章发布:请标题作者和来源,版权归区块链兄弟所有


事件回顾:

4月25日早间,火币Pro公告,SMT项目方反馈今日凌晨发现其交易存在异常问题,经初步排查,SMT的以太坊智能合约存在漏洞。火币Pro也同期检测到TXID为https://etherscan.io/tx/0x0775e55c402281e8ff24cf37d6f2079bf2a768cf7254593287b5f8a0f621fb83的异常。受此影响,火币Pro现决定暂停所有币种的充提币业务,随后,火币Pro又发布公告称暂停SMT/USDT、SMT/BTC和SMT/ETH的交易。此外,OKEx,gate.io等交易平台也已经暂停了SMT的充提和交易。截止暂停交易,SMT在火币Pro的价格下跌近20%。

该漏洞代理的直接经济损失高达上亿元人民币,间接产生的负面影响目前无法估量。这到底是怎样一个漏洞呢?下面将详细分析该漏洞的产生和解决方案。

漏洞分析:

SMT与前几天爆出的美图BEC代币都出现类似的安全漏洞—整数溢出,那么什么是整数溢出,整数溢出出现的原因是什么,怎样才能避免整数溢出呢?接下来我们带着这些问题来看下面的内容。

整数溢出

整数溢出分向上溢出和向下溢出,有关智能合约安全的其他关键点作者在《区块链开发实战——以太坊关键技术与案例分析》中有详细介绍,以下是截取本书中关于整数溢出的部分,通过下面文字的阅读大家就可以对:什么是整数溢出,整数溢出出现的原因是什么,怎样才能避免整数溢出呢?这三个问题有个答案了。

以下文字截取于《区块链开发实战——以太坊关键技术与案例分析》

pragma solidity ^0.4.10;/**
这是一个测试整数类型上溢和下溢的例子
*/contract Test{ // 整数上溢//如果uint8 类型的变量达到了它的最大值(255),如果在加上一个大于0的值便会变成0function test() returns(uint8){uint8 a = 255;uint8 b = 1; return a+b;// return 0} //整数下溢//如果uint8 类型的变量达到了它的最小值(0),如果在减去一个小于0的值便会变成255(uin8 类型的最大值)function test_1() returns(uint8){uint8 a = 0;uint8 b = 1; return a-b;// return 255}
}

有了上面的理论基础,我们在看一个转账的例子,看在我们的合约中应该如何避免不安全的代码出现:

// 存储用户余额信息mapping (address => uint256) public balanceOf;// 不安全的代码// 函数功能:转账,这里没有做整数溢出检查function transfer(address _to, uint256 _value) { /* 检查发送者是否有足够的余额*/if (balanceOf[msg.sender] < _value) throw; /* 修改发送者和接受者的余额 */balanceOf[msg.sender] -= _value;balanceOf[_to] += _value;
}// 安全代码function transfer(address _to, uint256 _value) { /* 检查发送者是否有足够的余额,同时做溢出检查:balanceOf[_to] + _value < balanceOf[_to] */if (balanceOf[msg.sender] < _value || balanceOf[_to] + _value < balanceOf[_to]) throw; /* 修改发送者和接受者的余额 */balanceOf[msg.sender] -= _value;balanceOf[_to] += _value;
}

我们在做整数运算的时候要时刻注意上溢,下溢检查,尤其对于较小数字的类型比如uint8、uint16、uint24更加要小心:它们更加容易达到最大值,最小值。

案例分析:

SMT合约中的整数安全问题简析

SMT的合约地址是:0x55F93985431Fc9304077687a35A1BA103dC1e081,合约代码可以访问etherscan的如下网址进行查看

https://etherscan.io/address/0x55f93985431fc9304077687a35a1ba103dc1e081#code

SMT合约有问题的代码存在于transferProxy()函数,代码如下:

function transferProxy(address _from, address _to, uint256 _value, uint256 _feeSmt,uint8 _v,bytes32 _r, bytes32 _s) public transferAllowed(_from) returns (bool){ if(balances[_from] < _feeSmt + _value) revert();uint256 nonce = nonces[_from];bytes32 h = keccak256(_from,_to,_value,_feeSmt,nonce); if(_from != ecrecover(h,_v,_r,_s)) revert(); if(balances[_to] + _value < balances[_to]|| balances[msg.sender] + _feeSmt < balances[msg.sender]) revert();balances[_to] += _value;Transfer(_from, _to, _value);balances[msg.sender] += _feeSmt;Transfer(_from, msg.sender, _feeSmt);balances[_from] -= _value + _feeSmt;nonces[_from] = nonce + 1;return true;}

其中的问题分析如下:

function transferProxy(address _from, address _to, uint256 _value, uint256 _feeSmt,uint8 _v,bytes32 _r, bytes32 _s) public transferAllowed(_from) returns (bool){ //错误1:这里没有做整数上溢出检查//_feeSmt,value都是由外部传入的参数,通过我们之前的理论这里可能会出现整数上溢出的情况// 例如:_feeSmt = 8fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ,// value = 7000000000000000000000000000000000000000000000000000000000000001// _feeSmt和value均是uint256无符号整数,相加后最高位舍掉,结果为0。// 那么_feeSmt + _value = 0 直接溢出,绕过代码检查,导致可以构造巨大数量的smt代币并进行转账if(balances[_from] < _feeSmt + _value) revert();uint256 nonce = nonces[_from];bytes32 h = keccak256(_from,_to,_value,_feeSmt,nonce); if(_from != ecrecover(h,_v,_r,_s)) revert(); if(balances[_to] + _value < balances[_to]|| balances[msg.sender] + _feeSmt < balances[msg.sender]) revert();balances[_to] += _value;Transfer(_from, _to, _value);balances[msg.sender] += _feeSmt;Transfer(_from, msg.sender, _feeSmt);balances[_from] -= _value + _feeSmt;nonces[_from] = nonce + 1;return true;}

作者修改后的代码如下:

function transferProxy(address _from, address _to, uint256 _value, uint256 _feeSmt,uint8 _v,bytes32 _r, bytes32 _s) public transferAllowed(_from) returns (bool){ //错误1:这里没有做整数上溢出检查//_feeSmt,value都是由外部传入的参数,通过我们之前的理论这里可能会出现整数上溢出的情况// 例如:_feeSmt = 8fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff ,// value = 7000000000000000000000000000000000000000000000000000000000000001// _feeSmt和value均是uint256无符号整数,相加后最高位舍掉,结果为0。// 那么_feeSmt + _value = 0 直接溢出,绕过代码检查,导致可以构造巨大数量的smt代币并进行转账// 在这里做整数上溢出检查if(balances[_to] + _value < balances[_to]|| balances[msg.sender] + _feeSmt < balances[msg.sender]) revert(); // 在这里做整数上溢出检查 ,防止交易费用 过大if(_feeSmt + _value < _value ) revert(); // 在这里做整数上溢出检查 ,防止交易费用 过大if(balances[_from] < _feeSmt + _value) revert();uint256 nonce = nonces[_from];bytes32 h = keccak256(_from,_to,_value,_feeSmt,nonce); if(_from != ecrecover(h,_v,_r,_s)) revert(); // 条件检查尽量 在开头做// if(balances[_to] + _value < balances[_to]// || balances[msg.sender] + _feeSmt < balances[msg.sender]) revert();balances[_to] += _value;Transfer(_from, _to, _value);balances[msg.sender] += _feeSmt;Transfer(_from, msg.sender, _feeSmt);balances[_from] -= _value + _feeSmt;nonces[_from] = nonce + 1;return true;}

***者发送的交易:

以下是***者恶意发送的转账交易地地址:https://etherscan.io/tx/0x1abab4c8db9a30e703114528e31dee129a3a758f7f8abc3b6494aad3d304e43f

(******交易日志截图)

BEC合约中的整数安全问题简析

BEC的合约地址是0xC5d105E63711398aF9bbff092d4B6769C82F793D,合约代码可以访问etherscan的如下网址进行查看https://etherscan.io/address/0xc5d105e63711398af9bbff092d4b6769c82f793d#code

BEC合约有问题的代码存在于batchTransfer()函数,代码如下:

 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;}
}

其中问题代码分析如下:

 function batchTransfer(address[] _receivers, uint256 _value) public whenNotPaused returns (bool) {uint cnt = _receivers.length; // 这里直接使用乘法运算符,可能会导致溢出// 变量cnt为转账的地址数量,可以通过外界的用户输入_receivers进行控制,_value为单地址转账数额,也可以直接进行控制。// 外界可以通过调整_receivers和_value的数值,产生乘法运算溢出,得出非预期amount数值,amount溢出后可以为一个很小的数字或者0,uint256 amount = uint256(cnt) * _value;require(cnt > 0 && cnt <= 20); // 这里判断当前用户拥有的代币余额是否大于或等于要转移的amount数量// 由于之前恶意用户通过调大单地址转账数额_value的数值,使amount溢出后可以为一个很小的数字或者0,// 所以很容易绕过balances[msg.sender] >= amount的检查代码。从而产生巨大_value数额的恶意转账。require(_value > 0 && balances[msg.sender] >= amount); //调用Safemath库中的安全函数来完成加减操作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;}
}

***者发送的交易:

以下是***者恶意发送的转账交易:

https://etherscan.io/tx/0xad89ff16fd1ebe3a0a7cf4ed282302c06626c1af33221ebe0d3a470aba4a660f。

(******交易日志截图)

合约整数漏洞事件总结

从上面的分析中,大家可以看出针对SMT和BEC的合约恶意***都是通过恶意的整数溢出来绕过条件检查。目前以太坊上运行着上千种合约,这上千种合约中可能也存在类似的安全隐患,所以作为合约的开发人员需要投入更多的精力来确保合约的安全性。

下篇我们将详细的介绍如何正确保合约的安全,敬请期待。

文章发布只为分享区块链技术内容,版权归原作者所有,观点仅代表作者本人,绝不代表区块链兄弟赞同其观点或证实其描述

转载于:https://blog.51cto.com/13633388/2108490

暂停交易?ERC20合约整数溢出安全漏洞案例技术分析一相关推荐

  1. Iog4j2漏洞相关技术分析

    背景 2021年12月初,极光安全团队通过安全威胁舆情发现Apache Log4j2 存在远程代码执行漏洞,迅速对该漏洞危害性评估和涉及面漏斗分析,制定了应急响应方案,对涉及到的代码组件类和主机资产类 ...

  2. php7反序列化问题,PHP7:反序列化漏洞案例及分析

    在典型的PHP-5反序列化利用中,我们会使用分配器来覆盖一个指向字符串内容的指针,从而阅读下一个堆slot的内容.然而在PHP-7中,内部字符串的表示是截然不同的. 在PHP-7中, 基本结构stru ...

  3. 干货,史上杀伤力最大的溢出型漏洞到底是什么?看这一篇就够了| 漏洞连载

    4月发生的BEC事件以及SMT事件已经沉淀一段时间了,具体的情况也被多方媒体所报道,相关的漏洞根源问题也有很多大神团队的分析和指正. 近日,有安全团队将各种已经发生或可能发生的类似溢出漏洞原理进行整理 ...

  4. checkm基因组_checkm8漏洞利用的技术分析

    checkm基因组 Most likely you've already heard about the famous exploit checkm8, which uses an unfixable ...

  5. CVE-2022-0185 价值$3w的 File System Context 内核整数溢出漏洞利用分析

    文章目录 1. 漏洞发现 2. 漏洞分析 3. 漏洞利用方法1-任意写篡改 `modprobe_path` 3-1 泄露内核基址 3-2 任意地址写思路 3-3 FUSE 页错误处理 3-4 完整利用 ...

  6. 殊途同归的CVE-2012-0774 TrueType字体整数溢出漏洞分析

    1. 前言 官方的漏洞通报中,关于这个漏洞的信息其实很少: Integer overflow in Adobe Reader and Acrobat 9.x before 9.5.1 and 10.x ...

  7. Android libcutils库中整数溢出导致的堆破坏漏洞的发现与利用

    作者:龚广(@oldfresher) 阅读本文之前,您最好理解Android中的Binder机制.用于图形系统的BufferQueue原理.堆管理器je_malloc的基本原理. 此文介绍了如何利用l ...

  8. xp正版验证补丁_实操web漏洞验证——IIS HTTP.sys 整数溢出漏洞

    一.漏洞描述 Http.sys 是一个位于 Windows 操作系统核心组件,能够让任何应用程序通过它提供的接口,以 Http 协议进行信息通讯.微软在 Windows 2003 Server 里引进 ...

  9. linux内核io源码,Linux Kernel do_io_submit()函数整数溢出漏洞

    发布日期:2010-09-21 更新日期:2010-09-27 受影响系统: Linux kernel 2.6.x 不受影响系统: Linux kernel 2.6.36-rc4 描述: ------ ...

最新文章

  1. J2EE常用资源管理方式总结
  2. HTTP 304 的理解
  3. mysql清理连接数缓存,MySQL连接池、线程缓存、线程池的区别
  4. Creating a custom ComboBox item renderer in Flex
  5. 分布式之系统底层原理
  6. ms2005 SQL Server设置改为SQL Server身份验证
  7. QPSQL driver not loaded
  8. 移动端HTML5框架
  9. Guns启动项目抛出:脚本错误,flyway执行迁移异常
  10. Linux进程地址空间探究
  11. GO语言练习:网络编程 ICMP 示例
  12. 机房管理制度(试行)
  13. ES部分查询方法,elasticsearch查询方法
  14. java complex_用java定义一个复数类Complex,能够创建复数对象,并且实现复数之间的加、减运算...
  15. 群星闪耀 视觉科技史上引领我们前进的不朽瞬间
  16. pdf合并在线,大家都在用的工具
  17. Tomcat开启APR模式并设置Tomcat为开机自启动服务
  18. 上标及下标 Unicode
  19. dockers安装redis
  20. [小甲鱼] 零基础入门python第031讲课后测试题及答案:永久存储,腌制一缸美味的泡菜

热门文章

  1. notes java api_如何使用Java来调用Notes API发送邮件(包括附件)
  2. python中debug有什么用途_Python debug 总结
  3. matlab音频信号的采样与重构,信号与系统实验(MATLAB 西电版)实验21 综合实验2-音频信号的采样与重构.ppt...
  4. 用硬盘安装linux物理机,老爷机安装UBUNTU的悲剧之旅(附用GRUB2硬盘安装ubuntu教程)...
  5. python不带颜色的图形_python-Matplotlib添加基于现有颜色系列的图例
  6. oraclek导出表_oracle如何导出和导入数据库/表
  7. c语言中srand的作用,C语言中srand(), rand(), time()函数  转载
  8. u盘在磁盘管理可以显示 但是电脑中找不到_U盘无法识别怎么办?试试这种方法,没准还有救!...
  9. 工作分流是什么意思_【嘉陵特装要闻】重庆嘉陵召开持续推进职工分流安置工作布置会...
  10. php html 停止工作,换行符php和html无法正常工作