Rari Fuse矿池攻击分析

攻击交易:
攻击交易较多选择其一(https://etherscan.io/address/0x6162759edad730152f0df8115c698a42e666157f)
https://etherscan.io/tx/0x254735c6c14e4d338b1cc5bca43aab6b0f395ae06085013b1b2527180d270a31
合约代码:
Comptroller::https://etherscan.io/address/0xe16db319d9da7ce40b666dd2e365a4b8b3c18217#code
dai池:https://etherscan.io/address/0x67db14e73c2dce786b5bbbfa4d010deab4bbfcf9#code
eth池:https://etherscan.io/address/0xd77e28a1b9a9cfe1fc2eee70e391c05d25853cbf#code

分析工具:
https://oko.palkeo.com/0x254735c6c14e4d338b1cc5bca43aab6b0f395ae06085013b1b2527180d270a31/

分析参考文章:
https://twitter.com/Hacxyk/status/1520370421773725698


在eth池中如果调用borrow会调用doTransferOut(borrower, borrowAmount);

 function borrowFresh(address payable borrower, uint borrowAmount) internal returns (uint) {
    
    
 ......
 		doTransferOut(borrower, borrowAmount);

        /* We write the previously calculated values into storage */
        accountBorrows[borrower].principal = vars.accountBorrowsNew;
        accountBorrows[borrower].interestIndex = borrowIndex;
        totalBorrows = vars.totalBorrowsNew;
        .......
        }
function doTransferOut(address payable to, uint amount) internal {
    
    
        // Send the Ether and revert on failure
        (bool success, ) = to.call.value(amount)("");
        require(success, "doTransferOut failed");
    }

会回调到调用者的默认回调函数.之后再更新borrow的值.
如果在回调函数中调用comptroller中的exitMarket函数,(在没更新borrow值时,删除marketToExit.accountMembership[msg.sender]),即可绕过满足borrow的提前条件(质押一定量的其他token)的提取操作的验证操作

function redeemAllowedInternal(address cToken, address redeemer, uint redeemTokens) internal view returns (uint) {
    
    
        if (!markets[cToken].isListed) {
    
    
            return uint(Error.MARKET_NOT_LISTED);
        }

        /* If the redeemer is not 'in' the market, then we can bypass the liquidity check */
        if (!markets[cToken].accountMembership[redeemer]) {
    
    
            return uint(Error.NO_ERROR);  ///*******************在此返回
        }

        /* Otherwise, perform a hypothetical liquidity check to guard against shortfall */
        (Error err, , uint shortfall) = getHypotheticalAccountLiquidityInternal(redeemer, CToken(cToken), redeemTokens, 0);
        if (err != Error.NO_ERROR) {
    
    
            return uint(err);
        }
        if (shortfall > 0) {
    
    
            return uint(Error.INSUFFICIENT_LIQUIDITY);
        }

        return uint(Error.NO_ERROR);
    }

攻击流程:

  1. dai池mint(质押)大量token.
  2. eth池borrow Eth;
    在回调函数中调用(comptroller)exitmarket();

3.调用(dai)redeemUnderlying取回质押的token;

猜你喜欢

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