The balance check in the PuppyRaffle::withdrawFees function could enable griefer to self-destruct a contract to send ETH to the raffle and blocking withdrawals.
The require statement in the withdrawFees() function checks that the contract's balance is equal to the totalFees and then allow the withdraw. But the malicious user can exploit the function, makes the require statement to revert and blocks the withdrawals.
The balance check in the withdrawFees function is crucial to prevent unauthorized withdrawals. It's a mechanism to ensure that the contract's balance matches the totalFees before allowing the withdrawal. However, it can be exploited by a malicious actor (griefer) in the following way.
A griefer can deploy a contract that includes a selfdestruct() function. The selfdestruct() function can be set to destroy the contract and send all of its Ether to the PuppyRaffle contract when a certain condition is met.
A griefer can trigger the selfdestruct function, the griefer can call the withdrawFees() function from the PuppyRaffle contract. Since the PuppyRaffle contract checks if the balance equals the totalFees before allowing the withdrawal, the balance check will pass, and the fees will be withdrawn.
When the griefer's contract is destroyed and sends all its Ether to the PuppyRaffle contract, the withdrawFees() function will fail because the contract balance no longer matches the totalFees. This effectively blocks any future withdrawals from the PuppyRaffle contract.
Here is an example of how a griefer contract might look like:
In this contract, the triggerSelfDestruct() function transfers all of the contract's Ether to the PuppyRaffle contract and then destroys the contract. When the PuppyRaffle contract receives the Ether, it will try to withdraw the fees, but the balance check will fail because the contract's balance no longer matches the totalFees. This effectively blocks any future withdrawals from the PuppyRaffle contract.
VS Code, Foundry
To prevent this vulnerability, you can track the balance internally. Instead of relying on address(this).balance to track the balance of the contract, you can maintain an internal variable that is updated whenever Ether is deposited or withdrawn. This way, even if an attacker self-destructs a contract and sends ETH to the raffle, the internal balance will not be affected, and the withdrawal will proceed as expected.
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.