Skip to content

Latest commit

 

History

History
75 lines (59 loc) · 3.38 KB

File metadata and controls

75 lines (59 loc) · 3.38 KB

Multichain Permit Attack

Step-by-step

  1. Craft and deploy a contract so that it passes the requirements.
  2. Find a victim that had permit the contract to use WETH.
  3. Call anySwapOutUnderlyingWithPermit with your malicious contract and the victim's address.

Detailed Description

Another attack that relies on an arbitry token parameter. Here, Multichain intended the token to be an Anytoken (Multichain was previously called AnySwap), which they use to track account balances when doing cross-chain transaction.

The anySwapOutUnderlyingWithPermit() method takes a token and will call permit on its underlying and then transfer from the underlying to the token.

The contract fails to take into account that WETH is special: WETH's fallback function triggers its deposit() method and returns true and does not implement permit, so calls to permit on WETH simply return true.

To make matters worst, most of the users of Multichain had given an unlimited token allowance to the Protocol, so when the contract uses transferFrom it can use an arbitrary amount.

    function anySwapOutUnderlyingWithPermit(
        address from,
        address token,
        address to,
        uint amount,
        uint deadline,
        uint8 v,
        bytes32 r,
        bytes32 s,
        uint toChainID
    ) external {
        address _underlying = AnyswapV1ERC20(token).underlying();
        IERC20(_underlying).permit(from, address(this), amount, deadline, v, r, s);
        TransferHelper.safeTransferFrom(_underlying, from, token, amount);
        AnyswapV1ERC20(token).depositVault(amount, from);
        _anySwapOut(from, token, to, amount, toChainID);
    }

    function _anySwapOut(address from, address token, address to, uint amount, uint toChainID) internal {
        AnyswapV1ERC20(token).burn(from, amount);
        emit LogAnySwapOut(token, from, to, amount, cID(), toChainID);
    }

Here, the attacker deployed a contract that returned WETH as the underlying.

  1. permit will pass due to the reason outlined above, even with no signature.
  2. transferFrom will pass if the victim allowed Multichain with permit.

Then it is just a matter of findings victims.

Possible mitigations

  • Implement a whitelist of allowed tokens.
  • Avoid asking users to sign unlimited allowances.

Diagrams and graphs

Class

class

Sources and references