Paraluni合约攻击学习

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,移除流动性完成攻击.

猜你喜欢

转载自blog.csdn.net/Timmbe/article/details/124654682
今日推荐