- Type: Exploit
- Network: Binance Smart Chain
- Total lost: 35K
- Category: Price manipulation
- Vulnerable contracts:
- Attack transactions:
- Attacker Addresses:
- Attack Block:: 22629432
- Date: Oct 30, 2022
- Reproduce:
forge test --match-contract Exploit_BVaults -vvv
- Create a malicious token and pair
- Inflate its price
- Call convertDustToEarned
- Swap again
- Cashout and repeat
This attack relies on the fack that BVault provided a convertDustToEarned
method that would swap all of the tokens in the pool to "earned" tokens.
Unfortunately, it did not do any kind of price check or use any kind of smoothing of the price curve. This makes it vulnerable to price inflation: the attacker created a malicious token and pair, inflated the price of the token in the pool and then used it to gain earnedTokens
.
function convertDustToEarned() public whenNotPaused {
require(isAutoComp, "!isAutoComp");
// Converts dust tokens into earned tokens, which will be reinvested on the next earn().
// Converts token0 dust (if any) to earned tokens
uint256 _token0Amt = IERC20(token0Address).balanceOf(address(this));
if (token0Address != earnedAddress && _token0Amt > 0) {
_vswapSwapToken(token0Address, earnedAddress, _token0Amt);
}
// Converts token1 dust (if any) to earned tokens
uint256 _token1Amt = IERC20(token1Address).balanceOf(address(this));
if (token1Address != earnedAddress && _token1Amt > 0) {
_vswapSwapToken(token1Address, earnedAddress, _token1Amt);
}
}
function _vswapSwapToken(address _inputToken, address _outputToken, uint256 _amount) internal {
IERC20(_inputToken).safeIncreaseAllowance(vswapRouterAddress, _amount);
IValueLiquidRouter(vswapRouterAddress).swapExactTokensForTokens(_inputToken, _outputToken, _amount, 1, vswapPaths[_inputToken][_outputToken], address(this), now.add(1800));
}
- Either introduce an oracle to get a second-source of truth for prices or use time-weighted-average to smooth the curve.