The Wildcat Protocol - Robert's results

Banking, but worse - a protocol for fixed-rate, undercollateralised credit facilities.

General Information

Platform: Code4rena

Start Date: 16/10/2023

Pot Size: $60,500 USDC

Total HM: 16

Participants: 131

Period: 10 days

Judge: 0xTheC0der

Total Solo HM: 3

Id: 296

League: ETH

Wildcat Protocol

Findings Distribution

Researcher Performance

Rank: 5/131

Findings: 2

Award: $866.18

🌟 Selected for report: 0

šŸš€ Solo Findings: 0

Findings Information

🌟 Selected for report: MiloTruck

Also found by: 0xDING99YA, Robert

Labels

bug
3 (High Risk)
partial-25
duplicate-491

Awards

647.6492 USDC - $647.65

External Links

Lines of code

https://github.com/code-423n4/2023-10-wildcat/blob/c5df665f0bc2ca5df6f06938d66494b11e7bdada/src/WildcatSanctionsSentinel.sol#L106

Vulnerability details

Impact

Any escrow contract can be DoSed by sending a 1 wei transaction to the escrow address that will be created for a user.

When an account has no code and has never been interacted with, the codehash will be bytes32(0).

This will result in escrow creation succeeding at this line https://github.com/code-423n4/2023-10-wildcat/blob/c5df665f0bc2ca5df6f06938d66494b11e7bdada/src/WildcatSanctionsSentinel.sol#L106

However, when an account has had a transaction sent to it, the codehash changes to keccak256(ā€œā€) (c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470). The require statement then fails because codehash does not equal bytes32(0) and creation will be reverted despite no code being at that address.

This is a high impact because you can stop any escrow contracts from ever being created.

Proof of Concept

contract CodehashTest {

function notZeroCodeHash() external payable returns(bytes32 firstCodeHash, bytes32 secondCodeHash) { // Random address that has had 0 interactions firstCodeHash = address(0xc93356BdeAf3ceA6284A6Cc747fa52DD04AfB2A7).codehash; payable(0xc93356BdeAf3ceA6284A6Cc747fa52DD04AfB2A7).transfer(1); secondCodeHash = address(0xc93356BdeAf3ceA6284A6Cc747fa52DD04AfB2A7).codehash; }

}

Tools Used

Manual

Add && != bytes32(c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470) to the require.

Assessed type

DoS

#0 - c4-pre-sort

2023-10-28T14:53:06Z

minhquanym marked the issue as duplicate of #531

#1 - c4-judge

2023-11-07T10:12:29Z

MarioPoneder marked the issue as duplicate of #491

#2 - c4-judge

2023-11-07T10:20:28Z

MarioPoneder marked the issue as partial-25

#3 - c4-judge

2023-11-07T10:20:33Z

MarioPoneder marked the issue as satisfactory

#4 - MarioPoneder

2023-11-07T10:20:40Z

found 1/3 instances, see primary

#5 - c4-judge

2023-11-07T10:21:43Z

MarioPoneder marked the issue as partial-25

Findings Information

🌟 Selected for report: MiloTruck

Also found by: 0xDING99YA, Robert

Labels

bug
3 (High Risk)
partial-25
duplicate-491

Awards

647.6492 USDC - $647.65

External Links

Lines of code

https://github.com/code-423n4/2023-10-wildcat/blob/c5df665f0bc2ca5df6f06938d66494b11e7bdada/src/WildcatMarketControllerFactory.sol#L294

Vulnerability details

Impact

Any controller contract can be DoSed by sending a 1 wei transaction to the controller address that will be created for a user.

When an account has no code and has never been interacted with, the codehash will be bytes32(0).

This will result in controller creation succeeding at this line https://github.com/code-423n4/2023-10-wildcat/blob/c5df665f0bc2ca5df6f06938d66494b11e7bdada/src/WildcatMarketControllerFactory.sol#L294

However, when an account has had a transaction sent to it, the codehash changes to keccak256(ā€œā€) (c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470). The require statement then fails because codehash does not equal bytes32(0) and creation will be reverted despite no code being at that address.

This is a high impact because you can stop any controller contracts from ever being created.

Proof of Concept

contract CodehashTest {

function notZeroCodeHash() external payable returns(bytes32 firstCodeHash, bytes32 secondCodeHash) { // Random address that has had 0 interactions firstCodeHash = address(0xc93356BdeAf3ceA6284A6Cc747fa52DD04AfB2A7).codehash; payable(0xc93356BdeAf3ceA6284A6Cc747fa52DD04AfB2A7).transfer(1); secondCodeHash = address(0xc93356BdeAf3ceA6284A6Cc747fa52DD04AfB2A7).codehash; }

}

Tools Used

Manual

Add && != bytes32(c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470) to the require.

Assessed type

DoS

#0 - c4-pre-sort

2023-10-28T14:52:46Z

minhquanym marked the issue as duplicate of #531

#1 - c4-judge

2023-11-07T10:14:19Z

MarioPoneder marked the issue as duplicate of #491

#2 - c4-judge

2023-11-07T10:20:05Z

MarioPoneder marked the issue as partial-25

#3 - c4-judge

2023-11-07T10:20:11Z

MarioPoneder marked the issue as satisfactory

#4 - MarioPoneder

2023-11-07T10:20:14Z

found 1/3 instances, see primary

#5 - c4-judge

2023-11-07T10:21:39Z

MarioPoneder marked the issue as partial-25

Findings Information

🌟 Selected for report: MiloTruck

Also found by: 0xDING99YA, Robert

Labels

bug
3 (High Risk)
partial-25
duplicate-491

Awards

647.6492 USDC - $647.65

External Links

Lines of code

https://github.com/code-423n4/2023-10-wildcat/blob/c5df665f0bc2ca5df6f06938d66494b11e7bdada/src/WildcatMarketController.sol#L351

Vulnerability details

Impact

Any market contract can be DoSed by sending a 1 wei transaction to the market address that will be created for a user.

When an account has no code and has never been interacted with, the codehash will be bytes32(0).

This will result in market creation succeeding at this line https://github.com/code-423n4/2023-10-wildcat/blob/c5df665f0bc2ca5df6f06938d66494b11e7bdada/src/WildcatMarketController.sol#L351

However, when an account has had a transaction sent to it, the codehash changes to keccak256(ā€œā€) (c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470). The require statement then fails because codehash does not equal bytes32(0) and creation will be reverted despite no code being at that address.

This is a high impact because you can stop any market contracts from ever being created.

Proof of Concept

contract CodehashTest {

function notZeroCodeHash() external payable returns(bytes32 firstCodeHash, bytes32 secondCodeHash) { // Random address that has had 0 interactions firstCodeHash = address(0xc93356BdeAf3ceA6284A6Cc747fa52DD04AfB2A7).codehash; payable(0xc93356BdeAf3ceA6284A6Cc747fa52DD04AfB2A7).transfer(1); secondCodeHash = address(0xc93356BdeAf3ceA6284A6Cc747fa52DD04AfB2A7).codehash; }

}

Tools Used

Manual

Add && != bytes32(c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470) to the require.

Assessed type

DoS

#0 - c4-pre-sort

2023-10-28T14:52:25Z

minhquanym marked the issue as duplicate of #531

#1 - c4-judge

2023-11-07T10:14:20Z

MarioPoneder marked the issue as duplicate of #491

#2 - c4-judge

2023-11-07T10:18:34Z

MarioPoneder marked the issue as partial-25

#3 - c4-judge

2023-11-07T10:18:39Z

MarioPoneder marked the issue as satisfactory

#4 - MarioPoneder

2023-11-07T10:19:38Z

found 1/3 instances, see primary

#5 - c4-judge

2023-11-07T10:21:23Z

MarioPoneder marked the issue as partial-25

Findings Information

🌟 Selected for report: MiloTruck

Also found by: 0xCiphky, LokiThe5th, Madalad, Robert, ZdravkoHr, nonseodion

Labels

bug
2 (Med Risk)
downgraded by judge
satisfactory
duplicate-499

Awards

218.5317 USDC - $218.53

External Links

Lines of code

https://github.com/code-423n4/2023-10-wildcat/blob/c5df665f0bc2ca5df6f06938d66494b11e7bdada/src/libraries/LibStoredInitCode.sol#L76

Vulnerability details

Impact

Permanent DoS of creating a market if anything fails in the market constructor.

Within a create2 call, instead of failing when a revert occurs in the constructor being run, it just returns address(0).

If this occurs within a market that's being created the transaction will not revert in the controller and instead will register the address as a valid market, despite nothing having been created.

https://github.com/code-423n4/2023-10-wildcat/blob/c5df665f0bc2ca5df6f06938d66494b11e7bdada/src/WildcatMarketController.sol#L356

Once this is registered, it will block any future attempts at registration, so any more attempts at creating the market will fail despite it never having been created.

https://github.com/code-423n4/2023-10-wildcat/blob/c5df665f0bc2ca5df6f06938d66494b11e7bdada/src/WildcatArchController.sol#L193

Proof of Concept

contract FactoryAssembly { event Deployed(address addr, uint salt);

// 1. Get bytecode of contract to be deployed // NOTE: _owner and _foo are arguments of the TestContract's constructor function getBytecode(address _owner, uint _foo) public pure returns (bytes memory) { bytes memory bytecode = type(TestContract).creationCode; return abi.encodePacked(bytecode, abi.encode(_owner, _foo)); } // 2. Compute the address of the contract to be deployed // NOTE: _salt is a random number used to create an address function getAddress( bytes memory bytecode, uint _salt ) public view returns (address) { bytes32 hash = keccak256( abi.encodePacked(bytes1(0xff), address(this), _salt, keccak256(bytecode)) ); // NOTE: cast last 20 bytes of hash to address return address(uint160(uint(hash))); } // 3. Deploy the contract // NOTE: // Check the event log Deployed which contains the address of the deployed TestContract. // The address in the log should equal the address computed from above. function deploy(bytes memory bytecode, uint _salt) public payable { address addr; /* NOTE: How to call create2 create2(v, p, n, s) create new contract with code at memory p to p + n and send v wei and return the new address where new address = first 20 bytes of keccak256(0xff + address(this) + s + keccak256(mem[p…(p+n))) s = big-endian 256-bit value */ assembly { addr := create2( callvalue(), // wei sent with current call // Actual code starts after skipping the first 32 bytes add(bytecode, 0x20), mload(bytecode), // Load the size of code contained in the first 32 bytes _salt // Salt from function arguments ) if iszero(extcodesize(addr)) { revert(0, 0) } } emit Deployed(addr, _salt); }

}

contract TestContract { address public owner; uint public foo;

constructor(address _owner, uint _foo) payable { owner = _owner; foo = _foo; revert(); } function getBalance() public view returns (uint) { return address(this).balance; }

}

TestContract in this PoC should revert the transaction when being created, but instead the transaction succeeds without TestContract having been created.

Tools Used

Manual

Add the same check that the normal create has: https://github.com/code-423n4/2023-10-wildcat/blob/c5df665f0bc2ca5df6f06938d66494b11e7bdada/src/libraries/LibStoredInitCode.sol#L35

Assessed type

DoS

#0 - c4-pre-sort

2023-10-27T04:44:53Z

minhquanym marked the issue as duplicate of #28

#1 - c4-judge

2023-11-07T15:00:47Z

MarioPoneder changed the severity to 2 (Med Risk)

#2 - c4-judge

2023-11-07T15:00:56Z

MarioPoneder marked the issue as satisfactory

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