Mystery Box

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

Mystery Box Audit Report (by coinleft)

Summary

This report identifies several vulnerabilities in the MysteryBox smart contract. The identified issues include a predictable randomness mechanism, an out-of-bounds index validation flaw, and a missing access control mechanism in the changeOwner function. These vulnerabilities can be exploited to manipulate rewards, access funds inappropriately, or take control of the contract.

Vulnerability Details

1. Predictable Randomness in openBox Function

  • Code:

    uint256 randomValue = uint256(keccak256(abi.encodePacked(block.timestamp, msg.sender))) % 100;
  • Description: The random number generation is based on block.timestamp and msg.sender, which are both publicly accessible and predictable values. An attacker can manipulate the block timestamp to influence the outcome of the randomness, thereby maximizing their chances of getting better rewards.

2. Incorrect Index Validation in claimSingleReward Function

  • Code:

    require(_index <= rewardsOwned[msg.sender].length, "Invalid index");
  • Description: The check allows _index to be equal to the length of the rewardsOwned[msg.sender] array. However, arrays are indexed from 0, and having an index equal to the length results in an out-of-bounds access, which can lead to errors.

3. Missing Access Control in changeOwner Function

  • Code:

    function changeOwner(address _newOwner) public {
    owner = _newOwner;
    }
  • Description: The function changeOwner lacks an access control check to verify that only the current owner can change the owner. This means that any user can call this function and take control of the contract, resulting in loss of ownership for the legitimate owner.

4 Reentrancy in claimAllRewards()and claimSingleReward(uint256)

function claimAllRewards() public {
uint256 totalValue = 0;
for (uint256 i = 0; i < rewardsOwned[msg.sender].length; i++) {
totalValue += rewardsOwned[msg.sender][i].value;
}
require(totalValue > 0, "No rewards to claim");
(bool success,) = payable(msg.sender).call{value: totalValue}("");
require(success, "Transfer failed");
delete rewardsOwned[msg.sender];
}
function claimSingleReward(uint256 _index) public {
require(_index <= rewardsOwned[msg.sender].length, "Invalid index"); //《=
uint256 value = rewardsOwned[msg.sender][_index].value;
require(value > 0, "No reward to claim");
(bool success,) = payable(msg.sender).call{value: value}("");
require(success, "Transfer failed");
delete rewardsOwned[msg.sender][_index];
}

Should delete rewardsOwned[msg.sender][_index] before transfer value.

Impact

  1. Predictable Randomness: Attackers can manipulate randomness to guarantee favorable rewards, which undermines the fairness of the protocol and leads to disproportionate gains.

  2. Out-of-Bounds Index: The incorrect index check can cause out-of-bounds errors, potentially leading to a denial of service or other unexpected behavior.

  3. Unauthorized Ownership Change: Anyone can become the contract owner, allowing unauthorized individuals to withdraw funds or perform other privileged actions.

Tools Used

  • VSCode

  • Foundry

Recommendations

1. Secure Randomness

Replace the predictable randomness mechanism with a more secure source, such as Chainlink VRF or another oracle-based solution to provide unbiased and unpredictable randomness.

2. Correct Index Validation

Update the index validation in claimSingleReward function to:

require(_index < rewardsOwned[msg.sender].length, "Invalid index");

This ensures that _index falls within the valid range of the array.

3. Add Access Control for changeOwner Function

Add an ownership check in the changeOwner function:

function changeOwner(address _newOwner) public {
require(msg.sender == owner, "Only owner can change");
owner = _newOwner;
}

This ensures that only the current owner can transfer ownership, preventing unauthorized takeovers.

Updates

Lead Judging Commences

inallhonesty Lead Judge
about 1 year ago
inallhonesty Lead Judge
about 1 year ago

Appeal created

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

Anyone can change owner

Weak Randomness

`claimAllRewards` reentrancy

`claimSingleReward` reentrancy

Support

FAQs

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

Give us feedback!