Tadle

Tadle
DeFiFoundry
27,750 USDC
View results
Submission Details
Severity: high
Valid

The drain vulnerability caused by a logical bug in the withdraw function.

Summary

Crypto Pre-Markets 'Tadle' is a new marketplace where traders and investors can trade tokens and points before their official launch. The vulnerability in question is critical, allowing an attacker to drain the entire capital pool once it accumulates funds from various actions by market participants, such as creating offers or takers.

Vulnerability Details

This vulnerability occurs within the withdraw function described below.

https://gist.github.com/parkttule/3e51d5ce700f4f61694341f1f8175da6

This function can be called by anyone externally, and if a value is assigned to the claimAbleAmount variable, it allows the withdrawal of that amount from the capital pool.

uint256 claimAbleAmount = userTokenBalanceMap[_msgSender()][
_tokenAddress
][_tokenBalanceType];

However, within the function, there is no logic either before or after the withdrawal that resets the balance in the userTokenBalanceMap[_msgSender()][_tokenAddress][_tokenBalanceType] mapping by the amount withdrawn.

if (_tokenAddress == wrappedNativeToken) {
/**
* @dev token is native token
* @dev transfer from capital pool to msg sender
* @dev withdraw native token to token manager contract
* @dev transfer native token to msg sender
*/
_transfer(
wrappedNativeToken,
capitalPoolAddr,
address(this),
claimAbleAmount,
capitalPoolAddr
);
IWrappedNativeToken(wrappedNativeToken).withdraw(claimAbleAmount);
payable(msg.sender).transfer(claimAbleAmount);
} else {
/**
* @dev token is ERC20 token
* @dev transfer from capital pool to msg sender
*/
_safe_transfer_from(
_tokenAddress,
capitalPoolAddr,
_msgSender(),
claimAbleAmount
);
}

By exploiting this, an attacker can manipulate the mapping value as desired during the process of creating an offer and subsequently creating a taker themselves. This allows them to repeatedly call the withdraw function, draining all the funds in the capital pool.

PoC

Below is the Proof of Concept (PoC) code that reflects the attack scenario.

https://gist.github.com/parkttule/ab02d80c01fc69ba868a2478cc1c4050

Based on the test/PreMarkets.t.sol test file, the PoC code has been written, and the attack scenario is as follows:

  • user represents a regular user who, during the process of creating an offer, submits a collateral amount equivalent to 1.2 ether to the capital pool. This step reflects typical usage activity within Tadle.

  • user1 is the attacker. user1 also creates an offer in the same way as a regular user.

  • Subsequently, user1 creates a taker based on their self-created offer and manipulates the tokenmanager mapping value to their desired amount.

  • user1 then creates a taker themselves and proceeds to make unlimited withdrawals based on the manipulated value.

  • The balances of the capital pool and user1 before and after the attack are compared.

Executing this PoC code allows the attacker to drain the balance existing in the capital pool.

Impact

The impact of this attack is significant, as it has the potential to drain all the funds stored in the capital pool, which holds the collateral provided by users. While the current PoC code simplifies the process by minimizing the use of functions and does not drain all the funds, theoretically, an attacker could create offers with multiple accounts and manipulate the claimAbleAmount during the taker creation process. This would allow them to drain the entire capital pool, making it a critical vulnerability.

Tools Used

I have written the PoC code using Foundry.

Recommendations

To address the vulnerability, the following patch should be applied within the withdraw function. This patch ensures that the userTokenBalanceMap[_msgSender()][_tokenAddress][_tokenBalanceType] value is reset by the amount withdrawn. Here's an example of how the code might be updated

https://gist.github.com/parkttule/6af7dab9efc67b579d03339f38ae2f8b

Updates

Lead Judging Commences

0xnevi Lead Judge about 1 year ago
Submission Judgement Published
Validated
Assigned finding tags:

finding-TokenManager-withdraw-userTokenBalanceMap-not-reset

Valid critical severity finding, the lack of clearance of the `userTokenBalanceMap` mapping allows complete draining of the CapitalPool contract. Note: This would require the approval issues highlighted in other issues to be fixed first (i.e. wrong approval address within `_transfer` and lack of approvals within `_safe_transfer_from` during ERC20 withdrawals)

Support

FAQs

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