How Was Socket Protocol Exploited?

4 min read

Learn how Socket Protocol was exploited, resulting in a loss of assets worth $3.3 million.

TL;DR#

On January 16, 2024, the Socket Protocol was exploited on the Ethereum Mainnet, which resulted in a loss of over $3.3 million worth of assets.

Introduction to Socket#

Socket is an interoperability protocol that powers seamless asset and data transfers for apps across blockchains.

Vulnerability Assessment#

The root cause of the exploit is the incomplete validation of user inputs, which was exploited to steal funds from users who had token approvals for the vulnerable contracts.

Steps#

Step 1:

We attempt to analyze one of the attack transactions executed by the exploiter.

Step 2:

The vulnerable WrappedTokenSwapperImpl contract was deployed just a couple of days prior to the occurrence of the incident.

Step 3:

In this contract, the performAction function uses the swapExtraData parameter without validating it before calling the target with this data.

function performAction(address fromToken, address toToken, uint256 amount, address receiverAddress, bytes32 metadata, bytes calldata swapExtraData) external payable override returns (uint256) {
  uint256 _initialBalanceTokenOut;
  uint256 _finalBalanceTokenOut;

  // Swap Native to Wrapped Token
  if (fromToken == NATIVE_TOKEN_ADDRESS) {
    _initialBalanceTokenOut = ERC20(toToken).balanceOf(socketGateway);
    (bool success, ) = toToken.call{value: amount}(swapExtraData);

    if (!success) {
      revert SwapFailed();
    }

    _finalBalanceTokenOut = ERC20(toToken).balanceOf(socketGateway);

    require((_finalBalanceTokenOut - _initialBalanceTokenOut) == amount, "Invalid wrapper contract");

    // Send weth to user
    ERC20(toToken).transfer(receiverAddress, amount);
  } else {
    _initialBalanceTokenOut = address(socketGateway).balance;

    // Swap Wrapped Token To Native Token
    ERC20(fromToken).safeTransferFrom(msg.sender, socketGateway, amount);

    (bool success, ) = fromToken.call(swapExtraData);

    if (!success) {
      revert SwapFailed();
    }

    _finalBalanceTokenOut = address(socketGateway).balance;

    require((_finalBalanceTokenOut - _initialBalanceTokenOut) == amount, "Invalid wrapper contract");

    // send ETH to the user
    payable(receiverAddress).transfer(amount);
  }

  emit SocketSwapTokens(fromToken, toToken, amount, amount, Identifier, receiverAddress, metadata);

  return amount;
}

Step 4:

As a result, the exploiter could craft a payload to invoke an arbitrary call to the transferFrom function from anyone that provided token approvals of a specified amount to the SocketGateway contract and then transfer these tokens directly to the attacker's address.

Step 5:

Essentially, the affected function didn't consider the case where the caller transfers in 0 WETH worth of assets, allowing the caller to specify other functions in the call and still bypassing the balance check.

Step 6:

The attacker used the fallback inside the SocketGateway contract to call and trigger the performAction function with routeId 406.

/// @notice fallback function to handle swap, bridge execution
/// @dev ensure routeId is converted to bytes4 and sent as msg.sig in the transaction
fallback() external payable {
  address routeAddress = addressAt(uint32(msg.sig));

  bytes memory result;

  assembly {
    // copy function selector and any arguments
    calldatacopy(0, 4, sub(calldatasize(), 4))
    // execute function call using the facet
    result := delegatecall(gas(), routeAddress, 0, sub(calldatasize(), 4), 0, 0)
    // get any return value
    returndatacopy(0, 0, returndatasize())
    // return any return value or error back to the caller
    switch result
    case 0 {
      revert(0, returndatasize())
    }
    default {
      return(0, returndatasize())
    }
  }
}

Step 7:

The stolen funds are held at this address and include assets worth 1,138 ETH, amounting to approximately $2.91 million; 165,356 MATIC, which are worth $138,651; 2.8896 WBTC, worth $123,659; 42.4753 WETH, worth $108,645; and 13,821 DAI, all of which total $3,295,768.

Aftermath#

The team acknowledged the occurrence of the incident and stated that the exploit affected wallets with infinite approvals for the Socket contracts. The team had subsequently paused the contract to minimize the extent of the damage caused.

The attack impacted approximately 712 users of the protocol that had granted unlimited approvals to the Socket contracts. As viewed in this transaction, the Socket Admin has already disabled the vulnerable contract with routeId 406.

Solution#

To mitigate and prevent similar exploits in the future, it's essential to adopt a comprehensive approach that encompasses both developer practices and user awareness. First and foremost, smart contract developers must not deploy contracts without thorough auditing by reputable audit firms. These audits help identify potential security vulnerabilities and weaknesses in the contract's code that might otherwise go unnoticed.

Additionally, smart contract developers should always practice rigorous input validation. This means sanitizing all inputs to the contract, ensuring that they are of the expected type, format, and within expected ranges. Proper input validation can prevent attackers from exploiting vulnerabilities that arise from improperly validated inputs, such as the one seen in the Socket Protocol exploit.

From the user's perspective, it is crucial to revoke approvals to the affected contracts immediately upon learning of such exploits. Users should regularly review and manage the token approvals they have granted to various third-party applications or protocols. This oversight reduces the risk of their assets being misused if a contract they interact with is compromised.

Despite the best efforts in implementing stringent security protocols, the risk of vulnerabilities being exploited remains. In such situations, Neptune Mutual plays an indispensable role. By setting up a dedicated cover pool with Neptune Mutual, the repercussions of incidents similar to the Socket Protocol attack can be significantly mitigated. Neptune Mutual offers coverage for losses stemming from smart contract vulnerabilities through its parametric policies.

Collaborating with Neptune Mutual streamlines the process for users by removing the need for them to submit extensive proof of loss. Once an incident has been confirmed and resolved using our comprehensive incident resolution framework, our priority shifts to swiftly compensating those impacted and providing them with immediate financial support.

Our marketplace extends across multiple major blockchain networks, including EthereumArbitrum, and the BNB chain. This extensive coverage enables us to cater to a diverse array of DeFi users, offering them protection against potential vulnerabilities and thereby reinforcing their trust in the ecosystem.

Reference Source Hacken

By

Tags