Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

The source chain id was not verified in BranchBridgeAgent#lzReceive. #328

Open
c4-submissions opened this issue Oct 3, 2023 · 4 comments
Labels
bug Something isn't working downgraded by judge Judge downgraded the risk level of this issue duplicate-855 edited-by-warden grade-a QA (Quality Assurance) Assets are not at risk. State handling, function incorrect as to spec, issues with clarity, syntax sufficient quality report This report is of sufficient quality

Comments

@c4-submissions
Copy link
Contributor

c4-submissions commented Oct 3, 2023

Lines of code

https://github.com/code-423n4/2023-09-maia/blob/f5ba4de628836b2a29f9b5fff59499690008c463/src/BranchBridgeAgent.sol#L578

Vulnerability details

Impact

BranchBridgeAgent#LzReceive did not verify the source chain id, the attacker can deploy the contract with the same address as the trusted rootBridgeAgent on other LayerZero supported evm chain(no RootBridgeAgent is deployed), and then send arbitrary messages to the target BranchBridgeAgent, including mint tokens, send administrator instructions, and so on.

Proof of Concept

BranchBridgeAgent uses lzReceive to accept the cross-chain message sent by RootBridgeAgent, and then calls lzReceiveNonBlocking. The change function uses _requiresEndpoint to verify whether the message source is reliable.

    function lzReceive(
@>      uint16,   // <--- source chain id was ignored.
        bytes calldata _srcAddress,
        uint64,
        bytes calldata _payload
    ) public override {
        address(this).excessivelySafeCall(
            gasleft(),
            150,
            abi.encodeWithSelector(
                this.lzReceiveNonBlocking.selector,
                msg.sender,  // <-- _endpoint 
                _srcAddress,
                _payload
            )
        );
    }

    function lzReceiveNonBlocking(
        address _endpoint,
        bytes calldata _srcAddress,
        bytes calldata _payload
    ) public override requiresEndpoint(_endpoint, _srcAddress) {  //<--- Verify _endpoint and _srcAddress
    ......
    }

    function _requiresEndpoint(
        address _endpoint,
        bytes calldata _srcAddress
    ) internal view virtual {
        //Verify Endpoint
        if (msg.sender != address(this)) revert LayerZeroUnauthorizedEndpoint();
        if (_endpoint != lzEndpointAddress)
            revert LayerZeroUnauthorizedEndpoint();

        //Verify Remote Caller
        if (_srcAddress.length != 40) revert LayerZeroUnauthorizedCaller();
        if (
            rootBridgeAgentAddress !=
            address(uint160(bytes20(_srcAddress[20:])))
        ) revert LayerZeroUnauthorizedCaller();
    }

However, the verification process only verifies _endpoint, _srcAddress,
source chain id not verified:

  1. Call msg.sender(_endpoint) of lzReceive as lzEndpointAddress. The attacker sends messages through LayerZero official Endpoint to pass _endpoint authentication.
    2._srcAddress is the address that initiates cross-chain calls on the source chain. If the attacker is on an LayerZero supported chain and no RootBridgeAgent is deployed on the chain, the attacker can create a RootBridgeAgent with the same address and pass the authentication of _srcAddress.

The attacker sends arbitrary messages to the BranchBridgeAgent in the following ways:

  1. Assume that the trusted rootBridgeAgentAddress in the target BranchBridgeAgent is 0x0A.
  2. Find a chain supported by LayerZero and name it chain X. No RootBridgeAgent or contract with address 0x0A is deployed on this chain.
  3. The attacker creates a RootBridgeAgent and deploys it to the X chain with the address 0x0A. The contract is controlled by the attacker.
  4. Attack In RootBridgeAgen, the send function of lzEndpoint is invoked to initiate a cross-chain call through LayerZero.
  5. BranchBridgeAgent.lzReceive received message from attacker cross LayerZero send come over, _endpoint and LayerZero official the Endpoint address is consistent, _srcAddress and trusted address also, so an attacker can pass the _requiresEndpoint Verify.
  6. The attacker constructs a message and sends it to BranchBridgeAgent, such as the command 0x00 to send administrator instructions.

The key to this issue is whether different chains have the same contract address.

EVM determines the address of the contract by publishing the account address of the contract and the transaction nonce, but it cannot be ruled out that some chains use other mechanisms to generate contract addresses.

The more chains supported by LayerZero, the possibility of duplication will increase.

It cannot be ruled out that a chain is controlled by an attacker and is officially supported by LayerZero.

Therefore, it is more secure to verify the source chain id for risk isolation.

Tools Used

vscode

Recommended Mitigation Steps

Verify the source chain id when accepting cross-chain messages

Assessed type

Access Control

@c4-submissions c4-submissions added 3 (High Risk) Assets can be stolen/lost/compromised directly bug Something isn't working labels Oct 3, 2023
c4-submissions added a commit that referenced this issue Oct 3, 2023
@c4-pre-sort
Copy link

0xA5DF marked the issue as duplicate of #855

@c4-pre-sort
Copy link

0xA5DF marked the issue as sufficient quality report

@c4-pre-sort c4-pre-sort added the sufficient quality report This report is of sufficient quality label Oct 12, 2023
@c4-judge
Copy link
Contributor

alcueca changed the severity to QA (Quality Assurance)

@c4-judge c4-judge added downgraded by judge Judge downgraded the risk level of this issue QA (Quality Assurance) Assets are not at risk. State handling, function incorrect as to spec, issues with clarity, syntax and removed 3 (High Risk) Assets can be stolen/lost/compromised directly labels Oct 25, 2023
@c4-judge
Copy link
Contributor

alcueca marked the issue as grade-b

@C4-Staff C4-Staff reopened this Nov 8, 2023
@C4-Staff C4-Staff added grade-a and removed grade-b labels Nov 8, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working downgraded by judge Judge downgraded the risk level of this issue duplicate-855 edited-by-warden grade-a QA (Quality Assurance) Assets are not at risk. State handling, function incorrect as to spec, issues with clarity, syntax sufficient quality report This report is of sufficient quality
Projects
None yet
Development

No branches or pull requests

5 participants