Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Contract can be re-used under certain conditions #166

Closed
code423n4 opened this issue Dec 15, 2022 · 3 comments
Closed

Contract can be re-used under certain conditions #166

code423n4 opened this issue Dec 15, 2022 · 3 comments
Labels
3 (High Risk) Assets can be stolen/lost/compromised directly bug Something isn't working duplicate-146 satisfactory satisfies C4 submission criteria; eligible for awards upgraded by judge Original issue severity upgraded from QA/Gas by judge

Comments

@code423n4
Copy link
Contributor

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

Recommended Mitigation Steps

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()

@code423n4 code423n4 added 2 (Med Risk) Assets not at direct risk, but function/availability of the protocol could be impacted or leak value bug Something isn't working labels Dec 15, 2022
code423n4 added a commit that referenced this issue Dec 15, 2022
@c4-judge
Copy link
Contributor

gzeon-c4 marked the issue as duplicate of #146

@c4-judge
Copy link
Contributor

gzeon-c4 marked the issue as satisfactory

@c4-judge c4-judge added the satisfactory satisfies C4 submission criteria; eligible for awards label Dec 17, 2022
@c4-judge c4-judge added 3 (High Risk) Assets can be stolen/lost/compromised directly upgraded by judge Original issue severity upgraded from QA/Gas by judge and removed 2 (Med Risk) Assets not at direct risk, but function/availability of the protocol could be impacted or leak value labels Jan 23, 2023
@c4-judge
Copy link
Contributor

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
3 (High Risk) Assets can be stolen/lost/compromised directly bug Something isn't working duplicate-146 satisfactory satisfies C4 submission criteria; eligible for awards upgraded by judge Original issue severity upgraded from QA/Gas by judge
Projects
None yet
Development

No branches or pull requests

2 participants