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

If ram is chosen via `ChoosingRam.sol::increaseValuesOfParticipants`, `ChoosingRam.sol:isRamSelected` remains false

Summary

When ram is selected with ChoosingRam.sol::increaseValuesOfParticipants, ChoosingRam.sol::isRamSelected remains false meaning ram can be overriden and ram cannot withdraw the funds that theyve won.

Vulnerability Details

ChoosingRam.sol::isRamSelected is not set to true when ChoosingRam.sol::selectedRam is set when all nft traits are true. So, it is still thought that ram has not been selected as the boolean is still false.

Proof of code imapct 1.

function test_canOverrideRam() public participants {
uint256 timeStamp = 1722470400; //Date and time (GMT): Thursday, August 1, 2024 12:00:00 AM
uint256 prevrandao;
uint256 player1TokenId = 0;
uint256 player2TokenId = 1;
for (uint256 i = 0; i < 100; i++) {
vm.prevrandao(bytes32(i));
if (uint256(keccak256(abi.encodePacked(block.timestamp, block.prevrandao, player1))) % 2 == 0) {
prevrandao = i;
break;
}
}
vm.startPrank(player1);
for (uint256 i = 0; i < 5; i++) {
choosingRam.increaseValuesOfParticipants(player1TokenId, player2TokenId);
}
vm.stopPrank();
assertEq(choosingRam.selectedRam(), player1);
for (uint256 i = 0; i < 100; i++) {
vm.prevrandao(bytes32(i));
if (uint256(keccak256(abi.encodePacked(block.timestamp, block.prevrandao, player2))) % 2 == 0) {
prevrandao = i;
break;
}
}
vm.startPrank(player2);
for (uint256 i = 0; i < 5; i++) {
choosingRam.increaseValuesOfParticipants(player2TokenId, player1TokenId);
}
vm.stopPrank();
assertEq(choosingRam.selectedRam(), player2);
}

Player2 becomes ram after player1 was ram

Proof of code impact 2.:

function test_isRamSelectedNotUpdated() public participants {
vm.startPrank(player3);
vm.deal(player3, 1 ether);
dussehra.enterPeopleWhoLikeRam{value: 1 ether}();
vm.stopPrank();
uint256 timeStamp = 1722470400; //Date and time (GMT): Thursday, August 1, 2024 12:00:00 AM
// vm.warp(timeStamp);
uint256 prevrandao;
uint256 player1TokenId = 0;
uint256 player2TokenId = 1;
for (uint256 i = 0; i < 100; i++) {
vm.prevrandao(bytes32(i));
// if this condition hits, challenger will win.
if (uint256(keccak256(abi.encodePacked(block.timestamp, block.prevrandao, player1))) % 2 == 0) {
prevrandao = i;
break;
}
}
vm.startPrank(player1);
for (uint256 i = 0; i < 5; i++) {
choosingRam.increaseValuesOfParticipants(player1TokenId, player2TokenId);
}
vm.stopPrank();
assertEq(choosingRam.selectedRam(), player1);
assertFalse(choosingRam.isRamSelected());
vm.expectRevert();
dussehra.killRavana();
vm.startPrank(player1);
vm.expectRevert();
dussehra.withdraw();
vm.stopPrank();
}

player1 cant withdraw even though they are selected ram.

Impact

  1. ChoosingRam.sol::RamIsNotSelected modifier on ChoosingRam.sol::increaseValuesOfParticipants doesn't prevent another address from replacing the old selected ram if the previous ram was set by ChoosingRam.sol::increaseValuesOfParticipants.

  2. The address who made became ram first through ChoosingRam.sol::increaseValuesOfParticipants cannot withdraw the eth they earned. If someone else uses impact 1. and overrides the previous ram, they too can also not withdraw. This is because of the modifier Dussehra.sol::RamIsSelected on Dussehra.sol::withdraw depends on the boolean ChoosingRam.sol::isRamSelected which is false if ram is chosen through ChoosingRam.sol::increaseValuesOfParticipants.

Tools Used

Manual review

Recommendations

set ChoosingRam.sol::isRamSelected when setting selected ram.

if (random == 0) {
if (ramNFT.getCharacteristics(tokenIdOfChallenger).isJitaKrodhah == false) {
ramNFT.updateCharacteristics(tokenIdOfChallenger, true, false, false, false, false);
} else if (ramNFT.getCharacteristics(tokenIdOfChallenger).isDhyutimaan == false) {
ramNFT.updateCharacteristics(tokenIdOfChallenger, true, true, false, false, false);
} else if (ramNFT.getCharacteristics(tokenIdOfChallenger).isVidvaan == false) {
ramNFT.updateCharacteristics(tokenIdOfChallenger, true, true, true, false, false);
} else if (ramNFT.getCharacteristics(tokenIdOfChallenger).isAatmavan == false) {
ramNFT.updateCharacteristics(tokenIdOfChallenger, true, true, true, true, false);
} else if (ramNFT.getCharacteristics(tokenIdOfChallenger).isSatyavaakyah == false) {
ramNFT.updateCharacteristics(tokenIdOfChallenger, true, true, true, true, true);
selectedRam = ramNFT.getCharacteristics(tokenIdOfChallenger).ram;
+ isRamSelected = true;
}
} else {
if (ramNFT.getCharacteristics(tokenIdOfAnyPerticipent).isJitaKrodhah == false) {
ramNFT.updateCharacteristics(tokenIdOfAnyPerticipent, true, false, false, false, false);
} else if (ramNFT.getCharacteristics(tokenIdOfAnyPerticipent).isDhyutimaan == false) {
ramNFT.updateCharacteristics(tokenIdOfAnyPerticipent, true, true, false, false, false);
} else if (ramNFT.getCharacteristics(tokenIdOfAnyPerticipent).isVidvaan == false) {
ramNFT.updateCharacteristics(tokenIdOfAnyPerticipent, true, true, true, false, false);
} else if (ramNFT.getCharacteristics(tokenIdOfAnyPerticipent).isAatmavan == false) {
ramNFT.updateCharacteristics(tokenIdOfAnyPerticipent, true, true, true, true, false);
} else if (ramNFT.getCharacteristics(tokenIdOfAnyPerticipent).isSatyavaakyah == false) {
ramNFT.updateCharacteristics(tokenIdOfAnyPerticipent, true, true, true, true, true);
selectedRam = ramNFT.getCharacteristics(tokenIdOfAnyPerticipent).ram;
+ isRamSelected = true;
}
}

Extra recommendation:
create a method that handles all the ifs and else ifs to avoid duplicate code.

Updates

Lead Judging Commences

bube Lead Judge over 1 year ago
Submission Judgement Published
Validated
Assigned finding tags:

`isRamSelected` is not set

Support

FAQs

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