GET CALL FROM
BLOCKCHAIN SEMANTICS
COUNSELOR
×

Blockchain Semantics Insights


Business Case |  Deep Tech |  Announcements |  Blockchain Glossary | 
Blockchain Semantics Blog Integer Overflow Bugs In ProxyTransfer Smart Contracts

Integer Overflow Bugs In ProxyTransfer Smart Contracts

By Viswanath Kapavarapu | July 18, 2018, 12:11 p.m. GMT

Smart Contracts are always thought to be a valuable addition because “nobody can mess with your contract once it’s been deployed”. However, this is also another way of saying that “bugs cannot be fixed once deployed”.

Programs that cannot be fixed once deployed can be susceptible to a number of attacks; the most popular amongst those attacks being the DAO Attack, Parity Wallet Hack, and the most recent one, the ProxyOverflow bug. In this article, we shall try to explore what went wrong with the ProxyOverflow Contracts.

ProxyTransfer is a new EIP in a process wherein the transaction fees are paid by the users in the form of tokens and not Ether, as opposed to traditional ERC20 contracts. In a traditional ERC20 contract, even if the user has 100 tokens, he cannot simply operate unless he holds some Ether too. However, this doesn’t really make sense as ‘Tokens themselves hold value and to say that tokens can only act in conjunction with Ether makes them unusable to a certain extent’. To fix this, a group of developers introduced a new proposal(EIP-xyz) where users can spend tokens as Transaction Fees. EIP gained a lot of traction that several DApps tried to incorporate, while the proposal itself is reviewed. However, some of those contracts came with an exploit and hidden cost.

Here’s the code snippet that caused the exploit:

/*
 * Proxy transfer MESH.

 * @param _from
 * @param _to
 * @param _value
 * @param feeMesh
 * @param _v
 * @param _r
 * @param _s
 */
function transferProxy(address _from, address _to, uint256 _value, uint256 _feeMesh,
uint8 _v,bytes32 _r, bytes32 _s) public transferAllowed(_from) returns (bool){

if(balances[_from] < _feeMesh + _value) revert();

uint256 nonce = nonces[_from];
bytes32 h = keccak256(_from,_to,_value,_feeMesh,nonce,name);
if(_from != ecrecover(h,_v,_r,_s)) revert();

if(balances[_to] + _value < balances[_to]
|| balances[msg.sender] + _feeMesh < balances[msg.sender]) revert();
balances[_to] += _value;
Transfer(_from, _to, _value);

balances[msg.sender] += _feeMesh;
Transfer(_from, msg.sender, _feeMesh);

balances[_from] -= _value + _feeMesh;
nonces[_from] = nonce +1;
returntrue;
}

_feeMesh and _value are both set by the sender. If variable _value is so large that the sum of _value and _feeMeshreaches the maximum uint value (2^256), the sum will circle back to zero. The sum can thus bypass the sanity check, even if it shouldn’t be doing so. Once it passes the check, a huge number of tokens are transferred to the attacker and the transfer fee shall be borne by msg.sender. This is an example of the IntOverflow bug, but the same theory holds true for underflow too.

ProxyOverflow pattern is found in tokens such as MESH, UGToken, SMT, SMART, MTC, FirstCoin, GG Token, CNY Token, and CNYTokenPlus.

Overflows/Underflows can be avoided using SafeMath practices. safeMath triggers exceptions in case of overflows and underflows.

 

Steps to be followed:

  1. Import the SafeMath library from here.
Use .add(), .sub(), .mul(), .div() instead of direct +, -, *, / operations.
  1. The line balances[_from] < _feeMesh + _value

If implemented using SafeMAth, it would look like:

balances[_from] < _feeMesh.add(_value)

Similar rules apply to other arithmetic operations.

 

ontract SafeProxyTransfer {
using SafeMath for uint;
/*
 * Proxy transfer MESH. When some users of the ethereum account has no ether,
 * he or she can authorize the agent for broadcast transactions, and agents may charge agency fees
 * @param _from
 * @param _to
 * @param _value
 * @param feeMesh
 * @param _v
 * @param _r
 * @param _s
 */
function transferProxy(address _from, address _to, uint256 _value, uint256 _feeMesh,
uint8 _v,bytes32 _r, bytes32 _s) public transferAllowed(_from) returns (bool){

if(balances[_from] < _feeMesh.add(_value)) revert();

uint256 nonce = nonces[_from];
bytes32 h = keccak256(_from,_to,_value,_feeMesh,nonce,name);
if(_from != ecrecover(h,_v,_r,_s)) revert();

if(balances[_to].add(_value) < balances[_to]
|| balances[msg.sender].add(_feeMesh) < balances[msg.sender]) revert();
balances[_to] = balances[_to].add(_value);
Transfer(_from, _to, _value);

balances[msg.sender] = balances[msg.sender].add(_feeMesh);
Transfer(_from, msg.sender, _feeMesh);

balances[_from] = balances[_from].sub(_value.add(_feeMesh));
nonces[_from] = nonce.add(1);
returntrue;
}
}

Follow BlockchainSemantics for more useful information.

If you liked the post, give it a   1
Apply for Blockchain Jobs

Course 1

Introduction to
Blockchain and Bitcoin

Course 2

Developing Decentralized
Applications on Ethereum
Using Solidity

Course 3

Investing In Bitcoin
and Cryptocurrencies

Comments


Be the first to comment.