Forgeries contest - carrotsmuggler's results

A protocol for on-chain games with NFT prizes on Ethereum.

General Information

Platform: Code4rena

Start Date: 13/12/2022

Pot Size: $36,500 USDC

Total HM: 5

Participants: 77

Period: 3 days

Judge: gzeon

Total Solo HM: 1

Id: 191

League: ETH

Forgeries

Findings Distribution

Researcher Performance

Rank: 68/77

Findings: 1

Award: $19.22

🌟 Selected for report: 0

🚀 Solo Findings: 0

Awards

19.2206 USDC - $19.22

Labels

bug
3 (High Risk)
satisfactory
upgraded by judge
duplicate-146

External Links

Lines of code

https://github.com/code-423n4/2022-12-forgeries/blob/fc271cf20c05ce857d967728edfb368c58881d85/src/VRFNFTRandomDraw.sol#L304-L320

Vulnerability details

Impact

The contract isn't designed to be used multiple times. However, under certain conditions the admin can start and stop the lottery at will, denying some winners the prize if they chose to do so. This can be done using lastResortTimelockOwnerClaimNFT() and redraw() functions. This is problematic since the contract can be used outside of its designed purpose as shown in the POC.

Proof of Concept

Assume the conditions to call lastResortTimelockOwnerClaimNFT() are satisfied. This can be easily done by creating the lottery and waiting until the time specified in settings.recoverTimelock. This is also satisfied if the lottery simply has been going on for a long time (users not claiming, winning token is burnt/not minted, etc)

  1. Run function reroll() as admin
  2. Wait for winner (VRF callback)
  3. Admin doesn't like winner, so admin calls lastResortTimelockOwnerClaimNFT() to remove the NFT
  4. Waits settings.drawBufferTime seconds. Then transfers NFT back to lottery with transferFrom and calls reroll()
  5. reroll() passes all checks since the lottery is the owner of the NFT again. Rerolls the winner denying the last winner

Similar behavior can also be observed after removing NFT with winnerClaimNFT(), transferring it and reroll()

Tools Used

Manual Review

Consider destroying the contract once done. Implement a function

function _end () internal {
    // event End();
    emit End();
    selfdestruct(owner);    
}

Call this function after the NFT is transferred out either via lastResortTimelockOwnerClaimNFT() or via winnerClaimNFT()

#0 - c4-judge

2022-12-17T12:47:18Z

gzeon-c4 marked the issue as duplicate of #146

#1 - c4-judge

2022-12-17T12:47:27Z

gzeon-c4 marked the issue as satisfactory

#2 - c4-judge

2023-01-23T17:09:34Z

gzeon-c4 changed the severity to 3 (High Risk)

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