Notional contest - leastwood's results

Fixed rates, now in crypto.

General Information

Platform: Code4rena

Start Date: 26/08/2021

Pot Size: $200,000 USDC

Total HM: 17

Participants: 11

Period: 14 days

Judge: ghoulsol

Total Solo HM: 12

Id: 23

League: ETH

Notional

Findings Distribution

Researcher Performance

Rank: 2/11

Findings: 8

Award: $35,784.57

🌟 Selected for report: 4

🚀 Solo Findings: 4

Findings Information

🌟 Selected for report: cmichel

Also found by: leastwood

Labels

bug
duplicate
3 (High Risk)

Awards

1557.1694 NOTE - $1,557.17

4671.5083 USDC - $4,671.51

External Links

Handle

leastwood

Vulnerability details

Impact

Notional's governance framework utilises a fork of Compound's Governor Alpha and ERC20 token. These are denoted specifically as the GovernorAlpha.sol and NoteERC20.sol contracts. However, the GovernorAlpha.sol has a key difference when compared to Compound's implementation of the same contract. Notional's Governor Alpha contract inherits Openzeppelin's TimelockController.sol contract. This enables Notional's governance framework to enforce a timelock on any proposals, giving users time to exit before a potentially dangerous maintenance operation is applied. TimelockController.sol's executeBatch() function is vulnerable to reentrancy as the check to see if the previous call has been executed is done after an external call is made. This allows an executor to hijack the contract and make unexpected changes to the Notional smart contract system.

Proof of Concept

Bug outlined here. Fix is outline in this commit.

Tools Used

Sourced from publicly disclosed post by Immnuefi.

Update Openzeppelin library to a version containing the commit fixing the bug (mentioned above). Tag v3.4.2-solc-0.7 in Openzeppelin's Github repository is an example of a compatible library that contains the aforementioned bug fix.

#0 - jeffywu

2021-09-11T18:16:32Z

Duplicate #58

Findings Information

🌟 Selected for report: leastwood

Labels

bug
3 (High Risk)
sponsor confirmed

Awards

3460.3765 NOTE - $3,460.38

10381.1295 USDC - $10,381.13

External Links

Handle

leastwood

Vulnerability details

Impact

The scripts/ folder outlines a number of deployment scripts used by the Notional team. Some of the contracts deployed utilise the ERC1967 upgradeable proxy standard. This standard involves first deploying an implementation contract and later a proxy contract which uses the implementation contract as its logic. When users make calls to the proxy contract, the proxy contract will delegate call to the underlying implementation contract. NoteERC20.sol and Router.sol both implement an initialize() function which aims to replace the role of the constructor() when deploying proxy contracts. It is important that these proxy contracts are deployed and initialized in the same transaction to avoid any malicious frontrunning. However, scripts/deployment.py does not follow this pattern when deploying NoteERC20.sol's proxy contract. As a result, a malicious attacker could monitor the Ethereum blockchain for bytecode that matches the NoteERC20 contract and frontrun the initialize() transaction to gain ownership of the contract. This can be repeated as a Denial Of Service (DOS) type of attack, effectively preventing Notional's contract deployment, leading to unrecoverable gas expenses.

Proof of Concept

https://github.com/code-423n4/2021-08-notional/blob/main/scripts/deployment.py#L44-L60 https://github.com/code-423n4/2021-08-notional/blob/main/scripts/mainnet/deploy_governance.py#L71-L105

Tools Used

Manual code review

As the GovernanceAlpha.sol and NoteERC20.sol are co-dependent contracts in terms of deployment, it won't be possible to deploy the governance contract before deploying and initializing the token contract. Therefore, it would be worthwhile to ensure the NoteERC20.sol proxy contract is deployed and initialized in the same transaction, or ensure the initialize() function is callable only by the deployer of the NoteERC20.sol contract. This could be set in the proxy contracts constructor().

Findings Information

🌟 Selected for report: leastwood

Labels

bug
3 (High Risk)
sponsor confirmed

Awards

3460.3765 NOTE - $3,460.38

10381.1295 USDC - $10,381.13

External Links

Handle

leastwood

Vulnerability details

Impact

There are a number of contracts which inherit UUPSUpgradeable.sol, namely; GovernanceAction.sol, PauseRouter.sol and NoteERC20.sol. All these contracts are deployed using a proxy pattern whereby the implementation contract is used by the proxy contract for all its logic. The proxy contract will make delegate calls to the implementation contract. This helps to facilitate future upgrades by pointing the proxy contract to a new and upgraded implementation contract. However, if the implementation contract is left uninitialized, it is possible for any user to gain ownership of the onlyOwner role in the implementation contract for NoteERC20.sol. Once the user has ownership they are able to perform an upgrade of the implementation contract's logic contract and delegate call into any arbitrary contract, allowing them to self-destruct the proxy's implementation contract. Consequently, this will prevent all NoteERC20.sol interactions until a new implementation contract is deployed.

Proof of Concept

Initial information about this issue was found here.

Consider the following scenario:

  • Notional finance deploys their contracts using their deployment scripts. These deployment scripts leave the implementation contracts uninitialized. Specifically the contract in question is NoteERC20.sol.
  • This allows any arbitrary user to call initialize() on the NoteERC20.sol implementation contract.
  • Once a user has gained control over NoteERC20.sol's implementation contract, they can bypass the _authorizeUpgrade check used to restrict upgrades to the onlyOwner role.
  • The malicious user then calls UUPSUpgradeable.upgradeToAndCall() shown here which in turn calls this function. The new implementation contract then points to their own contract containing a self-destruct call in its fallback function.
  • As a result, the implementation contract will be self-destructed due the user controlled delegate call shown here, preventing all future calls to the NoteERC20.sol proxy contract until a new implementation contract has been deployed.

Tools Used

Manual code review

Consider initializing the implementation contract for NoteERC20.sol and checking the correct permissions before deploying the proxy contract or performing any contract upgrades. This will help to ensure the implementation contract cannot be self-destructed.

#0 - jeffywu

2021-09-11T13:44:18Z

Acknowledged, I don't think this should be categorized high risk because the worst case is a denial of service and a redeployment of the ERC20 contract. As it stands, we've already successfully deployed our ERC20 contract so this is a non-issue.

I would categorize as 0 (Non-critical)

#1 - sockdrawermoney

2021-09-11T14:21:34Z

Warden leastwood added this proof of concept to illustrate the vulnerability https://gist.github.com/leastwood/b23d9e975883c817780116c2ceb785b8

#2 - jeffywu

2021-09-11T14:24:40Z

Ok I retract my previous statement, I misread the issue description. Up to you guys but do you want to pay out a full amount to someone who is reporting issues discovered elsewhere? OZ has already called initialize on our deployed contract for us.

#3 - sockdrawermoney

2021-09-12T20:37:57Z

@jeffywu I think the question is whether the issue is valid based on the original code base. Given your initial response and change after his proof of concept, my read was there was value here in what he reported. Is that a correct understanding?

#4 - jeffywu

2021-09-12T20:42:53Z

There was value added here but perhaps not at the same level as the other high risk issues.

#5 - sockdrawermoney

2021-09-13T00:27:50Z

@jeffywu Thanks for the input. As per our rules, awards are determined strictly based on the judge's assessment of the validity and severity, so we'll see how our judge chooses to score this.

Findings Information

🌟 Selected for report: leastwood

Also found by: JMukesh

Labels

bug
1 (Low Risk)
sponsor confirmed

Awards

155.7169 NOTE - $155.72

467.1508 USDC - $467.15

External Links

Handle

leastwood

Vulnerability details

Impact

The current ownership transfer process involves the current owner calling NoteERC20.transferOwnership(). This function checks the new owner is not the zero address and proceeds to write the new owner's address into the owner's state variable. If the nominated EOA account is not a valid account, it is entirely possible the owner may accidentally transfer ownership to an uncontrolled account, breaking all functions with the onlyOwner() modifier.

Proof of Concept

https://github.com/code-423n4/2021-08-notional/blob/main/contracts/external/governance/NoteERC20.sol#L123-L127

Tools Used

Manual code review

Consider implementing a two step process where the owner nominates an account and the nominated account needs to call an acceptOwnership() function for the transfer of ownership to fully succeed. This ensures the nominated EOA account is a valid and active account.

Findings Information

🌟 Selected for report: leastwood

Labels

bug
G (Gas Optimization)
sponsor confirmed

Awards

312.5 NOTE - $312.50

937.5 USDC - $937.50

External Links

Handle

leastwood

Vulnerability details

Impact

The StorageLayoutV1.sol contract is inherited by several contracts and represents a shared common state that ensures the slot layout of certain contracts are the same. It is possible to minimise the number of storage slots used by rearranging the state variables in the most efficient way.

Proof of Concept

https://github.com/code-423n4/2021-08-notional/blob/main/contracts/global/StorageLayoutV1.sol

Tools Used

Manual code review

Arrange the uint16 and bytes1 variables such that they fit into the same slot.

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