Skip to content
This repository has been archived by the owner on May 26, 2023. It is now read-only.

Latest commit

 

History

History
140 lines (105 loc) · 4.24 KB

065.md

File metadata and controls

140 lines (105 loc) · 4.24 KB

ladboy233

medium

Lack of expiration time for cross-chain message passing

Summary

Lack of expiration time for cross-chain message passing

Vulnerability Detail

In the current implementation, the L1CrossDomainMessagern.sol inherits from CrossDomainMessager.sol and L2CrossDomainMessenger.sol inherits from CrossMainMessager.sol as well.

In CrossDomainMessager.sol, we have this function:

function sendMessage(
	address _target,
	bytes calldata _message,
	uint32 _minGasLimit
) external payable {
	// Triggers a message to the other messenger. Note that the amount of gas provided to the
	// message is the amount of gas requested by the user PLUS the base gas value. We want to
	// guarantee the property that the call to the target contract will always have at least
	// the minimum gas limit specified by the user.
	_sendMessage(
		OTHER_MESSENGER,
		baseGas(_message, _minGasLimit),
		msg.value,
		abi.encodeWithSelector(
			this.relayMessage.selector,
			messageNonce(),
			msg.sender,
			_target,
			msg.value,
			_minGasLimit,
			_message
		)
	);

	emit SentMessage(_target, msg.sender, _message, messageNonce(), _minGasLimit);
	emit SentMessageExtension1(msg.sender, msg.value);

	unchecked {
		++msgNonce;
	}
}

The parent can other overwrite the _sendMessage method.

In L1CrossDomainMessagern.sol, the _sendMessage is overwrite to:

/**
 * @inheritdoc CrossDomainMessenger
 */
function _sendMessage(
	address _to,
	uint64 _gasLimit,
	uint256 _value,
	bytes memory _data
) internal override {
	PORTAL.depositTransaction{ value: _value }(_to, _value, _gasLimit, false, _data);
}

In L2CrossDomainMessagern.sol, the _sendMessage is overwrite to:

/**
 * @inheritdoc CrossDomainMessenger
 */
function _sendMessage(
	address _to,
	uint64 _gasLimit,
	uint256 _value,
	bytes memory _data
) internal override {
	L2ToL1MessagePasser(payable(Predeploys.L2_TO_L1_MESSAGE_PASSER)).initiateWithdrawal{
		value: _value
	}(_to, _gasLimit, _data);
}

The user can specify the target address with customized call data and attach ETH.

However, If we looked into the message data encoded format:

	_sendMessage(
		OTHER_MESSENGER,
		baseGas(_message, _minGasLimit),
		msg.value,
		abi.encodeWithSelector(
			this.relayMessage.selector,
			messageNonce(),
			msg.sender,
			_target,
			msg.value,
			_minGasLimit,
			_message
		)
	);

We see that there is no deadline and timestamp or expiration time encoded into the message.

For example, user A has a contract B in ethereum mainnet and contract C in optimism network.

Contract C in optimism is already paused by User A from operating because the User A identify issue in off-chain code that decode the transaction event from contract C.

After user A think he identify and fix the issue, User A performs a cross-chain call from ethereum network and try to deposit 0.1 ETH to contract C and try to unpause the contract C.

However, there is gas spike in ethereum network and the User A's deposit call with unpause instruction has low gas payment and the transaction is pending in the mempool.

Later, A hacker figured out a way to withdraw fund from contract C, the User A monitored on-chain activity for contract C in optimism network. User A fire up a deposit call with pause contract instruction and try to pause the contract C immediately.

The transaction get executed and Contract C is paused.

Later, the gas spike faded and the gas price from User A's previous depositTo with unpause instruction transation becomes profitable for miner to include the transction in the mainnet.

The unpause transaction get executed and the vulnerable contract C is unpaused after being paused because of the lack of expiration time in cross-chain message passing. The hacker is able to drain more fund from contract C because the contract is unexpectedly unpaused after paused.

Impact

The lack of deadline and timestamp in the cross-chain message allows outdated message and transaction to be maliciously executed.

Code Snippet

https://github.com/sherlock-audit/2023-01-optimism/blob/main/optimism/packages/contracts-bedrock/contracts/universal/CrossDomainMessenger.sol#L201-L243

Tool used

Manual Review

Recommendation

We recommend the protocol add deadline and expiration timestamp when doing message passing.