29204 - [SC - Critical] Direct theft of Users VestedZeroNFT by using sp...

Direct theft of User's VestedZeroNFT by using split function to mint a new NFT to take most fraction of the theft NFT of other users

Submitted on Mar 10th 2024 at 16:23:41 UTC by @perseverance for Boost | ZeroLend

Report ID: #29204

Report type: Smart Contract

Report severity: Critical

Target: https://github.com/zerolend/governance

Impacts:

  • Direct theft of any user NFTs, whether at-rest or in-motion, other than unclaimed royalties

Description

Description

Direct theft of User's VestedZeroNFT by using split function to mint a new NFT to take most fraction of the theft NFT of other users

Brief/Intro

VestedZeroNFT is a NFT based contract to hold all the user vests. NFTs can be traded on secondary marketplaces like Opensea, can be split into smaller chunks to allow for smaller otc deals to happen in secondary markets.

When mint a NFT tokenIT for a user, the function mint() can be used

https://github.com/zerolend/governance/blob/main/contracts/vesting/VestedZeroNFT.sol#L63-L72

The VestedZeroNFT has the split functionality to split a existed tokenID to mint a new tokenID

https://github.com/zerolend/governance/blob/main/contracts/vesting/VestedZeroNFT.sol#L230-L273

The intended purpose is that this allows the owner of the tokenID to split and mint a new tokenID from a fraction of the current tokenID.

Vulnerability Details

The vulnerability is this function does not check the msg.sender is the owner of the tokenID. The only check is:

This check is from ERC721Upgradeable contract. https://github.com/OpenZeppelin/openzeppelin-contracts-upgradeable/blob/master/contracts/token/ERC721/ERC721Upgradeable.sol#L477-L483

So the function just checks that the owner is not zero.

So the attacker can use this function to steal most fraction of the VestedZeroNFT tokenID.

The attacker can call

For the tokenID, the attacker can use any existed tokenID.

The fraction is 1 to steal most of current tokenID to mint a new tokenID for the attacker.

For example, if Ant has a tokenID for example = 2 that: pending = 10_000 * 10**18

After the hack, The tokenID = 2 pending = 1 * 10**18

The hacker new minted tokenID has

pending = 9999 * 10** 18

So 99.99% amount of pending of Ant's tokenID was stolen by the attacker.

The attacker can steal from tokenID of any owner, including the StakingBonus contract.

Impacts

About the severity assessment

So the bug allow attackers to steal the VestedZeroNFT token of users. So the Severity is Critical with Category: Direct theft of any user NFTs, whether at-rest or in-motion, other than unclaimed royalties

Proof of Concept

Test code POC:

In the above POC, to execute the attack, the hacker call the split function

Test log: Full Test Log: https://drive.google.com/file/d/1uQI10CD-J9HB4KweMPAlMUj19OEzadk0/view?usp=sharing

Test Log explanation:

So Pre-condition: Ant has 1 VestedZeroNFT with id = 2 The tokenIdToLockDetails information for this tokenID

This means pending = 10 000 * 10 **18

After the attack, The tokenIdToLockDetails information for this tokenID

So the pending is 1 * 10 **18

The attacker now has a tokenID = 3 with information

The pending = 9999 * 10 ** 18

To run the POC,

Step 1: First clone the governance repository:

Step2: Apply Git patch file

Bug5_diff.patch link: https://drive.google.com/file/d/1lsQmql7Bg4OAaSJJkK9_PD0Is1HyLqPV/view?usp=sharing

Apply the Patch by Git command using Git bash shell

Step 3: Input .env variables

cd to folder governance, To run the test, you need to

  1. rename .env.example to .env

  2. put the test Private_key to the variable

Step 4: Install and run test Run command

Last updated

Was this helpful?