Blockchain is a deterministic technology, so there is no randomness and no way to create random data for a lottery or similar application.
But not only that. The fact that the function does not have any kind of access control made it possible for an attacker to execute it at any time, choosing the right block.timestamp and block.difficulty to suit his/her interest.
This contract, within the selectWinner() function, uses on-chain data 2 times:
And
Take this test as an example:
As we can see, after finding the relationship between global variables + own address + number of players, the attacker is able to attack the contract and win the prize with 100% effectiveness.
The same goes for rarity. The attacker is able to find the relationship between the address and the difficulty and get the desired rarity.
Any attacker can set up their account in the right place so that they always win the raffle, so that it is no longer a "lottery" but a scam for the other users.
Foundry, terminal.
We don't know if this was intended by the developers, but it is highly recommended to secure the function with Open Zeppelin libraries such as onlyOwner or AccessControl. This will help to control the damage.
But the only real way to avoid the high-risk vulnerability is to use an oracle instead of on-chain data for randomness.
The most widely used and tested oracle for these cases is the Chainlink VRF, and it is possible to consult the documentation for it here:
https://docs.chain.link/vrf
Root cause: bad RNG Impact: manipulate winner
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.