The ChoosingRam::increaseValuesOfParticipants() function is intended to increase the attributes of the user's RamNFT. When a RamNFT is minted, it stores the address of the minter (RamNFT::CharacteristicsOfRam.ram) and defaults 5 characteristics to false:
When all of these characteristics are set to true, RamNFT::CharacteristicsOfRam.ram becomes the ChoosingRam::selectedRam. The ChoosingRam::selectedRam has access to the Dussehra::withdraw() function. Dussehra::withdraw() allows the ChoosingRam::selectedRam to have a share of the funds derived from each entry into the protocol (Dussehra::totalAmountGivenToRam)
The ChoosingRam::increaseValuesOfParticipants() function requires two uint256 arguments
The ChoosingRam::increaseValuesOfParticipants() function will change one RamNFT::CharacteristicsOfRam to true per function call. The function will either manipulate msg.sender's RamNFT, or it will manipulate the RamNFT of another participant (the second argument). It should take at least 5 function calls to flip all characteristics to true:
The spirit of this function is to utilize "randomness" to flip characteristics to true. The intention is to require users to call ChoosingRam::increaseValuesOfParticipants() multiple times (probably much more than the minimum of 5) in order to become ChoosingRam::selectedRam. We can make this assumption based on this check:
This check ensures that msg.sender is the owner of the RamNFT with tokenIdOfChallenger id. So we can assume the idea is for the user to input their tokenId and another tokenId. However, because there is no validation comparing the two arguments (uint256 tokenIdOfChallenger and uint256 tokenIdOfAnyPerticipent), the system can easily be gamed.
This foundry test shows how easy it is to game the system:
The user inputs their tokenId twice. They successfully flip each characteristic to true in each function call requiring a total of only 5 function calls. The user becomes ChoosingRam::selectedRam.
This is a high risk vulnerability that allows a user to game the system.
Abusing a lack of input validation, there is nothing stopping a user from using their own tokenId as both arguments for ChoosingRam::increaseValuesOfParticipants(). This allows any user to quickly become ChoosingRam::selectedRam in 5 function calls. As speculated earlier, it is unlikely that this is intended behavior. The intentions are to create a system dictated by 'randomness' and luck. The lack of input comparison bypasses the need for luck.
The point of this gamified NFT protocol is to gain ChoosingRam::selectedRam status. With this status, the user gains access to the Dussehra::withdraw() function, giving the user a claim to 50% of the RamNFT mint.
The ChoosingRam::increaseValuesOfParticipants() is very easy to manipulate, and it entitles the manipulator to 50% of the funds.
Manual Review
Foundry
The easiest form of mitigation would be to include input validation to ensure both uint256 arguments are different
However, the system can still be gamed: enter the raffle twice with different addresses, and use your second RamNFT as the second parameter.
A better solution is to have the function randomly choose a second participant. This solution will require more gas, but it won't allow msg.sender to freely choose the second input parameter.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.