Solidity合约中的整数安全问题——SMT BEC合约整数溢出解析
一. 整数安全回顾
1. 整数安全简介
在传统的桌面windows攻防对抗领域,伴随着微软和合作伙伴对软件开发流程推行 SDL规范,同时对安全投入的逐步加大,单一的封包超长和文件特定字段内容超长导致的溢出漏洞在一些大型软件里几乎绝迹。剩余漏洞除了浏览器中的UAF(有隔离堆和延迟释放对关键类进行利用缓解 ) ,弱类型语言存在的类型混淆,还零星剩下了一些整数类的漏洞。整数类漏洞,最近的如去年的nginx cve-2017-7529。
区块链方向,比较早的整数溢出类漏洞可追溯到2010年的比特币大整数溢出,CVE-2010-5139 ,黑客通过整数溢出构造了大概92233720368.54277039 个比特币,最近的SMT/BEC的整数安全场景与之前比特币的场景类似。
传统安全领域中,整数安全与数据模型和整数运算支持的运算符相关,其中数据模型又跟处理器架构体系和操作系统平台相关。如图1。
图1
C中容易引发整数安全问题的运算符简要罗列如下,如图2。
图2
Solidity合约中的整数安全场景与之类似。
2. Solidity中的整数安全场景
SMT 和 BEC 都是以太坊代币生态下的一个普通的 ERC-20 代币。转账流通都是通过以太坊的solidity合约进行实现。
区块链1.0的比特币也有脚本语言,但是为了安全阉割掉了循环和递归等图灵完备性语言才有的功能。以太坊 Solidity设计之初就被定位为图灵完备性语言。 Solidity的图灵完备性也为后续的合约漏洞陆续埋下了伏笔,如 The Dao 漏洞事件直接导致以太坊硬分叉成了eth 和旧链etc。
Solidity语言暂不支持类似于C中的 float double 等浮点型数据类型。支持int/uint变长的有符号或无符号整型。变量支持的步长以8 递增,支持从uint8 到uint256,以及int8 到int256 。需要注意的是,uint和int 默认代表的是uint256 和int256。uint8 的数值范围与 C中的uchar相同,即取值范围是0 到 2^8-1,uint256支持的取值范围是 0 到 2^256-1,余下数据类型以此类推。
Solidity语言中对于运算符的支持如下。
比较: , ,== ,!= ,>= ,> ,返回值为bool 类型。
位运算符:& ,|,(^ 异或),(~ 非)。
数学运算:+ ,-,一元运算+ ,* ,/,(% 求余),(** 平方)。
Solidity合约代码的逻辑都相对简单,运算符的使用中加法 减法和乘法居多。
以太坊提供有一个Solidity语言的在线编译测试工具。http://remix.ethereum.org/#optimize=false&version=soljson-v0.4.23+commit.124ca40d.js 我们以加法和减法运算作为举例,简单说明下整数溢出在Solidity 语言中的常规情况。
编写如下solidity测试代码。
pragma solidity ^0.4.0;
contract C {
// (2**256 - 1) + 1 = 0
function overflow() returns (uint256 _overflow) {
uint256 max = 2**256 - 1;
return max + 1; }
// 0 - 1 = 2**256 - 1
function underflow() returns (uint256 _underflow) {
uint256 min = 0;
return min - 1; }
}
在线测试工具中编译运行结果如下如图3图4。
图3
图4
可以看到uint256当取最大整数值,上溢之后直接回绕返回值为0 , uint256当取0下溢之后直接回绕,返回值为 2^256-1 。这是 solidity中整数溢出场景的常规情况。
3. Solidity中的整数溢出缓解和SafeMath库
为了减少solidity合约开发中产生的安全问题,以太坊的官方开发博客陆续发布了一些与 solidity开发安全相关的博文。在 2017年 8月 6日 单独发过一篇使用SafeMath 库进行整数安全操作的文章> 。详见链接: https://ethereumdev.io/safemath-protect-overflows/
/**
* @title SafeMath
* @dev Math operations with safety checks that throw on error
*/
library SafeMath {
function mul(uint256 a, uint256 b) internal constant returns (uint256) {
uint256 c = a * b;
assert(a == 0 || c / a == b);
return c;
}
function div(uint256 a, uint256 b) internal constant returns (uint256) {
// assert(b > 0); // Solidity automatically throws when dividing by 0
uint256 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return c;
}
function sub(uint256 a, uint256 b) internal constant returns (uint256) {
assert(b
return a - b;
}
function add(uint256 a, uint256 b) internal constant returns (uint256) {
uint256 c = a + b;
一. 整数安全回顾
1. 整数安全简介
在传统的桌面windows攻防对抗领域,伴随着微软和合作伙伴对软件开发流程推行 SDL规范,同时对安全投入的逐步加大,单一的封包超长和文件特定字段内容超长导致的溢出漏洞在一些大型软件里几乎绝迹。剩余漏洞除了浏览器中的UAF(有隔离堆和延迟释放对关键类进行利用缓解 ) ,弱类型语言存在的类型混淆,还零星剩下了一些整数类的漏洞。整数类漏洞,最近的如去年的nginx cve-2017-7529。
区块链方向,比较早的整数溢出类漏洞可追溯到2010年的比特币大整数溢出,CVE-2010-5139 ,黑客通过整数溢出构造了大概92233720368.54277039 个比特币,最近的SMT/BEC的整数安全场景与之前比特币的场景类似。
传统安全领域中,整数安全与数据模型和整数运算支持的运算符相关,其中数据模型又跟处理器架构体系和操作系统平台相关。如图1。
本文来自无奈人生安全网
图1
C中容易引发整数安全问题的运算符简要罗列如下,如图2。
图2
Solidity合约中的整数安全场景与之类似。
2. Solidity中的整数安全场景
SMT 和 BEC 都是以太坊代币生态下的一个普通的 ERC-20 代币。转账流通都是通过以太坊的solidity合约进行实现。
区块链1.0的比特币也有脚本语言,但是为了安全阉割掉了循环和递归等图灵完备性语言才有的功能。以太坊 Solidity设计之初就被定位为图灵完备性语言。 Solidity的图灵完备性也为后续的合约漏洞陆续埋下了伏笔,如 The Dao 漏洞事件直接导致以太坊硬分叉成了eth 和旧链etc。
Solidity语言暂不支持类似于C中的 float double 等浮点型数据类型。支持int/uint变长的有符号或无符号整型。变量支持的步长以8 递增,支持从uint8 到uint256,以及int8 到int256 。需要注意的是,uint和int 默认代表的是uint256 和int256。uint8 的数值范围与 C中的uchar相同,即取值范围是0 到 2^8-1,uint256支持的取值范围是 0 到 2^256-1,余下数据类型以此类推。 本文来自无奈人生安全网
Solidity语言中对于运算符的支持如下。
比较: , ,== ,!= ,>= ,> ,返回值为bool 类型。
位运算符:& ,|,(^ 异或),(~ 非)。
数学运算:+ ,-,一元运算+ ,* ,/,(% 求余),(** 平方)。
Solidity合约代码的逻辑都相对简单,运算符的使用中加法 减法和乘法居多。
以太坊提供有一个Solidity语言的在线编译测试工具。http://remix.ethereum.org/#optimize=false&version=soljson-v0.4.23+commit.124ca40d.js 我们以加法和减法运算作为举例,简单说明下整数溢出在Solidity 语言中的常规情况。
编写如下solidity测试代码。
pragma solidity ^0.4.0;
contract C {
// (2**256 - 1) + 1 = 0
function overflow() returns (uint256 _overflow) {
uint256 max = 2**256 - 1;
return max + 1; }
// 0 - 1 = 2**256 - 1
function underflow() returns (uint256 _underflow) {
uint256 min = 0;
return min - 1; }
}
在线测试工具中编译运行结果如下如图3图4。
无奈人生安全网
图3
图4
可以看到uint256当取最大整数值,上溢之后直接回绕返回值为0 , uint256当取0下溢之后直接回绕,返回值为 2^256-1 。这是 solidity中整数溢出场景的常规情况。
3. Solidity中的整数溢出缓解和SafeMath库
为了减少solidity合约开发中产生的安全问题,以太坊的官方开发博客陆续发布了一些与 solidity开发安全相关的博文。在 2017年 8月 6日 单独发过一篇使用SafeMath 库进行整数安全操作的文章> 。详见链接: https://ethereumdev.io/safemath-protect-overflows/
/**
* @title SafeMath
* @dev Math operations with safety checks that throw on error
*/
library SafeMath {
function mul(uint256 a, uint256 b) internal constant returns (uint256) { copyright 无奈人生
uint256 c = a * b;
assert(a == 0 || c / a == b);
return c;
}
function div(uint256 a, uint256 b) internal constant returns (uint256) {
// assert(b > 0); // Solidity automatically throws when dividing by 0
uint256 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return c;
}
function sub(uint256 a, uint256 b) internal constant returns (uint256) {
assert(b
return a - b;
}
function add(uint256 a, uint256 b) internal constant returns (uint256) {
uint256 c = a + b;
无奈人生安全网