Mystery Box

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

Predictable Randomness in the `openBox()` function

Summary

The MysteryBox contract uses an insecure method to generate random numbers for reward distribution, relying on block.timestamp and msg.sender. This approach is predictable and can be manipulated by miners or users, potentially allowing them to influence or predict the outcomes of box openings.

Vulnerability Details

The vulnerable code is in the openBox() function:

function openBox() public {
require(boxesOwned[msg.sender] > 0, "No boxes to open");
// Generate a random number between 0 and 99
@> uint256 randomValue = uint256(keccak256(abi.encodePacked(block.timestamp, msg.sender))) % 100;
// Determine the reward based on probability
if (randomValue < 75) {
// 75% chance to get Coal (0-74)
rewardsOwned[msg.sender].push(Reward("Coal", 0 ether));
} else if (randomValue < 95) {
// 20% chance to get Bronze Coin (75-94)
rewardsOwned[msg.sender].push(Reward("Bronze Coin", 0.1 ether));
} else if (randomValue < 99) {
// 4% chance to get Silver Coin (95-98)
rewardsOwned[msg.sender].push(Reward("Silver Coin", 0.5 ether));
} else {
// 1% chance to get Gold Coin (99)
rewardsOwned[msg.sender].push(Reward("Gold Coin", 1 ether));
}
boxesOwned[msg.sender] -= 1;
}

The issue lies in the random number generation (indicated by @>):

  1. block.timestamp can be manipulated by miners within a small range.

  2. msg.sender is known and controlled by the user calling the function.

  3. The combination of these values is predictable and can be calculated in advance.

Impact

The impact of this vulnerability is high:

  1. Reward Manipulation: Users or miners could potentially predict or influence the outcome of box openings.

  2. Economic Imbalance: Exploiters could consistently obtain high-value rewards, draining the contract's funds.

  3. Unfair Advantage: Knowledgeable users could have a significant advantage over others, undermining the fairness of the game.

  4. Loss of Trust: If exploited, users may lose trust in the fairness of the system, potentially leading to a loss of user base.

Tools Used

Manual code review.

Recommendations

To address this vulnerability, consider the following recommendations:

  1. Use a verifiable random function (VRF) provided by a trusted oracle service, such as Chainlink VRF. This provides cryptographically guaranteed randomness that can't be manipulated by miners or users.

Example implementation using Chainlink VRF:

import "@chainlink/contracts/src/v0.8/VRFConsumerBase.sol";
contract MysteryBox is VRFConsumerBase {
bytes32 internal keyHash;
uint256 internal fee;
mapping(bytes32 => address) public requestToSender;
constructor() VRFConsumerBase(
0x2Ca8E0C643bDe4C2E08ab1fA0da3401AdAD7734D, // VRF Coordinator
0x326C977E6efc84E512bB9C30f76E30c160eD06FB // LINK Token
) {
keyHash = 0x79d3d8832d904592c0bf9818b621522c988bb8b0c05cdc3b15aea1b6e8db0c15;
fee = 0.1 * 10 ** 18; // 0.1 LINK
}
@> function openBox() public returns (bytes32 requestId) {
require(LINK.balanceOf(address(this)) >= fee, "Not enough LINK");
requestId = requestRandomness(keyHash, fee);
requestToSender[requestId] = msg.sender;
return requestId;
}
@> function fulfillRandomness(bytes32 requestId, uint256 randomness) internal override {
address sender = requestToSender[requestId];
uint256 randomValue = randomness % 100;
// Use randomValue to determine the reward as before
// ...
delete requestToSender[requestId];
}
}
  1. If using an oracle is not feasible, implement a commit-reveal scheme where users submit a hash of their secret and the reveal happens in a separate transaction.

  2. Use block difficulty (block.difficulty) and a future block hash as additional sources of entropy, although this is still not truly random and can be manipulated to some extent.

By implementing one of these solutions, particularly the Chainlink VRF, the contract can ensure fair and unpredictable reward distribution, maintaining the integrity and excitement of the mystery box concept.

Updates

Appeal created

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