XSDWETHpool Hack Reply

  • bixia1994
  • 更新于 2023-10-04 16:35
  • 阅读 1293

Hack事件简介项目方在BSC上的XSD-WBNB池子被黑客攻击

Hack事件简介

项目方在BSC上的XSD-WBNB 池子被黑客攻击, 攻击交易为: https://bscscan.com/tx/0xbdf76f22c41fe212f07e24ca7266d436ef4517dc1395077fabf8125ebe304442 整个的攻击思路可以梳理如下:

  1. 从DODO中flashloan出4000 ether的WBNB
  2. 调用XSD项目方的router合约, 调用其swapXSDForETH方法, 将39,566.238265722260955438个XSD兑换成9.84 etehr的BNB
  3. 在fallback函数中, 直接调用XSD-WBNB的swap方法, 将3800 ether的BNB兑换成XSD
  4. 在fallback函数中, 调用PIDController的systemCalculations方法 (即: refreshPID)
  5. 在fallback函数中, 重入router的swapETHForXSD方法, 将0.00001 ether的BNB兑换成100 ether的XSD
  6. 然后利用重入后的router函数,直接burnPoolXSD, 将XSD-WBNB池子中的XSD burn掉3956623826572226095543, 此时池子中的XSD价格极度偏高
  7. 在router调用结束后, 将手中由3800 etherBNB swap得到的XSD, 全部dump到XSD-WBNB池子中, 得到3857 ether的BNB
  8. 偿还3800 ether的BNB的债务, 得到57 BNB的利润

核心漏洞逻辑

XSD-WBNB pool: 基本上是一个UniV2的仿盘 rotuer中的swapXSDForETH函数中,

  1. 没有non-reentrant防止重入
  2. 存在XSD.burnpoolXSD的逻辑, 可以将池子中的XSD销毁, 从而拉偏池子的价格
    //approve router to use users xsd
    //burn 10% of XSD when uXSD is +ve
    function swapXSDForETH(uint amountOut, uint amountInMax)
        external
        override
    {
        require(!swap_paused, "Swaps have been paused");
        (uint reserveA, uint reserveB, ) = IXSDWETHpool(XSDWETH_pool_address).getReserves();
        uint amounts = BankXLibrary.quote(amountOut, reserveB, reserveA);
        require(amounts <= amountInMax, 'BankXRouter: EXCESSIVE_INPUT_AMOUNT');
        TransferHelper.safeTransferFrom(
            xsd_address, msg.sender, XSDWETH_pool_address, amountInMax
        );
        XSDWETHpool(XSDWETH_pool_address).swap(0, amountOut, address(this));
        //function will fail if conditions are not met
        //XSDWETHpool(XSDWETH_pool_address).flush();
        IWBNB(WETH).withdraw(amountOut);
        TransferHelper.safeTransferETH(msg.sender, amountOut);
        //burn xsd here 
        //value of xsd liquidity pool has to be greater than 20% of the total xsd value
        if(XSD.totalSupply()-CollateralPool(payable(collateral_pool_address)).collat_XSD()>amountOut/10 && !pid_controller.bucket1()){
            XSD.burnpoolXSD(amountInMax/10);
        }
        refreshPID();
    }

    疑惑点

    refershPID()里面的逻辑是什么

    function refreshPID() internal{
        if(block.timestamp>(last_called+pid_cooldown)){
            pid_controller.systemCalculations();
            last_called = block.timestamp;
        }
    }

    pid_controller: https://bscscan.com/address/0x82a6405B9C38Eb1d012c7B06642dcb3D7792981B#code 初步看, systemCalculations函数里:

  3. 通过XSD-WBNB pool的reserve0/ reserve1 算出 xsd的price, 即spot price
  4. 根据xsd的price更新xsd的抵押率

通过拉高xsd的spot price改变collat_xsd的值, 使其能通过if条件的检查.

思路整理

router的swapXSDForETH函数中,存在XSD.burnpoolXSD的逻辑, 也就意味着可以通过这个函数去额外的burn掉池子中的XSD, 从而拉偏XSD的价格. 最简单的思路是 swapETHforXSD得到XSD, 然后burn掉池子中的XSD, 然后sync, 最后把XSD dump到池子里swap成ETH. 这里的挑战是burn池子的XSD这个逻辑在swapXSDForETH中, 希望能够burn掉尽可能多的XSD,但是不通过swap移动曲线. 幸运的是, swapXSDForETH中, 首先完成swap, 然后把ETH打出, 最后才是burn XSD. 我们可以在ETH打出后的fallback函数里, 将简单思路的逻辑插入执行. 于是整体思路变成:

  1. 调用router的swapXSDForETH
  2. 在ETH的fallback中, swapETHForXSD, 拉高XSD的价格
  3. 继续执行router的swapXSDForETH逻辑, burn掉pool里的XSD
  4. 在外侧dump XSD for ETH获利.

这里为了能够顺利进入到burn逻辑里, 在fallback函数中额外执行了pid_controller.systemCalculations();操作.

  • 原创
  • 学分: 7
  • 分类: 安全
  • 标签:
点赞 1
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
bixia1994
bixia1994
0x92Fb...C666
learn to code