XDEFI contest - kenzo's results

The fastest wallet in DeFi.

General Information

Platform: Code4rena

Start Date: 04/01/2022

Pot Size: $25,000 USDC

Total HM: 3

Participants: 40

Period: 3 days

Judge: Ivo Georgiev

Total Solo HM: 1

Id: 75

League: ETH

XDEFI

Findings Distribution

Researcher Performance

Rank: 5/40

Findings: 3

Award: $939.38

🌟 Selected for report: 0

πŸš€ Solo Findings: 0

Findings Information

🌟 Selected for report: cccz

Also found by: Fitraldys, cmichel, kenzo, onewayfunction, tqts

Labels

bug
duplicate
3 (High Risk)
sponsor confirmed

Awards

768.967 USDC - $768.97

External Links

Handle

kenzo

Vulnerability details

The lock function calls safeMint in the midst of it. This can lead to reentry to updateDistribution, thereby ruining contract invariants.

Impact

At worst case, loss of user funds: distributableXDEFI will be set to be bigger than it really is, and so when a legitimate user will try to unlock his tokens, the tx will fail because the contract will try sending the user rewards which the contract does not have. There might be other ways to exploit the reentrancy but I believe this simple example is enough to show that this is a high risk issue.

Proof of Concept

lock function safeMints to a user before totalDepositedXDEFI has been updated. (Code ref) The user can craft a contract that upon receiving the NFT, will call updateDistribution. Since totalDepositedXDEFI has not been updated yet, _updateXDEFIBalance will think that the deposit is a reward deposit, not a lock deposit. It will update distributableXDEFI as if there is XDEFI to distribute: [(Code ref])()

uint256 currentDistributableXDEFI = distributableXDEFI = IERC20(XDEFI).balanceOf(address(this)) - totalDepositedXDEFI;

So when a user will try to withdraw his funds, the contract will try to reward him with funds that are either aren't his or aren't in the contract at all. Additionally, this line might underflow further on.

Here is a simple POC scenario:

  • User 1 locks 10 tokens for 1 day
  • Exploiter creates a contract that upon receiving of NFT, will call updateDistribution
  • Exploiter uses the contract to deposit 10 tokens for 1 day. Contract calls updateDistribution.
  • One day passes
  • Exploiter unlocks his tokens
  • User 1 can not unlock his tokens now I've created a POC for this scenario. Create LockReenter.sol in the contracts directory, and add the test to XDEFIDistribution.js. POC

Move the safeMint to the end of lock function. Additionally, you can add a nonReenter modifier on updateDistribution.

#0 - deluca-mike

2022-01-09T05:28:19Z

Valid and duplicate of #25

Findings Information

🌟 Selected for report: leastwood

Also found by: MaCree, WatchPug, cmichel, egjlmn1, kenzo, onewayfunction, sirhashalot

Labels

bug
duplicate
2 (Med Risk)
sponsor confirmed

Awards

140.1442 USDC - $140.14

External Links

Handle

kenzo

Vulnerability details

Token IDs are defined as concatenation of points, total supply + 1. The total supply can decrease when merging. This means that the contract might try to mint a token with an ID which already exists.

Impact

Under specific circumstances, users won't be able to lock or merge tokens.

Proof of Concept

The merge function calls _burn, which decreases the total supply. When generating a new NFT, it's id is determined in _generateNewTokenId using only it's points and current total supply: (Code ref)

function _generateNewTokenId(uint256 points_) internal view returns (uint256 tokenId_) { return (points_ << uint256(128)) + uint128(totalSupply() + 1); }

Since the totalSupply will decrease after merge has called _burn, the contract might try to mint an ID which already exists.

Here is one example scenario:

  • User 1 locks 10 tokens for 1 day (NFT1)
  • User 1 locks 10 tokens for 1 day (NFT2)
  • User 2 locks 10 tokens for 2 days (NFT3)
  • User 3 locks 10 tokens for 2 days (NFT4)
  • One day passes
  • User 1 unlocks NFTs 1,2
  • User 1 tries to merge NFTs 1,2. At this point the merge function will burn the NFTs and decrease total supply back to 2. It will then try to mint a new NFT, with points that will equal NFT3's points, and since the total supply is 2, the totalSupply+1 portion will be 3 - same as NFT3. Therefore, the mint will revert since the token already exists.

Similarly, the lock function might fail when trying to mint a new token after the supply has decreased.

I've created a test POC for the first example. Add it to XDEFIDistribution.js to see it fails. POC

Probably do not use totalSupply for the IDs, but save a different counter which never decreases and use it.

#0 - deluca-mike

2022-01-09T05:05:55Z

Valid and duplicate of #17

Findings Information

🌟 Selected for report: leastwood

Also found by: StErMi, WatchPug, cmichel, danb, egjlmn1, gpersoon, hack3r-0m, harleythedog, kenzo

Labels

bug
duplicate
1 (Low Risk)
disagree with severity
sponsor acknowledged

Awards

30.2712 USDC - $30.27

External Links

Handle

kenzo

Vulnerability details

Since unlock updates distributableXDEFI without updating _pointsPerUnit, if unlock is called in the gap between when a funder is sending rewards to the contract and between somebody calling updateDistribution, the rewards will be lost.

Impact

Loss of rewards.

Proof of Concept

updateDistribution calls _updateXDEFIBalance, which updates distributableXDEFI , to calculate the addition needed to _pointsPerUnit . [(Code ref])(https://github.com/XDeFi-tech/xdefi-distribution/blob/master/contracts/XDEFIDistribution.sol#L147:#L151)

unlock calls _updateXDEFIBalance without updating _pointsPerUnit (rightfully).

But this means that if somebody calls unlock, after rewards have been sent and before updateDistribution has been called, the contract will update distributableXDEFI to be up to date without correspondingly updating _pointsPerUnit. Therefore the rewards will be lost.

I've created a simple POC to demonstrate this. Insert the test to XDEFIDistribution.js to see it fails. POC

Consider changing updateDistribution() functionality to be atomic - so pull the funds from the sender using transferFrom and\or using permit.

#0 - deluca-mike

2022-01-09T06:20:14Z

Technically valid, but this was expected, and we disagree with severity, as explained in the duplicate issue #30.

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax Β© 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter