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.