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

Predictable Randomness in `ChoosingRam::increaseValuesOfParticipants` and `ChoosingRam::selectRamIfNotSelected` functions

Description: In ChoosingRam contract, there are multiple functions where uint256 random = uint256(keccak256(abi.encodePacked(block.timestamp, block.prevrandao, ...)))
was used to get a random number to do certain tasks. There are some issues with this attempt

Impact: Using block-related properties such as block.timestamp and block.prevrandao (or its predecessor block.difficulty) does not provide true randomness and can be manipulated by miners

  1. Predictability: Since block.timestamp and block.prevrandao are known or can be influenced by miners, the output can be predicted or manipulated.

  2. Miner Manipulation: Miners can choose to include transactions in a block at specific times or modify the block timestamp slightly to influence the output.

Proof of Concept:

  1. Miners calls Dussehra::enterPeopleWhoLikeRam and get a token minted with their respective tokenId.

  2. Miners sees that ChoosingRam::selectRamIfNotSelected is being called which uses uint256 random = uint256(keccak256(abi.encodePacked(block.timestamp, block.prevrandao))) % ramNFT.tokenCounter(); to get a random number to choose a Ram.

  3. Miners could calculate potential outcomes for various timestamps and find an optimal value.

  4. The miner could then adjust the block's timestamp within allowed limits to produce a random value that favors a specific participant.

  5. Their Ram gets selected and gets the privilege to kill ravana, call withdraw function and get the money.

Mitigation: Consider using Chainlink VRF as it provides a secure source of randomness that cannot be predicted or influenced by any participant, including miners.

Here is a demo code of its implementation

Code
import "@chainlink/contracts/src/v0.8/VRFConsumerBase.sol";
contract RandomNumberConsumer is VRFConsumerBase {
bytes32 internal keyHash;
uint256 internal fee;
uint256 public randomResult;
constructor(address _vrfCoordinator, address _linkToken, bytes32 _keyHash, uint256 _fee)
VRFConsumerBase(_vrfCoordinator, _linkToken) {
keyHash = _keyHash;
fee = _fee;
}
function getRandomNumber() public returns (bytes32 requestId) {
require(LINK.balanceOf(address(this)) >= fee, "Not enough LINK");
return requestRandomness(keyHash, fee);
}
function fulfillRandomness(bytes32 requestId, uint256 randomness) internal override {
randomResult = randomness;
}
}

Tools: Manual Review

Updates

Lead Judging Commences

bube Lead Judge about 1 year ago
Submission Judgement Published
Validated
Assigned finding tags:

Weak randomness in `ChoosingRam::increaseValuesOfParticipants`

Support

FAQs

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