Beginner FriendlyFoundryNFT
100 EXP
View results
Submission Details
Severity: low
Invalid

`ChoosingRam::increaseValuesOfParticipants` allows users to call the function repeatedly, allowing a Ram to be selected within the first few minutes of launch.

Summary

ChoosingRam::increaseValuesOfParticipants allows users to call the function repeatedly with no time buffer. This allows the first users to call this function repeatedly selecting a Ram and leaving no chance for other users. This also opens the door for a DOS attack as a malicious user can enter the protocol with 2 wallets and call this function against their 2 tokens in rapid succession, ensuring they are the selected Ram rendering the protocol unusable for other participants.

Vulnerability Details

In this scenario the attacker enters as the first 2 participants.

  1. attacker enters with 1st wallet

  2. attacker enters with 2nd wallet

  3. attacker calls ChoosingRam::increaseValuesOfParticipants until one token is selected as Ram.

(Proof of Code)

function testDosAttack() public {
address attacker = makeAddr("attacker");
address attacker2 = makeAddr("attacker2");
vm.startPrank(attacker);
vm.deal(attacker, 1 ether);
dussehra.enterPeopleWhoLikeRam{value: 1 ether}();
vm.stopPrank();
vm.startPrank(attacker2);
vm.deal(attacker2, 1 ether);
dussehra.enterPeopleWhoLikeRam{value: 1 ether}();
vm.stopPrank();
vm.startPrank(attacker);
choosingRam.increaseValuesOfParticipants(0, 1);
choosingRam.increaseValuesOfParticipants(0, 1);
choosingRam.increaseValuesOfParticipants(0, 1);
choosingRam.increaseValuesOfParticipants(0, 1);
choosingRam.increaseValuesOfParticipants(0, 1);
vm.stopPrank();
console.log(choosingRam.selectedRam());
assertEq(choosingRam.selectedRam(), attacker2);
}

The attacker successfully called increaseValueOfParticipants 5 times in succession having their 2nd wallet become Ram.

Impact

Denies users a fair chance at becoming the selected Ram, hindering the functionality of the protocol.

Tools Used

Manual Review,
ChatGpt,
Slither,
Foundry,

Recommendations

Consider Implementing a time buffer for each user to prevent them from calling this function in rapid succession, leaving other users a chance to compete in the protocol.

You can modify the function to include a time buffer by implementing the following:

  1. Add a mapping to store the last call timestamp for each user.

  2. Add a constant for the buffer duration.

  3. Check the last call timestamp before proceeding with the function logic.

  4. Update the last call timestamp at the end of the function.

contract ChoosingRam {
RamNFT public ramNFT;
address public selectedRam;
+ uint256 public constant BUFFER_DURATION = 1 hours; // Set the buffer duration (e.g., 1 hour)
+ mapping(address => uint256) public lastCallTime;
function increaseValuesOfParticipants(uint256 tokenIdOfChallenger, uint256 tokenIdOfAnyPerticipent)
public
RamIsNotSelected
{
+ require(block.timestamp >= lastCallTime[msg.sender] + BUFFER_DURATION, "You must wait before calling this function again");
if (tokenIdOfChallenger > ramNFT.tokenCounter()) {
revert("ChoosingRam__InvalidTokenIdOfChallenger");
}
if (tokenIdOfAnyPerticipent > ramNFT.tokenCounter()) {
revert("ChoosingRam__InvalidTokenIdOfPerticipent");
}
if (ramNFT.getCharacteristics(tokenIdOfChallenger).ram != msg.sender) {
revert("ChoosingRam__CallerIsNotChallenger");
}
if (block.timestamp > 1728691200) {
revert("ChoosingRam__TimeToBeLikeRamFinish");
}
uint256 random = uint256(keccak256(abi.encodePacked(block.timestamp, block.prevrandao, msg.sender))) % 2;
if (random == 0) {
if (!ramNFT.getCharacteristics(tokenIdOfChallenger).isJitaKrodhah) {
ramNFT.updateCharacteristics(tokenIdOfChallenger, true, false, false, false, false);
} else if (!ramNFT.getCharacteristics(tokenIdOfChallenger).isDhyutimaan) {
ramNFT.updateCharacteristics(tokenIdOfChallenger, true, true, false, false, false);
} else if (!ramNFT.getCharacteristics(tokenIdOfChallenger).isVidvaan) {
ramNFT.updateCharacteristics(tokenIdOfChallenger, true, true, true, false, false);
} else if (!ramNFT.getCharacteristics(tokenIdOfChallenger).isAatmavan) {
ramNFT.updateCharacteristics(tokenIdOfChallenger, true, true, true, true, false);
} else if (!ramNFT.getCharacteristics(tokenIdOfChallenger).isSatyavaakyah) {
ramNFT.updateCharacteristics(tokenIdOfChallenger, true, true, true, true, true);
selectedRam = ramNFT.getCharacteristics(tokenIdOfChallenger).ram;
}
} else {
if (!ramNFT.getCharacteristics(tokenIdOfAnyPerticipent).isJitaKrodhah) {
ramNFT.updateCharacteristics(tokenIdOfAnyPerticipent, true, false, false, false, false);
} else if (!ramNFT.getCharacteristics(tokenIdOfAnyPerticipent).isDhyutimaan) {
ramNFT.updateCharacteristics(tokenIdOfAnyPerticipent, true, true, false, false, false);
} else if (!ramNFT.getCharacteristics(tokenIdOfAnyPerticipent).isVidvaan) {
ramNFT.updateCharacteristics(tokenIdOfAnyPerticipent, true, true, true, false, false);
} else if (!ramNFT.getCharacteristics(tokenIdOfAnyPerticipent).isAatmavan) {
ramNFT.updateCharacteristics(tokenIdOfAnyPerticipent, true, true, true, true, false);
} else if (!ramNFT.getCharacteristics(tokenIdOfAnyPerticipent).isSatyavaakyah) {
ramNFT.updateCharacteristics(tokenIdOfAnyPerticipent, true, true, true, true, true);
selectedRam = ramNFT.getCharacteristics(tokenIdOfAnyPerticipent).ram;
}
}
// Update the last call time for the user
+ lastCallTime[msg.sender] = block.timestamp;
}
}
Updates

Lead Judging Commences

bube Lead Judge over 1 year ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
Assigned finding tags:

Info/Gas/Invalid according to docs

brutalclowney Submitter
about 1 year ago
bube Lead Judge
about 1 year ago
bube Lead Judge about 1 year ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
Assigned finding tags:

Info/Gas/Invalid according to docs

Support

FAQs

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