The functions claimAllRewards and claimSingleReward are vulnerable to reentrancy attacks due to improper state management, allowing an attacker to repeatedly drain the contract's funds.
The reentrancy vulnerability arises from the fact that both claimAllRewards and claimSingleReward make external calls to the sender before updating the contract’s state. Specifically, the external call is made using the low level call to send ETH to the user, which can invoke a fallback function in a malicious contract, allowing the attacker to reenter the contract and repeatedly drain funds.
In both functions, the external call to msg.sender occurs before the state update (delete rewardsOwned[msg.sender] or delete rewardsOwned[msg.sender][_index]). This means that the external call could reenter the contract before the user's rewards are deleted, allowing them to claim rewards multiple times.
The attacker can reenter the contract during the external call and repeatedly claim rewards before the contract updates its internal state. This could result in the complete depletion of the contract's funds if not mitigated.
This is an example of the malicious contract:
The attacker starts by calling the buyBox function and sending 0.1 ETH.
The attacker then calls openBox. If a reward is assigned (25% chance), they proceed to claim it.
When claimSingleReward is called, the reward is transferred to the malicious contract.
The fallback function is triggered, and claimSingleReward is called again in a loop until the contract's balance is drained.
A similar exploit can be used against the claimAllRewards function.
Manual inspection.
The contract should implement the CEI (Checks Effects Interactions) pattern and update the state variables before the call to an external address is made.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.