GithubHelp home page GithubHelp logo

2023-01-tessera-mitigation-findings's Introduction

Tessera Mitigation Contest

Unless otherwise discussed, this repo will be made public after contest completion, sponsor review, judging, and two-week issue mitigation window.

Contributors to this repo: prior to report publication, please review the Agreements & Disclosures issue.


Contest findings are submitted to this repo

As a sponsor, you have three critical tasks in the contest process:

  1. Weigh in on severity.
  2. Respond to issues.
  3. Share your mitigation of findings.

Let's walk through each of these.

High and Medium Risk Issues

Please note: because wardens submit issues without seeing each other's submissions, there will always be findings that are duplicates. For all issues labeled 3 (High Risk) or 2 (Medium Risk), these have been pre-sorted for you so that there is only one primary issue open per unique finding. All duplicates have been labeled duplicate, linked to a primary issue, and closed.

Weigh in on severity

Judges have the ultimate discretion in determining severity of issues, as well as whether/how issues are considered duplicates. However, sponsor input is a significant criteria.

For a detailed breakdown of severity criteria and how to estimate risk, please refer to the judging criteria in our documentation.

If you disagree with a finding's severity, leave the severity label intact and add the label disagree with severity, along with a comment indicating your opinion for the judges to review. It is possible for issues to be considered 0 (Non-critical).

Feel free to use the question label for anything you would like additional C4 input on.

Please don't change the severity labels; that's up to the judge's discretion.

Respond to issues

Label each open/primary High or Medium risk finding as one of these:

  • sponsor confirmed, meaning: "Yes, this is a problem and we intend to fix it."
  • sponsor disputed, meaning either: "We cannot duplicate this issue" or "We disagree that this is an issue at all."
  • sponsor acknowledged, meaning: "Yes, technically the issue is correct, but we are not going to resolve it for xyz reasons."

(Note: please don't use sponsor disputed for a finding if you think it should be considered of lower or higher severity. Instead, use the label disagree with severity and add comments to recommend a different severity level -- and include your reasoning.)

Add any necessary comments explaining your rationale for your evaluation of the issue. Note that when the repo is public, after all issues are mitigated, wardens will read these comments.

QA and Gas Reports

For low and non-critical findings (AKA QA), as well as gas optimizations: all warden submissions in these three categories should now be submitted as bulk listings of issues and recommendations:

  • QA reports should include all low severity and non-critical findings, along with a summary statement.
  • Gas reports should include all gas optimization recommendations, along with a summary statement.

For QA and Gas reports, we ask that you:

  • Leave a comment for the judge on any reports you consider to be particularly high quality. (These reports will be awarded on a curve.)
  • Add the sponsor disputed label to any reports that you think should be completely disregarded by the judge, i.e. the report contains no valid findings at all.

Once labelling is complete

When you have finished labelling findings, drop the C4 team a note in your private Discord backroom channel and let us know you've completed the sponsor review process. At this point, we will pass the repo over to the judge to review your feedback while you work on mitigations.

Share your mitigation of findings

Note: this section does not need to be completed in order to finalize judging. You can continue work on mitigations while the judge finalizes their decisions and even beyond that. Ultimately we won't publish the final audit report until you give us the ok.

For each finding you have confirmed, you will want to mitigate the issue before the contest report is made public.

As you undertake that process, we request that you take the following steps:

  1. Within your own GitHub repo, create a pull request for each finding.
  2. Link the PR to the issue that it resolves within your contest findings repo.

This will allow for complete transparency in showing the work of mitigating the issues found in the contest. Do not close the issue; simply label it as resolved. If the issue in question has duplicates, please link to your PR from the open/primary issue.

2023-01-tessera-mitigation-findings's People

Contributors

code423n4 avatar itsmetechjay avatar

Watchers

Ashok avatar  avatar  avatar

2023-01-tessera-mitigation-findings's Issues

User might not be able to claim refund when the NFT is bought for less than the minimum reserve price

Lines of code

https://github.com/fractional-company/modular-fractional/blob/fc15c85069d8d55cfe840d4c313754c77f18979f/src/modules/GroupBuy.sol#L199

Vulnerability details

Impact

User might not be able to claim refund when the NFT is bought for less than the minimum reserve price because the minReservePrices is rounded down, which make the contract refund sightly more eth to each user. In most case, the last user will not be able to claim since the contract will not have sufficient fund.

Proof of Concept

https://github.com/fractional-company/modular-fractional/blob/fc15c85069d8d55cfe840d4c313754c77f18979f/src/modules/GroupBuy.sol#L199

minReservePrices[_poolId] = _price / filledQuantity;

https://github.com/fractional-company/modular-fractional/blob/fc15c85069d8d55cfe840d4c313754c77f18979f/src/modules/GroupBuy.sol#L260-L268

                contribution -= quantity * reservePrice;
            }

            // Mints total quantity of Raes to caller
            _mintRaes(poolToVault[_poolId], msg.sender, totalQty, _mintProof);
        }

        // Transfers remaining contribution balance back to caller
        payable(msg.sender).call{value: contribution}("");
  1. Alice and Bob each contributed 100 wei at 100 per rae
  2. NFT bought with 195 wei
  3. _price / filledQuantity = 195 / 2 = 97
  4. Alice call claim, got 100 - 97 = 3 wei refund
  5. The contract now have 100 + 100 - 195 - 97 = 2 wei
  6. Bob try to call claim, reverted because the contract try to send 3 wei but only have 2 wei

Recommended Mitigation Steps

Round up minReservePrices

Mitigation of M-04: See comments

Lines of code

https://github.com/fractional-company/modular-fractional/blob/160e893f29c47836eab808ddd52f168c0629a5ef/src/modules/GroupBuy.sol#L301

Vulnerability details

The PR does NOT fix the issue described in the finding, and instead addresses issue 45. The change breaks out of the loop, which solves the case where the price is the same as the lowest bid, but doesn't address the case where the price is higher than the lowest, and only kicks out part of the lowest bid.

Impact

Same as the prior finding

Proof of Concept

The POC is the same as the prior finding, and the example tree would be:

            A:(p:100,q:10)
            /             \
       B:(p:100,q:10)  C:(<whatever>)
       /           \
D:(p:102,q:10)   E:(<whatever>) 

with F:(p:101,q:5) being inserted. There has been no change to re-shuffle the node that has had its quantity reduced, once F is added

Tools Used

Code inspection

Recommended Mitigation Steps

Same as before: when modifying nodes of the tree, remove them first, then re-add them after modification

Mitigation Confirmed for H-08

code-423n4/2022-12-tessera-findings#47

The vault that is returned by the _market contract (after the execute call) is now validated. Note that the _market is still not validated, so an attacker could in theory still provide his address there, get the ETH, use it to buy the NFT (if it is available cheaper somewhere), transfer it to the (legitimate) vault and pocket the difference. However, I do not think that this is considered a vulnerability in the context of this protocol, as this "attack" could also be performed with a legitimate market (increasing the listing price to the maximum value that the protocol is willing to pay) by an NFT owner.

Mitigation of M-03: See comments

Lines of code

https://github.com/fractional-company/modular-fractional/blob/0404f5c96b980bc4dafd09f99ae09ae804aec22e/src/modules/GroupBuy.sol#L108-L114

Vulnerability details

The PR does not follow the recommended mitigation from the finding, and instead still allows under-priced bids to be added if the total value being added is at least a multiple of the minimum reserve price.

Impact

If, for example, the reserve price is 10 Eth, someone can bid 1 Eth with a quantity of 10, and still hit the original Medium-severity bug.

Proof of Concept

        // Reverts if ether contribution amount per Rae is less than minimum bid or reserve price per Rae
        {
            uint256 minPrice = (totalSupply == filledQuantities[_poolId])
                ? minReservePrices[_poolId]
                : minBidPrices[_poolId];
            if (msg.value < _quantity * minPrice || _quantity == 0) revert InvalidContribution();
        }

https://github.com/fractional-company/modular-fractional/blob/0404f5c96b980bc4dafd09f99ae09ae804aec22e/src/modules/GroupBuy.sol#L108-L114

Tools Used

Code inspection

Recommended Mitigation Steps

As in the original finding, revert() if the price is lower than the min bid, and the queue is already full

Mitigation Confirmed for H-01

The review comments for PR 204 request a change from using require() to a custom error. Ignoring that potential change, the code as it stands applies the recommended mitigation from the finding.

Mitigation Confirmed for H-09

The PR changes the state to success before execution, and includes the fix for H-08. Contrary to the finding's recommendation, reentrancy guards have not been added, but they are not needed, since claim() will revert since the vault address isn't set yet, and withdrawBalance() does not misbehave if called via a reentrant call.

Mitigation Confirmed for H-07

The PR properly applies the recommended mitigation from the finding, adds an automatic withdrawal in cases where the sender is the old active listing proposer, and also addresses H-04.

Mitigation of M-08: See comments

Lines of code

https://github.com/fractional-company/modular-fractional/blob/160e893f29c47836eab808ddd52f168c0629a5ef/src/modules/GroupBuy.sol#L301-L307

Vulnerability details

The PR applies the recommended mitigation from the finding, but the original finding's mitigation suggestion seems to indicated that the If two users place bids at the same price but with different quantities, the queue will pull from the bid with a higher quantity first. invariant should be violated.

Impact

The ordering invariant will be violated

Proof of Concept

If the price is equal to the lowest bid price but has a smaller quantity, the node won't be inserted as it should be:

            if (_price <= lowestBid.price) {
                break;
            }


            uint256 lowestBidQuantity = lowestBid.quantity;
            // Checks if lowest bid quantity amount is greater than given quantity amount
            if (lowestBidQuantity > quantity) {

https://github.com/fractional-company/modular-fractional/blob/160e893f29c47836eab808ddd52f168c0629a5ef/src/modules/GroupBuy.sol#L301-L307

Tools Used

Code inspection

Recommended Mitigation Steps

- if (_price < lowestBid.price) {
+ if (_price < lowestBid.price || (_price == lowestBid.price && lowestBidQuantity == quantity)) {

Mitigation Confirmed for M-09

code-423n4/2022-12-tessera-findings#49

This fixes the issue because the target amount was completely eliminated and the initial contribution is now used. However, it also introduces a semantic change. Previously, it was possible for the deployer to create a pool and contribute initially more than the min bid price. This is no longer possible (but probably not a huge problem, if this is desired, the deployer could also do a very small contribution when creating and then a larger one afterwards).

Attacker can steal the NFT bought by sending it to another vault he control

Lines of code

https://github.com/fractional-company/modular-fractional/blob/d0974eef922c3087ed9c1b8d758fe66307734c23/src/modules/GroupBuy.sol#L214

Vulnerability details

Impact

The mitigation of H-08 try to validate the vault returned by _market with the VaultRegistry. However, it only validated if the vault exists, but not if it is the correct vault. A similar attack described in code-423n4/2022-12-tessera-findings#47 can be carried out by using a valid vault address that is permissionlessly deployed with VaultRegistry.createFor but have the owner set to the attacker.

Proof of Concept

https://github.com/fractional-company/modular-fractional/blob/d0974eef922c3087ed9c1b8d758fe66307734c23/src/modules/GroupBuy.sol#L214-L215

        (, uint256 id) = IVaultRegistry(registry).vaultToToken(vault);
        if (id == 0) revert NotVault();
  1. Group assembles and raises funds to buy NFT X
  2. Attacker deploy a valid vault using VaultRegistry.createFor but setting himself as the owner, with a merkle root that enable NFT transfer
  3. Attacker calls purchase() and supplies their malicious contract in _market, returning the vault generated above
  4. Attacker call Vault.execute in the vault to retrieve the NFT to his own wallet
  5. Attacker receives the NFT bought by the raised funds with 0 cost except gas

https://github.com/fractional-company/modular-fractional/blob/9411afcd03d457192adc2bc59b3b378aeddd5865/src/Vault.sol#L36

    function execute(
        address _target,
        bytes calldata _data,
        bytes32[] calldata _proof
    ) external payable returns (bool success, bytes memory response) {
        bytes4 selector;
        assembly {
            selector := calldataload(_data.offset)
        }

        // Generate leaf node by hashing module, target and function selector.
        bytes32 leaf = keccak256(abi.encode(msg.sender, _target, selector));
        // Check that the caller is either a module with permission to call or the owner.
        if (!MerkleProof.verify(_proof, MERKLE_ROOT(), leaf)) {
            if (msg.sender != FACTORY() && msg.sender != OWNER())
                revert NotAuthorized(msg.sender, _target, selector);
        }

        (success, response) = _execute(_target, _data);
    }

Recommended Mitigation Steps

Also check the owner of the vault

Mitigation Confirmed for M-04

code-423n4/2022-12-tessera-findings#32

The comparison now uses <=, the described attack scenario no longer works. However, this also changes the behaviour when a new bid is inserted with the same price as the minimum price, as the new bid will not be filled at all now. I am not sure if this change in behaviour is intended or not, as it means that a new bidder needs to bid higher (although the new bid can only be 1 wei higher, so this might be a design decision to do it now like that).

Mitigation of H-02: See comments

Lines of code

https://github.com/fractional-company/modular-fractional/blob/fc15c85069d8d55cfe840d4c313754c77f18979f/src/modules/GroupBuy.sol#L198-L199

Vulnerability details

The PR applies the recommended mitigation from the finding, but doesn't take into account the rounding issue identified in M-09

Impact

If the price the NFT is bought for is not an exact multiple of the filledQuantities, there will be a loss of precision, and during the calculation of refunds, each user will get back more than they should, which will leave the last user with not enough funds to withdraw. It is much more likely for the price not to be an exact multiple than it is for it to be one, so most GroupBuys will have this issue.

Proof of Concept

The division will have a loss of precision:

        // Calculates actual min reserve price based on purchase price
        minReservePrices[_poolId] = _price / filledQuantity;

https://github.com/fractional-company/modular-fractional/blob/fc15c85069d8d55cfe840d4c313754c77f18979f/src/modules/GroupBuy.sol#L198-L199

And the same example the judge used in finding M-9 would still apply

Tools Used

Code inspection

Recommended Mitigation Steps

Decrease the total number of Raes if the price is not a multiple of the current total, so that it becomes a multiple

Agreements & Disclosures

Agreements

If you are a C4 Certified Contributor by commenting or interacting with this repo prior to public release of the contest report, you agree that you have read the Certified Warden docs and agree to be bound by:

To signal your agreement to these terms, add a ๐Ÿ‘ emoji to this issue.

Code4rena staff reserves the right to disqualify anyone from this role and similar future opportunities who is unable to participate within the above guidelines.

Disclosures

Sponsors may elect to add team members and contractors to assist in sponsor review and triage. All sponsor representatives added to the repo should comment on this issue to identify themselves.

To ensure contest integrity, the following potential conflicts of interest should also be disclosed with a comment in this issue:

  1. any sponsor staff or sponsor contractors who are also participating as wardens
  2. any wardens hired to assist with sponsor review (and thus presenting sponsor viewpoint on findings)
  3. any wardens who have a relationship with a judge that would typically fall in the category of potential conflict of interest (family, employer, business partner, etc)
  4. any other case where someone might reasonably infer a possible conflict of interest.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.