Suspend trading? Technical Analysis of ERC20 Contract Integer Overflow Security Vulnerability Cases (1)

The blockchain brother community, the pioneer of blockchain technology professional Q&A, the gathering place for Chinese blockchain technology enthusiasts

Author: Wu Shouhe, the first author of "Blockchain Development Practice - Key Technologies and Case Analysis of Ethereum", co-author of "Blockchain Development Practice - Key Technologies and Case Analysis of Hyperledger Fabric", Chief Architect of IONChain , HyperLedger core project developer, co-founder of blockchain technology community - Blockchain Brothers. github: https://github.com/gcc2ge

Source: Blockchain Brothers , the first non-profit media community in China focusing on blockchain technology sharing

Original link: http://www.blockchainbrother.com/article/1992

Article release: please title author and source, the copyright belongs to the blockchain brothers


Event recap:

On the morning of April 25, Huobi Pro announced that the SMT project team reported that there were abnormal problems in its transactions early this morning. After preliminary investigation, there were loopholes in the Ethereum smart contract of SMT. Huobi Pro also detected an anomaly with TXID https://etherscan.io/tx/0x0775e55c402281e8ff24cf37d6f2079bf2a768cf7254593287b5f8a0f621fb83. Affected by this, Huobi Pro now decides to suspend the deposit and withdrawal business of all currencies. Subsequently, Huobi Pro issued an announcement saying that the transactions of SMT/USDT, SMT/BTC and SMT/ETH were suspended. In addition, trading platforms such as OKEx and gate.io have also suspended the deposit, withdrawal and trading of SMT. As of the suspension of trading, the price of SMT on Huobi Pro has fallen by nearly 20%.

The direct economic loss of this loophole agent is as high as 100 million yuan, and the indirect negative impact is currently immeasurable. What kind of loophole is this? The generation and solution of this vulnerability will be analyzed in detail below.

Vulnerability Analysis:

SMT and the Meitu BEC token that broke out a few days ago have similar security vulnerabilities - integer overflow, so what is integer overflow, what is the reason for integer overflow, and how can we avoid integer overflow? Next, we take these questions to look at the following content.

Integer overflow

Integer overflow is divided into upward overflow and downward overflow. Other key points about smart contract security are described in detail in "Blockchain Development Practice - Key Technologies and Case Analysis of Ethereum". The following is an interception of integer overflow in this book. You can read the following text to understand: what is integer overflow, what is the reason for integer overflow, and how can we avoid integer overflow? There are answers to these three questions.

The following text is intercepted from "Blockchain Development Practice - Key Technologies and Case Analysis of Ethereum"

 
pragma solidity ^0.4.10;
/**
这是一个测试整数类型上溢和下溢的例子
*/
contract Test{
 // 整数上溢
 //如果uint8 类型的变量达到了它的最大值(255),如果在加上一个大于0的值便会变成0
 function 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
 }
}

With the above theoretical basis, we are looking at an example of transfer to see how to avoid insecure code in our contract:

 
// 存储用户余额信息
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;
}

We should always pay attention to overflow and underflow checks when doing integer operations, especially for smaller numbers such as uint8, uint16, uint24: they are more likely to reach the maximum and minimum values.

case analysis:

Brief Analysis of Integer Security Issues in SMT Contracts

The contract address of SMT is: 0x55F93985431Fc9304077687a35A1BA103dC1e081, the contract code can be viewed by visiting the following URL of etherscan

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

The problematic code of the SMT contract exists in the transferProxy() function, the code is as follows:

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

The analysis of the problems is as follows:

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

The author's modified code is as follows:

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

Transaction sent by attacker:

The following is the address of the transfer transaction sent by the attacker maliciously: https://etherscan.io/tx/0x1abab4c8db9a30e703114528e31dee129a3a758f7f8abc3b6494aad3d304e43f

(Screenshot of the hacker attack transaction log)

A Brief Analysis of Integer Security Issues in BEC Contracts

The contract address of BEC is 0xC5d105E63711398aF9bbff092d4B6769C82F793D. The contract code can be viewed by visiting the following URL of etherscan https://etherscan.io/address/0xc5d105e63711398af9bbff092d4b6769c82f793d#code

The problematic code of the BEC contract exists in the batchTransfer() function, the code is as follows:

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

The problem code analysis is as follows:

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

Transaction sent by attacker:

The following is the transfer transaction sent by the attacker maliciously:

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

(Screenshot of the hacker attack transaction log)

Summary of Contract Integer Vulnerability Events

From the above analysis, we can see that the contract malicious attacks against SMT and BEC bypass the conditional check through malicious integer overflow. At present, there are thousands of contracts running on Ethereum, and there may be similar security risks in these thousands of contracts, so the developers of the contracts need to invest more energy to ensure the security of the contracts.

In the next article, we will introduce in detail how to properly ensure the security of the contract, so stay tuned.

The article is published only to share the technical content of the blockchain, and the copyright belongs to the original author. The opinions only represent the author himself, and do not mean that the blockchain brothers agree with their views or confirm their descriptions

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324972982&siteId=291194637