The objective of this protocol is to grant the status of ChoosingRam::isRamSelected to one of the participants that enters the protocol through Dussehra::enterPeopleWhoLikeRam(). The ChoosingRam::increaseValuesOfParticipants() function or the ChoosingRam::selectRamIfNotSelected() function both have the ability to select a participant to be the ChoosingRam:selectedRam .  This lucky participant will get 50% of the entrance fees required to mint a RamNFT (Dussehra::totalAmountGivenToRam)
Both of the functions mentioned above have an important modifier: ChoosingRam::
ChoosingRam::isRamSelected is a boolean that should change to true when ChoosingRam:selectedRam has been chosen. We can see that in ChoosingRam::selectRamIfNotSelected(), the value is updated:
Only the RamNFT::organizer can call this function.
Presumably, this change should also occur in ChoosingRam::increaseValuesOfParticipants(). We can make this assumption because the function has the modifier mentioned earlier.  The problem is, ChoosingRam::increaseValuesOfParticipants() does not update ChoosingRam::isRamSelected.
The function chooses an address for ChoosingRam::selectedRam, but it does not update ChoosingRam::isRamSelected.
ChoosingRam::selectRamIfNotSelected() can be called by RamNFT::organizer after this timestamp:
Since ChoosingRam::increaseValuesOfParticipants() does not update ChoosingRam::isRamSelected, RamNFT::organizer will always be the actor that makes ChoosingRam::selectedRam official.
I was thinking about submitting this as a bug, but on its own, it's a Low at best. It's not a huge deal if ChoosingRam::selectedRam can constantly by changed until the timestamp deadline. The real threat lies in the attack opportunity provided to RamNFT::organiser thanks to this oversight.
RamNFT::organizer has more than enough information to dictate who the winner will be by exploiting weak randomness in ChoosingRam::selectRamIfNotSelected:
This calculation will produce a number that will be used to choose a "random" RamNFT id.
Along with the timestamps, RamNFT::tokenCounter (the amount of participants in the protocol), determines the "random" number
The owner of this nft will become ChoosingRam::selectedRam granting them claim to 50% of the mint fees.
The attack can occur in a few ways. In its simplest form, RamNFT::organiser can collude with a participant and choose them to be ChoosingRam::selectedRam. An attack contract may not be necessary, but it makes the attack much easier. If the RamNFT::organiser chooses to go with the simple route, they would have to deploy their attack at very specific times. This function in Foundry shows how RamNFT::organiser can figure out when to attack.
In this example, RamNFT::organiser wants the first entry to be the ChoosingRam::selectedRam: if random == 0
The function will keep track of all the timestamps that would produce 0 based on the value of RamNFT::tokenCounter
A counter of 101 will produce 0 849 times within the predetermined time constraints of ChoosingRam::selectRamIfNotSelected
Without an attack contract, RamNFT::organiser would have to make a precise call ofChoosingRam::selectRamIfNotSelected() during one of the returned timestamps
RamNFT::organiser room for error:The malicious actor would use this contract to deploy RamNFT which would mean that this contract would function as RamNFT::organiser
The malicious actor could enter the protocol and choose their RamNFT to become ChoosingRam::selectedRam (or collude with another participant)
Organizer deploys attack contract and uses the attack contract to deploy RamNFT
Organizer enters the protocol as first participant (tokenId: 0)
We can create an arbitrary amount of users (100 in this example) setting the counter (101 in this example)
The test shows ChoosingRam::increaseValuesOfParticipants maxing out the RamNFT for entrant 5
It does not trigger ChoosingRam::isSelected
The organizer figures out which blocks they can exploit
In the wild, the attack function could be triggered near one of these timestamps
Without a contract, the malicious actor's call of ChoosingRam::selectRamIfNotSelected() would need to be much more precise
This is a high rsk vulnerability that enables the RamNFT::organiser to acquire all the funds.
Users enter this protocol with the belief that they have a chance to win 50% of the entrance fees if they become ChoosingRam:selectedRam. This vulnerability erases the implied randomness of the protocol and gives all of the rewards to RamNFT::organiser.
ChoosingRam::increaseValuesOfParticipants() never sets the ChoosingRam::isRamSelected boolean to true. RamNFT::organiser will always set ChoosingRam:selectedRam with the ChoosingRam::selectRamIfNotSelected() function.
The malicious actor can:
Use an attack contract to serve the role of RamNFT::organiser while entering the contest themselves
Or collude with an entrant.
Either way, the malicious actor is in control of choosing ChoosingRam:selectedRam removing randomness from the equation. With or without an attack contract, the actor pulling the strings of RamNFT::organiser will receive a majority of the funds. They can choose to collude with a participant to get a share of  Dussehra::totalAmountGivenToRam along with the remaining 50%. Or, they can take 100%.
Manual Review
Foundry
When the conditions are met, ChoosingRam::increaseValuesOfParticipants should set ChoosingRam::isSelected to true
This will put some control of the outcome in the hands of the participants.
Without this change, RamNFT::organiser has all of the influence
We can consider not allowing contracts to become RamNFT::organiser
RamNFT
RamNFT::constructor()
This is a step in the right direction, but it doesn't address the main problem
The most important mitigation step is to use off-chain methods such as ChainlinkVRF to create randomness.
This implementation of "randomness" gives the malicious actor all the information they need to get their desired output.
It should not be used
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.