Using strict equality in withdrawFees function can cause accumulated fees to be forever stuck in the contract.
The require function in withdrawFees uses a strict equality check:
This check can be made to always fail by sending a small amount of ether directly to the smart contract address. This will make address(this).balance part of the check be greater than the uint256(totalFees) part of the check.
Even though the raffle contract only has one payable function which also has a hard requirement on funds that can be sent, there are other ways funds can be sent to the contract.
This exploit uses the selfdestruct function of a malicious contract. This contract receives funds from the attacker and then calls selfdestruct and provides puppyRaffle contract as the recipient of the ether.
This tiny amount of extra funds will cause address(this).balance of puppyRaffle contract to be greater than its uint256(totalFees) amount and therefore the check below will always fail and funds will be locked.
require(address(this).balance == uint256(totalFees), "PuppyRaffle: There are currently players active!");
src/PuppyRaffle.sol
https://github.com/Cyfrin/2023-10-Puppy-Raffle/blob/07399f4d02520a2abf6f462c024842e495ca82e4/src/PuppyRaffle.sol#L158
Fee funds can not be withdrawn from the smart contract.
Do not use strict equality, instead use an inequality.
Manual Audit
Foundry
Create a new attacker contract below.
Note: this is just a POC contract. It is beyond scope of this POC to ensure this attack contract is written securely and that funds are handled correctly once the contract has them.
And the test function.
Note: this test function is to be added to the existing test suite as it needs already existing components from there.
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.