Mystery Box

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

[H-2] Manipulable Randomness in `openBox` Function (Insecure Random Number Generation + Unfair Rewards Distribution)

Description: The openBox function in the Mysterybox contract uses an insecure method for generating random numbers by hashing the block.timestamp and the sender’s address (keccak256(abi.encodePacked(block.timestamp, msg.sender))). This approach allows miners or users to manipulate the outcome by controlling the block.timestamp or making multiple contract calls until the desired result is achieved. Since block.timestamps are predictable and can be influenced by miners within a certain range, this introduces a significant vulnerability to the randomness mechanism.

Impact:

  1. Predictable Outcomes: Users or miners can predict or manipulate the random number generated in the openBox function, leading to unfair rewards distribution.

  2. Exploitation for Higher Rewards: A malicious user can repeatedly attempt to open boxes at specific times or under specific conditions, increasing their chances of receiving rare rewards like "Gold Coin" or "Silver Coin".

Proof of Concept:

  1. A user can observe the block.timestamp and call the openBox function repeatedly, leveraging the predictable nature of the random number generation.

  2. A miner can influence the block.timestamp to increase their chances of receiving higher-tier rewards by adjusting the block's timestamp to force favorable outcomes.

example:

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

In this example, the random value can be influenced by manipulating the block's timestamp

Recommended Mitigation:
Use a secure source of randomness like Chainlink VRF (Verifiable Random Function) to ensure that random number generation is truly unpredictable and cannot be manipulated by users or miners.
Chainlink VRF provides a verifiable proof that the random number generated is fair and tamper-proof, as it involves off-chain computation that cannot be influenced by any party.

import "@chainlink/contracts/src/v0.8/VRFConsumerBase.sol";
contract Mysterybox is VRFConsumerBase {
bytes32 internal keyHash;
uint256 internal fee;
uint256 public randomResult;
constructor()
VRFConsumerBase(
0xAA77729D3466CA35AE8D28E24DB6D6B4F5F524B6, // VRF Coordinator
0x514910771AF9Ca656af840dff83E8264EcF986CA // LINK Token address
) {
keyHash = 0x6c3699283bda56ad74f6b855546325b68d482e983852a1e8a7d88e67e919f62a;
fee = 0.1 * 10 ** 18; // 0.1 LINK (Varies by network)
}
function openBox() public returns (bytes32 requestId) {
require(LINK.balanceOf(address(this)) >= fee, "Not enough LINK - fill contract with faucet");
return requestRandomness(keyHash, fee);
}
function fulfillRandomness(bytes32 requestId, uint256 randomness) internal override {
randomResult = randomness % 100;
// Proceed with reward distribution logic
}
}

This mitigates the risk of random number manipulation and ensures a fair and secure distribution of rewards in the openBox function.

Tools Used: Manual Review

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!