The PuppyRaffle::refund function sends Ether to msg.sender before changing the state. This design can lead to a re-entrancy exposure.
The refund function in PuppyRaffle interacts with arbitrary contracts without adhering to the check-effect-interaction pattern. This exposes the contract to a re-entrancy attack.
In this scenario, msg.sender can be a malicious contract with a function that repeatedly re-enters the refund function, causing the PuppyRaffle contract to send more Ether than the entranceFee.
The provided scripts and test suite demonstrate the validity and severity of the vulnerability. These scripts exploit the re-entrancy issue in the refund function.
Requirements
Install Foundry.
Clone the project codebase to your local workspace.
Copy the codes in the codebase below into their respective file and folder. Note the file names and path provided at the end of each code.
Create a .env file in your root folder and add the required variables.
The .env file should follow this format:
Step-by-step Guide to Run the PoC
Ensure the above requirements are installed.
Run source .env to load .env variables into the terminal.
Change DeployPuppyRaffle.sol::duration from "1 day" to "5 minutes"
Change DeployPuppyRaffle.sol::entranceFee from "1e18" to "100 wei" and set it as PuppyRaffle constructor first parameter.
Run the necessary command to deploy the following contracts.
To deploy PuppyRaffle contract:
To deploy AttackContract:
Wait for five minutes, then run the command below to execute the exploit script:
The preceding steps involved deploying the PuppyRaffle contract and subsequently deploying an AttackContract designed for exploiting the refund function in PuppyRaffle. Finally, a script is executed to initiate the attack.
Proof of Exploit:
Please note the disparity in the logged data:
Initial Puppy Raffle balance before the exploit: 400
Puppy Raffle balance after the exploit: 0
Expected balance under normal conditions: 300
The code below consists of Foundry scripts that deploy the contract to a chosen network and interact with it through our exploit script.
AttackContract
AttackContract deployment Script
Trigger Script
Exploit Scenario:
John enters the raffle.
John decides to get a refund and exit the game.
John initiates the refund function and gets credited.
Before the contract updates John's status on the network, John repeatedly gets more refunds, potentially wiping out the contract balance.
Foundry
Follow the check-interaction-effect pattern when implementing the refund function to avoid re-entrancy vulnerabilities. Here's an example of how to modify the function:
By changing the order of operations, you ensure that the state is updated before sending Ether, reducing the risk of re-entrancy attacks.
reentrancy in refund() function
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.