Lucene search

K
code423n4Code4renaCODE423N4:2023-01-ASTARIA-FINDINGS-ISSUES-539
HistoryJan 19, 2023 - 12:00 a.m.

Attacker can fake an ERC20 token as the paymentToken and call ClearingHouse.safeTransferFrom() to prematurely settle the auction, preventing the actual auction from completing

2023-01-1900:00:00
Code4rena
github.com
14
erc20 token
auction settlement
data validation

Lines of code

Vulnerability details

Impact

ClearingHouses are deployed for each new loan and settle payments between Seaport auctions and Astaria Vaults if a liquidation occurs.

However, due to the lack of proper data validation in the current implementation, anyone can fake a token and transfer it to the ClearingHouse to settle the auction, which would undermine the clearing process and harm the entire system.

#Proof of Concept

function safeTransferFrom(
    address from, // the from is the offerer
    address to,
    uint256 identifier,
    uint256 amount,
    bytes calldata data //empty from seaport
  ) public {
    //data is empty and useless
    _execute(from, to, identifier, amount);
  }

<https://github.com/code-423n4/2023-01-astaria/blob/1bfc58b42109b839528ab1c21dc9803d663df898/src/ClearingHouse.sol#L114-L167&gt;

function _execute(
    address tokenContract, // collateral token sending the fake nft
    address to, // buyer
    uint256 encodedMetaData, //retrieve token address from the encoded data
    uint256 // space to encode whatever is needed,
  ) internal {
    IAstariaRouter ASTARIA_ROUTER = IAstariaRouter(_getArgAddress(0)); // get the router from the immutable arg

    ClearingHouseStorage storage s = _getStorage();
    address paymentToken = bytes32(encodedMetaData).fromLast20Bytes();

    uint256 currentOfferPrice = _locateCurrentAmount({
      startAmount: s.auctionStack.startAmount,
      endAmount: s.auctionStack.endAmount,
      startTime: s.auctionStack.startTime,
      endTime: s.auctionStack.endTime,
      roundUp: true //we are a consideration we round up
    });
    uint256 payment = ERC20(paymentToken).balanceOf(address(this));

    require(payment &gt;= currentOfferPrice, "not enough funds received");

    uint256 collateralId = _getArgUint256(21);
    // pay liquidator fees here

    ILienToken.AuctionStack[] storage stack = s.auctionStack.stack;

    uint256 liquidatorPayment = ASTARIA_ROUTER.getLiquidatorFee(payment);

    ERC20(paymentToken).safeTransfer(
      s.auctionStack.liquidator,
      liquidatorPayment
    );

    ERC20(paymentToken).safeApprove(
      address(ASTARIA_ROUTER.TRANSFER_PROXY()),
      payment - liquidatorPayment
    );

    ASTARIA_ROUTER.LIEN_TOKEN().payDebtViaClearingHouse(
      paymentToken,
      collateralId,
      payment - liquidatorPayment,
      s.auctionStack.stack
    );

    if (ERC20(paymentToken).balanceOf(address(this)) &gt; 0) {
      ERC20(paymentToken).safeTransfer(
        ASTARIA_ROUTER.COLLATERAL_TOKEN().ownerOf(collateralId),
        ERC20(paymentToken).balanceOf(address(this))
      );
    }
    ASTARIA_ROUTER.COLLATERAL_TOKEN().settleAuction(collateralId);
  }

safeTransferFrom() is a public function without msg.sender access check, encodedMetaData is user data, there no check make sure address paymentToken = bytes32(encodedMetaData).fromLast20Bytes() is the settlementToken.

so the paymentToken can be a fake token worth nothing.

when an attacker call safeTransferFrom before the real auction got settled, the real auction can not settle.

Recommended Mitigation Steps

add check make sure paymentToken = settlementToken


The text was updated successfully, but these errors were encountered:

All reactions