KUMA Protocol - Versus contest - AkshaySrivastav's results

Bringing yield from Real World Assets to DeFi.

General Information

Platform: Code4rena

Start Date: 17/02/2023

Pot Size: $38,600 USDC

Total HM: 5

Participants: 5

Period: 5 days

Judge: GalloDaSballo

Total Solo HM: 2

Id: 217

League: ETH

KUMA Protocol

Findings Distribution

Researcher Performance

Rank: 5/5

Findings: 2

Award: $0.00

🌟 Selected for report: 0

🚀 Solo Findings: 0

Findings Information

🌟 Selected for report: bin2chen

Also found by: 0xsomeone, AkshaySrivastav, hihen

Labels

bug
3 (High Risk)
satisfactory
sponsor confirmed
duplicate-3

Awards

Data not available

External Links

Lines of code

https://github.com/code-423n4/2023-02-kuma/blob/main/src/kuma-protocol/KIBToken.sol#L276-L292

Vulnerability details

Impact

The KIBToken._transfer function overrides the ERC20Upgradeable._transfer function and adds custom logic.

The modified function looks like this:

function _transfer(address from, address to, uint256 amount) internal override {
    // ...

    uint256 startingFromBalance = this.balanceOf(from);
    if (startingFromBalance < amount) {
        revert Errors.ERC20_TRANSFER_AMOUNT_EXCEEDS_BALANCE();
    }
    uint256 newFromBalance = startingFromBalance - amount;
    uint256 newToBalance = this.balanceOf(to) + amount;

    uint256 previousEpochCumulativeYield_ = _previousEpochCumulativeYield;
    uint256 newFromBaseBalance = WadRayMath.wadToRay(newFromBalance).rayDiv(previousEpochCumulativeYield_);
    uint256 newToBaseBalance = WadRayMath.wadToRay(newToBalance).rayDiv(previousEpochCumulativeYield_);

    if (amount > 0) {
        _totalBaseSupply -= (_baseBalances[from] - newFromBaseBalance);
        _totalBaseSupply += (newToBaseBalance - _baseBalances[to]);
        _baseBalances[from] = newFromBaseBalance;
        _baseBalances[to] = newToBaseBalance;
    }

    // ...
}

It can be seen that while performing the transfer of amount tokens, the function cache the token balances of from and to in temporary variables. These cached values do not represent the actual balances of accounts in an edge case.

This implementation of _transfer function can be exploited by any KIBToken holder by passing their own address as the to parameter. When the from and to parameters are equal the function simply doubles the balance of that respective account. So any token holder holding x token at the start of function invocation will have 2x token at the end of invocation.

The bug can be repeated infinitely to gain a huge KIBToken token balance. This huge token balance can be used to drain assets from other contracts of the protocol, as well as to drain liquidity pools of KIBToken.

Proof of Concept

This test case was added to test/kuma-protocol/kib-token/KIBToken.transfer.t.sol and ran using forge test -m test_audit.

function test_audit_doubleMoneyBug() public {
    address alice = makeAddr("alice");
    assertEq(_KIBToken.balanceOf(alice), 0);        // Initial balance is 0

    _KIBToken.mint(alice, 100e18);                  // Tokens minted
    assertEq(_KIBToken.balanceOf(alice), 100e18);   // Balance is now 100e18

    vm.startPrank(alice);
    _KIBToken.transfer(alice, 100e18);              // Tokens transferred to self

    assertEq(_KIBToken.balanceOf(alice), 200e18);   // Balance is doubled 200e18
}

Tools Used

Forge

Consider adding a check require(from != to) in the _transfer function. Or, always try to reference the storage parameters directly instead of storing values in temporary variables.

#0 - c4-judge

2023-02-23T13:42:52Z

GalloDaSballo marked the issue as primary issue

#1 - GalloDaSballo

2023-02-23T13:43:00Z

Example of a short and sweet description with good POC

#2 - c4-judge

2023-02-26T19:51:22Z

GalloDaSballo marked the issue as duplicate of #3

#3 - GalloDaSballo

2023-02-26T19:52:23Z

Removed primary due to inaccuracy in statements I will not penalize further though as I believe the POC offered covers the exploit sufficiently

#4 - c4-judge

2023-02-26T19:59:28Z

GalloDaSballo marked the issue as satisfactory

#5 - c4-sponsor

2023-02-28T03:11:22Z

m19 marked the issue as sponsor confirmed

Findings Information

🌟 Selected for report: hihen

Also found by: 0x52, 0xsomeone, AkshaySrivastav, bin2chen

Labels

bug
2 (Med Risk)
satisfactory
duplicate-13

Awards

Data not available

External Links

Lines of code

https://github.com/code-423n4/2023-02-kuma/blob/main/src/kuma-protocol/KUMAFeeCollector.sol#L152

Vulnerability details

Impact

In KUMAFeeCollector contract, the addPayee validates that an already present payee cannot be added again to the _payees set.

    function addPayee(address payee, uint256 share) external override onlyManager {
        if (_payees.contains(payee)) {
            revert Errors.PAYEE_ALREADY_EXISTS();
        }
        // ...
    }

However a similar check is not present in the changePayees function. https://github.com/code-423n4/2023-02-kuma/blob/main/src/kuma-protocol/KUMAFeeCollector.sol#L152

So a single payee can be added multiple times to the _payees set using the changePayees function.

Proof of Concept

Consider this scenario:

  • KUMAFeeCollector is deployed and Account1 and Account2 are intended to be added as payees with 10 share each.
  • Using the addPayee function each account can be added only once.
  • But using the changePayees function, Account1 can be added twice to the _payees set.

The final payees list looks like this:

  • Account1 - 10 shares
  • Account2 - 10 shares
  • Account1 - 10 shares
  • _totalShares = 30

Tools Used

Manual review

Consider adding a check in changePayees function also which prevent addition of duplicate payee entries.

#0 - c4-judge

2023-02-26T19:53:40Z

GalloDaSballo marked the issue as duplicate of #13

#1 - GalloDaSballo

2023-02-26T19:53:48Z

Awarding 50% due to lack of detail in terms what goes wrong vs primary

#2 - c4-judge

2023-02-26T19:53:51Z

GalloDaSballo marked the issue as partial-50

#3 - akshaysrivastav

2023-03-01T04:58:25Z

Hey @GalloDaSballo I think this report also mentions all the necessary technical details as menttioned in #13. Just that, I intended the report to be precise and small.

As you can see, the example scenario above shows the exact _totalShares and individual shares values.

#4 - c4-judge

2023-03-01T11:21:04Z

GalloDaSballo marked the issue as full credit

#5 - GalloDaSballo

2023-03-01T11:21:25Z

After re-reading, I agree that the finding shows the issue with accounting, restoring full credit

#6 - c4-judge

2023-03-01T16:44:45Z

GalloDaSballo marked the issue as satisfactory

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax © 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter