Skip to content

Latest commit

 

History

History
79 lines (52 loc) · 3.51 KB

File metadata and controls

79 lines (52 loc) · 3.51 KB

Genuine Garnet Crab

Medium

An attacker could avoid penalties by repeatedly calling _computePenalty

Summary

The lack of restrictions in _computePenalty enables an attacker to bypass penalties partially or completely. By repeatedly calling _computePenalty, the attacker can reset monthly penalty percentages without any actual deduction being applied.

Root Cause

AirdropDistribution.sol #L190 In AirdropDistribution.sol, specifically within the _computePenalty function, there is no condition to prevent unauthorized calls that reset penaltyPercentageByMonth to zero for specific months, allowing potential misuse.

Internal pre-conditions

1.The attacker has an account ranked in the top 80% of the distribution. 2.The attacker can call _computePenalty before invoking claim to reset penalties. 3.The attacker sets monthsPassed to a non-zero value, resetting penalties across multiple months.

External pre-conditions

1.The Ethereum block timestamp is past the AIRDROP_INITIAL_START_TIME. 2.Low Ethereum gas prices allow repeated calls to be financially viable.

Attack Path

1.The attacker repeatedly calls _computePenalty, manipulating monthsPassed to reset penalty percentages. 2.Each call resets penaltyPercentageByMonth to zero without enforcing a claim or applying deductions. 3.Finally, the attacker calls claim without any penalties being deducted.

Impact

Stakers suffer a loss equivalent to all unpaid penalties, with funds reduced in line with the accumulated monthly penalty rates. The attacker gains the avoided penalty amount.

PoC

// SPDX-License-Identifier: GPL-3.0-or-later
pragma solidity >=0.8.0;

import "forge-std/Test.sol";
import "./AirdropDistribution.sol";

contract PenaltyTest is Test {
    AirdropDistribution airdrop;

    function setUp() public {
        airdrop = new AirdropDistribution();
    }

    // Wrapper function to access `_computePenalty` for testing purposes
    function computePenaltyWrapper(uint256 totalAmount, address account, uint256 monthsPassed) public returns (uint256) {
        return airdrop._computePenalty(totalAmount, account, monthsPassed);
    }

    function testAvoidPenalty() public {
        address attacker = address(0x123);
        uint256 totalAmount = 1000;
        uint256 monthsPassed = 3;

        // Initially compute penalty and verify penalty amount is applied
        uint256 penalty1 = computePenaltyWrapper(totalAmount, attacker, monthsPassed);
        
        // Call computePenaltyWrapper again and verify penalty is reset
        uint256 penalty2 = computePenaltyWrapper(totalAmount, attacker, monthsPassed);
        assertEq(penalty1, penalty2, "Penalty should be applied only once");
    }
}

Mitigation

1.Convert _computePenalty to a view function: This modification will ensure _computePenalty only calculates the penalty without modifying state variables, preventing any unauthorized resetting of penalties.

2.Reset Penalties Only in the claim Function: Implementing penalty resets solely in the claim function ensures that penalties are reset only upon an actual claim, eliminating the possibility of _computePenalty being used to manipulate penalty values.

3.Implement Security Checks in _computePenalty: Add security checks within _computePenalty to restrict unauthorized access and prevent unintended resets, providing additional safeguards against potential misuse.