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

`ChoosingRam::selectRamIfNotSelected` uses weak randomness generator, can lead to manipulated ram selection

Summary

The ChoosingRam contract uses a pseudorandom number generator in the selectRamIfNotSelected functions. The current implementation relies on block.timestamp and block.prevrandao, which are predictable and can be manipulated by miners, leading to potential unfair outcomes in the selection of Ram.

Vulnerability Details

Weak Random number generator in selectRamIfNotSelected Function:

uint256 random = uint256(keccak256(abi.encodePacked(block.timestamp, block.prevrandao))) % ramNFT.tokenCounter();

**Proof of Concept **

Manipulate Ram Selection
```
function test_canManipulateRamSelection() public {
    // To be selected as winner
    address winner = makeAddr("winner");

    vm.deal(player1, 1 ether);
    vm.deal(player2, 1 ether);
    vm.deal(player3, 1 ether);
    vm.deal(winner, 1 ether);

    vm.prank(player1);
    dussehra.enterPeopleWhoLikeRam{value: 1 ether}();

    vm.prank(player2);
    dussehra.enterPeopleWhoLikeRam{value: 1 ether}();

    vm.prank(player3);
    dussehra.enterPeopleWhoLikeRam{value: 1 ether}();

    vm.prank(winner);
    dussehra.enterPeopleWhoLikeRam{value: 1 ether}();

    console.log("Participant length", ramNFT.tokenCounter());

    // Set a range of timestamps to simulate a miner's control over the block timestamp
    uint256 startTime = 1728691200 + 1; // The earliest possible time
    uint256 endTime = 1728777600; // The latest possible time

    // Loop through the range to find a timestamp that makes the winner selected
    for (uint256 timestamp = startTime; timestamp <= endTime; timestamp++) {
        uint256 random = uint256(keccak256(abi.encodePacked(timestamp, block.prevrandao))) % 4;
        if (random == 3) {
            vm.warp(timestamp);
            break;
        }
    }

    // Organiser selects Ram
    vm.startPrank(organiser);
    choosingRam.selectRamIfNotSelected();
    vm.stopPrank();

    // Assert that the winner was selected
    assertEq(choosingRam.selectedRam(), winner);
}
```

Impact

Critical - The randomness can be predicted. This undermines the fairness of the Ram selection process.

Tools Used

  • Manual review

  • Static analysis

  • Foundry

Recommendations

Use Chainlink VRF (Verifiable Random Function):

Updates

Lead Judging Commences

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

Weak randomness in `ChoosingRam::selectRamIfNotSelected`

The organizer is trusted, but the function `ChoosingRam::selectRamIfNotSelected` uses a way to generate a random number that is not completely random.

Support

FAQs

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