The function ChoosingRam::selectRamIfNotSelected
depends on a random value to select the participant to be selected as Ram. This function generates the random number by using block.timestamp
and block.prevrandao
values. Those values are considered a bad source of randomness. The organiser can predict the outcome and execute the function only if the desired user will become Ram. The selected Ram will take the reward.
Using block.timestamp
as a source of randomness is commonly advised against, as the outcome can be manipulated by calling contracts. Also, for some chains like zkSync block.prevrandao
is a constant value. This will allow the users to predict the result of the calculated number in Line 90 of ChoosingRam.sol
: uint256 random = uint256(keccak256(abi.encodePacked(block.timestamp, block.prevrandao))) % ramNFT.tokenCounter();
. This will give the organiser the opportunity to break the random selection of the Ram and to select a specific user who will collect the reward.
The following code demonstrates how an attack can be executed.
The bad source of randomness gives the opportunity to the organiser to select the specific user which will become Ram and which will get the reward. Although, the organiser is considered to be trusted, the desired logic of the contract is not implemented correctly. The random number is not really a random number.
Manual review
Consider using a decentralized oracle for the generation of random numbers, such as Chainlinks VRF. The Chainlink VRF gives two methods to request randomness: subscription and direct funding method. They will have their added cost, but will solve the randomness issues of the Dussehra
contract.
The organizer is trusted, but the function `ChoosingRam::selectRamIfNotSelected` uses a way to generate a random number that is not completely random.
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.