Fractional v2 contest - 0xDjango's results

A collective ownership platform for NFTs on Ethereum.

General Information

Platform: Code4rena

Start Date: 07/07/2022

Pot Size: $75,000 USDC

Total HM: 32

Participants: 141

Period: 7 days

Judge: HardlyDifficult

Total Solo HM: 4

Id: 144

League: ETH

Fractional

Findings Distribution

Researcher Performance

Rank: 35/141

Findings: 3

Award: $344.41

🌟 Selected for report: 0

🚀 Solo Findings: 0

Findings Information

🌟 Selected for report: xiaoming90

Also found by: 0x29A, 0xDjango, 0xalpharush, Critical, Treasure-Seeker, ayeslick, infosec_us_team

Labels

bug
duplicate
3 (High Risk)

Awards

267.7106 USDC - $267.71

External Links

Lines of code

https://github.com/code-423n4/2022-07-fractional/blob/e2c5a962a94106f9495eb96769d7f60f7d5b14c9/src/modules/protoforms/BaseVault.sol#L58-L117

Vulnerability details

Impact

These three transfer functions allow an attacker to supply an arbitrary from and to to transfer ERC20s, ERC721s, and ERC1155s. The moment that a user sets approval for the contract to spend their tokens, an attacker can front-run the next call and steal the tokens for themselves.

Proof of Concept

This function allows anyone to transfer anyone's ERC20s given that the owner has already provided approval to the contract.

function batchDepositERC20( address _from, address _to, address[] calldata _tokens, uint256[] calldata _amounts ) external { for (uint256 i = 0; i < _tokens.length; ) { IERC20(_tokens[i]).transferFrom(_from, _to, _amounts[i]); unchecked { ++i; } } }

The same is true for the ERC721 and ERC1155 deposit functions.

Tools Used

Manual review.

Do not allow users to supply arbitrary to and from parameters to the token transfer functions.

#0 - 0x0aa0

2022-07-18T15:18:40Z

Duplicate of #468

Findings Information

Awards

14.6423 USDC - $14.64

Labels

bug
duplicate
2 (Med Risk)

External Links

Lines of code

https://github.com/code-423n4/2022-07-fractional/blob/e2c5a962a94106f9495eb96769d7f60f7d5b14c9/src/modules/Buyout.sol#L57-L98

Vulnerability details

Impact

All migration actions such as propose, join, leave, and commit require that the pool's buyout state is INACTIVE. At any point, a user can call buyout.Start() to start the buyout process which will change the buyout state to LIVE.

Proof of Concept

migration.join() for example looks as follows:

function join( address _vault, uint256 _proposalId, uint256 _amount ) external payable nonReentrant { // Reverts if address is not a registered vault (address token, uint256 id) = IVaultRegistry(registry).vaultToToken( _vault ); if (id == 0) revert NotVault(_vault); // Reverts if buyout state is not inactive (, , State current, , , ) = IBuyout(buyout).buyoutInfo(_vault); State required = State.INACTIVE; if (current != required) revert IBuyout.InvalidState(required, current); // Gets the migration proposal for the given ID Proposal storage proposal = migrationInfo[_vault][_proposalId]; // Updates ether balances of the proposal and caller proposal.totalEth += msg.value; userProposalEth[_proposalId][msg.sender] += msg.value; // Deposits fractional tokens into contract IFERC1155(token).safeTransferFrom( msg.sender, address(this), id, _amount, "" ); // Updates fraction balances of the proposal and caller proposal.totalFractions += _amount; userProposalFractions[_proposalId][msg.sender] += _amount; }

After the proposal has been created, this function allows users to transfer funds in support of the proposal. At any time, another user can start the buyout directly via Buyout.start() to change the buyout state to LIVE, therefore calls to propose, join, leave, and commit will revert.

Tools Used

Manual review.

Restrict Buyout.start() to be called from either the migrations contract or internally if used within a proxy structure.

#0 - 0x0aa0

2022-07-18T16:51:38Z

Duplicate of #87

#1 - HardlyDifficult

2022-08-02T21:54:21Z

QA Report

[L-01] Ownership transfer should be a two-step process

It is recommended that ownership transfer be completed in two steps, firstly by setting a pending admin and finally by accepting the change from the pending admin account.

https://github.com/code-423n4/2022-07-fractional/blob/e2c5a962a94106f9495eb96769d7f60f7d5b14c9/src/Vault.sol#L93-L97

[L-02] CEI Pattern not followed

I was not able to determine a valid attack vector arising from the ERC1155 transfer prior to updating ethBalance, though it would be wise to change the order.

https://github.com/code-423n4/2022-07-fractional/blob/e2c5a962a94106f9495eb96769d7f60f7d5b14c9/src/modules/Buyout.sol#L168-L176

[L-03] Use of transfer over call

It is recommended to use call in order to avoid potential future op code gas inflations.

https://github.com/code-423n4/2022-07-fractional/blob/e2c5a962a94106f9495eb96769d7f60f7d5b14c9/src/modules/Migration.sol#L172 https://github.com/code-423n4/2022-07-fractional/blob/e2c5a962a94106f9495eb96769d7f60f7d5b14c9/src/modules/Migration.sol#L325

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