Mystery Box

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

Array Inflation in transferReward function could lead to DoS

Summary

The transferReward function can be exploited by a malicious user to inflate a victim's rewardsOwned array with zero-value rewards. This can lead to a DoS, making it difficult for the victim to interact with the contract due to the increased gas cost for operations involving the inflated array.

Vulnerability Details

A malicious user can repeatedly transfer zero-value rewards to a victim's account. Each transfer adds a new entry to the victim's rewardsOwned array since deleting the reward from the destination resets the value to 0. Therefore, the transaction goes through because there is no limit or check to prevent this action, allowing the attacker to inflate the array size indefinitely.

function transferReward(address _to, uint256 _index) public {
require(_index < rewardsOwned[msg.sender].length, "Invalid index");
rewardsOwned[_to].push(rewardsOwned[msg.sender][_index]);
delete rewardsOwned[msg.sender][_index]; // This line deletes the reward but sets the index's value to 0
}

If the reward being transferred has zero value, the victim’s rewardsOwned array can be filled with thousands of zero-value rewards, making any operation on the array (such as viewing or claiming rewards) extremely gas-intensive.

Impact

This vulnerability can lead to the following issues:

  1. DoS: The victim will face increased gas costs when interacting with their rewards array. If the array is sufficiently large, certain functions like getRewards() will run out of gas and fail.

  2. User Frustration: The victim may become unable to claim legitimate rewards due to high gas costs, leading to a poor user experience and potential financial loss. Additionally, the victim may get confused about their rewards indexes since the array is so large.

  3. System Disruption: In severe cases, the contract itself may become unusable for affected accounts due to the excessive gas required for operations involving the inflated arrays.

Proof Of Concept

  • Attacker can create an exploit contract with a modified transferReward that transfers the reward N times enough to make the victim’s array large.

function transferRewardModified(address _to, uint256 _index, uint256 count) public {
// Get the reward to be transferred
Reward memory reward = rewardsOwned[msg.sender][_index];
// Push the reward N times to the recipient
for (uint256 i = 0; i < count; i++) {
rewardsOwned[_to].push(reward);
}
// Delete the reward from the sender's array
delete rewardsOwned[msg.sender][_index];
}

Attacker calls the transferRewardModified with a high count value (e.g., 1000) to transfer this zero-value reward to victim. While testing it on Remix IDE, repeating the attack allows the attacker to inflate the victim's array, making it increasingly expensive for the victim to call functions like getRewards() or claimAllRewards() or claimSingleReward

Tools Used

  • Manual review

  • Remix IDE

Recommendations

Before transferring a reward, check if its value is greater than zero. This will prevent zero-value rewards from being transferred and inflating the recipient’s array.

function transferReward(address _to, uint256 _index) public {
require(_index < rewardsOwned[msg.sender].length, "Invalid index");
require(reward.value > 0, "Cannot transfer zero-value reward"); //THIS WILL FIX IT
rewardsOwned[_to].push(rewardsOwned[msg.sender][_index]);
delete rewardsOwned[msg.sender][_index];
}
Updates

Appeal created

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

A user can poison the `rewardsOwned` of another user via `transferReward` of an empty reward index

Support

FAQs

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

Give us feedback!