Wault Finance漏洞分析


攻击信息:

攻击交易:

0x31262f15a5b82999bf8d9d0f7e58dcb1656108e6031a2797b612216a95e1670e

攻击合约:

0x886358f9296de461d12e791bc9ef6f5a03410c64

流程分析:

第一步:

首先通过闪电贷借出16839004个WUSD,调用WUSDMaster合约的redeem函数发送USDT和WEX到攻击合约中。成本大于是 0.015 USDT/WEX。

第二步:

通过闪电贷借入40000000USDT,把其中的23000000usdt换成WEX,算了一下成本,0.044 USDT/WEX。

第三步:

多次通过抵押,拉高wex的价格。

最后一次的价格算出来,1.44 USDT/WEX.

第四步:

 把WEX换成USDT。这时后价格为 0.041 USDT/WEX

第五步:

 还闪电贷。

第六步:

 最后获利,跨链。

代码分析:

 1     function redeem(uint256 amount) external nonReentrant {
 2         uint256 usdtTransferAmount = amount * (1000 - wexPermille - treasuryPermille) / 1000;
 3         uint256 usdtTreasuryAmount = amount * treasuryPermille / 1000;
 4         uint256 wexTransferAmount = wex.balanceOf(address(this)) * amount / wusd.totalSupply();
 5         wusd.burn(msg.sender, amount);
 6         usdt.safeTransfer(treasury, usdtTreasuryAmount);
 7         usdt.safeTransfer(msg.sender, usdtTransferAmount);
 8         wex.safeTransfer(msg.sender, wexTransferAmount);
 9         
10         emit Redeem(msg.sender, amount);
11     }

首先通过调用redeem函数,攻击者可以拿到当前最便宜的wex,然后用闪电贷,借出大量的资金,因为攻击者后面要砸盘,所以说,他用一部分来拉盘(这里指23000000那一笔),然后一部分用来重复抵押换取wex(%10用于把usdt换取wex)这一部分用来填补之前通过闪电贷借出wusd获得的wex和usdt。(相当于帮用户高位接盘)

 1     function stake(uint256 amount) external nonReentrant {
 2         require(amount <= maxStakeAmount, 'amount too high');
 3         usdt.safeTransferFrom(msg.sender, address(this), amount);
 4         if(feePermille > 0) {
 5             uint256 feeAmount = amount * feePermille / 1000;
 6             usdt.safeTransfer(treasury, feeAmount);
 7             amount = amount - feeAmount;
 8         }
 9         uint256 wexAmount = amount * wexPermille / 1000;
10         usdt.approve(address(wswapRouter), wexAmount);
11         wswapRouter.swapExactTokensForTokensSupportingFeeOnTransferTokens(
12             wexAmount,
13             0,
14             swapPath,
15             address(this),
16             block.timestamp
17         );
18         wusd.mint(msg.sender, amount);
19         
20         emit Stake(msg.sender, amount);
21     }