Holograph contest - 0x52's results

Omnichain protocol for deploying, minting, & bridging NFTs between blockchains.

General Information

Platform: Code4rena

Start Date: 18/10/2022

Pot Size: $75,000 USDC

Total HM: 27

Participants: 144

Period: 7 days

Judge: gzeon

Total Solo HM: 13

Id: 170

League: ETH

Holograph

Findings Distribution

Researcher Performance

Rank: 4/144

Findings: 4

Award: $4,660.40

QA:
grade-c

🌟 Selected for report: 1

πŸš€ Solo Findings: 1

Findings Information

🌟 Selected for report: 0xA5DF

Also found by: 0x52

Labels

bug
duplicate
3 (High Risk)
resolved
sponsor disputed
responded

Awards

1952.9001 USDC - $1,952.90

External Links

Lines of code

https://github.com/code-423n4/2022-10-holograph/blob/f8c2eae866280a1acfdc8a8352401ed031be1373/contracts/HolographOperator.sol#L301-L439

Vulnerability details

Impact

Operators maliciously slashed

Proof of Concept

A user can create a malicious token that when called by anyone other than themselves and the bridge use an extreme amount of gas. They create a bridge request with a gas limit higher than the block limit. If an operator tries to call execute they will always run out of gas. Meanwhile the malicious user can call the token for very little gas. The malicious user calls the request to slash the operator

Tools Used

Manual Review

Ensure gas limit is not higher than destination block gas limit

#0 - Minh-Trng

2022-10-25T20:45:27Z

a low level call will retain some gas for the parent https://eips.ethereum.org/EIPS/eip-150 so the rest of the code should still be able to execute

#1 - gzeoneth

2022-10-28T08:56:44Z

If the gasLimit is above block/tx gas limit, this will always revert and no one can execute the job and no slashing can occur.

Also attacker need to pay gasPrice * gasLimit upfront which can be huge if the gasLimit is set to very high.

#2 - gzeoneth

2022-10-31T12:31:53Z

Can be a duplicate of #364

#3 - 0xA5DF

2022-10-31T12:52:16Z

#364 makes the attack cheaper, but even if #364 was fixed, the attack would still be possible, and as I've shown at #414 it can cost a few bucks to do it on Polygon and Avalanche.

#4 - gzeoneth

2022-11-19T16:16:52Z

I don't think slashing is possible, the block gas limit issue is a dupe of #414

Findings Information

🌟 Selected for report: Chom

Also found by: 0x52, 0xA5DF, adriro, ladboy233

Labels

bug
duplicate
3 (High Risk)
sponsor confirmed
responded

Awards

168.7306 USDC - $168.73

External Links

Lines of code

https://github.com/code-423n4/2022-10-holograph/blob/f8c2eae866280a1acfdc8a8352401ed031be1373/contracts/HolographOperator.sol#L301-L439

Vulnerability details

Impact

Users tokens are still burned at source chain with no way to recover them

Proof of Concept

try HolographOperatorInterface(address(this)).nonRevertingBridgeCall{value: msg.value}( msg.sender, bridgeInRequestPayload ) { /// @dev do nothing } catch { _failedJobs[hash] = true; emit FailedOperatorJob(hash); }

When a bridging call fails, nothing is done on the destination chain. When sending the message from the source chain their tokens work burned. Since the destination call failed, no tokens were minted on the destination chain. This means their source tokens have been burned and they never received any tokens on the destination chain, leaving them with no tokens.

Tools Used

Manual Review

Create a function allowing users to create a message back to the source chain for failed transactions and a function that allows them to remint on source chain.

#0 - gzeoneth

2022-10-31T13:17:48Z

Duplicate of #102

#1 - ACC01ADE

2022-11-09T15:03:07Z

This will be properly implemented in the next update.

Findings Information

🌟 Selected for report: 0x52

Labels

bug
2 (Med Risk)
sponsor confirmed
selected for report
responded

Awards

2538.7702 USDC - $2,538.77

External Links

Lines of code

https://github.com/code-423n4/2022-10-holograph/blob/f8c2eae866280a1acfdc8a8352401ed031be1373/contracts/enforcer/PA1D.sol#L665-L675

Vulnerability details

Impact

bidShares returned are incorrect leading to incorrect royalties

Proof of Concept

Zora Market

function isValidBidShares(BidShares memory bidShares) public pure override returns (bool) { return bidShares.creator.value.add(bidShares.owner.value).add( bidShares.prevOwner.value ) == uint256(100).mul(Decimal.BASE); }

Above you can see the Zora market lines that validate bidShares, which shows that Zora market bidShare.values should be percentages written out to 18 decimals. However PA1D#bidSharesForToken sets the bidShares.creator.value to the raw basis points set by the owner, which is many order of magnitudes different than expected.

Tools Used

Manual Review

To return the proper value, basis points returned need to be adjusted. Convert from basis points to percentage by dividing by 10 ** 2 (100) then scale to 18 decimals. The final result it to multiple the basis point by 10 ** (18 - 2) or 10 ** 16:

function bidSharesForToken(uint256 tokenId) public view returns (ZoraBidShares memory bidShares) { // this information is outside of the scope of our bidShares.prevOwner.value = 0; bidShares.owner.value = 0; if (_getReceiver(tokenId) == address(0)) { - bidShares.creator.value = _getDefaultBp(); + bidShares.creator.value = _getDefaultBp() * (10 ** 16); } else { - bidShares.creator.value = _getBp(tokenId); + bidShares.creator.value = _getBp(tokenId) * (10 ** 16); } return bidShares; }

#0 - trust1995

2022-10-30T20:24:48Z

Nice find!

#1 - alexanderattar

2022-11-08T21:04:33Z

Good catch! We'll implement the suggested solution.

Lines of code

https://github.com/code-423n4/2022-10-holograph/blob/f8c2eae866280a1acfdc8a8352401ed031be1373/contracts/enforcer/PA1D.sol#L382-L399

Vulnerability details

Impact

Unexpected reverts or portion of ETH permanently stuck in contract

Proof of Concept

uint256 gasCost = (23300 * length) + length; uint256 balance = address(this).balance; require(balance - gasCost > 10000, "PA1D: Not enough ETH to transfer");

When calculating gasCost, it is accidentally calculated using 23300 instead of 2300, which is the actual stipend for an ETH transfer. This can lead to unexpected reverts since gas costs is calculated incorrectly.

Tools Used

Manual Review

Fix gas cost calculations by using the proper stipend for transfer:

- uint256 gasCost = (23300 * length) + length; + uint256 gasCost = (2300 * length) + length; uint256 balance = address(this).balance; require(balance - gasCost > 10000, "PA1D: Not enough ETH to transfer");

#0 - gzeoneth

2022-10-28T09:32:28Z

unsure if this is an intended behavior 21000 + 2300 = 23300 and also low risk

#1 - gzeoneth

2022-10-28T09:35:55Z

Also #106 mentioned gasPrice should be considered.

#2 - alexanderattar

2022-11-08T21:18:24Z

The code mentioned will be refactored based on this and other similar issues raised by wardens

#3 - gzeoneth

2022-11-21T07:13:46Z

As QA report

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