• 【漏洞分析】DoughFina 攻击事件分析:不做任何参数检查的去杠杆合约


    背景介绍

    2024 年 7 月 12 日,DoughFina 协议遭受了黑客攻击,造成本次攻击的主要原因是 ConnectorDeleverageParaswap 合约没有对输入参数进行检查,且该合约为 DSA 合约的 owner。攻击者可以构造恶意参数窃取 DSA 合约的资金。

    攻击交易
    https://app.blocksec.com/explorer/tx/eth/0x92cdcc732eebf47200ea56123716e337f6ef7d5ad714a2295794fdc6031ebb2e

    相关合约

    • DSA(被攻击地址):0x534a
      在 AAVE V3 上质押了 596 WETH,借出了 938566 USDC
    • 攻击合约:0x11a8
    • ConnectorDeleverageParaswap:0x9f54e8eaa9658316bb8006e03fff1cb191aafbe6
      通过闪电贷协助 DSA 降低在 AAVE V3 上的杠杆。

    攻击交易分析

    这个章节我们先尝试从 trace 来定位漏洞的位置。

    通过对这笔交易进行一个大概的观察,如下图所示,攻击者在发起攻击之前,先利用闪电贷的资金帮 0x534a 归还了他的借款 938566 USDC,其他部分都是常规的操作,其中需要深入调查的就是 0x11a8 调用 ConnectorDeleverageParaswap.flashloanReq 函数的过程。

    ConnectorDeleverageParaswap.flashloanReq 函数

    我们看到在 ConnectorDeleverageParaswap.flashloanReq 函数中,会调用 POOL.flashLoan

    POOL.flashLoan 执行一个常规的闪电贷流程

    1. ConnectorDeleverageParaswap 合约从闪电贷获取 5 USDC
    2. 调用 ConnectorDeleverageParaswap.executeOperation 函数
    3. 归还 5.025 USDC
    4. handleRepayment

    继续跟进到 ConnectorDeleverageParaswap.executeOperation 函数,可以看到它对传入的参数进行解析后直接调用 deloopInOneOrMultipleTransactions 函数

    deloopInOneOrMultipleTransactions 函数进行分析

    function deloopInOneOrMultipleTransactions(bool opt, address _dsaAddress, address[] memory assets, uint256[] memory amounts, uint256[] memory premiums, address[] memory collateralTokens, uint256[] memory collateralAmounts, bytes[] memory multiTokenSwapData) private {
        // Repay all flashloan assets or withdraw all collaterals
        // 使用闪电贷获得的资金来偿还用户在 Aave 上的债务。
        repayAllDebtAssetsWithFlashLoan(opt, _dsaAddress, assets, amounts);
    
        // Extract all collaterals
        // 从用户的 DSA 中提取指定数量的抵押品。
        extractAllCollaterals(_dsaAddress, collateralTokens, collateralAmounts);
    
        // Deloop all collaterals
        // 使用 Paraswap 将提取的抵押品换成债务代币
        deloopAllCollaterals(multiTokenSwapData);
    
        // Repay all flashloan assets or withdraw all collaterals
        // 偿还闪电贷,然后将剩余的资金存回 Aave 或转移到金库
        repayFlashloansAndTransferToTreasury(opt, _dsaAddress, assets, amounts, premiums);
    }
    

    不过在查看 ConnectorDeleverageParaswap.executeOperation 函数的执行 trace 时,发现 Phalcon 把调用的四个函数混在一起了不好分辨。

    根据转移的金额确定攻击发生的位置,猜测这笔 WETH 的转账与漏洞的利用有关。

    所以通过单步调试的方式来检查发生了什么。
    执行到 ConnectorDeleverageParaswap.deloopAllCollaterals 函数中时,对传入的 multiTokenSwapData 参数进行解析,得到对应的参数: flashloanVars.srcToken, flashloanVars.destToken, flashloanVars.srcAmount, flashloanVars.destAmount, flashloanVars.paraSwapContract, flashloanVars.tokenTransferProxy, flashloanVars.paraswapCallData

    其中 paraSwapContract(out4)对应的地址为 WETH 的合约地址(0xc02a),而不是进行 swap 的合约地址。

    当执行到 paraSwapContract.call 部分的函数时,由于 paraSwapContract 的地址已被替换为 WETH9 的地址,且 paraswapCallData 为攻击者构造的转账 calldata,所以实际执行的是 WETH 的转账操作

    function deloopAllCollaterals(bytes[] memory multiTokenSwapData) private {
        FlashloanVars memory flashloanVars;
    
        for (uint i = 0; i < multiTokenSwapData.length;) {
            // Deloop
            (flashloanVars.srcToken, flashloanVars.destToken, flashloanVars.srcAmount, flashloanVars.destAmount, flashloanVars.paraSwapContract, flashloanVars.tokenTransferProxy, flashloanVars.paraswapCallData) = _getParaswapData(multiTokenSwapData[i]);
    
            // using ParaSwap
            IERC20(flashloanVars.srcToken).safeIncreaseAllowance(flashloanVars.tokenTransferProxy, flashloanVars.srcAmount);
            (flashloanVars.sent, ) = flashloanVars.paraSwapContract.call(flashloanVars.paraswapCallData);
            if (!flashloanVars.sent) revert CustomError("ParaSwap deloop failed");
    
            unchecked { i++; }
        }
    }
    
    

    deloopInOneOrMultipleTransactions 函数分析

    已经定位到了漏洞发生的位置,接下来就根据 trace 分析 deloopInOneOrMultipleTransactions 函数对四个函数的调用情况

    1. repayAllDebtAssetsWithFlashLoan

      替 0x11a8 账户归还 5 USDC 的借款

    2. extractAllCollaterals

      传入空数组,跳过这函数的逻辑

    3. deloopAllCollaterals

      由于没有进行参数检查,攻击者在这个函数中构造了两个恶意的调用来获利。

      1. 第一个 for 循环:调用 0x534a.executeAction 把 5 USDC 兑换成 596 WETH,并且 approve 给 ConnectorDeleverageParaswap 合约

      2. 第二个 for 循环:把 596 WETH 转移到攻击者控制的 0x11a8 地址

    4. repayFlashloansAndTransferToTreasury

      提供 0.9 USDC 给 0x11a8 的 AAVE 账户

    攻击流程分析

    本次攻击是围绕降低 0x11a8 账户在 AAVE V3 上的杠杆而展开的,由于这个函数没有对传入的参数进行检查,所以攻击者构造了恶意的 multiTokenSwapData 参数在 deloopAllCollaterals 函数中对 0x534a 的 AVVE 资金进行转移。

    攻击者构造恶意的 data 参数,解析出恶意的 multiTokenSwapData 参数

    恶意的 multiTokenSwapData 参数传入到 deloopAllCollaterals 函数中

    恶意的 multiTokenSwapData 参数解析出恶意的 paraSwapContractparaswapCallData,导致了任意执行。

    后记

    第一次分析这个类型的攻击事件,感觉攻击事件还是得多分析,多积累积累经验,扩展自己的视野。好好看好好学吧,之前对项目类型的接触和理解上都有很大的局限,还是需要多接触一下目前经典的、热门的项目有利于提高自己的水平,跟上市场的步伐。继续干呗,这事儿只能靠慢慢积累起来的。


    __EOF__

  • 本文作者: ACai's Blog
  • 本文链接: https://www.cnblogs.com/acaigarden/p/18304048
  • 关于博主: 评论和私信会在第一时间回复。或者直接私信我。
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
  • 声援博主: 如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。
  • 相关阅读:
    pdf转jpg的方法【ps和工具方法】
    【数据结构】图的应用:最小生成树;最短路径;有向无环图描述表达式;拓扑排序;逆拓扑排序;关键路径
    一次单据图片处理的优化实践 | 京东物流技术团队
    【math】利用Cardano方法对一元三次方程求解及python实现
    【Darknet版YOLOv3&YOLOv4模型训练】
    关于React
    20221121 今天的世界发生了什么
    艾美捷SequENZ测序级改造型胰蛋白酶特异性和应用
    OceanBase 4.0 - 从分布式到单机,从单机到分布式
    Unity 编辑器资源导入处理函数 OnPreprocessTexture:深入解析与实用案例
  • 原文地址:https://www.cnblogs.com/ACaiGarden/p/18304048