Canto contest - cccz's results

Execution layer for original work.

General Information

Platform: Code4rena

Start Date: 14/06/2022

Pot Size: $100,000 USDC

Total HM: 26

Participants: 59

Period: 7 days

Judge: GalloDaSballo

Total Solo HM: 9

Id: 133

League: ETH

Canto

Findings Distribution

Researcher Performance

Rank: 2/59

Findings: 17

Award: $11,649.33

🌟 Selected for report: 2

🚀 Solo Findings: 0

Findings Information

🌟 Selected for report: Soosh

Also found by: 0x52, 0xDjango, TerrierLover, WatchPug, cccz, saian, zzzitron

Labels

bug
duplicate
3 (High Risk)

Awards

194.9666 USDC - $194.97

1207.2233 CANTO - $194.97

External Links

Lines of code

https://github.com/Plex-Engineer/lending-market/blob/755424c1f9ab3f9f0408443e6606f94e4f08a990/contracts/WETH.sol#L85-L88

Vulnerability details

Impact

The approve function of the WETH contract allows the user to spend anyone else's weth

function approve(address owner, address spender) external returns(bool) { _approve(owner, spender, _balanceOf[owner]); return true; } function _approve( address owner, address spender, uint256 amount ) internal { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); _allowance[owner][spender] = amount; emit Approval(owner, spender, amount); }

Proof of Concept

https://github.com/Plex-Engineer/lending-market/blob/755424c1f9ab3f9f0408443e6606f94e4f08a990/contracts/WETH.sol#L85-L88

Tools Used

None

Modify the approve function as follows

function approve(address spender) external returns(bool) { _approve(msg.sender, spender, _balanceOf[msg.sender]); return true; }

#0 - tkkwon1998

2022-06-21T03:28:20Z

duplicate of issue #19

Findings Information

🌟 Selected for report: cccz

Also found by: WatchPug

Labels

bug
3 (High Risk)
sponsor confirmed

Awards

1467.456 USDC - $1,467.46

9086.4148 CANTO - $1,467.46

External Links

Lines of code

https://github.com/Plex-Engineer/lending-market/blob/ab31a612be354e252d72faead63d86b844172761/contracts/Accountant/AccountantDelegate.sol#L74-L92

Vulnerability details

Impact

When the user borrows note tokens, the AccountantDelegate contract provides note tokens and gets cnote tokens. Later, when the user repays the note tokens, the cnote tokens are destroyed and the note tokens are transferred to the AccountantDelegate contract. However, in the sweepInterest function of the AccountantDelegate contract, all cnote tokens in the contract will be transferred to address 0. This will prevent the user from repaying the note tokens, and the sweepInterest function will not calculate the interest correctly later.

Proof of Concept

https://github.com/Plex-Engineer/lending-market/blob/ab31a612be354e252d72faead63d86b844172761/contracts/Accountant/AccountantDelegate.sol#L74-L92 https://github.com/Plex-Engineer/lending-market/blob/ab31a612be354e252d72faead63d86b844172761/contracts/CToken.sol#L533

Tools Used

None

function sweepInterest() external override returns(uint) { uint noteBalance = note.balanceOf(address(this)); uint CNoteBalance = cnote.balanceOf(address(this)); Exp memory expRate = Exp({mantissa: cnote.exchangeRateStored()}); // obtain exchange Rate from cNote Lending Market as a mantissa (scaled by 1e18) uint cNoteConverted = mul_ScalarTruncate(expRate, CNoteBalance); //calculate truncate(cNoteBalance* mantissa{expRate}) uint noteDifferential = sub_(note.totalSupply(), noteBalance); //cannot underflow, subtraction first to prevent against overflow, subtraction as integers require(cNoteConverted >= noteDifferential, "Note Loaned to LendingMarket must increase in value"); uint amtToSweep = sub_(cNoteConverted, noteDifferential); note.transfer(treasury, amtToSweep); - cnote.transfer(address(0), CNoteBalance); return 0; }

#0 - GalloDaSballo

2022-08-04T21:39:39Z

The warden has shown how, due to a programmer mistake, interest bearing Note will be burned

It is unclear why this decision was made, and I believe the sponsor should look into redeeming the cNote over destroying it

The sponsor confirmed, and because this finding shows unconditional loss of assets, I agree with High Severity

Findings Information

🌟 Selected for report: Ruhum

Also found by: cccz

Labels

bug
duplicate
3 (High Risk)

Awards

9086.4148 CANTO - $1,467.46

1467.456 USDC - $1,467.46

External Links

Lines of code

https://github.com/Plex-Engineer/lending-market/blob/ab31a612be354e252d72faead63d86b844172761/contracts/Accountant/AccountantDelegate.sol#L28-L29

Vulnerability details

Impact

In the initialize function of the AccountantDelegate contract, note._mint_to_Accountant is called. _mint_to_Accountant will mint note tokens to the AccountantDelegate contract instead of msg.sender. if note._initialSupply() ! = 0, note.balanceOf(msg.sender) == note._initialSupply() is false, the initialize function fails.

Proof of Concept

https://github.com/Plex-Engineer/lending-market/blob/ab31a612be354e252d72faead63d86b844172761/contracts/Accountant/AccountantDelegate.sol#L28-L29 https://github.com/Plex-Engineer/lending-market/blob/ab31a612be354e252d72faead63d86b844172761/contracts/Note.sol#L13-L19 https://github.com/Plex-Engineer/lending-market/blob/ab31a612be354e252d72faead63d86b844172761/contracts/ERC20.sol#L32 https://github.com/Plex-Engineer/lending-market/blob/ab31a612be354e252d72faead63d86b844172761/contracts/ERC20.sol#L242

Tools Used

None

Make sure _initialSupply == 0

#0 - nivasan1

2022-06-23T04:06:32Z

duplicate of #53

#1 - GalloDaSballo

2022-08-07T23:00:39Z

Dup of #53

Findings Information

🌟 Selected for report: Soosh

Also found by: 0x1f8b, Ruhum, TerrierLover, WatchPug, cccz, csanuragjain, hake, p4st13r4, zzzitron

Labels

bug
duplicate
3 (High Risk)

Awards

126.3383 USDC - $126.34

782.2807 CANTO - $126.34

External Links

Lines of code

https://github.com/Plex-Engineer/manifest/blob/688e9b4e7835854c22ef44b045d6d226b784b4b8/contracts/Proposal-Store.sol#L46-L50

Vulnerability details

Impact

In the ProposalStore contract, AddProposal can be called by anyone, so that anyone can add a new proposal or overwrite an old proposal.

function AddProposal(uint propId, string memory title, string memory desc, address[] memory targets, uint[] memory values, string[] memory signatures, bytes[] memory calldatas) public { Proposal memory newProp = Proposal(propId, title, desc, targets, values, signatures, calldatas); proposals[propId] = newProp; }

Proof of Concept

https://github.com/Plex-Engineer/manifest/blob/688e9b4e7835854c22ef44b045d6d226b784b4b8/contracts/Proposal-Store.sol#L46-L50

Tools Used

None

Add the OnlyUniGov modifier to the AddProposal function

#0 - tkkwon1998

2022-06-22T17:41:31Z

Duplicate of issue #26

Findings Information

🌟 Selected for report: Ruhum

Also found by: 0xf15ers, Soosh, WatchPug, cccz, hake

Labels

bug
duplicate
3 (High Risk)

Awards

1987.1989 CANTO - $320.93

320.9326 USDC - $320.93

External Links

Lines of code

https://github.com/Plex-Engineer/lending-market/blob/ab31a612be354e252d72faead63d86b844172761/contracts/Comptroller.sol#L1470

Vulnerability details

Impact

The Comptroller contract is forked from the Compound protocol and the reward token is modified, but the getWETHAddress function still uses the COMP token address

function getWETHAddress() virtual public view returns (address) { return 0xc00e94Cb662C3520282E6f5717214004A7f26888; }

Proof of Concept

https://github.com/Plex-Engineer/lending-market/blob/ab31a612be354e252d72faead63d86b844172761/contracts/Comptroller.sol#L1470

Tools Used

None

Modify the return value of getWETHAddress to the weth token address

#0 - tkkwon1998

2022-06-21T04:08:57Z

duplicate of issue #46

Findings Information

🌟 Selected for report: Picodes

Also found by: cccz

Labels

bug
duplicate
3 (High Risk)

Awards

1467.456 USDC - $1,467.46

9086.4148 CANTO - $1,467.46

External Links

Lines of code

https://github.com/Plex-Engineer/lending-market/blob/ab31a612be354e252d72faead63d86b844172761/contracts/ERC20.sol#L29-L34

Vulnerability details

Impact

In the ERC20 standard, _totalSupply indicates the number of tokens minted, but the tokens in the _initialSupply parts of the Note contract have not been minted, which causes _totalSupply to be incorrect

Proof of Concept

https://github.com/Plex-Engineer/lending-market/blob/ab31a612be354e252d72faead63d86b844172761/contracts/ERC20.sol#L29-L34 https://github.com/Plex-Engineer/lending-market/blob/ab31a612be354e252d72faead63d86b844172761/contracts/ERC20.sol#L237-L247

Tools Used

None

Consider making _initialSupply == 0

#0 - nivasan1

2022-06-23T04:09:10Z

duplicate of #107

#2 - GalloDaSballo

2022-08-12T00:39:59Z

Dup of #108

Findings Information

🌟 Selected for report: Ruhum

Also found by: 0xmint, cccz, csanuragjain, dipp, hake, zzzitron

Labels

bug
duplicate
3 (High Risk)

Awards

247.5766 USDC - $247.58

1532.982 CANTO - $247.58

External Links

Lines of code

https://github.com/Plex-Engineer/lending-market/blob/755424c1f9ab3f9f0408443e6606f94e4f08a990/contracts/Governance/GovernorBravoDelegate.sol#L63

Vulnerability details

Impact

In the queue function of the GovernorBravoDelegate contract, newProposal.executed = true will be set, which will make state(proposalId) != ProposalState.Queued, so the proposal cannot be executed.

function execute(uint proposalId) external payable { require(state(proposalId) == ProposalState.Queued, "GovernorBravo::execute: proposal can only be executed if it is queued");

Proof of Concept

https://github.com/Plex-Engineer/lending-market/blob/755424c1f9ab3f9f0408443e6606f94e4f08a990/contracts/Governance/GovernorBravoDelegate.sol#L63

Tools Used

None

Modify the following statements in the queue function

- newProposal.executed = true; + newProposal.executed = false;

#0 - tkkwon1998

2022-06-22T17:47:19Z

Duplicate of issue #39

Findings Information

🌟 Selected for report: cccz

Also found by: Picodes

Labels

bug
2 (Med Risk)
sponsor confirmed

Awards

440.2368 USDC - $440.24

2725.9244 CANTO - $440.24

External Links

Lines of code

https://github.com/Plex-Engineer/lending-market/blob/ab31a612be354e252d72faead63d86b844172761/contracts/Note.sol#L13-L19

Vulnerability details

Impact

In Note contract, if _initialSupply ! = 0, _totalSupply will overflow when the _mint_to_Accountant function executes _mint(msg.sender, type(uint).max)

constructor(string memory name_, string memory symbol_, uint256 totalSupply_) public { _name = name_; _symbol = symbol_; _initialSupply = totalSupply_; _totalSupply = totalSupply_; } ... function _mint(address account, uint256 amount) internal { require(account != address(0), "ERC20: mint to the zero address"); _beforeTokenTransfer(address(0), account, amount); _totalSupply += amount; _balances[account] += amount; emit Transfer(address(0), account, amount); _afterTokenTransfer(address(0), account, amount); }

Proof of Concept

https://github.com/Plex-Engineer/lending-market/blob/ab31a612be354e252d72faead63d86b844172761/contracts/Note.sol#L13-L19 https://github.com/Plex-Engineer/lending-market/blob/ab31a612be354e252d72faead63d86b844172761/contracts/ERC20.sol#L29-L34 https://github.com/Plex-Engineer/lending-market/blob/ab31a612be354e252d72faead63d86b844172761/contracts/ERC20.sol#L237-L247

Tools Used

None

ERC20.sol

constructor(string memory name_, string memory symbol_) public { _name = name_; _symbol = symbol_; }

note.sol

constructor() ERC20("Note", "NOTE") { admin = msg.sender; }

#0 - nivasan1

2022-06-23T04:07:08Z

duplicate of #53

#1 - GalloDaSballo

2022-08-07T23:03:30Z

In contrast to #53 -> Revert of initialize

This finding shows, how, based on constructor arguments, the function _mint_to_accountant can fail.

Am not convinced on the impact as I believe in the worst case the Sponsor would just be forced to re-deploy

#2 - GalloDaSballo

2022-08-12T00:38:46Z

The warden has shown how, because the function _mint_to_accountant mints the maximum value representable, deploying Note with a non-zero initialSupply will cause a revert.

Because this is contingent on a misconfiguration, I agree with Med Severity

#3 - liveactionllama

2022-10-18T00:20:35Z

Per discussion with @abhipingle - labeling this as sponsor confirmed.

Awards

73.3392 USDC - $73.34

687.9945 CANTO - $111.11

Labels

bug
QA (Quality Assurance)
sponsor confirmed

External Links

Lines of code

https://github.com/Plex-Engineer/lending-market/blob/755424c1f9ab3f9f0408443e6606f94e4f08a990/contracts/Treasury/TreasuryDelegator.sol#L44-L56

Vulnerability details

Impact

In AccountantDelegator and TreasuryDelegator contracts, when using abi.decode(data, (uint)) to convert data to uint type, the length of data is not checked, when the returned data is of bytes type, the abi.decode will return 0x20.

Proof of Concept

https://github.com/Plex-Engineer/lending-market/blob/755424c1f9ab3f9f0408443e6606f94e4f08a990/contracts/Treasury/TreasuryDelegator.sol#L44-L56 https://github.com/Plex-Engineer/lending-market/blob/755424c1f9ab3f9f0408443e6606f94e4f08a990/contracts/Accountant/AccountantDelegator.sol#L54-L74 This contract can test that when the function returns bytes data, abi.encode will decode the return value as 0x20.

pragma solidity 0.8.10; contract A{ uint public destination; uint256 public number; function convertA() external{ (bool su,bytes memory ret )= address(this).call(abi.encodeWithSelector(this.ret.selector)); number = ret.length; destination = abi.decode(ret, (uint)); } function ret() public returns(bytes memory){ return "1234"; } }

Tools Used

None

Requires data.length == 32

#0 - GalloDaSballo

2022-08-07T23:09:22Z

I don't get why the return data would be of type bytes, all signatures are specifying uint.

Skipping the check may be a gas optimization.

Downgrading to QA

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