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

Randomnes Vulnerabilities in the `RapBattle::_battle()` funtion.

Summary

Everyone can access the variables used to generate the random number, 
as they are public data accessible to anyone on the blockchain.

Vulnerability Details

```
    diff
    function _battle(uint256 _tokenId, uint256 _credBet) internal {
        address _defender = defender;
        require(defenderBet == _credBet, "RapBattle: Bet amounts do not match");
        uint256 defenderRapperSkill = getRapperSkill(defenderTokenId);
        uint256 challengerRapperSkill = getRapperSkill(_tokenId);
        uint256 totalBattleSkill = defenderRapperSkill + challengerRapperSkill;
        uint256 totalPrize = defenderBet + _credBet;

    @=> uint256 random =
    @=>      uint256(keccak256(abi.encodePacked(block.timestamp, block.prevrandao, msg.sender))) % totalBattleSkill;

        // Reset the defender
        defender = address(0);
        emit Battle(msg.sender, _tokenId, random < defenderRapperSkill ? _defender : msg.sender);

        // If random <= defenderRapperSkill -> defenderRapperSkill wins, otherwise they lose
        if (random <= defenderRapperSkill) {
            // We give them the money the defender deposited, and the challenger's bet
            // credToken.transferFrom(msg.sender, _defender, defenderBet);
            credToken.transfer(_defender, defenderBet);
            credToken.transferFrom(msg.sender, _defender, _credBet);

            // IOneShot.RapperStats memory stats = oneShotNft.getRapperStats(defenderTokenId);
            // stats.battlesWon = 1;
        } else {
            // Otherwise, since the challenger never sent us the money, we just give the money in the contract
            // credToken.transfer(msg.sender, defenderBet);
            credToken.transfer(msg.sender, _credBet);

            // IOneShot.RapperStats memory stats = oneShotNft.getRapperStats(_tokenId);
            // stats.battlesWon = 1;
        }
        totalPrize = 0;
        // Return the defender's NFT
        oneShotNft.transferFrom(address(this), _defender, defenderTokenId);
    }
```
The random variable is generated from publicly accessible data on the blockchain,
which means that anyone can reproduce this number and give it the desired value.

Impact

Keep this `random < defenderRapperSkill` condition true at all times so that the 
challenger wins every time and receives all the money intended for the winner.

Tools Used

-Foundry

Recommendations

Use Chainlink VRF until of using `block.timestamp, block.prevrandao` to generate a random number.
Updates

Lead Judging Commences

inallhonesty Lead Judge over 1 year ago
Submission Judgement Published
Validated
Assigned finding tags:

Weak Randomness

Support

FAQs

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