赞
踩
2022年3月13日,Paraluni合约遭受攻击,损失约170万美元
攻击交易:https://bscscan.com/tx/0xd0b4a1d4964cec578516bd3a2fcb6d46cadefe1fea5a2f18eec4c0a496e696f9
合约代码:
MasterChef:https://bscscan.com/address/0xa386f30853a7eb7e6a25ec8389337a5c6973421d#code
ParaRouter:https://bscscan.com/address/0x48bb5f07e78f32ac7039366533d620c72c389797#code
MasterChef合约中函数depositByAddLiquidity
允许将池pid,与任意token(2ge)地址传递,并在收取token后记录当前pid对应lptoken数量后调用paraRouter.addLiquidity
将用户传入token(2个)加入池中,计算lptoken的数量差值后记录用户对应的lptoken数量,但合约并没有设置防重入.
function depositByAddLiquidity(uint256 _pid, address[2] memory _tokens, uint256[2] memory _amounts) external{ require(_amounts[0] > 0 && _amounts[1] > 0, "!0"); address[2] memory tokens; uint256[2] memory amounts; (tokens[0], amounts[0]) = _doTransferIn(msg.sender, _tokens[0], _amounts[0]); (tokens[1], amounts[1]) = _doTransferIn(msg.sender, _tokens[1], _amounts[1]); depositByAddLiquidityInternal(msg.sender, _pid, tokens,amounts); } function depositByAddLiquidityInternal(address _user, uint256 _pid, address[2] memory _tokens, uint256[2] memory _amounts) internal { PoolInfo memory pool = poolInfo[_pid]; require(address(pool.ticket) == address(0), "T:E"); uint liquidity = addLiquidityInternal(address(pool.lpToken), _user, _tokens, _amounts); _deposit(_pid, liquidity, _user); } function addLiquidityInternal(address _lpAddress, address _user, address[2] memory _tokens, uint256[2] memory _amounts) internal returns (uint){ //Stack too deep, try removing local variables DepositVars memory vars; approveIfNeeded(_tokens[0], address(paraRouter), _amounts[0]); approveIfNeeded(_tokens[1], address(paraRouter), _amounts[1]); vars.oldBalance = IERC20(_lpAddress).balanceOf(address(this)); (vars.amountA, vars.amountB, vars.liquidity) = paraRouter.addLiquidity(_tokens[0], _tokens[1], _amounts[0], _amounts[1], 1, 1, address(this), block.timestamp + 600); vars.newBalance = IERC20(_lpAddress).balanceOf(address(this)); require(vars.newBalance > vars.oldBalance, "B:E"); vars.liquidity = vars.newBalance.sub(vars.oldBalance); addChange(_user, _tokens[0], _amounts[0].sub(vars.amountA)); addChange(_user, _tokens[1], _amounts[1].sub(vars.amountB)); return vars.liquidity; }
而且token地址由用户传入,所以如果传入用户自己生成的合约,并且再transfer函数中重入调用影响IERC20(_lpAddress).balanceOf(address(this))
的功能(如deposit
,depositByAddLiquidity
)就能使用户对应的lptoken数量加多倍,最后通过提取lptoken,移除流动性完成攻击.
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。